From 663a0079ec920d6bd368c2edc6307450a9b6aa49 Mon Sep 17 00:00:00 2001 From: Scott Godin Date: Thu, 6 Nov 2025 17:30:10 -0500 Subject: [PATCH 1/2] Filter DNS Results by Interface Type - The default bind address is [::]:0 (v6) - If binding to V4 address, then filter DNS responses to v4 results only - If binding to V6 address and on linux, then behavior is unchanged (linux is dual-stack and can send to IPv4 destinations on a v6 socket) - If binding to V6 address and non-linux, then filter DNS responses to v6 results only --- moq-native-ietf/src/quic.rs | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/moq-native-ietf/src/quic.rs b/moq-native-ietf/src/quic.rs index 0919fc2..bce01e2 100644 --- a/moq-native-ietf/src/quic.rs +++ b/moq-native-ietf/src/quic.rs @@ -303,13 +303,38 @@ impl Client { let host = url.host().context("invalid DNS name")?.to_string(); let port = url.port().unwrap_or(443); - // Look up the DNS entry. - let addr = tokio::net::lookup_host((host.clone(), port)) + // Determine whether our local socket is IPv6 or IPv4 + let is_ipv6 = self + .quic + .local_addr() + .context("failed to get local address")? + .is_ipv6(); + + // Perform DNS lookup to get all addresses + let addrs: Vec = tokio::net::lookup_host((host.clone(), port)) .await .context("failed DNS lookup")? - .next() + .collect(); + + // Select DNS address to use based on local socket type and OS + let chosen = if !is_ipv6 { + // If we are bound to an IPv4 socket, prefer IPv4 addresses + addrs.iter().find(|a| a.is_ipv4()).cloned() + } else if cfg!(target_os = "linux") { + // If IPv6 and running on Linux (dual-stack), use top DNS result + addrs.first().cloned() + } else { + // Non-linux IPv6 build: prefer IPv6 only + addrs.iter().find(|a| a.is_ipv6()).cloned() + }; + + // Fallback to the first available address if preferred selection fails + let addr = chosen + .or_else(|| addrs.first().cloned()) .context("no DNS entries")?; + log::info!("Connecting to address={}", addr); + let connection = self.quic.connect_with(config, addr, &host)?.await?; // Extract the CID that was used From 9167745181ea0da59761c12a8e32fb8b8c568b54 Mon Sep 17 00:00:00 2001 From: Scott Godin Date: Fri, 7 Nov 2025 12:28:33 -0500 Subject: [PATCH 2/2] - address some CoPilot suggestions and cleanup logic - log out all DNS results to assist in troubleshooting - move client connection logs to debug level --- moq-native-ietf/src/quic.rs | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/moq-native-ietf/src/quic.rs b/moq-native-ietf/src/quic.rs index bce01e2..812d1dd 100644 --- a/moq-native-ietf/src/quic.rs +++ b/moq-native-ietf/src/quic.rs @@ -316,24 +316,40 @@ impl Client { .context("failed DNS lookup")? .collect(); + // Fail early if DNS lookup returned no addresses + if addrs.is_empty() { + anyhow::bail!("DNS lookup for host '{}' returned no addresses", host); + } + + // Log all DNS responses + for (i, addr) in addrs.iter().enumerate() { + log::debug!( + "DNS[{}] = {} ({})", + i, + addr, + if addr.is_ipv4() { "ipv4" } else { "ipv6" } + ); + } + // Select DNS address to use based on local socket type and OS let chosen = if !is_ipv6 { // If we are bound to an IPv4 socket, prefer IPv4 addresses addrs.iter().find(|a| a.is_ipv4()).cloned() } else if cfg!(target_os = "linux") { - // If IPv6 and running on Linux (dual-stack), use top DNS result + // If IPv6 and running on Linux, then assume dual-stack, and use top DNS result addrs.first().cloned() } else { - // Non-linux IPv6 build: prefer IPv6 only + // If IPv6 and not running on Linux: prefer IPv6 addresses addrs.iter().find(|a| a.is_ipv6()).cloned() }; - // Fallback to the first available address if preferred selection fails - let addr = chosen - .or_else(|| addrs.first().cloned()) - .context("no DNS entries")?; + // Fail if no compatible address is found + let addr = chosen.context(format!( + "No compatible address found for local socket type (IPv{})", + if is_ipv6 { "6" } else { "4" } + ))?; - log::info!("Connecting to address={}", addr); + log::debug!("Connecting to address={}", addr); let connection = self.quic.connect_with(config, addr, &host)?.await?;