feat(resolver): filter_aaaa for IPv4-only networks (#112)
When enabled, AAAA queries short-circuit to NODATA (NOERROR + empty answer) so Happy Eyeballs clients don't stall waiting on a v6 address they can't use. Also strips `ipv6hint` SvcParam from HTTPS/SVCB answers (RFC 9460) so Chrome ≥103, Firefox, and Safari don't bypass the AAAA filter via the HTTPS record path. Local data is preserved: overrides, zones, the .numa proxy, and the blocklist sinkhole keep whatever v6 addresses they configure — the filter only kicks in on the cache/forward/recursive path. NODATA is correct per RFC 2308 here; NXDOMAIN would incorrectly imply the name doesn't exist for A queries either. Off by default. Opt in via `filter_aaaa = true` under `[server]`.
This commit is contained in:
@@ -93,6 +93,12 @@ pub struct ServerConfig {
|
||||
/// Defaults to `crate::data_dir()` (platform-specific system path) if unset.
|
||||
#[serde(default)]
|
||||
pub data_dir: Option<PathBuf>,
|
||||
/// Synthesize NODATA (NOERROR + empty answer) for AAAA queries, and
|
||||
/// strip `ipv6hint` from HTTPS/SVCB responses (RFC 9460). For IPv4-only
|
||||
/// networks where Happy Eyeballs fallback adds latency. Local zones,
|
||||
/// overrides, and the service proxy are not affected. Default false.
|
||||
#[serde(default)]
|
||||
pub filter_aaaa: bool,
|
||||
}
|
||||
|
||||
impl Default for ServerConfig {
|
||||
@@ -102,6 +108,7 @@ impl Default for ServerConfig {
|
||||
api_port: default_api_port(),
|
||||
api_bind_addr: default_api_bind_addr(),
|
||||
data_dir: None,
|
||||
filter_aaaa: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -580,6 +587,17 @@ mod tests {
|
||||
assert!(config.lan.enabled);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn filter_aaaa_defaults_false() {
|
||||
assert!(!ServerConfig::default().filter_aaaa);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn filter_aaaa_parses_from_server_section() {
|
||||
let config: Config = toml::from_str("[server]\nfilter_aaaa = true").unwrap();
|
||||
assert!(config.server.filter_aaaa);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn custom_bind_addrs_parse() {
|
||||
let toml = r#"
|
||||
|
||||
Reference in New Issue
Block a user