Skip to main content

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