From 9550aad4f832f24d44410cdd9e0c8964fd57740a Mon Sep 17 00:00:00 2001 From: robonen Date: Sun, 9 Aug 2026 16:37:31 +0700 Subject: [PATCH] feat: improve DNS cache handling by avoiding unnecessary flushes --- CHANGELOG.md | 7 +++++++ src/netcfg.rs | 34 +++++++++++++++++++++++++++++----- 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b7b073a..d1ec339 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,13 @@ versioning follows [Semantic Versioning](https://semver.org/). - A live view of the last 200 queries the resolver handled, each marked as blocked, served from cache, or sent upstream, with a filter by name. +### Fixed + +- The system DNS cache is no longer flushed on every periodic re-apply. Adapters + that already point at the resolver are left untouched, and the cache is only + cleared when something actually changed — previously the whole machine's cache + was discarded every five minutes for nothing. + ### Notes - The view is held in memory only. It is never written to the log file and is diff --git a/src/netcfg.rs b/src/netcfg.rs index 80251d7..5dca25a 100644 --- a/src/netcfg.rs +++ b/src/netcfg.rs @@ -179,6 +179,15 @@ fn parse_addrs(text: &str) -> Vec { /// достаточно проставить его один раз и обновлять изредка. #[cfg(windows)] pub fn redirect_to_local() -> Result<(), String> { + // Адаптер, уже смотрящий на нас, не трогаем вовсе, а кэш имён сбрасываем, + // только если что-то действительно изменилось. Вызов приходит и по таймеру, + // раз в пять минут, и безусловный сброс выбрасывал бы кэш всей системы на + // ровном месте — при том, что менять там обычно нечего. + // + // Сравниваем склейкой в строку, а не массивом: у пустого списка серверов + // сравнение массива с адресом даёт «равно», и адаптер без настройки молча + // остался бы ненастроенным. + // // Счётчик обязателен. Отдельная попытка на адаптер завёрнута в `try`, иначе // одна отключённая виртуальная карта срывала бы всю настройку, — но тогда // PowerShell завершается успешно, даже не тронув ни одного адаптера, и @@ -186,17 +195,32 @@ pub fn redirect_to_local() -> Result<(), String> { // идёт: на машине без IPv6 она падает законно. const SCRIPT: &str = "\ $ErrorActionPreference='Stop';\ - $n=0;\ + $n=0;$changed=0;\ foreach($a in Get-NetAdapter){\ - try{Set-DnsClientServerAddress -InterfaceIndex $a.ifIndex -ServerAddresses ('127.0.0.1');$n++}catch{};\ - try{Set-DnsClientServerAddress -InterfaceIndex $a.ifIndex -ServerAddresses ('::1')}catch{}\ + try{\ + $cur=((Get-DnsClientServerAddress -InterfaceIndex $a.ifIndex -AddressFamily IPv4).ServerAddresses -join ',');\ + if($cur -ne '127.0.0.1'){\ + Set-DnsClientServerAddress -InterfaceIndex $a.ifIndex -ServerAddresses ('127.0.0.1');\ + $changed++\ + };\ + $n++\ + }catch{};\ + try{\ + $cur6=((Get-DnsClientServerAddress -InterfaceIndex $a.ifIndex -AddressFamily IPv6).ServerAddresses -join ',');\ + if($cur6 -ne '::1'){\ + Set-DnsClientServerAddress -InterfaceIndex $a.ifIndex -ServerAddresses ('::1');\ + $changed++\ + }\ + }catch{}\ };\ - Clear-DnsClientCache;\ + if($changed -gt 0){Clear-DnsClientCache};\ $n"; + // Считаются адаптеры, которые в итоге смотрят на нас, а не только те, что + // пришлось переставить: холостой проход обязан заканчиваться успехом. let done = count_from(&powershell(SCRIPT)?); if done == 0 { - return Err("ни один адаптер не переключился".to_string()); + return Err("ни один адаптер не удалось настроить".to_string()); } set_marker(true); Ok(())