feat: improve DNS cache handling by avoiding unnecessary flushes
CI / Windows x64 (push) Successful in 12m36s

This commit is contained in:
2026-08-09 16:37:31 +07:00
parent 2b8e0cb701
commit 9550aad4f8
2 changed files with 36 additions and 5 deletions
+7
View File
@@ -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 - 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. 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 ### Notes
- The view is held in memory only. It is never written to the log file and is - The view is held in memory only. It is never written to the log file and is
+29 -5
View File
@@ -179,6 +179,15 @@ fn parse_addrs(text: &str) -> Vec<IpAddr> {
/// достаточно проставить его один раз и обновлять изредка. /// достаточно проставить его один раз и обновлять изредка.
#[cfg(windows)] #[cfg(windows)]
pub fn redirect_to_local() -> Result<(), String> { pub fn redirect_to_local() -> Result<(), String> {
// Адаптер, уже смотрящий на нас, не трогаем вовсе, а кэш имён сбрасываем,
// только если что-то действительно изменилось. Вызов приходит и по таймеру,
// раз в пять минут, и безусловный сброс выбрасывал бы кэш всей системы на
// ровном месте — при том, что менять там обычно нечего.
//
// Сравниваем склейкой в строку, а не массивом: у пустого списка серверов
// сравнение массива с адресом даёт «равно», и адаптер без настройки молча
// остался бы ненастроенным.
//
// Счётчик обязателен. Отдельная попытка на адаптер завёрнута в `try`, иначе // Счётчик обязателен. Отдельная попытка на адаптер завёрнута в `try`, иначе
// одна отключённая виртуальная карта срывала бы всю настройку, — но тогда // одна отключённая виртуальная карта срывала бы всю настройку, — но тогда
// PowerShell завершается успешно, даже не тронув ни одного адаптера, и // PowerShell завершается успешно, даже не тронув ни одного адаптера, и
@@ -186,17 +195,32 @@ pub fn redirect_to_local() -> Result<(), String> {
// идёт: на машине без IPv6 она падает законно. // идёт: на машине без IPv6 она падает законно.
const SCRIPT: &str = "\ const SCRIPT: &str = "\
$ErrorActionPreference='Stop';\ $ErrorActionPreference='Stop';\
$n=0;\ $n=0;$changed=0;\
foreach($a in Get-NetAdapter){\ foreach($a in Get-NetAdapter){\
try{Set-DnsClientServerAddress -InterfaceIndex $a.ifIndex -ServerAddresses ('127.0.0.1');$n++}catch{};\ try{\
try{Set-DnsClientServerAddress -InterfaceIndex $a.ifIndex -ServerAddresses ('::1')}catch{}\ $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"; $n";
// Считаются адаптеры, которые в итоге смотрят на нас, а не только те, что
// пришлось переставить: холостой проход обязан заканчиваться успехом.
let done = count_from(&powershell(SCRIPT)?); let done = count_from(&powershell(SCRIPT)?);
if done == 0 { if done == 0 {
return Err("ни один адаптер не переключился".to_string()); return Err("ни один адаптер не удалось настроить".to_string());
} }
set_marker(true); set_marker(true);
Ok(()) Ok(())