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