hickory_proto/rr/
record_data.rs

1// Copyright 2015-2023 Benjamin Fry <benjaminfry@me.com>
2//
3// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
4// https://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5// https://opensource.org/licenses/MIT>, at your option. This file may not be
6// copied, modified, or distributed except according to those terms.
7
8//! record data enum variants
9#![allow(deprecated, clippy::use_self)] // allows us to deprecate RData types
10
11#[cfg(test)]
12use std::convert::From;
13use std::{cmp::Ordering, fmt, net::IpAddr};
14
15#[cfg(feature = "serde-config")]
16use serde::{Deserialize, Serialize};
17
18use enum_as_inner::EnumAsInner;
19use tracing::{trace, warn};
20
21use crate::{
22    error::{ProtoError, ProtoErrorKind, ProtoResult},
23    rr::{
24        rdata::{
25            A, AAAA, ANAME, CAA, CNAME, CSYNC, HINFO, HTTPS, MX, NAPTR, NS, NULL, OPENPGPKEY, OPT,
26            PTR, SOA, SRV, SSHFP, SVCB, TLSA, TXT,
27        },
28        record_type::RecordType,
29        RecordData, RecordDataDecodable,
30    },
31    serialize::binary::{BinDecodable, BinDecoder, BinEncodable, BinEncoder, Restrict},
32};
33
34#[cfg(feature = "dnssec")]
35use super::dnssec::rdata::DNSSECRData;
36
37/// Record data enum variants for all valid DNS data types.
38///
39/// This is used to represent the generic Record as it is read off the wire. Allows for a Record to be abstractly referenced without knowing it's internal until runtime.
40///
41/// [RFC 1035](https://tools.ietf.org/html/rfc1035), DOMAIN NAMES - IMPLEMENTATION AND SPECIFICATION, November 1987
42///
43/// ```text
44/// 3.3. Standard RRs
45///
46/// The following RR definitions are expected to occur, at least
47/// potentially, in all classes.  In particular, NS, SOA, CNAME, and PTR
48/// will be used in all classes, and have the same format in all classes.
49/// Because their RDATA format is known, all domain names in the RDATA
50/// section of these RRs may be compressed.
51///
52/// <domain-name> is a domain name represented as a series of labels, and
53/// terminated by a label with zero length.  <character-string> is a single
54/// length octet followed by that number of characters.  <character-string>
55/// is treated as binary information, and can be up to 256 characters in
56/// length (including the length octet).
57/// ```
58#[cfg_attr(feature = "serde-config", derive(Deserialize, Serialize))]
59#[derive(Debug, EnumAsInner, PartialEq, Clone, Eq)]
60#[non_exhaustive]
61pub enum RData {
62    /// ```text
63    /// -- RFC 1035 -- Domain Implementation and Specification    November 1987
64    ///
65    /// 3.4. Internet specific RRs
66    ///
67    /// 3.4.1. A RDATA format
68    ///
69    ///     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
70    ///     |                    ADDRESS                    |
71    ///     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
72    ///
73    /// where:
74    ///
75    /// ADDRESS         A 32 bit Internet address.
76    ///
77    /// Hosts that have multiple Internet addresses will have multiple A
78    /// records.
79    ///
80    /// A records cause no additional section processing.  The RDATA section of
81    /// an A line in a Zone File is an Internet address expressed as four
82    /// decimal numbers separated by dots without any embedded spaces (e.g.,
83    /// "10.2.0.52" or "192.0.5.6").
84    /// ```
85    A(A),
86
87    /// ```text
88    /// -- RFC 1886 -- IPv6 DNS Extensions              December 1995
89    ///
90    /// 2.2 AAAA data format
91    ///
92    ///    A 128 bit IPv6 address is encoded in the data portion of an AAAA
93    ///    resource record in network byte order (high-order byte first).
94    /// ```
95    AAAA(AAAA),
96
97    /// ```text
98    /// 2.  The ANAME resource record
99    ///
100    ///   This document defines the "ANAME" DNS resource record type, with RR
101    ///   TYPE value [TBD].
102    ///
103    /// 2.1.  Presentation and wire format
104    ///
105    ///   The ANAME presentation format is identical to that of CNAME
106    ///   [RFC1033]:
107    ///
108    ///       owner ttl class ANAME target
109    /// ```
110    ANAME(ANAME),
111
112    /// ```text
113    /// -- RFC 6844          Certification Authority Authorization     January 2013
114    ///
115    /// 5.1.  Syntax
116    ///
117    /// A CAA RR contains a single property entry consisting of a tag-value
118    /// pair.  Each tag represents a property of the CAA record.  The value
119    /// of a CAA property is that specified in the corresponding value field.
120    ///
121    /// A domain name MAY have multiple CAA RRs associated with it and a
122    /// given property MAY be specified more than once.
123    ///
124    /// The CAA data field contains one property entry.  A property entry
125    /// consists of the following data fields:
126    ///
127    /// +0-1-2-3-4-5-6-7-|0-1-2-3-4-5-6-7-|
128    /// | Flags          | Tag Length = n |
129    /// +----------------+----------------+...+---------------+
130    /// | Tag char 0     | Tag char 1     |...| Tag char n-1  |
131    /// +----------------+----------------+...+---------------+
132    /// +----------------+----------------+.....+----------------+
133    /// | Value byte 0   | Value byte 1   |.....| Value byte m-1 |
134    /// +----------------+----------------+.....+----------------+
135    ///
136    /// Where n is the length specified in the Tag length field and m is the
137    /// remaining octets in the Value field (m = d - n - 2) where d is the
138    /// length of the RDATA section.
139    /// ```
140    CAA(CAA),
141
142    /// ```text
143    ///   3.3. Standard RRs
144    ///
145    /// The following RR definitions are expected to occur, at least
146    /// potentially, in all classes.  In particular, NS, SOA, CNAME, and PTR
147    /// will be used in all classes, and have the same format in all classes.
148    /// Because their RDATA format is known, all domain names in the RDATA
149    /// section of these RRs may be compressed.
150    ///
151    /// <domain-name> is a domain name represented as a series of labels, and
152    /// terminated by a label with zero length.  <character-string> is a single
153    /// length octet followed by that number of characters.  <character-string>
154    /// is treated as binary information, and can be up to 256 characters in
155    /// length (including the length octet).
156    ///
157    /// 3.3.1. CNAME RDATA format
158    ///
159    ///     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
160    ///     /                     CNAME                     /
161    ///     /                                               /
162    ///     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
163    ///
164    /// where:
165    ///
166    /// CNAME           A <domain-name> which specifies the canonical or primary
167    ///                 name for the owner.  The owner name is an alias.
168    ///
169    /// CNAME RRs cause no additional section processing, but name servers may
170    /// choose to restart the query at the canonical name in certain cases.  See
171    /// the description of name server logic in [RFC-1034] for details.
172    /// ```
173    CNAME(CNAME),
174
175    /// ```text
176    /// 2.1.  The CSYNC Resource Record Format
177    ///
178    /// 2.1.1.  The CSYNC Resource Record Wire Format
179    ///
180    /// The CSYNC RDATA consists of the following fields:
181    ///
182    ///                     1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
183    /// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
184    /// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
185    /// |                          SOA Serial                           |
186    /// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
187    /// |       Flags                   |            Type Bit Map       /
188    /// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
189    /// /                     Type Bit Map (continued)                  /
190    /// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
191    /// ```
192    CSYNC(CSYNC),
193
194    /// ```text
195    /// 3.3.2. HINFO RDATA format
196    ///
197    ///     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
198    ///     /                      CPU                      /
199    ///     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
200    ///     /                       OS                      /
201    ///     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
202    ///
203    /// where:
204    ///
205    /// CPU             A <character-string> which specifies the CPU type.
206    ///
207    /// OS              A <character-string> which specifies the operating
208    ///                 system type.
209    ///
210    /// Standard values for CPU and OS can be found in [RFC-1010].
211    ///
212    /// HINFO records are used to acquire general information about a host.  The
213    /// main use is for protocols such as FTP that can use special procedures
214    /// when talking between machines or operating systems of the same type.
215    /// ```
216    ///
217    /// `HINFO` is also used by [RFC 8482](https://tools.ietf.org/html/rfc8482)
218    HINFO(HINFO),
219
220    /// [RFC draft-ietf-dnsop-svcb-https-03, DNS SVCB and HTTPS RRs](https://datatracker.ietf.org/doc/html/draft-ietf-dnsop-svcb-https-03#section-8)
221    ///
222    /// ```text
223    ///    8.  Using SVCB with HTTPS and HTTP
224    ///
225    ///    Use of any protocol with SVCB requires a protocol-specific mapping
226    ///    specification.  This section specifies the mapping for HTTPS and
227    ///    HTTP.
228    ///
229    ///    To enable special handling for the HTTPS and HTTP use-cases, the
230    ///    HTTPS RR type is defined as a SVCB-compatible RR type, specific to
231    ///    the https and http schemes.  Clients MUST NOT perform SVCB queries or
232    ///    accept SVCB responses for "https" or "http" schemes.
233    ///
234    ///    The HTTPS RR wire format and presentation format are identical to
235    ///    SVCB, and both share the SvcParamKey registry.  SVCB semantics apply
236    ///    equally to HTTPS RRs unless specified otherwise.  The presentation
237    ///    format of the record is:
238    ///
239    ///    Name TTL IN HTTPS SvcPriority TargetName SvcParams
240    /// ```
241    HTTPS(HTTPS),
242
243    /// ```text
244    /// 3.3.9. MX RDATA format
245    ///
246    ///     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
247    ///     |                  PREFERENCE                   |
248    ///     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
249    ///     /                   EXCHANGE                    /
250    ///     /                                               /
251    ///     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
252    ///
253    /// where:
254    ///
255    /// PREFERENCE      A 16 bit integer which specifies the preference given to
256    ///                 this RR among others at the same owner.  Lower values
257    ///                 are preferred.
258    ///
259    /// EXCHANGE        A <domain-name> which specifies a host willing to act as
260    ///                 a mail exchange for the owner name.
261    ///
262    /// MX records cause type A additional section processing for the host
263    /// specified by EXCHANGE.  The use of MX RRs is explained in detail in
264    /// [RFC-974].
265    /// ```
266    MX(MX),
267
268    /// [RFC 3403 DDDS DNS Database, October 2002](https://tools.ietf.org/html/rfc3403#section-4)
269    ///
270    /// ```text
271    /// 4.1 Packet Format
272    ///
273    ///   The packet format of the NAPTR RR is given below.  The DNS type code
274    ///   for NAPTR is 35.
275    ///
276    ///      The packet format for the NAPTR record is as follows
277    ///                                       1  1  1  1  1  1
278    ///         0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
279    ///       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
280    ///       |                     ORDER                     |
281    ///       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
282    ///       |                   PREFERENCE                  |
283    ///       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
284    ///       /                     FLAGS                     /
285    ///       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
286    ///       /                   SERVICES                    /
287    ///       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
288    ///       /                    REGEXP                     /
289    ///       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
290    ///       /                  REPLACEMENT                  /
291    ///       /                                               /
292    ///       +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
293    ///
294    ///   <character-string> and <domain-name> as used here are defined in RFC
295    ///   1035 [7].
296    ///
297    ///   ORDER
298    ///      A 16-bit unsigned integer specifying the order in which the NAPTR
299    ///      records MUST be processed in order to accurately represent the
300    ///      ordered list of Rules.  The ordering is from lowest to highest.
301    ///      If two records have the same order value then they are considered
302    ///      to be the same rule and should be selected based on the
303    ///      combination of the Preference values and Services offered.
304    ///
305    ///   PREFERENCE
306    ///      Although it is called "preference" in deference to DNS
307    ///      terminology, this field is equivalent to the Priority value in the
308    ///      DDDS Algorithm.  It is a 16-bit unsigned integer that specifies
309    ///      the order in which NAPTR records with equal Order values SHOULD be
310    ///      processed, low numbers being processed before high numbers.  This
311    ///      is similar to the preference field in an MX record, and is used so
312    ///      domain administrators can direct clients towards more capable
313    ///      hosts or lighter weight protocols.  A client MAY look at records
314    ///      with higher preference values if it has a good reason to do so
315    ///      such as not supporting some protocol or service very well.
316    ///
317    ///      The important difference between Order and Preference is that once
318    ///      a match is found the client MUST NOT consider records with a
319    ///      different Order but they MAY process records with the same Order
320    ///      but different Preferences.  The only exception to this is noted in
321    ///      the second important Note in the DDDS algorithm specification
322    ///      concerning allowing clients to use more complex Service
323    ///      determination between steps 3 and 4 in the algorithm.  Preference
324    ///      is used to give communicate a higher quality of service to rules
325    ///      that are considered the same from an authority standpoint but not
326    ///      from a simple load balancing standpoint.
327    ///
328    ///      It is important to note that DNS contains several load balancing
329    ///      mechanisms and if load balancing among otherwise equal services
330    ///      should be needed then methods such as SRV records or multiple A
331    ///      records should be utilized to accomplish load balancing.
332    ///
333    ///   FLAGS
334    ///      A <character-string> containing flags to control aspects of the
335    ///      rewriting and interpretation of the fields in the record.  Flags
336    ///      are single characters from the set A-Z and 0-9.  The case of the
337    ///      alphabetic characters is not significant.  The field can be empty.
338    ///
339    ///      It is up to the Application specifying how it is using this
340    ///      Database to define the Flags in this field.  It must define which
341    ///      ones are terminal and which ones are not.
342    ///
343    ///   SERVICES
344    ///      A <character-string> that specifies the Service Parameters
345    ///      applicable to this this delegation path.  It is up to the
346    ///      Application Specification to specify the values found in this
347    ///      field.
348    ///
349    ///   REGEXP
350    ///      A <character-string> containing a substitution expression that is
351    ///      applied to the original string held by the client in order to
352    ///      construct the next domain name to lookup.  See the DDDS Algorithm
353    ///      specification for the syntax of this field.
354    ///
355    ///      As stated in the DDDS algorithm, The regular expressions MUST NOT
356    ///      be used in a cumulative fashion, that is, they should only be
357    ///      applied to the original string held by the client, never to the
358    ///      domain name produced by a previous NAPTR rewrite.  The latter is
359    ///      tempting in some applications but experience has shown such use to
360    ///      be extremely fault sensitive, very error prone, and extremely
361    ///      difficult to debug.
362    ///
363    ///   REPLACEMENT
364    ///      A <domain-name> which is the next domain-name to query for
365    ///      depending on the potential values found in the flags field.  This
366    ///      field is used when the regular expression is a simple replacement
367    ///      operation.  Any value in this field MUST be a fully qualified
368    ///      domain-name.  Name compression is not to be used for this field.
369    ///
370    ///      This field and the REGEXP field together make up the Substitution
371    ///      Expression in the DDDS Algorithm.  It is simply a historical
372    ///      optimization specifically for DNS compression that this field
373    ///      exists.  The fields are also mutually exclusive.  If a record is
374    ///      returned that has values for both fields then it is considered to
375    ///      be in error and SHOULD be either ignored or an error returned.
376    /// ```
377    NAPTR(NAPTR),
378
379    /// ```text
380    /// 3.3.10. NULL RDATA format (EXPERIMENTAL)
381    ///
382    ///     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
383    ///     /                  <anything>                   /
384    ///     /                                               /
385    ///     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
386    ///
387    /// Anything at all may be in the RDATA field so long as it is 65535 octets
388    /// or less.
389    ///
390    /// NULL records cause no additional section processing.  NULL RRs are not
391    /// allowed in Zone Files.  NULLs are used as placeholders in some
392    /// experimental extensions of the DNS.
393    /// ```
394    NULL(NULL),
395
396    /// ```text
397    /// 3.3.11. NS RDATA format
398    ///
399    ///     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
400    ///     /                   NSDNAME                     /
401    ///     /                                               /
402    ///     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
403    ///
404    /// where:
405    ///
406    /// NSDNAME         A <domain-name> which specifies a host which should be
407    ///                 authoritative for the specified class and domain.
408    ///
409    /// NS records cause both the usual additional section processing to locate
410    /// a type A record, and, when used in a referral, a special search of the
411    /// zone in which they reside for glue information.
412    ///
413    /// The NS RR states that the named host should be expected to have a zone
414    /// starting at owner name of the specified class.  Note that the class may
415    /// not indicate the protocol family which should be used to communicate
416    /// with the host, although it is typically a strong hint.  For example,
417    /// hosts which are name servers for either Internet (IN) or Hesiod (HS)
418    /// class information are normally queried using IN class protocols.
419    /// ```
420    NS(NS),
421
422    /// [RFC 7929](https://tools.ietf.org/html/rfc7929#section-2.1)
423    ///
424    /// ```text
425    /// The RDATA portion of an OPENPGPKEY resource record contains a single
426    /// value consisting of a Transferable Public Key formatted as specified
427    /// in [RFC4880].
428    /// ```
429    OPENPGPKEY(OPENPGPKEY),
430
431    /// ```text
432    /// RFC 6891                   EDNS(0) Extensions                 April 2013
433    /// 6.1.2.  Wire Format
434    ///
435    ///        +------------+--------------+------------------------------+
436    ///        | Field Name | Field Type   | Description                  |
437    ///        +------------+--------------+------------------------------+
438    ///        | NAME       | domain name  | MUST be 0 (root domain)      |
439    ///        | TYPE       | u_int16_t    | OPT (41)                     |
440    ///        | CLASS      | u_int16_t    | requestor's UDP payload size |
441    ///        | TTL        | u_int32_t    | extended RCODE and flags     |
442    ///        | RDLEN      | u_int16_t    | length of all RDATA          |
443    ///        | RDATA      | octet stream | {attribute,value} pairs      |
444    ///        +------------+--------------+------------------------------+
445    ///
446    /// The variable part of an OPT RR may contain zero or more options in
447    ///    the RDATA.  Each option MUST be treated as a bit field.  Each option
448    ///    is encoded as:
449    ///
450    ///                   +0 (MSB)                            +1 (LSB)
451    ///        +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
452    ///     0: |                          OPTION-CODE                          |
453    ///        +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
454    ///     2: |                         OPTION-LENGTH                         |
455    ///        +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
456    ///     4: |                                                               |
457    ///        /                          OPTION-DATA                          /
458    ///        /                                                               /
459    ///        +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
460    /// ```
461    OPT(OPT),
462
463    /// ```text
464    /// 3.3.12. PTR RDATA format
465    ///
466    ///     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
467    ///     /                   PTRDNAME                    /
468    ///     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
469    ///
470    /// where:
471    ///
472    /// PTRDNAME        A <domain-name> which points to some location in the
473    ///                 domain name space.
474    ///
475    /// PTR records cause no additional section processing.  These RRs are used
476    /// in special domains to point to some other location in the domain space.
477    /// These records are simple data, and don't imply any special processing
478    /// similar to that performed by CNAME, which identifies aliases.  See the
479    /// description of the IN-ADDR.ARPA domain for an example.
480    /// ```
481    PTR(PTR),
482
483    /// ```text
484    /// 3.3.13. SOA RDATA format
485    ///
486    ///     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
487    ///     /                     MNAME                     /
488    ///     /                                               /
489    ///     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
490    ///     /                     RNAME                     /
491    ///     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
492    ///     |                    SERIAL                     |
493    ///     |                                               |
494    ///     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
495    ///     |                    REFRESH                    |
496    ///     |                                               |
497    ///     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
498    ///     |                     RETRY                     |
499    ///     |                                               |
500    ///     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
501    ///     |                    EXPIRE                     |
502    ///     |                                               |
503    ///     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
504    ///     |                    MINIMUM                    |
505    ///     |                                               |
506    ///     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
507    ///
508    /// where:
509    ///
510    /// MNAME           The <domain-name> of the name server that was the
511    ///                 original or primary source of data for this zone.
512    ///
513    /// RNAME           A <domain-name> which specifies the mailbox of the
514    ///                 person responsible for this zone.
515    ///
516    /// SERIAL          The unsigned 32 bit version number of the original copy
517    ///                 of the zone.  Zone transfers preserve this value.  This
518    ///                 value wraps and should be compared using sequence space
519    ///                 arithmetic.
520    ///
521    /// REFRESH         A 32 bit time interval before the zone should be
522    ///                 refreshed.
523    ///
524    /// RETRY           A 32 bit time interval that should elapse before a
525    ///                 failed refresh should be retried.
526    ///
527    /// EXPIRE          A 32 bit time value that specifies the upper limit on
528    ///                 the time interval that can elapse before the zone is no
529    ///                 longer authoritative.
530    ///
531    /// MINIMUM         The unsigned 32 bit minimum TTL field that should be
532    ///                 exported with any RR from this zone.
533    ///
534    /// SOA records cause no additional section processing.
535    ///
536    /// All times are in units of seconds.
537    ///
538    /// Most of these fields are pertinent only for name server maintenance
539    /// operations.  However, MINIMUM is used in all query operations that
540    /// retrieve RRs from a zone.  Whenever a RR is sent in a response to a
541    /// query, the TTL field is set to the maximum of the TTL field from the RR
542    /// and the MINIMUM field in the appropriate SOA.  Thus MINIMUM is a lower
543    /// bound on the TTL field for all RRs in a zone.  Note that this use of
544    /// MINIMUM should occur when the RRs are copied into the response and not
545    /// when the zone is loaded from a Zone File or via a zone transfer.  The
546    /// reason for this provision is to allow future dynamic update facilities to
547    /// change the SOA RR with known semantics.
548    /// ```
549    SOA(SOA),
550
551    /// ```text
552    /// RFC 2782                       DNS SRV RR                  February 2000
553    ///
554    /// The format of the SRV RR
555    ///
556    ///  _Service._Proto.Name TTL Class SRV Priority Weight Port Target
557    /// ```
558    SRV(SRV),
559
560    /// [RFC 4255](https://tools.ietf.org/html/rfc4255#section-3.1)
561    ///
562    /// ```text
563    /// 3.1.  The SSHFP RDATA Format
564    ///
565    ///    The RDATA for a SSHFP RR consists of an algorithm number, fingerprint
566    ///    type and the fingerprint of the public host key.
567    ///
568    ///        1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
569    ///        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
570    ///        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
571    ///        |   algorithm   |    fp type    |                               /
572    ///        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               /
573    ///        /                                                               /
574    ///        /                          fingerprint                          /
575    ///        /                                                               /
576    ///        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
577    ///
578    /// 3.1.1.  Algorithm Number Specification
579    ///
580    ///    This algorithm number octet describes the algorithm of the public
581    ///    key.  The following values are assigned:
582    ///
583    ///           Value    Algorithm name
584    ///           -----    --------------
585    ///           0        reserved
586    ///           1        RSA
587    ///           2        DSS
588    ///
589    ///    Reserving other types requires IETF consensus [4].
590    ///
591    /// 3.1.2.  Fingerprint Type Specification
592    ///
593    ///    The fingerprint type octet describes the message-digest algorithm
594    ///    used to calculate the fingerprint of the public key.  The following
595    ///    values are assigned:
596    ///
597    ///           Value    Fingerprint type
598    ///           -----    ----------------
599    ///           0        reserved
600    ///           1        SHA-1
601    ///
602    ///    Reserving other types requires IETF consensus [4].
603    ///
604    ///    For interoperability reasons, as few fingerprint types as possible
605    ///    should be reserved.  The only reason to reserve additional types is
606    ///    to increase security.
607    ///
608    /// 3.1.3.  Fingerprint
609    ///
610    ///    The fingerprint is calculated over the public key blob as described
611    ///    in [7].
612    ///
613    ///    The message-digest algorithm is presumed to produce an opaque octet
614    ///    string output, which is placed as-is in the RDATA fingerprint field.
615    /// ```
616    ///
617    /// The algorithm and fingerprint type values have been updated in
618    /// [RFC 6594](https://tools.ietf.org/html/rfc6594) and
619    /// [RFC 7479](https://tools.ietf.org/html/rfc7479).
620    SSHFP(SSHFP),
621
622    /// [RFC draft-ietf-dnsop-svcb-https-03, DNS SVCB and HTTPS RRs](https://datatracker.ietf.org/doc/html/draft-ietf-dnsop-svcb-https-03#section-2)
623    ///
624    /// ```text
625    ///    2.  The SVCB record type
626    ///
627    ///   The SVCB DNS resource record (RR) type (RR type 64) is used to locate
628    ///   alternative endpoints for a service.
629    ///
630    ///   The algorithm for resolving SVCB records and associated address
631    ///   records is specified in Section 3.
632    ///
633    ///   Other SVCB-compatible resource record types can also be defined as-
634    ///   needed.  In particular, the HTTPS RR (RR type 65) provides special
635    ///   handling for the case of "https" origins as described in Section 8.
636    ///
637    ///   SVCB RRs are extensible by a list of SvcParams, which are pairs
638    ///   consisting of a SvcParamKey and a SvcParamValue.  Each SvcParamKey
639    ///   has a presentation name and a registered number.  Values are in a
640    ///   format specific to the SvcParamKey.  Their definition should specify
641    ///   both their presentation format and wire encoding (e.g., domain names,
642    ///   binary data, or numeric values).  The initial SvcParamKeys and
643    ///   formats are defined in Section 6.
644    /// ```
645    SVCB(SVCB),
646
647    /// [RFC 6698, DNS-Based Authentication for TLS](https://tools.ietf.org/html/rfc6698#section-2.1)
648    ///
649    /// ```text
650    ///                         1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
651    ///     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
652    ///    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
653    ///    |  Cert. Usage  |   Selector    | Matching Type |               /
654    ///    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+               /
655    ///    /                                                               /
656    ///    /                 Certificate Association Data                  /
657    ///    /                                                               /
658    ///    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
659    /// ```
660    TLSA(TLSA),
661
662    /// ```text
663    /// 3.3.14. TXT RDATA format
664    ///
665    ///     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
666    ///     /                   TXT-DATA                    /
667    ///     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
668    ///
669    /// where:
670    ///
671    /// TXT-DATA        One or more <character-string>s.
672    ///
673    /// TXT RRs are used to hold descriptive text.  The semantics of the text
674    /// depends on the domain where it is found.
675    /// ```
676    TXT(TXT),
677
678    /// A DNSSEC- or SIG(0)- specific record. See `DNSSECRData` for details.
679    ///
680    /// These types are in `DNSSECRData` to make them easy to disable when
681    /// crypto functionality isn't needed.
682    #[cfg(feature = "dnssec")]
683    #[cfg_attr(docsrs, doc(cfg(feature = "dnssec")))]
684    DNSSEC(DNSSECRData),
685
686    /// Unknown RecordData is for record types not supported by Hickory DNS
687    Unknown {
688        /// RecordType code
689        code: RecordType,
690        /// RData associated to the record
691        rdata: NULL,
692    },
693
694    /// This corresponds to a record type of 0, unspecified
695    #[deprecated(note = "Use None for the RData in the resource record instead")]
696    ZERO,
697}
698
699impl RData {
700    fn to_bytes(&self) -> Vec<u8> {
701        let mut buf: Vec<u8> = Vec::new();
702        {
703            let mut encoder: BinEncoder<'_> = BinEncoder::new(&mut buf);
704            self.emit(&mut encoder).unwrap_or_else(|_| {
705                warn!("could not encode RDATA: {:?}", self);
706            });
707        }
708        buf
709    }
710
711    /// Converts this to a Recordtype
712    pub fn record_type(&self) -> RecordType {
713        match *self {
714            Self::A(..) => RecordType::A,
715            Self::AAAA(..) => RecordType::AAAA,
716            Self::ANAME(..) => RecordType::ANAME,
717            Self::CAA(..) => RecordType::CAA,
718            Self::CNAME(..) => RecordType::CNAME,
719            Self::CSYNC(..) => RecordType::CSYNC,
720            Self::HINFO(..) => RecordType::HINFO,
721            Self::HTTPS(..) => RecordType::HTTPS,
722            Self::MX(..) => RecordType::MX,
723            Self::NAPTR(..) => RecordType::NAPTR,
724            Self::NS(..) => RecordType::NS,
725            Self::NULL(..) => RecordType::NULL,
726            Self::OPENPGPKEY(..) => RecordType::OPENPGPKEY,
727            Self::OPT(..) => RecordType::OPT,
728            Self::PTR(..) => RecordType::PTR,
729            Self::SOA(..) => RecordType::SOA,
730            Self::SRV(..) => RecordType::SRV,
731            Self::SSHFP(..) => RecordType::SSHFP,
732            Self::SVCB(..) => RecordType::SVCB,
733            Self::TLSA(..) => RecordType::TLSA,
734            Self::TXT(..) => RecordType::TXT,
735            #[cfg(feature = "dnssec")]
736            Self::DNSSEC(ref rdata) => DNSSECRData::to_record_type(rdata),
737            Self::Unknown { code, .. } => code,
738            Self::ZERO => RecordType::ZERO,
739        }
740    }
741
742    /// If this is an A or AAAA record type, then an IpAddr will be returned
743    pub fn ip_addr(&self) -> Option<IpAddr> {
744        match *self {
745            Self::A(a) => Some(IpAddr::from(a.0)),
746            Self::AAAA(aaaa) => Some(IpAddr::from(aaaa.0)),
747            _ => None,
748        }
749    }
750
751    /// Read data from the decoder
752    pub fn read(
753        decoder: &mut BinDecoder<'_>,
754        record_type: RecordType,
755        length: Restrict<u16>,
756    ) -> ProtoResult<Self> {
757        let start_idx = decoder.index();
758
759        let result = match record_type {
760            RecordType::A => {
761                trace!("reading A");
762                A::read(decoder).map(Self::A)
763            }
764            RecordType::AAAA => {
765                trace!("reading AAAA");
766                AAAA::read(decoder).map(Self::AAAA)
767            }
768            RecordType::ANAME => {
769                trace!("reading ANAME");
770                ANAME::read(decoder).map(Self::ANAME)
771            }
772            rt @ RecordType::ANY | rt @ RecordType::AXFR | rt @ RecordType::IXFR => {
773                return Err(ProtoErrorKind::UnknownRecordTypeValue(rt.into()).into());
774            }
775            RecordType::CAA => {
776                trace!("reading CAA");
777                CAA::read_data(decoder, length).map(Self::CAA)
778            }
779            RecordType::CNAME => {
780                trace!("reading CNAME");
781                CNAME::read(decoder).map(Self::CNAME)
782            }
783            RecordType::CSYNC => {
784                trace!("reading CSYNC");
785                CSYNC::read_data(decoder, length).map(Self::CSYNC)
786            }
787            RecordType::HINFO => {
788                trace!("reading HINFO");
789                HINFO::read_data(decoder, length).map(Self::HINFO)
790            }
791            RecordType::HTTPS => {
792                trace!("reading HTTPS");
793                HTTPS::read_data(decoder, length).map(Self::HTTPS)
794            }
795            RecordType::ZERO => {
796                trace!("reading EMPTY");
797                // we should never get here, since ZERO should be 0 length, and None in the Record.
798                //   this invariant is verified below, and the decoding will fail with an err.
799                #[allow(deprecated)]
800                Ok(Self::ZERO)
801            }
802            RecordType::MX => {
803                trace!("reading MX");
804                MX::read_data(decoder, length).map(Self::MX)
805            }
806            RecordType::NAPTR => {
807                trace!("reading NAPTR");
808                NAPTR::read_data(decoder, length).map(Self::NAPTR)
809            }
810            RecordType::NULL => {
811                trace!("reading NULL");
812                NULL::read_data(decoder, length).map(Self::NULL)
813            }
814            RecordType::NS => {
815                trace!("reading NS");
816                NS::read(decoder).map(Self::NS)
817            }
818            RecordType::OPENPGPKEY => {
819                trace!("reading OPENPGPKEY");
820                OPENPGPKEY::read_data(decoder, length).map(Self::OPENPGPKEY)
821            }
822            RecordType::OPT => {
823                trace!("reading OPT");
824                OPT::read_data(decoder, length).map(Self::OPT)
825            }
826            RecordType::PTR => {
827                trace!("reading PTR");
828                PTR::read(decoder).map(Self::PTR)
829            }
830            RecordType::SOA => {
831                trace!("reading SOA");
832                SOA::read_data(decoder, length).map(Self::SOA)
833            }
834            RecordType::SRV => {
835                trace!("reading SRV");
836                SRV::read_data(decoder, length).map(Self::SRV)
837            }
838            RecordType::SSHFP => {
839                trace!("reading SSHFP");
840                SSHFP::read_data(decoder, length).map(Self::SSHFP)
841            }
842            RecordType::SVCB => {
843                trace!("reading SVCB");
844                SVCB::read_data(decoder, length).map(Self::SVCB)
845            }
846            RecordType::TLSA => {
847                trace!("reading TLSA");
848                TLSA::read_data(decoder, length).map(Self::TLSA)
849            }
850            RecordType::TXT => {
851                trace!("reading TXT");
852                TXT::read_data(decoder, length).map(Self::TXT)
853            }
854            #[cfg(feature = "dnssec")]
855            r if r.is_dnssec() => DNSSECRData::read(decoder, record_type, length).map(Self::DNSSEC),
856            record_type => {
857                trace!("reading Unknown record: {}", record_type);
858                NULL::read_data(decoder, length).map(|rdata| Self::Unknown {
859                    code: record_type,
860                    rdata,
861                })
862            }
863        };
864
865        // we should have read rdata_length, but we did not
866        let read = decoder.index() - start_idx;
867        length
868            .map(|u| u as usize)
869            .verify_unwrap(|rdata_length| read == *rdata_length)
870            .map_err(|rdata_length| {
871                ProtoError::from(ProtoErrorKind::IncorrectRDataLengthRead {
872                    read,
873                    len: rdata_length,
874                })
875            })?;
876
877        result
878    }
879}
880
881impl BinEncodable for RData {
882    /// [RFC 4034](https://tools.ietf.org/html/rfc4034#section-6), DNSSEC Resource Records, March 2005
883    ///
884    /// ```text
885    /// 6.2.  Canonical RR Form
886    ///
887    ///    For the purposes of DNS security, the canonical form of an RR is the
888    ///    wire format of the RR where:
889    ///
890    ///    ...
891    ///
892    ///    3.  if the type of the RR is NS, MD, MF, CNAME, SOA, MB, MG, MR, PTR,
893    ///        HINFO, MINFO, MX, HINFO, RP, AFSDB, RT, SIG, PX, NXT, NAPTR, KX,
894    ///        SRV, DNAME, A6, RRSIG, or (rfc6840 removes NSEC), all uppercase
895    ///        US-ASCII letters in the DNS names contained within the RDATA are replaced
896    ///        by the corresponding lowercase US-ASCII letters;
897    /// ```
898    ///
899    /// Canonical name form for all non-1035 records:
900    ///   [RFC 3579](https://tools.ietf.org/html/rfc3597)
901    /// ```text
902    ///  4.  Domain Name Compression
903    ///
904    ///   RRs containing compression pointers in the RDATA part cannot be
905    ///   treated transparently, as the compression pointers are only
906    ///   meaningful within the context of a DNS message.  Transparently
907    ///   copying the RDATA into a new DNS message would cause the compression
908    ///   pointers to point at the corresponding location in the new message,
909    ///   which now contains unrelated data.  This would cause the compressed
910    ///   name to be corrupted.
911    ///
912    ///   To avoid such corruption, servers MUST NOT compress domain names
913    ///   embedded in the RDATA of types that are class-specific or not well-
914    ///   known.  This requirement was stated in [RFC1123] without defining the
915    ///   term "well-known"; it is hereby specified that only the RR types
916    ///   defined in [RFC1035] are to be considered "well-known".
917    ///
918    ///   The specifications of a few existing RR types have explicitly allowed
919    ///   compression contrary to this specification: [RFC2163] specified that
920    ///   compression applies to the PX RR, and [RFC2535] allowed compression
921    ///   in SIG RRs and NXT RRs records.  Since this specification disallows
922    ///   compression in these cases, it is an update to [RFC2163] (section 4)
923    ///   and [RFC2535] (sections 4.1.7 and 5.2).
924    ///
925    ///   Receiving servers MUST decompress domain names in RRs of well-known
926    ///   type, and SHOULD also decompress RRs of type RP, AFSDB, RT, SIG, PX,
927    ///   NXT, NAPTR, and SRV (although the current specification of the SRV RR
928    ///   in [RFC2782] prohibits compression, [RFC2052] mandated it, and some
929    ///   servers following that earlier specification are still in use).
930    ///
931    ///   Future specifications for new RR types that contain domain names
932    ///   within their RDATA MUST NOT allow the use of name compression for
933    ///   those names, and SHOULD explicitly state that the embedded domain
934    ///   names MUST NOT be compressed.
935    ///
936    ///   As noted in [RFC1123], the owner name of an RR is always eligible for
937    ///   compression.
938    ///
939    ///   ...
940    ///   As a courtesy to implementors, it is hereby noted that the complete
941    ///    set of such previously published RR types that contain embedded
942    ///    domain names, and whose DNSSEC canonical form therefore involves
943    ///   downcasing according to the DNS rules for character comparisons,
944    ///   consists of the RR types NS, MD, MF, CNAME, SOA, MB, MG, MR, PTR,
945    ///   HINFO, MINFO, MX, HINFO, RP, AFSDB, RT, SIG, PX, NXT, NAPTR, KX, SRV,
946    ///   DNAME, and A6.
947    ///   ...
948    /// ```
949    fn emit(&self, encoder: &mut BinEncoder<'_>) -> ProtoResult<()> {
950        match *self {
951            Self::A(ref address) => address.emit(encoder),
952            Self::AAAA(ref address) => address.emit(encoder),
953            Self::ANAME(ref name) => encoder.with_canonical_names(|encoder| name.emit(encoder)),
954            Self::CAA(ref caa) => encoder.with_canonical_names(|encoder| caa.emit(encoder)),
955            Self::CNAME(ref cname) => cname.emit(encoder),
956            Self::NS(ref ns) => ns.emit(encoder),
957            Self::PTR(ref ptr) => ptr.emit(encoder),
958            Self::CSYNC(ref csync) => csync.emit(encoder),
959            Self::HINFO(ref hinfo) => hinfo.emit(encoder),
960            Self::HTTPS(ref https) => https.emit(encoder),
961            Self::ZERO => Ok(()),
962            Self::MX(ref mx) => mx.emit(encoder),
963            Self::NAPTR(ref naptr) => encoder.with_canonical_names(|encoder| naptr.emit(encoder)),
964            Self::NULL(ref null) => null.emit(encoder),
965            Self::OPENPGPKEY(ref openpgpkey) => {
966                encoder.with_canonical_names(|encoder| openpgpkey.emit(encoder))
967            }
968            Self::OPT(ref opt) => opt.emit(encoder),
969            Self::SOA(ref soa) => soa.emit(encoder),
970            Self::SRV(ref srv) => encoder.with_canonical_names(|encoder| srv.emit(encoder)),
971            Self::SSHFP(ref sshfp) => encoder.with_canonical_names(|encoder| sshfp.emit(encoder)),
972            Self::SVCB(ref svcb) => svcb.emit(encoder),
973            Self::TLSA(ref tlsa) => encoder.with_canonical_names(|encoder| tlsa.emit(encoder)),
974            Self::TXT(ref txt) => txt.emit(encoder),
975            #[cfg(feature = "dnssec")]
976            Self::DNSSEC(ref rdata) => encoder.with_canonical_names(|encoder| rdata.emit(encoder)),
977            Self::Unknown { ref rdata, .. } => rdata.emit(encoder),
978        }
979    }
980}
981
982impl RecordData for RData {
983    fn try_from_rdata(data: RData) -> Result<Self, RData> {
984        Ok(data)
985    }
986
987    fn try_borrow(data: &RData) -> Option<&Self> {
988        Some(data)
989    }
990
991    fn record_type(&self) -> RecordType {
992        self.record_type()
993    }
994
995    fn into_rdata(self) -> RData {
996        self
997    }
998}
999
1000impl fmt::Display for RData {
1001    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
1002        fn w<D: fmt::Display>(f: &mut fmt::Formatter<'_>, rdata: D) -> Result<(), fmt::Error> {
1003            write!(f, "{rdata}")
1004        }
1005
1006        match *self {
1007            Self::A(address) => w(f, address),
1008            Self::AAAA(ref address) => w(f, address),
1009            Self::ANAME(ref name) => w(f, name),
1010            Self::CAA(ref caa) => w(f, caa),
1011            // to_lowercase for rfc4034 and rfc6840
1012            Self::CNAME(ref cname) => w(f, cname),
1013            Self::NS(ref ns) => w(f, ns),
1014            Self::PTR(ref ptr) => w(f, ptr),
1015            Self::CSYNC(ref csync) => w(f, csync),
1016            Self::HINFO(ref hinfo) => w(f, hinfo),
1017            Self::HTTPS(ref https) => w(f, https),
1018            Self::ZERO => Ok(()),
1019            // to_lowercase for rfc4034 and rfc6840
1020            Self::MX(ref mx) => w(f, mx),
1021            Self::NAPTR(ref naptr) => w(f, naptr),
1022            Self::NULL(ref null) => w(f, null),
1023            Self::OPENPGPKEY(ref openpgpkey) => w(f, openpgpkey),
1024            // Opt has no display representation
1025            Self::OPT(_) => Err(fmt::Error),
1026            // to_lowercase for rfc4034 and rfc6840
1027            Self::SOA(ref soa) => w(f, soa),
1028            // to_lowercase for rfc4034 and rfc6840
1029            Self::SRV(ref srv) => w(f, srv),
1030            Self::SSHFP(ref sshfp) => w(f, sshfp),
1031            Self::SVCB(ref svcb) => w(f, svcb),
1032            Self::TLSA(ref tlsa) => w(f, tlsa),
1033            Self::TXT(ref txt) => w(f, txt),
1034            #[cfg(feature = "dnssec")]
1035            Self::DNSSEC(ref rdata) => w(f, rdata),
1036            Self::Unknown { ref rdata, .. } => w(f, rdata),
1037        }
1038    }
1039}
1040
1041impl PartialOrd<Self> for RData {
1042    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
1043        Some(self.cmp(other))
1044    }
1045}
1046
1047impl Ord for RData {
1048    // RFC 4034                DNSSEC Resource Records               March 2005
1049    //
1050    // 6.3.  Canonical RR Ordering within an RRset
1051    //
1052    //    For the purposes of DNS security, RRs with the same owner name,
1053    //    class, and type are sorted by treating the RDATA portion of the
1054    //    canonical form of each RR as a left-justified unsigned octet sequence
1055    //    in which the absence of an octet sorts before a zero octet.
1056    //
1057    //    [RFC2181] specifies that an RRset is not allowed to contain duplicate
1058    //    records (multiple RRs with the same owner name, class, type, and
1059    //    RDATA).  Therefore, if an implementation detects duplicate RRs when
1060    //    putting the RRset in canonical form, it MUST treat this as a protocol
1061    //    error.  If the implementation chooses to handle this protocol error
1062    //    in the spirit of the robustness principle (being liberal in what it
1063    //    accepts), it MUST remove all but one of the duplicate RR(s) for the
1064    //    purposes of calculating the canonical form of the RRset.
1065    fn cmp(&self, other: &Self) -> Ordering {
1066        // TODO: how about we just store the bytes with the decoded data?
1067        //  the decoded data is useful for queries, the encoded data is needed for transfers, signing
1068        //  and ordering.
1069        self.to_bytes().cmp(&other.to_bytes())
1070    }
1071}
1072
1073#[cfg(test)]
1074mod tests {
1075    #![allow(clippy::dbg_macro, clippy::print_stdout)]
1076
1077    use std::str::FromStr;
1078
1079    use super::*;
1080    use crate::rr::domain::Name;
1081    use crate::rr::rdata::{MX, SOA, SRV, TXT};
1082    use crate::serialize::binary::bin_tests::test_emit_data_set;
1083    #[allow(clippy::useless_attribute)]
1084    #[allow(unused)]
1085    use crate::serialize::binary::*;
1086
1087    fn get_data() -> Vec<(RData, Vec<u8>)> {
1088        vec![
1089            (
1090                RData::CNAME(CNAME(Name::from_str("www.example.com").unwrap())),
1091                vec![
1092                    3, b'w', b'w', b'w', 7, b'e', b'x', b'a', b'm', b'p', b'l', b'e', 3, b'c',
1093                    b'o', b'm', 0,
1094                ],
1095            ),
1096            (
1097                RData::MX(MX::new(256, Name::from_str("n").unwrap())),
1098                vec![1, 0, 1, b'n', 0],
1099            ),
1100            (
1101                RData::NS(NS(Name::from_str("www.example.com").unwrap())),
1102                vec![
1103                    3, b'w', b'w', b'w', 7, b'e', b'x', b'a', b'm', b'p', b'l', b'e', 3, b'c',
1104                    b'o', b'm', 0,
1105                ],
1106            ),
1107            (
1108                RData::PTR(PTR(Name::from_str("www.example.com").unwrap())),
1109                vec![
1110                    3, b'w', b'w', b'w', 7, b'e', b'x', b'a', b'm', b'p', b'l', b'e', 3, b'c',
1111                    b'o', b'm', 0,
1112                ],
1113            ),
1114            (
1115                RData::SOA(SOA::new(
1116                    Name::from_str("www.example.com").unwrap(),
1117                    Name::from_str("xxx.example.com").unwrap(),
1118                    u32::MAX,
1119                    -1,
1120                    -1,
1121                    -1,
1122                    u32::MAX,
1123                )),
1124                vec![
1125                    3, b'w', b'w', b'w', 7, b'e', b'x', b'a', b'm', b'p', b'l', b'e', 3, b'c',
1126                    b'o', b'm', 0, 3, b'x', b'x', b'x', 0xC0, 0x04, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
1127                    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
1128                    0xFF, 0xFF,
1129                ],
1130            ),
1131            (
1132                RData::TXT(TXT::new(vec![
1133                    "abcdef".to_string(),
1134                    "ghi".to_string(),
1135                    "".to_string(),
1136                    "j".to_string(),
1137                ])),
1138                vec![
1139                    6, b'a', b'b', b'c', b'd', b'e', b'f', 3, b'g', b'h', b'i', 0, 1, b'j',
1140                ],
1141            ),
1142            (RData::A(A::from_str("0.0.0.0").unwrap()), vec![0, 0, 0, 0]),
1143            (
1144                RData::AAAA(AAAA::from_str("::").unwrap()),
1145                vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
1146            ),
1147            (
1148                RData::SRV(SRV::new(
1149                    1,
1150                    2,
1151                    3,
1152                    Name::from_str("www.example.com").unwrap(),
1153                )),
1154                vec![
1155                    0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 3, b'w', b'w', b'w', 7, b'e', b'x', b'a',
1156                    b'm', b'p', b'l', b'e', 3, b'c', b'o', b'm', 0,
1157                ],
1158            ),
1159            (
1160                RData::HINFO(HINFO::new("cpu".to_string(), "os".to_string())),
1161                vec![3, b'c', b'p', b'u', 2, b'o', b's'],
1162            ),
1163        ]
1164    }
1165
1166    // TODO this test kinda sucks, shows the problem with not storing the binary parts
1167    #[test]
1168    fn test_order() {
1169        let ordered: Vec<RData> = vec![
1170            RData::A(A::from_str("0.0.0.0").unwrap()),
1171            RData::AAAA(AAAA::from_str("::").unwrap()),
1172            RData::SRV(SRV::new(
1173                1,
1174                2,
1175                3,
1176                Name::from_str("www.example.com").unwrap(),
1177            )),
1178            RData::MX(MX::new(256, Name::from_str("n").unwrap())),
1179            RData::CNAME(CNAME(Name::from_str("www.example.com").unwrap())),
1180            RData::PTR(PTR(Name::from_str("www.example.com").unwrap())),
1181            RData::NS(NS(Name::from_str("www.example.com").unwrap())),
1182            RData::SOA(SOA::new(
1183                Name::from_str("www.example.com").unwrap(),
1184                Name::from_str("xxx.example.com").unwrap(),
1185                u32::MAX,
1186                -1,
1187                -1,
1188                -1,
1189                u32::MAX,
1190            )),
1191            RData::TXT(TXT::new(vec![
1192                "abcdef".to_string(),
1193                "ghi".to_string(),
1194                "".to_string(),
1195                "j".to_string(),
1196            ])),
1197        ];
1198        let mut unordered = vec![
1199            RData::CNAME(CNAME(Name::from_str("www.example.com").unwrap())),
1200            RData::MX(MX::new(256, Name::from_str("n").unwrap())),
1201            RData::PTR(PTR(Name::from_str("www.example.com").unwrap())),
1202            RData::NS(NS(Name::from_str("www.example.com").unwrap())),
1203            RData::SOA(SOA::new(
1204                Name::from_str("www.example.com").unwrap(),
1205                Name::from_str("xxx.example.com").unwrap(),
1206                u32::MAX,
1207                -1,
1208                -1,
1209                -1,
1210                u32::MAX,
1211            )),
1212            RData::TXT(TXT::new(vec![
1213                "abcdef".to_string(),
1214                "ghi".to_string(),
1215                "".to_string(),
1216                "j".to_string(),
1217            ])),
1218            RData::A(A::from_str("0.0.0.0").unwrap()),
1219            RData::AAAA(AAAA::from_str("::").unwrap()),
1220            RData::SRV(SRV::new(
1221                1,
1222                2,
1223                3,
1224                Name::from_str("www.example.com").unwrap(),
1225            )),
1226        ];
1227
1228        unordered.sort();
1229        assert_eq!(ordered, unordered);
1230    }
1231
1232    #[test]
1233    fn test_read() {
1234        for (test_pass, (expect, binary)) in get_data().into_iter().enumerate() {
1235            println!("test {test_pass}: {binary:?}");
1236            let length = binary.len() as u16; // pre exclusive borrow
1237            let mut decoder = BinDecoder::new(&binary);
1238
1239            assert_eq!(
1240                RData::read(
1241                    &mut decoder,
1242                    record_type_from_rdata(&expect),
1243                    Restrict::new(length)
1244                )
1245                .unwrap(),
1246                expect
1247            );
1248        }
1249    }
1250
1251    fn record_type_from_rdata(rdata: &RData) -> crate::rr::record_type::RecordType {
1252        match *rdata {
1253            RData::A(..) => RecordType::A,
1254            RData::AAAA(..) => RecordType::AAAA,
1255            RData::ANAME(..) => RecordType::ANAME,
1256            RData::CAA(..) => RecordType::CAA,
1257            RData::CNAME(..) => RecordType::CNAME,
1258            RData::CSYNC(..) => RecordType::CSYNC,
1259            RData::HINFO(..) => RecordType::HINFO,
1260            RData::HTTPS(..) => RecordType::HTTPS,
1261            RData::MX(..) => RecordType::MX,
1262            RData::NAPTR(..) => RecordType::NAPTR,
1263            RData::NS(..) => RecordType::NS,
1264            RData::NULL(..) => RecordType::NULL,
1265            RData::OPENPGPKEY(..) => RecordType::OPENPGPKEY,
1266            RData::OPT(..) => RecordType::OPT,
1267            RData::PTR(..) => RecordType::PTR,
1268            RData::SOA(..) => RecordType::SOA,
1269            RData::SRV(..) => RecordType::SRV,
1270            RData::SSHFP(..) => RecordType::SSHFP,
1271            RData::SVCB(..) => RecordType::SVCB,
1272            RData::TLSA(..) => RecordType::TLSA,
1273            RData::TXT(..) => RecordType::TXT,
1274            #[cfg(feature = "dnssec")]
1275            RData::DNSSEC(ref rdata) => rdata.to_record_type(),
1276            RData::Unknown { code, .. } => code,
1277            RData::ZERO => RecordType::ZERO,
1278        }
1279    }
1280
1281    #[test]
1282    fn test_write_to() {
1283        test_emit_data_set(get_data(), |e, d| d.emit(e));
1284    }
1285}