dnsmsg_parser/
dns_message_parser.rs

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