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