Merge pull request #31 from ferrous-systems/ja-explore-opt-in-dnssec

`explore`: make DNSSEC opt-in
This commit is contained in:
Jorge Aparicio 2024-05-22 14:31:40 +02:00 committed by GitHub
commit 3a54e693fa
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -1,3 +1,5 @@
use std::env;
use std::net::Ipv4Addr;
use std::sync::mpsc; use std::sync::mpsc;
use dns_test::client::Client; use dns_test::client::Client;
@ -7,6 +9,8 @@ use dns_test::zone_file::Root;
use dns_test::{Network, Resolver, Result, TrustAnchor, FQDN}; use dns_test::{Network, Resolver, Result, TrustAnchor, FQDN};
fn main() -> Result<()> { fn main() -> Result<()> {
let args = Args::from_env()?;
let network = Network::new()?; let network = Network::new()?;
let peer = &dns_test::PEER; let peer = &dns_test::PEER;
@ -21,32 +25,60 @@ fn main() -> Result<()> {
nameservers_ns nameservers_ns
.add(Record::a(root_ns.fqdn().clone(), root_ns.ipv4_addr())) .add(Record::a(root_ns.fqdn().clone(), root_ns.ipv4_addr()))
.add(Record::a(com_ns.fqdn().clone(), com_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 let nameservers_ns = if args.dnssec {
.referral( let nameservers_ns = nameservers_ns.sign()?;
nameservers_ns.zone().clone(), com_ns.add(nameservers_ns.ds().clone());
nameservers_ns.fqdn().clone(), nameservers_ns.start()?
nameservers_ns.ipv4_addr(), } else {
) nameservers_ns.start()?
.add(nameservers_ds); };
let com_ns = com_ns.sign()?;
let com_ds = com_ns.ds().clone();
let com_ns = com_ns.start()?;
root_ns com_ns.referral(
.referral(FQDN::COM, com_ns.fqdn().clone(), com_ns.ipv4_addr()) nameservers_ns.zone().clone(),
.add(com_ds); nameservers_ns.fqdn().clone(),
let root_ns = root_ns.sign()?; nameservers_ns.ipv4_addr(),
let root_ksk = root_ns.key_signing_key().clone(); );
let root_zsk = root_ns.zone_signing_key().clone();
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"); println!("DONE");
let trust_anchor = TrustAnchor::from_iter([root_ksk.clone(), root_zsk.clone()]); 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..."); println!("building docker image...");
let resolver = Resolver::new( let resolver = Resolver::new(
&network, &network,
@ -56,11 +88,6 @@ fn main() -> Result<()> {
.start(&dns_test::SUBJECT)?; .start(&dns_test::SUBJECT)?;
println!("DONE\n\n"); println!("DONE\n\n");
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)?;
let (tx, rx) = mpsc::channel(); let (tx, rx) = mpsc::channel();
ctrlc::set_handler(move || tx.send(()).expect("could not forward signal"))?; ctrlc::set_handler(move || tx.send(()).expect("could not forward signal"))?;
@ -86,7 +113,8 @@ fn main() -> Result<()> {
nameservers_ns.container_id() 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!( println!(
"attach to this container with: `docker exec -it {} bash`\n", "attach to this container with: `docker exec -it {} bash`\n",
resolver.container_id() resolver.container_id()
@ -99,10 +127,13 @@ fn main() -> Result<()> {
); );
println!("example queries (run these in the client container):\n"); println!("example queries (run these in the client container):\n");
println!("`dig @{resolver_addr} SOA .`\n"); let adflag = if args.dnssec { "+adflag" } else { "+noadflag" };
println!( println!("`dig @{resolver_addr} {adflag} SOA .`\n");
"`delv -a /etc/bind.keys @{resolver_addr} SOA .` (you MUST use the `-a` flag with delv)\n\n" if args.dnssec {
); println!(
"`delv -a /etc/bind.keys @{resolver_addr} SOA .` (you MUST use the `-a` flag with delv)\n\n"
);
}
println!( println!(
"to print the DNS traffic flowing through the resolver run this command in "to print the DNS traffic flowing through the resolver run this command in
@ -118,3 +149,38 @@ the resolver container before performing queries:\n"
Ok(()) Ok(())
} }
struct Args {
dnssec: bool,
}
impl Args {
fn from_env() -> Result<Self> {
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<T>() -> Result<T> {
eprintln!(
"usage: explore [--dnssec]
Options:
--dnssec sign zone files to enable DNSSEC"
);
Err("CLI error".into())
}