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