From b96aa89da9ceb2fe591f1609953e652889a14847 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Thu, 7 Mar 2024 14:15:10 +0100 Subject: [PATCH] add more EDE tests --- .../src/resolver/dnssec/scenarios/ede.rs | 137 +++++++++++++++--- packages/dns-test/src/client.rs | 6 +- 2 files changed, 122 insertions(+), 21 deletions(-) diff --git a/packages/conformance-tests/src/resolver/dnssec/scenarios/ede.rs b/packages/conformance-tests/src/resolver/dnssec/scenarios/ede.rs index 1c30c7b3..ccae7178 100644 --- a/packages/conformance-tests/src/resolver/dnssec/scenarios/ede.rs +++ b/packages/conformance-tests/src/resolver/dnssec/scenarios/ede.rs @@ -8,25 +8,11 @@ use dns_test::{Network, Resolver, Result, FQDN}; #[ignore] #[test] fn dnskey_missing() -> Result<()> { - let subject = dns_test::subject(); - let supports_ede = subject.supports_ede(); - - let expected_ipv4_addr = Ipv4Addr::new(1, 2, 3, 4); - let needle_fqdn = FQDN("example.nameservers.com.")?; - - let network = Network::new()?; - 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| { - // remove the ZSK DNSKEY record + fixture( + ExtendedDnsError::DnskeyMissing, + |_needle_fqdn, zone, records| { if zone == &FQDN::NAMESERVERS { + // remove the DNSKEY record that contains the ZSK let mut remove_count = 0; *records = records .drain(..) @@ -44,8 +30,119 @@ fn dnskey_missing() -> Result<()> { !remove }) .collect(); - assert_eq!(1, remove_count); + assert_eq!(1, remove_count, "sanity check"); } + }, + ) +} + +#[ignore] +#[test] +fn rrsigs_missing() -> Result<()> { + fixture( + ExtendedDnsError::RrsigsMissing, + |needle_fqdn, zone, records| { + if zone == &FQDN::NAMESERVERS { + // remove the RRSIG records that covers the needle record + let mut remove_count = 0; + *records = records + .drain(..) + .filter(|record| { + let remove = if let Record::RRSIG(rrsig) = record { + rrsig.type_covered == RecordType::A && rrsig.fqdn == *needle_fqdn + } else { + false + }; + + if remove { + remove_count += 1; + } + + !remove + }) + .collect(); + assert_eq!(1, remove_count, "sanity check"); + } + }, + ) +} + +#[ignore] +#[test] +fn unsupported_dnskey_algorithm() -> Result<()> { + fixture( + ExtendedDnsError::UnsupportedDnskeyAlgorithm, + |needle_fqdn, zone, records| { + if zone == &FQDN::NAMESERVERS { + // lie about the algorithm that was used to sign the needle record + let mut modified_count = 0; + for record in records { + if let Record::RRSIG(rrsig) = record { + if rrsig.type_covered == RecordType::A && rrsig.fqdn == *needle_fqdn { + assert_ne!(1, rrsig.algorithm, "modify the value below"); + rrsig.algorithm = 1; + modified_count += 1; + } + } + } + assert_eq!(1, modified_count, "sanity check"); + } + }, + ) +} + +#[ignore] +#[test] +fn dnssec_bogus() -> Result<()> { + fixture( + ExtendedDnsError::DnssecBogus, + |needle_fqdn, zone, records| { + if zone == &FQDN::NAMESERVERS { + // corrupt the RRSIG record that covers the needle record + let mut modified_count = 0; + for record in records { + if let Record::RRSIG(rrsig) = record { + if rrsig.type_covered == RecordType::A && rrsig.fqdn == *needle_fqdn { + rrsig.signature_expiration = rrsig.signature_inception - 1; + modified_count += 1; + } + } + } + assert_eq!(1, modified_count, "sanity check"); + } + }, + ) +} + +// Sets up a minimal, DNSSEC-enabled DNS graph where the leaf zone contains a "needle" A record +// that we'll search for +// +// `amend` can be used to modify zone files *after* they have been signed. it's used to introduce +// errors in the signed zone files +// +// the query for the needle record is expected to fail with the `expected` Extended DNS Error +fn fixture( + expected: ExtendedDnsError, + amend: fn(needle_fqdn: &FQDN, zone: &FQDN, records: &mut Vec), +) -> Result<()> { + let subject = dns_test::subject(); + let supports_ede = subject.supports_ede(); + + let expected_ipv4_addr = Ipv4Addr::new(1, 2, 3, 4); + let needle_fqdn = FQDN("example.nameservers.com.")?; + + let network = Network::new()?; + 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| { + amend(&needle_fqdn, zone, records); }), )?; @@ -67,7 +164,7 @@ fn dnskey_missing() -> Result<()> { assert!(output.status.is_servfail()); if supports_ede { - assert_eq!(Some(ExtendedDnsError::DnskeyMissing), output.ede); + assert_eq!(Some(expected), output.ede); } Ok(()) diff --git a/packages/dns-test/src/client.rs b/packages/dns-test/src/client.rs index 3dd2a652..281eab82 100644 --- a/packages/dns-test/src/client.rs +++ b/packages/dns-test/src/client.rs @@ -255,8 +255,10 @@ impl FromStr for DigOutput { #[derive(Debug, PartialEq)] pub enum ExtendedDnsError { - DnssecBogus, DnskeyMissing, + DnssecBogus, + RrsigsMissing, + UnsupportedDnskeyAlgorithm, } impl FromStr for ExtendedDnsError { @@ -266,8 +268,10 @@ impl FromStr for ExtendedDnsError { let code: u16 = input.parse()?; let code = match code { + 1 => Self::UnsupportedDnskeyAlgorithm, 6 => Self::DnssecBogus, 9 => Self::DnskeyMissing, + 10 => Self::RrsigsMissing, _ => todo!("EDE {code} has not yet been implemented"), };