From 1aab8812df518978b27bec5768df764b3ccf0749 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 1 Mar 2024 19:08:28 +0100 Subject: [PATCH 1/2] `explore`: make DNSSEC opt-in --- packages/dns-test/examples/explore.rs | 113 ++++++++++++++++++++------ 1 file changed, 86 insertions(+), 27 deletions(-) diff --git a/packages/dns-test/examples/explore.rs b/packages/dns-test/examples/explore.rs index 277e16b9..0047bf7e 100644 --- a/packages/dns-test/examples/explore.rs +++ b/packages/dns-test/examples/explore.rs @@ -1,3 +1,4 @@ +use std::env; use std::sync::mpsc; use dns_test::client::Client; @@ -7,6 +8,8 @@ use dns_test::zone_file::Root; use dns_test::{Network, Resolver, Result, TrustAnchor, FQDN}; fn main() -> Result<()> { + let args = Args::from_env()?; + let network = Network::new()?; let peer = &dns_test::PEER; @@ -21,32 +24,47 @@ fn main() -> Result<()> { nameservers_ns .add(Record::a(root_ns.fqdn().clone(), root_ns.ipv4_addr())) .add(Record::a(com_ns.fqdn().clone(), com_ns.ipv4_addr())); - let nameservers_ns = nameservers_ns.sign()?; - let nameservers_ds = nameservers_ns.ds().clone(); - let nameservers_ns = nameservers_ns.start()?; - com_ns - .referral( - nameservers_ns.zone().clone(), - nameservers_ns.fqdn().clone(), - nameservers_ns.ipv4_addr(), - ) - .add(nameservers_ds); - let com_ns = com_ns.sign()?; - let com_ds = com_ns.ds().clone(); - let com_ns = com_ns.start()?; + let nameservers_ns = if args.dnssec { + let nameservers_ns = nameservers_ns.sign()?; + com_ns.add(nameservers_ns.ds().clone()); + nameservers_ns.start()? + } else { + nameservers_ns.start()? + }; - root_ns - .referral(FQDN::COM, com_ns.fqdn().clone(), com_ns.ipv4_addr()) - .add(com_ds); - let root_ns = root_ns.sign()?; - let root_ksk = root_ns.key_signing_key().clone(); - let root_zsk = root_ns.zone_signing_key().clone(); + com_ns.referral( + nameservers_ns.zone().clone(), + nameservers_ns.fqdn().clone(), + nameservers_ns.ipv4_addr(), + ); + + let com_ns = if args.dnssec { + let com_ns = com_ns.sign()?; + root_ns.add(com_ns.ds().clone()); + com_ns.start()? + } else { + com_ns.start()? + }; + + root_ns.referral(FQDN::COM, com_ns.fqdn().clone(), com_ns.ipv4_addr()); + + let mut trust_anchor = TrustAnchor::empty(); + let root_ns = if args.dnssec { + let root_ns = root_ns.sign()?; + let root_ksk = root_ns.key_signing_key(); + let root_zsk = root_ns.zone_signing_key(); + + trust_anchor.add(root_ksk.clone()); + trust_anchor.add(root_zsk.clone()); + + root_ns.start()? + } else { + root_ns.start()? + }; - let root_ns = root_ns.start()?; println!("DONE"); - let trust_anchor = TrustAnchor::from_iter([root_ksk.clone(), root_zsk.clone()]); println!("building docker image..."); let resolver = Resolver::new( &network, @@ -58,8 +76,11 @@ fn main() -> Result<()> { let resolver_addr = resolver.ipv4_addr(); let client = Client::new(&network)?; - // generate `/etc/bind.keys` - client.delv(resolver_addr, RecordType::SOA, &FQDN::ROOT, &trust_anchor)?; + + if args.dnssec { + // generate `/etc/bind.keys` + client.delv(resolver_addr, RecordType::SOA, &FQDN::ROOT, &trust_anchor)?; + } let (tx, rx) = mpsc::channel(); @@ -99,10 +120,13 @@ fn main() -> Result<()> { ); println!("example queries (run these in the client container):\n"); - println!("`dig @{resolver_addr} SOA .`\n"); - println!( - "`delv -a /etc/bind.keys @{resolver_addr} SOA .` (you MUST use the `-a` flag with delv)\n\n" - ); + let adflag = if args.dnssec { "+adflag" } else { "+noadflag" }; + println!("`dig @{resolver_addr} {adflag} SOA .`\n"); + if args.dnssec { + println!( + "`delv -a /etc/bind.keys @{resolver_addr} SOA .` (you MUST use the `-a` flag with delv)\n\n" + ); + } println!( "to print the DNS traffic flowing through the resolver run this command in @@ -118,3 +142,38 @@ the resolver container before performing queries:\n" Ok(()) } + +struct Args { + dnssec: bool, +} + +impl Args { + fn from_env() -> Result { + let args: Vec<_> = env::args().skip(1).collect(); + let num_args = args.len(); + + let dnssec = if num_args == 0 { + false + } else if num_args == 1 { + if args[0] == "--dnssec" { + true + } else { + return cli_error(); + } + } else { + return cli_error(); + }; + + Ok(Self { dnssec }) + } +} + +fn cli_error() -> Result { + eprintln!( + "usage: explore [--dnssec] +Options: + --dnssec sign zone files to enable DNSSEC" + ); + + Err("CLI error".into()) +} From 5d15aa222820309894ee78ac8885a38df594dcaa Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 1 Mar 2024 19:13:58 +0100 Subject: [PATCH 2/2] `explore`: generate `bind.keys` w/o querying resolver this avoids the resolver caching any query. that way `tshark` can observe all the messages involved in DNSSEC validating a query "from scratch" --- packages/dns-test/examples/explore.rs | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/packages/dns-test/examples/explore.rs b/packages/dns-test/examples/explore.rs index 0047bf7e..bc13d63a 100644 --- a/packages/dns-test/examples/explore.rs +++ b/packages/dns-test/examples/explore.rs @@ -1,4 +1,5 @@ use std::env; +use std::net::Ipv4Addr; use std::sync::mpsc; use dns_test::client::Client; @@ -65,6 +66,19 @@ fn main() -> Result<()> { println!("DONE"); + let client = Client::new(&network)?; + if args.dnssec { + // this will send queries to the loopback address and fail because there's no resolver + // but as a side-effect it will generate the `/etc/bind.keys` file we want + // ignore the expected error + let _ = client.delv( + Ipv4Addr::new(127, 0, 0, 1), + RecordType::SOA, + &FQDN::ROOT, + &trust_anchor, + )?; + } + println!("building docker image..."); let resolver = Resolver::new( &network, @@ -74,14 +88,6 @@ fn main() -> Result<()> { .start(&dns_test::SUBJECT)?; println!("DONE\n\n"); - let resolver_addr = resolver.ipv4_addr(); - let client = Client::new(&network)?; - - if args.dnssec { - // generate `/etc/bind.keys` - client.delv(resolver_addr, RecordType::SOA, &FQDN::ROOT, &trust_anchor)?; - } - let (tx, rx) = mpsc::channel(); ctrlc::set_handler(move || tx.send(()).expect("could not forward signal"))?; @@ -107,7 +113,8 @@ fn main() -> Result<()> { nameservers_ns.container_id() ); - println!("resolver's IP address: {resolver_addr}"); + let resolver_addr = resolver.ipv4_addr(); + println!("resolver's IP address: {resolver_addr}",); println!( "attach to this container with: `docker exec -it {} bash`\n", resolver.container_id()