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 dns_test::client::{Client, Dnssec, Recurse};
use dns_test::client::{Client, DigSettings};
use dns_test::name_server::NameServer;
use dns_test::record::{Record, RecordType};
use dns_test::zone_file::Root;
@ -44,13 +44,9 @@ fn can_resolve() -> Result<()> {
let resolver_ip_addr = resolver.ipv4_addr();
let client = Client::new(&network)?;
let output = client.dig(
Recurse::Yes,
Dnssec::No,
resolver_ip_addr,
RecordType::A,
&needle_fqdn,
)?;
let settings = *DigSettings::default().recurse();
let output = client.dig(settings, resolver_ip_addr, RecordType::A, &needle_fqdn)?;
assert!(output.status.is_noerror());
@ -94,13 +90,8 @@ fn nxdomain() -> Result<()> {
let resolver_ip_addr = resolver.ipv4_addr();
let client = Client::new(&network)?;
let output = client.dig(
Recurse::Yes,
Dnssec::No,
resolver_ip_addr,
RecordType::A,
&needle_fqdn,
)?;
let settings = *DigSettings::default().recurse();
let output = client.dig(settings, resolver_ip_addr, RecordType::A, &needle_fqdn)?;
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::record::RecordType;
use dns_test::tshark::{Capture, Direction};
@ -20,13 +20,8 @@ fn edns_support() -> Result<()> {
let mut tshark = resolver.eavesdrop()?;
let client = Client::new(network)?;
let ans = client.dig(
Recurse::Yes,
Dnssec::Yes,
resolver.ipv4_addr(),
RecordType::SOA,
&FQDN::ROOT,
)?;
let settings = *DigSettings::default().authentic_data().recurse();
let ans = client.dig(settings, resolver.ipv4_addr(), RecordType::SOA, &FQDN::ROOT)?;
assert!(ans.status.is_servfail());
tshark.wait_for_capture()?;

View File

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

View File

@ -53,16 +53,17 @@ impl Client {
pub fn dig(
&self,
recurse: Recurse,
dnssec: Dnssec,
settings: DigSettings,
server: Ipv4Addr,
record_type: RecordType,
fqdn: &FQDN,
) -> Result<DigOutput> {
let output = self.inner.stdout(&[
"dig",
recurse.as_str(),
dnssec.as_str(),
settings.rdflag(),
settings.do_bit(),
settings.adflag(),
settings.cdflag(),
&format!("@{server}"),
record_type.as_str(),
fqdn.as_str(),
@ -72,32 +73,68 @@ impl Client {
}
}
#[derive(Clone, Copy)]
pub enum Dnssec {
Yes,
No,
#[derive(Clone, Copy, Default)]
pub struct DigSettings {
adflag: bool,
cdflag: bool,
dnssec: bool,
recurse: bool,
}
impl Dnssec {
fn as_str(&self) -> &'static str {
match self {
Self::Yes => "+dnssec",
Self::No => "+nodnssec",
impl DigSettings {
/// Sets the AD bit in the query
pub fn authentic_data(&mut self) -> &mut Self {
self.adflag = true;
self
}
fn adflag(&self) -> &'static str {
if self.adflag {
"+adflag"
} else {
"+noadflag"
}
}
}
#[derive(Clone, Copy)]
pub enum Recurse {
Yes,
No,
}
/// Sets the CD bit in the query
pub fn checking_disabled(&mut self) -> &mut Self {
self.cdflag = true;
self
}
impl Recurse {
fn as_str(&self) -> &'static str {
match self {
Self::Yes => "+recurse",
Self::No => "+norecurse",
fn cdflag(&self) -> &'static str {
if self.cdflag {
"+cdflag"
} else {
"+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)]
pub struct DigFlags {
pub qr: bool,
pub recursion_desired: bool,
pub recursion_available: bool,
pub authoritative_answer: 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 {
@ -200,6 +238,7 @@ impl FromStr for DigFlags {
let mut recursion_available = false;
let mut authoritative_answer = false;
let mut authenticated_data = false;
let mut checking_disabled = false;
for flag in input.split_whitespace() {
match flag {
@ -208,16 +247,18 @@ impl FromStr for DigFlags {
"ra" => recursion_available = true,
"aa" => authoritative_answer = true,
"ad" => authenticated_data = true,
"cd" => checking_disabled = true,
_ => return Err(format!("unknown flag: {flag}").into()),
}
}
Ok(Self {
qr,
recursion_desired,
recursion_available,
authoritative_answer,
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)]
mod tests {
use crate::client::{Client, Dnssec, Recurse};
use crate::client::{Client, DigSettings};
use crate::record::RecordType;
use super::*;
@ -307,13 +307,7 @@ mod tests {
let ip_addr = tld_ns.ipv4_addr();
let client = Client::new(&network)?;
let output = client.dig(
Recurse::No,
Dnssec::No,
ip_addr,
RecordType::SOA,
&FQDN::COM,
)?;
let output = client.dig(DigSettings::default(), ip_addr, RecordType::SOA, &FQDN::COM)?;
assert!(output.status.is_noerror());
@ -338,8 +332,7 @@ mod tests {
let client = Client::new(&network)?;
let output = client.dig(
Recurse::No,
Dnssec::No,
DigSettings::default(),
ipv4_addr,
RecordType::NS,
&FQDN::COM,
@ -364,13 +357,8 @@ mod tests {
let ns_addr = tld_ns.ipv4_addr();
let client = Client::new(&network)?;
let output = client.dig(
Recurse::No,
Dnssec::Yes,
ns_addr,
RecordType::SOA,
&FQDN::ROOT,
)?;
let settings = *DigSettings::default().dnssec();
let output = client.dig(settings, ns_addr, RecordType::SOA, &FQDN::ROOT)?;
assert!(output.status.is_noerror());

View File

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