1#[cfg(fuzzing)]
21use arbitrary::Arbitrary;
22use std::fmt;
23
24#[derive(Eq, Ord, PartialOrd, PartialEq, Clone, Copy)]
25#[cfg_attr(fuzzing, derive(Arbitrary))]
26pub struct Class(pub u16);
27
28pub const CLASS_IN: Class = Class(1); pub const CLASS_CH: Class = Class(3); impl fmt::Display for Class {
32 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
33 match self {
34 &CLASS_IN => write!(f, "IN"),
35 &CLASS_CH => write!(f, "CH"),
36 Class(x) => write!(f, "Class#{}", x),
37 }
38 }
39}
40
41impl fmt::Debug for Class {
42 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
43 write!(f, "Class({})", self)
44 }
45}
46
47#[derive(Ord, PartialOrd, PartialEq, Eq, Clone, Hash, Copy)]
48#[cfg_attr(fuzzing, derive(Arbitrary))]
49pub struct Type(pub u16);
50
51pub const RR_A: Type = Type(1);
52pub const RR_NS: Type = Type(2);
53pub const RR_CNAME: Type = Type(5);
54pub const RR_SOA: Type = Type(6);
55pub const RR_PTR: Type = Type(12);
56pub const RR_MX: Type = Type(15);
57pub const RR_RP: Type = Type(17);
58pub const RR_AFSDB: Type = Type(18);
59pub const RR_RT: Type = Type(21);
60pub const RR_NAPTR: Type = Type(35);
61pub const RR_OPT: Type = Type(41);
62pub const RR_NSEC: Type = Type(47);
63pub const RR_NSEC3: Type = Type(50);
64pub const RR_ANY: Type = Type(255);
65
66impl fmt::Display for Type {
67 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
68 match self {
69 &RR_A => write!(f, "A"),
70 &RR_NS => write!(f, "NS"),
71 &RR_CNAME => write!(f, "CNAME"),
72 &RR_SOA => write!(f, "SOA"),
73 &RR_PTR => write!(f, "PTR"),
74 &RR_NAPTR => write!(f, "NAPTR"),
75 &RR_OPT => write!(f, "OPT"),
76 &RR_NSEC => write!(f, "NSEC"),
77 &RR_NSEC3 => write!(f, "NSEC3"),
78 Type(x) => write!(f, "Type#{}", x),
79 }
80 }
81}
82
83impl fmt::Debug for Type {
84 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
85 write!(f, "Type({})", self)
86 }
87}
88
89#[derive(Ord, PartialOrd, PartialEq, Eq, Clone, Copy)]
90#[cfg_attr(fuzzing, derive(Arbitrary))]
91pub struct RCode(pub u16);
92pub const NOERROR: RCode = RCode(0);
93pub const FORMERR: RCode = RCode(1);
94pub const SERVFAIL: RCode = RCode(2);
95pub const NXDOMAIN: RCode = RCode(3);
96pub const NOTIMP: RCode = RCode(4);
97pub const REFUSED: RCode = RCode(5);
98pub const YXDOMAIN: RCode = RCode(6);
99pub const YXRRSET: RCode = RCode(7);
100pub const NXRRSET: RCode = RCode(8);
101pub const NOTAUTH: RCode = RCode(9);
102pub const NOTZONE: RCode = RCode(10);
103pub const DSOTYPENI: RCode = RCode(11);
104pub const BADVERS: RCode = RCode(16);
105pub const BADSIG: RCode = RCode(16); pub const BADKEY: RCode = RCode(17);
107pub const BADTIME: RCode = RCode(18);
108pub const BADMODE: RCode = RCode(19);
109pub const BADNAME: RCode = RCode(20);
110pub const BADALG: RCode = RCode(21);
111pub const BADTRUNC: RCode = RCode(22);
112pub const BADCOOKIE: RCode = RCode(23);
113
114impl fmt::Display for RCode {
115 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
116 match self {
117 &NOERROR => write!(f, "NOERROR"),
118 &FORMERR => write!(f, "FORMERR"),
119 &SERVFAIL => write!(f, "SERVFAIL"),
120 &NXDOMAIN => write!(f, "NXDOMAIN"),
121 &NOTIMP => write!(f, "NOTIMP"),
122 &REFUSED => write!(f, "REFUSED"),
123 &YXDOMAIN => write!(f, "YXDOMAIN"),
124 &YXRRSET => write!(f, "YXRRSET"),
125 &NXRRSET => write!(f, "NXRRSET"),
126 &NOTAUTH => write!(f, "NOTAUTH"),
127 &NOTZONE => write!(f, "NOTZONE"),
128 &DSOTYPENI => write!(f, "DSOTYPENI"),
129 &BADVERS => write!(f, "BADVERS/BADSIG"),
130 &BADKEY => write!(f, "BADKEY"),
131 &BADTIME => write!(f, "BADTIME"),
132 &BADMODE => write!(f, "BADMODE"),
133 &BADNAME => write!(f, "BADNAME"),
134 &BADALG => write!(f, "BADALG"),
135 &BADTRUNC => write!(f, "BADTRUNC"),
136 &BADCOOKIE => write!(f, "BADCOOKIE"),
137 RCode(x) => write!(f, "RCode#{}", x),
138 }
139 }
140}
141
142impl fmt::Debug for RCode {
143 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
144 write!(f, "RCode({})", self)
145 }
146}
147
148fn display_byte(b: u8) -> String {
149 match b {
150 n @ 32..=127 => char::from(n).to_string(),
151 n => format!("\\{}", n),
152 }
153}
154
155#[derive(Ord, Clone, PartialEq, Eq, PartialOrd, Hash, Debug)]
156pub struct Label(Vec<u8>);
157
158impl From<Vec<u8>> for Label {
159 fn from(mut v: Vec<u8>) -> Self {
160 assert!(!v.is_empty());
161 v.shrink_to_fit();
162 Label(v)
163 }
164}
165impl fmt::Display for Label {
166 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
167 write!(
168 f,
169 "{}",
170 self.0.iter().map(|&b| display_byte(b)).collect::<String>()
171 )
172 }
173}
174
175#[cfg(fuzzing)]
176impl<'a> Arbitrary<'a> for Label {
177 fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
178 loop {
180 let v = Vec::<u8>::arbitrary(u)?;
181 if v.len() > 0 && v.len() < 64 {
182 return Ok(Self(v));
183 }
184 }
185 }
186}
187
188#[derive(Clone, PartialEq, Eq, PartialOrd, Hash)]
189#[cfg_attr(fuzzing, derive(Arbitrary))]
190pub struct Domain(Vec<Label>);
191
192impl Domain {
193 pub fn ends_with(&self, other: &Self) -> bool {
194 self.0.ends_with(&other.0)
195 }
196}
197
198impl From<Vec<Label>> for Domain {
199 fn from(mut v: Vec<Label>) -> Self {
200 v.shrink_to_fit();
201 Domain(v)
202 }
203}
204
205impl fmt::Display for Domain {
206 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
207 write!(
208 f,
209 "{}",
210 self.0
211 .iter()
212 .map(|x| x.to_string())
213 .collect::<Vec<String>>()
214 .join(".")
215 )
216 }
217}
218
219impl fmt::Debug for Domain {
220 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
221 write!(f, "Domain({:?})", self.0)
222 }
223}
224
225impl std::str::FromStr for Domain {
226 type Err = &'static str;
227 fn from_str(s: &str) -> Result<Self, Self::Err> {
228 let mut v = vec![];
229 let mut l = vec![];
230 for c in s.chars() {
231 match c {
232 '\\' => return Err("\\ not yet supported"), '.' => {
234 if l.is_empty() {
235 return Err("illegal empty label");
236 }
237 l.shrink_to_fit();
238 v.push(Label(l));
239 l = vec![]
240 }
241 ch if ch.is_ascii() => l.push(ch as u8),
242 _ => return Err("illegal charactor in label"),
243 }
244 }
245 if !l.is_empty() {
246 l.shrink_to_fit();
247 v.push(Label(l));
248 }
249 v.shrink_to_fit();
250 Ok(Domain(v))
251 }
252}
253
254pub fn compare_longest_suffix(lhs: &Domain, rhs: &Domain) -> std::cmp::Ordering {
256 use std::cmp::Ordering::*;
257 if lhs.0.len() != rhs.0.len() {
258 if lhs.0.len() < rhs.0.len() {
259 Greater } else {
261 Less
262 }
263 } else {
264 lhs.0.cmp(&rhs.0)
266 }
267}
268
269#[derive(Clone, Eq, PartialEq)]
270#[cfg_attr(fuzzing, derive(Arbitrary))]
271pub struct Question {
272 pub qdomain: Domain,
273 pub qclass: Class,
274 pub qtype: Type,
275}
276
277impl fmt::Display for Question {
278 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
279 write!(f, "{:?} {:?} {:?}", self.qdomain, self.qclass, self.qtype)
280 }
281}
282
283impl fmt::Debug for Question {
284 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
285 write!(
286 f,
287 "Question({:?} {:?} {:?})",
288 self.qdomain, self.qclass, self.qtype
289 )
290 }
291}
292
293#[derive(Ord, Eq, PartialEq, PartialOrd, Clone)]
294#[cfg_attr(fuzzing, derive(Arbitrary))]
295pub struct EdnsCode(pub u16);
296
297pub const EDNS_NSID: EdnsCode = EdnsCode(3);
298pub const EDNS_CLIENT_SUBNET: EdnsCode = EdnsCode(8);
299pub const EDNS_COOKIE: EdnsCode = EdnsCode(10);
300pub const EDNS_EDE: EdnsCode = EdnsCode(15);
301
302impl fmt::Display for EdnsCode {
303 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
304 match self {
305 &EDNS_NSID => write!(f, "NSID"),
306 &EDNS_CLIENT_SUBNET => write!(f, "CLIENT_SUBNET"),
307 &EDNS_COOKIE => write!(f, "COOKIE"),
308 &EDNS_EDE => write!(f, "EXTENDED_DNS_ERROR"),
309 EdnsCode(c) => write!(f, "EDNS#{}", c),
310 }
311 }
312}
313
314impl fmt::Debug for EdnsCode {
315 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
316 write!(f, "EdnsCode({})", self)
317 }
318}
319
320#[derive(Debug, PartialEq, Eq, Copy, Clone)]
321pub struct EdeCode(u16);
322
323pub const EDE_OTHER: EdeCode = EdeCode(0);
324pub const EDE_UNSUPPORTED_DNSKEY_ALGO: EdeCode = EdeCode(1);
325pub const EDE_UNSUPPORTED_DS_DIGEST: EdeCode = EdeCode(2);
326pub const EDE_STALE_ANSWER: EdeCode = EdeCode(3);
327pub const EDE_FORGED_ANSWER: EdeCode = EdeCode(4);
328pub const EDE_DNSSEC_INDETERMINATE: EdeCode = EdeCode(5);
329pub const EDE_DNSSEC_BOGUS: EdeCode = EdeCode(6);
330pub const EDE_SIGNATURE_EXPIRED: EdeCode = EdeCode(7);
331pub const EDE_SIGNATURE_NOT_YET_VALID: EdeCode = EdeCode(8);
332pub const EDE_DNSKEY_MISSING: EdeCode = EdeCode(9);
333pub const EDE_RRSIG_MISSING: EdeCode = EdeCode(10);
334pub const EDE_NO_ZONE_KEY_BIT_SET: EdeCode = EdeCode(11);
335pub const EDE_NSEC_MISSING: EdeCode = EdeCode(12);
336pub const EDE_CACHED_ERROR: EdeCode = EdeCode(13);
337pub const EDE_NOT_READY: EdeCode = EdeCode(14);
338pub const EDE_BLOCKED: EdeCode = EdeCode(15);
339pub const EDE_CENSORED: EdeCode = EdeCode(16);
340pub const EDE_FILTERED: EdeCode = EdeCode(17);
341pub const EDE_PROHIBITED: EdeCode = EdeCode(18);
342pub const EDE_STALE_NXDOMAIN: EdeCode = EdeCode(19);
343pub const EDE_NOT_AUTHORITATIVE: EdeCode = EdeCode(20);
344pub const EDE_NOT_SUPPORTED: EdeCode = EdeCode(21);
345pub const EDE_NO_REACHABLE_AUTHORITY: EdeCode = EdeCode(22);
346pub const EDE_NETWORK_ERROR: EdeCode = EdeCode(23);
347pub const EDE_INVALID_DATA: EdeCode = EdeCode(24);
348
349impl fmt::Display for EdeCode {
350 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
351 match self {
352 &EDE_OTHER => write!(f, "OTHER"),
353 &EDE_UNSUPPORTED_DNSKEY_ALGO => write!(f, "UNSUPPORTED_DNSKEY_ALGO"),
354 &EDE_UNSUPPORTED_DS_DIGEST => write!(f, "UNSUPPORTED_DS_DIGEST"),
355 &EDE_STALE_ANSWER => write!(f, "STALE_ANSWER"),
356 &EDE_FORGED_ANSWER => write!(f, "FORGED_ANSWER"),
357 &EDE_DNSSEC_INDETERMINATE => write!(f, "DNSSEC_INDETERMINATE"),
358 &EDE_DNSSEC_BOGUS => write!(f, "DNSSEC_BOGUS"),
359 &EDE_SIGNATURE_EXPIRED => write!(f, "SIGNATURE_EXPIRED"),
360 &EDE_SIGNATURE_NOT_YET_VALID => write!(f, "SIGNATURE_NOT_YET_VALID"),
361 &EDE_DNSKEY_MISSING => write!(f, "DNSKEY_MISSING"),
362 &EDE_RRSIG_MISSING => write!(f, "RRSIG_MISSING"),
363 &EDE_NO_ZONE_KEY_BIT_SET => write!(f, "NO_ZONE_KEY_BIT_SET"),
364 &EDE_NSEC_MISSING => write!(f, "NSEC_MISSING"),
365 &EDE_CACHED_ERROR => write!(f, "CACHED_ERROR"),
366 &EDE_NOT_READY => write!(f, "NOT_READY"),
367 &EDE_BLOCKED => write!(f, "BLOCKED"),
368 &EDE_CENSORED => write!(f, "CENSORED"),
369 &EDE_FILTERED => write!(f, "FILTERED"),
370 &EDE_PROHIBITED => write!(f, "PROHIBITED"),
371 &EDE_STALE_NXDOMAIN => write!(f, "STALE_NXDOMAIN"),
372 &EDE_NOT_AUTHORITATIVE => write!(f, "NOT_AUTHORITATIVE"),
373 &EDE_NOT_SUPPORTED => write!(f, "NOT_SUPPOTED"),
374 &EDE_NO_REACHABLE_AUTHORITY => write!(f, "NO_REACHABLE_AUTHORITY"),
375 &EDE_NETWORK_ERROR => write!(f, "NETWORK_ERROR"),
376 &EDE_INVALID_DATA => write!(f, "INVALID_DATA"),
377 EdeCode(c) => write!(f, "EdeCode({})", c),
378 }
379 }
380}
381
382#[derive(Clone, Eq, PartialEq)]
383#[cfg_attr(fuzzing, derive(Arbitrary))]
384pub struct EdnsOption {
385 pub code: EdnsCode,
386 pub data: Vec<u8>,
387}
388
389impl fmt::Debug for EdnsOption {
390 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
391 match self.code {
392 EDNS_EDE => write!(
393 f,
394 "EdnsOption({}: {})",
395 self.code,
396 String::from_utf8_lossy(&self.data[..])
397 ),
398 EDNS_COOKIE => write!(
399 f,
400 "EdnsOption({}: {})",
401 self.code,
402 self.data[..]
403 .iter()
404 .map(|b| format!("{:02x}", b))
405 .collect::<Vec<_>>()
406 .join("")
407 ),
408 ref code => write!(f, "EdnsOption({}: {:?})", code, self.data),
409 }
410 }
411}
412
413#[derive(Debug, Clone, Eq, PartialEq, Default)]
414#[cfg_attr(fuzzing, derive(Arbitrary))]
415pub struct EdnsData(Vec<EdnsOption>);
416
417#[derive(Debug, Clone, Eq, PartialEq)]
418#[cfg_attr(fuzzing, derive(Arbitrary))]
419pub struct SoaData {
420 pub mname: Domain,
421 pub rname: Domain,
422 pub serial: u32,
423 pub refresh: u32,
424 pub retry: u32,
425 pub expire: u32,
426 pub minimum: u32,
427}
428
429#[derive(Debug, Clone, Eq, PartialEq)]
430#[cfg_attr(fuzzing, derive(Arbitrary))]
431pub struct PrefDomainData {
432 pub pref: u16,
433 pub domain: Domain,
434}
435
436#[derive(Debug, Clone, Eq, PartialEq)]
437#[cfg_attr(fuzzing, derive(Arbitrary))]
438pub struct AFSDBData {
439 pub subtype: u16,
440 pub hostname: Domain,
441}
442
443#[derive(Debug, Clone, Eq, PartialEq)]
444#[cfg_attr(fuzzing, derive(Arbitrary))]
445pub struct RPData {
446 pub mbox: Domain,
447 pub txt: Domain,
448}
449
450#[derive(Debug, Clone, Eq, PartialEq)]
451pub struct NAPTRData {
452 pub order: u16,
453 pub preference: u16,
454 pub flags: Vec<u8>,
455 pub services: Vec<u8>,
456 pub regexp: Vec<u8>,
457 pub replacement: Domain,
458}
459
460#[cfg(fuzzing)]
461impl<'a> Arbitrary<'a> for NAPTRData {
462 fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
463 let order = <_>::arbitrary(u)?;
464 let preference = <_>::arbitrary(u)?;
465 let mut flags: Vec<u8> = <_>::arbitrary(u)?;
466 let mut services: Vec<u8> = <_>::arbitrary(u)?;
467 let mut regexp: Vec<u8> = <_>::arbitrary(u)?;
468 let replacement = <_>::arbitrary(u)?;
469 flags.truncate(255);
470 services.truncate(255);
471 regexp.truncate(255);
472 Ok(NAPTRData {
473 order,
474 preference,
475 flags,
476 services,
477 regexp,
478 replacement,
479 })
480 }
481}
482
483#[derive(Debug, Clone, Eq, PartialEq)]
484#[cfg_attr(fuzzing, derive(Arbitrary))]
485pub enum RData {
486 CName(Domain),
487 Mx(PrefDomainData),
488 Ns(Domain),
489 Ptr(Domain),
490 Soa(SoaData),
491 Opt(EdnsData),
492 AfsDb(AFSDBData),
493 Rp(RPData),
494 Rt(PrefDomainData),
495 NaPtr(NAPTRData),
496 Other(Vec<u8>),
497}
498
499impl std::fmt::Display for RData {
500 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
501 use RData::*;
502 match self {
503 CName(d) | Ns(d) | Ptr(d) => write!(f, "\"{}\"", d),
504 Mx(pd) | Rt(pd) => write!(f, "{} {}", pd.pref, pd.domain),
505 AfsDb(afs) => write!(f, "{} {}", afs.subtype, afs.hostname),
506 Rp(rp) => write!(f, "{} {}", rp.mbox, rp.txt),
507 NaPtr(na) => write!(
508 f,
509 "{} {} {:?} {:?} {:?} \"{}\"",
510 na.order, na.preference, na.flags, na.services, na.regexp, na.replacement
511 ),
512 Soa(v) => write!(
513 f,
514 "{:?} {:?} {} {} {} {} {}",
515 v.mname, v.rname, v.serial, v.refresh, v.retry, v.expire, v.minimum
516 ),
517 Opt(v) => write!(f, "{:?}", v),
518 Other(v) => write!(f, "\\#{} {:?}", v.len(), v),
519 }
520 }
521}
522
523#[derive(Clone, Eq, PartialEq)]
524pub struct RR {
525 pub domain: Domain,
526 pub class: Class,
527 pub rrtype: Type,
528 pub ttl: u32,
529 pub rdata: RData,
530}
531
532impl std::fmt::Display for RR {
533 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
534 write!(
535 f,
536 "\"{}\" {} {:?} {:?} {}",
537 self.domain, self.ttl, self.class, self.rrtype, self.rdata
538 )
539 }
540}
541
542impl fmt::Debug for RR {
543 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
544 write!(f, "RR({})", self)
545 }
546}
547
548#[cfg(fuzzing)]
549impl<'a> Arbitrary<'a> for RR {
550 fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
551 let domain = <_>::arbitrary(u)?;
552 let class = <_>::arbitrary(u)?;
553 let ttl = <_>::arbitrary(u)?;
554 let rdata = <_>::arbitrary(u)?;
555 let rrtype = match &rdata {
556 RData::Ns(_) => RR_NS,
557 RData::CName(_) => RR_CNAME,
558 RData::Soa(_) => RR_SOA,
559 RData::Ptr(_) => RR_PTR,
560 RData::Mx(_) => RR_MX,
561 RData::Rp(_) => RR_RP,
562 RData::AfsDb(_) => RR_AFSDB,
563 RData::Rt(_) => RR_RT,
564 RData::NaPtr(_) => RR_NAPTR,
565 RData::Opt(_) => RR_OPT,
566 RData::Other(_) => loop {
567 let rrtype = <_>::arbitrary(u)?;
569 if rrtype != RR_NS
570 && rrtype != RR_CNAME
571 && rrtype != RR_SOA
572 && rrtype != RR_PTR
573 && rrtype != RR_MX
574 && rrtype != RR_RP
575 && rrtype != RR_AFSDB
576 && rrtype != RR_RT
577 && rrtype != RR_NAPTR
578 && rrtype != RR_OPT
579 {
580 break rrtype;
581 }
582 },
583 };
584 return Ok(Self {
585 domain,
586 class,
587 rrtype,
588 ttl,
589 rdata,
590 });
591 }
592}
593
594#[derive(Ord, Eq, PartialOrd, PartialEq, Clone, Copy)]
595#[cfg_attr(fuzzing, derive(Arbitrary))]
596pub struct Opcode(pub u8);
597
598pub const OPCODE_QUERY: Opcode = Opcode(0);
599pub const OPCODE_IQUERY: Opcode = Opcode(1);
600pub const OPCODE_STATUS: Opcode = Opcode(2);
601pub const OPCODE_NOTIFY: Opcode = Opcode(4);
602pub const OPCODE_UPDATE: Opcode = Opcode(5);
603
604impl std::fmt::Display for Opcode {
605 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
606 match self {
607 &OPCODE_QUERY => write!(f, "QUERY"),
608 &OPCODE_IQUERY => write!(f, "IQUERY"),
609 &OPCODE_STATUS => write!(f, "STATUS"),
610 &OPCODE_NOTIFY => write!(f, "NOTIFY"),
611 &OPCODE_UPDATE => write!(f, "UPDATE"),
612 Opcode(x) => write!(f, "#{}", x),
613 }
614 }
615}
616
617impl fmt::Debug for Opcode {
618 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
619 write!(f, "Opcode({})", self)
620 }
621}
622
623#[derive(Debug, Clone, Eq, PartialEq)]
624pub struct DNSPkt {
625 pub qid: u16,
626 pub rd: bool,
627 pub tc: bool,
628 pub aa: bool,
629 pub qr: bool,
630 pub opcode: Opcode,
631
632 pub cd: bool,
633 pub ad: bool,
634 pub ra: bool,
635 pub rcode: RCode,
636 pub bufsize: u16,
637 pub edns_ver: Option<u8>,
638 pub edns_do: bool,
639
640 pub question: Question,
641
642 pub answer: Vec<RR>,
643 pub nameserver: Vec<RR>,
644 pub additional: Vec<RR>,
645
646 pub edns: Option<EdnsData>,
647}
648
649#[cfg(fuzzing)]
650impl<'a> Arbitrary<'a> for DNSPkt {
651 fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
652 let qid = <_>::arbitrary(u)?;
653 let rd = <_>::arbitrary(u)?;
654 let tc = <_>::arbitrary(u)?;
655 let aa = <_>::arbitrary(u)?;
656 let qr = <_>::arbitrary(u)?;
657 let opcode: u8 = <_>::arbitrary(u)?;
658 let cd = <_>::arbitrary(u)?;
659 let ad = <_>::arbitrary(u)?;
660 let ra = <_>::arbitrary(u)?;
661 let rcode = loop {
662 let rcode = RCode::arbitrary(u)?;
663 if rcode.0 <= 0b1111_1111_1111u16 {
664 break rcode;
665 }
666 };
667 let bufsize = <_>::arbitrary(u)?;
668 let edns_ver = <_>::arbitrary(u)?;
669 let edns_do = <_>::arbitrary(u)?;
670 let question = <_>::arbitrary(u)?;
671 let answer = <_>::arbitrary(u)?;
672 let additional = <_>::arbitrary(u)?;
673 let nameserver = <_>::arbitrary(u)?;
674 let edns = <_>::arbitrary(u)?;
675
676 return Ok(Self {
677 qid,
678 rd,
679 tc,
680 aa,
681 qr,
682 opcode: Opcode(opcode % 31),
683 cd,
684 ad,
685 ra,
686 rcode,
687 bufsize,
688 edns_ver,
689 edns_do,
690 question,
691 answer,
692 additional,
693 nameserver,
694 edns,
695 });
696 }
697}
698
699#[derive(Clone)]
700struct DomainTree<T: Default> {
701 label: Label,
702 data: T,
703 children: std::collections::LinkedList<Self>,
704}
705
706#[cfg(any(test, fuzzing))]
707impl<T: fmt::Debug + Default> fmt::Debug for DomainTree<T> {
708 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
709 write!(
710 f,
711 "DomainTree(label: {}, data: {:?}, children: {:#?})",
712 self.label, self.data, self.children
713 )
714 }
715}
716
717impl<T: Default> DomainTree<T> {
718 fn new() -> Self {
719 DomainTree {
720 label: Label("root".into()),
721 data: Default::default(),
722 children: Default::default(),
723 }
724 }
725}
726
727type DomainOffsets = DomainTree<u16>;
728
729fn push_u16(v: &mut Vec<u8>, d: u16) {
730 v.push((d >> 8) as u8);
731 v.push((d & 0xFF) as u8);
732}
733
734fn push_u32(v: &mut Vec<u8>, d: u32) {
735 v.push(((d >> 24) & 0xFF) as u8);
736 v.push(((d >> 16) & 0xFF) as u8);
737 v.push(((d >> 8) & 0xFF) as u8);
738 v.push((d & 0xFF) as u8);
739}
740
741fn push_label(v: &mut Vec<u8>, l: &Label) {
742 assert!(!l.0.is_empty());
743 assert!(l.0.len() < 64);
744 v.push(l.0.len() as u8);
745 v.extend_from_slice(l.0.as_slice())
746}
747
748fn push_prefix(
757 v: &mut Vec<u8>,
758 l: &[Label],
759 node: &mut Option<&mut DomainOffsets>,
760 base_offset: usize,
761) -> Option<DomainOffsets> {
762 assert!(!l.is_empty());
763 let label = &l[l.len() - 1];
764 let prefix = &l[..l.len() - 1];
765 let mut child = None;
766 if let Some(node) = node {
767 for it in &mut node.children {
768 if it.label == *label {
769 child = Some(&mut *it);
770 }
771 }
772 }
773 if !prefix.is_empty() {
774 let ret = push_prefix(v, prefix, &mut child, base_offset);
775 match (ret, child) {
776 (None, None) => {
777 unreachable!()
779 }
780 (None, Some(_)) => {
781 None
783 }
784 (Some(r), None) => {
785 let offset = v.len() + base_offset;
787 push_label(v, label);
788 let mut children = std::collections::LinkedList::new();
789 children.push_back(r);
790 Some(DomainTree {
791 label: label.clone(),
792 data: offset as u16,
793 children,
794 })
795 }
796 (Some(r), Some(n)) => {
797 n.children.push_back(r);
799 assert!((n.data >> 8) < 64);
800 assert_ne!(n.data, 0);
801 v.push(0b1100_0000u8 + (n.data >> 8) as u8);
802 v.push((n.data & 0xff) as u8);
803 None
804 }
805 }
806 } else {
807 match &child {
808 None => {
809 let offset = v.len() + base_offset;
811 push_label(v, label);
812 Some(DomainTree {
813 label: label.clone(),
814 data: offset as u16,
815 children: std::collections::LinkedList::new(),
816 })
817 }
818 Some(n) => {
819 v.push(0b1100_0000u8 + (n.data >> 8) as u8);
821 v.push((n.data & 0xff) as u8);
822 None
823 }
824 }
825 }
826}
827
828fn push_compressed_domain(
829 v: &mut Vec<u8>,
830 d: &Domain,
831 offsets: &mut DomainOffsets,
832 base_offset: usize,
833) {
834 if d.0.is_empty() {
835 v.push(0u8);
836 } else {
837 match push_prefix(v, &d.0, &mut Some(offsets), base_offset) {
838 None => { }
839 Some(n) => {
840 offsets.children.push_back(n);
841 v.push(0u8);
842 }
843 }
844 }
845}
846
847fn push_str(v: &mut Vec<u8>, s: &[u8]) {
848 assert!(s.len() < 256);
849 v.push(s.len() as u8);
850 v.extend(s);
851}
852
853fn make_edns_opt(v: &mut Vec<u8>, t: &EdnsOption) {
854 push_u16(v, t.code.0);
855 push_u16(v, t.data.len() as u16);
856 v.extend_from_slice(t.data.as_slice());
857}
858
859impl EdnsData {
860 pub const fn new() -> Self {
861 Self(vec![])
862 }
863 fn push_opt(&self, v: &mut Vec<u8>) {
864 self.0.iter().for_each(|o| make_edns_opt(v, o));
865 }
866
867 fn get_opt(&self, opt: &EdnsCode) -> Option<&EdnsOption> {
868 self.0.iter().find(|o| o.code == *opt)
869 }
870
871 pub fn get_nsid(&self) -> Option<&[u8]> {
872 self.get_opt(&EDNS_NSID).map(|opt| &opt.data[..])
873 }
874
875 pub fn set_nsid(&mut self, nsid: &[u8]) {
876 self.set_opt(EdnsOption {
877 code: EDNS_NSID,
878 data: nsid.to_vec(),
879 });
880 }
881
882 pub fn get_cookie(&self) -> Option<(&[u8], Option<&[u8]>)> {
883 self.get_opt(&EDNS_COOKIE)
884 .map(|opt| (&opt.data[..8], opt.data.get(8..)))
885 }
886
887 pub fn set_cookie(&mut self, client: &[u8], server: &[u8]) {
888 assert!(client.len() == 8);
889 assert!(server.len() >= 8 && server.len() <= 32);
890 let mut data = Vec::with_capacity(client.len() + server.len());
891 data.extend(client);
892 data.extend(server);
893 self.set_opt(EdnsOption {
894 code: EDNS_COOKIE,
895 data,
896 })
897 }
898
899 pub fn get_extended_dns_error(&self) -> Option<(EdeCode, String)> {
900 self.get_opt(&EDNS_EDE).map(|opt| {
901 (
902 EdeCode(u16::from_be_bytes([opt.data[0], opt.data[1]])),
903 String::from_utf8_lossy(&opt.data[2..]).into_owned(),
904 )
905 })
906 }
907
908 pub fn set_opt(&mut self, opt: EdnsOption) {
909 self.0.push(opt);
910 }
911
912 pub fn set_extended_dns_error(&mut self, code: EdeCode, msg: &str) {
913 let mut data = vec![];
914 data.extend(code.0.to_be_bytes().iter());
915 data.extend(msg.bytes());
916 self.set_opt(EdnsOption {
917 code: EDNS_EDE,
918 data,
919 });
920 }
921}
922
923fn push_rr(v: &mut Vec<u8>, rr: &RR, offsets: &mut DomainOffsets) {
924 push_compressed_domain(v, &rr.domain, offsets, 0);
925 push_u16(v, rr.rrtype.0);
926 push_u16(v, rr.class.0);
927 push_u32(v, rr.ttl);
928 match &rr.rdata {
929 RData::CName(d) | RData::Ptr(d) | RData::Ns(d) => {
930 let mut vs = vec![];
931 push_compressed_domain(&mut vs, d, offsets, v.len() + 2);
932 push_u16(v, vs.len() as u16);
933 v.extend_from_slice(vs.as_slice());
934 }
935 RData::Mx(pd) | RData::Rt(pd) => {
936 let mut vs = vec![];
937 push_u16(&mut vs, pd.pref);
938 push_compressed_domain(&mut vs, &pd.domain, offsets, v.len() + 2);
939 push_u16(v, vs.len() as u16);
940 v.extend_from_slice(vs.as_slice());
941 }
942 RData::NaPtr(na) => {
943 let mut vs = vec![];
944 push_u16(&mut vs, na.order);
945 push_u16(&mut vs, na.preference);
946 push_str(&mut vs, &na.flags);
947 push_str(&mut vs, &na.services);
948 push_str(&mut vs, &na.regexp);
949 push_compressed_domain(&mut vs, &na.replacement, offsets, v.len() + 2);
950 push_u16(v, vs.len() as u16);
951 v.extend_from_slice(vs.as_slice());
952 }
953 RData::Rp(rp) => {
954 let mut vs = vec![];
955 push_compressed_domain(&mut vs, &rp.mbox, offsets, v.len() + 2);
956 push_compressed_domain(&mut vs, &rp.txt, offsets, v.len() + 2);
957 push_u16(v, vs.len() as u16);
958 v.extend_from_slice(vs.as_slice());
959 }
960 RData::Soa(s) => {
961 assert!(rr.rrtype == RR_SOA);
962 let mut vs = vec![];
963 push_compressed_domain(&mut vs, &s.mname, offsets, v.len() + 2);
964 push_compressed_domain(&mut vs, &s.rname, offsets, v.len() + 2);
965 push_u32(&mut vs, s.serial);
966 push_u32(&mut vs, s.refresh);
967 push_u32(&mut vs, s.retry);
968 push_u32(&mut vs, s.expire);
969 push_u32(&mut vs, s.minimum);
970
971 push_u16(v, vs.len() as u16);
972 v.extend_from_slice(vs.as_slice());
973 }
974 RData::AfsDb(afs) => {
975 let mut vs = vec![];
976 push_u16(&mut vs, afs.subtype);
977 push_compressed_domain(&mut vs, &afs.hostname, offsets, v.len() + 2);
978 push_u16(v, vs.len() as u16);
979 v.extend_from_slice(vs.as_slice());
980 }
981 RData::Opt(o) => {
982 assert!(rr.rrtype == RR_OPT);
983 let mut vo = vec![];
984 o.push_opt(&mut vo);
985
986 push_u16(v, vo.len() as u16);
987 v.extend_from_slice(vo.as_slice());
988 }
989 RData::Other(x) => {
990 use std::convert::TryFrom as _;
991 assert!(rr.rrtype != RR_OPT && rr.rrtype != RR_SOA);
992 push_u16(v, u16::try_from(x.len()).unwrap());
993 v.extend_from_slice(x.as_slice());
994 }
995 }
996}
997
998impl DNSPkt {
999 pub fn status(&self) -> String {
1000 match self
1001 .edns
1002 .as_ref()
1003 .and_then(|e| e.get_extended_dns_error())
1004 .map(|e| e.0)
1005 {
1006 Some(x) => format!("{} ({})", self.rcode, x),
1007 None => format!("{}", self.rcode),
1008 }
1009 }
1010 pub fn serialise(&self) -> Vec<u8> {
1011 self.serialise_with_size(65536)
1012 }
1013 pub fn serialise_with_size(&self, size: usize) -> Vec<u8> {
1014 assert!(size >= 512);
1015 let mut ret: Vec<u8> = Vec::new();
1016 let mut offsets = DomainOffsets::new();
1017 assert!(self.rcode.0 <= 0b1111_1111_1111);
1018 let flag1: u8 = u8::from(self.rd)
1019 | (if self.tc { 0b0000_0010 } else { 0b0 })
1020 | (if self.aa { 0b0000_0100 } else { 0b0 })
1021 | (if self.qr { 0b1000_0000 } else { 0b0 })
1022 | (self.opcode.0 << 3);
1023 let flag2: u8 = (if self.cd { 0b0010_0000 } else { 0b0 })
1024 |(if self.ad { 0b0100_0000 } else { 0b0 })
1025 |(if self.ra { 0b1000_0000 } else { 0b0 })
1026 |((self.rcode.0 & 0b0000_1111) as u8);
1028 let mut additional = self.additional.clone();
1029
1030 if self.edns.is_some() {
1031 let edns = self.edns.clone().unwrap_or_default();
1032
1033 additional.push(RR {
1034 domain: Domain::from(vec![]),
1035 class: Class(self.bufsize),
1036 rrtype: RR_OPT,
1037 ttl: (((self.rcode.0 >> 4) as u32) << 24)
1038 | ((self.edns_ver.unwrap_or(0) as u32) << 16)
1039 | (if self.edns_do {
1040 0b0000_0000_0000_0000_1000_0000_0000_0000
1041 } else {
1042 0b0
1043 }),
1044 rdata: RData::Opt(edns),
1045 });
1046 }
1047
1048 push_u16(&mut ret, self.qid);
1049 ret.push(flag1);
1050 ret.push(flag2);
1051 push_u16(&mut ret, 1); push_u16(&mut ret, self.answer.len() as u16);
1053 push_u16(&mut ret, self.nameserver.len() as u16);
1054 push_u16(&mut ret, additional.len() as u16);
1055 push_compressed_domain(&mut ret, &self.question.qdomain, &mut offsets, 0);
1056 push_u16(&mut ret, self.question.qtype.0);
1057 push_u16(&mut ret, self.question.qclass.0);
1058
1059 let mut trunc = false;
1060 let mut ancount: u16 = 0;
1061 let mut nscount: u16 = 0;
1062 let mut adcount: u16 = 0;
1063
1064 for rr in &self.answer {
1065 let offset = ret.len();
1066 push_rr(&mut ret, rr, &mut offsets);
1067 if ret.len() > size {
1068 ret.truncate(offset);
1069 trunc = true;
1070 break;
1071 } else {
1072 ancount += 1;
1073 }
1074 }
1075
1076 if !trunc {
1077 for rr in &self.nameserver {
1078 let offset = ret.len();
1079 push_rr(&mut ret, rr, &mut offsets);
1080 if ret.len() > size {
1081 ret.truncate(offset);
1082 trunc = true;
1083 break;
1084 } else {
1085 nscount += 1;
1086 }
1087 }
1088 }
1089
1090 if !trunc {
1091 for rr in &additional {
1092 let offset = ret.len();
1093 push_rr(&mut ret, rr, &mut offsets);
1094 if ret.len() > size {
1095 ret.truncate(offset);
1096 trunc = true;
1097 break;
1098 } else {
1099 adcount += 1;
1100 }
1101 }
1102 }
1103
1104 if trunc {
1105 ret[2] |= 0b0000_0010;
1107 ret.splice(6..7, ancount.to_be_bytes().iter().copied());
1108 ret.splice(8..9, nscount.to_be_bytes().iter().copied());
1109 ret.splice(10..11, adcount.to_be_bytes().iter().copied());
1110 }
1111
1112 ret
1113 }
1114
1115 pub fn get_expiry(&self) -> std::time::Duration {
1116 self.answer
1117 .iter()
1118 .chain(self.nameserver.iter())
1119 .chain(self.additional.iter())
1120 .map(|rr| std::time::Duration::from_secs(rr.ttl as u64))
1121 .min()
1122 .unwrap_or_else(|| std::time::Duration::from_secs(0))
1123 }
1124
1125 #[must_use]
1126 pub fn clone_with_ttl_decrement(&self, decrement: u32) -> DNSPkt {
1127 DNSPkt {
1128 question: self.question.clone(),
1129 additional: self
1130 .additional
1131 .iter()
1132 .map(|x| RR {
1133 ttl: x.ttl - decrement,
1134 ..x.clone()
1135 })
1136 .collect(),
1137 nameserver: self
1138 .nameserver
1139 .iter()
1140 .map(|x| RR {
1141 ttl: x.ttl - decrement,
1142 ..x.clone()
1143 })
1144 .collect(),
1145 answer: self
1146 .answer
1147 .iter()
1148 .map(|x| RR {
1149 ttl: x.ttl - decrement,
1150 ..x.clone()
1151 })
1152 .collect(),
1153 edns: self.edns.clone(),
1154 ..*self
1155 }
1156 }
1157}
1158
1159#[test]
1160fn test_compressed_domain() {
1161 let mut v = vec![];
1162 let domain = Domain(vec![]);
1163 let mut offsets = DomainOffsets::new();
1164 push_compressed_domain(&mut v, &domain, &mut offsets, 0);
1165 push_compressed_domain(&mut v, &"local".parse().unwrap(), &mut offsets, 0);
1166 push_compressed_domain(&mut v, &"c.d.example.com".parse().unwrap(), &mut offsets, 0);
1167 push_compressed_domain(
1168 &mut v,
1169 &"a.b.c.d.example.com".parse().unwrap(),
1170 &mut offsets,
1171 0,
1172 );
1173 assert_eq!(
1174 v,
1175 [
1176 0, 5, 108, 111, 99, 97, 108, 0, 1, 99, 1, 100, 7, 101, 120, 97, 109, 112, 108, 101, 3, 99, 111, 109,
1179 0, 1, 97, 1, 98, 192, 8 ]
1182 );
1183}
1184
1185#[test]
1186fn test_compression_roundtrip() {
1187 let mut v = vec![];
1188 let mut offsets = DomainOffsets::new();
1189 push_compressed_domain(
1190 &mut v,
1191 &"test.example.com".parse().unwrap(),
1192 &mut offsets,
1193 0,
1194 );
1195 push_compressed_domain(
1196 &mut v,
1197 &"test2.example.com".parse().unwrap(),
1198 &mut offsets,
1199 0,
1200 );
1201 push_compressed_domain(
1202 &mut v,
1203 &"test.example.com".parse().unwrap(),
1204 &mut offsets,
1205 0,
1206 );
1207 let mut p = super::parse::PktParser::new(&v);
1208 assert_eq!(p.get_domain().unwrap(), "test.example.com".parse().unwrap());
1209 assert_eq!(
1210 p.get_domain().unwrap(),
1211 "test2.example.com".parse().unwrap()
1212 );
1213 assert_eq!(p.get_domain().unwrap(), "test.example.com".parse().unwrap());
1214}
1215
1216#[test]
1217fn test_rr_roundtrip() {
1218 let mut v = vec![];
1219 let mut offsets = DomainOffsets::new();
1220 let orig_cname = RR {
1221 domain: "test.example.com".parse().unwrap(),
1222 class: CLASS_IN,
1223 rrtype: RR_CNAME,
1224 ttl: 300,
1225 rdata: RData::CName("test.example.com".parse().unwrap()),
1226 };
1227 let orig_naptr = RR {
1228 domain: "test.example.com".parse().unwrap(),
1229 class: CLASS_IN,
1230 rrtype: RR_NAPTR,
1231 ttl: 300,
1232 rdata: RData::NaPtr(NAPTRData {
1233 order: 10,
1234 preference: 20,
1235 flags: "FLAG".into(),
1236 services: "SERVICE SERVICE".into(),
1237 regexp: "REGEXP".into(),
1238 replacement: "test.example.com".parse().unwrap(),
1239 }),
1240 };
1241 push_rr(&mut v, &orig_cname, &mut offsets);
1242 push_rr(&mut v, &orig_naptr, &mut offsets);
1243 let mut p = super::parse::PktParser::new(&v);
1244 assert_eq!(orig_cname, p.get_rr().unwrap());
1245 assert_eq!(orig_naptr, p.get_rr().unwrap());
1246}
1247
1248#[test]
1249fn test_pkt_roundtrip() {
1250 let mut orig_edns = EdnsData::new();
1251 orig_edns.set_extended_dns_error(EDE_OTHER, "Testing");
1252 let orig_pkt = DNSPkt {
1253 qid: 140,
1254 rd: false,
1255 tc: false,
1256 aa: false,
1257 qr: true,
1258 opcode: Opcode(15),
1259 cd: false,
1260 ad: false,
1261 ra: false,
1262 rcode: NOERROR,
1263 bufsize: 512,
1264 edns_ver: Some(0),
1265 edns_do: false,
1266 question: Question {
1267 qdomain: Domain::from(vec![]),
1268 qclass: Class(2570),
1269 qtype: Type(768),
1270 },
1271 answer: vec![
1272 RR {
1273 domain: Domain::from(vec![]),
1274 ttl: 16843009,
1275 class: Class(257),
1276 rrtype: RR_NAPTR,
1277 rdata: RData::NaPtr(NAPTRData {
1278 order: 47288,
1279 preference: 11960,
1280 flags: "flags".into(),
1281 services: "".into(),
1282 regexp: "\u{1}".into(),
1283 replacement: Domain::from(vec![]),
1284 }),
1285 },
1286 RR {
1287 domain: Domain::from(vec![]),
1288 ttl: 1234,
1289 class: CLASS_IN,
1290 rrtype: RR_SOA,
1291 rdata: RData::Soa(SoaData {
1292 mname: "dnsmaster.example.com".parse().unwrap(),
1293 rname: "ns1.example.com".parse().unwrap(),
1294 serial: 1,
1295 refresh: 3600,
1296 retry: 300,
1297 expire: 86400,
1298 minimum: 600,
1299 }),
1300 },
1301 RR {
1302 domain: Domain::from(vec![]),
1303 ttl: 1234,
1304 class: CLASS_IN,
1305 rrtype: RR_MX,
1306 rdata: RData::Mx(PrefDomainData {
1307 pref: 10,
1308 domain: "mx.example.com".parse().unwrap(),
1309 }),
1310 },
1311 ],
1312 nameserver: vec![],
1313 additional: vec![],
1314 edns: Some(orig_edns),
1315 };
1316 let v = orig_pkt.serialise();
1317 let mut p = super::parse::PktParser::new(&v);
1318 assert_eq!(orig_pkt, p.get_dns().unwrap());
1319}
1320
1321#[test]
1322fn domain_from_str() {
1323 assert_eq!(
1324 "example.com".parse(),
1325 Ok(Domain(vec![
1326 Label(vec![b'e', b'x', b'a', b'm', b'p', b'l', b'e']),
1327 Label(vec![b'c', b'o', b'm'])
1328 ]))
1329 );
1330}