Fix DNS failure on network change #9
34
src/main.rs
34
src/main.rs
@@ -86,10 +86,13 @@ async fn main() -> numa::Result<()> {
|
|||||||
let system_dns = discover_system_dns();
|
let system_dns = discover_system_dns();
|
||||||
|
|
||||||
let upstream_addr = if config.upstream.address.is_empty() {
|
let upstream_addr = if config.upstream.address.is_empty() {
|
||||||
system_dns.default_upstream.unwrap_or_else(|| {
|
system_dns
|
||||||
info!("could not detect system DNS, falling back to 9.9.9.9 (Quad9)");
|
.default_upstream
|
||||||
"9.9.9.9".to_string()
|
.or_else(numa::system_dns::detect_dhcp_dns)
|
||||||
})
|
.unwrap_or_else(|| {
|
||||||
|
info!("could not detect system DNS, falling back to 9.9.9.9 (Quad9)");
|
||||||
|
"9.9.9.9".to_string()
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
config.upstream.address.clone()
|
config.upstream.address.clone()
|
||||||
};
|
};
|
||||||
@@ -296,16 +299,19 @@ async fn network_watch_loop(ctx: Arc<numa::ctx::ServerCtx>) {
|
|||||||
// Check upstream change (only for auto-detected upstream)
|
// Check upstream change (only for auto-detected upstream)
|
||||||
if ctx.upstream_auto {
|
if ctx.upstream_auto {
|
||||||
let dns_info = numa::system_dns::discover_system_dns();
|
let dns_info = numa::system_dns::discover_system_dns();
|
||||||
if let Some(new_addr) = dns_info.default_upstream {
|
// Use detected upstream, or try DHCP-provided DNS, or fall back to Quad9
|
||||||
if let Ok(new_upstream) =
|
let new_addr = dns_info
|
||||||
format!("{}:{}", new_addr, ctx.upstream_port).parse::<SocketAddr>()
|
.default_upstream
|
||||||
{
|
.or_else(numa::system_dns::detect_dhcp_dns)
|
||||||
let mut upstream = ctx.upstream.lock().unwrap();
|
.unwrap_or_else(|| "9.9.9.9".to_string());
|
||||||
if new_upstream != *upstream {
|
if let Ok(new_upstream) =
|
||||||
info!("upstream changed: {} → {}", *upstream, new_upstream);
|
format!("{}:{}", new_addr, ctx.upstream_port).parse::<SocketAddr>()
|
||||||
*upstream = new_upstream;
|
{
|
||||||
changed = true;
|
let mut upstream = ctx.upstream.lock().unwrap();
|
||||||
}
|
if new_upstream != *upstream {
|
||||||
|
info!("upstream changed: {} → {}", *upstream, new_upstream);
|
||||||
|
*upstream = new_upstream;
|
||||||
|
changed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -205,6 +205,53 @@ fn read_upstream_from_file(path: &str) -> Option<String> {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Detect DNS server from DHCP lease — fallback when scutil/resolv.conf only shows 127.0.0.1.
|
||||||
|
/// On macOS: parses `ipconfig getpacket en0` for domain_name_server.
|
||||||
|
/// On Linux/Windows: returns None (not implemented yet).
|
||||||
|
pub fn detect_dhcp_dns() -> Option<String> {
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
{
|
||||||
|
detect_dhcp_dns_macos()
|
||||||
|
}
|
||||||
|
#[cfg(not(target_os = "macos"))]
|
||||||
|
{
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
fn detect_dhcp_dns_macos() -> Option<String> {
|
||||||
|
// Try common interfaces
|
||||||
|
for iface in &["en0", "en1"] {
|
||||||
|
let output = std::process::Command::new("ipconfig")
|
||||||
|
.args(["getpacket", iface])
|
||||||
|
.output()
|
||||||
|
.ok()?;
|
||||||
|
let text = String::from_utf8_lossy(&output.stdout);
|
||||||
|
for line in text.lines() {
|
||||||
|
if line.contains("domain_name_server") {
|
||||||
|
// Format: "domain_name_server (ip_mult): {213.154.124.25, 1.0.0.1}"
|
||||||
|
if let Some(braces) = line.split('{').nth(1) {
|
||||||
|
let inner = braces.trim_end_matches('}').trim();
|
||||||
|
// Take the first non-loopback DNS server
|
||||||
|
for addr in inner.split(',') {
|
||||||
|
let addr = addr.trim();
|
||||||
|
if !addr.is_empty()
|
||||||
|
&& addr != "127.0.0.1"
|
||||||
|
&& addr != "0.0.0.0"
|
||||||
|
&& addr.parse::<std::net::Ipv4Addr>().is_ok()
|
||||||
|
{
|
||||||
|
log::info!("detected DHCP DNS: {}", addr);
|
||||||
|
return Some(addr.to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
// --- Windows implementation ---
|
// --- Windows implementation ---
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
|
|||||||
Reference in New Issue
Block a user