From 642daa35a1d110d355572d3c90285be56cd26ce8 Mon Sep 17 00:00:00 2001 From: Ryan Fowler Date: Wed, 5 Aug 2026 11:28:28 -0400 Subject: [PATCH] fix: preserve DoH TTL presence --- src/dns/inspect.rs | 45 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/src/dns/inspect.rs b/src/dns/inspect.rs index 1fa37f8..5d272de 100644 --- a/src/dns/inspect.rs +++ b/src/dns/inspect.rs @@ -391,8 +391,11 @@ async fn lookup( let key = format!("{}\0{}", record.typ, record.value); let records = out.records.entry(record.typ.clone()).or_default(); if let Some(idx) = seen.get(&key).copied() { - if record.ttl < records[idx].ttl { + if record.has_ttl + && (!records[idx].has_ttl || record.ttl < records[idx].ttl) + { records[idx].ttl = record.ttl; + records[idx].has_ttl = true; } continue; } @@ -468,7 +471,7 @@ async fn lookup_doh_records( typ: typ.to_string(), value: normalize_doh_value(answer.answer_type, &answer.data), ttl: answer.ttl.unwrap_or_default(), - has_ttl: true, + has_ttl: answer.ttl.is_some(), } }) .collect()) @@ -969,6 +972,44 @@ mod tests { task.abort(); } + #[tokio::test] + async fn test_inspect_doh_preserves_missing_zero_and_nonzero_ttls() { + let (server_url, task) = start_test_server(|request| { + let query_type = request + .uri() + .query() + .unwrap_or_default() + .split('&') + .find_map(|part| part.strip_prefix("type=")) + .unwrap_or_default(); + if query_type == "A" { + return http::Response::new( + r#"{"Status":0,"Answer":[ + {"type":1,"data":"192.0.2.1"}, + {"type":1,"data":"192.0.2.2","TTL":0}, + {"type":1,"data":"192.0.2.3","TTL":60} + ]}"# + .to_string(), + ); + } + http::Response::new(r#"{"Status":0}"#.to_string()) + }) + .await; + + let out = inspect( + &Url::parse("https://example.com").unwrap(), + Some(server_url.as_str()), + ) + .await + .unwrap(); + + assert!(out.contains("192.0.2.1\n"), "output: {out}"); + assert!(!out.contains("192.0.2.1 (TTL"), "output: {out}"); + assert!(out.contains("192.0.2.2 (TTL 0s)"), "output: {out}"); + assert!(out.contains("192.0.2.3 (TTL 1m)"), "output: {out}"); + task.abort(); + } + #[tokio::test] async fn test_inspect_doh_partial_failure_preserves_records_and_exits_nonzero() { let (server_url, task) = start_test_server(|request| {