From fef26b7139efc38b422844b25225f9ffd4e20087 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 29 Apr 2024 18:48:11 +0200 Subject: [PATCH 1/2] dns-test: add getters & make some fields public --- packages/dns-test/src/record.rs | 20 ++++++++++++++------ packages/dns-test/src/tshark.rs | 4 ++++ 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/packages/dns-test/src/record.rs b/packages/dns-test/src/record.rs index aaaf446a..dc9d4423 100644 --- a/packages/dns-test/src/record.rs +++ b/packages/dns-test/src/record.rs @@ -142,6 +142,14 @@ impl Record { } .into() } + + pub fn try_into_ds(self) -> CoreResult { + if let Self::DS(v) = self { + Ok(v) + } else { + Err(self) + } + } } impl FromStr for Record { @@ -327,12 +335,12 @@ impl fmt::Display for DNSKEY { #[derive(Clone, Debug)] pub struct DS { - zone: FQDN, - ttl: u32, - key_tag: u16, - algorithm: u8, - digest_type: u8, - digest: String, + pub zone: FQDN, + pub ttl: u32, + pub key_tag: u16, + pub algorithm: u8, + pub digest_type: u8, + pub digest: String, } impl FromStr for DS { diff --git a/packages/dns-test/src/tshark.rs b/packages/dns-test/src/tshark.rs index 8b850019..c78e1903 100644 --- a/packages/dns-test/src/tshark.rs +++ b/packages/dns-test/src/tshark.rs @@ -179,6 +179,10 @@ impl Message { .ok() } + pub fn as_value(&self) -> &serde_json::Value { + &self.inner + } + fn opt_record(&self) -> Option<&serde_json::Value> { for (key, value) in self.inner.get("Additional records")?.as_object()? { if key.ends_with(": type OPT") { From 261b9f4428ff72e01401edf2c19a6bf8d024918b Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 29 Apr 2024 18:48:37 +0200 Subject: [PATCH 2/2] resolver: test that DS query is sent to parent zone --- .../src/resolver/dnssec/rfc4035.rs | 1 + .../src/resolver/dnssec/rfc4035/section_3.rs | 1 + .../dnssec/rfc4035/section_3/section_3_1.rs | 1 + .../section_3/section_3_1/section_3_1_4.rs | 77 +++++++++++++++++++ 4 files changed, 80 insertions(+) create mode 100644 packages/conformance-tests/src/resolver/dnssec/rfc4035/section_3.rs create mode 100644 packages/conformance-tests/src/resolver/dnssec/rfc4035/section_3/section_3_1.rs create mode 100644 packages/conformance-tests/src/resolver/dnssec/rfc4035/section_3/section_3_1/section_3_1_4.rs diff --git a/packages/conformance-tests/src/resolver/dnssec/rfc4035.rs b/packages/conformance-tests/src/resolver/dnssec/rfc4035.rs index 289eace0..5ee74792 100644 --- a/packages/conformance-tests/src/resolver/dnssec/rfc4035.rs +++ b/packages/conformance-tests/src/resolver/dnssec/rfc4035.rs @@ -1 +1,2 @@ +mod section_3; mod section_4; diff --git a/packages/conformance-tests/src/resolver/dnssec/rfc4035/section_3.rs b/packages/conformance-tests/src/resolver/dnssec/rfc4035/section_3.rs new file mode 100644 index 00000000..137bed61 --- /dev/null +++ b/packages/conformance-tests/src/resolver/dnssec/rfc4035/section_3.rs @@ -0,0 +1 @@ +mod section_3_1; diff --git a/packages/conformance-tests/src/resolver/dnssec/rfc4035/section_3/section_3_1.rs b/packages/conformance-tests/src/resolver/dnssec/rfc4035/section_3/section_3_1.rs new file mode 100644 index 00000000..b2554b53 --- /dev/null +++ b/packages/conformance-tests/src/resolver/dnssec/rfc4035/section_3/section_3_1.rs @@ -0,0 +1 @@ +mod section_3_1_4; diff --git a/packages/conformance-tests/src/resolver/dnssec/rfc4035/section_3/section_3_1/section_3_1_4.rs b/packages/conformance-tests/src/resolver/dnssec/rfc4035/section_3/section_3_1/section_3_1_4.rs new file mode 100644 index 00000000..c3489208 --- /dev/null +++ b/packages/conformance-tests/src/resolver/dnssec/rfc4035/section_3/section_3_1/section_3_1_4.rs @@ -0,0 +1,77 @@ +use dns_test::{ + client::{Client, DigSettings}, + name_server::{Graph, NameServer, Sign}, + record::RecordType, + tshark::{Capture, Direction}, + Network, Resolver, Result, FQDN, +}; + +#[test] +#[ignore] +fn on_clients_ds_query_it_queries_the_parent_zone() -> Result<()> { + let network = Network::new()?; + + let leaf_ns = NameServer::new(&dns_test::PEER, FQDN::NAMESERVERS, &network)?; + + let Graph { + nameservers, + root, + trust_anchor, + } = Graph::build(leaf_ns, Sign::Yes)?; + + let mut com_ns_addr = None; + for nameserver in &nameservers { + if nameserver.zone() == &FQDN::COM { + com_ns_addr = Some(nameserver.ipv4_addr()); + } + } + let com_ns_addr = com_ns_addr.expect("com. NS not found"); + + let trust_anchor = &trust_anchor.unwrap(); + let resolver = Resolver::new(&network, root) + .trust_anchor(trust_anchor) + .start(&dns_test::SUBJECT)?; + + let mut tshark = resolver.eavesdrop()?; + + let resolver_addr = resolver.ipv4_addr(); + + let client = Client::new(&network)?; + let settings = *DigSettings::default().recurse(); + let output = client.dig(settings, resolver_addr, RecordType::DS, &FQDN::NAMESERVERS)?; + + tshark.wait_for_capture()?; + + let captures = tshark.terminate()?; + + // check that we were able to retrieve the DS record + assert!(output.status.is_noerror()); + let [record] = output.answer.try_into().unwrap(); + let ds = record.try_into_ds().unwrap(); + assert_eq!(ds.zone, FQDN::NAMESERVERS); + + // check that DS query was forwarded to the `com.` (parent zone) nameserver + let client_addr = client.ipv4_addr(); + let mut outgoing_ds_query_count = 0; + for Capture { message, direction } in captures { + if let Direction::Outgoing { destination } = direction { + if destination != client_addr { + let queries = message.as_value()["Queries"] + .as_object() + .expect("expected Object"); + for query in queries.keys() { + if query.contains("type DS") { + assert!(query.contains("nameservers.com")); + assert_eq!(com_ns_addr, destination); + + outgoing_ds_query_count += 1; + } + } + } + } + } + + assert_eq!(1, outgoing_ds_query_count); + + Ok(()) +}