From 43a58b46d22ee870ac6e8d8081e484d37808426b Mon Sep 17 00:00:00 2001 From: iHsin Date: Mon, 15 Jun 2026 22:14:25 +0800 Subject: [PATCH] fix: add IPv6 bootstrap DNS servers for IPv6-only uplinks On IPv6-only mobile networks (e.g. 464XLAT cellular) the outbound interface has no IPv4 address, so the IPv4-only default bootstrap nameservers all time out. Every DNS client then fails to initialize, leaving "no DNS clients available for query" and breaking all domain-based connections while literal-IP traffic still works. Add AliDNS/Google IPv6 servers to the built-in default-nameserver list so bootstrap resolution works over IPv6. Also switch the hardcoded defaults from Host::Domain to typed Host::Ipv4/Host::Ipv6. Bootstrap clients are built with no parent resolver, so a Host::Domain entry hits the resolve path and fails to initialize; literal IPs must use the typed variants. Co-Authored-By: Claude Opus 4.8 (1M context) --- uniffi/clash-android-ffi/src/lib.rs | 41 ++++++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/uniffi/clash-android-ffi/src/lib.rs b/uniffi/clash-android-ffi/src/lib.rs index cf159b7..eebb1fa 100644 --- a/uniffi/clash-android-ffi/src/lib.rs +++ b/uniffi/clash-android-ffi/src/lib.rs @@ -6,7 +6,7 @@ static GLOBAL: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc; #[global_allocator] static GLOBAL: ::mimalloc::MiMalloc = ::mimalloc::MiMalloc; -use std::net::{IpAddr, Ipv4Addr, SocketAddr}; +use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr}; use std::path::PathBuf; use std::sync::{Arc, Once}; @@ -215,24 +215,57 @@ async fn run_clash( config.general.ipv6 = over.ipv6; let default_nameserver = if config.dns.default_nameserver.is_empty() { + // Bootstrap nameservers. These are built with no parent resolver, so the + // host must be a literal IP (a `Host::Domain` would hit the resolve path + // and fail). The IPv6 servers let resolution work on IPv6-only uplinks + // (e.g. 464XLAT cellular), where the interface has no IPv4 address and the + // IPv4 servers are unreachable. vec![ NameServer { net: DNSNetMode::Udp, - host: Host::Domain("223.5.5.5".to_string()), + host: Host::Ipv4(Ipv4Addr::new(223, 5, 5, 5)), // AliDNS port: 53, interface: None, proxy: None, }, NameServer { net: DNSNetMode::Udp, - host: Host::Domain("223.6.6.6".to_string()), + host: Host::Ipv4(Ipv4Addr::new(223, 6, 6, 6)), // AliDNS port: 53, interface: None, proxy: None, }, NameServer { net: DNSNetMode::Udp, - host: Host::Domain("8.8.8.8".to_string()), + host: Host::Ipv4(Ipv4Addr::new(8, 8, 8, 8)), // Google + port: 53, + interface: None, + proxy: None, + }, + NameServer { + net: DNSNetMode::Udp, + // AliDNS public IPv6 + host: Host::Ipv6(Ipv6Addr::new(0x2400, 0x3200, 0, 0, 0, 0, 0, 1)), + port: 53, + interface: None, + proxy: None, + }, + NameServer { + net: DNSNetMode::Udp, + // AliDNS public IPv6 + host: Host::Ipv6(Ipv6Addr::new( + 0x2400, 0x3200, 0xbaba, 0, 0, 0, 0, 1, + )), + port: 53, + interface: None, + proxy: None, + }, + NameServer { + net: DNSNetMode::Udp, + // Google public IPv6 + host: Host::Ipv6(Ipv6Addr::new( + 0x2001, 0x4860, 0x4860, 0, 0, 0, 0, 0x8888, + )), port: 53, interface: None, proxy: None,