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