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