1use alloc::string::String;
2use alloc::vec::Vec;
3use core::{fmt, str};
4use nex_macro::packet;
5use nex_macro_helper::packet::{Packet, PacketSize, PrimitiveValues};
6use nex_macro_helper::types::{u1, u16be, u32be, u4};
7use std::str::Utf8Error;
8
9#[allow(non_snake_case)]
13#[allow(non_upper_case_globals)]
14pub mod DnsClasses {
15 use super::DnsClass;
16
17 pub const IN: DnsClass = DnsClass(1);
19 pub const CS: DnsClass = DnsClass(2);
21 pub const CH: DnsClass = DnsClass(3);
23 pub const HS: DnsClass = DnsClass(4);
25}
26
27#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
29pub struct DnsClass(pub u16);
30
31impl DnsClass {
32 pub fn new(value: u16) -> Self {
33 Self(value)
34 }
35}
36
37impl PrimitiveValues for DnsClass {
38 type T = (u16,);
39
40 fn to_primitive_values(&self) -> (u16,) {
41 (self.0,)
42 }
43}
44
45impl fmt::Display for DnsClass {
46 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
47 write!(
48 f,
49 "{}",
50 match self {
51 &DnsClasses::IN => "IN", &DnsClasses::CS => "CS", &DnsClasses::CH => "CH", &DnsClasses::HS => "HS", _ => "unknown",
56 }
57 )
58 }
59}
60
61#[allow(non_snake_case)]
65#[allow(non_upper_case_globals)]
66pub mod DnsTypes {
67 use super::DnsType;
68
69 pub const A: DnsType = DnsType(1);
70 pub const NS: DnsType = DnsType(2);
71 pub const MD: DnsType = DnsType(3);
72 pub const MF: DnsType = DnsType(4);
73 pub const CNAME: DnsType = DnsType(5);
74 pub const SOA: DnsType = DnsType(6);
75 pub const MB: DnsType = DnsType(7);
76 pub const MG: DnsType = DnsType(8);
77 pub const MR: DnsType = DnsType(9);
78 pub const NULL: DnsType = DnsType(10);
79 pub const WKS: DnsType = DnsType(11);
80 pub const PTR: DnsType = DnsType(12);
81 pub const HINFO: DnsType = DnsType(13);
82 pub const MINFO: DnsType = DnsType(14);
83 pub const MX: DnsType = DnsType(15);
84 pub const TXT: DnsType = DnsType(16);
85 pub const RP: DnsType = DnsType(17);
86 pub const AFSDB: DnsType = DnsType(18);
87 pub const X25: DnsType = DnsType(19);
88 pub const ISDN: DnsType = DnsType(20);
89 pub const RT: DnsType = DnsType(21);
90 pub const NSAP: DnsType = DnsType(22);
91 pub const NSAP_PTR: DnsType = DnsType(23);
92 pub const SIG: DnsType = DnsType(24);
93 pub const KEY: DnsType = DnsType(25);
94 pub const PX: DnsType = DnsType(26);
95 pub const GPOS: DnsType = DnsType(27);
96 pub const AAAA: DnsType = DnsType(28);
97 pub const LOC: DnsType = DnsType(29);
98 pub const NXT: DnsType = DnsType(30);
99 pub const EID: DnsType = DnsType(31);
100 pub const NIMLOC: DnsType = DnsType(32);
101 pub const SRV: DnsType = DnsType(33);
102 pub const ATMA: DnsType = DnsType(34);
103 pub const NAPTR: DnsType = DnsType(35);
104 pub const KX: DnsType = DnsType(36);
105 pub const CERT: DnsType = DnsType(37);
106 pub const A6: DnsType = DnsType(38);
107 pub const DNAME: DnsType = DnsType(39);
108 pub const SINK: DnsType = DnsType(40);
109 pub const OPT: DnsType = DnsType(41);
110 pub const APL: DnsType = DnsType(42);
111 pub const DS: DnsType = DnsType(43);
112 pub const SSHFP: DnsType = DnsType(44);
113 pub const IPSECKEY: DnsType = DnsType(45);
114 pub const RRSIG: DnsType = DnsType(46);
115 pub const NSEC: DnsType = DnsType(47);
116 pub const DNSKEY: DnsType = DnsType(48);
117 pub const DHCID: DnsType = DnsType(49);
118 pub const NSEC3: DnsType = DnsType(50);
119 pub const NSEC3PARAM: DnsType = DnsType(51);
120 pub const TLSA: DnsType = DnsType(52);
121 pub const SMIMEA: DnsType = DnsType(53);
122 pub const HIP: DnsType = DnsType(55);
123 pub const NINFO: DnsType = DnsType(56);
124 pub const RKEY: DnsType = DnsType(57);
125 pub const TALINK: DnsType = DnsType(58);
126 pub const CDS: DnsType = DnsType(59);
127 pub const CDNSKEY: DnsType = DnsType(60);
128 pub const OPENPGPKEY: DnsType = DnsType(61);
129 pub const CSYNC: DnsType = DnsType(62);
130 pub const ZONEMD: DnsType = DnsType(63);
131 pub const SVCB: DnsType = DnsType(64);
132 pub const HTTPS: DnsType = DnsType(65);
133 pub const SPF: DnsType = DnsType(99);
134 pub const UINFO: DnsType = DnsType(100);
135 pub const UID: DnsType = DnsType(101);
136 pub const GID: DnsType = DnsType(102);
137 pub const UNSPEC: DnsType = DnsType(103);
138 pub const NID: DnsType = DnsType(104);
139 pub const L32: DnsType = DnsType(105);
140 pub const L64: DnsType = DnsType(106);
141 pub const LP: DnsType = DnsType(107);
142 pub const EUI48: DnsType = DnsType(108);
143 pub const EUI64: DnsType = DnsType(109);
144 pub const TKEY: DnsType = DnsType(249);
145 pub const TSIG: DnsType = DnsType(250);
146 pub const IXFR: DnsType = DnsType(251);
147 pub const AXFR: DnsType = DnsType(252);
148 pub const MAILB: DnsType = DnsType(253);
149 pub const MAILA: DnsType = DnsType(254);
150 pub const ANY: DnsType = DnsType(255);
151 pub const URI: DnsType = DnsType(256);
152 pub const CAA: DnsType = DnsType(257);
153 pub const AVC: DnsType = DnsType(258);
154 pub const DOA: DnsType = DnsType(259);
155 pub const AMTRELAY: DnsType = DnsType(260);
156 pub const TA: DnsType = DnsType(32768);
157 pub const DLV: DnsType = DnsType(32769);
158}
159
160#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
162pub struct DnsType(pub u16);
163
164impl DnsType {
165 pub fn new(value: u16) -> Self {
166 Self(value)
167 }
168}
169
170impl PrimitiveValues for DnsType {
171 type T = (u16,);
172
173 fn to_primitive_values(&self) -> (u16,) {
174 (self.0,)
175 }
176}
177
178impl fmt::Display for DnsType {
179 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
180 write!(
181 f,
182 "{}",
183 match self {
184 &DnsTypes::A => "A", &DnsTypes::NS => "NS", &DnsTypes::MD => "MD", &DnsTypes::MF => "MF", &DnsTypes::CNAME => "CNAME", &DnsTypes::SOA => "SOA", &DnsTypes::MB => "MB", &DnsTypes::MG => "MG", &DnsTypes::MR => "MR", &DnsTypes::NULL => "NULL", &DnsTypes::WKS => "WKS", &DnsTypes::PTR => "PTR", &DnsTypes::HINFO => "HINFO", &DnsTypes::MINFO => "MINFO", &DnsTypes::MX => "MX", &DnsTypes::TXT => "TXT", &DnsTypes::RP => "RP", &DnsTypes::AFSDB => "AFSDB", &DnsTypes::X25 => "X25", &DnsTypes::ISDN => "ISDN", &DnsTypes::RT => "RT", &DnsTypes::NSAP => "NSAP", &DnsTypes::NSAP_PTR => "NSAP_PTR", &DnsTypes::SIG => "SIG", &DnsTypes::KEY => "KEY", &DnsTypes::PX => "PX", &DnsTypes::GPOS => "GPOS", &DnsTypes::AAAA => "AAAA", &DnsTypes::LOC => "LOC", &DnsTypes::NXT => "NXT", &DnsTypes::EID => "EID", &DnsTypes::NIMLOC => "NIMLOC", &DnsTypes::SRV => "SRV", &DnsTypes::ATMA => "ATMA", &DnsTypes::NAPTR => "NAPTR", &DnsTypes::KX => "KX", &DnsTypes::CERT => "CERT", &DnsTypes::A6 => "A6", &DnsTypes::DNAME => "DNAME", &DnsTypes::SINK => "SINK", &DnsTypes::OPT => "OPT", &DnsTypes::APL => "APL", &DnsTypes::DS => "DS", &DnsTypes::SSHFP => "SSHFP", &DnsTypes::IPSECKEY => "IPSECKEY", &DnsTypes::RRSIG => "RRSIG", &DnsTypes::NSEC => "NSEC", &DnsTypes::DNSKEY => "DNSKEY", &DnsTypes::DHCID => "DHCID", &DnsTypes::NSEC3 => "NSEC3", &DnsTypes::NSEC3PARAM => "NSEC3PARAM", &DnsTypes::TLSA => "TLSA", &DnsTypes::SMIMEA => "SMIMEA", &DnsTypes::HIP => "HIP", &DnsTypes::NINFO => "NINFO", &DnsTypes::RKEY => "RKEY", &DnsTypes::TALINK => "TALINK", &DnsTypes::CDS => "CDS", &DnsTypes::CDNSKEY => "CDNSKEY", &DnsTypes::OPENPGPKEY => "OPENPGPKEY", &DnsTypes::CSYNC => "CSYNC", &DnsTypes::ZONEMD => "ZONEMD", &DnsTypes::SVCB => "SVCB", &DnsTypes::HTTPS => "HTTPS", &DnsTypes::SPF => "SPF", &DnsTypes::UINFO => "UINFO", &DnsTypes::UID => "UID", &DnsTypes::GID => "GID", &DnsTypes::UNSPEC => "UNSPEC", &DnsTypes::NID => "NID", &DnsTypes::L32 => "L32", &DnsTypes::L64 => "L64", &DnsTypes::LP => "LP", &DnsTypes::EUI48 => "EUI48", &DnsTypes::EUI64 => "EUI64", &DnsTypes::TKEY => "TKEY", &DnsTypes::TSIG => "TSIG", &DnsTypes::IXFR => "IXFR", &DnsTypes::AXFR => "AXFR", &DnsTypes::MAILB => "MAILB", &DnsTypes::MAILA => "MAILA", &DnsTypes::ANY => "ANY", &DnsTypes::URI => "URI", &DnsTypes::CAA => "CAA", &DnsTypes::AVC => "AVC", &DnsTypes::DOA => "DOA", &DnsTypes::AMTRELAY => "AMTRELAY", &DnsTypes::TA => "TA", &DnsTypes::DLV => "DLV", _ => "unknown",
274 }
275 )
276 }
277}
278
279#[packet]
282pub struct Dns {
283 pub id: u16be,
284 pub is_response: u1,
285 #[construct_with(u4)]
286 pub opcode: OpCode,
287 pub is_authoriative: u1,
288 pub is_truncated: u1,
289 pub is_recursion_desirable: u1,
290 pub is_recursion_available: u1,
291 pub zero_reserved: u1,
292 pub is_answer_authenticated: u1,
293 pub is_non_authenticated_data: u1,
294 #[construct_with(u4)]
295 pub rcode: RetCode,
296 pub query_count: u16be,
297 pub response_count: u16be,
298 pub authority_rr_count: u16be,
299 pub additional_rr_count: u16be,
300 #[length_fn = "queries_length"]
301 pub queries: Vec<DnsQuery>,
302 #[length_fn = "responses_length"]
303 pub responses: Vec<DnsResponse>,
304 #[length_fn = "authority_length"]
305 pub authorities: Vec<DnsResponse>,
306 #[length_fn = "additional_length"]
307 pub additionals: Vec<DnsResponse>,
308 #[payload]
309 pub payload: Vec<u8>,
310}
311
312fn queries_length(packet: &DnsPacket) -> usize {
313 let base = 12;
314 let mut length = 0;
315 for _ in 0..packet.get_query_count() {
316 match DnsQueryPacket::new(&packet.packet()[base + length..]) {
317 Some(query) => length += query.packet_size(),
318 None => break,
319 }
320 }
321 length
322}
323
324fn responses_length(packet: &DnsPacket) -> usize {
325 let base = 12 + queries_length(packet);
326 let mut length = 0;
327 for _ in 0..packet.get_response_count() {
328 match DnsResponsePacket::new(&packet.packet()[base + length..]) {
329 Some(query) => length += query.packet_size(),
330 None => break,
331 }
332 }
333 length
334}
335
336fn authority_length(packet: &DnsPacket) -> usize {
337 let base = 12 + queries_length(packet) + responses_length(packet);
338 let mut length = 0;
339 for _ in 0..packet.get_authority_rr_count() {
340 match DnsResponsePacket::new(&packet.packet()[base + length..]) {
341 Some(query) => length += query.packet_size(),
342 None => break,
343 }
344 }
345 length
346}
347
348fn additional_length(packet: &DnsPacket) -> usize {
349 let base = 12 + queries_length(packet) + responses_length(packet) + authority_length(packet);
350 let mut length = 0;
351 for _ in 0..packet.get_additional_rr_count() {
352 match DnsResponsePacket::new(&packet.packet()[base + length..]) {
353 Some(query) => length += query.packet_size(),
354 None => break,
355 }
356 }
357 length
358}
359
360#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
363pub enum OpCode {
364 Query,
365 InverseQuery,
366 Status,
367 Reserved,
368 Notify,
369 Update,
370 Dso,
371 Unassigned(u8),
372}
373
374impl PrimitiveValues for OpCode {
375 type T = (u8,);
376 fn to_primitive_values(&self) -> (u8,) {
377 match self {
378 Self::Query => (0,),
379 Self::InverseQuery => (1,),
380 Self::Status => (2,),
381 Self::Reserved => (3,),
382 Self::Notify => (4,),
383 Self::Update => (5,),
384 Self::Dso => (6,),
385 Self::Unassigned(n) => (*n,),
386 }
387 }
388}
389
390impl OpCode {
391 pub fn new(value: u8) -> Self {
392 match value {
393 0 => Self::Query,
394 1 => Self::InverseQuery,
395 2 => Self::Status,
396 3 => Self::Reserved,
397 4 => Self::Notify,
398 5 => Self::Update,
399 6 => Self::Dso,
400 _ => Self::Unassigned(value),
401 }
402 }
403}
404
405#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
408pub enum RetCode {
409 NoError,
410 FormErr,
411 ServFail,
412 NXDomain,
413 NotImp,
414 Refused,
415 YXDomain,
416 YXRRSet,
417 NXRRSet,
418 NotAuth,
419 NotZone,
420 Dsotypeni,
421 BadVers,
422 BadKey,
423 BadTime,
424 BadMode,
425 BadName,
426 BadAlg,
427 BadTrunc,
428 BadCookie,
429 Unassigned(u8),
430}
431
432impl PrimitiveValues for RetCode {
433 type T = (u8,);
434 fn to_primitive_values(&self) -> (u8,) {
435 match self {
436 Self::NoError => (0,),
437 Self::FormErr => (1,),
438 Self::ServFail => (2,),
439 Self::NXDomain => (3,),
440 Self::NotImp => (4,),
441 Self::Refused => (5,),
442 Self::YXDomain => (6,),
443 Self::YXRRSet => (7,),
444 Self::NXRRSet => (8,),
445 Self::NotAuth => (9,),
446 Self::NotZone => (10,),
447 Self::Dsotypeni => (11,),
448 Self::BadVers => (16,),
449 Self::BadKey => (17,),
450 Self::BadTime => (18,),
451 Self::BadMode => (19,),
452 Self::BadName => (20,),
453 Self::BadAlg => (21,),
454 Self::BadTrunc => (22,),
455 Self::BadCookie => (23,),
456 Self::Unassigned(n) => (*n,),
457 }
458 }
459}
460
461impl RetCode {
462 pub fn new(value: u8) -> Self {
463 match value {
464 0 => Self::NoError,
465 1 => Self::FormErr,
466 2 => Self::ServFail,
467 3 => Self::NXDomain,
468 4 => Self::NotImp,
469 5 => Self::Refused,
470 6 => Self::YXDomain,
471 7 => Self::YXRRSet,
472 8 => Self::NXRRSet,
473 9 => Self::NotAuth,
474 10 => Self::NotZone,
475 11 => Self::Dsotypeni,
476 16 => Self::BadVers,
477 17 => Self::BadKey,
478 18 => Self::BadTime,
479 19 => Self::BadMode,
480 20 => Self::BadName,
481 21 => Self::BadAlg,
482 22 => Self::BadTrunc,
483 23 => Self::BadCookie,
484 _ => Self::Unassigned(value),
485 }
486 }
487}
488
489#[packet]
491pub struct DnsQuery {
492 #[length_fn = "qname_length"]
493 pub qname: Vec<u8>,
494 #[construct_with(u16be)]
495 pub qtype: DnsType,
496 #[construct_with(u16be)]
497 pub qclass: DnsClass,
498 #[payload]
499 pub payload: Vec<u8>,
500}
501
502fn qname_length(packet: &DnsQueryPacket) -> usize {
503 packet.packet().iter().take_while(|w| *w != &0).count() + 1
504}
505
506impl DnsQuery {
507 pub fn get_qname_parsed(&self) -> Result<String, Utf8Error> {
508 let name = &self.qname;
509 let mut qname = String::new();
510 let mut offset = 0;
511 loop {
512 let label_len = name[offset] as usize;
513 if label_len == 0 {
514 break;
515 }
516 if !qname.is_empty() {
517 qname.push('.');
518 }
519 match str::from_utf8(&name[offset + 1..offset + 1 + label_len]) {
520 Ok(label) => qname.push_str(label),
521 Err(e) => return Err(e),
522 }
523 offset += label_len + 1;
524 }
525 Ok(qname)
526 }
527}
528
529#[packet]
531pub struct DnsResponse {
532 #[length_fn = "rname_length"]
533 pub rname: Vec<u8>,
534 #[construct_with(u16be)]
535 pub rtype: DnsType,
536 #[construct_with(u16be)]
537 pub rclass: DnsClass,
538 pub ttl: u32be,
539 pub data_len: u16be,
540 #[length = "data_len"]
541 pub data: Vec<u8>,
542 #[payload]
543 pub payload: Vec<u8>,
544}
545
546fn rname_length(packet: &DnsResponsePacket) -> usize {
548 let mut offset = 0;
549 let mut size = 0;
550 loop {
551 let label_len = packet.packet()[offset] as usize;
552 if label_len == 0 {
553 size += 1;
554 break;
555 }
556 if label_len & 0xC0 == 0xC0 {
557 size += 2;
558 break;
559 }
560 size += label_len + 1;
561 offset += label_len + 1;
562 }
563 size
564}
565
566pub fn parse_name(packet: &DnsPacket, coded_name: &Vec<u8>) -> Result<String, Utf8Error> {
568 let start = packet.packet();
571 let mut name = coded_name.as_slice();
572 let mut rname = String::new();
573 let mut offset: usize = 0;
574
575 loop {
576 let label_len: u16 = name[offset] as u16;
577 if label_len == 0 {
578 break;
579 }
580 if (label_len & 0xC0) == 0xC0 {
581 let offset1 = ((label_len & 0x3F) as usize) << 8;
582 let offset2 = name[offset + 1] as usize;
583 offset = offset1 + offset2;
584 name = start;
586 continue;
587 }
588 if !rname.is_empty() {
589 rname.push('.');
590 }
591 match str::from_utf8(&name[offset + 1..offset + 1 + label_len as usize]) {
592 Ok(label) => rname.push_str(label),
593 Err(e) => return Err(e),
594 }
595 offset += label_len as usize + 1;
596 }
597 Ok(rname)
598}
599
600#[packet]
604pub struct DnsRrTXT {
605 pub data_len: u8,
606 #[length = "data_len"]
607 pub text: Vec<u8>,
608 #[payload]
609 pub payload: Vec<u8>,
610}
611
612#[packet]
616pub struct DnsRrSrv {
617 pub priority: u16be,
618 pub weight: u16be,
619 pub port: u16be,
620 #[length_fn = "target_length"]
621 pub target: Vec<u8>,
622 #[payload]
623 pub payload: Vec<u8>,
624}
625
626fn target_length(packet: &DnsRrSrvPacket) -> usize {
627 let mut offset = 6;
628 let mut size = 0;
629 loop {
630 let label_len = packet.packet()[offset] as usize;
631 if label_len == 0 {
632 size += 1;
633 break;
634 }
635 if label_len & 0xC0 == 0xC0 {
636 size += 2;
637 break;
638 }
639 size += label_len + 1;
640 offset += label_len + 1;
641 }
642 size
643}
644
645#[derive(Debug)]
650pub struct SrvName {
651 pub instance: Option<String>,
652 pub service: Option<String>,
653 pub protocol: Option<String>,
654 pub domain: Option<String>,
655}
656
657impl SrvName {
658 pub fn new(name: &str) -> Self {
659 let parts: Vec<&str> = name.split('.').collect();
660 let (instance, service, protocol, domain) = match parts.as_slice() {
661 [instance, service, protocol, domain @ ..]
662 if service.starts_with('_') && protocol.starts_with('_') =>
663 {
664 (
665 Some(String::from(*instance)),
666 Some(String::from(*service)),
667 Some(String::from(*protocol)),
668 Some(String::from(domain.join("."))),
669 )
670 }
671 [service, protocol, domain @ ..]
672 if service.starts_with('_') && protocol.starts_with('_') =>
673 {
674 (
675 None,
676 Some(String::from(*service)),
677 Some(String::from(*protocol)),
678 Some(String::from(domain.join("."))),
679 )
680 }
681 [instance, service, protocol, domain @ ..] => (
682 Some(String::from(*instance)),
683 Some(String::from(*service)),
684 Some(String::from(*protocol)),
685 Some(String::from(domain.join("."))),
686 ),
687 _ => (None, None, None, None),
688 };
689
690 SrvName {
691 instance,
692 service,
693 protocol,
694 domain,
695 }
696 }
697}
698
699#[test]
700fn test_dns_query_packet() {
701 let packet = DnsPacket::new(b"\x1e\xcb\x01\x20\x00\x01\x00\x00\x00\x00\x00\x01\x0a\x63\x6c\x6f\x75\x64\x66\x6c\x61\x72\x65\x03\x63\x6f\x6d\x00\x00\x01\x00\x01\x00\x00\x29\x10\x00\x00\x00\x00\x00\x00\x00").unwrap();
702 assert_eq!(packet.get_id(), 7883);
703 assert_eq!(packet.get_is_response(), 0);
704 assert_eq!(packet.get_opcode(), OpCode::Query);
705 assert_eq!(packet.get_is_authoriative(), 0);
706 assert_eq!(packet.get_is_truncated(), 0);
707 assert_eq!(packet.get_is_recursion_desirable(), 1);
708 assert_eq!(packet.get_is_recursion_available(), 0);
709 assert_eq!(packet.get_zero_reserved(), 0);
710 assert_eq!(packet.get_rcode(), RetCode::NoError);
711 assert_eq!(packet.get_query_count(), 1);
712 assert_eq!(packet.get_response_count(), 0);
713 assert_eq!(packet.get_authority_rr_count(), 0);
714 assert_eq!(packet.get_additional_rr_count(), 1);
715 assert_eq!(packet.get_queries().len(), 1);
716 assert_eq!(
717 packet.get_queries()[0]
718 .get_qname_parsed()
719 .unwrap_or(String::new()),
720 "cloudflare.com"
721 );
722 assert_eq!(packet.get_queries()[0].qtype, DnsTypes::A);
723 assert_eq!(packet.get_queries()[0].qclass, DnsClasses::IN);
724 assert_eq!(packet.get_responses().len(), 0);
725 assert_eq!(packet.get_authorities().len(), 0);
726 assert_eq!(packet.get_additionals().len(), 1);
727}
728
729#[test]
730fn test_dns_reponse_packet() {
731 let packet = DnsPacket::new(b"\x1e\xcb\x81\xa0\x00\x01\x00\x02\x00\x00\x00\x01\x0a\x63\x6c\x6f\x75\x64\x66\x6c\x61\x72\x65\x03\x63\x6f\x6d\x00\x00\x01\x00\x01\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\xc4\x00\x04h\x10\x85\xe5\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\xc4\x00\x04h\x10\x84\xe5\x00\x00)\x04\xd0\x00\x00\x00\x00\x00\x00").unwrap();
732 assert_eq!(packet.get_id(), 7883);
733 assert_eq!(packet.get_is_response(), 1);
734 assert_eq!(packet.get_opcode(), OpCode::Query);
735 assert_eq!(packet.get_is_authoriative(), 0);
736 assert_eq!(packet.get_is_truncated(), 0);
737 assert_eq!(packet.get_is_recursion_desirable(), 1);
738 assert_eq!(packet.get_is_recursion_available(), 1);
739 assert_eq!(packet.get_zero_reserved(), 0);
740 assert_eq!(packet.get_rcode(), RetCode::NoError);
741 assert_eq!(packet.get_query_count(), 1);
742 assert_eq!(packet.get_response_count(), 2);
743 assert_eq!(packet.get_authority_rr_count(), 0);
744 assert_eq!(packet.get_additional_rr_count(), 1);
745 assert_eq!(packet.get_queries().len(), 1);
746 assert_eq!(
747 packet.get_queries()[0]
748 .get_qname_parsed()
749 .unwrap_or(String::new()),
750 "cloudflare.com"
751 );
752 assert_eq!(packet.get_queries()[0].qtype, DnsTypes::A);
753 assert_eq!(packet.get_queries()[0].qclass, DnsClasses::IN);
754 assert_eq!(packet.get_responses().len(), 2);
755 assert_eq!(packet.get_responses()[0].rtype, DnsTypes::A);
756 assert_eq!(packet.get_responses()[0].rclass, DnsClasses::IN);
757 assert_eq!(packet.get_responses()[0].ttl, 196);
758 assert_eq!(packet.get_responses()[0].data_len, 4);
759 assert_eq!(
760 packet.get_responses()[0].data.as_slice(),
761 [104, 16, 133, 229]
762 );
763 assert_eq!(packet.get_authorities().len(), 0);
764 assert_eq!(packet.get_additionals().len(), 1);
765}
766
767#[test]
768fn test_mdns_response() {
769 let data = b"\x00\x00\x84\x00\x00\x00\x00\x04\x00\x00\x00\x00\x0b\x5f\x61\x6d\x7a\x6e\x2d\x61\x6c\x65\x78\x61\x04\x5f\x74\x63\x70\x05\x6c\x6f\x63\x61\x6c\x00\x00\x0c\x00\x01\x00\x00\x11\x94\x00\x0b\x08\x5f\x73\x65\x72\x76\x69\x63\x65\xc0\x0c\xc0\x2e\x00\x10\x80\x01\x00\x00\x11\x94\x00\x0a\x09\x76\x65\x72\x73\x69\x6f\x6e\x3d\x31\xc0\x2e\x00\x21\x80\x01\x00\x00\x00\x78\x00\x1d\x00\x00\x00\x00\x19\x8f\x14\x61\x76\x73\x2d\x66\x66\x72\x65\x67\x2d\x31\x36\x35\x34\x34\x37\x35\x36\x38\x33\xc0\x1d\xc0\x61\x00\x01\x80\x01\x00\x00\x00\x78\x00\x04\xc0\xa8\x01\x06";
770 let packet = DnsPacket::new(data).expect("Failed to parse dns response");
771 assert_eq!(packet.get_id(), 0);
772 assert_eq!(packet.get_is_response(), 1);
773 assert_eq!(packet.get_opcode(), OpCode::Query);
774 assert_eq!(packet.get_is_authoriative(), 1);
775 assert_eq!(packet.get_is_truncated(), 0);
776 assert_eq!(packet.get_is_recursion_desirable(), 0);
777 assert_eq!(packet.get_is_recursion_available(), 0);
778 assert_eq!(packet.get_zero_reserved(), 0);
779 assert_eq!(packet.get_rcode(), RetCode::NoError);
780 assert_eq!(packet.get_query_count(), 0);
781 assert_eq!(packet.get_response_count(), 4);
782 assert_eq!(packet.get_authority_rr_count(), 0);
783 assert_eq!(packet.get_additional_rr_count(), 0);
784 assert_eq!(packet.get_responses().len(), 4);
785 let responses = packet.get_responses();
786 assert_eq!(
788 parse_name(&packet, &responses[0].rname).unwrap_or(String::new()),
789 "_amzn-alexa._tcp.local"
790 );
791 assert_eq!(responses[0].rtype, DnsTypes::PTR);
792 assert_eq!(responses[0].rclass, DnsClasses::IN);
793 assert_eq!(responses[0].ttl, 4500);
794 assert_eq!(responses[0].data_len, 11);
795 assert_eq!(
796 parse_name(&packet, &responses[0].data).unwrap_or(String::new()),
797 "_service._amzn-alexa._tcp.local"
798 );
799 assert_eq!(
801 parse_name(&packet, &responses[1].rname).unwrap_or(String::new()),
802 "_service._amzn-alexa._tcp.local"
803 );
804 assert_eq!(responses[1].rtype, DnsTypes::TXT);
805 assert_eq!(responses[1].ttl, 4500);
806 assert_eq!(responses[1].data_len, 10);
807 let text_rr = DnsRrTXTPacket::new(&responses[1].data).unwrap();
808 assert_eq!(text_rr.get_data_len(), 9);
809 assert_eq!(String::from_utf8(text_rr.get_text()).unwrap(), "version=1");
810 let srv_name = parse_name(&packet, &responses[2].rname).unwrap_or(String::new());
812 assert_eq!(srv_name, "_service._amzn-alexa._tcp.local");
813 assert_eq!(responses[2].rtype, DnsTypes::SRV);
814 assert_eq!(responses[2].data_len, 29);
815 let srv_rr = DnsRrSrvPacket::new(&responses[2].data).unwrap();
816 assert_eq!(srv_rr.get_priority(), 0);
817 assert_eq!(srv_rr.get_weight(), 0);
818 assert_eq!(srv_rr.get_port(), 6543);
819 assert_eq!(
820 parse_name(&packet, &srv_rr.get_target()).unwrap_or(String::new()),
821 "avs-ffreg-1654475683.local"
822 );
823 let srv = SrvName::new(&srv_name);
824 assert_eq!(srv.instance, Some(String::from("_service")));
825 assert_eq!(srv.service, Some(String::from("_amzn-alexa")));
826 assert_eq!(srv.protocol, Some(String::from("_tcp")));
827 assert_eq!(srv.domain, Some(String::from("local")));
828 assert_eq!(responses[3].rtype, DnsTypes::A);
830 assert_eq!(responses[3].data.as_slice(), [192, 168, 1, 6]);
831}