1#[cfg(feature = "logging")]
8use crate::log::{debug, trace};
9
10use crate::current_time_millis;
11use crate::error::{e_fmt, Error, Result};
12use crate::service_info::{is_unicast_link_local, DnsRegistry, MyIntf, ServiceInfo};
13
14use if_addrs::Interface;
15
16#[cfg(feature = "serde")]
17use serde::{Deserialize, Serialize};
18
19use std::{
20 any::Any,
21 cmp,
22 collections::HashMap,
23 convert::TryInto,
24 fmt,
25 hash::Hash,
26 net::{IpAddr, Ipv4Addr, Ipv6Addr},
27 str,
28};
29
30#[derive(Clone, Debug, Eq, Hash, PartialEq, Default)]
32#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
33pub struct InterfaceId {
34 pub name: String,
36
37 pub index: u32,
39}
40
41impl InterfaceId {
42 pub fn get_addrs(&self) -> Vec<IpAddr> {
44 if_addrs::get_if_addrs()
45 .unwrap_or_default()
46 .into_iter()
47 .filter(|iface| iface.index == Some(self.index))
48 .map(|iface| iface.ip())
49 .collect()
50 }
51}
52
53impl fmt::Display for InterfaceId {
54 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
55 write!(f, "{}('{}')", self.index, self.name)
56 }
57}
58
59impl From<&Interface> for InterfaceId {
60 fn from(interface: &Interface) -> Self {
61 InterfaceId {
62 name: interface.name.clone(),
63 index: interface.index.unwrap_or_default(),
64 }
65 }
66}
67
68#[derive(Debug, Clone, Eq, PartialEq, Hash)]
70#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
71pub struct ScopedIpV4 {
72 addr: Ipv4Addr,
73 interface_ids: Vec<InterfaceId>,
75}
76
77impl ScopedIpV4 {
78 pub fn new(addr: Ipv4Addr, interface_id: InterfaceId) -> Self {
80 Self {
81 addr,
82 interface_ids: vec![interface_id],
83 }
84 }
85
86 pub const fn addr(&self) -> &Ipv4Addr {
88 &self.addr
89 }
90
91 pub fn interface_ids(&self) -> &[InterfaceId] {
93 &self.interface_ids
94 }
95
96 pub(crate) fn add_interface_id(&mut self, id: InterfaceId) {
98 if !self.interface_ids.contains(&id) {
99 self.interface_ids.push(id);
100 }
101 }
102}
103
104#[derive(Debug, Clone, Eq, PartialEq, Hash)]
106#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
107pub struct ScopedIpV6 {
108 addr: Ipv6Addr,
109 scope_id: InterfaceId,
110}
111
112impl ScopedIpV6 {
113 pub const fn addr(&self) -> &Ipv6Addr {
115 &self.addr
116 }
117
118 pub const fn scope_id(&self) -> &InterfaceId {
120 &self.scope_id
121 }
122}
123
124#[derive(Debug, Clone, Eq, PartialEq, Hash)]
126#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
127#[non_exhaustive]
128pub enum ScopedIp {
129 V4(ScopedIpV4),
130 V6(ScopedIpV6),
131}
132
133impl ScopedIp {
134 pub const fn to_ip_addr(&self) -> IpAddr {
135 match self {
136 ScopedIp::V4(v4) => IpAddr::V4(v4.addr),
137 ScopedIp::V6(v6) => IpAddr::V6(v6.addr),
138 }
139 }
140
141 pub const fn is_ipv4(&self) -> bool {
142 matches!(self, ScopedIp::V4(_))
143 }
144
145 pub const fn is_ipv6(&self) -> bool {
146 matches!(self, ScopedIp::V6(_))
147 }
148
149 pub const fn is_loopback(&self) -> bool {
150 match self {
151 ScopedIp::V4(v4) => v4.addr.is_loopback(),
152 ScopedIp::V6(v6) => v6.addr.is_loopback(),
153 }
154 }
155}
156
157impl From<IpAddr> for ScopedIp {
158 fn from(ip: IpAddr) -> Self {
159 match ip {
160 IpAddr::V4(v4) => ScopedIp::V4(ScopedIpV4 {
161 addr: v4,
162 interface_ids: vec![],
163 }),
164 IpAddr::V6(v6) => ScopedIp::V6(ScopedIpV6 {
165 addr: v6,
166 scope_id: InterfaceId::default(),
167 }),
168 }
169 }
170}
171
172impl From<&Interface> for ScopedIp {
173 fn from(interface: &Interface) -> Self {
174 match interface.ip() {
175 IpAddr::V4(v4) => ScopedIp::V4(ScopedIpV4 {
176 addr: v4,
177 interface_ids: vec![InterfaceId::from(interface)],
178 }),
179 IpAddr::V6(v6) => ScopedIp::V6(ScopedIpV6 {
180 addr: v6,
181 scope_id: InterfaceId::from(interface),
182 }),
183 }
184 }
185}
186
187impl fmt::Display for ScopedIp {
188 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
189 match self {
190 ScopedIp::V4(v4) => write!(f, "{}", v4.addr),
191 ScopedIp::V6(v6) => {
192 if v6.scope_id.index != 0 && is_unicast_link_local(&v6.addr) {
193 #[cfg(windows)]
194 {
195 write!(f, "{}%{}", v6.addr, v6.scope_id.index)
196 }
197 #[cfg(not(windows))]
198 {
199 write!(f, "{}%{}", v6.addr, v6.scope_id.name)
200 }
201 } else {
202 write!(f, "{}", v6.addr)
203 }
204 }
205 }
206 }
207}
208
209#[derive(Debug, PartialEq, Eq, Clone, Copy, PartialOrd, Ord)]
213#[non_exhaustive]
214#[repr(u16)]
215pub enum RRType {
216 A = 1,
218
219 CNAME = 5,
221
222 PTR = 12,
224
225 HINFO = 13,
227
228 TXT = 16,
230
231 AAAA = 28,
233
234 SRV = 33,
236
237 NSEC = 47,
239
240 ANY = 255,
242}
243
244impl RRType {
245 pub const fn from_u16(value: u16) -> Option<Self> {
247 match value {
248 1 => Some(RRType::A),
249 5 => Some(RRType::CNAME),
250 12 => Some(RRType::PTR),
251 13 => Some(RRType::HINFO),
252 16 => Some(RRType::TXT),
253 28 => Some(RRType::AAAA),
254 33 => Some(RRType::SRV),
255 47 => Some(RRType::NSEC),
256 255 => Some(RRType::ANY),
257 _ => None,
258 }
259 }
260}
261
262impl fmt::Display for RRType {
263 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
264 match self {
265 RRType::A => write!(f, "TYPE_A"),
266 RRType::CNAME => write!(f, "TYPE_CNAME"),
267 RRType::PTR => write!(f, "TYPE_PTR"),
268 RRType::HINFO => write!(f, "TYPE_HINFO"),
269 RRType::TXT => write!(f, "TYPE_TXT"),
270 RRType::AAAA => write!(f, "TYPE_AAAA"),
271 RRType::SRV => write!(f, "TYPE_SRV"),
272 RRType::NSEC => write!(f, "TYPE_NSEC"),
273 RRType::ANY => write!(f, "TYPE_ANY"),
274 }
275 }
276}
277
278pub const CLASS_IN: u16 = 1;
280pub const CLASS_MASK: u16 = 0x7FFF;
281
282pub const CLASS_CACHE_FLUSH: u16 = 0x8000;
284
285pub(crate) const MAX_PKT_ABSOLUTE_IPV4: usize = 8972;
293
294pub(crate) const MAX_PKT_ABSOLUTE_IPV6: usize = 8952;
299
300pub(crate) const fn max_pkt_absolute(is_ipv4: bool) -> usize {
302 if is_ipv4 {
303 MAX_PKT_ABSOLUTE_IPV4
304 } else {
305 MAX_PKT_ABSOLUTE_IPV6
306 }
307}
308
309pub const MAX_PKT_DEFAULT: usize = 1452;
316
317const MSG_HEADER_LEN: usize = 12;
318
319const MAX_LABEL_BYTES: usize = 63;
323
324const MAX_NAME_BYTES: usize = 255;
328
329#[derive(Debug, PartialEq, Eq)]
334pub enum WriteError {
335 NameTooLong,
337
338 PacketFull,
340}
341
342type WriteResult = core::result::Result<(), WriteError>;
344
345pub const FLAGS_QR_MASK: u16 = 0x8000; pub const FLAGS_QR_QUERY: u16 = 0x0000;
357
358pub const FLAGS_QR_RESPONSE: u16 = 0x8000;
360
361pub const FLAGS_AA: u16 = 0x0400;
363
364pub const FLAGS_TC: u16 = 0x0200;
375
376pub type DnsRecordBox = Box<dyn DnsRecordExt>;
378
379impl Clone for DnsRecordBox {
380 fn clone(&self) -> Self {
381 self.clone_box()
382 }
383}
384
385const U16_SIZE: usize = 2;
386
387#[inline]
389pub const fn ip_address_rr_type(address: &IpAddr) -> RRType {
390 match address {
391 IpAddr::V4(_) => RRType::A,
392 IpAddr::V6(_) => RRType::AAAA,
393 }
394}
395
396#[derive(Eq, PartialEq, Debug, Clone)]
397pub struct DnsEntry {
398 pub(crate) name: String, pub(crate) ty: RRType,
400 class: u16,
401 cache_flush: bool,
402}
403
404impl DnsEntry {
405 const fn new(name: String, ty: RRType, class: u16) -> Self {
406 Self {
407 name,
408 ty,
409 class: class & CLASS_MASK,
410 cache_flush: (class & CLASS_CACHE_FLUSH) != 0,
411 }
412 }
413}
414
415pub trait DnsEntryExt: fmt::Debug {
417 fn entry_name(&self) -> &str;
418
419 fn entry_type(&self) -> RRType;
420}
421
422#[derive(Debug)]
424pub struct DnsQuestion {
425 pub(crate) entry: DnsEntry,
426}
427
428impl DnsEntryExt for DnsQuestion {
429 fn entry_name(&self) -> &str {
430 &self.entry.name
431 }
432
433 fn entry_type(&self) -> RRType {
434 self.entry.ty
435 }
436}
437
438#[derive(Debug, Clone)]
442pub struct DnsRecord {
443 pub(crate) entry: DnsEntry,
444 ttl: u32, created: u64, expires: u64, refresh: u64, new_name: Option<String>,
454}
455
456impl DnsRecord {
457 fn new(name: &str, ty: RRType, class: u16, ttl: u32) -> Self {
458 let created = current_time_millis();
459
460 let refresh = get_expiration_time(created, ttl, 80);
464
465 let expires = get_expiration_time(created, ttl, 100);
466
467 Self {
468 entry: DnsEntry::new(name.to_string(), ty, class),
469 ttl,
470 created,
471 expires,
472 refresh,
473 new_name: None,
474 }
475 }
476
477 pub const fn get_ttl(&self) -> u32 {
478 self.ttl
479 }
480
481 pub const fn get_expire_time(&self) -> u64 {
482 self.expires
483 }
484
485 pub const fn get_refresh_time(&self) -> u64 {
486 self.refresh
487 }
488
489 pub const fn is_expired(&self, now: u64) -> bool {
490 now >= self.expires
491 }
492
493 pub const fn expires_soon(&self, now: u64) -> bool {
497 now + 1000 >= self.expires
498 }
499
500 pub const fn refresh_due(&self, now: u64) -> bool {
501 now >= self.refresh
502 }
503
504 pub fn halflife_passed(&self, now: u64) -> bool {
506 let halflife = get_expiration_time(self.created, self.ttl, 50);
507 now > halflife
508 }
509
510 pub fn is_unique(&self) -> bool {
511 self.entry.cache_flush
512 }
513
514 pub fn refresh_no_more(&mut self) {
517 self.refresh = get_expiration_time(self.created, self.ttl, 100);
518 }
519
520 pub fn refresh_maybe(&mut self, now: u64) -> bool {
522 if self.is_expired(now) || !self.refresh_due(now) {
523 return false;
524 }
525
526 trace!(
527 "{} qtype {} is due to refresh",
528 &self.entry.name,
529 self.entry.ty
530 );
531
532 if self.refresh == get_expiration_time(self.created, self.ttl, 80) {
539 self.refresh = get_expiration_time(self.created, self.ttl, 85);
540 } else if self.refresh == get_expiration_time(self.created, self.ttl, 85) {
541 self.refresh = get_expiration_time(self.created, self.ttl, 90);
542 } else if self.refresh == get_expiration_time(self.created, self.ttl, 90) {
543 self.refresh = get_expiration_time(self.created, self.ttl, 95);
544 } else {
545 self.refresh_no_more();
546 }
547
548 true
549 }
550
551 fn get_remaining_ttl(&self, now: u64) -> u32 {
553 let remaining_millis = get_expiration_time(self.created, self.ttl, 100) - now;
554 cmp::max(0, remaining_millis / 1000) as u32
555 }
556
557 pub const fn get_created(&self) -> u64 {
559 self.created
560 }
561
562 fn set_expire(&mut self, expire_at: u64) {
564 self.expires = expire_at;
565 }
566
567 fn reset_ttl(&mut self, other: &Self) {
568 self.ttl = other.ttl;
569 self.created = other.created;
570 self.expires = get_expiration_time(self.created, self.ttl, 100);
571 self.refresh = if self.ttl > 1 {
572 get_expiration_time(self.created, self.ttl, 80)
573 } else {
574 self.expires
577 };
578 }
579
580 pub fn update_ttl(&mut self, now: u64) {
582 if now > self.created {
583 let elapsed = now - self.created;
584 self.ttl -= (elapsed / 1000) as u32;
585 }
586 }
587
588 pub fn set_new_name(&mut self, new_name: String) {
589 if new_name == self.entry.name {
590 self.new_name = None;
591 } else {
592 self.new_name = Some(new_name);
593 }
594 }
595
596 pub fn get_new_name(&self) -> Option<&str> {
597 self.new_name.as_deref()
598 }
599
600 pub(crate) fn get_name(&self) -> &str {
602 self.new_name.as_deref().unwrap_or(&self.entry.name)
603 }
604
605 pub fn get_original_name(&self) -> &str {
606 &self.entry.name
607 }
608}
609
610impl PartialEq for DnsRecord {
611 fn eq(&self, other: &Self) -> bool {
612 self.entry == other.entry
613 }
614}
615
616pub trait DnsRecordExt: fmt::Debug {
618 fn get_record(&self) -> &DnsRecord;
619 fn get_record_mut(&mut self) -> &mut DnsRecord;
620 fn write(&self, packet: &mut DnsOutPacket) -> WriteResult;
622 fn any(&self) -> &dyn Any;
623
624 fn matches(&self, other: &dyn DnsRecordExt) -> bool;
626
627 fn rrdata_match(&self, other: &dyn DnsRecordExt) -> bool;
629
630 fn compare_rdata(&self, other: &dyn DnsRecordExt) -> cmp::Ordering;
633
634 fn compare(&self, other: &dyn DnsRecordExt) -> cmp::Ordering {
636 match self.get_class().cmp(&other.get_class()) {
650 cmp::Ordering::Equal => match self.get_type().cmp(&other.get_type()) {
651 cmp::Ordering::Equal => self.compare_rdata(other),
652 not_equal => not_equal,
653 },
654 not_equal => not_equal,
655 }
656 }
657
658 fn rdata_print(&self) -> String;
660
661 fn get_class(&self) -> u16 {
663 self.get_record().entry.class
664 }
665
666 fn get_cache_flush(&self) -> bool {
667 self.get_record().entry.cache_flush
668 }
669
670 fn get_name(&self) -> &str {
672 self.get_record().get_name()
673 }
674
675 fn get_type(&self) -> RRType {
676 self.get_record().entry.ty
677 }
678
679 fn reset_ttl(&mut self, other: &dyn DnsRecordExt) {
682 self.get_record_mut().reset_ttl(other.get_record());
683 }
684
685 fn get_created(&self) -> u64 {
686 self.get_record().get_created()
687 }
688
689 fn get_expire(&self) -> u64 {
690 self.get_record().get_expire_time()
691 }
692
693 fn set_expire(&mut self, expire_at: u64) {
694 self.get_record_mut().set_expire(expire_at);
695 }
696
697 fn set_expire_sooner(&mut self, expire_at: u64) {
699 if expire_at < self.get_expire() {
700 self.get_record_mut().set_expire(expire_at);
701 }
702 }
703
704 fn expires_soon(&self, now: u64) -> bool {
706 self.get_record().expires_soon(now)
707 }
708
709 fn updated_refresh_time(&mut self, now: u64) -> Option<u64> {
712 if self.get_record_mut().refresh_maybe(now) {
713 Some(self.get_record().get_refresh_time())
714 } else {
715 None
716 }
717 }
718
719 fn suppressed_by_answer(&self, other: &dyn DnsRecordExt) -> bool {
722 self.matches(other) && (other.get_record().ttl > self.get_record().ttl / 2)
723 }
724
725 fn suppressed_by(&self, msg: &DnsIncoming) -> bool {
727 for answer in msg.answers.iter() {
728 if self.suppressed_by_answer(answer.as_ref()) {
729 return true;
730 }
731 }
732 false
733 }
734
735 fn clone_box(&self) -> DnsRecordBox;
736
737 fn boxed(self) -> DnsRecordBox;
738}
739
740#[derive(Debug, Clone)]
742pub(crate) struct DnsAddress {
743 pub(crate) record: DnsRecord,
744 address: IpAddr,
745 pub(crate) interface_id: InterfaceId,
746}
747
748impl DnsAddress {
749 pub fn new(
750 name: &str,
751 ty: RRType,
752 class: u16,
753 ttl: u32,
754 address: IpAddr,
755 interface_id: InterfaceId,
756 ) -> Self {
757 let record = DnsRecord::new(name, ty, class, ttl);
758 Self {
759 record,
760 address,
761 interface_id,
762 }
763 }
764
765 pub fn address(&self) -> ScopedIp {
766 match self.address {
767 IpAddr::V4(v4) => ScopedIp::V4(ScopedIpV4 {
768 addr: v4,
769 interface_ids: vec![self.interface_id.clone()],
770 }),
771 IpAddr::V6(v6) => ScopedIp::V6(ScopedIpV6 {
772 addr: v6,
773 scope_id: self.interface_id.clone(),
774 }),
775 }
776 }
777}
778
779impl DnsRecordExt for DnsAddress {
780 fn get_record(&self) -> &DnsRecord {
781 &self.record
782 }
783
784 fn get_record_mut(&mut self) -> &mut DnsRecord {
785 &mut self.record
786 }
787
788 fn write(&self, packet: &mut DnsOutPacket) -> WriteResult {
789 match self.address {
790 IpAddr::V4(addr) => packet.write_bytes(addr.octets().as_ref()),
791 IpAddr::V6(addr) => packet.write_bytes(addr.octets().as_ref()),
792 };
793 Ok(())
794 }
795
796 fn any(&self) -> &dyn Any {
797 self
798 }
799
800 fn matches(&self, other: &dyn DnsRecordExt) -> bool {
801 if let Some(other_a) = other.any().downcast_ref::<Self>() {
802 return self.address == other_a.address
803 && self.record.entry == other_a.record.entry
804 && self.interface_id == other_a.interface_id;
805 }
806 false
807 }
808
809 fn rrdata_match(&self, other: &dyn DnsRecordExt) -> bool {
810 if let Some(other_a) = other.any().downcast_ref::<Self>() {
811 return self.address == other_a.address;
812 }
813 false
814 }
815
816 fn compare_rdata(&self, other: &dyn DnsRecordExt) -> cmp::Ordering {
817 if let Some(other_a) = other.any().downcast_ref::<Self>() {
818 self.address.cmp(&other_a.address)
819 } else {
820 cmp::Ordering::Greater
821 }
822 }
823
824 fn rdata_print(&self) -> String {
825 format!("{}", self.address)
826 }
827
828 fn clone_box(&self) -> DnsRecordBox {
829 Box::new(self.clone())
830 }
831
832 fn boxed(self) -> DnsRecordBox {
833 Box::new(self)
834 }
835}
836
837#[derive(Debug, Clone)]
839pub struct DnsPointer {
840 record: DnsRecord,
841 alias: String, }
843
844impl DnsPointer {
845 pub fn new(name: &str, ty: RRType, class: u16, ttl: u32, alias: String) -> Self {
846 let record = DnsRecord::new(name, ty, class, ttl);
847 Self { record, alias }
848 }
849
850 pub fn alias(&self) -> &str {
851 &self.alias
852 }
853}
854
855impl DnsRecordExt for DnsPointer {
856 fn get_record(&self) -> &DnsRecord {
857 &self.record
858 }
859
860 fn get_record_mut(&mut self) -> &mut DnsRecord {
861 &mut self.record
862 }
863
864 fn write(&self, packet: &mut DnsOutPacket) -> WriteResult {
865 packet.write_name(&self.alias)
866 }
867
868 fn any(&self) -> &dyn Any {
869 self
870 }
871
872 fn matches(&self, other: &dyn DnsRecordExt) -> bool {
873 if let Some(other_ptr) = other.any().downcast_ref::<Self>() {
874 return self.alias == other_ptr.alias && self.record.entry == other_ptr.record.entry;
875 }
876 false
877 }
878
879 fn rrdata_match(&self, other: &dyn DnsRecordExt) -> bool {
880 if let Some(other_ptr) = other.any().downcast_ref::<Self>() {
881 return self.alias == other_ptr.alias;
882 }
883 false
884 }
885
886 fn compare_rdata(&self, other: &dyn DnsRecordExt) -> cmp::Ordering {
887 if let Some(other_ptr) = other.any().downcast_ref::<Self>() {
888 self.alias.cmp(&other_ptr.alias)
889 } else {
890 cmp::Ordering::Greater
891 }
892 }
893
894 fn rdata_print(&self) -> String {
895 self.alias.clone()
896 }
897
898 fn clone_box(&self) -> DnsRecordBox {
899 Box::new(self.clone())
900 }
901
902 fn boxed(self) -> DnsRecordBox {
903 Box::new(self)
904 }
905}
906
907#[derive(Debug, Clone)]
909pub struct DnsSrv {
910 pub(crate) record: DnsRecord,
911 pub(crate) priority: u16, pub(crate) weight: u16, host: String,
914 port: u16,
915}
916
917impl DnsSrv {
918 pub fn new(
919 name: &str,
920 class: u16,
921 ttl: u32,
922 priority: u16,
923 weight: u16,
924 port: u16,
925 host: String,
926 ) -> Self {
927 let record = DnsRecord::new(name, RRType::SRV, class, ttl);
928 Self {
929 record,
930 priority,
931 weight,
932 host,
933 port,
934 }
935 }
936
937 pub fn host(&self) -> &str {
938 &self.host
939 }
940
941 pub fn port(&self) -> u16 {
942 self.port
943 }
944
945 pub fn set_host(&mut self, host: String) {
946 self.host = host;
947 }
948}
949
950impl DnsRecordExt for DnsSrv {
951 fn get_record(&self) -> &DnsRecord {
952 &self.record
953 }
954
955 fn get_record_mut(&mut self) -> &mut DnsRecord {
956 &mut self.record
957 }
958
959 fn write(&self, packet: &mut DnsOutPacket) -> WriteResult {
960 packet.write_short(self.priority);
961 packet.write_short(self.weight);
962 packet.write_short(self.port);
963 packet.write_name(&self.host)
964 }
965
966 fn any(&self) -> &dyn Any {
967 self
968 }
969
970 fn matches(&self, other: &dyn DnsRecordExt) -> bool {
971 if let Some(other_svc) = other.any().downcast_ref::<Self>() {
972 return self.host == other_svc.host
973 && self.port == other_svc.port
974 && self.weight == other_svc.weight
975 && self.priority == other_svc.priority
976 && self.record.entry == other_svc.record.entry;
977 }
978 false
979 }
980
981 fn rrdata_match(&self, other: &dyn DnsRecordExt) -> bool {
982 if let Some(other_srv) = other.any().downcast_ref::<Self>() {
983 return self.host == other_srv.host
984 && self.port == other_srv.port
985 && self.weight == other_srv.weight
986 && self.priority == other_srv.priority;
987 }
988 false
989 }
990
991 fn compare_rdata(&self, other: &dyn DnsRecordExt) -> cmp::Ordering {
992 let Some(other_srv) = other.any().downcast_ref::<Self>() else {
993 return cmp::Ordering::Greater;
994 };
995
996 match self
998 .priority
999 .to_be_bytes()
1000 .cmp(&other_srv.priority.to_be_bytes())
1001 {
1002 cmp::Ordering::Equal => {
1003 match self
1005 .weight
1006 .to_be_bytes()
1007 .cmp(&other_srv.weight.to_be_bytes())
1008 {
1009 cmp::Ordering::Equal => {
1010 match self.port.to_be_bytes().cmp(&other_srv.port.to_be_bytes()) {
1012 cmp::Ordering::Equal => self.host.cmp(&other_srv.host),
1013 not_equal => not_equal,
1014 }
1015 }
1016 not_equal => not_equal,
1017 }
1018 }
1019 not_equal => not_equal,
1020 }
1021 }
1022
1023 fn rdata_print(&self) -> String {
1024 format!(
1025 "priority: {}, weight: {}, port: {}, host: {}",
1026 self.priority, self.weight, self.port, self.host
1027 )
1028 }
1029
1030 fn clone_box(&self) -> DnsRecordBox {
1031 Box::new(self.clone())
1032 }
1033
1034 fn boxed(self) -> DnsRecordBox {
1035 Box::new(self)
1036 }
1037}
1038
1039#[derive(Clone)]
1054pub struct DnsTxt {
1055 pub(crate) record: DnsRecord,
1056 text: Vec<u8>,
1057}
1058
1059impl DnsTxt {
1060 pub fn new(name: &str, class: u16, ttl: u32, text: Vec<u8>) -> Self {
1061 let record = DnsRecord::new(name, RRType::TXT, class, ttl);
1062 Self { record, text }
1063 }
1064
1065 pub fn text(&self) -> &[u8] {
1066 &self.text
1067 }
1068}
1069
1070impl DnsRecordExt for DnsTxt {
1071 fn get_record(&self) -> &DnsRecord {
1072 &self.record
1073 }
1074
1075 fn get_record_mut(&mut self) -> &mut DnsRecord {
1076 &mut self.record
1077 }
1078
1079 fn write(&self, packet: &mut DnsOutPacket) -> WriteResult {
1080 packet.write_bytes(&self.text);
1081 Ok(())
1082 }
1083
1084 fn any(&self) -> &dyn Any {
1085 self
1086 }
1087
1088 fn matches(&self, other: &dyn DnsRecordExt) -> bool {
1089 if let Some(other_txt) = other.any().downcast_ref::<Self>() {
1090 return self.text == other_txt.text && self.record.entry == other_txt.record.entry;
1091 }
1092 false
1093 }
1094
1095 fn rrdata_match(&self, other: &dyn DnsRecordExt) -> bool {
1096 if let Some(other_txt) = other.any().downcast_ref::<Self>() {
1097 return self.text == other_txt.text;
1098 }
1099 false
1100 }
1101
1102 fn compare_rdata(&self, other: &dyn DnsRecordExt) -> cmp::Ordering {
1103 if let Some(other_txt) = other.any().downcast_ref::<Self>() {
1104 self.text.cmp(&other_txt.text)
1105 } else {
1106 cmp::Ordering::Greater
1107 }
1108 }
1109
1110 fn rdata_print(&self) -> String {
1111 format!("{:?}", decode_txt(&self.text))
1112 }
1113
1114 fn clone_box(&self) -> DnsRecordBox {
1115 Box::new(self.clone())
1116 }
1117
1118 fn boxed(self) -> DnsRecordBox {
1119 Box::new(self)
1120 }
1121}
1122
1123impl fmt::Debug for DnsTxt {
1124 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1125 let properties = decode_txt(&self.text);
1126 write!(
1127 f,
1128 "DnsTxt {{ record: {:?}, text: {:?} }}",
1129 self.record, properties
1130 )
1131 }
1132}
1133
1134fn decode_txt(txt: &[u8]) -> Vec<TxtProperty> {
1136 let mut properties = Vec::new();
1137 let mut offset = 0;
1138 while offset < txt.len() {
1139 let length = txt[offset] as usize;
1140 if length == 0 {
1141 break; }
1143 offset += 1; let offset_end = offset + length;
1146 if offset_end > txt.len() {
1147 trace!("ERROR: DNS TXT: size given for property is out of range. (offset={}, length={}, offset_end={}, record length={})", offset, length, offset_end, txt.len());
1148 break; }
1150 let kv_bytes = &txt[offset..offset_end];
1151
1152 let (k, v) = kv_bytes.iter().position(|&x| x == b'=').map_or_else(
1154 || (kv_bytes.to_vec(), None),
1155 |idx| (kv_bytes[..idx].to_vec(), Some(kv_bytes[idx + 1..].to_vec())),
1156 );
1157
1158 match String::from_utf8(k) {
1160 Ok(k_string) => {
1161 properties.push(TxtProperty {
1162 key: k_string,
1163 val: v,
1164 });
1165 }
1166 Err(e) => trace!("ERROR: convert to String from key: {}", e),
1167 }
1168
1169 offset += length;
1170 }
1171
1172 properties
1173}
1174
1175#[derive(Clone, PartialEq, Eq)]
1177pub struct TxtProperty {
1178 key: String,
1180
1181 val: Option<Vec<u8>>,
1185}
1186
1187impl TxtProperty {
1188 pub fn val_str(&self) -> &str {
1190 self.val
1191 .as_ref()
1192 .map_or("", |v| std::str::from_utf8(&v[..]).unwrap_or_default())
1193 }
1194}
1195
1196impl<K, V> From<&(K, V)> for TxtProperty
1198where
1199 K: ToString,
1200 V: ToString,
1201{
1202 fn from(prop: &(K, V)) -> Self {
1203 Self {
1204 key: prop.0.to_string(),
1205 val: Some(prop.1.to_string().into_bytes()),
1206 }
1207 }
1208}
1209
1210impl<K, V> From<(K, V)> for TxtProperty
1211where
1212 K: ToString,
1213 V: AsRef<[u8]>,
1214{
1215 fn from(prop: (K, V)) -> Self {
1216 Self {
1217 key: prop.0.to_string(),
1218 val: Some(prop.1.as_ref().into()),
1219 }
1220 }
1221}
1222
1223impl From<&str> for TxtProperty {
1225 fn from(key: &str) -> Self {
1226 Self {
1227 key: key.to_string(),
1228 val: None,
1229 }
1230 }
1231}
1232
1233impl fmt::Display for TxtProperty {
1234 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1235 write!(f, "{}={}", self.key, self.val_str())
1236 }
1237}
1238
1239impl fmt::Debug for TxtProperty {
1243 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1244 let val_string = self.val.as_ref().map_or_else(
1245 || "None".to_string(),
1246 |v| {
1247 std::str::from_utf8(&v[..]).map_or_else(
1248 |_| format!("Some({})", u8_slice_to_hex(&v[..])),
1249 |s| format!("Some(\"{s}\")"),
1250 )
1251 },
1252 );
1253
1254 write!(
1255 f,
1256 "TxtProperty {{key: \"{}\", val: {}}}",
1257 &self.key, &val_string,
1258 )
1259 }
1260}
1261
1262const HEX_TABLE: [char; 16] = [
1263 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f',
1264];
1265
1266fn u8_slice_to_hex(slice: &[u8]) -> String {
1270 let mut hex = String::with_capacity(slice.len() * 2 + 2);
1271 hex.push_str("0x");
1272 for b in slice {
1273 hex.push(HEX_TABLE[(b >> 4) as usize]);
1274 hex.push(HEX_TABLE[(b & 0x0F) as usize]);
1275 }
1276 hex
1277}
1278
1279#[derive(Debug, Clone)]
1281struct DnsHostInfo {
1282 record: DnsRecord,
1283 cpu: String,
1284 os: String,
1285}
1286
1287impl DnsHostInfo {
1288 fn new(name: &str, ty: RRType, class: u16, ttl: u32, cpu: String, os: String) -> Self {
1289 let record = DnsRecord::new(name, ty, class, ttl);
1290 Self { record, cpu, os }
1291 }
1292}
1293
1294impl DnsRecordExt for DnsHostInfo {
1295 fn get_record(&self) -> &DnsRecord {
1296 &self.record
1297 }
1298
1299 fn get_record_mut(&mut self) -> &mut DnsRecord {
1300 &mut self.record
1301 }
1302
1303 fn write(&self, packet: &mut DnsOutPacket) -> WriteResult {
1304 debug!("Writing HInfo: cpu {} os {}", &self.cpu, &self.os);
1305 packet.write_bytes(self.cpu.as_bytes());
1306 packet.write_bytes(self.os.as_bytes());
1307 Ok(())
1308 }
1309
1310 fn any(&self) -> &dyn Any {
1311 self
1312 }
1313
1314 fn matches(&self, other: &dyn DnsRecordExt) -> bool {
1315 if let Some(other_hinfo) = other.any().downcast_ref::<Self>() {
1316 return self.cpu == other_hinfo.cpu
1317 && self.os == other_hinfo.os
1318 && self.record.entry == other_hinfo.record.entry;
1319 }
1320 false
1321 }
1322
1323 fn rrdata_match(&self, other: &dyn DnsRecordExt) -> bool {
1324 if let Some(other_hinfo) = other.any().downcast_ref::<Self>() {
1325 return self.cpu == other_hinfo.cpu && self.os == other_hinfo.os;
1326 }
1327 false
1328 }
1329
1330 fn compare_rdata(&self, other: &dyn DnsRecordExt) -> cmp::Ordering {
1331 if let Some(other_hinfo) = other.any().downcast_ref::<Self>() {
1332 match self.cpu.cmp(&other_hinfo.cpu) {
1333 cmp::Ordering::Equal => self.os.cmp(&other_hinfo.os),
1334 ordering => ordering,
1335 }
1336 } else {
1337 cmp::Ordering::Greater
1338 }
1339 }
1340
1341 fn rdata_print(&self) -> String {
1342 format!("cpu: {}, os: {}", self.cpu, self.os)
1343 }
1344
1345 fn clone_box(&self) -> DnsRecordBox {
1346 Box::new(self.clone())
1347 }
1348
1349 fn boxed(self) -> DnsRecordBox {
1350 Box::new(self)
1351 }
1352}
1353
1354#[derive(Debug, Clone)]
1360pub struct DnsNSec {
1361 record: DnsRecord,
1362 next_domain: String,
1363 type_bitmap: Vec<u8>,
1364}
1365
1366impl DnsNSec {
1367 pub fn new(
1368 name: &str,
1369 class: u16,
1370 ttl: u32,
1371 next_domain: String,
1372 type_bitmap: Vec<u8>,
1373 ) -> Self {
1374 let record = DnsRecord::new(name, RRType::NSEC, class, ttl);
1375 Self {
1376 record,
1377 next_domain,
1378 type_bitmap,
1379 }
1380 }
1381
1382 pub fn _types(&self) -> Vec<u16> {
1384 let mut bit_num = 0;
1393 let mut results = Vec::new();
1394
1395 for byte in self.type_bitmap.iter() {
1396 let mut bit_mask: u8 = 0x80; for _ in 0..8 {
1400 if (byte & bit_mask) != 0 {
1401 results.push(bit_num);
1402 }
1403 bit_num += 1;
1404 bit_mask >>= 1; }
1406 }
1407 results
1408 }
1409}
1410
1411impl DnsRecordExt for DnsNSec {
1412 fn get_record(&self) -> &DnsRecord {
1413 &self.record
1414 }
1415
1416 fn get_record_mut(&mut self) -> &mut DnsRecord {
1417 &mut self.record
1418 }
1419
1420 fn write(&self, packet: &mut DnsOutPacket) -> WriteResult {
1421 packet.write_bytes(self.next_domain.as_bytes());
1422 packet.write_bytes(&self.type_bitmap);
1423 Ok(())
1424 }
1425
1426 fn any(&self) -> &dyn Any {
1427 self
1428 }
1429
1430 fn matches(&self, other: &dyn DnsRecordExt) -> bool {
1431 if let Some(other_record) = other.any().downcast_ref::<Self>() {
1432 return self.next_domain == other_record.next_domain
1433 && self.type_bitmap == other_record.type_bitmap
1434 && self.record.entry == other_record.record.entry;
1435 }
1436 false
1437 }
1438
1439 fn rrdata_match(&self, other: &dyn DnsRecordExt) -> bool {
1440 if let Some(other_record) = other.any().downcast_ref::<Self>() {
1441 return self.next_domain == other_record.next_domain
1442 && self.type_bitmap == other_record.type_bitmap;
1443 }
1444 false
1445 }
1446
1447 fn compare_rdata(&self, other: &dyn DnsRecordExt) -> cmp::Ordering {
1448 if let Some(other_nsec) = other.any().downcast_ref::<Self>() {
1449 match self.next_domain.cmp(&other_nsec.next_domain) {
1450 cmp::Ordering::Equal => self.type_bitmap.cmp(&other_nsec.type_bitmap),
1451 ordering => ordering,
1452 }
1453 } else {
1454 cmp::Ordering::Greater
1455 }
1456 }
1457
1458 fn rdata_print(&self) -> String {
1459 format!(
1460 "next_domain: {}, type_bitmap len: {}",
1461 self.next_domain,
1462 self.type_bitmap.len()
1463 )
1464 }
1465
1466 fn clone_box(&self) -> DnsRecordBox {
1467 Box::new(self.clone())
1468 }
1469
1470 fn boxed(self) -> DnsRecordBox {
1471 Box::new(self)
1472 }
1473}
1474
1475#[derive(Clone, Copy, Debug)]
1477enum Section {
1478 Question,
1479 Answer,
1480 Authority,
1481 Additional,
1482}
1483
1484pub struct DnsOutPacket {
1486 data: Vec<u8>,
1488
1489 names: HashMap<String, u16>,
1491
1492 max_size: usize,
1494
1495 question_count: u16,
1497 answer_count: u16,
1498 auth_count: u16,
1499 addi_count: u16,
1500}
1501
1502impl DnsOutPacket {
1503 fn new(max_size: usize) -> Self {
1504 Self {
1505 data: vec![0; MSG_HEADER_LEN],
1506 names: HashMap::new(),
1507 max_size,
1508 question_count: 0,
1509 answer_count: 0,
1510 auth_count: 0,
1511 addi_count: 0,
1512 }
1513 }
1514
1515 pub fn size(&self) -> usize {
1516 self.data.len()
1517 }
1518
1519 pub fn as_bytes(&self) -> &[u8] {
1520 &self.data
1521 }
1522
1523 fn is_empty(&self) -> bool {
1525 self.question_count == 0
1526 && self.answer_count == 0
1527 && self.auth_count == 0
1528 && self.addi_count == 0
1529 }
1530
1531 fn bump(&mut self, section: Section) {
1533 match section {
1534 Section::Question => self.question_count += 1,
1535 Section::Answer => self.answer_count += 1,
1536 Section::Authority => self.auth_count += 1,
1537 Section::Additional => self.addi_count += 1,
1538 }
1539 }
1540
1541 fn write_question(&mut self, question: &DnsQuestion) -> WriteResult {
1542 let start_size = self.size();
1543
1544 self.write_name(&question.entry.name).map_err(|e| {
1545 self.rollback(start_size);
1546 e
1547 })?;
1548 self.write_short(question.entry.ty as u16);
1549 self.write_short(question.entry.class);
1550
1551 if self.size() > self.max_size {
1552 self.rollback(start_size);
1553 return Err(WriteError::PacketFull);
1554 }
1555
1556 Ok(())
1557 }
1558
1559 fn rollback(&mut self, start_size: usize) {
1562 self.data.truncate(start_size);
1563 self.names
1564 .retain(|_, offset| (*offset as usize) < start_size);
1565 }
1566
1567 fn write_record(&mut self, record_ext: &dyn DnsRecordExt, now: u64) -> WriteResult {
1571 let start_size = self.size();
1572
1573 let record = record_ext.get_record();
1574 self.write_name(record.get_name())?;
1575 self.write_short(record.entry.ty as u16);
1576 if record.entry.cache_flush {
1577 self.write_short(record.entry.class | CLASS_CACHE_FLUSH);
1579 } else {
1580 self.write_short(record.entry.class);
1581 }
1582
1583 if now == 0 {
1584 self.write_u32(record.ttl);
1585 } else {
1586 self.write_u32(record.get_remaining_ttl(now));
1587 }
1588
1589 self.write_short(0);
1591 let record_offset = self.size();
1592
1593 if let Err(e) = record_ext.write(self) {
1594 self.rollback(start_size);
1595 return Err(e);
1596 }
1597
1598 self.set_short_at(record_offset - 2, (self.size() - record_offset) as u16);
1599
1600 if self.size() > self.max_size {
1601 self.rollback(start_size);
1602 return Err(WriteError::PacketFull);
1603 }
1604
1605 Ok(())
1606 }
1607
1608 fn set_short_at(&mut self, index: usize, value: u16) {
1609 self.data[index..index + 2].copy_from_slice(&value.to_be_bytes());
1610 }
1611
1612 fn parse_escaped_name(name: &str) -> Vec<String> {
1619 let mut labels = Vec::new();
1620 let mut current_label = String::new();
1621 let mut chars = name.chars().peekable();
1622
1623 while let Some(ch) = chars.next() {
1624 match ch {
1625 '\\' => {
1626 if let Some(&next_ch) = chars.peek() {
1628 match next_ch {
1629 '.' | '\\' => {
1630 chars.next();
1632 current_label.push(next_ch);
1633 }
1634 _ => {
1635 current_label.push(ch);
1637 }
1638 }
1639 } else {
1640 current_label.push(ch);
1642 }
1643 }
1644 '.' => {
1645 if !current_label.is_empty() {
1647 labels.push(current_label.clone());
1648 current_label.clear();
1649 }
1650 }
1651 _ => {
1652 current_label.push(ch);
1653 }
1654 }
1655 }
1656
1657 if !current_label.is_empty() {
1659 labels.push(current_label);
1660 }
1661
1662 labels
1663 }
1664
1665 fn write_name(&mut self, name: &str) -> WriteResult {
1691 let name_to_parse = name.strip_suffix('.').unwrap_or(name);
1693
1694 let labels = Self::parse_escaped_name(name_to_parse);
1696
1697 if labels.is_empty() {
1698 self.write_byte(0);
1699 return Ok(());
1700 }
1701
1702 if labels.iter().any(|label| label.len() > MAX_LABEL_BYTES) {
1704 return Err(WriteError::NameTooLong);
1705 }
1706
1707 for (i, label) in labels.iter().enumerate() {
1709 let remaining: String = labels[i..].join(".");
1711
1712 const POINTER_MASK: u16 = 0xC000;
1714 if let Some(&offset) = self.names.get(&remaining) {
1715 let pointer = offset | POINTER_MASK;
1716 self.write_short(pointer);
1717 return Ok(());
1718 }
1719
1720 self.names.insert(remaining, self.size() as u16);
1722
1723 self.write_utf8(label)?;
1725 }
1726
1727 self.write_byte(0);
1729 Ok(())
1730 }
1731
1732 fn write_byte(&mut self, v: u8) {
1733 self.data.push(v);
1734 }
1735
1736 fn write_bytes(&mut self, s: &[u8]) {
1737 self.data.extend(s);
1738 }
1739
1740 fn write_utf8(&mut self, s: &str) -> WriteResult {
1743 if s.len() > MAX_LABEL_BYTES {
1744 return Err(WriteError::NameTooLong);
1745 }
1746 self.write_byte(s.len() as u8);
1747 self.write_bytes(s.as_bytes());
1748 Ok(())
1749 }
1750
1751 fn write_u32(&mut self, v: u32) {
1752 self.data.extend(&v.to_be_bytes());
1753 }
1754
1755 fn write_short(&mut self, v: u16) {
1756 self.data.extend(&v.to_be_bytes());
1757 }
1758
1759 fn set_truncated(&mut self) {
1762 let flags = u16::from_be_bytes([self.data[2], self.data[3]]);
1763 self.set_short_at(2, flags | FLAGS_TC);
1764 }
1765
1766 fn write_header(&mut self, id: u16, flags: u16) {
1789 self.set_short_at(0, id);
1790 self.set_short_at(2, flags);
1791 self.set_short_at(4, self.question_count);
1792 self.set_short_at(6, self.answer_count);
1793 self.set_short_at(8, self.auth_count);
1794 self.set_short_at(10, self.addi_count);
1795 }
1796}
1797
1798struct PacketBuilder<'a> {
1801 out: &'a DnsOutgoing,
1802
1803 max_size: usize,
1805
1806 is_ipv4: bool,
1809
1810 finished: Vec<DnsOutPacket>,
1811 current: DnsOutPacket,
1812}
1813
1814impl<'a> PacketBuilder<'a> {
1815 fn new(out: &'a DnsOutgoing, max_size: usize, is_ipv4: bool) -> Self {
1816 Self {
1817 out,
1818 max_size,
1819 is_ipv4,
1820 finished: Vec::new(),
1821 current: DnsOutPacket::new(max_size),
1822 }
1823 }
1824
1825 fn add<F>(&mut self, section: Section, write: F)
1832 where
1833 F: Fn(&mut DnsOutPacket) -> WriteResult,
1834 {
1835 match write(&mut self.current) {
1836 Ok(()) => {
1837 self.current.bump(section);
1838 return;
1839 }
1840 Err(WriteError::NameTooLong) => return,
1842 Err(WriteError::PacketFull) => {}
1843 }
1844
1845 if !self.current.is_empty() {
1847 self.flush();
1848
1849 match write(&mut self.current) {
1850 Ok(()) => {
1851 self.current.bump(section);
1852 return;
1853 }
1854 Err(WriteError::NameTooLong) => return,
1855 Err(WriteError::PacketFull) => {}
1856 }
1857 }
1858
1859 if matches!(section, Section::Question) {
1861 return;
1862 }
1863
1864 self.current.max_size = max_pkt_absolute(self.is_ipv4);
1870
1871 if write(&mut self.current).is_ok() {
1872 self.current.bump(section);
1873 self.flush();
1874 } else {
1875 self.current.max_size = self.max_size;
1877 debug!(
1878 "Record too big for absolute max size, skipping: {:?}",
1879 section
1880 );
1881 }
1882 }
1883
1884 fn flush(&mut self) {
1886 self.current
1887 .write_header(self.out.wire_id(), self.out.flags);
1888
1889 let next = DnsOutPacket::new(self.max_size);
1890 self.finished
1891 .push(std::mem::replace(&mut self.current, next));
1892 }
1893
1894 fn finish(mut self) -> Vec<DnsOutPacket> {
1895 if !self.current.is_empty() || self.finished.is_empty() {
1898 self.flush();
1899 }
1900
1901 let mut packets = self.finished;
1902
1903 if self.out.is_query() {
1911 if let Some((_last, rest)) = packets.split_last_mut() {
1912 for packet in rest {
1913 packet.set_truncated();
1914 }
1915 }
1916 }
1917
1918 packets
1919 }
1920}
1921
1922#[derive(Debug)]
1924pub struct DnsOutgoing {
1925 flags: u16,
1926 id: u16,
1927 multicast: bool,
1928 questions: Vec<DnsQuestion>,
1929 answers: Vec<(DnsRecordBox, u64)>,
1930 authorities: Vec<DnsRecordBox>,
1931 additionals: Vec<DnsRecordBox>,
1932 known_answer_count: i64, }
1934
1935impl DnsOutgoing {
1936 pub fn new(flags: u16) -> Self {
1937 Self {
1938 flags,
1939 id: 0,
1940 multicast: true,
1941 questions: Vec::new(),
1942 answers: Vec::new(),
1943 authorities: Vec::new(),
1944 additionals: Vec::new(),
1945 known_answer_count: 0,
1946 }
1947 }
1948
1949 pub fn questions(&self) -> &[DnsQuestion] {
1950 &self.questions
1951 }
1952
1953 pub(crate) fn _answers(&self) -> &[(DnsRecordBox, u64)] {
1955 &self.answers
1956 }
1957
1958 pub fn answers_count(&self) -> usize {
1959 self.answers.len()
1960 }
1961
1962 pub fn authorities(&self) -> &[DnsRecordBox] {
1963 &self.authorities
1964 }
1965
1966 pub fn additionals(&self) -> &[DnsRecordBox] {
1967 &self.additionals
1968 }
1969
1970 pub fn known_answer_count(&self) -> i64 {
1971 self.known_answer_count
1972 }
1973
1974 pub fn set_id(&mut self, id: u16) {
1975 self.id = id;
1976 }
1977
1978 const fn wire_id(&self) -> u16 {
1980 if self.multicast {
1981 0
1982 } else {
1983 self.id
1984 }
1985 }
1986
1987 pub const fn is_query(&self) -> bool {
1988 (self.flags & FLAGS_QR_MASK) == FLAGS_QR_QUERY
1989 }
1990
1991 pub fn add_additional_answer(&mut self, answer: impl DnsRecordExt + 'static) {
2025 trace!("add_additional_answer: {:?}", &answer);
2026 self.additionals.push(answer.boxed());
2027 }
2028
2029 pub fn add_answer_box(&mut self, answer_box: DnsRecordBox) {
2031 self.answers.push((answer_box, 0));
2032 }
2033
2034 pub fn add_authority(&mut self, record: DnsRecordBox) {
2035 self.authorities.push(record);
2036 }
2037
2038 pub(crate) fn retain_answers<F>(&mut self, mut keep: F)
2040 where
2041 F: FnMut(&DnsRecordBox) -> bool,
2042 {
2043 self.answers.retain(|(record, _)| keep(record));
2044 }
2045
2046 pub(crate) fn retain_additionals<F>(&mut self, mut keep: F)
2048 where
2049 F: FnMut(&DnsRecordBox) -> bool,
2050 {
2051 self.additionals.retain(|record| keep(record));
2052 }
2053
2054 pub fn add_answer(
2057 &mut self,
2058 msg: &DnsIncoming,
2059 answer: impl DnsRecordExt + Send + 'static,
2060 ) -> bool {
2061 trace!("Check for add_answer");
2062 if answer.suppressed_by(msg) {
2063 trace!("my answer is suppressed by incoming msg");
2064 self.known_answer_count += 1;
2065 return false;
2066 }
2067
2068 self.add_answer_at_time(answer, 0)
2069 }
2070
2071 pub fn add_answer_at_time(
2075 &mut self,
2076 answer: impl DnsRecordExt + Send + 'static,
2077 now: u64,
2078 ) -> bool {
2079 if now == 0 || !answer.get_record().is_expired(now) {
2080 trace!("add_answer push: {:?}", &answer);
2081 self.answers.push((answer.boxed(), now));
2082 return true;
2083 }
2084 false
2085 }
2086
2087 pub(crate) fn add_answer_with_additionals(
2096 &mut self,
2097 msg: &DnsIncoming,
2098 service: &ServiceInfo,
2099 intf: &MyIntf,
2100 dns_registry: &DnsRegistry,
2101 is_ipv4: bool,
2102 ) {
2103 let intf_addrs = if is_ipv4 {
2104 service.get_addrs_on_my_intf_v4(intf)
2105 } else {
2106 service.get_addrs_on_my_intf_v6(intf)
2107 };
2108 if intf_addrs.is_empty() {
2109 trace!("No addrs on LAN of intf {:?}", intf);
2110 return;
2111 }
2112
2113 let service_fullname = dns_registry.resolve_name(service.get_fullname());
2115 let hostname = dns_registry.resolve_name(service.get_hostname());
2116
2117 let ptr_added = self.add_answer(
2118 msg,
2119 DnsPointer::new(
2120 service.get_type(),
2121 RRType::PTR,
2122 CLASS_IN,
2123 service.get_other_ttl(),
2124 service_fullname.to_string(),
2125 ),
2126 );
2127
2128 if !ptr_added {
2129 trace!("answer was not added for msg {:?}", msg);
2130 return;
2131 }
2132
2133 if let Some(sub) = service.get_subtype() {
2134 trace!("Adding subdomain {}", sub);
2135 self.add_additional_answer(DnsPointer::new(
2136 sub,
2137 RRType::PTR,
2138 CLASS_IN,
2139 service.get_other_ttl(),
2140 service_fullname.to_string(),
2141 ));
2142 }
2143
2144 self.add_additional_answer(DnsSrv::new(
2147 service_fullname,
2148 CLASS_IN | CLASS_CACHE_FLUSH,
2149 service.get_host_ttl(),
2150 service.get_priority(),
2151 service.get_weight(),
2152 service.get_port(),
2153 hostname.to_string(),
2154 ));
2155
2156 self.add_additional_answer(DnsTxt::new(
2157 service_fullname,
2158 CLASS_IN | CLASS_CACHE_FLUSH,
2159 service.get_other_ttl(),
2160 service.generate_txt(),
2161 ));
2162
2163 for address in intf_addrs {
2164 self.add_additional_answer(DnsAddress::new(
2165 hostname,
2166 ip_address_rr_type(&address),
2167 CLASS_IN | CLASS_CACHE_FLUSH,
2168 service.get_host_ttl(),
2169 address,
2170 intf.into(),
2171 ));
2172 }
2173 }
2174
2175 pub fn add_question(&mut self, name: &str, qtype: RRType) {
2176 let q = DnsQuestion {
2177 entry: DnsEntry::new(name.to_string(), qtype, CLASS_IN),
2178 };
2179 self.questions.push(q);
2180 }
2181
2182 pub fn clear_cache_flush_bits(&mut self) {
2187 for (rec, _) in &mut self.answers {
2188 rec.get_record_mut().entry.cache_flush = false;
2189 }
2190 for rec in &mut self.additionals {
2191 rec.get_record_mut().entry.cache_flush = false;
2192 }
2193 for rec in &mut self.authorities {
2194 rec.get_record_mut().entry.cache_flush = false;
2195 }
2196 }
2197
2198 pub fn to_data_on_wire(&self, max_size: usize, is_ipv4: bool) -> Vec<Vec<u8>> {
2203 let packet_list = self.to_packets(max_size, is_ipv4);
2204 packet_list.into_iter().map(|p| p.data).collect()
2205 }
2206
2207 pub fn to_packets(&self, max_size: usize, is_ipv4: bool) -> Vec<DnsOutPacket> {
2224 debug_assert!(
2225 max_size <= MAX_PKT_ABSOLUTE_IPV6,
2226 "max_size {} exceeds the RFC 6762 section 17 ceiling",
2227 max_size
2228 );
2229 let mut builder = PacketBuilder::new(self, max_size, is_ipv4);
2230
2231 for question in self.questions.iter() {
2232 builder.add(Section::Question, |packet| packet.write_question(question));
2233 }
2234
2235 for (answer, time) in self.answers.iter() {
2236 builder.add(Section::Answer, |packet| {
2237 packet.write_record(answer.as_ref(), *time)
2238 });
2239 }
2240
2241 for auth in self.authorities.iter() {
2242 builder.add(Section::Authority, |packet| {
2243 packet.write_record(auth.as_ref(), 0)
2244 });
2245 }
2246
2247 for addi in self.additionals.iter() {
2248 builder.add(Section::Additional, |packet| {
2249 packet.write_record(addi.as_ref(), 0)
2250 });
2251 }
2252
2253 builder.finish()
2254 }
2255}
2256
2257#[derive(Debug)]
2259pub struct DnsIncoming {
2260 offset: usize,
2261 data: Vec<u8>,
2262 questions: Vec<DnsQuestion>,
2263 answers: Vec<DnsRecordBox>,
2264 authorities: Vec<DnsRecordBox>,
2265 additional: Vec<DnsRecordBox>,
2266 id: u16,
2267 flags: u16,
2268 num_questions: u16,
2269 num_answers: u16,
2270 num_authorities: u16,
2271 num_additionals: u16,
2272 interface_id: InterfaceId,
2273}
2274
2275impl DnsIncoming {
2276 pub fn new(data: Vec<u8>, interface_id: InterfaceId) -> Result<Self> {
2277 let mut incoming = Self {
2278 offset: 0,
2279 data,
2280 questions: Vec::new(),
2281 answers: Vec::new(),
2282 authorities: Vec::new(),
2283 additional: Vec::new(),
2284 id: 0,
2285 flags: 0,
2286 num_questions: 0,
2287 num_answers: 0,
2288 num_authorities: 0,
2289 num_additionals: 0,
2290 interface_id,
2291 };
2292
2293 if let Err(e) = incoming.read_sections() {
2313 return Err(Error::Msg(format!(
2316 "{e}; raw packet ({} bytes): {:02x?}",
2317 incoming.data.len(),
2318 incoming.data,
2319 )));
2320 }
2321
2322 Ok(incoming)
2323 }
2324
2325 fn read_sections(&mut self) -> Result<()> {
2328 self.read_header()?;
2329 self.read_questions()?;
2330 self.read_answers()?;
2331 self.read_authorities()?;
2332 self.read_additional()?;
2333 Ok(())
2334 }
2335
2336 pub fn id(&self) -> u16 {
2337 self.id
2338 }
2339
2340 pub fn questions(&self) -> &[DnsQuestion] {
2341 &self.questions
2342 }
2343
2344 pub fn answers(&self) -> &[DnsRecordBox] {
2345 &self.answers
2346 }
2347
2348 pub fn authorities(&self) -> &[DnsRecordBox] {
2349 &self.authorities
2350 }
2351
2352 pub fn additionals(&self) -> &[DnsRecordBox] {
2353 &self.additional
2354 }
2355
2356 pub fn answers_mut(&mut self) -> &mut Vec<DnsRecordBox> {
2357 &mut self.answers
2358 }
2359
2360 pub fn authorities_mut(&mut self) -> &mut Vec<DnsRecordBox> {
2361 &mut self.authorities
2362 }
2363
2364 pub fn additionals_mut(&mut self) -> &mut Vec<DnsRecordBox> {
2365 &mut self.additional
2366 }
2367
2368 pub fn all_records(self) -> impl Iterator<Item = DnsRecordBox> {
2369 self.answers
2370 .into_iter()
2371 .chain(self.authorities)
2372 .chain(self.additional)
2373 }
2374
2375 pub fn num_additionals(&self) -> u16 {
2376 self.num_additionals
2377 }
2378
2379 pub fn num_authorities(&self) -> u16 {
2380 self.num_authorities
2381 }
2382
2383 pub fn num_questions(&self) -> u16 {
2384 self.num_questions
2385 }
2386
2387 pub const fn is_query(&self) -> bool {
2388 (self.flags & FLAGS_QR_MASK) == FLAGS_QR_QUERY
2389 }
2390
2391 pub const fn is_response(&self) -> bool {
2392 (self.flags & FLAGS_QR_MASK) == FLAGS_QR_RESPONSE
2393 }
2394
2395 fn read_header(&mut self) -> Result<()> {
2396 if self.data.len() < MSG_HEADER_LEN {
2397 return Err(e_fmt!(
2398 "DNS incoming: header is too short: {} bytes",
2399 self.data.len()
2400 ));
2401 }
2402
2403 let data = &self.data[0..];
2404 self.id = u16_from_be_slice(&data[..2]);
2405 self.flags = u16_from_be_slice(&data[2..4]);
2406 self.num_questions = u16_from_be_slice(&data[4..6]);
2407 self.num_answers = u16_from_be_slice(&data[6..8]);
2408 self.num_authorities = u16_from_be_slice(&data[8..10]);
2409 self.num_additionals = u16_from_be_slice(&data[10..12]);
2410
2411 self.offset = MSG_HEADER_LEN;
2412
2413 trace!(
2414 "read_header: id {}, {} questions {} answers {} authorities {} additionals",
2415 self.id,
2416 self.num_questions,
2417 self.num_answers,
2418 self.num_authorities,
2419 self.num_additionals
2420 );
2421 Ok(())
2422 }
2423
2424 fn read_questions(&mut self) -> Result<()> {
2425 trace!("read_questions: {}", &self.num_questions);
2426 for i in 0..self.num_questions {
2427 let name = self.read_name()?;
2428
2429 let data = &self.data[self.offset..];
2430 if data.len() < 4 {
2431 return Err(Error::Msg(format!(
2432 "DNS incoming: question idx {} too short: {}",
2433 i,
2434 data.len()
2435 )));
2436 }
2437 let ty = u16_from_be_slice(&data[..2]);
2438 let class = u16_from_be_slice(&data[2..4]);
2439 self.offset += 4;
2440
2441 let Some(rr_type) = RRType::from_u16(ty) else {
2442 return Err(Error::Msg(format!(
2443 "DNS incoming: question idx {i} qtype unknown: {ty}",
2444 )));
2445 };
2446
2447 self.questions.push(DnsQuestion {
2448 entry: DnsEntry::new(name, rr_type, class),
2449 });
2450 }
2451 Ok(())
2452 }
2453
2454 fn read_answers(&mut self) -> Result<()> {
2455 self.answers = self.read_rr_records(self.num_answers)?;
2456 Ok(())
2457 }
2458
2459 fn read_authorities(&mut self) -> Result<()> {
2460 self.authorities = self.read_rr_records(self.num_authorities)?;
2461 Ok(())
2462 }
2463
2464 fn read_additional(&mut self) -> Result<()> {
2465 self.additional = self.read_rr_records(self.num_additionals)?;
2466 Ok(())
2467 }
2468
2469 fn read_rr_records(&mut self, count: u16) -> Result<Vec<DnsRecordBox>> {
2471 trace!("read_rr_records: {}", count);
2472 let mut rr_records = Vec::new();
2473
2474 const RR_HEADER_REMAIN: usize = 10;
2500
2501 for _ in 0..count {
2502 let name = self.read_name()?;
2503 let slice = &self.data[self.offset..];
2504
2505 if slice.len() < RR_HEADER_REMAIN {
2506 return Err(Error::Msg(format!(
2507 "read_others: RR '{}' is too short after name: {} bytes",
2508 &name,
2509 slice.len()
2510 )));
2511 }
2512
2513 let ty = u16_from_be_slice(&slice[..2]);
2514 let class = u16_from_be_slice(&slice[2..4]);
2515 let mut ttl = u32_from_be_slice(&slice[4..8]);
2516 if ttl == 0 && self.is_response() {
2517 ttl = 1;
2524 }
2525 let rdata_len = u16_from_be_slice(&slice[8..10]) as usize;
2526 self.offset += RR_HEADER_REMAIN;
2527 let next_offset = self.offset + rdata_len;
2528
2529 if next_offset > self.data.len() {
2531 return Err(Error::Msg(format!(
2532 "RR {name} RDATA length {rdata_len} is invalid: remain data len: {}",
2533 self.data.len() - self.offset
2534 )));
2535 }
2536
2537 match self.read_rdata(ty, class, ttl, rdata_len, &name) {
2541 Ok(Some(record)) => {
2542 if self.offset == next_offset {
2543 trace!("read_rr_records: {:?}", &record);
2544 rr_records.push(record);
2545 } else {
2546 debug!(
2547 "skipping record '{}' (type {}): RDATA ended at {}, expected {}",
2548 &name, ty, self.offset, next_offset
2549 );
2550 }
2551 }
2552 Ok(None) => {
2553 trace!("Unsupported DNS record type: {} name: {}", ty, &name);
2554 }
2555 Err(e) => {
2556 debug!(
2557 "skipping record '{}' (type {}) with invalid RDATA: {}",
2558 &name, ty, e,
2559 );
2560 }
2561 }
2562
2563 self.offset = next_offset;
2567 }
2568
2569 Ok(rr_records)
2570 }
2571
2572 fn read_rdata(
2579 &mut self,
2580 ty: u16,
2581 class: u16,
2582 ttl: u32,
2583 rdata_len: usize,
2584 name: &str,
2585 ) -> Result<Option<DnsRecordBox>> {
2586 let rec: Option<DnsRecordBox> = match RRType::from_u16(ty) {
2587 None => None,
2588
2589 Some(rr_type) => match rr_type {
2590 RRType::CNAME | RRType::PTR => {
2591 Some(DnsPointer::new(name, rr_type, class, ttl, self.read_name()?).boxed())
2592 }
2593 RRType::TXT => {
2594 Some(DnsTxt::new(name, class, ttl, self.read_vec(rdata_len)?).boxed())
2595 }
2596 RRType::SRV => Some(
2597 DnsSrv::new(
2598 name,
2599 class,
2600 ttl,
2601 self.read_u16()?,
2602 self.read_u16()?,
2603 self.read_u16()?,
2604 self.read_name()?,
2605 )
2606 .boxed(),
2607 ),
2608 RRType::HINFO => Some(
2609 DnsHostInfo::new(
2610 name,
2611 rr_type,
2612 class,
2613 ttl,
2614 self.read_char_string()?,
2615 self.read_char_string()?,
2616 )
2617 .boxed(),
2618 ),
2619 RRType::A => Some(
2620 DnsAddress::new(
2621 name,
2622 rr_type,
2623 class,
2624 ttl,
2625 self.read_ipv4()?.into(),
2626 self.interface_id.clone(),
2627 )
2628 .boxed(),
2629 ),
2630 RRType::AAAA => Some(
2631 DnsAddress::new(
2632 name,
2633 rr_type,
2634 class,
2635 ttl,
2636 self.read_ipv6()?.into(),
2637 self.interface_id.clone(),
2638 )
2639 .boxed(),
2640 ),
2641 RRType::NSEC => Some(
2642 DnsNSec::new(
2643 name,
2644 class,
2645 ttl,
2646 self.read_name()?,
2647 self.read_type_bitmap()?,
2648 )
2649 .boxed(),
2650 ),
2651 _ => None,
2652 },
2653 };
2654
2655 Ok(rec)
2656 }
2657
2658 fn read_char_string(&mut self) -> Result<String> {
2659 let length = self.data[self.offset];
2660 self.offset += 1;
2661 self.read_string(length as usize)
2662 }
2663
2664 fn read_u16(&mut self) -> Result<u16> {
2665 let slice = &self.data[self.offset..];
2666 if slice.len() < U16_SIZE {
2667 return Err(Error::Msg(format!(
2668 "read_u16: slice len is only {}",
2669 slice.len()
2670 )));
2671 }
2672 let num = u16_from_be_slice(&slice[..U16_SIZE]);
2673 self.offset += U16_SIZE;
2674 Ok(num)
2675 }
2676
2677 fn read_type_bitmap(&mut self) -> Result<Vec<u8>> {
2679 if self.data.len() < self.offset + 2 {
2688 return Err(Error::Msg(format!(
2689 "DnsIncoming is too short: {} at NSEC Type Bit Map offset {}",
2690 self.data.len(),
2691 self.offset
2692 )));
2693 }
2694
2695 let block_num = self.data[self.offset];
2696 self.offset += 1;
2697 if block_num != 0 {
2698 return Err(Error::Msg(format!(
2699 "NSEC block number is not 0: {block_num}"
2700 )));
2701 }
2702
2703 let block_len = self.data[self.offset] as usize;
2704 if !(1..=32).contains(&block_len) {
2705 return Err(Error::Msg(format!(
2706 "NSEC block length must be in the range 1-32: {block_len}"
2707 )));
2708 }
2709 self.offset += 1;
2710
2711 let end = self.offset + block_len;
2712 if end > self.data.len() {
2713 return Err(Error::Msg(format!(
2714 "NSEC block overflow: {} over RData len {}",
2715 end,
2716 self.data.len()
2717 )));
2718 }
2719 let bitmap = self.data[self.offset..end].to_vec();
2720 self.offset += block_len;
2721
2722 Ok(bitmap)
2723 }
2724
2725 fn read_vec(&mut self, length: usize) -> Result<Vec<u8>> {
2726 if self.data.len() < self.offset + length {
2727 return Err(e_fmt!(
2728 "DNS Incoming: not enough data to read a chunk of data"
2729 ));
2730 }
2731
2732 let v = self.data[self.offset..self.offset + length].to_vec();
2733 self.offset += length;
2734 Ok(v)
2735 }
2736
2737 fn read_ipv4(&mut self) -> Result<Ipv4Addr> {
2738 if self.data.len() < self.offset + 4 {
2739 return Err(e_fmt!("DNS Incoming: not enough data to read an IPV4"));
2740 }
2741
2742 let bytes: [u8; 4] = self.data[self.offset..self.offset + 4]
2743 .try_into()
2744 .map_err(|_| e_fmt!("DNS incoming: Not enough bytes for reading an IPV4"))?;
2745 self.offset += bytes.len();
2746 Ok(Ipv4Addr::from(bytes))
2747 }
2748
2749 fn read_ipv6(&mut self) -> Result<Ipv6Addr> {
2750 if self.data.len() < self.offset + 16 {
2751 return Err(e_fmt!("DNS Incoming: not enough data to read an IPV6"));
2752 }
2753
2754 let bytes: [u8; 16] = self.data[self.offset..self.offset + 16]
2755 .try_into()
2756 .map_err(|_| e_fmt!("DNS incoming: Not enough bytes for reading an IPV6"))?;
2757 self.offset += bytes.len();
2758 Ok(Ipv6Addr::from(bytes))
2759 }
2760
2761 fn read_string(&mut self, length: usize) -> Result<String> {
2762 if self.data.len() < self.offset + length {
2763 return Err(e_fmt!("DNS Incoming: not enough data to read a string"));
2764 }
2765
2766 let s = str::from_utf8(&self.data[self.offset..self.offset + length])
2767 .map_err(|e| Error::Msg(e.to_string()))?;
2768 self.offset += length;
2769 Ok(s.to_string())
2770 }
2771
2772 fn read_name(&mut self) -> Result<String> {
2777 let mut name = String::new();
2778 self.offset = self.read_labels(self.offset, &mut name)?;
2779 Ok(name)
2780 }
2781
2782 fn read_labels(&self, mut offset: usize, name: &mut String) -> Result<usize> {
2811 let data = &self.data[..];
2812
2813 loop {
2824 if offset >= data.len() {
2825 return Err(Error::Msg(format!(
2826 "read_labels: offset: {} data len {}. DnsIncoming: {:?}",
2827 offset,
2828 data.len(),
2829 self
2830 )));
2831 }
2832 let length = data[offset];
2833
2834 if length == 0 {
2837 return Ok(offset + 1); }
2839
2840 match length & 0xC0 {
2842 0x00 => {
2843 offset += 1;
2845 let ending = offset + length as usize;
2846
2847 if ending > data.len() {
2849 return Err(Error::Msg(format!(
2850 "read_labels: ending {} exceeds data length {}",
2851 ending,
2852 data.len()
2853 )));
2854 }
2855
2856 let label = str::from_utf8(&data[offset..ending])
2857 .map_err(|e| Error::Msg(format!("read_labels: from_utf8: {e}")))?;
2858
2859 if name.len() + label.len() + 1 > MAX_NAME_BYTES {
2868 return Err(Error::Msg(format!(
2869 "read_labels: name exceeds {MAX_NAME_BYTES} bytes: {name}"
2870 )));
2871 }
2872
2873 *name += label;
2874 *name += ".";
2875 offset = ending;
2876 }
2877 0xC0 => {
2878 self.follow_pointer(offset, name)?;
2880 return Ok(offset + U16_SIZE);
2881 }
2882 _ => {
2883 return Err(Error::Msg(format!(
2884 "Bad name with invalid length: 0x{:x} offset {}, data (so far): {:x?}",
2885 length,
2886 offset,
2887 &data[..offset]
2888 )));
2889 }
2890 };
2891 }
2892 }
2893
2894 fn follow_pointer(&self, at: usize, name: &mut String) -> Result<()> {
2900 let data = &self.data[..];
2901 let mut pointer_at = at;
2902
2903 let target = loop {
2906 let slice = &data[pointer_at..];
2907 if slice.len() < U16_SIZE {
2908 return Err(Error::Msg(format!(
2909 "follow_pointer: u16 slice len is only {}",
2910 slice.len()
2911 )));
2912 }
2913 let target = (u16_from_be_slice(slice) ^ 0xC000) as usize;
2914
2915 if target >= pointer_at {
2918 return Err(Error::Msg(format!(
2919 "Invalid name compression: pointer {target} at offset {pointer_at} must point backwards"
2920 )));
2921 }
2922
2923 if data[target] & 0xC0 != 0xC0 {
2924 break target;
2925 }
2926
2927 pointer_at = target;
2929 };
2930
2931 self.read_labels(target, name)?;
2932 Ok(())
2933 }
2934}
2935
2936const fn u16_from_be_slice(bytes: &[u8]) -> u16 {
2937 let u8_array: [u8; 2] = [bytes[0], bytes[1]];
2938 u16::from_be_bytes(u8_array)
2939}
2940
2941const fn u32_from_be_slice(s: &[u8]) -> u32 {
2942 let u8_array: [u8; 4] = [s[0], s[1], s[2], s[3]];
2943 u32::from_be_bytes(u8_array)
2944}
2945
2946const fn get_expiration_time(created: u64, ttl: u32, percent: u32) -> u64 {
2949 created + (ttl as u64 * percent as u64 * 10)
2952}
2953
2954#[cfg(test)]
2955mod tests {
2956 use super::{
2957 u16_from_be_slice, DnsAddress, DnsHostInfo, DnsIncoming, DnsOutPacket, DnsOutgoing,
2958 DnsPointer, DnsTxt, RRType, CLASS_CACHE_FLUSH, CLASS_IN, FLAGS_QR_QUERY, FLAGS_QR_RESPONSE,
2959 FLAGS_TC, MAX_PKT_ABSOLUTE_IPV6, MAX_PKT_DEFAULT, MSG_HEADER_LEN,
2960 };
2961 use crate::InterfaceId;
2962 use std::collections::HashMap;
2963 use std::net::{IpAddr, Ipv4Addr};
2964
2965 const IPV6: bool = false;
2968
2969 #[test]
2970 fn test_dns_outgoing_serialization_empty() {
2971 let out = DnsOutgoing::new(0);
2972 let packets = out.to_packets(MAX_PKT_DEFAULT, IPV6);
2973 assert_eq!(packets.len(), 1);
2974 assert_eq!(packets[0].as_bytes(), &[0; 12]);
2975 let expected_names = HashMap::new();
2976 assert_eq!(&packets[0].names, &expected_names);
2977 }
2978
2979 #[test]
2980 fn test_dns_outgoing_serialization_question() {
2981 let mut out = DnsOutgoing::new(0);
2982 out.add_question("123.test", RRType::A);
2983 let packets = out.to_packets(MAX_PKT_DEFAULT, IPV6);
2984 assert_eq!(packets.len(), 1);
2985 assert_eq!(
2986 packets[0].as_bytes(),
2987 &[
2988 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 3, 49, 50, 51, 4, 116, 101, 115, 116, 0, 0, 1, 0, 1,
2991 ]
2992 );
2993 let mut expected_names = HashMap::new();
2994 expected_names.insert("123.test".to_string(), 12);
2995 expected_names.insert("test".to_string(), 16);
2996 assert_eq!(&packets[0].names, &expected_names);
2997 }
2998
2999 #[test]
3000 fn test_dns_outgoing_serialization_question_with_authority() {
3001 let mut out = DnsOutgoing::new(0);
3002 out.add_question("123.test", RRType::ANY);
3003 out.add_authority(Box::new(DnsTxt::new(
3004 "124.test",
3005 CLASS_IN,
3006 0x00112233,
3007 b"help".to_vec(),
3008 )));
3009 out.add_authority(Box::new(DnsHostInfo::new(
3010 "124.test",
3011 RRType::CNAME,
3012 CLASS_IN,
3013 0x00112233,
3014 "arm".to_string(),
3015 "linux".to_string(),
3016 )));
3017 let packets = out.to_packets(MAX_PKT_DEFAULT, IPV6);
3018 assert_eq!(packets.len(), 1);
3019 assert_eq!(
3020 packets[0].as_bytes(),
3021 &[
3022 0, 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 3, 49, 50, 51, 4, 116, 101, 115, 116, 0, 0, 255, 0, 1, 3, 49, 50, 52, 192, 16, 0,
3025 16, 0, 1, 0, 17, 34, 51, 0, 4, 104, 101, 108, 112, 192, 26, 0, 5, 0, 1, 0, 17, 34,
3026 51, 0, 8, 97, 114, 109, 108, 105, 110, 117, 120,
3027 ]
3028 );
3029 let mut expected_names = HashMap::new();
3030 expected_names.insert("123.test".to_string(), 12);
3031 expected_names.insert("test".to_string(), 16);
3032 expected_names.insert("124.test".to_string(), 26);
3033 assert_eq!(&packets[0].names, &expected_names);
3034 }
3035
3036 #[test]
3037 fn test_dns_outgoing_serialization_additional_answer() {
3038 let mut out = DnsOutgoing::new(0);
3039 out.add_additional_answer(DnsAddress::new(
3040 "test.local",
3041 RRType::A,
3042 CLASS_IN | CLASS_CACHE_FLUSH,
3043 0xdead_beef,
3044 IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)),
3045 InterfaceId::default(),
3046 ));
3047 let packets = out.to_packets(MAX_PKT_DEFAULT, IPV6);
3048 assert_eq!(packets.len(), 1);
3049 assert_eq!(
3050 packets[0].as_bytes(),
3051 &[
3052 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 116, 101, 115, 116, 5, 108, 111, 99, 97, 108, 0, 0, 1, 128, 1, 222, 173, 190,
3055 239, 0, 4, 127, 0, 0, 1,
3056 ]
3057 );
3058 let mut expected_names = HashMap::new();
3059 expected_names.insert("test.local".to_string(), 12);
3060 expected_names.insert("local".to_string(), 17);
3061 assert_eq!(&packets[0].names, &expected_names);
3062 }
3063
3064 #[test]
3065 fn test_dns_outgoing_serialization_answer_at_time() {
3066 let mut out = DnsOutgoing::new(0);
3067 out.add_answer_at_time(
3068 DnsPointer::new(
3069 "test",
3070 RRType::PTR,
3071 CLASS_IN,
3072 0xaaaa5555,
3073 "test-service".to_string(),
3074 ),
3075 0,
3076 );
3077 let packets = out.to_packets(MAX_PKT_DEFAULT, IPV6);
3078 assert_eq!(packets.len(), 1);
3079 assert_eq!(
3080 packets[0].as_bytes(),
3081 &[
3082 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 4, 116, 101, 115, 116, 0, 0, 12, 0, 1, 170, 170, 85, 85, 0, 14, 12, 116, 101, 115,
3085 116, 45, 115, 101, 114, 118, 105, 99, 101, 0,
3086 ]
3087 );
3088
3089 let mut out = DnsOutgoing::new(0);
3090 out.add_answer_at_time(
3091 DnsPointer::new(
3092 "test",
3093 RRType::CNAME,
3094 CLASS_IN,
3095 0xaaaa5555,
3096 "test-service.local".to_string(),
3097 ),
3098 0,
3099 );
3100 out.add_answer_at_time(
3101 DnsPointer::new(
3102 "test",
3103 RRType::AAAA,
3104 CLASS_IN,
3105 0xffffffff,
3106 "test-service.local".to_string(),
3107 ),
3108 0,
3109 );
3110 let packets = out.to_packets(MAX_PKT_DEFAULT, IPV6);
3111 assert_eq!(packets.len(), 1);
3112 assert_eq!(
3113 packets[0].as_bytes(),
3114 &[
3115 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 4, 116, 101, 115, 116, 0, 0, 5, 0, 1, 170, 170, 85, 85, 0, 20, 12, 116, 101, 115,
3118 116, 45, 115, 101, 114, 118, 105, 99, 101, 5, 108, 111, 99, 97, 108, 0, 192, 12, 0,
3119 28, 0, 1, 255, 255, 255, 255, 0, 2, 192, 28,
3120 ]
3121 );
3122 let mut expected_names = HashMap::new();
3123 expected_names.insert("test".to_string(), 12);
3124 expected_names.insert("test-service.local".to_string(), 28);
3125 expected_names.insert("local".to_string(), 41);
3126 assert_eq!(&packets[0].names, &expected_names);
3127 }
3128
3129 #[test]
3133 fn test_dns_outgoing_question_label_too_long() {
3134 let long_label = "a".repeat(64);
3135 let mut out = DnsOutgoing::new(0);
3136 out.add_question(&format!("{long_label}.local"), RRType::PTR);
3137 out.add_question("123.test", RRType::A);
3138
3139 let packets = out.to_packets(MAX_PKT_DEFAULT, IPV6);
3140 assert_eq!(packets.len(), 1);
3141 assert_eq!(
3142 packets[0].as_bytes(),
3143 &[
3144 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 3, 49, 50, 51, 4, 116, 101, 115, 116, 0, 0, 1, 0, 1,
3147 ]
3148 );
3149
3150 let mut expected_names = HashMap::new();
3152 expected_names.insert("123.test".to_string(), 12);
3153 expected_names.insert("test".to_string(), 16);
3154 assert_eq!(&packets[0].names, &expected_names);
3155 }
3156
3157 #[test]
3160 fn test_dns_outgoing_record_label_too_long() {
3161 let long_label = "a".repeat(64);
3162 let mut out = DnsOutgoing::new(0);
3163 out.add_answer_at_time(
3164 DnsPointer::new(
3165 "_test._tcp.local.",
3166 RRType::PTR,
3167 CLASS_IN,
3168 0,
3169 format!("{long_label}._test._tcp.local."),
3170 ),
3171 0,
3172 );
3173 out.add_answer_at_time(
3174 DnsPointer::new(
3175 "_test._tcp.local.",
3176 RRType::PTR,
3177 CLASS_IN,
3178 0,
3179 "ok._test._tcp.local.".to_string(),
3180 ),
3181 0,
3182 );
3183
3184 let packets = out.to_packets(MAX_PKT_DEFAULT, IPV6);
3185 assert_eq!(packets.len(), 1);
3186
3187 assert_eq!(&packets[0].as_bytes()[6..8], &[0, 1]);
3189
3190 let incoming = DnsIncoming::new(
3192 packets[0].as_bytes().to_vec(),
3193 InterfaceId {
3194 name: "test".to_string(),
3195 index: 1,
3196 },
3197 )
3198 .unwrap();
3199 assert_eq!(incoming.answers().len(), 1);
3200 }
3201
3202 #[test]
3207 fn test_incoming_name_with_merged_labels_does_not_panic() {
3208 let mut data: Vec<u8> = vec![0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0];
3210 data.push(63);
3211 data.extend(vec![b'a'; 62]);
3212 data.push(b'\\');
3213 data.push(63);
3214 data.extend(vec![b'b'; 63]);
3215 data.push(0);
3216 data.extend([0, 12, 0, 1]); let incoming = DnsIncoming::new(
3219 data,
3220 InterfaceId {
3221 name: "test".to_string(),
3222 index: 1,
3223 },
3224 )
3225 .unwrap();
3226 let name = incoming.questions()[0].entry.name.clone();
3227
3228 assert!(name.starts_with("aaa"));
3230 assert!(name.contains("\\.bbb"));
3231
3232 let mut out = DnsOutgoing::new(0);
3234 out.add_question(&name, RRType::PTR);
3235 let packets = out.to_packets(MAX_PKT_DEFAULT, IPV6);
3236 assert_eq!(packets.len(), 1);
3237 assert_eq!(packets[0].as_bytes(), &[0; MSG_HEADER_LEN]);
3238 }
3239
3240 #[test]
3244 fn test_read_name_pointer_loop_is_rejected() {
3245 let mut data: Vec<u8> = vec![0, 0, 0x84, 0, 0, 0, 0, 1, 0, 0, 0, 0];
3249 data.extend_from_slice(&[5, b'l', b'o', b'c', b'a', b'l']); data.extend_from_slice(&[2, b'_', b'x']); data.extend_from_slice(&[0xC0, 12]); data.extend_from_slice(&[0, 12, 0, 1]); data.extend_from_slice(&[0, 0, 0, 120]); data.extend_from_slice(&[0, 2]); data.extend_from_slice(&[0xC0, 12]); assert!(DnsIncoming::new(data, test_interface_id()).is_err());
3258 }
3259
3260 #[test]
3268 fn test_read_name_pointer_after_backward_jump() {
3269 fn push_question(data: &mut Vec<u8>, label_len: usize) {
3271 data.push(label_len as u8);
3272 data.extend(vec![b'a'; label_len]);
3273 data.push(0); data.extend_from_slice(&[0, 12]); data.extend_from_slice(&[0, 1]); }
3277
3278 let mut data: Vec<u8> = vec![
3279 0, 0, 0, 0, 0, 11, 0, 1, 0, 0, 0, 0, ];
3285
3286 for _ in 0..10 {
3288 push_question(&mut data, 60);
3289 }
3290 assert_eq!(data.len(), 672);
3291
3292 push_question(&mut data, 22);
3294 assert_eq!(data.len(), 700);
3295
3296 data[640] = 62;
3298
3299 data.extend_from_slice(&[0xC2, 0x80]); data.extend_from_slice(&[0x00, 0xC2]); data.extend_from_slice(&[0xBE, 0x01]); data.extend_from_slice(&[0, 0, 0, 120]); data.extend_from_slice(&[0, 0]); assert_eq!(u16_from_be_slice(&data[700..702]) ^ 0xC000, 640);
3308 assert_eq!(u16_from_be_slice(&data[703..705]) ^ 0xC000, 702);
3309
3310 let incoming = DnsIncoming::new(data, test_interface_id())
3311 .expect("a name whose pointers all point backwards must parse");
3312 assert_eq!(incoming.questions().len(), 11);
3313
3314 assert_eq!(incoming.answers().len(), 0);
3316 }
3317
3318 #[test]
3325 fn test_read_name_mutual_pointers_are_rejected() {
3326 let mut data: Vec<u8> = vec![0, 0, 0x84, 0, 0, 0, 0, 2, 0, 0, 0, 0];
3327
3328 data.push(0); data.extend_from_slice(&[0x00, 0xC2]); data.extend_from_slice(&[0x00, 0x01]); data.extend_from_slice(&[0, 0, 0, 120]); data.extend_from_slice(&[0x00, 0x04]); data.extend_from_slice(&[0xC0, 25]); data.extend_from_slice(&[0xC0, 23]); assert_eq!(data.len(), 27);
3337
3338 data.extend_from_slice(&[0xC0, 23]); data.extend_from_slice(&[0x00, 0xC2, 0x00, 0x01]); data.extend_from_slice(&[0, 0, 0, 120]); data.extend_from_slice(&[0, 0]); assert_eq!(u16_from_be_slice(&data[27..29]) ^ 0xC000, 23);
3346 assert_eq!(u16_from_be_slice(&data[23..25]) ^ 0xC000, 25);
3347 assert_eq!(u16_from_be_slice(&data[25..27]) ^ 0xC000, 23);
3348
3349 assert!(DnsIncoming::new(data, test_interface_id()).is_err());
3350 }
3351
3352 #[test]
3357 fn test_read_name_label_cycle_is_rejected() {
3358 let mut data: Vec<u8> = vec![0, 0, 0x84, 0, 0, 0, 0, 2, 0, 0, 0, 0];
3359
3360 data.push(0); data.extend_from_slice(&[0x00, 0xC2]); data.extend_from_slice(&[0x00, 0x01]); data.extend_from_slice(&[0, 0, 0, 120]); data.extend_from_slice(&[0x00, 0x07]); data.push(0x04); data.extend_from_slice(b"aaaa"); data.extend_from_slice(&[0xC0, 23]); assert_eq!(data.len(), 30);
3370
3371 data.extend_from_slice(&[0xC0, 23]); data.extend_from_slice(&[0x00, 0xC2, 0x00, 0x01]); data.extend_from_slice(&[0, 0, 0, 120]); data.extend_from_slice(&[0, 0]); assert_eq!(u16_from_be_slice(&data[28..30]) ^ 0xC000, 23);
3380 assert_eq!(u16_from_be_slice(&data[30..32]) ^ 0xC000, 23);
3381
3382 assert!(DnsIncoming::new(data, test_interface_id()).is_err());
3383 }
3384
3385 #[test]
3395 fn test_malformed_nsec_record_is_skipped() {
3396 let data: Vec<u8> = vec![
3397 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x05, 0x5f,
3398 0x6d, 0x69, 0x69, 0x6f, 0x04, 0x5f, 0x75, 0x64, 0x70, 0x05, 0x6c, 0x6f, 0x63, 0x61,
3399 0x6c, 0x00, 0x00, 0x0c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x78, 0x00, 0x24, 0x21, 0x64,
3400 0x72, 0x65, 0x61, 0x6d, 0x65, 0x2d, 0x76, 0x61, 0x63, 0x75, 0x75, 0x6d, 0x2d, 0x70,
3401 0x32, 0x30, 0x32, 0x39, 0x5f, 0x6d, 0x69, 0x69, 0x6f, 0x34, 0x34, 0x37, 0x33, 0x30,
3402 0x35, 0x32, 0x34, 0x37, 0xc0, 0x0c, 0x21, 0x64, 0x72, 0x65, 0x61, 0x6d, 0x65, 0x2d,
3403 0x76, 0x61, 0x63, 0x75, 0x75, 0x6d, 0x2d, 0x70, 0x32, 0x30, 0x32, 0x39, 0x5f, 0x6d,
3404 0x69, 0x69, 0x6f, 0x34, 0x34, 0x37, 0x33, 0x30, 0x35, 0x32, 0x34, 0x37, 0x00, 0x00,
3405 0x2f, 0x80, 0x01, 0x00, 0x00, 0x00, 0x78, 0x00, 0x09, 0xc0, 0x79, 0x00, 0x05, 0x40,
3406 0x00, 0x00, 0x00, 0x00, 0xc0, 0x4c, 0x00, 0x01, 0x80, 0x01, 0x00, 0x00, 0x00, 0x78,
3407 0x00, 0x04, 0x0a, 0x2a, 0x02, 0x32, 0xc0, 0x28, 0x00, 0x21, 0x80, 0x01, 0x00, 0x00,
3408 0x00, 0x78, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0xd4, 0x31, 0xc0, 0x4c, 0xc0, 0x28,
3409 0x00, 0x10, 0x80, 0x01, 0x00, 0x00, 0x00, 0x78, 0x00, 0x0f, 0x0e, 0x70, 0x61, 0x74,
3410 0x68, 0x3d, 0x2f, 0x6d, 0x79, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65,
3411 ];
3412
3413 assert_eq!(u16_from_be_slice(&data[121..123]) ^ 0xC000, 121);
3416
3417 let incoming = DnsIncoming::new(data, test_interface_id())
3418 .expect("one malformed record must not fail the whole packet");
3419
3420 assert_eq!(incoming.answers().len(), 4);
3422 assert!(
3423 !incoming
3424 .answers()
3425 .iter()
3426 .any(|r| r.get_type() == RRType::NSEC),
3427 "the malformed NSEC record must be skipped"
3428 );
3429 }
3430
3431 fn test_interface_id() -> InterfaceId {
3432 InterfaceId {
3433 name: "test".to_string(),
3434 index: 1,
3435 }
3436 }
3437
3438 fn packet_flags(packet: &DnsOutPacket) -> u16 {
3440 let bytes = packet.as_bytes();
3441 u16::from_be_bytes([bytes[2], bytes[3]])
3442 }
3443
3444 fn ptr_answer(index: usize) -> DnsPointer {
3445 DnsPointer::new(
3446 "_spill._tcp.local.",
3447 RRType::PTR,
3448 CLASS_IN,
3449 4500,
3450 format!("instance-{index:04}._spill._tcp.local."),
3451 )
3452 }
3453
3454 fn parsed_answer_count(packets: &[DnsOutPacket]) -> usize {
3457 packets
3458 .iter()
3459 .map(|packet: &DnsOutPacket| {
3460 let parsed = DnsIncoming::new(packet.as_bytes().to_vec(), test_interface_id())
3461 .expect("each packet must parse on its own");
3462 assert!(
3463 !parsed.answers().is_empty(),
3464 "a spilled packet must not be empty"
3465 );
3466 parsed.answers().len()
3467 })
3468 .sum()
3469 }
3470
3471 #[test]
3474 fn test_dns_outgoing_response_spills_into_packets() {
3475 const ANSWER_COUNT: usize = 100;
3476
3477 let mut out = DnsOutgoing::new(FLAGS_QR_RESPONSE);
3478 for i in 0..ANSWER_COUNT {
3479 out.add_answer_at_time(ptr_answer(i), 0);
3480 }
3481
3482 let packets = out.to_packets(MAX_PKT_DEFAULT, IPV6);
3483 assert!(
3484 packets.len() > 1,
3485 "{} answers should not fit in one packet",
3486 ANSWER_COUNT
3487 );
3488
3489 for packet in &packets {
3490 assert!(
3491 packet.size() <= MAX_PKT_DEFAULT,
3492 "packet of {} bytes exceeds the limit",
3493 packet.size()
3494 );
3495
3496 assert_eq!(packet_flags(packet) & FLAGS_TC, 0);
3499 }
3500
3501 assert_eq!(parsed_answer_count(&packets), ANSWER_COUNT);
3502 }
3503
3504 #[test]
3507 fn test_dns_outgoing_query_truncation_bit() {
3508 let mut out = DnsOutgoing::new(FLAGS_QR_QUERY);
3509 out.add_question("_spill._tcp.local.", RRType::PTR);
3510 for i in 0..100 {
3511 out.add_answer_box(Box::new(ptr_answer(i)));
3512 }
3513
3514 let packets = out.to_packets(MAX_PKT_DEFAULT, IPV6);
3515 assert!(
3516 packets.len() > 1,
3517 "known answers should not fit in one packet"
3518 );
3519
3520 let (last, rest) = packets.split_last().expect("at least one packet");
3521 for packet in rest {
3522 assert_ne!(
3523 packet_flags(packet) & FLAGS_TC,
3524 0,
3525 "a packet with more known answers to follow must set TC"
3526 );
3527 }
3528 assert_eq!(
3529 packet_flags(last) & FLAGS_TC,
3530 0,
3531 "the last packet must not set TC"
3532 );
3533
3534 assert_eq!(packets[0].as_bytes()[4..6], 1u16.to_be_bytes());
3536 for packet in rest.iter().skip(1) {
3537 assert_eq!(packet.as_bytes()[4..6], [0, 0]);
3538 }
3539 assert_eq!(parsed_answer_count(&packets), 100);
3540 }
3541
3542 #[test]
3546 fn test_dns_outgoing_oversized_record_sent_alone() {
3547 let mut out = DnsOutgoing::new(FLAGS_QR_RESPONSE);
3548 out.add_answer_at_time(ptr_answer(0), 0);
3549 out.add_answer_at_time(
3550 DnsTxt::new("big._spill._tcp.local.", CLASS_IN, 4500, vec![b'x'; 2000]),
3551 0,
3552 );
3553 out.add_answer_at_time(ptr_answer(1), 0);
3554
3555 let packets = out.to_packets(MAX_PKT_DEFAULT, IPV6);
3556 assert_eq!(packets.len(), 3, "the big record needs a packet to itself");
3557
3558 assert!(packets[0].size() <= MAX_PKT_DEFAULT);
3559 assert!(
3560 packets[1].size() > MAX_PKT_DEFAULT,
3561 "the oversized record must not be dropped"
3562 );
3563 assert!(packets[1].size() <= MAX_PKT_ABSOLUTE_IPV6);
3565 assert!(packets[2].size() <= MAX_PKT_DEFAULT);
3566
3567 let parsed = DnsIncoming::new(packets[1].as_bytes().to_vec(), test_interface_id()).unwrap();
3569 assert_eq!(parsed.answers().len(), 1);
3570 assert_eq!(parsed.answers()[0].get_name(), "big._spill._tcp.local.");
3571 assert_eq!(parsed_answer_count(&packets), 3);
3572 }
3573
3574 #[test]
3577 fn test_dns_outgoing_record_over_absolute_ceiling_dropped() {
3578 let mut out = DnsOutgoing::new(FLAGS_QR_RESPONSE);
3579 out.add_answer_at_time(ptr_answer(0), 0);
3580 out.add_answer_at_time(
3581 DnsTxt::new(
3582 "huge._spill._tcp.local.",
3583 CLASS_IN,
3584 4500,
3585 vec![b'x'; MAX_PKT_ABSOLUTE_IPV6],
3586 ),
3587 0,
3588 );
3589 out.add_answer_at_time(ptr_answer(1), 0);
3590
3591 let packets = out.to_packets(MAX_PKT_DEFAULT, IPV6);
3592 for packet in &packets {
3593 assert!(
3594 packet.size() <= MAX_PKT_ABSOLUTE_IPV6,
3595 "an unsendable packet must never be generated"
3596 );
3597 }
3598 assert_eq!(
3599 parsed_answer_count(&packets),
3600 2,
3601 "only the huge record is dropped"
3602 );
3603 }
3604
3605 #[test]
3607 fn test_dns_outgoing_all_sections_spill() {
3608 let mut out = DnsOutgoing::new(FLAGS_QR_RESPONSE);
3609 for i in 0..40 {
3610 out.add_answer_at_time(ptr_answer(i), 0);
3611 }
3612 for i in 40..80 {
3613 out.add_authority(Box::new(ptr_answer(i)));
3614 }
3615 for i in 80..120 {
3616 out.add_additional_answer(ptr_answer(i));
3617 }
3618
3619 let packets = out.to_packets(MAX_PKT_DEFAULT, IPV6);
3620 assert!(packets.len() > 1);
3621
3622 let mut answers = 0;
3623 let mut authorities = 0;
3624 let mut additionals = 0;
3625 for packet in &packets {
3626 assert!(packet.size() <= MAX_PKT_DEFAULT);
3627 let parsed = DnsIncoming::new(packet.as_bytes().to_vec(), test_interface_id()).unwrap();
3628 answers += parsed.answers().len();
3629 authorities += parsed.authorities().len();
3630 additionals += parsed.additionals().len();
3631 }
3632
3633 assert_eq!(answers, 40);
3634 assert_eq!(authorities, 40);
3635 assert_eq!(additionals, 40);
3636 }
3637}