1use std::{fmt::Write as _, str::Utf8Error};
2
3use data_encoding::{BASE32HEX_NOPAD, BASE64, HEXUPPER};
4use hickory_proto::{
5 ProtoError,
6 dnssec::{
7 PublicKey, SupportedAlgorithms, Verifier,
8 rdata::{CDNSKEY, CDS, DNSKEY, DNSSECRData, DS},
9 },
10 op::{Message as TrustDnsMessage, Query},
11 rr::{
12 Name, RData, Record, RecordType,
13 rdata::{
14 A, AAAA, NULL, OPT, SVCB,
15 opt::{EdnsCode, EdnsOption},
16 },
17 },
18 serialize::binary::{BinDecodable, BinDecoder},
19};
20use snafu::Snafu;
21
22use super::dns_message::{
23 self, DnsQueryMessage, DnsRecord, DnsUpdateMessage, EdnsOptionEntry, OptPseudoSection,
24 QueryHeader, QueryQuestion, UpdateHeader, ZoneInfo,
25};
26use crate::ede::{EDE, EDE_OPTION_CODE};
27
28#[derive(Debug, Snafu)]
30pub enum DnsMessageParserError {
31 #[snafu(display("Encountered error: {}", cause))]
32 SimpleError { cause: String },
33
34 #[snafu(display("Encountered error from TrustDns: {}", source))]
35 TrustDnsError { source: ProtoError },
36
37 #[snafu(display("UTF8Error: {}", source))]
38 Utf8ParsingError { source: Utf8Error },
39}
40
41pub type DnsParserResult<T> = Result<T, DnsMessageParserError>;
43
44#[derive(Debug, Default, Clone)]
46pub struct DnsParserOptions {
47 pub lowercase_hostnames: bool,
49}
50
51trait DnsParserOptionsTarget {
52 fn to_string_with_options(&self, options: &DnsParserOptions) -> String;
53}
54
55impl DnsParserOptionsTarget for Name {
56 fn to_string_with_options(&self, options: &DnsParserOptions) -> String {
57 if options.lowercase_hostnames {
58 self.to_lowercase().to_string()
59 } else {
60 self.to_string()
61 }
62 }
63}
64
65#[derive(Debug)]
67pub struct DnsMessageParser {
68 raw_message: Vec<u8>,
69 raw_message_for_rdata_parsing: Option<Vec<u8>>,
76 options: DnsParserOptions,
77}
78
79impl DnsMessageParser {
80 pub fn new(raw_message: Vec<u8>) -> Self {
81 DnsMessageParser {
82 raw_message,
83 raw_message_for_rdata_parsing: None,
84 options: DnsParserOptions::default(),
85 }
86 }
87
88 pub fn with_options(raw_message: Vec<u8>, options: DnsParserOptions) -> Self {
89 DnsMessageParser {
90 raw_message,
91 raw_message_for_rdata_parsing: None,
92 options,
93 }
94 }
95
96 pub fn raw_message(&self) -> &[u8] {
97 &self.raw_message
98 }
99
100 pub fn parse_as_query_message(&mut self) -> DnsParserResult<DnsQueryMessage> {
101 let msg = TrustDnsMessage::from_vec(&self.raw_message).map_err(|source| {
102 DnsMessageParserError::TrustDnsError {
103 source: ProtoError::from(source),
104 }
105 })?;
106 let header = parse_dns_query_message_header(&msg);
107 let edns_section = parse_edns(&msg).transpose()?;
108 let rcode_high = edns_section.as_ref().map_or(0, |edns| edns.extended_rcode);
109 let response_code = (u16::from(rcode_high) << 4) | ((u16::from(header.rcode)) & 0x000F);
110
111 Ok(DnsQueryMessage {
112 response_code,
113 response: parse_response_code(response_code),
114 header,
115 question_section: self.parse_dns_query_message_question_section(&msg),
116 answer_section: self.parse_dns_message_section(&msg.answers)?,
117 authority_section: self.parse_dns_message_section(&msg.authorities)?,
118 additional_section: self.parse_dns_message_section(&msg.additionals)?,
119 opt_pseudo_section: edns_section,
120 })
121 }
122
123 pub fn parse_as_update_message(&mut self) -> DnsParserResult<DnsUpdateMessage> {
124 let msg = TrustDnsMessage::from_vec(&self.raw_message).map_err(|source| {
125 DnsMessageParserError::TrustDnsError {
126 source: ProtoError::from(source),
127 }
128 })?;
129 let header = parse_dns_update_message_header(&msg);
130 let response_code = (u16::from(header.rcode)) & 0x000F;
131 Ok(DnsUpdateMessage {
132 response_code,
133 response: parse_response_code(response_code),
134 header,
135 zone_to_update: self.parse_dns_update_message_zone_section(&msg)?,
136 prerequisite_section: self.parse_dns_message_section(&msg.answers)?,
137 update_section: self.parse_dns_message_section(&msg.authorities)?,
138 additional_section: self.parse_dns_message_section(&msg.additionals)?,
139 })
140 }
141
142 fn parse_dns_query_message_question_section(
143 &self,
144 dns_message: &TrustDnsMessage,
145 ) -> Vec<QueryQuestion> {
146 dns_message
147 .queries
148 .iter()
149 .map(|query| self.parse_dns_query_question(query))
150 .collect()
151 }
152
153 fn parse_dns_query_question(&self, question: &Query) -> QueryQuestion {
154 QueryQuestion {
155 name: question.name().to_string_with_options(&self.options),
156 class: question.query_class().to_string(),
157 record_type: format_record_type(question.query_type()),
158 record_type_id: u16::from(question.query_type()),
159 }
160 }
161
162 fn parse_dns_update_message_zone_section(
163 &self,
164 dns_message: &TrustDnsMessage,
165 ) -> DnsParserResult<ZoneInfo> {
166 let zones = dns_message
167 .queries
168 .iter()
169 .map(|query| self.parse_dns_query_question(query).into())
170 .collect::<Vec<ZoneInfo>>();
171
172 zones
173 .first()
174 .cloned()
175 .ok_or_else(|| DnsMessageParserError::SimpleError {
176 cause: format!(
177 "Unexpected number of records in update section: {}",
178 zones.len()
179 ),
180 })
181 }
182
183 fn parse_dns_message_section(&mut self, records: &[Record]) -> DnsParserResult<Vec<DnsRecord>> {
184 records
185 .iter()
186 .map(|record| self.parse_dns_record(record))
187 .collect::<Result<Vec<_>, _>>()
188 }
189
190 pub(crate) fn parse_dns_record(&mut self, record: &Record) -> DnsParserResult<DnsRecord> {
191 let record_data = match &record.data {
192 RData::Unknown { code, rdata } => self.format_unknown_rdata(u16::from(*code), rdata),
193 RData::Update0(_) => Ok((Some(String::from("")), None)), rdata => self.format_rdata(rdata),
195 }?;
196
197 Ok(DnsRecord {
198 name: record.name.to_string_with_options(&self.options),
199 class: record.dns_class.to_string(),
200 record_type: format_record_type(record.record_type()),
201 record_type_id: u16::from(record.record_type()),
202 ttl: record.ttl,
203 rdata: record_data.0,
204 rdata_bytes: record_data.1,
205 })
206 }
207
208 fn get_rdata_decoder_with_raw_message(&mut self, raw_rdata: &[u8]) -> BinDecoder<'_> {
209 let (index, raw_message_for_rdata_parsing_data) =
210 match self.raw_message_for_rdata_parsing.take() {
211 Some(mut buf) => {
212 let index = buf.len();
213 buf.extend_from_slice(raw_rdata);
214 (index, buf)
215 }
216 None => {
217 let mut buf = Vec::<u8>::with_capacity(self.raw_message.len() * 2);
218 buf.extend(&self.raw_message);
219 buf.extend_from_slice(raw_rdata);
220 (self.raw_message.len(), buf)
221 }
222 };
223 self.raw_message_for_rdata_parsing = Some(raw_message_for_rdata_parsing_data);
224
225 BinDecoder::new(
226 self.raw_message_for_rdata_parsing
227 .as_ref()
228 .expect("None raw_message_for_rdata_parsing"),
229 )
230 .clone(index as u16)
231 }
232
233 fn parse_wks_rdata(
234 &mut self,
235 raw_rdata: &[u8],
236 ) -> DnsParserResult<(Option<String>, Option<Vec<u8>>)> {
237 let mut decoder = BinDecoder::new(raw_rdata);
238 let address = parse_ipv4_address(&mut decoder)?;
239 let protocol = parse_u8(&mut decoder)?;
240 let port = {
241 let mut port_string = String::new();
242 let mut current_bit: u32 = 0;
243 while !decoder.is_empty() {
244 let mut current_byte = parse_u8(&mut decoder)?;
245 if current_byte == 0 {
246 current_bit += 8;
247 continue;
248 }
249 for _i in 0..8 {
250 if current_byte & 0b1000_0000 == 0b1000_0000 {
251 write!(port_string, "{current_bit} ").expect("can always write to String");
252 }
253 current_byte <<= 1;
254 current_bit += 1;
255 }
256 }
257 port_string
258 };
259 Ok((
260 Some(format!("{} {} {}", address, protocol, port.trim_end())),
261 None,
262 ))
263 }
264
265 fn parse_a6_rdata(
266 &mut self,
267 raw_rdata: &[u8],
268 ) -> DnsParserResult<(Option<String>, Option<Vec<u8>>)> {
269 let mut decoder = BinDecoder::new(raw_rdata);
270 let prefix = parse_u8(&mut decoder)?;
271 let ipv6_address = {
272 if prefix > 128 {
273 return Err(DnsMessageParserError::SimpleError {
274 cause: String::from("IPV6 prefix can't be greater than 128."),
275 });
276 }
277 let address_length = (128 - prefix) / 8;
278 let mut address_vec = parse_vec(&mut decoder, address_length)?;
279 if address_vec.len() < 16 {
280 let pad_len = 16 - address_length;
281 let mut padded_address_vec = vec![0; pad_len as usize];
282 padded_address_vec.extend(&address_vec);
283 address_vec = padded_address_vec;
284 }
285 let mut dec = BinDecoder::new(&address_vec);
286 parse_ipv6_address(&mut dec)?
287 };
288 let domain_name = Self::parse_domain_name(&mut decoder, &self.options)?;
289 Ok((Some(format!("{prefix} {ipv6_address} {domain_name}")), None))
290 }
291
292 fn parse_loc_rdata(
293 &mut self,
294 raw_rdata: &[u8],
295 ) -> DnsParserResult<(Option<String>, Option<Vec<u8>>)> {
296 let mut decoder = BinDecoder::new(raw_rdata);
297 let _max_latitude: u32 = 0x8000_0000 + 90 * 3_600_000;
298 let _min_latitude: u32 = 0x8000_0000 - 90 * 3_600_000;
299 let _max_longitude: u32 = 0x8000_0000 + 180 * 3_600_000;
300 let _min_longitude: u32 = 0x8000_0000 - 180 * 3_600_000;
301 let _version = parse_u8(&mut decoder)?;
302 if _version != 0 {
303 return Err(DnsMessageParserError::SimpleError {
304 cause: String::from("LOC record version should be 0."),
305 });
306 }
307 let size = parse_loc_rdata_size(parse_u8(&mut decoder)?)?;
308 let horizontal_precision = parse_loc_rdata_size(parse_u8(&mut decoder)?)?;
309 let vertical_precision = parse_loc_rdata_size(parse_u8(&mut decoder)?)?;
310
311 let latitude = {
312 let received_lat = parse_u32(&mut decoder)?;
313 if received_lat < _min_latitude || received_lat > _max_latitude {
314 return Err(DnsMessageParserError::SimpleError {
315 cause: String::from("LOC record latitude out of bounds"),
316 });
317 }
318 let dir = if received_lat > 0x8000_0000 { "N" } else { "S" };
319 parse_loc_rdata_coordinates(received_lat, dir)
320 };
321
322 let longitude = {
323 let received_lon = parse_u32(&mut decoder)?;
324 if received_lon < _min_longitude || received_lon > _max_longitude {
325 return Err(DnsMessageParserError::SimpleError {
326 cause: String::from("LOC record longitude out of bounds"),
327 });
328 }
329 let dir = if received_lon > 0x8000_0000 { "E" } else { "W" };
330 parse_loc_rdata_coordinates(received_lon, dir)
331 };
332 let altitude = (parse_u32(&mut decoder)? as f64 - 10_000_000.0) / 100.0;
333
334 Ok((
335 Some(format!(
336 "{latitude} {longitude} {altitude:.2}m {size}m {horizontal_precision}m {vertical_precision}m"
337 )),
338 None,
339 ))
340 }
341
342 fn parse_apl_rdata(
343 &mut self,
344 raw_rdata: &[u8],
345 ) -> DnsParserResult<(Option<String>, Option<Vec<u8>>)> {
346 let mut decoder = BinDecoder::new(raw_rdata);
347 let mut apl_rdata = "".to_string();
348 while !decoder.is_empty() {
349 let address_family = parse_u16(&mut decoder)?;
350 let prefix = parse_u8(&mut decoder)?;
351 let mut afd_length = parse_u8(&mut decoder)?;
352 let negation = if afd_length > 127 {
353 afd_length -= 128;
354 "!"
355 } else {
356 ""
357 };
358 let mut address_vec = parse_vec(&mut decoder, afd_length)?;
359 let address = if address_family == 1 {
360 if afd_length < 4 {
361 address_vec.resize(4, 0);
362 }
363 let mut dec = BinDecoder::new(&address_vec);
364 parse_ipv4_address(&mut dec)?
365 } else {
366 if afd_length < 16 {
367 address_vec.resize(16, 0);
368 }
369 let mut dec = BinDecoder::new(&address_vec);
370 parse_ipv6_address(&mut dec)?
371 };
372 write!(apl_rdata, "{negation}{address_family}:{address}/{prefix}")
373 .expect("can always write to String");
374 apl_rdata.push(' ');
375 }
376 Ok((Some(apl_rdata.trim_end().to_string()), None))
377 }
378
379 pub fn format_unknown_rdata(
380 &mut self,
381 code: u16,
382 rdata: &NULL,
383 ) -> DnsParserResult<(Option<String>, Option<Vec<u8>>)> {
384 match code {
385 dns_message::RTYPE_MB => {
386 let options = self.options.clone();
387 let mut decoder = self.get_rdata_decoder_with_raw_message(&rdata.anything);
388 let madname = Self::parse_domain_name(&mut decoder, &options)?;
389 Ok((Some(madname), None))
390 }
391
392 dns_message::RTYPE_MG => {
393 let options = self.options.clone();
394 let mut decoder = self.get_rdata_decoder_with_raw_message(&rdata.anything);
395 let mgname = Self::parse_domain_name(&mut decoder, &options)?;
396 Ok((Some(mgname), None))
397 }
398
399 dns_message::RTYPE_MR => {
400 let options = self.options.clone();
401 let mut decoder = self.get_rdata_decoder_with_raw_message(&rdata.anything);
402 let newname = Self::parse_domain_name(&mut decoder, &options)?;
403 Ok((Some(newname), None))
404 }
405
406 dns_message::RTYPE_WKS => self.parse_wks_rdata(&rdata.anything),
407
408 dns_message::RTYPE_MINFO => {
409 let options = self.options.clone();
410 let mut decoder = self.get_rdata_decoder_with_raw_message(&rdata.anything);
411 let rmailbx = Self::parse_domain_name(&mut decoder, &options)?;
412 let emailbx = Self::parse_domain_name(&mut decoder, &options)?;
413 Ok((Some(format!("{rmailbx} {emailbx}")), None))
414 }
415
416 dns_message::RTYPE_RP => {
417 let options = self.options.clone();
418 let mut decoder = self.get_rdata_decoder_with_raw_message(&rdata.anything);
419 let mbox = Self::parse_domain_name(&mut decoder, &options)?;
420 let txt = Self::parse_domain_name(&mut decoder, &options)?;
421 Ok((Some(format!("{mbox} {txt}")), None))
422 }
423
424 dns_message::RTYPE_AFSDB => {
425 let options = self.options.clone();
426 let mut decoder = self.get_rdata_decoder_with_raw_message(&rdata.anything);
427 let subtype = parse_u16(&mut decoder)?;
428 let hostname = Self::parse_domain_name(&mut decoder, &options)?;
429 Ok((Some(format!("{subtype} {hostname}")), None))
430 }
431
432 dns_message::RTYPE_X25 => {
433 let mut decoder = BinDecoder::new(&rdata.anything);
434 let psdn_address = parse_character_string(&mut decoder)?;
435 Ok((
436 Some(format!(
437 "\"{}\"",
438 escape_string_for_text_representation(psdn_address)
439 )),
440 None,
441 ))
442 }
443
444 dns_message::RTYPE_ISDN => {
445 let mut decoder = BinDecoder::new(&rdata.anything);
446 let address = parse_character_string(&mut decoder)?;
447 if decoder.is_empty() {
448 Ok((
449 Some(format!(
450 "\"{}\"",
451 escape_string_for_text_representation(address)
452 )),
453 None,
454 ))
455 } else {
456 let sub_address = parse_character_string(&mut decoder)?;
457 Ok((
458 Some(format!(
459 "\"{}\" \"{}\"",
460 escape_string_for_text_representation(address),
461 escape_string_for_text_representation(sub_address)
462 )),
463 None,
464 ))
465 }
466 }
467
468 dns_message::RTYPE_RT => {
469 let options = self.options.clone();
470 let mut decoder = self.get_rdata_decoder_with_raw_message(&rdata.anything);
471 let preference = parse_u16(&mut decoder)?;
472 let intermediate_host = Self::parse_domain_name(&mut decoder, &options)?;
473 Ok((Some(format!("{preference} {intermediate_host}")), None))
474 }
475
476 dns_message::RTYPE_NSAP => {
477 let raw_rdata = &rdata.anything;
478 let mut decoder = BinDecoder::new(raw_rdata);
479 let rdata_len = raw_rdata.len() as u16;
480 let nsap_rdata = HEXUPPER.encode(&parse_vec_with_u16_len(&mut decoder, rdata_len)?);
481 Ok((Some(format!("0x{nsap_rdata}")), None))
482 }
483
484 dns_message::RTYPE_PX => {
485 let options = self.options.clone();
486 let mut decoder = self.get_rdata_decoder_with_raw_message(&rdata.anything);
487 let preference = parse_u16(&mut decoder)?;
488 let map822 = Self::parse_domain_name(&mut decoder, &options)?;
489 let mapx400 = Self::parse_domain_name(&mut decoder, &options)?;
490 Ok((Some(format!("{preference} {map822} {mapx400}")), None))
491 }
492
493 dns_message::RTYPE_LOC => self.parse_loc_rdata(&rdata.anything),
494
495 dns_message::RTYPE_KX => {
496 let options = self.options.clone();
497 let mut decoder = self.get_rdata_decoder_with_raw_message(&rdata.anything);
498 let preference = parse_u16(&mut decoder)?;
499 let exchanger = Self::parse_domain_name(&mut decoder, &options)?;
500 Ok((Some(format!("{preference} {exchanger}")), None))
501 }
502
503 dns_message::RTYPE_A6 => self.parse_a6_rdata(&rdata.anything),
504
505 dns_message::RTYPE_SINK => {
506 let raw_rdata = &rdata.anything;
507 let mut decoder = BinDecoder::new(raw_rdata);
508 let meaning = parse_u8(&mut decoder)?;
509 let coding = parse_u8(&mut decoder)?;
510 let subcoding = parse_u8(&mut decoder)?;
511 let data_len = raw_rdata.len() as u16 - 3;
512 let data = BASE64.encode(&parse_vec_with_u16_len(&mut decoder, data_len)?);
513
514 Ok((Some(format!("{meaning} {coding} {subcoding} {data}")), None))
515 }
516
517 dns_message::RTYPE_APL => self.parse_apl_rdata(&rdata.anything),
518
519 dns_message::RTYPE_DHCID => {
520 let raw_rdata = &rdata.anything;
521 let mut decoder = BinDecoder::new(raw_rdata);
522 let raw_data_len = raw_rdata.len() as u16;
523 let digest = BASE64.encode(&parse_vec_with_u16_len(&mut decoder, raw_data_len)?);
524 Ok((Some(digest), None))
525 }
526
527 dns_message::RTYPE_SPF => {
528 let mut decoder = BinDecoder::new(&rdata.anything);
529 let mut text = String::new();
530 while !decoder.is_empty() {
531 text.push('\"');
532 text.push_str(&parse_character_string(&mut decoder)?);
533 text.push_str("\" ");
534 }
535 Ok((Some(text.trim_end().to_string()), None))
536 }
537
538 _ => Ok((None, Some(rdata.anything.clone()))),
539 }
540 }
541
542 fn format_rdata(&self, rdata: &RData) -> DnsParserResult<(Option<String>, Option<Vec<u8>>)> {
543 match rdata {
544 RData::A(ip) => Ok((Some(ip.to_string()), None)),
545 RData::AAAA(ip) => Ok((Some(ip.to_string()), None)),
546 RData::ANAME(name) => Ok((Some(name.to_string_with_options(&self.options)), None)),
547 RData::CNAME(name) => Ok((Some(name.to_string_with_options(&self.options)), None)),
548 RData::CERT(cert) => {
549 let crl = BASE64.encode(&cert.cert_data);
550 Ok((
551 Some(format!(
552 "{} {} {} {}",
553 u16::from(cert.cert_type),
554 cert.key_tag,
555 cert.algorithm,
556 crl
557 )),
558 None,
559 ))
560 }
561
562 RData::CSYNC(csync) => {
563 let csync_rdata = format!("{csync}");
565 Ok((Some(csync_rdata), None))
566 }
567 RData::MX(mx) => {
568 let srv_rdata = format!(
569 "{} {}",
570 mx.preference,
571 mx.exchange.to_string_with_options(&self.options),
572 );
573 Ok((Some(srv_rdata), None))
574 }
575 RData::NULL(null) => Ok((Some(BASE64.encode(&null.anything)), None)),
576 RData::NS(ns) => Ok((Some(ns.to_string_with_options(&self.options)), None)),
577 RData::OPENPGPKEY(key) => {
578 if let Ok(key_string) = String::from_utf8(key.public_key.clone()) {
579 Ok((Some(format!("({})", &key_string)), None))
580 } else {
581 Err(DnsMessageParserError::SimpleError {
582 cause: String::from("Invalid OPENPGPKEY rdata"),
583 })
584 }
585 }
586 RData::PTR(ptr) => Ok((Some(ptr.to_string_with_options(&self.options)), None)),
587 RData::SOA(soa) => Ok((
588 Some(format!(
589 "{} {} {} {} {} {} {}",
590 soa.mname.to_string_with_options(&self.options),
591 soa.rname.to_string_with_options(&self.options),
592 soa.serial,
593 soa.refresh,
594 soa.retry,
595 soa.expire,
596 soa.minimum
597 )),
598 None,
599 )),
600 RData::SRV(srv) => {
601 let srv_rdata = format!(
602 "{} {} {} {}",
603 srv.priority,
604 srv.weight,
605 srv.port,
606 srv.target.to_string_with_options(&self.options)
607 );
608 Ok((Some(srv_rdata), None))
609 }
610 RData::TXT(txt) => {
611 let txt_rdata = txt
612 .txt_data
613 .iter()
614 .map(|value| {
615 format!(
616 "\"{}\"",
617 escape_string_for_text_representation(
618 String::from_utf8_lossy(value).to_string()
619 )
620 )
621 })
622 .collect::<Vec<String>>()
623 .join(" ");
624 Ok((Some(txt_rdata), None))
625 }
626 RData::CAA(caa) => {
627 let caa_rdata = format!(
628 "{} {} \"{}\"",
629 caa.issuer_critical as u8,
630 &caa.tag,
631 if caa.tag.eq_ignore_ascii_case("iodef") {
632 let url = caa
633 .value_as_iodef()
634 .map_err(|source| DnsMessageParserError::TrustDnsError { source })?;
635 url.as_str().to_string()
636 } else if caa.tag.eq_ignore_ascii_case("issue")
637 || caa.tag.eq_ignore_ascii_case("issuewild")
638 {
639 let (option_name, vec_keyvalue) = caa
640 .value_as_issue()
641 .map_err(|source| DnsMessageParserError::TrustDnsError { source })?;
642
643 let mut final_issuer = String::new();
644 if let Some(name) = option_name {
645 final_issuer.push_str(&name.to_string_with_options(&self.options));
646 for keyvalue in vec_keyvalue.iter() {
647 final_issuer.push_str("; ");
648 final_issuer.push_str(keyvalue.key());
649 final_issuer.push('=');
650 final_issuer.push_str(keyvalue.value());
651 }
652 }
653 final_issuer.trim_end().to_string()
654 } else {
655 std::str::from_utf8(&caa.value)
656 .map_err(|source| DnsMessageParserError::Utf8ParsingError { source })?
657 .to_string()
658 }
659 );
660 Ok((Some(caa_rdata), None))
661 }
662
663 RData::TLSA(tlsa) => {
664 let tlsa_rdata = format!(
665 "{} {} {} {}",
666 u8::from(tlsa.cert_usage),
667 u8::from(tlsa.selector),
668 u8::from(tlsa.matching),
669 HEXUPPER.encode(&tlsa.cert_data)
670 );
671 Ok((Some(tlsa_rdata), None))
672 }
673 RData::SSHFP(sshfp) => {
674 let sshfp_rdata = format!(
675 "{} {} {}",
676 Into::<u8>::into(sshfp.algorithm),
677 Into::<u8>::into(sshfp.fingerprint_type),
678 HEXUPPER.encode(&sshfp.fingerprint)
679 );
680 Ok((Some(sshfp_rdata), None))
681 }
682 RData::NAPTR(naptr) => {
683 let naptr_rdata = format!(
684 r#"{} {} "{}" "{}" "{}" {}"#,
685 naptr.order,
686 naptr.preference,
687 escape_string_for_text_representation(
688 std::str::from_utf8(&naptr.flags)
689 .map_err(|source| DnsMessageParserError::Utf8ParsingError { source })?
690 .to_string()
691 ),
692 escape_string_for_text_representation(
693 std::str::from_utf8(&naptr.services)
694 .map_err(|source| DnsMessageParserError::Utf8ParsingError { source })?
695 .to_string()
696 ),
697 escape_string_for_text_representation(
698 std::str::from_utf8(&naptr.regexp)
699 .map_err(|source| DnsMessageParserError::Utf8ParsingError { source })?
700 .to_string()
701 ),
702 naptr.replacement.to_string_with_options(&self.options)
703 );
704 Ok((Some(naptr_rdata), None))
705 }
706 RData::HINFO(hinfo) => {
707 let hinfo_data = format!(
708 r#""{}" "{}""#,
709 std::str::from_utf8(&hinfo.cpu)
710 .map_err(|source| DnsMessageParserError::Utf8ParsingError { source })?,
711 std::str::from_utf8(&hinfo.os)
712 .map_err(|source| DnsMessageParserError::Utf8ParsingError { source })?,
713 );
714 Ok((Some(hinfo_data), None))
715 }
716 RData::HTTPS(https) => {
717 let https_data = format_svcb_record(&https.0, &self.options);
718 Ok((Some(https_data), None))
719 }
720 RData::SVCB(svcb) => {
721 let svcb_data = format_svcb_record(svcb, &self.options);
722 Ok((Some(svcb_data), None))
723 }
724 RData::OPT(opt) => {
725 let parsed = parse_edns_options(opt)?;
726 let ede_data = parsed.0.iter().map(|entry| EdnsOptionEntry {
727 opt_code: 15u16,
728 opt_name: "EDE".to_string(),
729 opt_data: format!(
730 "EDE={}({}){}",
731 entry.info_code(),
732 entry.purpose().unwrap_or(""),
733 entry.extra_text().unwrap_or("".to_string())
734 ),
735 });
736 let opt_data = parsed
737 .1
738 .into_iter()
739 .chain(ede_data)
740 .map(|entry| format!("{}={}", entry.opt_name, entry.opt_data))
741 .collect::<Vec<String>>()
742 .join(",");
743 Ok((Some(opt_data), None))
744 }
745 RData::DNSSEC(dnssec) => match dnssec {
746 DNSSECRData::CDS(cds) => Ok((Some(format_cds_record(cds)), None)),
749 DNSSECRData::DS(ds) => Ok((Some(format_ds_record(ds)), None)),
750 DNSSECRData::CDNSKEY(cdnskey) => Ok((Some(format_cdnskey_record(cdnskey)), None)),
751 DNSSECRData::DNSKEY(dnskey) => Ok((Some(format_dnskey_record(dnskey)), None)),
752 DNSSECRData::NSEC(nsec) => {
753 let nsec_rdata = format!(
754 "{} {}",
755 nsec.next_domain_name()
756 .to_string_with_options(&self.options),
757 nsec.type_bit_maps()
758 .flat_map(format_record_type)
759 .collect::<Vec<String>>()
760 .join(" ")
761 );
762 Ok((Some(nsec_rdata), None))
763 }
764 DNSSECRData::NSEC3(nsec3) => {
765 let nsec3_rdata = format!(
766 "{} {} {} {} {} {}",
767 u8::from(nsec3.hash_algorithm()),
768 nsec3.opt_out() as u8,
769 nsec3.iterations(),
770 HEXUPPER.encode(nsec3.salt()),
771 BASE32HEX_NOPAD.encode(nsec3.next_hashed_owner_name()),
772 nsec3
773 .type_bit_maps()
774 .flat_map(format_record_type)
775 .collect::<Vec<String>>()
776 .join(" ")
777 );
778 Ok((Some(nsec3_rdata), None))
779 }
780 DNSSECRData::NSEC3PARAM(nsec3param) => {
781 let nsec3param_rdata = format!(
782 "{} {} {} {}",
783 u8::from(nsec3param.hash_algorithm()),
784 nsec3param.opt_out() as u8,
785 nsec3param.iterations(),
786 HEXUPPER.encode(nsec3param.salt()),
787 );
788 Ok((Some(nsec3param_rdata), None))
789 }
790
791 DNSSECRData::SIG(sig) => {
792 let sig_rdata = format!(
793 "{} {} {} {} {} {} {} {} {}",
794 match format_record_type(sig.input().type_covered) {
795 Some(record_type) => record_type,
796 None => String::from("Unknown record type"),
797 },
798 u8::from(sig.input().algorithm),
799 sig.input().num_labels,
800 sig.input().original_ttl,
801 sig.input().sig_expiration.get(), sig.input().sig_inception.get(), sig.input().key_tag,
804 sig.input()
805 .signer_name
806 .to_string_with_options(&self.options),
807 BASE64.encode(sig.sig())
808 );
809 Ok((Some(sig_rdata), None))
810 }
811 DNSSECRData::RRSIG(sig) => {
814 let sig_rdata = format!(
815 "{} {} {} {} {} {} {} {} {}",
816 match format_record_type(sig.input().type_covered) {
817 Some(record_type) => record_type,
818 None => String::from("Unknown record type"),
819 },
820 u8::from(sig.input().algorithm),
821 sig.input().num_labels,
822 sig.input().original_ttl,
823 sig.input().sig_expiration.get(), sig.input().sig_inception.get(), sig.input().key_tag,
826 sig.input()
827 .signer_name
828 .to_string_with_options(&self.options),
829 BASE64.encode(sig.sig())
830 );
831 Ok((Some(sig_rdata), None))
832 }
833 DNSSECRData::KEY(key) => {
834 let key_rdata = format!(
835 "{} {} {} {}",
836 key.flags(),
837 u8::from(key.protocol()),
838 u8::from(key.algorithm()),
839 BASE64.encode(key.public_key())
840 );
841 Ok((Some(key_rdata), None))
842 }
843 DNSSECRData::Unknown { code: _, rdata } => Ok((None, Some(rdata.anything.clone()))),
844 _ => Err(DnsMessageParserError::SimpleError {
845 cause: format!("Unsupported rdata {rdata:?}"),
846 }),
847 },
848 _ => Err(DnsMessageParserError::SimpleError {
849 cause: format!("Unsupported rdata {rdata:?}"),
850 }),
851 }
852 }
853
854 fn parse_domain_name(
855 decoder: &mut BinDecoder<'_>,
856 options: &DnsParserOptions,
857 ) -> DnsParserResult<String> {
858 parse_domain_name(decoder).map(|n| n.to_string_with_options(options))
859 }
860}
861
862fn format_record_type(record_type: RecordType) -> Option<String> {
863 match record_type {
864 RecordType::Unknown(code) => parse_unknown_record_type(code),
865 _ => Some(record_type.to_string()),
866 }
867}
868
869fn format_svcb_record(svcb: &SVCB, options: &DnsParserOptions) -> String {
870 format!(
871 "{} {} {}",
872 svcb.svc_priority,
873 svcb.target_name.to_string_with_options(options),
874 svcb.svc_params
875 .iter()
876 .map(|(key, value)| format!(r#"{}="{}""#, key, value.to_string().trim_end_matches(',')))
877 .collect::<Vec<_>>()
878 .join(" ")
879 )
880}
881
882fn format_cdnskey_record(cdnskey: &CDNSKEY) -> String {
883 format!(
884 "{} 3 {} {}",
885 {
886 if cdnskey.revoke() {
887 0b0000_0000_0000_0000
888 } else if cdnskey.zone_key() && cdnskey.secure_entry_point() {
889 0b0000_0001_0000_0001
890 } else {
891 0b0000_0001_0000_0000
892 }
893 },
894 cdnskey.algorithm().map_or(0, u8::from),
895 cdnskey
896 .public_key()
897 .map_or("".to_string(), |k| BASE64.encode(k.public_bytes()))
898 )
899}
900
901fn format_dnskey_record(dnskey: &DNSKEY) -> String {
902 format!(
903 "{} 3 {} {}",
904 {
905 if dnskey.revoke() {
906 0b0000_0000_0000_0000
907 } else if dnskey.zone_key() && dnskey.secure_entry_point() {
908 0b0000_0001_0000_0001
909 } else {
910 0b0000_0001_0000_0000
911 }
912 },
913 u8::from(dnskey.algorithm()),
914 BASE64.encode(dnskey.public_key().public_bytes())
915 )
916}
917
918fn format_cds_record(cds: &CDS) -> String {
919 format!(
920 "{} {} {} {}",
921 cds.key_tag(),
922 cds.algorithm().map_or(0, u8::from),
923 u8::from(cds.digest_type()),
924 HEXUPPER.encode(cds.digest())
925 )
926}
927
928fn format_ds_record(ds: &DS) -> String {
929 format!(
930 "{} {} {} {}",
931 ds.key_tag(),
932 u8::from(ds.algorithm()),
933 u8::from(ds.digest_type()),
934 HEXUPPER.encode(ds.digest())
935 )
936}
937
938fn parse_response_code(rcode: u16) -> Option<&'static str> {
939 match rcode {
940 0 => Some("NoError"), 1 => Some("FormErr"), 2 => Some("ServFail"), 3 => Some("NXDomain"), 4 => Some("NotImp"), 5 => Some("Refused"), 6 => Some("YXDomain"), 7 => Some("YXRRSet"), 8 => Some("NXRRSet"), 9 => Some("NotAuth"), 10 => Some("NotZone"), 16 => Some("BADVERS"), 17 => Some("BADKEY"), 18 => Some("BADTIME"), 19 => Some("BADMODE"), 20 => Some("BADNAME"), 21 => Some("BADALG"), 22 => Some("BADTRUNC"), 23 => Some("BADCOOKIE"), _ => None,
962 }
963}
964
965fn parse_dns_query_message_header(dns_message: &TrustDnsMessage) -> QueryHeader {
966 QueryHeader {
967 id: dns_message.id,
968 opcode: dns_message.op_code.into(),
969 rcode: dns_message.response_code,
970 qr: dns_message.message_type as u8,
971 aa: dns_message.authoritative,
972 tc: dns_message.truncation,
973 rd: dns_message.recursion_desired,
974 ra: dns_message.recursion_available,
975 ad: dns_message.authentic_data,
976 cd: dns_message.checking_disabled,
977 question_count: dns_message.queries.len() as u16,
978 answer_count: dns_message.answers.len() as u16,
979 authority_count: dns_message.authorities.len() as u16,
980 additional_count: dns_message.additionals.len() as u16 + dns_message.edns.is_some() as u16,
981 }
982}
983
984fn parse_dns_update_message_header(dns_message: &TrustDnsMessage) -> UpdateHeader {
985 UpdateHeader {
986 id: dns_message.id,
987 opcode: dns_message.op_code.into(),
988 rcode: dns_message.response_code,
989 qr: dns_message.message_type as u8,
990 zone_count: dns_message.queries.len() as u16,
991 prerequisite_count: dns_message.answers.len() as u16,
992 update_count: dns_message.authorities.len() as u16,
993 additional_count: dns_message.additionals.len() as u16 + dns_message.edns.is_some() as u16,
994 }
995}
996
997fn parse_edns(dns_message: &TrustDnsMessage) -> Option<DnsParserResult<OptPseudoSection>> {
998 dns_message.edns.as_ref().map(|edns| {
999 parse_edns_options(edns.options()).map(|(ede, rest)| OptPseudoSection {
1000 extended_rcode: edns.rcode_high(),
1001 version: edns.version(),
1002 dnssec_ok: edns.flags().dnssec_ok,
1003 udp_max_payload_size: edns.max_payload(),
1004 ede,
1005 options: rest,
1006 })
1007 })
1008}
1009
1010fn parse_edns_options(edns: &OPT) -> DnsParserResult<(Vec<EDE>, Vec<EdnsOptionEntry>)> {
1011 let ede_opts: Vec<EDE> = edns
1012 .as_ref()
1013 .iter()
1014 .filter_map(|(_, option)| {
1015 if let EdnsOption::Unknown(EDE_OPTION_CODE, option) = option {
1016 Some(EDE::from_bytes(option).map_err(|source| {
1017 DnsMessageParserError::TrustDnsError {
1018 source: ProtoError::from(source),
1019 }
1020 }))
1021 } else {
1022 None
1023 }
1024 })
1025 .collect::<Result<Vec<EDE>, DnsMessageParserError>>()?;
1026
1027 let rest: Vec<EdnsOptionEntry> = edns
1028 .as_ref()
1029 .iter()
1030 .filter(|(code, _)| u16::from(*code) != EDE_OPTION_CODE)
1031 .map(|(code, option)| match option {
1032 EdnsOption::DAU(algorithms) => Ok(parse_edns_opt_dnssec_algorithms(*code, *algorithms)),
1033 EdnsOption::Unknown(_, opt_data) => Ok(parse_edns_opt(*code, opt_data)),
1034 option => Vec::<u8>::try_from(option)
1035 .map(|bytes| parse_edns_opt(*code, &bytes))
1036 .map_err(|source| DnsMessageParserError::TrustDnsError { source }),
1037 })
1038 .collect::<Result<Vec<EdnsOptionEntry>, DnsMessageParserError>>()?;
1039
1040 Ok((ede_opts, rest))
1041}
1042
1043fn parse_edns_opt_dnssec_algorithms(
1044 opt_code: EdnsCode,
1045 algorithms: SupportedAlgorithms,
1046) -> EdnsOptionEntry {
1047 let algorithm_names: Vec<String> = algorithms.iter().map(|alg| alg.to_string()).collect();
1048 EdnsOptionEntry {
1049 opt_code: Into::<u16>::into(opt_code),
1050 opt_name: format!("{opt_code:?}"),
1051 opt_data: algorithm_names.join(" "),
1052 }
1053}
1054
1055fn parse_edns_opt(opt_code: EdnsCode, opt_data: &[u8]) -> EdnsOptionEntry {
1056 EdnsOptionEntry {
1057 opt_code: Into::<u16>::into(opt_code),
1058 opt_name: format!("{opt_code:?}"),
1059 opt_data: BASE64.encode(opt_data),
1060 }
1061}
1062
1063fn parse_loc_rdata_size(data: u8) -> DnsParserResult<f64> {
1064 let base = (data & 0xF0) >> 4;
1065 if base > 9 {
1066 return Err(DnsMessageParserError::SimpleError {
1067 cause: format!("The base shouldn't be greater than 9. Base: {base}"),
1068 });
1069 }
1070
1071 let exponent = data & 0x0F;
1072 if exponent > 9 {
1073 return Err(DnsMessageParserError::SimpleError {
1074 cause: format!("The exponent shouldn't be greater than 9. Exponent: {exponent}"),
1075 });
1076 }
1077
1078 let ten: u64 = 10;
1079 let ans = (base as f64) * ten.pow(exponent as u32) as f64;
1080 Ok(ans / 100.0) }
1082
1083fn parse_loc_rdata_coordinates(coordinates: u32, dir: &str) -> String {
1084 let degree = (coordinates as i64 - 0x8000_0000) as f64 / 3_600_000.00;
1085 let minute = degree.fract() * 60.0;
1086 let second = minute.fract() * 60.0;
1087
1088 format!(
1089 "{} {} {:.3} {}",
1090 degree.trunc().abs(),
1091 minute.trunc().abs(),
1092 second.abs(),
1093 dir
1094 )
1095}
1096
1097fn parse_character_string(decoder: &mut BinDecoder<'_>) -> DnsParserResult<String> {
1098 let raw_len = decoder
1099 .read_u8()
1100 .map_err(|source| DnsMessageParserError::TrustDnsError {
1101 source: ProtoError::from(source),
1102 })?;
1103 let len = raw_len.unverified() as usize;
1104 let raw_text =
1105 decoder
1106 .read_slice(len)
1107 .map_err(|source| DnsMessageParserError::TrustDnsError {
1108 source: ProtoError::from(source),
1109 })?;
1110 match raw_text.verify_unwrap(|r| r.len() == len) {
1111 Ok(verified_text) => Ok(String::from_utf8_lossy(verified_text).to_string()),
1112 Err(raw_data) => Err(DnsMessageParserError::SimpleError {
1113 cause: format!(
1114 "Unexpected data length: expected {}, got {}. Raw data {}",
1115 len,
1116 raw_data.len(),
1117 format_bytes_as_hex_string(raw_data)
1118 ),
1119 }),
1120 }
1121}
1122
1123fn parse_u8(decoder: &mut BinDecoder<'_>) -> DnsParserResult<u8> {
1124 Ok(decoder
1125 .read_u8()
1126 .map_err(|source| DnsMessageParserError::TrustDnsError {
1127 source: ProtoError::from(source),
1128 })?
1129 .unverified())
1130}
1131
1132fn parse_u16(decoder: &mut BinDecoder<'_>) -> DnsParserResult<u16> {
1133 Ok(decoder
1134 .read_u16()
1135 .map_err(|source| DnsMessageParserError::TrustDnsError {
1136 source: ProtoError::from(source),
1137 })?
1138 .unverified())
1139}
1140
1141fn parse_u32(decoder: &mut BinDecoder<'_>) -> DnsParserResult<u32> {
1142 Ok(decoder
1143 .read_u32()
1144 .map_err(|source| DnsMessageParserError::TrustDnsError {
1145 source: ProtoError::from(source),
1146 })?
1147 .unverified())
1148}
1149
1150fn parse_vec(decoder: &mut BinDecoder<'_>, buffer_len: u8) -> DnsParserResult<Vec<u8>> {
1151 let len = buffer_len as usize;
1152 Ok(decoder
1153 .read_vec(len)
1154 .map_err(|source| DnsMessageParserError::TrustDnsError {
1155 source: ProtoError::from(source),
1156 })?
1157 .unverified())
1158}
1159
1160fn parse_vec_with_u16_len(
1161 decoder: &mut BinDecoder<'_>,
1162 buffer_len: u16,
1163) -> DnsParserResult<Vec<u8>> {
1164 let len = buffer_len as usize;
1165 Ok(decoder
1166 .read_vec(len)
1167 .map_err(|source| DnsMessageParserError::TrustDnsError {
1168 source: ProtoError::from(source),
1169 })?
1170 .unverified())
1171}
1172
1173fn parse_ipv6_address(decoder: &mut BinDecoder<'_>) -> DnsParserResult<String> {
1174 Ok(<AAAA as BinDecodable>::read(decoder)
1175 .map_err(|source| DnsMessageParserError::TrustDnsError {
1176 source: ProtoError::from(source),
1177 })?
1178 .to_string())
1179}
1180
1181fn parse_ipv4_address(decoder: &mut BinDecoder<'_>) -> DnsParserResult<String> {
1182 Ok(<A as BinDecodable>::read(decoder)
1183 .map_err(|source| DnsMessageParserError::TrustDnsError {
1184 source: ProtoError::from(source),
1185 })?
1186 .to_string())
1187}
1188
1189fn parse_domain_name(decoder: &mut BinDecoder<'_>) -> DnsParserResult<Name> {
1190 Name::read(decoder).map_err(|source| DnsMessageParserError::TrustDnsError {
1191 source: ProtoError::from(source),
1192 })
1193}
1194
1195fn escape_string_for_text_representation(original_string: String) -> String {
1196 original_string.replace('\\', "\\\\").replace('\"', "\\\"")
1197}
1198
1199fn parse_unknown_record_type(rtype: u16) -> Option<String> {
1200 match rtype {
1201 1 => Some(String::from("A")),
1202 2 => Some(String::from("NS")),
1203 3 => Some(String::from("MD")),
1204 4 => Some(String::from("MF")),
1205 5 => Some(String::from("CNAME")),
1206 6 => Some(String::from("SOA")),
1207 7 => Some(String::from("MB")),
1208 8 => Some(String::from("MG")),
1209 9 => Some(String::from("MR")),
1210 10 => Some(String::from("NULL")),
1211 11 => Some(String::from("WKS")),
1212 12 => Some(String::from("PTR")),
1213 13 => Some(String::from("HINFO")),
1214 14 => Some(String::from("MINFO")),
1215 15 => Some(String::from("MX")),
1216 16 => Some(String::from("TXT")),
1217 17 => Some(String::from("RP")),
1218 18 => Some(String::from("AFSDB")),
1219 19 => Some(String::from("X25")),
1220 20 => Some(String::from("ISDN")),
1221 21 => Some(String::from("RT")),
1222 22 => Some(String::from("NSAP")),
1223 23 => Some(String::from("NSAP-PTR")),
1224 24 => Some(String::from("SIG")),
1225 25 => Some(String::from("KEY")),
1226 26 => Some(String::from("PX")),
1227 27 => Some(String::from("GPOS")),
1228 28 => Some(String::from("AAAA")),
1229 29 => Some(String::from("LOC")),
1230 30 => Some(String::from("NXT")),
1231 31 => Some(String::from("EID")),
1232 32 => Some(String::from("NIMLOC")),
1233 33 => Some(String::from("SRV")),
1234 34 => Some(String::from("ATMA")),
1235 35 => Some(String::from("NAPTR")),
1236 36 => Some(String::from("KX")),
1237 37 => Some(String::from("CERT")),
1238 38 => Some(String::from("A6")),
1239 39 => Some(String::from("DNAME")),
1240 40 => Some(String::from("SINK")),
1241 41 => Some(String::from("OPT")),
1242 42 => Some(String::from("APL")),
1243 43 => Some(String::from("DS")),
1244 44 => Some(String::from("SSHFP")),
1245 45 => Some(String::from("IPSECKEY")),
1246 46 => Some(String::from("RRSIG")),
1247 47 => Some(String::from("NSEC")),
1248 48 => Some(String::from("DNSKEY")),
1249 49 => Some(String::from("DHCID")),
1250 50 => Some(String::from("NSEC3")),
1251 51 => Some(String::from("NSEC3PARAM")),
1252 52 => Some(String::from("TLSA")),
1253 53 => Some(String::from("SMIMEA")),
1254 55 => Some(String::from("HIP")),
1255 56 => Some(String::from("NINFO")),
1256 57 => Some(String::from("RKEY")),
1257 58 => Some(String::from("TALINK")),
1258 59 => Some(String::from("CDS")),
1259 60 => Some(String::from("CDNSKEY")),
1260 61 => Some(String::from("OPENPGPKEY")),
1261 62 => Some(String::from("CSYNC")),
1262 63 => Some(String::from("ZONEMD")),
1263 99 => Some(String::from("SPF")),
1264 100 => Some(String::from("UINFO")),
1265 101 => Some(String::from("UID")),
1266 102 => Some(String::from("GID")),
1267 103 => Some(String::from("UNSPEC")),
1268 104 => Some(String::from("NID")),
1269 105 => Some(String::from("L32")),
1270 106 => Some(String::from("L64")),
1271 107 => Some(String::from("LP")),
1272 108 => Some(String::from("EUI48")),
1273 109 => Some(String::from("EUI64")),
1274 249 => Some(String::from("TKEY")),
1275 250 => Some(String::from("TSIG")),
1276 251 => Some(String::from("IXFR")),
1277 252 => Some(String::from("AXFR")),
1278 253 => Some(String::from("MAILB")),
1279 254 => Some(String::from("MAILA")),
1280 255 => Some(String::from("ANY")),
1281 256 => Some(String::from("URI")),
1282 257 => Some(String::from("CAA")),
1283 258 => Some(String::from("AVC")),
1284 259 => Some(String::from("DOA")),
1285 260 => Some(String::from("AMTRELAY")),
1286 32768 => Some(String::from("TA")),
1287 32769 => Some(String::from("DLV")),
1288
1289 _ => None,
1290 }
1291}
1292
1293fn format_bytes_as_hex_string(bytes: &[u8]) -> String {
1294 bytes
1295 .iter()
1296 .map(|e| format!("{e:02X}"))
1297 .collect::<Vec<String>>()
1298 .join(".")
1299}
1300
1301#[cfg(test)]
1302mod tests {
1303 use std::{
1304 net::{Ipv4Addr, Ipv6Addr},
1305 str::FromStr,
1306 };
1307
1308 #[allow(deprecated)]
1309 use hickory_proto::dnssec::rdata::key::UpdateScope;
1310 use hickory_proto::{
1311 dnssec::{
1312 Algorithm as DNSSEC_Algorithm, DigestType, Nsec3HashAlgorithm, PublicKeyBuf,
1313 rdata::{
1314 KEY, NSEC, NSEC3, NSEC3PARAM, RRSIG,
1315 key::{KeyTrust, KeyUsage, Protocol},
1316 sig::SigInput,
1317 },
1318 },
1319 rr::{
1320 SerialNumber,
1321 domain::Name,
1322 rdata::{
1323 CAA, CERT, CSYNC, HINFO, HTTPS, NAPTR, OPT, SSHFP, TLSA, TXT,
1324 caa::KeyValue,
1325 cert::{Algorithm as CertAlgorithm, CertType},
1326 sshfp::{Algorithm, FingerprintType},
1327 svcb,
1328 tlsa::{CertUsage, Matching, Selector},
1329 },
1330 },
1331 serialize::binary::Restrict,
1332 };
1333
1334 use super::*;
1335
1336 impl DnsMessageParser {
1337 pub fn raw_message_for_rdata_parsing(&self) -> Option<&Vec<u8>> {
1338 self.raw_message_for_rdata_parsing.as_ref()
1339 }
1340 }
1341
1342 fn format_rdata(rdata: &RData) -> DnsParserResult<(Option<String>, Option<Vec<u8>>)> {
1343 DnsMessageParser::new(Vec::new()).format_rdata(rdata)
1344 }
1345
1346 fn format_rdata_with_options(
1347 rdata: &RData,
1348 options: DnsParserOptions,
1349 ) -> DnsParserResult<(Option<String>, Option<Vec<u8>>)> {
1350 DnsMessageParser::with_options(Vec::new(), options).format_rdata(rdata)
1351 }
1352
1353 #[test]
1354 fn test_parse_as_query_message() {
1355 let raw_dns_message = "szgAAAABAAAAAAAAAmg1B2V4YW1wbGUDY29tAAAGAAE=";
1356 let raw_query_message = BASE64
1357 .decode(raw_dns_message.as_bytes())
1358 .expect("Invalid base64 encoded data.");
1359 let parse_result = DnsMessageParser::new(raw_query_message).parse_as_query_message();
1360 assert!(parse_result.is_ok());
1361 let message = parse_result.expect("Message is not parsed.");
1362 assert_eq!(message.header.qr, 0);
1363 assert_eq!(message.question_section.len(), 1);
1364 assert_eq!(
1365 message.question_section.first().unwrap().name,
1366 "h5.example.com."
1367 );
1368 assert_eq!(
1369 &message
1370 .question_section
1371 .first()
1372 .unwrap()
1373 .record_type
1374 .clone()
1375 .unwrap(),
1376 "SOA"
1377 );
1378 }
1379
1380 #[test]
1381 fn test_parse_as_query_message_with_ede() {
1382 let raw_dns_message =
1383 "szgAAAABAAAAAAABAmg1B2V4YW1wbGUDY29tAAAGAAEAACkE0AEBQAAABgAPAAIAFQ==";
1384 let raw_query_message = BASE64
1385 .decode(raw_dns_message.as_bytes())
1386 .expect("Invalid base64 encoded data.");
1387 let parse_result = DnsMessageParser::new(raw_query_message).parse_as_query_message();
1388 assert!(parse_result.is_ok());
1389 let message = parse_result.expect("Message is not parsed.");
1390 let opt_pseudo_section = message.opt_pseudo_section.expect("OPT section was missing");
1391 assert_eq!(opt_pseudo_section.ede.len(), 1);
1392 assert_eq!(opt_pseudo_section.ede[0].info_code(), 21u16);
1393 assert_eq!(opt_pseudo_section.ede[0].purpose(), Some("Not Supported"));
1394 assert_eq!(opt_pseudo_section.ede[0].extra_text(), None);
1395 }
1396
1397 #[test]
1398 fn test_parse_as_query_message_with_ede_with_extra_text() {
1399 let raw_dns_message = "szgAAAABAAAAAAABAmg1B2V4YW1wbGUDY29tAAAGAAEAACkE0AEBQAAAOQAPADUACW5vIFNFUCBtYXRjaGluZyB0aGUgRFMgZm91bmQgZm9yIGRuc3NlYy1mYWlsZWQub3JnLg==";
1400 let raw_query_message = BASE64
1401 .decode(raw_dns_message.as_bytes())
1402 .expect("Invalid base64 encoded data.");
1403 let parse_result = DnsMessageParser::new(raw_query_message).parse_as_query_message();
1404 assert!(parse_result.is_ok());
1405 let message = parse_result.expect("Message is not parsed.");
1406 let opt_pseudo_section = message.opt_pseudo_section.expect("OPT section was missing");
1407 assert_eq!(opt_pseudo_section.ede.len(), 1);
1408 assert_eq!(opt_pseudo_section.ede[0].info_code(), 9u16);
1409 assert_eq!(opt_pseudo_section.ede[0].purpose(), Some("DNSKEY Missing"));
1410 assert_eq!(
1411 opt_pseudo_section.ede[0].extra_text(),
1412 Some("no SEP matching the DS found for dnssec-failed.org.".to_string())
1413 );
1414 }
1415
1416 #[test]
1417 fn test_parse_as_query_message_with_multiple_ede() {
1418 let raw_dns_message =
1419 "szgAAAABAAAAAAABAmg1B2V4YW1wbGUDY29tAAAGAAEAACkAAAEBQAAADAAPAAIAFQAPAAIAFA==";
1420 let raw_query_message = BASE64
1421 .decode(raw_dns_message.as_bytes())
1422 .expect("Invalid base64 encoded data.");
1423 let parse_result = DnsMessageParser::new(raw_query_message).parse_as_query_message();
1424 assert!(parse_result.is_ok());
1425 let message = parse_result.expect("Message is not parsed.");
1426 let opt_pseudo_section = message.opt_pseudo_section.expect("OPT section was missing");
1427 assert_eq!(opt_pseudo_section.ede.len(), 2);
1428 assert_eq!(opt_pseudo_section.ede[0].info_code(), 21u16);
1429 assert_eq!(opt_pseudo_section.ede[0].purpose(), Some("Not Supported"));
1430 assert_eq!(opt_pseudo_section.ede[0].extra_text(), None);
1431 assert_eq!(opt_pseudo_section.ede[1].info_code(), 20u16);
1432 assert_eq!(
1433 opt_pseudo_section.ede[1].purpose(),
1434 Some("Not Authoritative")
1435 );
1436 assert_eq!(opt_pseudo_section.ede[1].extra_text(), None);
1437 }
1438
1439 #[test]
1440 fn test_parse_as_query_message_with_invalid_data() {
1441 let err = DnsMessageParser::new(vec![1, 2, 3])
1442 .parse_as_query_message()
1443 .expect_err("Expected TrustDnsError.");
1444 match err {
1445 DnsMessageParserError::TrustDnsError { source: e } => {
1446 assert_eq!(
1447 e.to_string(),
1448 "decoding error: unexpected end of input reached"
1449 )
1450 }
1451 DnsMessageParserError::SimpleError { cause: e } => {
1452 panic!("Expected TrustDnsError, got {}.", &e)
1453 }
1454 _ => panic!("{err}."),
1455 }
1456 }
1457
1458 #[test]
1459 fn test_parse_as_query_message_with_unsupported_rdata() {
1460 let raw_query_message_base64 = "eEaFgAABAAEAAAAABGRvYTEHZXhhbXBsZQNjb20AAQMAAcAMAQMAAQAADhAAIAAAAAAAAAAAAgIiImh0dHBzOi8vd3d3LmlzYy5vcmcv";
1461 let raw_query_message = BASE64
1462 .decode(raw_query_message_base64.as_bytes())
1463 .expect("Invalid base64 encoded data.");
1464 let dns_query_message = DnsMessageParser::new(raw_query_message)
1465 .parse_as_query_message()
1466 .expect("Invalid DNS query message.");
1467 assert_eq!(dns_query_message.answer_section[0].rdata, None);
1468 assert_ne!(dns_query_message.answer_section[0].rdata_bytes, None);
1469 }
1470
1471 #[test]
1472 fn test_parse_response_with_https_rdata() {
1473 let raw_response_message_base64 = "Oe2BgAABAAEAAAABBGNkbnAHc2FuamFnaANjb20AAEEAAcAMAEEAAQAAASwAPQABAAABAAYCaDMCaDIABAAIrEDEHKxAxRwABgAgJgZHAADmAAAAAAAArEDEHCYGRwAA5gAAAAAAAKxAxRwAACkE0AAAAAAAHAAKABjWOVAgEGik/gEAAABlwiAuXkvEOviB1sk=";
1474 let raw_response_message = BASE64
1475 .decode(raw_response_message_base64.as_bytes())
1476 .expect("Invalid base64 encoded data.");
1477 let dns_response_message = DnsMessageParser::new(raw_response_message)
1478 .parse_as_query_message()
1479 .expect("Invalid DNS query message.");
1480 assert_eq!(
1481 dns_response_message.answer_section[0].rdata,
1482 Some(r#"1 . alpn="h3,h2" ipv4hint="172.64.196.28,172.64.197.28" ipv6hint="2606:4700:e6::ac40:c41c,2606:4700:e6::ac40:c51c""#.to_string())
1483 );
1484 assert_eq!(dns_response_message.answer_section[0].record_type_id, 65u16);
1485 assert_eq!(dns_response_message.answer_section[0].rdata_bytes, None);
1486 }
1487
1488 #[test]
1489 fn test_parse_response_with_hinfo_rdata() {
1490 let raw_response_message_base64 =
1491 "wS2BgAABAAEAAAAAB3RyYWNrZXIEZGxlcgNvcmcAAP8AAcAMAA0AAQAAC64ACQdSRkM4NDgyAA==";
1492 let raw_response_message = BASE64
1493 .decode(raw_response_message_base64.as_bytes())
1494 .expect("Invalid base64 encoded data.");
1495 let dns_response_message = DnsMessageParser::new(raw_response_message)
1496 .parse_as_query_message()
1497 .expect("Invalid DNS query message.");
1498 assert_eq!(
1499 dns_response_message.answer_section[0].rdata,
1500 Some(r#""RFC8482" """#.to_string())
1501 );
1502 assert_eq!(dns_response_message.answer_section[0].record_type_id, 13u16);
1503 assert_eq!(dns_response_message.answer_section[0].rdata_bytes, None);
1504 }
1505
1506 #[test]
1507 fn test_format_bytes_as_hex_string() {
1508 assert_eq!(
1509 "01.02.03.AB.CD.EF",
1510 &format_bytes_as_hex_string(&[1, 2, 3, 0xab, 0xcd, 0xef])
1511 );
1512 }
1513
1514 #[test]
1515 fn test_parse_unknown_record_type() {
1516 assert_eq!("A", parse_unknown_record_type(1).unwrap());
1517 assert_eq!("ANY", parse_unknown_record_type(255).unwrap());
1518 assert!(parse_unknown_record_type(22222).is_none());
1519 }
1520
1521 #[test]
1522 fn test_parse_as_update_message_failure() {
1523 let raw_dns_message = "ChVqYW1lcy1WaXJ0dWFsLU1hY2hpbmUSC0JJTkQgOS4xNi4zcq0ICAQQARgBIgSs\
1524 FDetKgTAN1MeMMn/Ajg1QL6m6fcFTQLEKhVS+QMSSIIAAAEAAAAFAAUJZmFjZWJvb2sxA2NvbQAAAQABwAwAAgABAAKjA\
1525 AAPA25zMQhyZW50b25kY8AWwAwAAgABAAKjAAAGA25zMsAvIENLMFBPSk1HODc0TEpSRUY3RUZOODQzMFFWSVQ4QlNNwB\
1526 YAMgABAAFRgAAjAQEAAAAUZQGgwlcg7hVvbE45Y2s62gMS2SoAByIAAAAAApDATAAuAAEAAVGAALcAMggCAAFRgF8ACGF\
1527 e9r15m6QDY29tAFOih16McCzogcR6RZIu3kqZa27Bo1jtfzwzDENJIZItSCRuLqRO6oA90sCLItOEQv0skpQKtJQXmTZU\
1528 nqe3XK+1t/Op8G9cmeMXgCvynTJmm0WouSv+SuwBOjgqCaNuWpwbiIcaXY/NlId1lPpl8LJyTIRtFqGifW0FnYFe/Lzs3\
1529 pfZLoKMAG4/8Upqqv4F+Ij1oue1C6KWe0hn+beIKkIgN0pLMjVFTUhITThBMDFNTzBBRVFRTjdHMlVQSjI4NjfAFgAyAA\
1530 EAAVGAACIBAQAAABQ86ELf24DH1kAfgQ4dyyuf0+6y5wAGIAAAAAASwCsAAQABAAKjAAAEbD0TCsArAAEAAQACowAABKx\
1531 iwCLARgABAAEAAqMAAAQuprYzwEYAAQABAAKjAAAEXXMcaAAAKRAAAACAAAAAWgUDY29tAGC+pun3BW2/LUQYcvkDEkiC\
1532 AAABAAAABQAFCWZhY2Vib29rMQNjb20AAAEAAcAMAAIAAQACowAADwNuczEIcmVudG9uZGPAFsAMAAIAAQACowAABgNuc\
1533 zLALyBDSzBQT0pNRzg3NExKUkVGN0VGTjg0MzBRVklUOEJTTcAWADIAAQABUYAAIwEBAAAAFGUBoMJXIO4Vb2xOOWNrOt\
1534 oDEtkqAAciAAAAAAKQwEwALgABAAFRgAC3ADIIAgABUYBfAAhhXva9eZukA2NvbQBToodejHAs6IHEekWSLt5KmWtuwaN\
1535 Y7X88MwxDSSGSLUgkbi6kTuqAPdLAiyLThEL9LJKUCrSUF5k2VJ6nt1yvtbfzqfBvXJnjF4Ar8p0yZptFqLkr/krsATo4\
1536 KgmjblqcG4iHGl2PzZSHdZT6ZfCyckyEbRahon1tBZ2BXvy87N6X2S6CjABuP/FKaqr+BfiI9aLntQuilntIZ/m3iCpCI\
1537 DdKSzI1RU1ISE04QTAxTU8wQUVRUU43RzJVUEoyODY3wBYAMgABAAFRgAAiAQEAAAAUPOhC39uAx9ZAH4EOHcsrn9Pusu\
1538 cABiAAAAAAEsArAAEAAQACowAABGw9EwrAKwABAAEAAqMAAASsYsAiwEYAAQABAAKjAAAELqa2M8BGAAEAAQACowAABF1\
1539 zHGgAACkQAAAAgAAAAHgB";
1540 let raw_update_message = BASE64
1541 .decode(raw_dns_message.as_bytes())
1542 .expect("Invalid base64 encoded data.");
1543 assert!(
1544 DnsMessageParser::new(raw_update_message)
1545 .parse_as_update_message()
1546 .is_err()
1547 );
1548 }
1549
1550 #[test]
1551 fn test_parse_bad_prefix_value() {
1552 let raw_dns_message = "oAAAMgABAAAAAAABAAABAAAAACYAAC8BAAAAAaAAAAAAAA==";
1554 let raw_query_message = BASE64
1555 .decode(raw_dns_message.as_bytes())
1556 .expect("Invalid base64 encoded data.");
1557 assert!(
1558 DnsMessageParser::new(raw_query_message)
1559 .parse_as_query_message()
1560 .is_err()
1561 );
1562 }
1563
1564 #[test]
1565 fn test_parse_as_update_message() {
1566 let raw_dns_message = "xjUoAAABAAAAAQAAB2V4YW1wbGUDY29tAAAGAAECaDXADAD/AP8AAAAAAAA=";
1567 let raw_update_message = BASE64
1568 .decode(raw_dns_message.as_bytes())
1569 .expect("Invalid base64 encoded data.");
1570 let parse_result = DnsMessageParser::new(raw_update_message).parse_as_update_message();
1571 assert!(parse_result.is_ok());
1572 let message = parse_result.expect("Message is not parsed.");
1573 assert_eq!(message.header.qr, 0);
1574 assert_eq!(message.update_section.len(), 1);
1575 assert_eq!(message.update_section.first().unwrap().class, "ANY");
1576 assert_eq!(&message.zone_to_update.zone_type.clone().unwrap(), "SOA");
1577 assert_eq!(message.zone_to_update.name, "example.com.");
1578 }
1579
1580 #[test]
1581 fn test_parse_loc_rdata_size() {
1582 let data: u8 = 51;
1583 let expected: f64 = 30.0;
1584 assert!((expected - parse_loc_rdata_size(data).unwrap()).abs() < f64::EPSILON);
1585
1586 let data: u8 = 22;
1587 let expected: f64 = 10000.0;
1588 assert!((expected - parse_loc_rdata_size(data).unwrap()).abs() < f64::EPSILON);
1589
1590 let data: u8 = 19;
1591 let expected: f64 = 10.0;
1592 assert!((expected - parse_loc_rdata_size(data).unwrap()).abs() < f64::EPSILON);
1593 }
1594
1595 #[test]
1596 fn test_parse_loc_rdata_coordinates() {
1597 let coordinates: u32 = 2299997648;
1598 let dir = "N";
1599 let expected = String::from("42 21 54.000 N");
1600 assert_eq!(expected, parse_loc_rdata_coordinates(coordinates, dir));
1601
1602 let coordinates: u32 = 1891505648;
1603 let dir = "W";
1604 let expected = String::from("71 6 18.000 W");
1605 assert_eq!(expected, parse_loc_rdata_coordinates(coordinates, dir));
1606 }
1607
1608 #[test]
1609 fn test_format_rdata_for_a_type() {
1610 let rdata = RData::A(Ipv4Addr::from_str("1.2.3.4").unwrap().into());
1611 let rdata_text = format_rdata(&rdata);
1612 assert!(rdata_text.is_ok());
1613 if let Ok((parsed, raw_rdata)) = rdata_text {
1614 assert!(raw_rdata.is_none());
1615 assert_eq!("1.2.3.4", parsed.unwrap());
1616 }
1617 }
1618
1619 #[test]
1620 fn test_format_rdata_for_aaaa_type() {
1621 let rdata = RData::AAAA(Ipv6Addr::from_str("2001::1234").unwrap().into());
1622 let rdata_text = format_rdata(&rdata);
1623 assert!(rdata_text.is_ok());
1624 if let Ok((parsed, raw_rdata)) = rdata_text {
1625 assert!(raw_rdata.is_none());
1626 assert_eq!("2001::1234", parsed.unwrap());
1627 }
1628 }
1629
1630 #[test]
1631 fn test_format_rdata_for_cname_type() {
1632 let rdata = RData::CNAME(hickory_proto::rr::rdata::CNAME(
1633 Name::from_str("www.example.com.").unwrap(),
1634 ));
1635 let rdata_text = format_rdata(&rdata);
1636 assert!(rdata_text.is_ok());
1637 if let Ok((parsed, raw_rdata)) = rdata_text {
1638 assert!(raw_rdata.is_none());
1639 assert_eq!("www.example.com.", parsed.unwrap());
1640 }
1641 }
1642
1643 #[test]
1644 fn test_format_rdata_for_cname_type_downcase() {
1645 let rdata = RData::CNAME(hickory_proto::rr::rdata::CNAME(
1646 Name::from_str("WWW.Example.Com.").unwrap(),
1647 ));
1648 let rdata_text = format_rdata_with_options(
1649 &rdata,
1650 DnsParserOptions {
1651 lowercase_hostnames: true,
1652 },
1653 );
1654 assert!(rdata_text.is_ok());
1655 if let Ok((parsed, raw_rdata)) = rdata_text {
1656 assert!(raw_rdata.is_none());
1657 assert_eq!("www.example.com.", parsed.unwrap());
1658 }
1659 }
1660
1661 #[test]
1662 fn test_format_rdata_for_txt_type() {
1663 let rdata = RData::TXT(TXT::new(vec![
1664 "abc\"def".to_string(),
1665 "gh\\i".to_string(),
1666 "".to_string(),
1667 "j".to_string(),
1668 ]));
1669 let rdata_text = format_rdata(&rdata);
1670 assert!(rdata_text.is_ok());
1671 if let Ok((parsed, raw_rdata)) = rdata_text {
1672 assert!(raw_rdata.is_none());
1673 assert_eq!(r#""abc\"def" "gh\\i" "" "j""#, parsed.unwrap());
1674 }
1675 }
1676
1677 #[test]
1678 fn test_format_rdata_for_caa_type() {
1679 let rdata1 = RData::CAA(CAA::new_issue(
1680 true,
1681 Some(Name::parse("example.com", None).unwrap()),
1682 vec![],
1683 ));
1684 let rdata2 = RData::CAA(CAA::new_issue(
1685 true,
1686 Some(Name::parse("example.com", None).unwrap()),
1687 vec![KeyValue::new("key", "value")],
1688 ));
1689 let rdata_text1 = format_rdata(&rdata1);
1690 let rdata_text2 = format_rdata(&rdata2);
1691
1692 assert!(rdata_text1.is_ok());
1693 assert!(rdata_text2.is_ok());
1694
1695 if let Ok((parsed, raw_rdata)) = rdata_text1 {
1696 assert!(raw_rdata.is_none());
1697 assert_eq!("1 issue \"example.com\"", parsed.unwrap());
1698 }
1699
1700 if let Ok((parsed, raw_rdata)) = rdata_text2 {
1701 assert!(raw_rdata.is_none());
1702 assert_eq!("1 issue \"example.com; key=value\"", parsed.unwrap());
1703 }
1704 }
1705
1706 #[test]
1707 fn test_format_rdata_for_tlsa_type() {
1708 let rdata = RData::TLSA(TLSA::new(
1709 CertUsage::PkixEe,
1710 Selector::Spki,
1711 Matching::Sha256,
1712 vec![1, 2, 3, 4, 5, 6, 7, 8],
1713 ));
1714 let rdata_text = format_rdata(&rdata);
1715 assert!(rdata_text.is_ok());
1716 if let Ok((parsed, raw_rdata)) = rdata_text {
1717 assert!(raw_rdata.is_none());
1718 assert_eq!("1 1 1 0102030405060708", parsed.unwrap());
1719 }
1720 }
1721
1722 #[test]
1723 fn test_format_rdata_for_sshfp_type() {
1724 let rdata = RData::SSHFP(SSHFP::new(
1725 Algorithm::ECDSA,
1726 FingerprintType::SHA1,
1727 vec![115, 115, 104, 102, 112],
1728 ));
1729 let rdata_text = format_rdata(&rdata);
1730 assert!(rdata_text.is_ok());
1731 if let Ok((parsed, raw_rdata)) = rdata_text {
1732 assert!(raw_rdata.is_none());
1733 assert_eq!("3 1 7373686670", parsed.unwrap());
1734 }
1735 }
1736
1737 #[test]
1738 fn test_format_rdata_for_naptr_type() {
1739 let rdata1 = RData::NAPTR(NAPTR::new(
1740 8,
1741 16,
1742 b"aa11AA-".to_vec().into_boxed_slice(),
1743 b"services".to_vec().into_boxed_slice(),
1744 b"regexpr".to_vec().into_boxed_slice(),
1745 Name::from_str("naptr.example.com").unwrap(),
1746 ));
1747 let rdata_text1 = format_rdata(&rdata1);
1748
1749 let rdata2 = RData::NAPTR(NAPTR::new(
1750 8,
1751 16,
1752 b"aa1\"\\1AA-".to_vec().into_boxed_slice(),
1753 b"\\services2\"".to_vec().into_boxed_slice(),
1754 b"re%ge\"xp.r\\".to_vec().into_boxed_slice(),
1755 Name::from_str("naptr.example.com").unwrap(),
1756 ));
1757 let rdata_text2 = format_rdata(&rdata2);
1758
1759 assert!(rdata_text1.is_ok());
1760 assert!(rdata_text2.is_ok());
1761
1762 if let Ok((parsed, raw_rdata)) = rdata_text1 {
1763 assert!(raw_rdata.is_none());
1764 assert_eq!(
1765 "8 16 \"aa11AA-\" \"services\" \"regexpr\" naptr.example.com",
1766 parsed.unwrap()
1767 );
1768 }
1769
1770 if let Ok((parsed, raw_rdata)) = rdata_text2 {
1771 assert!(raw_rdata.is_none());
1772 assert_eq!(
1773 "8 16 \"aa1\\\"\\\\1AA-\" \"\\\\services2\\\"\" \"re%ge\\\"xp.r\\\\\" naptr.example.com",
1774 parsed.unwrap()
1775 );
1776 }
1777 }
1778
1779 #[test]
1780 fn test_format_rdata_for_dnskey_type() {
1781 let rdata1 = RData::DNSSEC(DNSSECRData::DNSKEY(DNSKEY::new(
1782 true,
1783 true,
1784 false,
1785 PublicKeyBuf::new(vec![0, 1, 2, 3, 4, 5, 6, 7], DNSSEC_Algorithm::RSASHA256),
1786 )));
1787 let rdata_text1 = format_rdata(&rdata1);
1788
1789 let rdata2 = RData::DNSSEC(DNSSECRData::DNSKEY(DNSKEY::new(
1790 true,
1791 false,
1792 false,
1793 PublicKeyBuf::new(vec![0, 1, 2, 3, 4, 5, 6, 7], DNSSEC_Algorithm::RSASHA256),
1794 )));
1795 let rdata_text2 = format_rdata(&rdata2);
1796
1797 let rdata3 = RData::DNSSEC(DNSSECRData::DNSKEY(DNSKEY::new(
1798 true,
1799 true,
1800 true,
1801 PublicKeyBuf::new(vec![0, 1, 2, 3, 4, 5, 6, 7], DNSSEC_Algorithm::RSASHA256),
1802 )));
1803 let rdata_text3 = format_rdata(&rdata3);
1804
1805 assert!(rdata_text1.is_ok());
1806 assert!(rdata_text2.is_ok());
1807 assert!(rdata_text3.is_ok());
1808
1809 if let Ok((parsed, raw_rdata)) = rdata_text1 {
1810 assert!(raw_rdata.is_none());
1811 assert_eq!("257 3 8 AAECAwQFBgc=", parsed.unwrap());
1812 }
1813 if let Ok((parsed, raw_rdata)) = rdata_text2 {
1814 assert!(raw_rdata.is_none());
1815 assert_eq!("256 3 8 AAECAwQFBgc=", parsed.unwrap());
1816 }
1817 if let Ok((parsed, raw_rdata)) = rdata_text3 {
1818 assert!(raw_rdata.is_none());
1819 assert_eq!("0 3 8 AAECAwQFBgc=", parsed.unwrap());
1820 }
1821 }
1822
1823 #[test]
1824 fn test_format_rdata_for_nsec_type() {
1825 let rdata = RData::DNSSEC(DNSSECRData::NSEC(NSEC::new(
1826 Name::from_str("www.example.com").unwrap(),
1827 vec![RecordType::A, RecordType::AAAA],
1828 )));
1829 let rdata_text = format_rdata(&rdata);
1830 assert!(rdata_text.is_ok());
1831 if let Ok((parsed, raw_rdata)) = rdata_text {
1832 assert!(raw_rdata.is_none());
1833 assert_eq!("www.example.com A AAAA", parsed.unwrap());
1834 }
1835 }
1836
1837 #[test]
1838 fn test_format_rdata_for_nsec3_type() {
1839 let rdata = RData::DNSSEC(DNSSECRData::NSEC3(NSEC3::new(
1840 Nsec3HashAlgorithm::SHA1,
1841 true,
1842 2,
1843 vec![1, 2, 3, 4, 5],
1844 vec![6, 7, 8, 9, 0],
1845 vec![RecordType::A, RecordType::AAAA],
1846 )));
1847 let rdata_text = format_rdata(&rdata);
1848 assert!(rdata_text.is_ok());
1849 if let Ok((parsed, raw_rdata)) = rdata_text {
1850 assert!(raw_rdata.is_none());
1851 assert_eq!("1 1 2 0102030405 0O3GG280 A AAAA", parsed.unwrap());
1852 }
1853 }
1854
1855 #[test]
1856 fn test_format_rdata_for_nsec3param_type() {
1857 let rdata = RData::DNSSEC(DNSSECRData::NSEC3PARAM(NSEC3PARAM::new(
1858 Nsec3HashAlgorithm::SHA1,
1859 true,
1860 2,
1861 vec![1, 2, 3, 4, 5],
1862 )));
1863 let rdata_text = format_rdata(&rdata);
1864 assert!(rdata_text.is_ok());
1865 if let Ok((parsed, raw_rdata)) = rdata_text {
1866 assert!(raw_rdata.is_none());
1867 assert_eq!("1 1 2 0102030405", parsed.unwrap());
1868 }
1869 }
1870
1871 #[test]
1872 fn test_format_rdata_for_sig_type() {
1873 let mut wire: Vec<u8> = Vec::new();
1876 wire.extend_from_slice(&10u16.to_be_bytes());
1877 wire.push(8u8);
1878 wire.push(0u8);
1879 wire.extend_from_slice(&0u32.to_be_bytes());
1880 wire.extend_from_slice(&2u32.to_be_bytes());
1881 wire.extend_from_slice(&1u32.to_be_bytes());
1882 wire.extend_from_slice(&5u16.to_be_bytes());
1883 wire.extend_from_slice(&[
1884 3, b'w', b'w', b'w', 7, b'e', b'x', b'a', b'm', b'p', b'l', b'e', 3, b'c', b'o', b'm',
1885 0,
1886 ]);
1887 wire.extend(0u8..=31);
1888 test_format_rdata(
1889 &BASE64.encode(&wire),
1890 24,
1891 "NULL 8 0 0 2 1 5 www.example.com. AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8=",
1892 );
1893 }
1894
1895 #[test]
1896 fn test_format_rdata_for_key_type() {
1897 let rdata = RData::DNSSEC(DNSSECRData::KEY(KEY::new(
1898 KeyTrust::NotPrivate,
1899 KeyUsage::Host,
1900 #[allow(deprecated)]
1901 UpdateScope {
1902 zone: false,
1903 strong: false,
1904 unique: true,
1905 general: true,
1906 },
1907 Protocol::DNSSEC,
1908 DNSSEC_Algorithm::RSASHA256,
1909 vec![
1910 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
1911 23, 24, 25, 26, 27, 28, 29, 29, 31,
1912 ],
1913 )));
1914 let rdata_text = format_rdata(&rdata);
1915 assert!(rdata_text.is_ok());
1916 if let Ok((parsed, raw_rdata)) = rdata_text {
1917 assert!(raw_rdata.is_none());
1918 assert_eq!(
1919 "16387 3 8 AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHR8=",
1920 parsed.unwrap()
1921 );
1922 }
1923 }
1924
1925 #[test]
1928 fn test_format_rdata_for_rsig_type() {
1929 let input = SigInput {
1930 type_covered: RecordType::NULL,
1931 algorithm: DNSSEC_Algorithm::RSASHA256,
1932 num_labels: 0,
1933 original_ttl: 0,
1934 sig_expiration: SerialNumber::new(2),
1935 sig_inception: SerialNumber::new(1),
1936 key_tag: 5,
1937 signer_name: Name::from_str("www.example.com").unwrap(),
1938 };
1939 let rdata = RData::DNSSEC(DNSSECRData::RRSIG(RRSIG::from_sig(
1940 input,
1941 (0u8..=31).collect(),
1942 )));
1943 let rdata_text = format_rdata(&rdata);
1944 assert!(rdata_text.is_ok());
1945 if let Ok((parsed, raw_rdata)) = rdata_text {
1946 assert!(raw_rdata.is_none());
1947 assert_eq!(
1948 "NULL 8 0 0 2 1 5 www.example.com AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8=",
1949 parsed.unwrap()
1950 );
1951 }
1952 }
1953
1954 #[test]
1955 fn test_format_rdata_for_ds_type() {
1956 let rdata = RData::DNSSEC(DNSSECRData::DS(DS::new(
1957 0xF00F,
1958 DNSSEC_Algorithm::RSASHA256,
1959 DigestType::SHA256,
1960 vec![5, 6, 7, 8],
1961 )));
1962 let rdata_text = format_rdata(&rdata);
1963 assert!(rdata_text.is_ok());
1964 if let Ok((parsed, raw_rdata)) = rdata_text {
1965 assert!(raw_rdata.is_none());
1966 assert_eq!("61455 8 2 05060708", parsed.unwrap());
1967 }
1968 }
1969
1970 #[test]
1971 fn test_format_rdata_for_svcb_type() {
1972 let rdata = RData::SVCB(svcb::SVCB::new(
1973 1,
1974 Name::root(),
1975 vec![
1976 (
1977 svcb::SvcParamKey::Alpn,
1978 svcb::SvcParamValue::Alpn(svcb::Alpn(vec!["h3".to_string(), "h2".to_string()])),
1979 ),
1980 (
1981 svcb::SvcParamKey::Ipv4Hint,
1982 svcb::SvcParamValue::Ipv4Hint(svcb::IpHint(vec![
1983 A(Ipv4Addr::new(104, 18, 36, 155)),
1984 A(Ipv4Addr::new(172, 64, 151, 101)),
1985 ])),
1986 ),
1987 ],
1988 ));
1989 let rdata_text = format_rdata(&rdata);
1990 assert!(rdata_text.is_ok());
1991 if let Ok((parsed, raw_rdata)) = rdata_text {
1992 assert!(raw_rdata.is_none());
1993 assert_eq!(
1994 r#"1 . alpn="h3,h2" ipv4hint="104.18.36.155,172.64.151.101""#,
1995 parsed.unwrap()
1996 );
1997 }
1998 }
1999
2000 #[test]
2001 fn test_format_rdata_for_https_type() {
2002 let rdata = RData::HTTPS(HTTPS(svcb::SVCB::new(
2003 1,
2004 Name::root(),
2005 vec![
2006 (
2007 svcb::SvcParamKey::Alpn,
2008 svcb::SvcParamValue::Alpn(svcb::Alpn(vec!["h3".to_string(), "h2".to_string()])),
2009 ),
2010 (
2011 svcb::SvcParamKey::Ipv4Hint,
2012 svcb::SvcParamValue::Ipv4Hint(svcb::IpHint(vec![
2013 A(Ipv4Addr::new(104, 18, 36, 155)),
2014 A(Ipv4Addr::new(172, 64, 151, 101)),
2015 ])),
2016 ),
2017 ],
2018 )));
2019 let rdata_text = format_rdata(&rdata);
2020 assert!(rdata_text.is_ok());
2021 if let Ok((parsed, raw_rdata)) = rdata_text {
2022 assert!(raw_rdata.is_none());
2023 assert_eq!(
2024 r#"1 . alpn="h3,h2" ipv4hint="104.18.36.155,172.64.151.101""#,
2025 parsed.unwrap()
2026 );
2027 }
2028 }
2029
2030 #[test]
2031 fn test_format_rdata_for_hinfo_type() {
2032 let rdata = RData::HINFO(HINFO::new("intel".to_string(), "linux".to_string()));
2033 let rdata_text = format_rdata(&rdata);
2034 assert!(rdata_text.is_ok());
2035 if let Ok((parsed, raw_rdata)) = rdata_text {
2036 assert!(raw_rdata.is_none());
2037 assert_eq!(r#""intel" "linux""#, parsed.unwrap());
2038 }
2039 }
2040
2041 #[test]
2042 fn test_format_rdata_for_csync_type() {
2043 let types = vec![RecordType::A, RecordType::NS, RecordType::AAAA];
2044 let rdata = RData::CSYNC(CSYNC::new(123, true, true, types));
2045 let rdata_text = format_rdata(&rdata);
2046 assert!(rdata_text.is_ok());
2047 if let Ok((parsed, raw_rdata)) = rdata_text {
2048 assert!(raw_rdata.is_none());
2049 assert_eq!("123 3 A NS AAAA", parsed.unwrap());
2050 }
2051 }
2052
2053 #[test]
2054 fn test_format_rdata_for_opt_type() {
2055 let options = vec![(
2056 EdnsCode::LLQ,
2057 EdnsOption::Unknown(u16::from(EdnsCode::LLQ), vec![0x01; 18]),
2058 )];
2059 let rdata = RData::OPT(OPT::new(options));
2060 let rdata_text = format_rdata(&rdata);
2061 assert!(rdata_text.is_ok());
2062 if let Ok((parsed, raw_rdata)) = rdata_text {
2063 assert!(raw_rdata.is_none());
2064 assert_eq!("LLQ=AQEBAQEBAQEBAQEBAQEBAQEB", parsed.unwrap());
2065 }
2066 }
2067
2068 #[test]
2069 fn test_format_rdata_for_cert_type() {
2070 let rdata = RData::CERT(CERT::new(
2071 CertType::Experimental(65534),
2072 65535,
2073 CertAlgorithm::RSASHA1,
2074 BASE64
2075 .decode(
2076 b"MxFcby9k/yvedMfQgKzhH5er0Mu/vILz4\
2077 5IkskceFGgiWCn/GxHhai6VAuHAoNUz4YoU1tVfSCSqQYn6//11U6Nld80jEeC8aTrO+KKmCaY=",
2078 )
2079 .unwrap(),
2080 ));
2081 let rdata_text = format_rdata(&rdata);
2082 assert!(rdata_text.is_ok());
2083 if let Ok((parsed, raw_rdata)) = rdata_text {
2084 assert!(raw_rdata.is_none());
2085 assert_eq!(
2086 "65534 65535 RSASHA1 MxFcby9k/yvedMfQgKzhH5er0Mu/vILz4\
2087 5IkskceFGgiWCn/GxHhai6VAuHAoNUz4YoU1tVfSCSqQYn6//11U6Nld80jEeC8aTrO+KKmCaY=",
2088 parsed.unwrap()
2089 );
2090 }
2091 }
2092
2093 #[test]
2094 fn test_format_rdata_for_minfo_type() {
2095 test_format_rdata_with_compressed_domain_names(
2096 "5ZWBgAABAAEAAAABBm1pbmZvbwhleGFtcGxlMQNjb20AAA4AAcAMAA4AAQAADGsADQRmcmVkwBMDam9lwBMAACkQAAAAAAAAHAAKABgZ5zwJEK3VJQEAAABfSBqpS2bKf9CNBXg=",
2097 "BGZyZWTAEwNqb2XAEw==",
2098 14,
2099 "fred.example1.com. joe.example1.com.",
2100 );
2101 }
2102
2103 #[test]
2104 fn test_format_rdata_for_mb_type() {
2105 test_format_rdata_with_compressed_domain_names(
2106 "t8eBgAABAAEAAAABAm1iCGV4YW1wbGUxA2NvbQAABwABwAwABwABAAAA5AAJBmFhYmJjY8APAA\
2107 ApEAAAAAAAABwACgAYedbJkVVpMhsBAAAAX0U+y6UJQtCd0MuPBmFhYmJjY8AP",
2108 "BmFhYmJjY8AP",
2109 7,
2110 "aabbcc.example1.com.",
2111 );
2112 }
2113
2114 #[test]
2115 fn test_format_rdata_for_mg_type() {
2116 test_format_rdata_with_compressed_domain_names(
2117 "o8ABIAABAAAAAAABAm1nCGV4YW1wbGUxA2NvbQAACAABAAApEAAAAAAAAAwACgAICQ3LVdp9euQ=",
2118 "wAw=",
2119 8,
2120 "mg.example1.com.",
2121 );
2122 }
2123
2124 #[test]
2125 fn test_format_rdata_for_mr_type() {
2126 test_format_rdata_with_compressed_domain_names(
2127 "VWQBIAABAAAAAAABAm1yCGV4YW1wbGUxA2NvbQAACQABAAApEAAAAAAAAAwACgAIaPayFPJ4rmY=",
2128 "wAw=",
2129 9,
2130 "mr.example1.com.",
2131 );
2132 }
2133
2134 #[test]
2135 fn test_format_rdata_for_wks_type() {
2136 test_format_rdata("gAgBDgYAAAFA", 11, "128.8.1.14 6 23 25");
2137
2138 test_format_rdata("gAgBDgYAAAE=", 11, "128.8.1.14 6 23");
2139 }
2140
2141 #[test]
2142 fn test_format_rdata_for_rp_type() {
2143 test_format_rdata_with_compressed_domain_names(
2144 "Xc0BIAABAAAAAAABAnJwCGV4YW1wbGUxA2NvbQAAEQABAAApEAAAAAAAAAwACgAIMoUjsVrqjwo=",
2145 "BWxvdWllB3RyYW50b3IDdW1kA2VkdQAETEFNMQZwZW9wbGUDdW1kA2VkdQA=",
2146 17,
2147 "louie.trantor.umd.edu. LAM1.people.umd.edu.",
2148 );
2149 }
2150
2151 #[test]
2152 fn test_format_rdata_for_afsdb_type() {
2153 test_format_rdata_with_compressed_domain_names(
2154 "uaMBIAABAAAAAAABBWFmc2RiCGV4YW1wbGUxA2NvbQAAEgABAAApEAAAAAAAAAwACgAINy\
2155 n/qwKTyVc=",
2156 "AAEHYmlnYmlyZAd0b2FzdGVyA2NvbQA=",
2157 18,
2158 "1 bigbird.toaster.com.",
2159 );
2160 }
2161
2162 #[test]
2163 fn test_format_rdata_for_x25_type() {
2164 test_format_rdata("DDMxMTA2MTcwMDk1Ng==", 19, "\"311061700956\"");
2165 }
2166
2167 #[test]
2168 fn test_format_rdata_for_isdn_type() {
2169 test_format_rdata("DzE1MDg2MjAyODAwMzIxNw==", 20, "\"150862028003217\"");
2170 }
2171
2172 #[test]
2173 fn test_format_rdata_for_rt_type() {
2174 test_format_rdata_with_compressed_domain_names(
2175 "K1cBEAABAAAAAAABAnJ0CGV4YW1wbGUxA2NvbQAAFQABAAApAgAAAIAAABwACgAY4Rzxu\
2176 TfOxRwNw0bSX0VXy7WIF30GJ7DD",
2177 "AAoCYWEHZXhhbXBsZQNjb20A",
2178 21,
2179 "10 aa.example.com.",
2180 );
2181 }
2182
2183 #[test]
2184 fn test_format_rdata_for_nsap_type() {
2185 test_format_rdata(
2186 "RwAFgABaAAAAAAHhM////wABYQA=",
2187 22,
2188 "0x47000580005A0000000001E133FFFFFF00016100",
2189 );
2190 }
2191
2192 #[test]
2193 fn test_format_rdata_for_px_type() {
2194 test_format_rdata_with_compressed_domain_names(
2195 "QF+BgAABAAEAAAABAnB4CGV4YW1wbGUxA2NvbQAAGgABwAwAGgABAAAOEAAlAAoEbmV0\
2196 MgJpdAAJUFJNRC1uZXQyCUFETUQtcDQwMARDLWl0AAAAKRAAAAAAAAAcAAoAGDnSHBrTcxU1AQAAAF9FWK\
2197 fIBBM9awy20w==",
2198 "AAoEbmV0MgJpdAAJUFJNRC1uZXQyCUFETUQtcDQwMARDLWl0AA==",
2199 26,
2200 "10 net2.it. PRMD-net2.ADMD-p400.C-it.",
2201 );
2202 }
2203
2204 #[test]
2205 fn test_format_rdata_for_loc_type() {
2206 test_format_rdata(
2207 "ADMWE4kXLdBwvhXwAJiNIA==",
2208 29,
2209 "42 21 54.000 N 71 6 18.000 W -24.00m 30m 10000m 10m",
2210 );
2211 }
2212
2213 #[test]
2214 fn test_format_rdata_for_kx_type() {
2215 test_format_rdata_with_compressed_domain_names(
2216 "E4yBgAABAAEAAAABAmt4CGV4YW1wbGUxA2NvbQAAJAABwAwAJAABAAAOEAASAAoCYWEHZ\
2217 XhhbXBsZQNjb20AAAApEAAAAAAAABwACgAYohY6RsSf9dsBAAAAX0VY5DfEoTM1iq9G",
2218 "AAoCYWEHZXhhbXBsZQNjb20A",
2219 36,
2220 "10 aa.example.com.",
2221 );
2222 }
2223
2224 #[test]
2225 fn test_format_rdata_for_a6_type() {
2226 test_format_rdata(
2227 "QBI0VniavN7wCFNVQk5FVC0xA0lQNghleGFtcGxlMQNjb20A",
2228 38,
2229 "64 ::1234:5678:9abc:def0 SUBNET-1.IP6.example1.com.",
2230 );
2231 }
2232
2233 #[test]
2234 fn test_format_rdata_for_sink_type() {
2235 test_format_rdata("AQIDdddd", 40, "1 2 3 dddd");
2236 }
2237
2238 #[test]
2239 fn test_format_rdata_for_apl_type() {
2240 test_format_rdata(
2241 "AAEVA8CoIAABHIPAqCY=",
2242 42,
2243 "1:192.168.32.0/21 !1:192.168.38.0/28",
2244 );
2245
2246 test_format_rdata("AAEEAeAAAggB/w==", 42, "1:224.0.0.0/4 2:ff00::/8");
2247
2248 test_format_rdata(
2249 "AAEVA8CoIAABHATAqCYsAAEdA8AAJgABHYPAACYAAR2EwAAmCA==",
2250 42,
2251 "1:192.168.32.0/21 1:192.168.38.44/28 \
2252 1:192.0.38.0/29 !1:192.0.38.0/29 !1:192.0.38.8/29",
2253 );
2254
2255 test_format_rdata(
2256 "AAEVA8CoIAABHATAqCYsAAEdA8AAJg==",
2257 42,
2258 "1:192.168.32.0/21 1:192.168.38.44/28 1:192.0.38.0/29",
2259 );
2260 }
2261
2262 #[test]
2263 fn test_format_rdata_for_dhcid_type() {
2264 test_format_rdata(
2265 "AAIBY2/AuCccgoJbsaxcQc9TUapptP69lOjxfNuVAA2kjEA=",
2266 49,
2267 "AAIBY2/AuCccgoJbsaxcQc9TUapptP69lOjxfNuVAA2kjEA=",
2268 );
2269 }
2270
2271 #[test]
2272 fn test_format_rdata_for_spf_type() {
2273 test_format_rdata(
2274 "BnY9c3BmMQMrbXgVYTpjb2xvLmV4YW1wbGUuY29tLzI4BC1hbGw=",
2275 99,
2276 "\"v=spf1\" \"+mx\" \"a:colo.example.com/28\" \"-all\"",
2277 );
2278 }
2279
2280 fn test_format_rdata(raw_data: &str, code: u16, expected_output: &str) {
2281 let raw_rdata = BASE64
2282 .decode(raw_data.as_bytes())
2283 .expect("Invalid base64 encoded rdata.");
2284 let mut decoder = BinDecoder::new(&raw_rdata);
2285 let record = Record::from_rdata(
2286 Name::new(),
2287 1,
2288 RData::read(
2289 &mut decoder,
2290 RecordType::from(code),
2291 Restrict::new(raw_rdata.len() as u16),
2292 )
2293 .unwrap(),
2294 );
2295 let rdata_text = DnsMessageParser::new(Vec::<u8>::new())
2296 .parse_dns_record(&record)
2297 .map(|r| r.rdata);
2298 assert!(rdata_text.is_ok());
2299 assert_eq!(expected_output, rdata_text.unwrap().unwrap());
2300 }
2301
2302 fn test_format_rdata_with_compressed_domain_names(
2303 raw_message: &str,
2304 raw_data_encoded: &str,
2305 code: u16,
2306 expected_output: &str,
2307 ) {
2308 let raw_message = BASE64
2309 .decode(raw_message.as_bytes())
2310 .expect("Invalid base64 encoded raw message.");
2311 let raw_message_len = raw_message.len();
2312 let mut message_parser = DnsMessageParser::new(raw_message);
2313 let raw_rdata = BASE64
2314 .decode(raw_data_encoded.as_bytes())
2315 .expect("Invalid base64 encoded raw rdata.");
2316 for i in 1..=2 {
2317 let record_rdata = NULL::with(raw_rdata.clone());
2318 let rdata_text = message_parser.format_unknown_rdata(code, &record_rdata);
2319 assert!(rdata_text.is_ok());
2320 assert_eq!(expected_output, rdata_text.unwrap().0.unwrap());
2321 assert_eq!(
2322 raw_message_len + i * raw_rdata.len(),
2323 message_parser
2324 .raw_message_for_rdata_parsing()
2325 .unwrap()
2326 .len()
2327 );
2328 }
2329 }
2330}