fix(packet): parse SOA natively to stop malformed replies (#128)
SOA records were stored as opaque bytes (DnsRecord::UNKNOWN), so the
RFC 1035 §3.3.13 MNAME/RNAME name-compression pointers — offsets into
the upstream packet — were re-emitted verbatim. Once Numa applied its
own compression to surrounding names, those pointers landed on garbage
and clients rejected the reply ("malformed reply packet" in kdig).
Parse SOA via read_qname and write via write_qname, matching the
NS/CNAME/MX pattern. Adds the canonical-rdata arm in dnssec.rs for
RRSIG verification. Regression test round-trips a CNAME-chain response
with a compressed SOA in authority through hickory-proto strict parse.
This commit is contained in:
@@ -882,6 +882,28 @@ fn record_rdata_canonical(record: &DnsRecord) -> Vec<u8> {
|
||||
rdata.extend(type_bitmap);
|
||||
rdata
|
||||
}
|
||||
DnsRecord::SOA {
|
||||
mname,
|
||||
rname,
|
||||
serial,
|
||||
refresh,
|
||||
retry,
|
||||
expire,
|
||||
minimum,
|
||||
..
|
||||
} => {
|
||||
let mname_wire = name_to_wire(mname);
|
||||
let rname_wire = name_to_wire(rname);
|
||||
let mut rdata = Vec::with_capacity(mname_wire.len() + rname_wire.len() + 20);
|
||||
rdata.extend(&mname_wire);
|
||||
rdata.extend(&rname_wire);
|
||||
rdata.extend(&serial.to_be_bytes());
|
||||
rdata.extend(&refresh.to_be_bytes());
|
||||
rdata.extend(&retry.to_be_bytes());
|
||||
rdata.extend(&expire.to_be_bytes());
|
||||
rdata.extend(&minimum.to_be_bytes());
|
||||
rdata
|
||||
}
|
||||
DnsRecord::UNKNOWN { data, .. } => data.clone(),
|
||||
DnsRecord::RRSIG { .. } => Vec::new(),
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user