1use std::collections::HashMap;
9use std::net::{Ipv4Addr, Ipv6Addr};
10
11use super::bitmap;
12use super::edns::EdnsOption;
13use super::svcb::SvcParam;
14use super::types::{self, rr_type};
15use crate::layer::field::FieldError;
16use crate::layer::field_ext::DnsName;
17
18#[derive(Debug, Clone, PartialEq)]
23pub enum DnsRData {
24 A(Ipv4Addr),
26
27 AAAA(Ipv6Addr),
29
30 NS(DnsName),
32
33 CNAME(DnsName),
35
36 PTR(DnsName),
38
39 DNAME(DnsName),
41
42 MX { preference: u16, exchange: DnsName },
44
45 TXT(Vec<Vec<u8>>),
48
49 SOA {
51 mname: DnsName,
52 rname: DnsName,
53 serial: u32,
54 refresh: u32,
55 retry: u32,
56 expire: u32,
57 minimum: u32,
58 },
59
60 SRV {
62 priority: u16,
63 weight: u16,
64 port: u16,
65 target: DnsName,
66 },
67
68 HINFO { cpu: Vec<u8>, os: Vec<u8> },
70
71 NAPTR {
73 order: u16,
74 preference: u16,
75 flags: Vec<u8>,
76 services: Vec<u8>,
77 regexp: Vec<u8>,
78 replacement: DnsName,
79 },
80
81 SVCB {
83 priority: u16,
84 target: DnsName,
85 params: Vec<SvcParam>,
86 },
87
88 HTTPS {
90 priority: u16,
91 target: DnsName,
92 params: Vec<SvcParam>,
93 },
94
95 CAA {
97 flags: u8,
98 tag: String,
99 value: Vec<u8>,
100 },
101
102 RRSIG {
104 type_covered: u16,
105 algorithm: u8,
106 labels: u8,
107 original_ttl: u32,
108 sig_expiration: u32,
109 sig_inception: u32,
110 key_tag: u16,
111 signer_name: DnsName,
112 signature: Vec<u8>,
113 },
114
115 NSEC {
117 next_domain: DnsName,
118 type_bitmaps: Vec<u16>,
119 },
120
121 NSEC3 {
123 hash_algorithm: u8,
124 flags: u8,
125 iterations: u16,
126 salt: Vec<u8>,
127 next_hashed: Vec<u8>,
128 type_bitmaps: Vec<u16>,
129 },
130
131 NSEC3PARAM {
133 hash_algorithm: u8,
134 flags: u8,
135 iterations: u16,
136 salt: Vec<u8>,
137 },
138
139 DNSKEY {
141 flags: u16,
142 protocol: u8,
143 algorithm: u8,
144 public_key: Vec<u8>,
145 },
146
147 DS {
149 key_tag: u16,
150 algorithm: u8,
151 digest_type: u8,
152 digest: Vec<u8>,
153 },
154
155 DLV {
157 key_tag: u16,
158 algorithm: u8,
159 digest_type: u8,
160 digest: Vec<u8>,
161 },
162
163 TSIG {
165 algorithm_name: DnsName,
166 time_signed: u64,
167 fudge: u16,
168 mac: Vec<u8>,
169 original_id: u16,
170 error: u16,
171 other_data: Vec<u8>,
172 },
173
174 TLSA {
176 usage: u8,
177 selector: u8,
178 matching_type: u8,
179 cert_data: Vec<u8>,
180 },
181
182 OPT(Vec<EdnsOption>),
184
185 Unknown { rtype: u16, data: Vec<u8> },
187}
188
189impl DnsRData {
190 pub fn parse(
198 rtype: u16,
199 packet: &[u8],
200 rdata_offset: usize,
201 rdlength: u16,
202 ) -> Result<Self, FieldError> {
203 let rdlen = rdlength as usize;
204 let rdata_end = rdata_offset + rdlen;
205
206 if rdata_end > packet.len() {
208 return Err(FieldError::BufferTooShort {
209 offset: rdata_offset,
210 need: rdlen,
211 have: packet.len().saturating_sub(rdata_offset),
212 });
213 }
214
215 let rdata = &packet[rdata_offset..rdata_end];
216
217 match rtype {
218 rr_type::A => Self::parse_a(rdata),
219 rr_type::AAAA => Self::parse_aaaa(rdata),
220 rr_type::NS => {
221 Self::parse_name_record(packet, rdata_offset, rdlen, |n| DnsRData::NS(n))
222 }
223 rr_type::CNAME => {
224 Self::parse_name_record(packet, rdata_offset, rdlen, |n| DnsRData::CNAME(n))
225 }
226 rr_type::PTR => {
227 Self::parse_name_record(packet, rdata_offset, rdlen, |n| DnsRData::PTR(n))
228 }
229 rr_type::DNAME => {
230 Self::parse_name_record(packet, rdata_offset, rdlen, |n| DnsRData::DNAME(n))
231 }
232 rr_type::MX => Self::parse_mx(packet, rdata_offset, rdata),
233 rr_type::TXT => Self::parse_txt(rdata),
234 rr_type::SOA => Self::parse_soa(packet, rdata_offset, rdata_end),
235 rr_type::SRV => Self::parse_srv(packet, rdata_offset, rdata),
236 rr_type::HINFO => Self::parse_hinfo(rdata),
237 rr_type::NAPTR => Self::parse_naptr(packet, rdata_offset, rdata_end),
238 rr_type::SVCB => Self::parse_svcb(packet, rdata_offset, rdata, rdlen, false),
239 rr_type::HTTPS => Self::parse_svcb(packet, rdata_offset, rdata, rdlen, true),
240 rr_type::CAA => Self::parse_caa(rdata),
241 rr_type::RRSIG => Self::parse_rrsig(packet, rdata_offset, rdata, rdlen),
242 rr_type::NSEC => Self::parse_nsec(packet, rdata_offset, rdata, rdlen),
243 rr_type::NSEC3 => Self::parse_nsec3(rdata),
244 rr_type::NSEC3PARAM => Self::parse_nsec3param(rdata),
245 rr_type::DNSKEY => Self::parse_dnskey(rdata),
246 rr_type::DS => Self::parse_ds(rdata),
247 rr_type::DLV => Self::parse_dlv(rdata),
248 rr_type::TSIG => Self::parse_tsig(packet, rdata_offset, rdata_end),
249 rr_type::TLSA => Self::parse_tlsa(rdata),
250 rr_type::OPT => Self::parse_opt(rdata),
251 _ => Ok(DnsRData::Unknown {
252 rtype,
253 data: rdata.to_vec(),
254 }),
255 }
256 }
257
258 fn parse_a(rdata: &[u8]) -> Result<Self, FieldError> {
263 if rdata.len() != 4 {
264 return Err(FieldError::InvalidValue(format!(
265 "A record RDATA must be 4 bytes, got {}",
266 rdata.len()
267 )));
268 }
269 Ok(DnsRData::A(Ipv4Addr::new(
270 rdata[0], rdata[1], rdata[2], rdata[3],
271 )))
272 }
273
274 fn parse_aaaa(rdata: &[u8]) -> Result<Self, FieldError> {
275 if rdata.len() != 16 {
276 return Err(FieldError::InvalidValue(format!(
277 "AAAA record RDATA must be 16 bytes, got {}",
278 rdata.len()
279 )));
280 }
281 let mut bytes = [0u8; 16];
282 bytes.copy_from_slice(rdata);
283 Ok(DnsRData::AAAA(Ipv6Addr::from(bytes)))
284 }
285
286 fn parse_name_record<F>(
288 packet: &[u8],
289 rdata_offset: usize,
290 _rdlen: usize,
291 constructor: F,
292 ) -> Result<Self, FieldError>
293 where
294 F: FnOnce(DnsName) -> DnsRData,
295 {
296 let (name, _consumed) = DnsName::decode(packet, rdata_offset)?;
297 Ok(constructor(name))
298 }
299
300 fn parse_mx(packet: &[u8], rdata_offset: usize, rdata: &[u8]) -> Result<Self, FieldError> {
301 if rdata.len() < 2 {
302 return Err(FieldError::BufferTooShort {
303 offset: 0,
304 need: 2,
305 have: rdata.len(),
306 });
307 }
308 let preference = u16::from_be_bytes([rdata[0], rdata[1]]);
309 let (exchange, _consumed) = DnsName::decode(packet, rdata_offset + 2)?;
310 Ok(DnsRData::MX {
311 preference,
312 exchange,
313 })
314 }
315
316 fn parse_txt(rdata: &[u8]) -> Result<Self, FieldError> {
317 let mut strings = Vec::new();
318 let mut pos = 0;
319
320 while pos < rdata.len() {
321 let str_len = rdata[pos] as usize;
322 pos += 1;
323
324 if pos + str_len > rdata.len() {
325 return Err(FieldError::BufferTooShort {
326 offset: pos,
327 need: str_len,
328 have: rdata.len() - pos,
329 });
330 }
331
332 strings.push(rdata[pos..pos + str_len].to_vec());
333 pos += str_len;
334 }
335
336 Ok(DnsRData::TXT(strings))
337 }
338
339 fn parse_soa(packet: &[u8], rdata_offset: usize, rdata_end: usize) -> Result<Self, FieldError> {
340 let (mname, consumed1) = DnsName::decode(packet, rdata_offset)?;
341 let (rname, consumed2) = DnsName::decode(packet, rdata_offset + consumed1)?;
342
343 let fixed_start = rdata_offset + consumed1 + consumed2;
344 if fixed_start + 20 > rdata_end {
345 return Err(FieldError::BufferTooShort {
346 offset: fixed_start,
347 need: 20,
348 have: rdata_end.saturating_sub(fixed_start),
349 });
350 }
351
352 let fixed = &packet[fixed_start..fixed_start + 20];
353 let serial = u32::from_be_bytes([fixed[0], fixed[1], fixed[2], fixed[3]]);
354 let refresh = u32::from_be_bytes([fixed[4], fixed[5], fixed[6], fixed[7]]);
355 let retry = u32::from_be_bytes([fixed[8], fixed[9], fixed[10], fixed[11]]);
356 let expire = u32::from_be_bytes([fixed[12], fixed[13], fixed[14], fixed[15]]);
357 let minimum = u32::from_be_bytes([fixed[16], fixed[17], fixed[18], fixed[19]]);
358
359 Ok(DnsRData::SOA {
360 mname,
361 rname,
362 serial,
363 refresh,
364 retry,
365 expire,
366 minimum,
367 })
368 }
369
370 fn parse_srv(packet: &[u8], rdata_offset: usize, rdata: &[u8]) -> Result<Self, FieldError> {
371 if rdata.len() < 6 {
372 return Err(FieldError::BufferTooShort {
373 offset: 0,
374 need: 6,
375 have: rdata.len(),
376 });
377 }
378 let priority = u16::from_be_bytes([rdata[0], rdata[1]]);
379 let weight = u16::from_be_bytes([rdata[2], rdata[3]]);
380 let port = u16::from_be_bytes([rdata[4], rdata[5]]);
381 let (target, _consumed) = DnsName::decode(packet, rdata_offset + 6)?;
382
383 Ok(DnsRData::SRV {
384 priority,
385 weight,
386 port,
387 target,
388 })
389 }
390
391 fn parse_hinfo(rdata: &[u8]) -> Result<Self, FieldError> {
392 if rdata.is_empty() {
393 return Err(FieldError::BufferTooShort {
394 offset: 0,
395 need: 1,
396 have: 0,
397 });
398 }
399
400 let cpu_len = rdata[0] as usize;
401 if 1 + cpu_len >= rdata.len() {
402 return Err(FieldError::BufferTooShort {
403 offset: 1,
404 need: cpu_len + 1, have: rdata.len() - 1,
406 });
407 }
408 let cpu = rdata[1..1 + cpu_len].to_vec();
409
410 let os_start = 1 + cpu_len;
411 let os_len = rdata[os_start] as usize;
412 if os_start + 1 + os_len > rdata.len() {
413 return Err(FieldError::BufferTooShort {
414 offset: os_start + 1,
415 need: os_len,
416 have: rdata.len() - os_start - 1,
417 });
418 }
419 let os = rdata[os_start + 1..os_start + 1 + os_len].to_vec();
420
421 Ok(DnsRData::HINFO { cpu, os })
422 }
423
424 fn parse_naptr(
425 packet: &[u8],
426 rdata_offset: usize,
427 rdata_end: usize,
428 ) -> Result<Self, FieldError> {
429 let rdata = &packet[rdata_offset..rdata_end];
430 if rdata.len() < 4 {
431 return Err(FieldError::BufferTooShort {
432 offset: 0,
433 need: 4,
434 have: rdata.len(),
435 });
436 }
437
438 let order = u16::from_be_bytes([rdata[0], rdata[1]]);
439 let preference = u16::from_be_bytes([rdata[2], rdata[3]]);
440 let mut pos = 4;
441
442 let (flags, consumed) = Self::parse_character_string(rdata, pos)?;
444 pos += consumed;
445
446 let (services, consumed) = Self::parse_character_string(rdata, pos)?;
447 pos += consumed;
448
449 let (regexp, consumed) = Self::parse_character_string(rdata, pos)?;
450 pos += consumed;
451
452 let (replacement, _consumed) = DnsName::decode(packet, rdata_offset + pos)?;
454
455 Ok(DnsRData::NAPTR {
456 order,
457 preference,
458 flags,
459 services,
460 regexp,
461 replacement,
462 })
463 }
464
465 fn parse_svcb(
466 packet: &[u8],
467 rdata_offset: usize,
468 rdata: &[u8],
469 rdlen: usize,
470 is_https: bool,
471 ) -> Result<Self, FieldError> {
472 if rdata.len() < 2 {
473 return Err(FieldError::BufferTooShort {
474 offset: 0,
475 need: 2,
476 have: rdata.len(),
477 });
478 }
479
480 let priority = u16::from_be_bytes([rdata[0], rdata[1]]);
481 let (target, name_consumed) = DnsName::decode(packet, rdata_offset + 2)?;
482
483 let params_start = 2 + name_consumed;
484 let params = if params_start < rdlen {
485 SvcParam::parse_all(&rdata[params_start..])?
486 } else {
487 Vec::new()
488 };
489
490 if is_https {
491 Ok(DnsRData::HTTPS {
492 priority,
493 target,
494 params,
495 })
496 } else {
497 Ok(DnsRData::SVCB {
498 priority,
499 target,
500 params,
501 })
502 }
503 }
504
505 fn parse_caa(rdata: &[u8]) -> Result<Self, FieldError> {
506 if rdata.len() < 2 {
507 return Err(FieldError::BufferTooShort {
508 offset: 0,
509 need: 2,
510 have: rdata.len(),
511 });
512 }
513
514 let flags = rdata[0];
515 let tag_len = rdata[1] as usize;
516
517 if 2 + tag_len > rdata.len() {
518 return Err(FieldError::BufferTooShort {
519 offset: 2,
520 need: tag_len,
521 have: rdata.len() - 2,
522 });
523 }
524
525 let tag = String::from_utf8_lossy(&rdata[2..2 + tag_len]).into_owned();
526 let value = rdata[2 + tag_len..].to_vec();
527
528 Ok(DnsRData::CAA { flags, tag, value })
529 }
530
531 fn parse_rrsig(
532 packet: &[u8],
533 rdata_offset: usize,
534 rdata: &[u8],
535 rdlen: usize,
536 ) -> Result<Self, FieldError> {
537 if rdata.len() < 18 {
538 return Err(FieldError::BufferTooShort {
539 offset: 0,
540 need: 18,
541 have: rdata.len(),
542 });
543 }
544
545 let type_covered = u16::from_be_bytes([rdata[0], rdata[1]]);
546 let algorithm = rdata[2];
547 let labels = rdata[3];
548 let original_ttl = u32::from_be_bytes([rdata[4], rdata[5], rdata[6], rdata[7]]);
549 let sig_expiration = u32::from_be_bytes([rdata[8], rdata[9], rdata[10], rdata[11]]);
550 let sig_inception = u32::from_be_bytes([rdata[12], rdata[13], rdata[14], rdata[15]]);
551 let key_tag = u16::from_be_bytes([rdata[16], rdata[17]]);
552
553 let (signer_name, name_consumed) = DnsName::decode(packet, rdata_offset + 18)?;
554 let sig_start = 18 + name_consumed;
555
556 let signature = if sig_start < rdlen {
557 rdata[sig_start..].to_vec()
558 } else {
559 Vec::new()
560 };
561
562 Ok(DnsRData::RRSIG {
563 type_covered,
564 algorithm,
565 labels,
566 original_ttl,
567 sig_expiration,
568 sig_inception,
569 key_tag,
570 signer_name,
571 signature,
572 })
573 }
574
575 fn parse_nsec(
576 packet: &[u8],
577 rdata_offset: usize,
578 rdata: &[u8],
579 rdlen: usize,
580 ) -> Result<Self, FieldError> {
581 let (next_domain, name_consumed) = DnsName::decode(packet, rdata_offset)?;
582
583 let type_bitmaps = if name_consumed < rdlen {
584 bitmap::bitmap_to_rr_list(&rdata[name_consumed..])?
585 } else {
586 Vec::new()
587 };
588
589 Ok(DnsRData::NSEC {
590 next_domain,
591 type_bitmaps,
592 })
593 }
594
595 fn parse_nsec3(rdata: &[u8]) -> Result<Self, FieldError> {
596 if rdata.len() < 5 {
597 return Err(FieldError::BufferTooShort {
598 offset: 0,
599 need: 5,
600 have: rdata.len(),
601 });
602 }
603
604 let hash_algorithm = rdata[0];
605 let flags = rdata[1];
606 let iterations = u16::from_be_bytes([rdata[2], rdata[3]]);
607 let salt_len = rdata[4] as usize;
608 let mut pos = 5;
609
610 if pos + salt_len >= rdata.len() {
611 return Err(FieldError::BufferTooShort {
612 offset: pos,
613 need: salt_len + 1, have: rdata.len() - pos,
615 });
616 }
617 let salt = rdata[pos..pos + salt_len].to_vec();
618 pos += salt_len;
619
620 let hash_len = rdata[pos] as usize;
621 pos += 1;
622
623 if pos + hash_len > rdata.len() {
624 return Err(FieldError::BufferTooShort {
625 offset: pos,
626 need: hash_len,
627 have: rdata.len() - pos,
628 });
629 }
630 let next_hashed = rdata[pos..pos + hash_len].to_vec();
631 pos += hash_len;
632
633 let type_bitmaps = if pos < rdata.len() {
634 bitmap::bitmap_to_rr_list(&rdata[pos..])?
635 } else {
636 Vec::new()
637 };
638
639 Ok(DnsRData::NSEC3 {
640 hash_algorithm,
641 flags,
642 iterations,
643 salt,
644 next_hashed,
645 type_bitmaps,
646 })
647 }
648
649 fn parse_nsec3param(rdata: &[u8]) -> Result<Self, FieldError> {
650 if rdata.len() < 5 {
651 return Err(FieldError::BufferTooShort {
652 offset: 0,
653 need: 5,
654 have: rdata.len(),
655 });
656 }
657
658 let hash_algorithm = rdata[0];
659 let flags = rdata[1];
660 let iterations = u16::from_be_bytes([rdata[2], rdata[3]]);
661 let salt_len = rdata[4] as usize;
662
663 if 5 + salt_len > rdata.len() {
664 return Err(FieldError::BufferTooShort {
665 offset: 5,
666 need: salt_len,
667 have: rdata.len() - 5,
668 });
669 }
670
671 let salt = rdata[5..5 + salt_len].to_vec();
672
673 Ok(DnsRData::NSEC3PARAM {
674 hash_algorithm,
675 flags,
676 iterations,
677 salt,
678 })
679 }
680
681 fn parse_dnskey(rdata: &[u8]) -> Result<Self, FieldError> {
682 if rdata.len() < 4 {
683 return Err(FieldError::BufferTooShort {
684 offset: 0,
685 need: 4,
686 have: rdata.len(),
687 });
688 }
689
690 let flags = u16::from_be_bytes([rdata[0], rdata[1]]);
691 let protocol = rdata[2];
692 let algorithm = rdata[3];
693 let public_key = rdata[4..].to_vec();
694
695 Ok(DnsRData::DNSKEY {
696 flags,
697 protocol,
698 algorithm,
699 public_key,
700 })
701 }
702
703 fn parse_ds(rdata: &[u8]) -> Result<Self, FieldError> {
704 if rdata.len() < 4 {
705 return Err(FieldError::BufferTooShort {
706 offset: 0,
707 need: 4,
708 have: rdata.len(),
709 });
710 }
711
712 let key_tag = u16::from_be_bytes([rdata[0], rdata[1]]);
713 let algorithm = rdata[2];
714 let digest_type = rdata[3];
715 let digest = rdata[4..].to_vec();
716
717 Ok(DnsRData::DS {
718 key_tag,
719 algorithm,
720 digest_type,
721 digest,
722 })
723 }
724
725 fn parse_dlv(rdata: &[u8]) -> Result<Self, FieldError> {
726 if rdata.len() < 4 {
728 return Err(FieldError::BufferTooShort {
729 offset: 0,
730 need: 4,
731 have: rdata.len(),
732 });
733 }
734
735 let key_tag = u16::from_be_bytes([rdata[0], rdata[1]]);
736 let algorithm = rdata[2];
737 let digest_type = rdata[3];
738 let digest = rdata[4..].to_vec();
739
740 Ok(DnsRData::DLV {
741 key_tag,
742 algorithm,
743 digest_type,
744 digest,
745 })
746 }
747
748 fn parse_tsig(
749 packet: &[u8],
750 rdata_offset: usize,
751 rdata_end: usize,
752 ) -> Result<Self, FieldError> {
753 let (algorithm_name, name_consumed) = DnsName::decode(packet, rdata_offset)?;
754 let mut pos = rdata_offset + name_consumed;
755
756 if pos + 6 > rdata_end {
758 return Err(FieldError::BufferTooShort {
759 offset: pos,
760 need: 6,
761 have: rdata_end.saturating_sub(pos),
762 });
763 }
764 let time_signed = ((packet[pos] as u64) << 40)
765 | ((packet[pos + 1] as u64) << 32)
766 | ((packet[pos + 2] as u64) << 24)
767 | ((packet[pos + 3] as u64) << 16)
768 | ((packet[pos + 4] as u64) << 8)
769 | (packet[pos + 5] as u64);
770 pos += 6;
771
772 if pos + 2 > rdata_end {
774 return Err(FieldError::BufferTooShort {
775 offset: pos,
776 need: 2,
777 have: rdata_end.saturating_sub(pos),
778 });
779 }
780 let fudge = u16::from_be_bytes([packet[pos], packet[pos + 1]]);
781 pos += 2;
782
783 if pos + 2 > rdata_end {
785 return Err(FieldError::BufferTooShort {
786 offset: pos,
787 need: 2,
788 have: rdata_end.saturating_sub(pos),
789 });
790 }
791 let mac_size = u16::from_be_bytes([packet[pos], packet[pos + 1]]) as usize;
792 pos += 2;
793
794 if pos + mac_size > rdata_end {
795 return Err(FieldError::BufferTooShort {
796 offset: pos,
797 need: mac_size,
798 have: rdata_end.saturating_sub(pos),
799 });
800 }
801 let mac = packet[pos..pos + mac_size].to_vec();
802 pos += mac_size;
803
804 if pos + 6 > rdata_end {
806 return Err(FieldError::BufferTooShort {
807 offset: pos,
808 need: 6,
809 have: rdata_end.saturating_sub(pos),
810 });
811 }
812 let original_id = u16::from_be_bytes([packet[pos], packet[pos + 1]]);
813 let error = u16::from_be_bytes([packet[pos + 2], packet[pos + 3]]);
814 let other_len = u16::from_be_bytes([packet[pos + 4], packet[pos + 5]]) as usize;
815 pos += 6;
816
817 if pos + other_len > rdata_end {
818 return Err(FieldError::BufferTooShort {
819 offset: pos,
820 need: other_len,
821 have: rdata_end.saturating_sub(pos),
822 });
823 }
824 let other_data = packet[pos..pos + other_len].to_vec();
825
826 Ok(DnsRData::TSIG {
827 algorithm_name,
828 time_signed,
829 fudge,
830 mac,
831 original_id,
832 error,
833 other_data,
834 })
835 }
836
837 fn parse_tlsa(rdata: &[u8]) -> Result<Self, FieldError> {
838 if rdata.len() < 3 {
839 return Err(FieldError::BufferTooShort {
840 offset: 0,
841 need: 3,
842 have: rdata.len(),
843 });
844 }
845
846 let usage = rdata[0];
847 let selector = rdata[1];
848 let matching_type = rdata[2];
849 let cert_data = rdata[3..].to_vec();
850
851 Ok(DnsRData::TLSA {
852 usage,
853 selector,
854 matching_type,
855 cert_data,
856 })
857 }
858
859 fn parse_opt(rdata: &[u8]) -> Result<Self, FieldError> {
860 let options = EdnsOption::parse_all(rdata)?;
861 Ok(DnsRData::OPT(options))
862 }
863
864 fn parse_character_string(data: &[u8], offset: usize) -> Result<(Vec<u8>, usize), FieldError> {
867 if offset >= data.len() {
868 return Err(FieldError::BufferTooShort {
869 offset,
870 need: 1,
871 have: 0,
872 });
873 }
874 let len = data[offset] as usize;
875 if offset + 1 + len > data.len() {
876 return Err(FieldError::BufferTooShort {
877 offset: offset + 1,
878 need: len,
879 have: data.len() - offset - 1,
880 });
881 }
882 Ok((data[offset + 1..offset + 1 + len].to_vec(), 1 + len))
883 }
884
885 pub fn build(&self) -> Vec<u8> {
891 match self {
892 DnsRData::A(addr) => addr.octets().to_vec(),
893
894 DnsRData::AAAA(addr) => addr.octets().to_vec(),
895
896 DnsRData::NS(name)
897 | DnsRData::CNAME(name)
898 | DnsRData::PTR(name)
899 | DnsRData::DNAME(name) => name.encode(),
900
901 DnsRData::MX {
902 preference,
903 exchange,
904 } => {
905 let mut out = Vec::new();
906 out.extend_from_slice(&preference.to_be_bytes());
907 out.extend_from_slice(&exchange.encode());
908 out
909 }
910
911 DnsRData::TXT(strings) => {
912 let mut out = Vec::new();
913 for s in strings {
914 out.push(s.len() as u8);
915 out.extend_from_slice(s);
916 }
917 out
918 }
919
920 DnsRData::SOA {
921 mname,
922 rname,
923 serial,
924 refresh,
925 retry,
926 expire,
927 minimum,
928 } => {
929 let mut out = Vec::new();
930 out.extend_from_slice(&mname.encode());
931 out.extend_from_slice(&rname.encode());
932 out.extend_from_slice(&serial.to_be_bytes());
933 out.extend_from_slice(&refresh.to_be_bytes());
934 out.extend_from_slice(&retry.to_be_bytes());
935 out.extend_from_slice(&expire.to_be_bytes());
936 out.extend_from_slice(&minimum.to_be_bytes());
937 out
938 }
939
940 DnsRData::SRV {
941 priority,
942 weight,
943 port,
944 target,
945 } => {
946 let mut out = Vec::new();
947 out.extend_from_slice(&priority.to_be_bytes());
948 out.extend_from_slice(&weight.to_be_bytes());
949 out.extend_from_slice(&port.to_be_bytes());
950 out.extend_from_slice(&target.encode());
951 out
952 }
953
954 DnsRData::HINFO { cpu, os } => {
955 let mut out = Vec::new();
956 out.push(cpu.len() as u8);
957 out.extend_from_slice(cpu);
958 out.push(os.len() as u8);
959 out.extend_from_slice(os);
960 out
961 }
962
963 DnsRData::NAPTR {
964 order,
965 preference,
966 flags,
967 services,
968 regexp,
969 replacement,
970 } => {
971 let mut out = Vec::new();
972 out.extend_from_slice(&order.to_be_bytes());
973 out.extend_from_slice(&preference.to_be_bytes());
974 out.push(flags.len() as u8);
975 out.extend_from_slice(flags);
976 out.push(services.len() as u8);
977 out.extend_from_slice(services);
978 out.push(regexp.len() as u8);
979 out.extend_from_slice(regexp);
980 out.extend_from_slice(&replacement.encode());
981 out
982 }
983
984 DnsRData::SVCB {
985 priority,
986 target,
987 params,
988 }
989 | DnsRData::HTTPS {
990 priority,
991 target,
992 params,
993 } => {
994 let mut out = Vec::new();
995 out.extend_from_slice(&priority.to_be_bytes());
996 out.extend_from_slice(&target.encode());
997 for p in params {
998 out.extend_from_slice(&p.build());
999 }
1000 out
1001 }
1002
1003 DnsRData::CAA { flags, tag, value } => {
1004 let mut out = Vec::new();
1005 out.push(*flags);
1006 out.push(tag.len() as u8);
1007 out.extend_from_slice(tag.as_bytes());
1008 out.extend_from_slice(value);
1009 out
1010 }
1011
1012 DnsRData::RRSIG {
1013 type_covered,
1014 algorithm,
1015 labels,
1016 original_ttl,
1017 sig_expiration,
1018 sig_inception,
1019 key_tag,
1020 signer_name,
1021 signature,
1022 } => {
1023 let mut out = Vec::new();
1024 out.extend_from_slice(&type_covered.to_be_bytes());
1025 out.push(*algorithm);
1026 out.push(*labels);
1027 out.extend_from_slice(&original_ttl.to_be_bytes());
1028 out.extend_from_slice(&sig_expiration.to_be_bytes());
1029 out.extend_from_slice(&sig_inception.to_be_bytes());
1030 out.extend_from_slice(&key_tag.to_be_bytes());
1031 out.extend_from_slice(&signer_name.encode());
1032 out.extend_from_slice(signature);
1033 out
1034 }
1035
1036 DnsRData::NSEC {
1037 next_domain,
1038 type_bitmaps,
1039 } => {
1040 let mut out = Vec::new();
1041 out.extend_from_slice(&next_domain.encode());
1042 out.extend_from_slice(&bitmap::rr_list_to_bitmap(type_bitmaps));
1043 out
1044 }
1045
1046 DnsRData::NSEC3 {
1047 hash_algorithm,
1048 flags,
1049 iterations,
1050 salt,
1051 next_hashed,
1052 type_bitmaps,
1053 } => {
1054 let mut out = Vec::new();
1055 out.push(*hash_algorithm);
1056 out.push(*flags);
1057 out.extend_from_slice(&iterations.to_be_bytes());
1058 out.push(salt.len() as u8);
1059 out.extend_from_slice(salt);
1060 out.push(next_hashed.len() as u8);
1061 out.extend_from_slice(next_hashed);
1062 out.extend_from_slice(&bitmap::rr_list_to_bitmap(type_bitmaps));
1063 out
1064 }
1065
1066 DnsRData::NSEC3PARAM {
1067 hash_algorithm,
1068 flags,
1069 iterations,
1070 salt,
1071 } => {
1072 let mut out = Vec::new();
1073 out.push(*hash_algorithm);
1074 out.push(*flags);
1075 out.extend_from_slice(&iterations.to_be_bytes());
1076 out.push(salt.len() as u8);
1077 out.extend_from_slice(salt);
1078 out
1079 }
1080
1081 DnsRData::DNSKEY {
1082 flags,
1083 protocol,
1084 algorithm,
1085 public_key,
1086 } => {
1087 let mut out = Vec::new();
1088 out.extend_from_slice(&flags.to_be_bytes());
1089 out.push(*protocol);
1090 out.push(*algorithm);
1091 out.extend_from_slice(public_key);
1092 out
1093 }
1094
1095 DnsRData::DS {
1096 key_tag,
1097 algorithm,
1098 digest_type,
1099 digest,
1100 }
1101 | DnsRData::DLV {
1102 key_tag,
1103 algorithm,
1104 digest_type,
1105 digest,
1106 } => {
1107 let mut out = Vec::new();
1108 out.extend_from_slice(&key_tag.to_be_bytes());
1109 out.push(*algorithm);
1110 out.push(*digest_type);
1111 out.extend_from_slice(digest);
1112 out
1113 }
1114
1115 DnsRData::TSIG {
1116 algorithm_name,
1117 time_signed,
1118 fudge,
1119 mac,
1120 original_id,
1121 error,
1122 other_data,
1123 } => {
1124 let mut out = Vec::new();
1125 out.extend_from_slice(&algorithm_name.encode());
1126 out.push((time_signed >> 40) as u8);
1128 out.push((time_signed >> 32) as u8);
1129 out.push((time_signed >> 24) as u8);
1130 out.push((time_signed >> 16) as u8);
1131 out.push((time_signed >> 8) as u8);
1132 out.push(*time_signed as u8);
1133 out.extend_from_slice(&fudge.to_be_bytes());
1134 out.extend_from_slice(&(mac.len() as u16).to_be_bytes());
1135 out.extend_from_slice(mac);
1136 out.extend_from_slice(&original_id.to_be_bytes());
1137 out.extend_from_slice(&error.to_be_bytes());
1138 out.extend_from_slice(&(other_data.len() as u16).to_be_bytes());
1139 out.extend_from_slice(other_data);
1140 out
1141 }
1142
1143 DnsRData::TLSA {
1144 usage,
1145 selector,
1146 matching_type,
1147 cert_data,
1148 } => {
1149 let mut out = Vec::new();
1150 out.push(*usage);
1151 out.push(*selector);
1152 out.push(*matching_type);
1153 out.extend_from_slice(cert_data);
1154 out
1155 }
1156
1157 DnsRData::OPT(options) => {
1158 let mut out = Vec::new();
1159 for opt in options {
1160 out.extend_from_slice(&opt.build());
1161 }
1162 out
1163 }
1164
1165 DnsRData::Unknown { data, .. } => data.clone(),
1166 }
1167 }
1168
1169 pub fn build_compressed(&self, offset: usize, map: &mut HashMap<String, u16>) -> Vec<u8> {
1181 match self {
1182 DnsRData::NS(name)
1183 | DnsRData::CNAME(name)
1184 | DnsRData::PTR(name)
1185 | DnsRData::DNAME(name) => name.encode_compressed(offset, map),
1186
1187 DnsRData::MX {
1188 preference,
1189 exchange,
1190 } => {
1191 let mut out = Vec::new();
1192 out.extend_from_slice(&preference.to_be_bytes());
1193 let name_bytes = exchange.encode_compressed(offset + 2, map);
1194 out.extend_from_slice(&name_bytes);
1195 out
1196 }
1197
1198 DnsRData::SOA {
1199 mname,
1200 rname,
1201 serial,
1202 refresh,
1203 retry,
1204 expire,
1205 minimum,
1206 } => {
1207 let mut out = Vec::new();
1208 let mname_bytes = mname.encode_compressed(offset, map);
1209 out.extend_from_slice(&mname_bytes);
1210 let rname_bytes = rname.encode_compressed(offset + mname_bytes.len(), map);
1211 out.extend_from_slice(&rname_bytes);
1212 out.extend_from_slice(&serial.to_be_bytes());
1213 out.extend_from_slice(&refresh.to_be_bytes());
1214 out.extend_from_slice(&retry.to_be_bytes());
1215 out.extend_from_slice(&expire.to_be_bytes());
1216 out.extend_from_slice(&minimum.to_be_bytes());
1217 out
1218 }
1219
1220 DnsRData::SRV {
1221 priority,
1222 weight,
1223 port,
1224 target,
1225 } => {
1226 let mut out = Vec::new();
1227 out.extend_from_slice(&priority.to_be_bytes());
1228 out.extend_from_slice(&weight.to_be_bytes());
1229 out.extend_from_slice(&port.to_be_bytes());
1230 out.extend_from_slice(&target.encode());
1232 out
1233 }
1234
1235 DnsRData::NAPTR {
1236 order,
1237 preference,
1238 flags,
1239 services,
1240 regexp,
1241 replacement,
1242 } => {
1243 let mut out = Vec::new();
1244 out.extend_from_slice(&order.to_be_bytes());
1245 out.extend_from_slice(&preference.to_be_bytes());
1246 out.push(flags.len() as u8);
1247 out.extend_from_slice(flags);
1248 out.push(services.len() as u8);
1249 out.extend_from_slice(services);
1250 out.push(regexp.len() as u8);
1251 out.extend_from_slice(regexp);
1252 let name_bytes = replacement.encode_compressed(offset + out.len(), map);
1253 out.extend_from_slice(&name_bytes);
1254 out
1255 }
1256
1257 DnsRData::RRSIG {
1258 type_covered,
1259 algorithm,
1260 labels,
1261 original_ttl,
1262 sig_expiration,
1263 sig_inception,
1264 key_tag,
1265 signer_name,
1266 signature,
1267 } => {
1268 let mut out = Vec::new();
1269 out.extend_from_slice(&type_covered.to_be_bytes());
1270 out.push(*algorithm);
1271 out.push(*labels);
1272 out.extend_from_slice(&original_ttl.to_be_bytes());
1273 out.extend_from_slice(&sig_expiration.to_be_bytes());
1274 out.extend_from_slice(&sig_inception.to_be_bytes());
1275 out.extend_from_slice(&key_tag.to_be_bytes());
1276 let name_bytes = signer_name.encode_compressed(offset + out.len(), map);
1279 out.extend_from_slice(&name_bytes);
1280 out.extend_from_slice(signature);
1281 out
1282 }
1283
1284 DnsRData::NSEC {
1285 next_domain,
1286 type_bitmaps,
1287 } => {
1288 let mut out = Vec::new();
1289 out.extend_from_slice(&next_domain.encode());
1291 out.extend_from_slice(&bitmap::rr_list_to_bitmap(type_bitmaps));
1292 out
1293 }
1294
1295 DnsRData::SVCB { .. } | DnsRData::HTTPS { .. } => self.build(),
1297
1298 _ => self.build(),
1300 }
1301 }
1302
1303 pub fn summary(&self) -> String {
1309 match self {
1310 DnsRData::A(addr) => addr.to_string(),
1311
1312 DnsRData::AAAA(addr) => addr.to_string(),
1313
1314 DnsRData::NS(name) => format!("NS {}", name),
1315
1316 DnsRData::CNAME(name) => format!("CNAME {}", name),
1317
1318 DnsRData::PTR(name) => format!("PTR {}", name),
1319
1320 DnsRData::DNAME(name) => format!("DNAME {}", name),
1321
1322 DnsRData::MX {
1323 preference,
1324 exchange,
1325 } => {
1326 format!("MX {} {}", preference, exchange)
1327 }
1328
1329 DnsRData::TXT(strings) => {
1330 let parts: Vec<String> = strings
1331 .iter()
1332 .map(|s| format!("\"{}\"", String::from_utf8_lossy(s)))
1333 .collect();
1334 format!("TXT {}", parts.join(" "))
1335 }
1336
1337 DnsRData::SOA {
1338 mname,
1339 rname,
1340 serial,
1341 refresh,
1342 retry,
1343 expire,
1344 minimum,
1345 } => {
1346 format!(
1347 "SOA {} {} {} {} {} {} {}",
1348 mname, rname, serial, refresh, retry, expire, minimum
1349 )
1350 }
1351
1352 DnsRData::SRV {
1353 priority,
1354 weight,
1355 port,
1356 target,
1357 } => {
1358 format!("SRV {} {} {} {}", priority, weight, port, target)
1359 }
1360
1361 DnsRData::HINFO { cpu, os } => {
1362 format!(
1363 "HINFO \"{}\" \"{}\"",
1364 String::from_utf8_lossy(cpu),
1365 String::from_utf8_lossy(os)
1366 )
1367 }
1368
1369 DnsRData::NAPTR {
1370 order,
1371 preference,
1372 flags,
1373 services,
1374 regexp,
1375 replacement,
1376 } => {
1377 format!(
1378 "NAPTR {} {} \"{}\" \"{}\" \"{}\" {}",
1379 order,
1380 preference,
1381 String::from_utf8_lossy(flags),
1382 String::from_utf8_lossy(services),
1383 String::from_utf8_lossy(regexp),
1384 replacement
1385 )
1386 }
1387
1388 DnsRData::SVCB {
1389 priority,
1390 target,
1391 params,
1392 } => {
1393 let param_strs: Vec<String> = params
1394 .iter()
1395 .map(|p| {
1396 let val = p.build_value();
1397 format!("key{}={} bytes", p.key(), val.len())
1398 })
1399 .collect();
1400 format!("SVCB {} {} {}", priority, target, param_strs.join(" "))
1401 }
1402
1403 DnsRData::HTTPS {
1404 priority,
1405 target,
1406 params,
1407 } => {
1408 let param_strs: Vec<String> = params
1409 .iter()
1410 .map(|p| {
1411 let val = p.build_value();
1412 format!("key{}={} bytes", p.key(), val.len())
1413 })
1414 .collect();
1415 format!("HTTPS {} {} {}", priority, target, param_strs.join(" "))
1416 }
1417
1418 DnsRData::CAA { flags, tag, value } => {
1419 format!(
1420 "CAA {} {} \"{}\"",
1421 flags,
1422 tag,
1423 String::from_utf8_lossy(value)
1424 )
1425 }
1426
1427 DnsRData::RRSIG {
1428 type_covered,
1429 algorithm,
1430 labels,
1431 original_ttl,
1432 key_tag,
1433 signer_name,
1434 ..
1435 } => {
1436 format!(
1437 "RRSIG {} {} {} {} {} {}",
1438 types::dns_type_name(*type_covered),
1439 algorithm,
1440 labels,
1441 original_ttl,
1442 key_tag,
1443 signer_name
1444 )
1445 }
1446
1447 DnsRData::NSEC {
1448 next_domain,
1449 type_bitmaps,
1450 } => {
1451 let type_names: Vec<&str> = type_bitmaps
1452 .iter()
1453 .map(|t| types::dns_type_name(*t))
1454 .collect();
1455 format!("NSEC {} [{}]", next_domain, type_names.join(" "))
1456 }
1457
1458 DnsRData::NSEC3 {
1459 hash_algorithm,
1460 iterations,
1461 next_hashed,
1462 type_bitmaps,
1463 ..
1464 } => {
1465 let type_names: Vec<&str> = type_bitmaps
1466 .iter()
1467 .map(|t| types::dns_type_name(*t))
1468 .collect();
1469 format!(
1470 "NSEC3 alg={} iter={} hash={} [{}]",
1471 hash_algorithm,
1472 iterations,
1473 hex(next_hashed),
1474 type_names.join(" ")
1475 )
1476 }
1477
1478 DnsRData::NSEC3PARAM {
1479 hash_algorithm,
1480 flags,
1481 iterations,
1482 salt,
1483 } => {
1484 format!(
1485 "NSEC3PARAM alg={} flags={} iter={} salt={}",
1486 hash_algorithm,
1487 flags,
1488 iterations,
1489 if salt.is_empty() {
1490 "-".to_string()
1491 } else {
1492 hex(salt)
1493 }
1494 )
1495 }
1496
1497 DnsRData::DNSKEY {
1498 flags,
1499 protocol,
1500 algorithm,
1501 public_key,
1502 } => {
1503 format!(
1504 "DNSKEY flags={} proto={} alg={} key={} bytes",
1505 flags,
1506 protocol,
1507 algorithm,
1508 public_key.len()
1509 )
1510 }
1511
1512 DnsRData::DS {
1513 key_tag,
1514 algorithm,
1515 digest_type,
1516 digest,
1517 } => {
1518 format!(
1519 "DS {} {} {} {}",
1520 key_tag,
1521 algorithm,
1522 digest_type,
1523 hex(digest)
1524 )
1525 }
1526
1527 DnsRData::DLV {
1528 key_tag,
1529 algorithm,
1530 digest_type,
1531 digest,
1532 } => {
1533 format!(
1534 "DLV {} {} {} {}",
1535 key_tag,
1536 algorithm,
1537 digest_type,
1538 hex(digest)
1539 )
1540 }
1541
1542 DnsRData::TSIG {
1543 algorithm_name,
1544 original_id,
1545 error,
1546 mac,
1547 ..
1548 } => {
1549 format!(
1550 "TSIG {} id={} err={} mac={} bytes",
1551 algorithm_name,
1552 original_id,
1553 error,
1554 mac.len()
1555 )
1556 }
1557
1558 DnsRData::TLSA {
1559 usage,
1560 selector,
1561 matching_type,
1562 cert_data,
1563 } => {
1564 format!(
1565 "TLSA {} {} {} {} bytes",
1566 usage,
1567 selector,
1568 matching_type,
1569 cert_data.len()
1570 )
1571 }
1572
1573 DnsRData::OPT(options) => {
1574 if options.is_empty() {
1575 "OPT (empty)".to_string()
1576 } else {
1577 let summaries: Vec<String> = options.iter().map(|o| o.summary()).collect();
1578 format!("OPT [{}]", summaries.join(", "))
1579 }
1580 }
1581
1582 DnsRData::Unknown { rtype, data } => {
1583 format!("TYPE{} ({} bytes)", rtype, data.len())
1584 }
1585 }
1586 }
1587}
1588
1589fn hex(data: &[u8]) -> String {
1591 data.iter().map(|b| format!("{:02x}", b)).collect()
1592}
1593
1594#[cfg(test)]
1599mod tests {
1600 use super::*;
1601
1602 fn roundtrip(rtype: u16, rdata: &DnsRData) -> DnsRData {
1606 let built = rdata.build();
1607 DnsRData::parse(rtype, &built, 0, built.len() as u16).unwrap()
1608 }
1609
1610 #[test]
1615 fn test_a_parse() {
1616 let wire = [192, 0, 2, 1]; let rdata = DnsRData::parse(rr_type::A, &wire, 0, 4).unwrap();
1618 assert_eq!(rdata, DnsRData::A(Ipv4Addr::new(192, 0, 2, 1)));
1619 }
1620
1621 #[test]
1622 fn test_a_build_roundtrip() {
1623 let original = DnsRData::A(Ipv4Addr::new(10, 0, 0, 1));
1624 let result = roundtrip(rr_type::A, &original);
1625 assert_eq!(result, original);
1626 }
1627
1628 #[test]
1629 fn test_a_invalid_length() {
1630 let wire = [192, 0, 2]; assert!(DnsRData::parse(rr_type::A, &wire, 0, 3).is_err());
1632 }
1633
1634 #[test]
1639 fn test_aaaa_parse() {
1640 let wire = [
1641 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1642 0x00, 0x01,
1643 ];
1644 let rdata = DnsRData::parse(rr_type::AAAA, &wire, 0, 16).unwrap();
1645 assert_eq!(rdata, DnsRData::AAAA("2001:db8::1".parse().unwrap()));
1646 }
1647
1648 #[test]
1649 fn test_aaaa_build_roundtrip() {
1650 let original = DnsRData::AAAA("::1".parse().unwrap());
1651 let result = roundtrip(rr_type::AAAA, &original);
1652 assert_eq!(result, original);
1653 }
1654
1655 #[test]
1656 fn test_aaaa_invalid_length() {
1657 let wire = [0u8; 15]; assert!(DnsRData::parse(rr_type::AAAA, &wire, 0, 15).is_err());
1659 }
1660
1661 #[test]
1666 fn test_mx_parse() {
1667 let mut wire = Vec::new();
1669 wire.extend_from_slice(&10u16.to_be_bytes());
1670 wire.extend_from_slice(&DnsName::from("mail.example.com").encode());
1671 let rdlen = wire.len() as u16;
1672
1673 let rdata = DnsRData::parse(rr_type::MX, &wire, 0, rdlen).unwrap();
1674 match &rdata {
1675 DnsRData::MX {
1676 preference,
1677 exchange,
1678 } => {
1679 assert_eq!(*preference, 10);
1680 assert_eq!(exchange.to_fqdn(), "mail.example.com.");
1681 }
1682 _ => panic!("expected MX, got {:?}", rdata),
1683 }
1684 }
1685
1686 #[test]
1687 fn test_mx_build_roundtrip() {
1688 let original = DnsRData::MX {
1689 preference: 20,
1690 exchange: DnsName::from("mx.test.org"),
1691 };
1692 let result = roundtrip(rr_type::MX, &original);
1693 assert_eq!(result, original);
1694 }
1695
1696 #[test]
1701 fn test_txt_single_string() {
1702 let text = b"v=spf1 include:example.com ~all";
1703 let mut wire = Vec::new();
1704 wire.push(text.len() as u8);
1705 wire.extend_from_slice(text);
1706 let rdlen = wire.len() as u16;
1707
1708 let rdata = DnsRData::parse(rr_type::TXT, &wire, 0, rdlen).unwrap();
1709 match &rdata {
1710 DnsRData::TXT(strings) => {
1711 assert_eq!(strings.len(), 1);
1712 assert_eq!(strings[0], text.to_vec());
1713 }
1714 _ => panic!("expected TXT"),
1715 }
1716 }
1717
1718 #[test]
1719 fn test_txt_multiple_strings() {
1720 let s1 = b"hello";
1721 let s2 = b"world";
1722 let mut wire = Vec::new();
1723 wire.push(s1.len() as u8);
1724 wire.extend_from_slice(s1);
1725 wire.push(s2.len() as u8);
1726 wire.extend_from_slice(s2);
1727 let rdlen = wire.len() as u16;
1728
1729 let rdata = DnsRData::parse(rr_type::TXT, &wire, 0, rdlen).unwrap();
1730 match &rdata {
1731 DnsRData::TXT(strings) => {
1732 assert_eq!(strings.len(), 2);
1733 assert_eq!(strings[0], s1.to_vec());
1734 assert_eq!(strings[1], s2.to_vec());
1735 }
1736 _ => panic!("expected TXT"),
1737 }
1738 }
1739
1740 #[test]
1741 fn test_txt_zero_length_string() {
1742 let mut wire = Vec::new();
1743 wire.push(0); wire.push(5); wire.extend_from_slice(b"hello");
1746 let rdlen = wire.len() as u16;
1747
1748 let rdata = DnsRData::parse(rr_type::TXT, &wire, 0, rdlen).unwrap();
1749 match &rdata {
1750 DnsRData::TXT(strings) => {
1751 assert_eq!(strings.len(), 2);
1752 assert!(strings[0].is_empty());
1753 assert_eq!(strings[1], b"hello".to_vec());
1754 }
1755 _ => panic!("expected TXT"),
1756 }
1757 }
1758
1759 #[test]
1760 fn test_txt_build_roundtrip() {
1761 let original = DnsRData::TXT(vec![
1762 b"first".to_vec(),
1763 Vec::new(), b"third".to_vec(),
1765 ]);
1766 let result = roundtrip(rr_type::TXT, &original);
1767 assert_eq!(result, original);
1768 }
1769
1770 #[test]
1775 fn test_soa_parse_and_roundtrip() {
1776 let original = DnsRData::SOA {
1777 mname: DnsName::from("ns1.example.com"),
1778 rname: DnsName::from("admin.example.com"),
1779 serial: 2024010101,
1780 refresh: 3600,
1781 retry: 900,
1782 expire: 604800,
1783 minimum: 86400,
1784 };
1785 let result = roundtrip(rr_type::SOA, &original);
1786 assert_eq!(result, original);
1787 }
1788
1789 #[test]
1790 fn test_soa_with_compressed_names() {
1791 let example_name = DnsName::from("example.com");
1794 let mut packet = example_name.encode(); let rdata_offset = packet.len();
1796
1797 let mut compression_map = HashMap::new();
1799 compression_map.insert("example.com".to_string(), 0u16);
1800
1801 let mname = DnsName::from("ns1.example.com");
1802 let mname_bytes = mname.encode_compressed(rdata_offset, &mut compression_map);
1803 packet.extend_from_slice(&mname_bytes);
1804
1805 let rname = DnsName::from("admin.example.com");
1806 let rname_offset = rdata_offset + mname_bytes.len();
1807 let rname_bytes = rname.encode_compressed(rname_offset, &mut compression_map);
1808 packet.extend_from_slice(&rname_bytes);
1809
1810 packet.extend_from_slice(&2024010101u32.to_be_bytes());
1812 packet.extend_from_slice(&3600u32.to_be_bytes());
1813 packet.extend_from_slice(&900u32.to_be_bytes());
1814 packet.extend_from_slice(&604800u32.to_be_bytes());
1815 packet.extend_from_slice(&86400u32.to_be_bytes());
1816
1817 let rdlen = (packet.len() - rdata_offset) as u16;
1818 let rdata = DnsRData::parse(rr_type::SOA, &packet, rdata_offset, rdlen).unwrap();
1819
1820 match &rdata {
1821 DnsRData::SOA {
1822 mname,
1823 rname,
1824 serial,
1825 ..
1826 } => {
1827 assert_eq!(mname.to_fqdn(), "ns1.example.com.");
1828 assert_eq!(rname.to_fqdn(), "admin.example.com.");
1829 assert_eq!(*serial, 2024010101);
1830 }
1831 _ => panic!("expected SOA"),
1832 }
1833 }
1834
1835 #[test]
1840 fn test_srv_build_roundtrip() {
1841 let original = DnsRData::SRV {
1842 priority: 10,
1843 weight: 60,
1844 port: 5060,
1845 target: DnsName::from("sipserver.example.com"),
1846 };
1847 let result = roundtrip(rr_type::SRV, &original);
1848 assert_eq!(result, original);
1849 }
1850
1851 #[test]
1856 fn test_cname_roundtrip() {
1857 let original = DnsRData::CNAME(DnsName::from("www.example.com"));
1858 let result = roundtrip(rr_type::CNAME, &original);
1859 assert_eq!(result, original);
1860 }
1861
1862 #[test]
1863 fn test_ns_roundtrip() {
1864 let original = DnsRData::NS(DnsName::from("ns1.example.com"));
1865 let result = roundtrip(rr_type::NS, &original);
1866 assert_eq!(result, original);
1867 }
1868
1869 #[test]
1870 fn test_ptr_roundtrip() {
1871 let original = DnsRData::PTR(DnsName::from("1.2.0.192.in-addr.arpa"));
1872 let result = roundtrip(rr_type::PTR, &original);
1873 assert_eq!(result, original);
1874 }
1875
1876 #[test]
1881 fn test_hinfo_roundtrip() {
1882 let original = DnsRData::HINFO {
1883 cpu: b"x86_64".to_vec(),
1884 os: b"Linux".to_vec(),
1885 };
1886 let result = roundtrip(rr_type::HINFO, &original);
1887 assert_eq!(result, original);
1888 }
1889
1890 #[test]
1895 fn test_caa_roundtrip() {
1896 let original = DnsRData::CAA {
1897 flags: 0,
1898 tag: "issue".to_string(),
1899 value: b"letsencrypt.org".to_vec(),
1900 };
1901 let result = roundtrip(rr_type::CAA, &original);
1902 assert_eq!(result, original);
1903 }
1904
1905 #[test]
1910 fn test_dnskey_roundtrip() {
1911 let original = DnsRData::DNSKEY {
1912 flags: 257, protocol: 3, algorithm: 13, public_key: vec![0x01, 0x02, 0x03, 0x04],
1916 };
1917 let result = roundtrip(rr_type::DNSKEY, &original);
1918 assert_eq!(result, original);
1919 }
1920
1921 #[test]
1926 fn test_ds_roundtrip() {
1927 let original = DnsRData::DS {
1928 key_tag: 12345,
1929 algorithm: 8,
1930 digest_type: 2,
1931 digest: vec![0xAA, 0xBB, 0xCC, 0xDD],
1932 };
1933 let result = roundtrip(rr_type::DS, &original);
1934 assert_eq!(result, original);
1935 }
1936
1937 #[test]
1942 fn test_nsec_roundtrip() {
1943 let original = DnsRData::NSEC {
1944 next_domain: DnsName::from("next.example.com"),
1945 type_bitmaps: vec![1, 2, 5, 6, 15, 16, 28, 46, 47], };
1947 let result = roundtrip(rr_type::NSEC, &original);
1948 assert_eq!(result, original);
1949 }
1950
1951 #[test]
1956 fn test_nsec3_roundtrip() {
1957 let original = DnsRData::NSEC3 {
1958 hash_algorithm: 1,
1959 flags: 0,
1960 iterations: 10,
1961 salt: vec![0xAA, 0xBB],
1962 next_hashed: vec![0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08],
1963 type_bitmaps: vec![1, 28], };
1965 let result = roundtrip(rr_type::NSEC3, &original);
1966 assert_eq!(result, original);
1967 }
1968
1969 #[test]
1970 fn test_nsec3_empty_salt() {
1971 let original = DnsRData::NSEC3 {
1972 hash_algorithm: 1,
1973 flags: 1,
1974 iterations: 0,
1975 salt: Vec::new(),
1976 next_hashed: vec![0x01, 0x02, 0x03, 0x04],
1977 type_bitmaps: vec![1],
1978 };
1979 let result = roundtrip(rr_type::NSEC3, &original);
1980 assert_eq!(result, original);
1981 }
1982
1983 #[test]
1988 fn test_nsec3param_roundtrip() {
1989 let original = DnsRData::NSEC3PARAM {
1990 hash_algorithm: 1,
1991 flags: 0,
1992 iterations: 10,
1993 salt: vec![0xDE, 0xAD],
1994 };
1995 let result = roundtrip(rr_type::NSEC3PARAM, &original);
1996 assert_eq!(result, original);
1997 }
1998
1999 #[test]
2004 fn test_rrsig_roundtrip() {
2005 let original = DnsRData::RRSIG {
2006 type_covered: rr_type::A,
2007 algorithm: 8,
2008 labels: 3,
2009 original_ttl: 3600,
2010 sig_expiration: 1700000000,
2011 sig_inception: 1690000000,
2012 key_tag: 54321,
2013 signer_name: DnsName::from("example.com"),
2014 signature: vec![0x01, 0x02, 0x03, 0x04, 0x05],
2015 };
2016 let result = roundtrip(rr_type::RRSIG, &original);
2017 assert_eq!(result, original);
2018 }
2019
2020 #[test]
2025 fn test_tlsa_roundtrip() {
2026 let original = DnsRData::TLSA {
2027 usage: 3, selector: 1, matching_type: 1, cert_data: vec![0xAB; 32],
2031 };
2032 let result = roundtrip(rr_type::TLSA, &original);
2033 assert_eq!(result, original);
2034 }
2035
2036 #[test]
2041 fn test_naptr_roundtrip() {
2042 let original = DnsRData::NAPTR {
2043 order: 100,
2044 preference: 10,
2045 flags: b"s".to_vec(),
2046 services: b"SIP+D2T".to_vec(),
2047 regexp: Vec::new(),
2048 replacement: DnsName::from("_sip._tcp.example.com"),
2049 };
2050 let result = roundtrip(rr_type::NAPTR, &original);
2051 assert_eq!(result, original);
2052 }
2053
2054 #[test]
2059 fn test_svcb_roundtrip() {
2060 let original = DnsRData::SVCB {
2061 priority: 1,
2062 target: DnsName::from("svc.example.com"),
2063 params: vec![SvcParam::Alpn(vec!["h2".to_string()]), SvcParam::Port(443)],
2064 };
2065 let result = roundtrip(rr_type::SVCB, &original);
2066 assert_eq!(result, original);
2067 }
2068
2069 #[test]
2070 fn test_https_roundtrip() {
2071 let original = DnsRData::HTTPS {
2072 priority: 1,
2073 target: DnsName::root(),
2074 params: vec![SvcParam::Alpn(vec!["h2".to_string(), "h3".to_string()])],
2075 };
2076 let result = roundtrip(rr_type::HTTPS, &original);
2077 assert_eq!(result, original);
2078 }
2079
2080 #[test]
2085 fn test_opt_roundtrip() {
2086 let original = DnsRData::OPT(vec![
2087 EdnsOption::NSID(b"my-ns".to_vec()),
2088 EdnsOption::Cookie {
2089 client: vec![1, 2, 3, 4, 5, 6, 7, 8],
2090 server: vec![11, 12, 13, 14, 15, 16, 17, 18],
2091 },
2092 ]);
2093 let result = roundtrip(rr_type::OPT, &original);
2094 assert_eq!(result, original);
2095 }
2096
2097 #[test]
2098 fn test_opt_empty() {
2099 let original = DnsRData::OPT(vec![]);
2100 let result = roundtrip(rr_type::OPT, &original);
2101 assert_eq!(result, original);
2102 }
2103
2104 #[test]
2109 fn test_tsig_roundtrip() {
2110 let original = DnsRData::TSIG {
2111 algorithm_name: DnsName::from("hmac-sha256"),
2112 time_signed: 1700000000,
2113 fudge: 300,
2114 mac: vec![0xAA; 32],
2115 original_id: 0x1234,
2116 error: 0,
2117 other_data: Vec::new(),
2118 };
2119 let result = roundtrip(rr_type::TSIG, &original);
2120 assert_eq!(result, original);
2121 }
2122
2123 #[test]
2128 fn test_dlv_roundtrip() {
2129 let original = DnsRData::DLV {
2130 key_tag: 9999,
2131 algorithm: 13,
2132 digest_type: 2,
2133 digest: vec![0x11, 0x22, 0x33, 0x44],
2134 };
2135 let result = roundtrip(rr_type::DLV, &original);
2136 assert_eq!(result, original);
2137 }
2138
2139 #[test]
2144 fn test_dname_roundtrip() {
2145 let original = DnsRData::DNAME(DnsName::from("target.example.com"));
2146 let result = roundtrip(rr_type::DNAME, &original);
2147 assert_eq!(result, original);
2148 }
2149
2150 #[test]
2155 fn test_unknown_roundtrip() {
2156 let original = DnsRData::Unknown {
2157 rtype: 9999,
2158 data: vec![0x01, 0x02, 0x03],
2159 };
2160 let built = original.build();
2161 let parsed = DnsRData::parse(9999, &built, 0, built.len() as u16).unwrap();
2162 assert_eq!(parsed, original);
2163 }
2164
2165 #[test]
2170 fn test_mx_compressed() {
2171 let rdata = DnsRData::MX {
2172 preference: 10,
2173 exchange: DnsName::from("mail.example.com"),
2174 };
2175
2176 let mut map = HashMap::new();
2177 map.insert("example.com".to_string(), 20u16);
2179
2180 let compressed = rdata.build_compressed(100, &mut map);
2181 let uncompressed = rdata.build();
2182
2183 assert!(compressed.len() < uncompressed.len());
2185
2186 assert_eq!(u16::from_be_bytes([compressed[0], compressed[1]]), 10);
2188 }
2189
2190 #[test]
2191 fn test_soa_compressed() {
2192 let rdata = DnsRData::SOA {
2193 mname: DnsName::from("ns1.example.com"),
2194 rname: DnsName::from("admin.example.com"),
2195 serial: 1,
2196 refresh: 2,
2197 retry: 3,
2198 expire: 4,
2199 minimum: 5,
2200 };
2201
2202 let mut map = HashMap::new();
2203 let compressed = rdata.build_compressed(0, &mut map);
2204
2205 let uncompressed = rdata.build();
2208 assert!(compressed.len() < uncompressed.len());
2209 }
2210
2211 #[test]
2216 fn test_summary_a() {
2217 let rdata = DnsRData::A(Ipv4Addr::new(1, 2, 3, 4));
2218 assert_eq!(rdata.summary(), "1.2.3.4");
2219 }
2220
2221 #[test]
2222 fn test_summary_aaaa() {
2223 let rdata = DnsRData::AAAA("::1".parse().unwrap());
2224 assert_eq!(rdata.summary(), "::1");
2225 }
2226
2227 #[test]
2228 fn test_summary_mx() {
2229 let rdata = DnsRData::MX {
2230 preference: 10,
2231 exchange: DnsName::from("mail.example.com"),
2232 };
2233 assert_eq!(rdata.summary(), "MX 10 mail.example.com.");
2234 }
2235
2236 #[test]
2237 fn test_summary_txt() {
2238 let rdata = DnsRData::TXT(vec![b"hello world".to_vec()]);
2239 assert_eq!(rdata.summary(), "TXT \"hello world\"");
2240 }
2241
2242 #[test]
2243 fn test_summary_unknown() {
2244 let rdata = DnsRData::Unknown {
2245 rtype: 9999,
2246 data: vec![0; 10],
2247 };
2248 assert_eq!(rdata.summary(), "TYPE9999 (10 bytes)");
2249 }
2250}