Skip to content

Commit 78929a3

Browse files
committed
fix: bind DNS server to multiple addresses for resolv.conf compatibility
DNS server now binds to: - 0.0.0.0:53 (catches most via DNAT) - 127.0.0.53:53 (systemd-resolved) - 127.0.0.54:53 (alternative systemd-resolved address) This ensures robust DNS resolution regardless of /etc/resolv.conf configuration. We intentionally do NOT modify resolv.conf to avoid side effects.
1 parent 731d015 commit 78929a3

1 file changed

Lines changed: 31 additions & 32 deletions

File tree

src/jail/linux/dns.rs

Lines changed: 31 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -148,44 +148,43 @@ fn build_dummy_response(query: Packet<'_>) -> Result<Vec<u8>> {
148148
}
149149

150150
/// Run DNS server synchronously (blocks forever). Used when spawned inside namespace.
151+
///
152+
/// We bind to multiple addresses to handle different /etc/resolv.conf configurations:
153+
/// - 0.0.0.0:53 - Catches most queries via DNAT rules
154+
/// - 127.0.0.53:53 - Used by systemd-resolved on Ubuntu/Debian
155+
/// - 127.0.0.54:53 - Alternative systemd-resolved address
156+
///
157+
/// We intentionally DO NOT modify /etc/resolv.conf to avoid side effects and maintain
158+
/// robustness across different system configurations.
151159
pub fn run_dns_server_blocking() -> Result<()> {
152-
info!("Starting blocking DNS server on 0.0.0.0:53");
153-
154-
let socket =
155-
UdpSocket::bind("0.0.0.0:53").context("Failed to bind DNS server to 0.0.0.0:53")?;
156-
157-
socket.set_read_timeout(Some(Duration::from_millis(500)))?;
158-
159-
let mut buf = [0u8; MAX_DNS_PACKET_SIZE];
160-
loop {
161-
match socket.recv_from(&mut buf) {
162-
Ok((size, src)) => {
163-
debug!("Received DNS query from {}: {} bytes", src, size);
164-
165-
match Packet::parse(&buf[..size]) {
166-
Ok(query) => {
167-
if let Ok(response) = build_dummy_response(query) {
168-
if let Err(e) = socket.send_to(&response, src) {
169-
warn!("Failed to send DNS response to {}: {}", src, e);
170-
} else {
171-
debug!("Sent dummy DNS response to {}", src);
172-
}
173-
}
174-
}
175-
Err(e) => {
176-
debug!("Failed to parse DNS query: {}", e);
177-
}
178-
}
160+
// Bind to multiple addresses to handle different nameserver configurations
161+
let addresses = vec!["0.0.0.0:53", "127.0.0.53:53", "127.0.0.54:53"];
162+
163+
let mut servers = Vec::new();
164+
for addr in &addresses {
165+
let mut server = DummyDnsServer::new();
166+
match server.start(addr) {
167+
Ok(()) => {
168+
info!("Started DNS server on {}", addr);
169+
servers.push(server);
179170
}
180-
Err(e) if e.kind() == std::io::ErrorKind::WouldBlock => continue,
181-
Err(e) if e.kind() == std::io::ErrorKind::TimedOut => continue,
182-
Err(e) if e.kind() == std::io::ErrorKind::Interrupted => continue,
183171
Err(e) => {
184-
error!("DNS server receive error: {}", e);
185-
return Err(e.into());
172+
// Log but don't fail - some addresses may not be available
173+
debug!("Could not start DNS server on {}: {}", addr, e);
186174
}
187175
}
188176
}
177+
178+
if servers.is_empty() {
179+
anyhow::bail!("Failed to start DNS server on any address");
180+
}
181+
182+
info!("DNS servers running on {} address(es)", servers.len());
183+
184+
// Block forever - servers will run in their own threads
185+
loop {
186+
thread::sleep(Duration::from_secs(3600));
187+
}
189188
}
190189

191190
#[cfg(test)]

0 commit comments

Comments
 (0)