From 8f414879b8f8345b829ab4cfa66f43c6728704f1 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 10 May 2024 14:19:27 +0200 Subject: [PATCH 1/2] test CD bit forwarding --- .../dnssec/rfc4035/section_3/section_3_2.rs | 2 ++ .../section_3/section_3_2/section_3_2_2.rs | 23 +++++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 packages/conformance-tests/src/resolver/dnssec/rfc4035/section_3/section_3_2/section_3_2_2.rs diff --git a/packages/conformance-tests/src/resolver/dnssec/rfc4035/section_3/section_3_2.rs b/packages/conformance-tests/src/resolver/dnssec/rfc4035/section_3/section_3_2.rs index f7c0f0df..7d2bd623 100644 --- a/packages/conformance-tests/src/resolver/dnssec/rfc4035/section_3/section_3_2.rs +++ b/packages/conformance-tests/src/resolver/dnssec/rfc4035/section_3/section_3_2.rs @@ -1,3 +1,5 @@ +mod section_3_2_2; + use dns_test::{ client::{Client, DigSettings}, name_server::NameServer, diff --git a/packages/conformance-tests/src/resolver/dnssec/rfc4035/section_3/section_3_2/section_3_2_2.rs b/packages/conformance-tests/src/resolver/dnssec/rfc4035/section_3/section_3_2/section_3_2_2.rs new file mode 100644 index 00000000..de88b4e4 --- /dev/null +++ b/packages/conformance-tests/src/resolver/dnssec/rfc4035/section_3/section_3_2/section_3_2_2.rs @@ -0,0 +1,23 @@ +use dns_test::{ + client::{Client, DigSettings}, + name_server::NameServer, + record::RecordType, + zone_file::Root, + Network, Resolver, Result, FQDN, +}; + +#[test] +fn copies_cd_bit_from_query_to_response() -> Result<()> { + let network = &Network::new()?; + let ns = NameServer::new(&dns_test::PEER, FQDN::ROOT, network)?.start()?; + let resolver = Resolver::new(network, Root::new(ns.fqdn().clone(), ns.ipv4_addr())) + .start(&dns_test::SUBJECT)?; + + let client = Client::new(network)?; + let settings = *DigSettings::default().checking_disabled().recurse(); + let ans = client.dig(settings, resolver.ipv4_addr(), RecordType::SOA, &FQDN::ROOT)?; + + assert!(ans.flags.checking_disabled); + + Ok(()) +} From b6e97bf3b677a384f61b22115538eb88a95d4be6 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 10 May 2024 15:07:54 +0200 Subject: [PATCH 2/2] move existing test into RFC4035 section 3.2.2 --- .../conformance-tests/src/resolver/dnssec.rs | 1 + .../src/resolver/dnssec/fixtures.rs | 50 ++++++++++++++ .../section_3/section_3_2/section_3_2_2.rs | 34 ++++++++++ .../src/resolver/dnssec/scenarios/bogus.rs | 66 ++++--------------- packages/dns-test/src/resolver.rs | 4 ++ packages/dns-test/src/zone_file/mod.rs | 1 + 6 files changed, 101 insertions(+), 55 deletions(-) create mode 100644 packages/conformance-tests/src/resolver/dnssec/fixtures.rs diff --git a/packages/conformance-tests/src/resolver/dnssec.rs b/packages/conformance-tests/src/resolver/dnssec.rs index f408ef38..f813ae4b 100644 --- a/packages/conformance-tests/src/resolver/dnssec.rs +++ b/packages/conformance-tests/src/resolver/dnssec.rs @@ -1,4 +1,5 @@ //! DNSSEC functionality +mod fixtures; mod rfc4035; mod scenarios; diff --git a/packages/conformance-tests/src/resolver/dnssec/fixtures.rs b/packages/conformance-tests/src/resolver/dnssec/fixtures.rs new file mode 100644 index 00000000..eb326de9 --- /dev/null +++ b/packages/conformance-tests/src/resolver/dnssec/fixtures.rs @@ -0,0 +1,50 @@ +use std::net::Ipv4Addr; + +use base64::prelude::*; +use dns_test::{ + name_server::{Graph, NameServer, Sign}, + record::Record, + Network, Resolver, Result, FQDN, +}; + +pub fn bad_signature_in_leaf_nameserver( + leaf_fqdn: &FQDN, + leaf_ipv4_addr: Ipv4Addr, +) -> Result<(Resolver, Graph)> { + assert_eq!(Some(FQDN::NAMESERVERS), leaf_fqdn.parent()); + + let network = Network::new()?; + + let mut leaf_ns = NameServer::new(&dns_test::PEER, FQDN::NAMESERVERS, &network)?; + leaf_ns.add(Record::a(leaf_fqdn.clone(), leaf_ipv4_addr)); + + let graph = Graph::build( + leaf_ns, + Sign::AndAmend(&|zone, records| { + if zone == &FQDN::NAMESERVERS { + let mut modified = 0; + for record in records { + if let Record::RRSIG(rrsig) = record { + if rrsig.fqdn == *leaf_fqdn { + let mut signature = BASE64_STANDARD.decode(&rrsig.signature).unwrap(); + let last = signature.last_mut().expect("empty signature"); + *last = !*last; + + rrsig.signature = BASE64_STANDARD.encode(&signature); + modified += 1; + } + } + } + + assert_eq!(modified, 1, "sanity check"); + } + }), + )?; + + let trust_anchor = graph.trust_anchor.as_ref().unwrap(); + let resolver = Resolver::new(&network, graph.root.clone()) + .trust_anchor(trust_anchor) + .start(&dns_test::SUBJECT)?; + + Ok((resolver, graph)) +} diff --git a/packages/conformance-tests/src/resolver/dnssec/rfc4035/section_3/section_3_2/section_3_2_2.rs b/packages/conformance-tests/src/resolver/dnssec/rfc4035/section_3/section_3_2/section_3_2_2.rs index de88b4e4..ce9b6ab5 100644 --- a/packages/conformance-tests/src/resolver/dnssec/rfc4035/section_3/section_3_2/section_3_2_2.rs +++ b/packages/conformance-tests/src/resolver/dnssec/rfc4035/section_3/section_3_2/section_3_2_2.rs @@ -1,3 +1,5 @@ +use std::net::Ipv4Addr; + use dns_test::{ client::{Client, DigSettings}, name_server::NameServer, @@ -6,6 +8,8 @@ use dns_test::{ Network, Resolver, Result, FQDN, }; +use crate::resolver::dnssec::fixtures; + #[test] fn copies_cd_bit_from_query_to_response() -> Result<()> { let network = &Network::new()?; @@ -21,3 +25,33 @@ fn copies_cd_bit_from_query_to_response() -> Result<()> { Ok(()) } + +#[test] +fn if_cd_bit_is_set_then_respond_with_data_that_fails_authentication() -> Result<()> { + let needle_fqdn = FQDN("example.nameservers.com.")?; + let needle_ipv4_addr = Ipv4Addr::new(1, 2, 3, 4); + + let (resolver, _graph) = + fixtures::bad_signature_in_leaf_nameserver(&needle_fqdn, needle_ipv4_addr)?; + + let resolver_addr = resolver.ipv4_addr(); + + let client = Client::new(resolver.network())?; + + let settings = *DigSettings::default() + .recurse() + .authentic_data() + .checking_disabled(); + let output = client.dig(settings, resolver_addr, RecordType::A, &needle_fqdn)?; + + assert!(output.status.is_noerror()); + assert!(!output.flags.authenticated_data); + + let [record] = output.answer.try_into().unwrap(); + let record = record.try_into_a().unwrap(); + + assert_eq!(needle_fqdn, record.fqdn); + assert_eq!(needle_ipv4_addr, record.ipv4_addr); + + Ok(()) +} diff --git a/packages/conformance-tests/src/resolver/dnssec/scenarios/bogus.rs b/packages/conformance-tests/src/resolver/dnssec/scenarios/bogus.rs index b41db3a3..c84ec51a 100644 --- a/packages/conformance-tests/src/resolver/dnssec/scenarios/bogus.rs +++ b/packages/conformance-tests/src/resolver/dnssec/scenarios/bogus.rs @@ -1,73 +1,29 @@ use std::net::Ipv4Addr; -use base64::prelude::*; use dns_test::client::{Client, DigSettings}; -use dns_test::name_server::{Graph, NameServer, Sign}; -use dns_test::record::{Record, RecordType}; -use dns_test::{Network, Resolver, Result, FQDN}; +use dns_test::record::RecordType; +use dns_test::{Result, FQDN}; +use crate::resolver::dnssec::fixtures; + +// TODO find out which RFC section states this #[ignore] #[test] -fn bad_signature_in_leaf_nameserver() -> Result<()> { - let expected_ipv4_addr = Ipv4Addr::new(1, 2, 3, 4); +fn if_cd_bit_is_clear_and_data_is_not_authentic_then_respond_with_servfail() -> Result<()> { let needle_fqdn = FQDN("example.nameservers.com.")?; + let needle_ipv4_addr = Ipv4Addr::new(1, 2, 3, 4); - let network = Network::new()?; + let (resolver, _graph) = + fixtures::bad_signature_in_leaf_nameserver(&needle_fqdn, needle_ipv4_addr)?; - let mut leaf_ns = NameServer::new(&dns_test::PEER, FQDN::NAMESERVERS, &network)?; - leaf_ns.add(Record::a(needle_fqdn.clone(), expected_ipv4_addr)); - - let Graph { - nameservers: _nameservers, - root, - trust_anchor, - } = Graph::build( - leaf_ns, - Sign::AndAmend(&|zone, records| { - if zone == &FQDN::NAMESERVERS { - let mut modified = 0; - for record in records { - if let Record::RRSIG(rrsig) = record { - if rrsig.fqdn == needle_fqdn { - let mut signature = BASE64_STANDARD.decode(&rrsig.signature).unwrap(); - let last = signature.last_mut().expect("empty signature"); - *last = !*last; - - rrsig.signature = BASE64_STANDARD.encode(&signature); - modified += 1; - } - } - } - - assert_eq!(modified, 1, "sanity check"); - } - }), - )?; - - let trust_anchor = &trust_anchor.unwrap(); - let resolver = Resolver::new(&network, root) - .trust_anchor(trust_anchor) - .start(&dns_test::SUBJECT)?; let resolver_addr = resolver.ipv4_addr(); - let client = Client::new(&network)?; + let client = Client::new(resolver.network())?; - let mut settings = *DigSettings::default().recurse().authentic_data(); + let settings = *DigSettings::default().recurse().authentic_data(); let output = client.dig(settings, resolver_addr, RecordType::A, &needle_fqdn)?; - // the resolver will try to validate the chain of trust; the validation fails so it responds - // with SERVFAIL assert!(output.status.is_servfail()); - // avoids a SERVFAIL response - settings.checking_disabled(); - - let output = client.dig(settings, resolver_addr, RecordType::A, &needle_fqdn)?; - - // when the CD (Checking Disabled) bit is set the server won't respond with SERVFAIL on - // validation errors. the outcome of the validation process is reported in the AD bit - assert!(output.status.is_noerror()); - assert!(!output.flags.authenticated_data); - Ok(()) } diff --git a/packages/dns-test/src/resolver.rs b/packages/dns-test/src/resolver.rs index 678c7b94..4abf28f8 100644 --- a/packages/dns-test/src/resolver.rs +++ b/packages/dns-test/src/resolver.rs @@ -31,6 +31,10 @@ impl Resolver { self.container.eavesdrop() } + pub fn network(&self) -> &Network { + self.container.network() + } + pub fn container_id(&self) -> &str { self.container.id() } diff --git a/packages/dns-test/src/zone_file/mod.rs b/packages/dns-test/src/zone_file/mod.rs index 57a6c29a..2c8c02b4 100644 --- a/packages/dns-test/src/zone_file/mod.rs +++ b/packages/dns-test/src/zone_file/mod.rs @@ -92,6 +92,7 @@ impl FromStr for ZoneFile { } /// A root (server) hint +#[derive(Clone)] pub struct Root { pub ipv4_addr: Ipv4Addr, pub ns: FQDN,