Merge pull request #120 from razvandimescu/feat/named-record-types

feat(question): name SVCB/LOC/NAPTR record types in logs
This commit was merged in pull request #120.
This commit is contained in:
Razvan Dimescu
2026-04-19 08:08:54 +03:00
committed by GitHub
2 changed files with 63 additions and 112 deletions

View File

@@ -511,13 +511,12 @@ fn strip_dnssec_records(pkt: &mut DnsPacket) {
pkt.resources.retain(|r| !is_dnssec_record(r)); pkt.resources.retain(|r| !is_dnssec_record(r));
} }
const SVCB_QTYPE: u16 = 64;
fn strip_svcb_ipv6_hints(pkt: &mut DnsPacket) { fn strip_svcb_ipv6_hints(pkt: &mut DnsPacket) {
let https_qtype = QueryType::HTTPS.to_num(); let https_qtype = QueryType::HTTPS.to_num();
let svcb_qtype = QueryType::SVCB.to_num();
pkt.for_each_record_mut(|rec| { pkt.for_each_record_mut(|rec| {
if let DnsRecord::UNKNOWN { qtype, data, .. } = rec { if let DnsRecord::UNKNOWN { qtype, data, .. } = rec {
if *qtype == https_qtype || *qtype == SVCB_QTYPE { if *qtype == https_qtype || *qtype == svcb_qtype {
if let Some(new_data) = crate::svcb::strip_ipv6hint(data) { if let Some(new_data) = crate::svcb::strip_ipv6hint(data) {
*data = new_data; *data = new_data;
} }
@@ -1307,7 +1306,7 @@ mod tests {
let mut svcb_pkt = pkt.clone(); let mut svcb_pkt = pkt.clone();
svcb_pkt.questions[0].name = "svc.test".to_string(); svcb_pkt.questions[0].name = "svc.test".to_string();
svcb_pkt.questions[0].qtype = QueryType::UNKNOWN(64); svcb_pkt.questions[0].qtype = QueryType::SVCB;
if let DnsRecord::UNKNOWN { domain, qtype, .. } = &mut svcb_pkt.answers[0] { if let DnsRecord::UNKNOWN { domain, qtype, .. } = &mut svcb_pkt.answers[0] {
*domain = "svc.test".to_string(); *domain = "svc.test".to_string();
*qtype = 64; *qtype = 64;
@@ -1322,12 +1321,12 @@ mod tests {
ctx.cache ctx.cache
.write() .write()
.unwrap() .unwrap()
.insert("svc.test", QueryType::UNKNOWN(64), &svcb_pkt); .insert("svc.test", QueryType::SVCB, &svcb_pkt);
let ctx = Arc::new(ctx); let ctx = Arc::new(ctx);
for (name, qtype, label) in [ for (name, qtype, label) in [
("hints.test", QueryType::HTTPS, "HTTPS"), ("hints.test", QueryType::HTTPS, "HTTPS"),
("svc.test", QueryType::UNKNOWN(64), "SVCB"), ("svc.test", QueryType::SVCB, "SVCB"),
] { ] {
let (resp, path) = resolve_in_test(&ctx, name, qtype).await; let (resp, path) = resolve_in_test(&ctx, name, qtype).await;
assert_eq!(path, QueryPath::Cached, "{label}"); assert_eq!(path, QueryPath::Cached, "{label}");

View File

@@ -1,115 +1,67 @@
use crate::buffer::BytePacketBuffer; use crate::buffer::BytePacketBuffer;
use crate::Result; use crate::Result;
macro_rules! define_qtypes {
( $( $variant:ident = $num:literal, $str:literal ),* $(,)? ) => {
#[derive(PartialEq, Eq, Debug, Clone, Hash, Copy)] #[derive(PartialEq, Eq, Debug, Clone, Hash, Copy)]
pub enum QueryType { pub enum QueryType {
UNKNOWN(u16), UNKNOWN(u16),
A, // 1 $( $variant, )*
NS, // 2
CNAME, // 5
SOA, // 6
PTR, // 12
MX, // 15
TXT, // 16
AAAA, // 28
SRV, // 33
DS, // 43
RRSIG, // 46
NSEC, // 47
DNSKEY, // 48
NSEC3, // 50
OPT, // 41 (EDNS0 pseudo-type)
HTTPS, // 65
} }
impl QueryType { impl QueryType {
pub fn to_num(&self) -> u16 { pub fn to_num(&self) -> u16 {
match *self { match *self {
QueryType::UNKNOWN(x) => x, QueryType::UNKNOWN(x) => x,
QueryType::A => 1, $( QueryType::$variant => $num, )*
QueryType::NS => 2,
QueryType::CNAME => 5,
QueryType::SOA => 6,
QueryType::PTR => 12,
QueryType::MX => 15,
QueryType::TXT => 16,
QueryType::AAAA => 28,
QueryType::SRV => 33,
QueryType::OPT => 41,
QueryType::DS => 43,
QueryType::RRSIG => 46,
QueryType::NSEC => 47,
QueryType::DNSKEY => 48,
QueryType::NSEC3 => 50,
QueryType::HTTPS => 65,
} }
} }
pub fn from_num(num: u16) -> QueryType { pub fn from_num(num: u16) -> QueryType {
match num { match num {
1 => QueryType::A, $( $num => QueryType::$variant, )*
2 => QueryType::NS,
5 => QueryType::CNAME,
6 => QueryType::SOA,
12 => QueryType::PTR,
15 => QueryType::MX,
16 => QueryType::TXT,
28 => QueryType::AAAA,
33 => QueryType::SRV,
41 => QueryType::OPT,
43 => QueryType::DS,
46 => QueryType::RRSIG,
47 => QueryType::NSEC,
48 => QueryType::DNSKEY,
50 => QueryType::NSEC3,
65 => QueryType::HTTPS,
_ => QueryType::UNKNOWN(num), _ => QueryType::UNKNOWN(num),
} }
} }
pub fn as_str(&self) -> &'static str { pub fn as_str(&self) -> &'static str {
match self { match self {
QueryType::A => "A",
QueryType::NS => "NS",
QueryType::CNAME => "CNAME",
QueryType::SOA => "SOA",
QueryType::PTR => "PTR",
QueryType::MX => "MX",
QueryType::TXT => "TXT",
QueryType::AAAA => "AAAA",
QueryType::SRV => "SRV",
QueryType::OPT => "OPT",
QueryType::DS => "DS",
QueryType::RRSIG => "RRSIG",
QueryType::NSEC => "NSEC",
QueryType::DNSKEY => "DNSKEY",
QueryType::NSEC3 => "NSEC3",
QueryType::HTTPS => "HTTPS",
QueryType::UNKNOWN(_) => "UNKNOWN", QueryType::UNKNOWN(_) => "UNKNOWN",
$( QueryType::$variant => $str, )*
} }
} }
pub fn parse_str(s: &str) -> Option<QueryType> { pub fn parse_str(s: &str) -> Option<QueryType> {
match s.to_ascii_uppercase().as_str() { match s.to_ascii_uppercase().as_str() {
"A" => Some(QueryType::A), $( $str => Some(QueryType::$variant), )*
"NS" => Some(QueryType::NS),
"CNAME" => Some(QueryType::CNAME),
"SOA" => Some(QueryType::SOA),
"PTR" => Some(QueryType::PTR),
"MX" => Some(QueryType::MX),
"TXT" => Some(QueryType::TXT),
"AAAA" => Some(QueryType::AAAA),
"SRV" => Some(QueryType::SRV),
"DS" => Some(QueryType::DS),
"RRSIG" => Some(QueryType::RRSIG),
"DNSKEY" => Some(QueryType::DNSKEY),
"NSEC" => Some(QueryType::NSEC),
"NSEC3" => Some(QueryType::NSEC3),
"HTTPS" => Some(QueryType::HTTPS),
_ => None, _ => None,
} }
} }
} }
};
}
define_qtypes! {
A = 1, "A",
NS = 2, "NS",
CNAME = 5, "CNAME",
SOA = 6, "SOA",
PTR = 12, "PTR",
MX = 15, "MX",
TXT = 16, "TXT",
AAAA = 28, "AAAA",
LOC = 29, "LOC",
SRV = 33, "SRV",
NAPTR = 35, "NAPTR",
OPT = 41, "OPT",
DS = 43, "DS",
RRSIG = 46, "RRSIG",
NSEC = 47, "NSEC",
DNSKEY = 48, "DNSKEY",
NSEC3 = 50, "NSEC3",
SVCB = 64, "SVCB",
HTTPS = 65, "HTTPS",
}
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct DnsQuestion { pub struct DnsQuestion {