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