dnsmsg_parser/
dns_message_parser.rs

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/// Error type for DNS message parsing
33#[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
45/// Result alias for parsing
46pub type DnsParserResult<T> = Result<T, DnsMessageParserError>;
47
48/// Options for DNS message parser
49#[derive(Debug, Default, Clone)]
50pub struct DnsParserOptions {
51    /// Whether hostnames in RData should be lowercased, for consistency
52    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/// A DNS message parser
70#[derive(Debug)]
71pub struct DnsMessageParser {
72    raw_message: Vec<u8>,
73    // This field is used to facilitate parsing of compressed domain names contained
74    // in some record data. We could instantiate a new copy of the raw_message whenever
75    // we need to parse rdata, but to avoid impact on performance, we'll instantiate
76    // only one copy of raw_message upon the first call to parse an rdata that may
77    // contain compressed domain name, and store it here as a member field; for
78    // subsequent invocations of the same call, we simply reuse this copy.
79    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)), // Previously none value
192            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                // Using CSYNC's formatter since not all data is exposed otherwise
557                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                // See https://tools.ietf.org/html/rfc4034 for details
746                // on dnssec related rdata formats
747                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(), // currently in epoch convert to human readable ?
801                        sig.sig_inception().get(), // currently in epoch convert to human readable ?
802                        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                // RSIG is a derivation of SIG but choosing to keep this duplicate code in lieu of the alternative
809                // which is to allocate to the heap with Box in order to deref.
810                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(), // currently in epoch convert to human readable ?
821                        sig.sig_inception().get(), // currently in epoch convert to human readable ?
822                        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"), // 0    NoError    No Error                             [RFC1035]
938        1 => Some("FormErr"), // 1    FormErr    Format Error                         [RFC1035]
939        2 => Some("ServFail"), // 2    ServFail   Server Failure                       [RFC1035]
940        3 => Some("NXDomain"), // 3    NXDomain   Non-Existent Domain                  [RFC1035]
941        4 => Some("NotImp"),  // 4    NotImp     Not Implemented                      [RFC1035]
942        5 => Some("Refused"), // 5    Refused    Query Refused                        [RFC1035]
943        6 => Some("YXDomain"), // 6    YXDomain   Name Exists when it should not       [RFC2136][RFC6672]
944        7 => Some("YXRRSet"),  // 7    YXRRSet    RR Set Exists when it should not     [RFC2136]
945        8 => Some("NXRRSet"),  // 8    NXRRSet    RR Set that should exist does not    [RFC2136]
946        9 => Some("NotAuth"),  // 9    NotAuth    Server Not Authoritative for zone    [RFC2136]
947        10 => Some("NotZone"), // 10   NotZone    Name not contained in zone           [RFC2136]
948        // backwards compat for 4 bit ResponseCodes so far.
949        16 => Some("BADVERS"), // 16    BADVERS    Bad OPT Version    [RFC6891]
950        // 16    BADSIG    TSIG Signature Failure               [RFC2845]
951        17 => Some("BADKEY"), // 17    BADKEY    Key not recognized                   [RFC2845]
952        18 => Some("BADTIME"), // 18    BADTIME   Signature out of time window         [RFC2845]
953        19 => Some("BADMODE"), // 19    BADMODE   Bad TKEY Mode                        [RFC2930]
954        20 => Some("BADNAME"), // 20    BADNAME   Duplicate key name                   [RFC2930]
955        21 => Some("BADALG"), // 21    BADALG    Algorithm not supported              [RFC2930]
956        22 => Some("BADTRUNC"), // 22    BADTRUNC  Bad Truncation                       [RFC4635]
957        23 => Some("BADCOOKIE"), // 23    BADCOOKIE (TEMPORARY - registered 2015-07-26, expires 2016-07-26)    Bad/missing server cookie    [draft-ietf-dnsop-cookies]
958        _ => 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) // convert cm to metre
1077}
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        // this testcase have prefix value of 160,
1543        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    // rsig is a derivation of the SIG record data, but the upstream crate does not handle that with an trait
1917    // so there isn't really a great way to reduce code duplication here.
1918    #[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}