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::DNAME => return Err(ParseError::UnsupportedRecordType(record_type)),
1072            RecordType::HINFO => Self::HINFO(HINFO::from_tokens(tokens)?),
1073            RecordType::HTTPS => Self::HTTPS(HTTPS(SVCB::from_tokens(tokens)?)),
1074            RecordType::IXFR => return Err(ParseError::from("parsing IXFR doesn't make sense")),
1075            RecordType::MX => Self::MX(MX::from_tokens(tokens, origin)?),
1076            RecordType::NAPTR => Self::NAPTR(NAPTR::from_tokens(tokens, origin)?),
1077            RecordType::NULL => {
1078                return Err(ParseError::Message(
1079                    "parse is not implemented for NULL record",
1080                ));
1081            }
1082            RecordType::NS => Self::NS(NS(Name::from_tokens(tokens, origin)?)),
1083            RecordType::OPENPGPKEY => Self::OPENPGPKEY(OPENPGPKEY::from_tokens(tokens)?),
1084            RecordType::OPT => return Err(ParseError::from("parsing OPT doesn't make sense")),
1085            RecordType::PTR => Self::PTR(PTR(Name::from_tokens(tokens, origin)?)),
1086            RecordType::SMIMEA => Self::SMIMEA(SMIMEA::from_tokens(tokens)?),
1087            RecordType::SOA => Self::SOA(SOA::from_tokens(tokens, origin)?),
1088            RecordType::SRV => Self::SRV(SRV::from_tokens(tokens, origin)?),
1089            RecordType::SSHFP => Self::SSHFP(SSHFP::from_tokens(tokens)?),
1090            RecordType::SVCB => Self::SVCB(SVCB::from_tokens(tokens)?),
1091            RecordType::TLSA => Self::TLSA(TLSA::from_tokens(tokens)?),
1092            RecordType::TXT => Self::TXT(TXT::from_tokens(tokens)?),
1093            RecordType::SIG => return Err(ParseError::from("parsing SIG doesn't make sense")),
1094            RecordType::DNSKEY => {
1095                return Err(ParseError::from("DNSKEY should be dynamically generated"));
1096            }
1097            RecordType::CDNSKEY => {
1098                return Err(ParseError::from("CDNSKEY should be dynamically generated"));
1099            }
1100            RecordType::KEY => return Err(ParseError::from("KEY should be dynamically generated")),
1101            #[cfg(feature = "__dnssec")]
1102            RecordType::DS => Self::DNSSEC(DNSSECRData::DS(DS::from_tokens(tokens)?)),
1103            #[cfg(not(feature = "__dnssec"))]
1104            RecordType::DS => return Err(ParseError::from("DS should be dynamically generated")),
1105            RecordType::CDS => return Err(ParseError::from("CDS should be dynamically generated")),
1106            RecordType::NSEC => {
1107                return Err(ParseError::from("NSEC should be dynamically generated"));
1108            }
1109            RecordType::NSEC3 => {
1110                return Err(ParseError::from("NSEC3 should be dynamically generated"));
1111            }
1112            RecordType::NSEC3PARAM => {
1113                return Err(ParseError::from(
1114                    "NSEC3PARAM should be dynamically generated",
1115                ));
1116            }
1117            RecordType::RRSIG => {
1118                return Err(ParseError::from("RRSIG should be dynamically generated"));
1119            }
1120            RecordType::TSIG => return Err(ParseError::from("TSIG is only used during AXFR")),
1121            #[allow(deprecated)]
1122            RecordType::ZERO => Self::ZERO,
1123            r @ RecordType::Unknown(..) => {
1124                // TODO: add a way to associate generic record types to the zone
1125                return Err(ParseError::UnsupportedRecordType(r));
1126            }
1127        };
1128
1129        Ok(rdata)
1130    }
1131}
1132
1133impl BinEncodable for RData {
1134    /// [RFC 4034](https://tools.ietf.org/html/rfc4034#section-6), DNSSEC Resource Records, March 2005
1135    ///
1136    /// ```text
1137    /// 6.2.  Canonical RR Form
1138    ///
1139    ///    For the purposes of DNS security, the canonical form of an RR is the
1140    ///    wire format of the RR where:
1141    ///
1142    ///    ...
1143    ///
1144    ///    3.  if the type of the RR is NS, MD, MF, CNAME, SOA, MB, MG, MR, PTR,
1145    ///        HINFO, MINFO, MX, HINFO, RP, AFSDB, RT, SIG, PX, NXT, NAPTR, KX,
1146    ///        SRV, DNAME, A6, RRSIG, or (rfc6840 removes NSEC), all uppercase
1147    ///        US-ASCII letters in the DNS names contained within the RDATA are replaced
1148    ///        by the corresponding lowercase US-ASCII letters;
1149    /// ```
1150    ///
1151    /// Canonical name form for all non-1035 records:
1152    ///   [RFC 3597](https://tools.ietf.org/html/rfc3597)
1153    /// ```text
1154    ///  4.  Domain Name Compression
1155    ///
1156    ///   RRs containing compression pointers in the RDATA part cannot be
1157    ///   treated transparently, as the compression pointers are only
1158    ///   meaningful within the context of a DNS message.  Transparently
1159    ///   copying the RDATA into a new DNS message would cause the compression
1160    ///   pointers to point at the corresponding location in the new message,
1161    ///   which now contains unrelated data.  This would cause the compressed
1162    ///   name to be corrupted.
1163    ///
1164    ///   To avoid such corruption, servers MUST NOT compress domain names
1165    ///   embedded in the RDATA of types that are class-specific or not well-
1166    ///   known.  This requirement was stated in [RFC1123] without defining the
1167    ///   term "well-known"; it is hereby specified that only the RR types
1168    ///   defined in [RFC1035] are to be considered "well-known".
1169    ///
1170    ///   The specifications of a few existing RR types have explicitly allowed
1171    ///   compression contrary to this specification: [RFC2163] specified that
1172    ///   compression applies to the PX RR, and [RFC2535] allowed compression
1173    ///   in SIG RRs and NXT RRs records.  Since this specification disallows
1174    ///   compression in these cases, it is an update to [RFC2163] (section 4)
1175    ///   and [RFC2535] (sections 4.1.7 and 5.2).
1176    ///
1177    ///   Receiving servers MUST decompress domain names in RRs of well-known
1178    ///   type, and SHOULD also decompress RRs of type RP, AFSDB, RT, SIG, PX,
1179    ///   NXT, NAPTR, and SRV (although the current specification of the SRV RR
1180    ///   in [RFC2782] prohibits compression, [RFC2052] mandated it, and some
1181    ///   servers following that earlier specification are still in use).
1182    ///
1183    ///   Future specifications for new RR types that contain domain names
1184    ///   within their RDATA MUST NOT allow the use of name compression for
1185    ///   those names, and SHOULD explicitly state that the embedded domain
1186    ///   names MUST NOT be compressed.
1187    ///
1188    ///   As noted in [RFC1123], the owner name of an RR is always eligible for
1189    ///   compression.
1190    ///
1191    ///   ...
1192    ///   As a courtesy to implementors, it is hereby noted that the complete
1193    ///    set of such previously published RR types that contain embedded
1194    ///    domain names, and whose DNSSEC canonical form therefore involves
1195    ///   downcasing according to the DNS rules for character comparisons,
1196    ///   consists of the RR types NS, MD, MF, CNAME, SOA, MB, MG, MR, PTR,
1197    ///   HINFO, MINFO, MX, HINFO, RP, AFSDB, RT, SIG, PX, NXT, NAPTR, KX, SRV,
1198    ///   DNAME, and A6.
1199    ///   ...
1200    /// ```
1201    fn emit(&self, encoder: &mut BinEncoder<'_>) -> ProtoResult<()> {
1202        match self {
1203            Self::A(address) => address.emit(encoder),
1204            Self::AAAA(address) => address.emit(encoder),
1205            Self::ANAME(name) => name.emit(encoder),
1206            Self::CAA(caa) => caa.emit(encoder),
1207            Self::CERT(cert) => cert.emit(encoder),
1208            Self::CNAME(cname) => cname.emit(encoder),
1209            Self::NS(ns) => ns.emit(encoder),
1210            Self::PTR(ptr) => ptr.emit(encoder),
1211            Self::CSYNC(csync) => csync.emit(encoder),
1212            Self::HINFO(hinfo) => hinfo.emit(encoder),
1213            Self::HTTPS(https) => https.emit(encoder),
1214            Self::ZERO => Ok(()),
1215            Self::MX(mx) => mx.emit(encoder),
1216            Self::NAPTR(naptr) => naptr.emit(encoder),
1217            Self::NULL(null) => null.emit(encoder),
1218            Self::OPENPGPKEY(openpgpkey) => openpgpkey.emit(encoder),
1219            Self::OPT(opt) => opt.emit(encoder),
1220            Self::SMIMEA(opt) => opt.emit(encoder),
1221            Self::SOA(soa) => soa.emit(encoder),
1222            Self::SRV(srv) => srv.emit(encoder),
1223            Self::SSHFP(sshfp) => sshfp.emit(encoder),
1224            Self::SVCB(svcb) => svcb.emit(encoder),
1225            Self::TLSA(tlsa) => tlsa.emit(encoder),
1226            Self::TSIG(tsig) => tsig.emit(encoder),
1227            Self::TXT(txt) => txt.emit(encoder),
1228            #[cfg(feature = "__dnssec")]
1229            Self::DNSSEC(rdata) => rdata.emit(encoder),
1230            Self::Unknown { rdata, .. } => rdata.emit(encoder),
1231            Self::Update0(_) => Ok(()),
1232        }
1233    }
1234}
1235
1236impl RecordData for RData {
1237    fn try_borrow(data: &RData) -> Option<&Self> {
1238        Some(data)
1239    }
1240
1241    fn record_type(&self) -> RecordType {
1242        self.record_type()
1243    }
1244
1245    fn into_rdata(self) -> RData {
1246        self
1247    }
1248
1249    fn is_update(&self) -> bool {
1250        matches!(self, RData::Update0(_))
1251    }
1252}
1253
1254impl fmt::Display for RData {
1255    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
1256        fn w<D: fmt::Display>(f: &mut fmt::Formatter<'_>, rdata: D) -> Result<(), fmt::Error> {
1257            write!(f, "{rdata}")
1258        }
1259
1260        match self {
1261            Self::A(address) => w(f, address),
1262            Self::AAAA(address) => w(f, address),
1263            Self::ANAME(name) => w(f, name),
1264            Self::CAA(caa) => w(f, caa),
1265            Self::CERT(cert) => w(f, cert),
1266            // to_lowercase for rfc4034 and rfc6840
1267            Self::CNAME(cname) => w(f, cname),
1268            Self::NS(ns) => w(f, ns),
1269            Self::PTR(ptr) => w(f, ptr),
1270            Self::CSYNC(csync) => w(f, csync),
1271            Self::HINFO(hinfo) => w(f, hinfo),
1272            Self::HTTPS(https) => w(f, https),
1273            Self::ZERO => Ok(()),
1274            // to_lowercase for rfc4034 and rfc6840
1275            Self::MX(mx) => w(f, mx),
1276            Self::NAPTR(naptr) => w(f, naptr),
1277            Self::NULL(null) => w(f, null),
1278            Self::OPENPGPKEY(openpgpkey) => w(f, openpgpkey),
1279            // Opt has no display representation
1280            Self::OPT(_) => Err(fmt::Error),
1281            Self::SMIMEA(smimea) => w(f, smimea),
1282            // to_lowercase for rfc4034 and rfc6840
1283            Self::SOA(soa) => w(f, soa),
1284            // to_lowercase for rfc4034 and rfc6840
1285            Self::SRV(srv) => w(f, srv),
1286            Self::SSHFP(sshfp) => w(f, sshfp),
1287            Self::SVCB(svcb) => w(f, svcb),
1288            Self::TLSA(tlsa) => w(f, tlsa),
1289            Self::TSIG(tsig) => w(f, tsig),
1290            Self::TXT(txt) => w(f, txt),
1291            #[cfg(feature = "__dnssec")]
1292            Self::DNSSEC(rdata) => w(f, rdata),
1293            Self::Unknown { rdata, .. } => w(f, rdata),
1294            Self::Update0(_) => w(f, "UPDATE"),
1295        }
1296    }
1297}
1298
1299impl PartialOrd<Self> for RData {
1300    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
1301        Some(self.cmp(other))
1302    }
1303}
1304
1305impl Ord for RData {
1306    // RFC 4034                DNSSEC Resource Records               March 2005
1307    //
1308    // 6.3.  Canonical RR Ordering within an RRset
1309    //
1310    //    For the purposes of DNS security, RRs with the same owner name,
1311    //    class, and type are sorted by treating the RDATA portion of the
1312    //    canonical form of each RR as a left-justified unsigned octet sequence
1313    //    in which the absence of an octet sorts before a zero octet.
1314    //
1315    //    [RFC2181] specifies that an RRset is not allowed to contain duplicate
1316    //    records (multiple RRs with the same owner name, class, type, and
1317    //    RDATA).  Therefore, if an implementation detects duplicate RRs when
1318    //    putting the RRset in canonical form, it MUST treat this as a protocol
1319    //    error.  If the implementation chooses to handle this protocol error
1320    //    in the spirit of the robustness principle (being liberal in what it
1321    //    accepts), it MUST remove all but one of the duplicate RR(s) for the
1322    //    purposes of calculating the canonical form of the RRset.
1323    fn cmp(&self, other: &Self) -> Ordering {
1324        // TODO: how about we just store the bytes with the decoded data?
1325        //  the decoded data is useful for queries, the encoded data is needed for transfers, signing
1326        //  and ordering.
1327        self.to_bytes().cmp(&other.to_bytes())
1328    }
1329}
1330
1331impl From<IpAddr> for RData {
1332    fn from(ip: IpAddr) -> Self {
1333        match ip {
1334            IpAddr::V4(ip) => RData::A(A(ip)),
1335            IpAddr::V6(ip) => RData::AAAA(AAAA(ip)),
1336        }
1337    }
1338}
1339
1340impl From<Ipv4Addr> for RData {
1341    fn from(ip: Ipv4Addr) -> Self {
1342        RData::A(A(ip))
1343    }
1344}
1345
1346impl From<Ipv6Addr> for RData {
1347    fn from(ip: Ipv6Addr) -> Self {
1348        RData::AAAA(AAAA(ip))
1349    }
1350}
1351
1352#[cfg(test)]
1353mod tests {
1354    #![allow(clippy::dbg_macro, clippy::print_stdout)]
1355
1356    use alloc::string::ToString;
1357    use core::str::FromStr;
1358    #[cfg(feature = "std")]
1359    use std::println;
1360
1361    use super::*;
1362    use crate::rr::domain::Name;
1363    use crate::rr::rdata::{MX, SOA, SRV, TXT};
1364    use crate::serialize::binary::bin_tests::test_emit_data_set;
1365
1366    fn get_data() -> Vec<(RData, Vec<u8>)> {
1367        vec![
1368            (
1369                RData::CNAME(CNAME(Name::from_str("www.example.com.").unwrap())),
1370                vec![
1371                    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',
1372                    b'o', b'm', 0,
1373                ],
1374            ),
1375            (
1376                RData::MX(MX::new(256, Name::from_str("n.").unwrap())),
1377                vec![1, 0, 1, b'n', 0],
1378            ),
1379            (
1380                RData::NS(NS(Name::from_str("www.example.com.").unwrap())),
1381                vec![
1382                    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',
1383                    b'o', b'm', 0,
1384                ],
1385            ),
1386            (
1387                RData::PTR(PTR(Name::from_str("www.example.com.").unwrap())),
1388                vec![
1389                    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',
1390                    b'o', b'm', 0,
1391                ],
1392            ),
1393            (
1394                RData::SOA(SOA::new(
1395                    Name::from_str("www.example.com.").unwrap(),
1396                    Name::from_str("xxx.example.com.").unwrap(),
1397                    u32::MAX,
1398                    -1,
1399                    -1,
1400                    -1,
1401                    u32::MAX,
1402                )),
1403                vec![
1404                    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',
1405                    b'o', b'm', 0, 3, b'x', b'x', b'x', 0xC0, 0x04, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
1406                    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
1407                    0xFF, 0xFF,
1408                ],
1409            ),
1410            (
1411                RData::TXT(TXT::new(vec![
1412                    "abcdef".to_string(),
1413                    "ghi".to_string(),
1414                    "".to_string(),
1415                    "j".to_string(),
1416                ])),
1417                vec![
1418                    6, b'a', b'b', b'c', b'd', b'e', b'f', 3, b'g', b'h', b'i', 0, 1, b'j',
1419                ],
1420            ),
1421            (RData::A(A::from(Ipv4Addr::UNSPECIFIED)), vec![0, 0, 0, 0]),
1422            (
1423                RData::AAAA(AAAA::from(Ipv6Addr::UNSPECIFIED)),
1424                vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
1425            ),
1426            (
1427                RData::SRV(SRV::new(
1428                    1,
1429                    2,
1430                    3,
1431                    Name::from_str("www.example.com.").unwrap(),
1432                )),
1433                vec![
1434                    0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 3, b'w', b'w', b'w', 7, b'e', b'x', b'a',
1435                    b'm', b'p', b'l', b'e', 3, b'c', b'o', b'm', 0,
1436                ],
1437            ),
1438            (
1439                RData::HINFO(HINFO::new("cpu".to_string(), "os".to_string())),
1440                vec![3, b'c', b'p', b'u', 2, b'o', b's'],
1441            ),
1442        ]
1443    }
1444
1445    // TODO this test kinda sucks, shows the problem with not storing the binary parts
1446    #[test]
1447    fn test_order() {
1448        let ordered: Vec<RData> = vec![
1449            RData::A(A::from(Ipv4Addr::UNSPECIFIED)),
1450            RData::AAAA(AAAA::from(Ipv6Addr::UNSPECIFIED)),
1451            RData::SRV(SRV::new(
1452                1,
1453                2,
1454                3,
1455                Name::from_str("www.example.com").unwrap(),
1456            )),
1457            RData::MX(MX::new(256, Name::from_str("n").unwrap())),
1458            RData::CNAME(CNAME(Name::from_str("www.example.com").unwrap())),
1459            RData::PTR(PTR(Name::from_str("www.example.com").unwrap())),
1460            RData::NS(NS(Name::from_str("www.example.com").unwrap())),
1461            RData::SOA(SOA::new(
1462                Name::from_str("www.example.com").unwrap(),
1463                Name::from_str("xxx.example.com").unwrap(),
1464                u32::MAX,
1465                -1,
1466                -1,
1467                -1,
1468                u32::MAX,
1469            )),
1470            RData::TXT(TXT::new(vec![
1471                "abcdef".to_string(),
1472                "ghi".to_string(),
1473                "".to_string(),
1474                "j".to_string(),
1475            ])),
1476        ];
1477        let mut unordered = vec![
1478            RData::CNAME(CNAME(Name::from_str("www.example.com").unwrap())),
1479            RData::MX(MX::new(256, Name::from_str("n").unwrap())),
1480            RData::PTR(PTR(Name::from_str("www.example.com").unwrap())),
1481            RData::NS(NS(Name::from_str("www.example.com").unwrap())),
1482            RData::SOA(SOA::new(
1483                Name::from_str("www.example.com").unwrap(),
1484                Name::from_str("xxx.example.com").unwrap(),
1485                u32::MAX,
1486                -1,
1487                -1,
1488                -1,
1489                u32::MAX,
1490            )),
1491            RData::TXT(TXT::new(vec![
1492                "abcdef".to_string(),
1493                "ghi".to_string(),
1494                "".to_string(),
1495                "j".to_string(),
1496            ])),
1497            RData::A(A::from(Ipv4Addr::UNSPECIFIED)),
1498            RData::AAAA(AAAA::from(Ipv6Addr::UNSPECIFIED)),
1499            RData::SRV(SRV::new(
1500                1,
1501                2,
1502                3,
1503                Name::from_str("www.example.com").unwrap(),
1504            )),
1505        ];
1506
1507        unordered.sort();
1508        assert_eq!(ordered, unordered);
1509    }
1510
1511    #[test]
1512    #[cfg_attr(not(feature = "std"), expect(clippy::unused_enumerate_index))]
1513    fn test_read() {
1514        for (_test_pass, (expect, binary)) in get_data().into_iter().enumerate() {
1515            #[cfg(feature = "std")]
1516            println!("test {_test_pass}: {binary:?}");
1517            let length = binary.len() as u16; // pre exclusive borrow
1518            let mut decoder = BinDecoder::new(&binary);
1519
1520            assert_eq!(
1521                RData::read(
1522                    &mut decoder,
1523                    record_type_from_rdata(&expect),
1524                    Restrict::new(length)
1525                )
1526                .unwrap(),
1527                expect
1528            );
1529        }
1530    }
1531
1532    fn record_type_from_rdata(rdata: &RData) -> RecordType {
1533        match rdata {
1534            RData::A(..) => RecordType::A,
1535            RData::AAAA(..) => RecordType::AAAA,
1536            RData::ANAME(..) => RecordType::ANAME,
1537            RData::CAA(..) => RecordType::CAA,
1538            RData::CERT(..) => RecordType::CERT,
1539            RData::CNAME(..) => RecordType::CNAME,
1540            RData::CSYNC(..) => RecordType::CSYNC,
1541            RData::HINFO(..) => RecordType::HINFO,
1542            RData::HTTPS(..) => RecordType::HTTPS,
1543            RData::MX(..) => RecordType::MX,
1544            RData::NAPTR(..) => RecordType::NAPTR,
1545            RData::NS(..) => RecordType::NS,
1546            RData::NULL(..) => RecordType::NULL,
1547            RData::OPENPGPKEY(..) => RecordType::OPENPGPKEY,
1548            RData::OPT(..) => RecordType::OPT,
1549            RData::PTR(..) => RecordType::PTR,
1550            RData::SMIMEA(..) => RecordType::SMIMEA,
1551            RData::SOA(..) => RecordType::SOA,
1552            RData::SRV(..) => RecordType::SRV,
1553            RData::SSHFP(..) => RecordType::SSHFP,
1554            RData::SVCB(..) => RecordType::SVCB,
1555            RData::TLSA(..) => RecordType::TLSA,
1556            RData::TSIG(..) => RecordType::TSIG,
1557            RData::TXT(..) => RecordType::TXT,
1558            #[cfg(feature = "__dnssec")]
1559            RData::DNSSEC(rdata) => rdata.to_record_type(),
1560            RData::Unknown { code, .. } => *code,
1561            RData::Update0(record_type) => *record_type,
1562            RData::ZERO => RecordType::ZERO,
1563        }
1564    }
1565
1566    #[test]
1567    fn test_write_to() {
1568        test_emit_data_set(get_data(), |e, d| d.emit(e));
1569    }
1570
1571    #[test]
1572    fn test_a() {
1573        let tokens = ["192.168.0.1"];
1574        let name = Name::from_str("example.com.").unwrap();
1575        let record =
1576            RData::from_tokens(RecordType::A, tokens.iter().map(AsRef::as_ref), Some(&name))
1577                .unwrap();
1578
1579        assert_eq!(record, RData::A("192.168.0.1".parse().unwrap()));
1580    }
1581
1582    #[test]
1583    fn test_a_parse() {
1584        let data = "192.168.0.1";
1585        let record = RData::try_from_str(RecordType::A, data).unwrap();
1586
1587        assert_eq!(record, RData::A("192.168.0.1".parse().unwrap()));
1588    }
1589
1590    #[test]
1591    fn test_aaaa() {
1592        let tokens = ["::1"];
1593        let name = Name::from_str("example.com.").unwrap();
1594        let record = RData::from_tokens(
1595            RecordType::AAAA,
1596            tokens.iter().map(AsRef::as_ref),
1597            Some(&name),
1598        )
1599        .unwrap();
1600
1601        assert_eq!(record, RData::AAAA("::1".parse().unwrap()));
1602    }
1603
1604    #[test]
1605    fn test_aaaa_parse() {
1606        let data = "::1";
1607        let record = RData::try_from_str(RecordType::AAAA, data).unwrap();
1608
1609        assert_eq!(record, RData::AAAA("::1".parse().unwrap()));
1610    }
1611
1612    #[test]
1613    fn test_ns_parse() {
1614        let data = "ns.example.com";
1615        let record = RData::try_from_str(RecordType::NS, data).unwrap();
1616
1617        assert_eq!(
1618            record,
1619            RData::NS(NS(Name::from_str("ns.example.com").unwrap()))
1620        );
1621    }
1622
1623    #[test]
1624    fn test_csync() {
1625        let tokens = ["123", "1", "A", "NS"];
1626        let name = Name::from_str("example.com.").unwrap();
1627        let record = RData::from_tokens(
1628            RecordType::CSYNC,
1629            tokens.iter().map(AsRef::as_ref),
1630            Some(&name),
1631        )
1632        .unwrap();
1633
1634        assert_eq!(
1635            record,
1636            RData::CSYNC(CSYNC::new(
1637                123,
1638                true,
1639                false,
1640                [RecordType::A, RecordType::NS]
1641            ))
1642        );
1643    }
1644
1645    #[test]
1646    fn test_csync_parse() {
1647        let data = "123 1 A NS";
1648        let record = RData::try_from_str(RecordType::CSYNC, data).unwrap();
1649
1650        assert_eq!(
1651            record,
1652            RData::CSYNC(CSYNC::new(
1653                123,
1654                true,
1655                false,
1656                [RecordType::A, RecordType::NS]
1657            ))
1658        );
1659    }
1660
1661    #[cfg(feature = "__dnssec")]
1662    #[test]
1663    #[allow(deprecated)]
1664    fn test_ds() {
1665        let tokens = [
1666            "60485",
1667            "5",
1668            "1",
1669            "2BB183AF5F22588179A53B0A",
1670            "98631FAD1A292118",
1671        ];
1672        let name = Name::from_str("dskey.example.com.").unwrap();
1673        let record = RData::from_tokens(
1674            RecordType::DS,
1675            tokens.iter().map(AsRef::as_ref),
1676            Some(&name),
1677        )
1678        .unwrap();
1679
1680        assert_eq!(
1681            record,
1682            RData::DNSSEC(DNSSECRData::DS(DS::new(
1683                60485,
1684                crate::dnssec::Algorithm::RSASHA1,
1685                crate::dnssec::DigestType::SHA1,
1686                vec![
1687                    0x2B, 0xB1, 0x83, 0xAF, 0x5F, 0x22, 0x58, 0x81, 0x79, 0xA5, 0x3B, 0x0A, 0x98,
1688                    0x63, 0x1F, 0xAD, 0x1A, 0x29, 0x21, 0x18
1689                ]
1690            )))
1691        );
1692    }
1693
1694    #[test]
1695    fn test_any() {
1696        let tokens = ["test"];
1697        let name = Name::from_str("example.com.").unwrap();
1698        let result = RData::from_tokens(
1699            RecordType::ANY,
1700            tokens.iter().map(AsRef::as_ref),
1701            Some(&name),
1702        );
1703
1704        assert!(result.is_err());
1705    }
1706
1707    #[test]
1708    fn test_dynamically_generated() {
1709        let dynamically_generated = vec![
1710            RecordType::DS,
1711            RecordType::CDS,
1712            RecordType::DNSKEY,
1713            RecordType::CDNSKEY,
1714            RecordType::KEY,
1715            RecordType::NSEC,
1716            RecordType::NSEC3,
1717            RecordType::NSEC3PARAM,
1718            RecordType::RRSIG,
1719        ];
1720
1721        let tokens = ["test"];
1722
1723        let name = Name::from_str("example.com.").unwrap();
1724
1725        for record_type in dynamically_generated {
1726            let result =
1727                RData::from_tokens(record_type, tokens.iter().map(AsRef::as_ref), Some(&name));
1728            assert!(result.is_err());
1729        }
1730    }
1731}