make dig queries more configurable

switch from enum arguments like `Recurse` and `Dnssec` to a
build-pattern-based `Settings` struct
This commit is contained in:
Jorge Aparicio 2024-02-20 15:06:59 +01:00
parent df344e57b1
commit b87ae21d2a
6 changed files with 97 additions and 98 deletions

View File

@ -1,6 +1,6 @@
use std::net::Ipv4Addr; use std::net::Ipv4Addr;
use dns_test::client::{Client, Dnssec, Recurse}; use dns_test::client::{Client, DigSettings};
use dns_test::name_server::NameServer; use dns_test::name_server::NameServer;
use dns_test::record::{Record, RecordType}; use dns_test::record::{Record, RecordType};
use dns_test::zone_file::Root; use dns_test::zone_file::Root;
@ -44,13 +44,9 @@ fn can_resolve() -> Result<()> {
let resolver_ip_addr = resolver.ipv4_addr(); let resolver_ip_addr = resolver.ipv4_addr();
let client = Client::new(&network)?; let client = Client::new(&network)?;
let output = client.dig(
Recurse::Yes, let settings = *DigSettings::default().recurse();
Dnssec::No, let output = client.dig(settings, resolver_ip_addr, RecordType::A, &needle_fqdn)?;
resolver_ip_addr,
RecordType::A,
&needle_fqdn,
)?;
assert!(output.status.is_noerror()); assert!(output.status.is_noerror());
@ -94,13 +90,8 @@ fn nxdomain() -> Result<()> {
let resolver_ip_addr = resolver.ipv4_addr(); let resolver_ip_addr = resolver.ipv4_addr();
let client = Client::new(&network)?; let client = Client::new(&network)?;
let output = client.dig( let settings = *DigSettings::default().recurse();
Recurse::Yes, let output = client.dig(settings, resolver_ip_addr, RecordType::A, &needle_fqdn)?;
Dnssec::No,
resolver_ip_addr,
RecordType::A,
&needle_fqdn,
)?;
assert!(dbg!(output).status.is_nxdomain()); assert!(dbg!(output).status.is_nxdomain());

View File

@ -1,4 +1,4 @@
use dns_test::client::{Client, Dnssec, Recurse}; use dns_test::client::{Client, DigSettings};
use dns_test::name_server::NameServer; use dns_test::name_server::NameServer;
use dns_test::record::RecordType; use dns_test::record::RecordType;
use dns_test::tshark::{Capture, Direction}; use dns_test::tshark::{Capture, Direction};
@ -20,13 +20,8 @@ fn edns_support() -> Result<()> {
let mut tshark = resolver.eavesdrop()?; let mut tshark = resolver.eavesdrop()?;
let client = Client::new(network)?; let client = Client::new(network)?;
let ans = client.dig( let settings = *DigSettings::default().authentic_data().recurse();
Recurse::Yes, let ans = client.dig(settings, resolver.ipv4_addr(), RecordType::SOA, &FQDN::ROOT)?;
Dnssec::Yes,
resolver.ipv4_addr(),
RecordType::SOA,
&FQDN::ROOT,
)?;
assert!(ans.status.is_servfail()); assert!(ans.status.is_servfail());
tshark.wait_for_capture()?; tshark.wait_for_capture()?;

View File

@ -1,6 +1,6 @@
use std::net::Ipv4Addr; use std::net::Ipv4Addr;
use dns_test::client::{Client, Dnssec, Recurse}; use dns_test::client::{Client, DigSettings};
use dns_test::name_server::NameServer; use dns_test::name_server::NameServer;
use dns_test::record::{Record, RecordType}; use dns_test::record::{Record, RecordType};
use dns_test::zone_file::Root; use dns_test::zone_file::Root;
@ -31,13 +31,8 @@ fn can_validate_without_delegation() -> Result<()> {
let resolver_addr = resolver.ipv4_addr(); let resolver_addr = resolver.ipv4_addr();
let client = Client::new(&network)?; let client = Client::new(&network)?;
let output = client.dig( let settings = *DigSettings::default().recurse().authentic_data();
Recurse::Yes, let output = client.dig(settings, resolver_addr, RecordType::SOA, &FQDN::ROOT)?;
Dnssec::Yes,
resolver_addr,
RecordType::SOA,
&FQDN::ROOT,
)?;
assert!(output.status.is_noerror()); assert!(output.status.is_noerror());
assert!(output.flags.authenticated_data); assert!(output.flags.authenticated_data);
@ -103,19 +98,14 @@ fn can_validate_with_delegation() -> Result<()> {
let resolver_addr = resolver.ipv4_addr(); let resolver_addr = resolver.ipv4_addr();
let client = Client::new(&network)?; let client = Client::new(&network)?;
let output = client.dig( let settings = *DigSettings::default().recurse().authentic_data();
Recurse::Yes, let output = client.dig(settings, resolver_addr, RecordType::A, &needle_fqdn)?;
Dnssec::Yes,
resolver_addr,
RecordType::A,
&needle_fqdn,
)?;
assert!(output.status.is_noerror()); assert!(output.status.is_noerror());
assert!(output.flags.authenticated_data); assert!(output.flags.authenticated_data);
let [a, _rrsig] = output.answer.try_into().unwrap(); let [a] = output.answer.try_into().unwrap();
let a = a.try_into_a().unwrap(); let a = a.try_into_a().unwrap();
assert_eq!(needle_fqdn, a.fqdn); assert_eq!(needle_fqdn, a.fqdn);

View File

@ -53,16 +53,17 @@ impl Client {
pub fn dig( pub fn dig(
&self, &self,
recurse: Recurse, settings: DigSettings,
dnssec: Dnssec,
server: Ipv4Addr, server: Ipv4Addr,
record_type: RecordType, record_type: RecordType,
fqdn: &FQDN, fqdn: &FQDN,
) -> Result<DigOutput> { ) -> Result<DigOutput> {
let output = self.inner.stdout(&[ let output = self.inner.stdout(&[
"dig", "dig",
recurse.as_str(), settings.rdflag(),
dnssec.as_str(), settings.do_bit(),
settings.adflag(),
settings.cdflag(),
&format!("@{server}"), &format!("@{server}"),
record_type.as_str(), record_type.as_str(),
fqdn.as_str(), fqdn.as_str(),
@ -72,32 +73,68 @@ impl Client {
} }
} }
#[derive(Clone, Copy)] #[derive(Clone, Copy, Default)]
pub enum Dnssec { pub struct DigSettings {
Yes, adflag: bool,
No, cdflag: bool,
dnssec: bool,
recurse: bool,
} }
impl Dnssec { impl DigSettings {
fn as_str(&self) -> &'static str { /// Sets the AD bit in the query
match self { pub fn authentic_data(&mut self) -> &mut Self {
Self::Yes => "+dnssec", self.adflag = true;
Self::No => "+nodnssec", self
}
fn adflag(&self) -> &'static str {
if self.adflag {
"+adflag"
} else {
"+noadflag"
} }
} }
}
#[derive(Clone, Copy)] /// Sets the CD bit in the query
pub enum Recurse { pub fn checking_disabled(&mut self) -> &mut Self {
Yes, self.cdflag = true;
No, self
} }
impl Recurse { fn cdflag(&self) -> &'static str {
fn as_str(&self) -> &'static str { if self.cdflag {
match self { "+cdflag"
Self::Yes => "+recurse", } else {
Self::No => "+norecurse", "+nocdflag"
}
}
/// Sets the DO bit in the query
pub fn dnssec(&mut self) -> &mut Self {
self.dnssec = true;
self
}
fn do_bit(&self) -> &'static str {
if self.dnssec {
"+dnssec"
} else {
"+nodnssec"
}
}
/// Sets the RD bit in the query
pub fn recurse(&mut self) -> &mut Self {
self.recurse = true;
self
}
fn rdflag(&self) -> &'static str {
if self.recurse {
"+recurse"
} else {
"+norecurse"
} }
} }
} }
@ -184,11 +221,12 @@ impl FromStr for DigOutput {
#[derive(Debug, Default, PartialEq)] #[derive(Debug, Default, PartialEq)]
pub struct DigFlags { pub struct DigFlags {
pub qr: bool,
pub recursion_desired: bool,
pub recursion_available: bool,
pub authoritative_answer: bool,
pub authenticated_data: bool, pub authenticated_data: bool,
pub authoritative_answer: bool,
pub checking_disabled: bool,
pub qr: bool,
pub recursion_available: bool,
pub recursion_desired: bool,
} }
impl FromStr for DigFlags { impl FromStr for DigFlags {
@ -200,6 +238,7 @@ impl FromStr for DigFlags {
let mut recursion_available = false; let mut recursion_available = false;
let mut authoritative_answer = false; let mut authoritative_answer = false;
let mut authenticated_data = false; let mut authenticated_data = false;
let mut checking_disabled = false;
for flag in input.split_whitespace() { for flag in input.split_whitespace() {
match flag { match flag {
@ -208,16 +247,18 @@ impl FromStr for DigFlags {
"ra" => recursion_available = true, "ra" => recursion_available = true,
"aa" => authoritative_answer = true, "aa" => authoritative_answer = true,
"ad" => authenticated_data = true, "ad" => authenticated_data = true,
"cd" => checking_disabled = true,
_ => return Err(format!("unknown flag: {flag}").into()), _ => return Err(format!("unknown flag: {flag}").into()),
} }
} }
Ok(Self { Ok(Self {
qr,
recursion_desired,
recursion_available,
authoritative_answer,
authenticated_data, authenticated_data,
authoritative_answer,
checking_disabled,
qr,
recursion_available,
recursion_desired,
}) })
} }
} }

View File

@ -295,7 +295,7 @@ fn nsd_conf(fqdn: &FQDN) -> String {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::client::{Client, Dnssec, Recurse}; use crate::client::{Client, DigSettings};
use crate::record::RecordType; use crate::record::RecordType;
use super::*; use super::*;
@ -307,13 +307,7 @@ mod tests {
let ip_addr = tld_ns.ipv4_addr(); let ip_addr = tld_ns.ipv4_addr();
let client = Client::new(&network)?; let client = Client::new(&network)?;
let output = client.dig( let output = client.dig(DigSettings::default(), ip_addr, RecordType::SOA, &FQDN::COM)?;
Recurse::No,
Dnssec::No,
ip_addr,
RecordType::SOA,
&FQDN::COM,
)?;
assert!(output.status.is_noerror()); assert!(output.status.is_noerror());
@ -338,8 +332,7 @@ mod tests {
let client = Client::new(&network)?; let client = Client::new(&network)?;
let output = client.dig( let output = client.dig(
Recurse::No, DigSettings::default(),
Dnssec::No,
ipv4_addr, ipv4_addr,
RecordType::NS, RecordType::NS,
&FQDN::COM, &FQDN::COM,
@ -364,13 +357,8 @@ mod tests {
let ns_addr = tld_ns.ipv4_addr(); let ns_addr = tld_ns.ipv4_addr();
let client = Client::new(&network)?; let client = Client::new(&network)?;
let output = client.dig( let settings = *DigSettings::default().dnssec();
Recurse::No, let output = client.dig(settings, ns_addr, RecordType::SOA, &FQDN::ROOT)?;
Dnssec::Yes,
ns_addr,
RecordType::SOA,
&FQDN::ROOT,
)?;
assert!(output.status.is_noerror()); assert!(output.status.is_noerror());

View File

@ -244,7 +244,7 @@ struct Ip {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::client::{Client, Dnssec, Recurse}; use crate::client::{Client, DigSettings};
use crate::name_server::NameServer; use crate::name_server::NameServer;
use crate::record::{Record, RecordType}; use crate::record::{Record, RecordType};
use crate::zone_file::Root; use crate::zone_file::Root;
@ -260,8 +260,7 @@ mod tests {
let client = Client::new(network)?; let client = Client::new(network)?;
let resp = client.dig( let resp = client.dig(
Recurse::No, DigSettings::default(),
Dnssec::No,
ns.ipv4_addr(), ns.ipv4_addr(),
RecordType::SOA, RecordType::SOA,
&FQDN::ROOT, &FQDN::ROOT,
@ -322,13 +321,8 @@ mod tests {
let resolver_addr = resolver.ipv4_addr(); let resolver_addr = resolver.ipv4_addr();
let client = Client::new(network)?; let client = Client::new(network)?;
let output = client.dig( let settings = *DigSettings::default().recurse();
Recurse::Yes, let output = client.dig(settings, dbg!(resolver_addr), RecordType::A, root_ns.fqdn())?;
Dnssec::No,
dbg!(resolver_addr),
RecordType::A,
root_ns.fqdn(),
)?;
assert!(output.status.is_noerror()); assert!(output.status.is_noerror());