Skip to main content

forgedns_proto/
types.rs

1/*
2 * SPDX-FileCopyrightText: 2025 Sven Shi
3 * SPDX-License-Identifier: GPL-3.0-or-later
4 */
5
6//! DNS enums used by the owned message model.
7
8use crate::core::error::{DnsError, Result as DnsResult};
9use std::fmt;
10use std::fmt::{Display, Formatter};
11use std::str::FromStr;
12
13/// DNS message direction.
14#[derive(Debug, Eq, PartialEq, PartialOrd, Copy, Clone, Hash)]
15pub enum MessageType {
16    /// Query message sent by a client or intermediate resolver.
17    Query,
18    /// Response message sent back to the requester.
19    Response,
20}
21
22/// DNS operation code.
23#[derive(Debug, PartialEq, Eq, PartialOrd, Copy, Clone, Hash)]
24#[allow(dead_code)]
25pub enum Opcode {
26    /// Query request [RFC 1035](https://tools.ietf.org/html/rfc1035)
27    Query,
28
29    /// Inverse query (obsolete) [RFC 3425]
30    IQuery,
31
32    /// Status message [RFC 1035](https://tools.ietf.org/html/rfc1035)
33    Status,
34
35    /// Notify of change [RFC 1996](https://tools.ietf.org/html/rfc1996)
36    Notify,
37
38    /// Update message [RFC 2136](https://tools.ietf.org/html/rfc2136)
39    Update,
40
41    /// Any other opcode
42    Unknown(u8),
43}
44
45impl Display for Opcode {
46    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
47        match self {
48            Self::Query => f.write_str("QUERY"),
49            Self::IQuery => f.write_str("IQUERY"),
50            Self::Status => f.write_str("STATUS"),
51            Self::Notify => f.write_str("NOTIFY"),
52            Self::Update => f.write_str("UPDATE"),
53            Self::Unknown(opcode) => write!(f, "Unknown opcode ({opcode})"),
54        }
55    }
56}
57
58/// Convert from `OpCode` to `u8`
59impl From<Opcode> for u8 {
60    fn from(rt: Opcode) -> Self {
61        match rt {
62            Opcode::Query => 0,
63            Opcode::IQuery => 1,
64            // 1	IQuery (Inverse Query, OBSOLETE)	[RFC3425]
65            Opcode::Status => 2,
66            // 3	Unassigned
67            Opcode::Notify => 4,
68            Opcode::Update => 5,
69            // 6-15	Unassigned
70            Opcode::Unknown(opcode) => opcode,
71        }
72    }
73}
74
75/// Convert from `u8` to `OpCode`
76impl From<u8> for Opcode {
77    fn from(value: u8) -> Self {
78        match value {
79            0 => Self::Query,
80            1 => Self::IQuery,
81            2 => Self::Status,
82            4 => Self::Notify,
83            5 => Self::Update,
84            _ => Self::Unknown(value),
85        }
86    }
87}
88
89#[derive(Debug, Eq, PartialEq, PartialOrd, Copy, Clone, Hash, Default)]
90#[allow(dead_code)]
91pub enum Rcode {
92    /// No Error [RFC 1035](https://tools.ietf.org/html/rfc1035)
93    #[default]
94    NoError,
95
96    /// Format Error [RFC 1035](https://tools.ietf.org/html/rfc1035)
97    FormErr,
98
99    /// Server Failure [RFC 1035](https://tools.ietf.org/html/rfc1035)
100    ServFail,
101
102    /// Non-Existent Domain [RFC 1035](https://tools.ietf.org/html/rfc1035)
103    NXDomain,
104
105    /// Not Implemented [RFC 1035](https://tools.ietf.org/html/rfc1035)
106    NotImp,
107
108    /// Query Refused [RFC 1035](https://tools.ietf.org/html/rfc1035)
109    Refused,
110
111    /// Name Exists when it should not [RFC 2136](https://tools.ietf.org/html/rfc2136)
112    YXDomain,
113
114    /// RR Set Exists when it should not [RFC 2136](https://tools.ietf.org/html/rfc2136)
115    YXRRSet,
116
117    /// RR Set that should exist does not [RFC 2136](https://tools.ietf.org/html/rfc2136)
118    NXRRSet,
119
120    /// Server Not Authoritative for zone [RFC 2136](https://tools.ietf.org/html/rfc2136)
121    /// or Not Authorized [RFC 8945](https://www.rfc-editor.org/rfc/rfc8945)
122    NotAuth,
123
124    /// Name not contained in zone [RFC 2136](https://tools.ietf.org/html/rfc2136)
125    NotZone,
126
127    /// Bad OPT Version [RFC 6891](https://tools.ietf.org/html/rfc6891#section-9)
128    BADVERS,
129
130    /// TSIG Signature Failure [RFC 8945](https://www.rfc-editor.org/rfc/rfc8945)
131    BADSIG,
132
133    /// Key not recognized [RFC 8945](https://www.rfc-editor.org/rfc/rfc8945)
134    BADKEY,
135
136    /// Signature out of time window [RFC 8945](https://www.rfc-editor.org/rfc/rfc8945)
137    BADTIME,
138
139    /// Bad TKEY Mode [RFC 2930](https://tools.ietf.org/html/rfc2930#section-2.6)
140    BADMODE,
141
142    /// Duplicate key name [RFC 2930](https://tools.ietf.org/html/rfc2930#section-2.6)
143    BADNAME,
144
145    /// Algorithm not supported [RFC 2930](https://tools.ietf.org/html/rfc2930#section-2.6)
146    BADALG,
147
148    /// Bad Truncation [RFC 4635](https://tools.ietf.org/html/rfc4635#section-4)
149    BADTRUNC,
150
151    /// Bad/missing Server Cookie [RFC 7873](https://datatracker.ietf.org/doc/html/rfc7873)
152    BADCOOKIE,
153    // 24-3840      Unassigned
154    // 3841-4095    Reserved for Private Use                        [RFC6895]
155    // 4096-65534   Unassigned
156    // 65535        Reserved, can be allocated by Standards Action  [RFC6895]
157    /// An unknown or unregistered response code was received.
158    Unknown(u16),
159}
160
161impl Rcode {
162    #[inline]
163    pub fn value(self) -> u16 {
164        u16::from(self)
165    }
166
167    #[inline]
168    pub fn low(self) -> u8 {
169        match self {
170            Self::NoError => 0,
171            Self::FormErr => 1,
172            Self::ServFail => 2,
173            Self::NXDomain => 3,
174            Self::NotImp => 4,
175            Self::Refused => 5,
176            Self::YXDomain => 6,
177            Self::YXRRSet => 7,
178            Self::NXRRSet => 8,
179            Self::NotAuth => 9,
180            Self::NotZone => 10,
181            Self::BADVERS | Self::BADSIG => 0,
182            Self::BADKEY => 1,
183            Self::BADTIME => 2,
184            Self::BADMODE => 3,
185            Self::BADNAME => 4,
186            Self::BADALG => 5,
187            Self::BADTRUNC => 6,
188            Self::BADCOOKIE => 7,
189            Self::Unknown(code) => (code & 0x000f) as u8,
190        }
191    }
192
193    #[inline]
194    pub fn high(self) -> u8 {
195        match self {
196            Self::NoError
197            | Self::FormErr
198            | Self::ServFail
199            | Self::NXDomain
200            | Self::NotImp
201            | Self::Refused
202            | Self::YXDomain
203            | Self::YXRRSet
204            | Self::NXRRSet
205            | Self::NotAuth
206            | Self::NotZone => 0,
207            Self::BADVERS | Self::BADSIG => 1,
208            Self::BADKEY => 1,
209            Self::BADTIME => 1,
210            Self::BADMODE => 1,
211            Self::BADNAME => 1,
212            Self::BADALG => 1,
213            Self::BADTRUNC => 1,
214            Self::BADCOOKIE => 1,
215            Self::Unknown(code) => ((code >> 4) & 0x00ff) as u8,
216        }
217    }
218
219    #[inline]
220    pub fn has_extended_bits(self) -> bool {
221        self.high() != 0
222    }
223
224    #[inline]
225    pub fn from_parts(high: u8, low: u8) -> Self {
226        Self::from((u16::from(high) << 4) | u16::from(low & 0x0f))
227    }
228
229    /// Transforms the response code into the human message
230    pub fn to_str(self) -> &'static str {
231        match self {
232            Self::NoError => "No Error",
233            Self::FormErr => "Form Error", // 1     FormErr       Format Error                        [RFC1035]
234            Self::ServFail => "Server Failure", // 2     ServFail      Server Failure                      [RFC1035]
235            Self::NXDomain => "Non-Existent Domain", // 3     NXDomain      Non-Existent Domain                 [RFC1035]
236            Self::NotImp => "Not Implemented", // 4     NotImp        Not Implemented                     [RFC1035]
237            Self::Refused => "Query Refused", // 5     Refused       Query Refused                       [RFC1035]
238            Self::YXDomain => "Name should not exist", // 6     YXDomain      Name Exists when it should not      [RFC2136][RFC6672]
239            Self::YXRRSet => "RR Set should not exist", // 7     YXRRSet       RR Set Exists when it should not    [RFC2136]
240            Self::NXRRSet => "RR Set does not exist", // 8     NXRRSet       RR Set that should exist does not   [RFC2136]
241            Self::NotAuth => "Not authorized", // 9     NotAuth       Server Not Authoritative for zone   [RFC2136]
242            Self::NotZone => "Name not in zone", // 10    NotZone       Name not contained in zone          [RFC2136]
243            Self::BADVERS => "Bad OPT Version",
244            Self::BADSIG => "TSIG Signature Failure",
245            Self::BADKEY => "Key not recognized", // 17    BADKEY        Key not recognized                  [RFC2845]
246            Self::BADTIME => "Signature out of time window", // 18    BADTIME       Signature out of time window        [RFC2845]
247            Self::BADMODE => "Bad TKEY mode", // 19    BADMODE       Bad TKEY Mode                       [RFC2930]
248            Self::BADNAME => "Duplicate key name", // 20    BADNAME       Duplicate key name                  [RFC2930]
249            Self::BADALG => "Algorithm not supported", // 21    BADALG        Algorithm not supported             [RFC2930]
250            Self::BADTRUNC => "Bad truncation", // 22    BADTRUNC      Bad Truncation                      [RFC4635]
251            Self::BADCOOKIE => "Bad server cookie", // 23    BADCOOKIE     Bad/missing Server Cookie           [RFC7873]
252            Self::Unknown(_) => "Unknown response code",
253        }
254    }
255}
256
257impl Display for Rcode {
258    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
259        f.write_str(self.to_str())
260    }
261}
262
263impl From<u16> for Rcode {
264    fn from(value: u16) -> Self {
265        match value {
266            0 => Self::NoError, // 0    NoError    No Error                             [RFC1035]
267            1 => Self::FormErr, // 1    FormErr    Format Error                         [RFC1035]
268            2 => Self::ServFail, // 2    ServFail   Server Failure                       [RFC1035]
269            3 => Self::NXDomain, // 3    NXDomain   Non-Existent Domain                  [RFC1035]
270            4 => Self::NotImp,  // 4    NotImp     Not Implemented                      [RFC1035]
271            5 => Self::Refused, // 5    Refused    Query Refused                        [RFC1035]
272            6 => Self::YXDomain, // 6    YXDomain   Name Exists when it should not       [RFC2136][RFC6672]
273            7 => Self::YXRRSet,  // 7    YXRRSet    RR Set Exists when it should not     [RFC2136]
274            8 => Self::NXRRSet,  // 8    NXRRSet    RR Set that should exist does not    [RFC2136]
275            9 => Self::NotAuth,  // 9    NotAuth    Server Not Authoritative for zone    [RFC2136]
276            10 => Self::NotZone, // 10   NotZone    Name not contained in zone           [RFC2136]
277            16 => Self::BADVERS, // 16    BADVERS/BADSIG context-dependent; default to EDNS BADVERS
278            17 => Self::BADKEY,  // 17    BADKEY    Key not recognized                   [RFC2845]
279            18 => Self::BADTIME, // 18    BADTIME   Signature out of time window         [RFC2845]
280            19 => Self::BADMODE, // 19    BADMODE   Bad TKEY Mode                        [RFC2930]
281            20 => Self::BADNAME, // 20    BADNAME   Duplicate key name                   [RFC2930]
282            21 => Self::BADALG,  // 21    BADALG    Algorithm not supported              [RFC2930]
283            22 => Self::BADTRUNC, // 22    BADTRUNC  Bad Truncation                       [RFC4635]
284            23 => Self::BADCOOKIE, // 23    BADCOOKIE Bad/missing Server Cookie            [RFC7873]
285            code => Self::Unknown(code),
286        }
287    }
288}
289
290impl From<Rcode> for u16 {
291    fn from(rt: Rcode) -> Self {
292        match rt {
293            Rcode::NoError => 0, // 0   NoError    No Error                              [RFC1035]
294            Rcode::FormErr => 1, // 1   FormErr    Format Error                          [RFC1035]
295            Rcode::ServFail => 2, // 2   ServFail   Server Failure                        [RFC1035]
296            Rcode::NXDomain => 3, // 3   NXDomain   Non-Existent Domain                   [RFC1035]
297            Rcode::NotImp => 4,  // 4   NotImp     Not Implemented                       [RFC1035]
298            Rcode::Refused => 5, // 5   Refused    Query Refused                         [RFC1035]
299            Rcode::YXDomain => 6, // 6   YXDomain   Name Exists when it should not        [RFC2136][RFC6672]
300            Rcode::YXRRSet => 7,  // 7   YXRRSet    RR Set Exists when it should not      [RFC2136]
301            Rcode::NXRRSet => 8,  // 8   NXRRSet    RR Set that should exist does not     [RFC2136]
302            Rcode::NotAuth => 9,  // 9   NotAuth    Server Not Authoritative for zone     [RFC2136]
303            Rcode::NotZone => 10, // 10  NotZone    Name not contained in zone            [RFC2136]
304            //
305            // 11-15    Unassigned
306            //
307            // 16  BADVERS  Bad OPT Version         [RFC6891]
308            // 16  BADSIG   TSIG Signature Failure  [RFC2845]
309            Rcode::BADVERS | Rcode::BADSIG => 16,
310            Rcode::BADKEY => 17, // 17  BADKEY    Key not recognized                     [RFC2845]
311            Rcode::BADTIME => 18, // 18  BADTIME   Signature out of time window           [RFC2845]
312            Rcode::BADMODE => 19, // 19  BADMODE   Bad TKEY Mode                          [RFC2930]
313            Rcode::BADNAME => 20, // 20  BADNAME   Duplicate key name                     [RFC2930]
314            Rcode::BADALG => 21, // 21  BADALG    Algorithm not supported                [RFC2930]
315            Rcode::BADTRUNC => 22, // 22  BADTRUNC  Bad Truncation                         [RFC4635]
316            Rcode::BADCOOKIE => 23, // 23  BADCOOKIE Bad/missing Server Cookie              [RFC7873]
317            Rcode::Unknown(code) => code,
318        }
319    }
320}
321
322#[cfg(test)]
323mod tests {
324    use super::Rcode;
325
326    #[test]
327    fn rcode_parts_roundtrip_matches_known_layout() {
328        assert_eq!(Rcode::NoError.low(), 0);
329        assert_eq!(Rcode::NoError.high(), 0);
330        assert!(!Rcode::NoError.has_extended_bits());
331
332        assert_eq!(Rcode::BADVERS.low(), 0);
333        assert_eq!(Rcode::BADVERS.high(), 1);
334        assert!(Rcode::BADVERS.has_extended_bits());
335
336        assert_eq!(Rcode::Unknown(0x03af).low(), 0x0f);
337        assert_eq!(Rcode::Unknown(0x03af).high(), 0x3a);
338        assert_eq!(Rcode::from_parts(0x3a, 0x0f), Rcode::Unknown(0x03af));
339        assert_eq!(Rcode::from_parts(1, 0), Rcode::BADVERS);
340    }
341}
342
343/// DNS class values supported by ForgeDNS.
344#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
345#[allow(dead_code)]
346pub enum DNSClass {
347    /// Internet
348    IN,
349    /// CSNET
350    CS,
351    /// Chaos
352    CH,
353    /// Hesiod
354    HS,
355    /// QCLASS NONE
356    NONE,
357    /// QCLASS * (ANY)
358    ANY,
359    /// Special class for OPT Version, it was overloaded for EDNS - RFC 6891
360    /// From the RFC: `Values lower than 512 MUST be treated as equal to 512`
361    OPT(u16),
362    /// Unknown DNSClass was parsed
363    Unknown(u16),
364}
365
366impl FromStr for DNSClass {
367    type Err = DnsError;
368
369    fn from_str(str: &str) -> DnsResult<Self> {
370        debug_assert!(str.chars().all(|x| !char::is_ascii_lowercase(&x)));
371        match str {
372            "IN" => Ok(Self::IN),
373            "CS" => Ok(Self::CS),
374            "CH" => Ok(Self::CH),
375            "HS" => Ok(Self::HS),
376            "NONE" => Ok(Self::NONE),
377            "ANY" | "*" => Ok(Self::ANY),
378            _ => Err(DnsError::UnknownDnsClassStr(str.to_string())),
379        }
380    }
381}
382impl From<u16> for DNSClass {
383    fn from(value: u16) -> Self {
384        match value {
385            1 => Self::IN,
386            2 => Self::CS,
387            3 => Self::CH,
388            4 => Self::HS,
389            254 => Self::NONE,
390            255 => Self::ANY,
391            _ => Self::Unknown(value),
392        }
393    }
394}
395
396impl From<DNSClass> for u16 {
397    fn from(rt: DNSClass) -> Self {
398        match rt {
399            DNSClass::IN => 1,
400            DNSClass::CS => 2,
401            DNSClass::CH => 3,
402            DNSClass::HS => 4,
403            DNSClass::NONE => 254,
404            DNSClass::ANY => 255,
405            // see https://tools.ietf.org/html/rfc6891#section-6.1.2
406            DNSClass::OPT(max_payload_len) => max_payload_len.max(512),
407            DNSClass::Unknown(unknown) => unknown,
408        }
409    }
410}
411
412impl DNSClass {
413    /// Return the OPT version from value
414    pub fn for_opt(value: u16) -> Self {
415        // From RFC 6891: `Values lower than 512 MUST be treated as equal to 512`
416        let value = value.max(512);
417        Self::OPT(value)
418    }
419}
420
421/// Convert from `DNSClass` to `&str`
422impl From<DNSClass> for &'static str {
423    fn from(rt: DNSClass) -> &'static str {
424        match rt {
425            DNSClass::IN => "IN",
426            DNSClass::CS => "CS",
427            DNSClass::CH => "CH",
428            DNSClass::HS => "HS",
429            DNSClass::NONE => "NONE",
430            DNSClass::ANY => "ANY",
431            DNSClass::OPT(_) => "OPT",
432            DNSClass::Unknown(..) => "UNKNOWN",
433        }
434    }
435}
436impl Display for DNSClass {
437    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
438        f.write_str(Into::<&str>::into(*self))
439    }
440}
441
442/// The type of the resource record.
443///
444/// This specifies the type of data in the RData field of the Resource Record
445#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)]
446#[allow(dead_code)]
447pub enum RecordType {
448    /// [RFC 1035](https://tools.ietf.org/html/rfc1035) IPv4 Address record
449    A,
450    /// [RFC 1035](https://tools.ietf.org/html/rfc1035) Name server record
451    NS,
452    /// [RFC 1035](https://tools.ietf.org/html/rfc1035) Mail destination record (obsolete)
453    MD,
454    /// [RFC 1035](https://tools.ietf.org/html/rfc1035) Mail forwarder record (obsolete)
455    MF,
456    /// [RFC 1035](https://tools.ietf.org/html/rfc1035) Canonical name record
457    CNAME,
458    /// [RFC 1035](https://tools.ietf.org/html/rfc1035) and [RFC 2308](https://tools.ietf.org/html/rfc2308) Start of [a zone of] authority record
459    SOA,
460    /// [RFC 1035](https://tools.ietf.org/html/rfc1035) Mailbox domain name (experimental)
461    MB,
462    /// [RFC 1035](https://tools.ietf.org/html/rfc1035) Mail group member (experimental)
463    MG,
464    /// [RFC 1035](https://tools.ietf.org/html/rfc1035) Mail rename domain name (experimental)
465    MR,
466    /// [RFC 1035](https://tools.ietf.org/html/rfc1035) Null server record, for testing
467    NULL,
468    /// [RFC 1035](https://tools.ietf.org/html/rfc1035) Well-known services
469    WKS,
470    /// [RFC 1035](https://tools.ietf.org/html/rfc1035) Pointer record
471    PTR,
472    /// [RFC 1035](https://tools.ietf.org/html/rfc1035) host information
473    HINFO,
474    /// [RFC 1035](https://tools.ietf.org/html/rfc1035) Mailbox or mail list information
475    MINFO,
476    /// [RFC 1035](https://tools.ietf.org/html/rfc1035) Mail exchange record
477    MX,
478    /// [RFC 1035](https://tools.ietf.org/html/rfc1035) Text record
479    TXT,
480    /// [RFC 1183](https://tools.ietf.org/html/rfc1183) Responsible person
481    RP,
482    /// [RFC 1183](https://tools.ietf.org/html/rfc1183) AFS database server
483    AFSDB,
484    /// [RFC 1035](https://tools.ietf.org/html/rfc1035) X.25 PSDN address
485    X25,
486    /// [RFC 1706](https://tools.ietf.org/html/rfc1706) NSAP address
487    NSAP,
488    /// [RFC 1183](https://tools.ietf.org/html/rfc1183) ISDN address
489    ISDN,
490    /// [RFC 1183](https://tools.ietf.org/html/rfc1183) Route through record
491    RT,
492    /// [RFC 2673](https://tools.ietf.org/html/rfc2673) Endpoint identifier
493    EID,
494    /// [RFC 2673](https://tools.ietf.org/html/rfc2673) Nimrod locator
495    NIMLOC,
496    /// [RFC 1706](https://tools.ietf.org/html/rfc1706) NSAP-PTR record
497    NSAPPTR,
498    /// [RFC 2535](https://tools.ietf.org/html/rfc2535) (and [RFC 2931](https://tools.ietf.org/html/rfc2931)) Signature, to support [RFC 2137](https://tools.ietf.org/html/rfc2137) Update
499    SIG,
500    /// [RFC 2535](https://tools.ietf.org/html/rfc2535) and [RFC 2930](https://tools.ietf.org/html/rfc2930) Key record
501    KEY,
502    /// [RFC 2163](https://tools.ietf.org/html/rfc2163) X.400 mail mapping
503    PX,
504    /// [RFC 1712](https://tools.ietf.org/html/rfc1712) Geographical position
505    GPOS,
506    /// [RFC 3596](https://tools.ietf.org/html/rfc3596) IPv6 address record
507    AAAA,
508    /// [RFC 1876](https://tools.ietf.org/html/rfc1876) Location record
509    LOC,
510    /// [RFC 2535](https://tools.ietf.org/html/rfc2535) Next domain record (obsolete)
511    NXT,
512    /// [RFC 2672](https://tools.ietf.org/html/rfc2672) Service locator
513    SRV,
514    /// [RFC 3403](https://tools.ietf.org/html/rfc3403) Naming Authority Pointer
515    NAPTR,
516    /// [RFC 2230](https://tools.ietf.org/html/rfc2230) Key exchanger
517    KX,
518    /// [RFC 4398](https://tools.ietf.org/html/rfc4398) Storing Certificates in the Domain Name System (DNS)
519    CERT,
520    /// [RFC 2648](https://tools.ietf.org/html/rfc2648) ATM address
521    ATMA,
522    /// [RFC 2874](https://tools.ietf.org/html/rfc2874) A6 IPv6 address (historic)
523    A6,
524    /// [RFC 2535](https://tools.ietf.org/html/rfc2535) Kitchen sink (obsolete)
525    SINK,
526    /// [RFC 6672](https://tools.ietf.org/html/rfc6672) Delegation name
527    DNAME,
528    /// [RFC 6891](https://tools.ietf.org/html/rfc6891) Option
529    OPT,
530    /// [RFC 3123](https://tools.ietf.org/html/rfc3123) Address Prefix List
531    APL,
532    /// [RFC 4034](https://tools.ietf.org/html/rfc4034) Delegation signer
533    DS,
534    /// [RFC 4255](https://tools.ietf.org/html/rfc4255) SSH Public Key Fingerprint
535    SSHFP,
536    /// [RFC 4025](https://tools.ietf.org/html/rfc4025) IPsec Key
537    IPSECKEY,
538    /// [RFC 4034](https://tools.ietf.org/html/rfc4034) DNSSEC signature
539    RRSIG,
540    /// [RFC 4034](https://tools.ietf.org/html/rfc4034) Next-Secure record
541    NSEC,
542    /// [RFC 4034](https://tools.ietf.org/html/rfc4034) DNS Key record
543    DNSKEY,
544    /// [RFC 4701](https://tools.ietf.org/html/rfc4701) DHCP identifier
545    DHCID,
546    /// [RFC 5155](https://tools.ietf.org/html/rfc5155) NSEC record version 3
547    NSEC3,
548    /// [RFC 5155](https://tools.ietf.org/html/rfc5155) NSEC3 parameters
549    NSEC3PARAM,
550    /// [RFC 6698](https://tools.ietf.org/html/rfc6698) TLSA certificate association
551    TLSA,
552    /// [RFC 8162](https://tools.ietf.org/html/rfc8162) S/MIME cert association
553    SMIMEA,
554    /// [RFC 5205](https://tools.ietf.org/html/rfc5205) Host Identity Protocol
555    HIP,
556    /// [RFC 3755](https://tools.ietf.org/html/rfc3755) no implementation
557    NINFO,
558    /// [RFC 4034](https://tools.ietf.org/html/rfc4034) reserved key record
559    RKEY,
560    /// [RFC 4034](https://tools.ietf.org/html/rfc4034) trust anchor linkage
561    TALINK,
562    /// [RFC 7344](https://tools.ietf.org/html/rfc7344) Child DS
563    CDS,
564    /// [RFC 7344](https://tools.ietf.org/html/rfc7344) Child DNSKEY
565    CDNSKEY,
566    /// [RFC 7929](https://tools.ietf.org/html/rfc7929) OpenPGP public key
567    OPENPGPKEY,
568    /// [RFC 7477](https://tools.ietf.org/html/rfc7477) Child-to-parent synchronization record
569    CSYNC,
570    /// [RFC 8976](https://tools.ietf.org/html/rfc8976) Message digest for DNS zones
571    ZONEMD,
572    /// [RFC 9460](https://tools.ietf.org/html/rfc9460) DNS SVCB and HTTPS RRs
573    SVCB,
574    /// [RFC 9460](https://tools.ietf.org/html/rfc9460) DNS SVCB and HTTPS RRs
575    HTTPS,
576    /// [RFC 7208](https://tools.ietf.org/html/rfc7208) Sender Policy Framework
577    SPF,
578    /// [RFC 1712](https://tools.ietf.org/html/rfc1712) User information
579    UINFO,
580    /// [RFC 1712](https://tools.ietf.org/html/rfc1712) User ID
581    UID,
582    /// [RFC 1712](https://tools.ietf.org/html/rfc1712) Group ID
583    GID,
584    /// [RFC 1035](https://tools.ietf.org/html/rfc1035) Binary unspecified payload
585    UNSPEC,
586    /// [RFC 6742](https://tools.ietf.org/html/rfc6742) ILNP node identifier
587    NID,
588    /// [RFC 6742](https://tools.ietf.org/html/rfc6742) ILNP 32-bit locator
589    L32,
590    /// [RFC 6742](https://tools.ietf.org/html/rfc6742) ILNP 64-bit locator
591    L64,
592    /// [RFC 6742](https://tools.ietf.org/html/rfc6742) ILNP locator pointer
593    LP,
594    /// [RFC 7043](https://tools.ietf.org/html/rfc7043) EUI-48 address
595    EUI48,
596    /// [RFC 7043](https://tools.ietf.org/html/rfc7043) EUI-64 address
597    EUI64,
598    /// [draft-ietf-dnsop-aname](https://tools.ietf.org/html/draft-ietf-dnsop-aname-04) ANAME pseudo-record
599    ANAME,
600    /// [RFC 7553](https://tools.ietf.org/html/rfc7553) URI record
601    URI,
602    /// [RFC 6844](https://tools.ietf.org/html/rfc6844) Certification Authority Authorization
603    CAA,
604    /// [RFC 6844](https://tools.ietf.org/html/rfc6844) Application visibility and control
605    AVC,
606    /// [RFC 8490](https://tools.ietf.org/html/rfc8490) Digital object architecture
607    DOA,
608    /// [RFC 8777](https://tools.ietf.org/html/rfc8777) Automatic multicast tunneling relay
609    AMTRELAY,
610    /// [RFC 9606](https://tools.ietf.org/html/rfc9606) Resolver information
611    RESINFO,
612    /// [RFC 2930](https://tools.ietf.org/html/rfc2930) Secret key record
613    TKEY,
614    /// [RFC 8945](https://tools.ietf.org/html/rfc8945) Transaction Signature
615    TSIG,
616    /// [RFC 1995](https://tools.ietf.org/html/rfc1995) Incremental Zone Transfer
617    IXFR,
618    /// [RFC 1035](https://tools.ietf.org/html/rfc1035) Authoritative Zone Transfer
619    AXFR,
620    /// [RFC 1035](https://tools.ietf.org/html/rfc1035) Mailbox-related records (obsolete)
621    MAILB,
622    /// [RFC 1035](https://tools.ietf.org/html/rfc1035) Mail agent records (obsolete)
623    MAILA,
624    /// [RFC 1035](https://tools.ietf.org/html/rfc1035) All cached records, aka ANY
625    ANY,
626    /// [RFC 6895](https://www.rfc-editor.org/rfc/rfc6895) DNSSEC trust anchor
627    TA,
628    /// [RFC 4431](https://tools.ietf.org/html/rfc4431) DNSSEC lookaside validation
629    DLV,
630    /// Unknown Record type, or unsupported
631    Unknown(u16),
632
633    /// This corresponds to a record type of 0, unspecified
634    ZERO,
635}
636
637impl From<u16> for RecordType {
638    /// Convert from `u16` to `RecordType`
639    fn from(value: u16) -> Self {
640        match value {
641            0 => Self::ZERO,
642            1 => Self::A,
643            2 => Self::NS,
644            3 => Self::MD,
645            4 => Self::MF,
646            5 => Self::CNAME,
647            6 => Self::SOA,
648            7 => Self::MB,
649            8 => Self::MG,
650            9 => Self::MR,
651            10 => Self::NULL,
652            11 => Self::WKS,
653            12 => Self::PTR,
654            13 => Self::HINFO,
655            14 => Self::MINFO,
656            15 => Self::MX,
657            16 => Self::TXT,
658            17 => Self::RP,
659            18 => Self::AFSDB,
660            19 => Self::X25,
661            22 => Self::NSAP,
662            20 => Self::ISDN,
663            21 => Self::RT,
664            31 => Self::EID,
665            32 => Self::NIMLOC,
666            23 => Self::NSAPPTR,
667            24 => Self::SIG,
668            25 => Self::KEY,
669            26 => Self::PX,
670            27 => Self::GPOS,
671            28 => Self::AAAA,
672            29 => Self::LOC,
673            30 => Self::NXT,
674            33 => Self::SRV,
675            35 => Self::NAPTR,
676            36 => Self::KX,
677            37 => Self::CERT,
678            34 => Self::ATMA,
679            38 => Self::A6,
680            40 => Self::SINK,
681            39 => Self::DNAME,
682            41 => Self::OPT,
683            42 => Self::APL,
684            43 => Self::DS,
685            44 => Self::SSHFP,
686            45 => Self::IPSECKEY,
687            46 => Self::RRSIG,
688            47 => Self::NSEC,
689            48 => Self::DNSKEY,
690            49 => Self::DHCID,
691            50 => Self::NSEC3,
692            51 => Self::NSEC3PARAM,
693            52 => Self::TLSA,
694            53 => Self::SMIMEA,
695            55 => Self::HIP,
696            56 => Self::NINFO,
697            57 => Self::RKEY,
698            58 => Self::TALINK,
699            59 => Self::CDS,
700            60 => Self::CDNSKEY,
701            61 => Self::OPENPGPKEY,
702            62 => Self::CSYNC,
703            63 => Self::ZONEMD,
704            64 => Self::SVCB,
705            65 => Self::HTTPS,
706            99 => Self::SPF,
707            100 => Self::UINFO,
708            101 => Self::UID,
709            102 => Self::GID,
710            103 => Self::UNSPEC,
711            104 => Self::NID,
712            105 => Self::L32,
713            106 => Self::L64,
714            107 => Self::LP,
715            108 => Self::EUI48,
716            109 => Self::EUI64,
717            249 => Self::TKEY,
718            250 => Self::TSIG,
719            251 => Self::IXFR,
720            252 => Self::AXFR,
721            253 => Self::MAILB,
722            254 => Self::MAILA,
723            255 => Self::ANY,
724            256 => Self::URI,
725            257 => Self::CAA,
726            258 => Self::AVC,
727            259 => Self::DOA,
728            260 => Self::AMTRELAY,
729            261 => Self::RESINFO,
730            32768 => Self::TA,
731            32769 => Self::DLV,
732            65305 => Self::ANAME,
733            _ => Self::Unknown(value),
734        }
735    }
736}
737impl From<RecordType> for u16 {
738    fn from(rt: RecordType) -> Self {
739        match rt {
740            RecordType::A => 1,
741            RecordType::NS => 2,
742            RecordType::MD => 3,
743            RecordType::MF => 4,
744            RecordType::CNAME => 5,
745            RecordType::SOA => 6,
746            RecordType::MB => 7,
747            RecordType::MG => 8,
748            RecordType::MR => 9,
749            RecordType::NULL => 10,
750            RecordType::WKS => 11,
751            RecordType::PTR => 12,
752            RecordType::HINFO => 13,
753            RecordType::MINFO => 14,
754            RecordType::MX => 15,
755            RecordType::TXT => 16,
756            RecordType::RP => 17,
757            RecordType::AFSDB => 18,
758            RecordType::X25 => 19,
759            RecordType::NSAP => 22,
760            RecordType::ISDN => 20,
761            RecordType::RT => 21,
762            RecordType::EID => 31,
763            RecordType::NIMLOC => 32,
764            RecordType::NSAPPTR => 23,
765            RecordType::SIG => 24,
766            RecordType::KEY => 25,
767            RecordType::PX => 26,
768            RecordType::GPOS => 27,
769            RecordType::AAAA => 28,
770            RecordType::LOC => 29,
771            RecordType::NXT => 30,
772            RecordType::SRV => 33,
773            RecordType::NAPTR => 35,
774            RecordType::KX => 36,
775            RecordType::CERT => 37,
776            RecordType::ATMA => 34,
777            RecordType::A6 => 38,
778            RecordType::SINK => 40,
779            RecordType::DNAME => 39,
780            RecordType::OPT => 41,
781            RecordType::APL => 42,
782            RecordType::DS => 43,
783            RecordType::SSHFP => 44,
784            RecordType::IPSECKEY => 45,
785            RecordType::RRSIG => 46,
786            RecordType::NSEC => 47,
787            RecordType::DNSKEY => 48,
788            RecordType::DHCID => 49,
789            RecordType::NSEC3 => 50,
790            RecordType::NSEC3PARAM => 51,
791            RecordType::TLSA => 52,
792            RecordType::SMIMEA => 53,
793            RecordType::HIP => 55,
794            RecordType::NINFO => 56,
795            RecordType::RKEY => 57,
796            RecordType::TALINK => 58,
797            RecordType::CDS => 59,
798            RecordType::CDNSKEY => 60,
799            RecordType::OPENPGPKEY => 61,
800            RecordType::CSYNC => 62,
801            RecordType::ZONEMD => 63,
802            RecordType::SVCB => 64,
803            RecordType::HTTPS => 65,
804            RecordType::SPF => 99,
805            RecordType::UINFO => 100,
806            RecordType::UID => 101,
807            RecordType::GID => 102,
808            RecordType::UNSPEC => 103,
809            RecordType::NID => 104,
810            RecordType::L32 => 105,
811            RecordType::L64 => 106,
812            RecordType::LP => 107,
813            RecordType::EUI48 => 108,
814            RecordType::EUI64 => 109,
815            RecordType::ANAME => 65305,
816            RecordType::URI => 256,
817            RecordType::CAA => 257,
818            RecordType::AVC => 258,
819            RecordType::DOA => 259,
820            RecordType::AMTRELAY => 260,
821            RecordType::RESINFO => 261,
822            RecordType::TKEY => 249,
823            RecordType::TSIG => 250,
824            RecordType::IXFR => 251,
825            RecordType::AXFR => 252,
826            RecordType::MAILB => 253,
827            RecordType::MAILA => 254,
828            RecordType::ANY => 255,
829            RecordType::TA => 32768,
830            RecordType::DLV => 32769,
831            RecordType::ZERO => 0,
832            RecordType::Unknown(code) => code,
833        }
834    }
835}
836
837impl FromStr for RecordType {
838    type Err = DnsError;
839
840    /// Convert `&str` to `RecordType`
841    fn from_str(str: &str) -> DnsResult<Self> {
842        match str {
843            "A" => Ok(Self::A),
844            "NS" => Ok(Self::NS),
845            "MD" => Ok(Self::MD),
846            "MF" => Ok(Self::MF),
847            "CNAME" => Ok(Self::CNAME),
848            "SOA" => Ok(Self::SOA),
849            "MB" => Ok(Self::MB),
850            "MG" => Ok(Self::MG),
851            "MR" => Ok(Self::MR),
852            "NULL" => Ok(Self::NULL),
853            "WKS" => Ok(Self::WKS),
854            "PTR" => Ok(Self::PTR),
855            "HINFO" => Ok(Self::HINFO),
856            "MINFO" => Ok(Self::MINFO),
857            "MX" => Ok(Self::MX),
858            "TXT" => Ok(Self::TXT),
859            "RP" => Ok(Self::RP),
860            "AFSDB" => Ok(Self::AFSDB),
861            "X25" => Ok(Self::X25),
862            "NSAP" => Ok(Self::NSAP),
863            "ISDN" => Ok(Self::ISDN),
864            "RT" => Ok(Self::RT),
865            "EID" => Ok(Self::EID),
866            "NIMLOC" => Ok(Self::NIMLOC),
867            "NSAPPTR" => Ok(Self::NSAPPTR),
868            "SIG" => Ok(Self::SIG),
869            "KEY" => Ok(Self::KEY),
870            "PX" => Ok(Self::PX),
871            "GPOS" => Ok(Self::GPOS),
872            "AAAA" => Ok(Self::AAAA),
873            "LOC" => Ok(Self::LOC),
874            "NXT" => Ok(Self::NXT),
875            "SRV" => Ok(Self::SRV),
876            "NAPTR" => Ok(Self::NAPTR),
877            "KX" => Ok(Self::KX),
878            "CERT" => Ok(Self::CERT),
879            "ATMA" => Ok(Self::ATMA),
880            "A6" => Ok(Self::A6),
881            "SINK" => Ok(Self::SINK),
882            "DNAME" => Ok(Self::DNAME),
883            "OPT" => Ok(Self::OPT),
884            "APL" => Ok(Self::APL),
885            "DS" => Ok(Self::DS),
886            "SSHFP" => Ok(Self::SSHFP),
887            "IPSECKEY" => Ok(Self::IPSECKEY),
888            "RRSIG" => Ok(Self::RRSIG),
889            "NSEC" => Ok(Self::NSEC),
890            "DNSKEY" => Ok(Self::DNSKEY),
891            "DHCID" => Ok(Self::DHCID),
892            "NSEC3" => Ok(Self::NSEC3),
893            "NSEC3PARAM" => Ok(Self::NSEC3PARAM),
894            "TLSA" => Ok(Self::TLSA),
895            "SMIMEA" => Ok(Self::SMIMEA),
896            "HIP" => Ok(Self::HIP),
897            "NINFO" => Ok(Self::NINFO),
898            "RKEY" => Ok(Self::RKEY),
899            "TALINK" => Ok(Self::TALINK),
900            "CDS" => Ok(Self::CDS),
901            "CDNSKEY" => Ok(Self::CDNSKEY),
902            "OPENPGPKEY" => Ok(Self::OPENPGPKEY),
903            "CSYNC" => Ok(Self::CSYNC),
904            "ZONEMD" => Ok(Self::ZONEMD),
905            "SVCB" => Ok(Self::SVCB),
906            "HTTPS" => Ok(Self::HTTPS),
907            "SPF" => Ok(Self::SPF),
908            "UINFO" => Ok(Self::UINFO),
909            "UID" => Ok(Self::UID),
910            "GID" => Ok(Self::GID),
911            "UNSPEC" => Ok(Self::UNSPEC),
912            "NID" => Ok(Self::NID),
913            "L32" => Ok(Self::L32),
914            "L64" => Ok(Self::L64),
915            "LP" => Ok(Self::LP),
916            "EUI48" => Ok(Self::EUI48),
917            "EUI64" => Ok(Self::EUI64),
918            "ANAME" => Ok(Self::ANAME),
919            "URI" => Ok(Self::URI),
920            "CAA" => Ok(Self::CAA),
921            "AVC" => Ok(Self::AVC),
922            "DOA" => Ok(Self::DOA),
923            "AMTRELAY" => Ok(Self::AMTRELAY),
924            "RESINFO" => Ok(Self::RESINFO),
925            "TKEY" => Ok(Self::TKEY),
926            "TSIG" => Ok(Self::TSIG),
927            "IXFR" => Ok(Self::IXFR),
928            "AXFR" => Ok(Self::AXFR),
929            "MAILB" => Ok(Self::MAILB),
930            "MAILA" => Ok(Self::MAILA),
931            "ANY" | "*" => Ok(Self::ANY),
932            "TA" => Ok(Self::TA),
933            "DLV" => Ok(Self::DLV),
934            _ => Err(DnsError::UnknownRecordTypeStr(str.to_string())),
935        }
936    }
937}
938
939/// Convert from `RecordType` to `&str`
940impl From<RecordType> for &'static str {
941    fn from(rt: RecordType) -> &'static str {
942        match rt {
943            RecordType::A => "A",
944            RecordType::NS => "NS",
945            RecordType::MD => "MD",
946            RecordType::MF => "MF",
947            RecordType::CNAME => "CNAME",
948            RecordType::SOA => "SOA",
949            RecordType::MB => "MB",
950            RecordType::MG => "MG",
951            RecordType::MR => "MR",
952            RecordType::NULL => "NULL",
953            RecordType::WKS => "WKS",
954            RecordType::PTR => "PTR",
955            RecordType::HINFO => "HINFO",
956            RecordType::MINFO => "MINFO",
957            RecordType::MX => "MX",
958            RecordType::TXT => "TXT",
959            RecordType::RP => "RP",
960            RecordType::AFSDB => "AFSDB",
961            RecordType::X25 => "X25",
962            RecordType::NSAP => "NSAP",
963            RecordType::ISDN => "ISDN",
964            RecordType::RT => "RT",
965            RecordType::EID => "EID",
966            RecordType::NIMLOC => "NIMLOC",
967            RecordType::NSAPPTR => "NSAPPTR",
968            RecordType::SIG => "SIG",
969            RecordType::KEY => "KEY",
970            RecordType::PX => "PX",
971            RecordType::GPOS => "GPOS",
972            RecordType::AAAA => "AAAA",
973            RecordType::LOC => "LOC",
974            RecordType::NXT => "NXT",
975            RecordType::SRV => "SRV",
976            RecordType::NAPTR => "NAPTR",
977            RecordType::KX => "KX",
978            RecordType::CERT => "CERT",
979            RecordType::ATMA => "ATMA",
980            RecordType::A6 => "A6",
981            RecordType::SINK => "SINK",
982            RecordType::DNAME => "DNAME",
983            RecordType::OPT => "OPT",
984            RecordType::APL => "APL",
985            RecordType::DS => "DS",
986            RecordType::SSHFP => "SSHFP",
987            RecordType::IPSECKEY => "IPSECKEY",
988            RecordType::RRSIG => "RRSIG",
989            RecordType::NSEC => "NSEC",
990            RecordType::DNSKEY => "DNSKEY",
991            RecordType::DHCID => "DHCID",
992            RecordType::NSEC3 => "NSEC3",
993            RecordType::NSEC3PARAM => "NSEC3PARAM",
994            RecordType::TLSA => "TLSA",
995            RecordType::SMIMEA => "SMIMEA",
996            RecordType::HIP => "HIP",
997            RecordType::NINFO => "NINFO",
998            RecordType::RKEY => "RKEY",
999            RecordType::TALINK => "TALINK",
1000            RecordType::CDS => "CDS",
1001            RecordType::CDNSKEY => "CDNSKEY",
1002            RecordType::OPENPGPKEY => "OPENPGPKEY",
1003            RecordType::CSYNC => "CSYNC",
1004            RecordType::ZONEMD => "ZONEMD",
1005            RecordType::SVCB => "SVCB",
1006            RecordType::HTTPS => "HTTPS",
1007            RecordType::SPF => "SPF",
1008            RecordType::UINFO => "UINFO",
1009            RecordType::UID => "UID",
1010            RecordType::GID => "GID",
1011            RecordType::UNSPEC => "UNSPEC",
1012            RecordType::NID => "NID",
1013            RecordType::L32 => "L32",
1014            RecordType::L64 => "L64",
1015            RecordType::LP => "LP",
1016            RecordType::EUI48 => "EUI48",
1017            RecordType::EUI64 => "EUI64",
1018            RecordType::ANAME => "ANAME",
1019            RecordType::URI => "URI",
1020            RecordType::CAA => "CAA",
1021            RecordType::AVC => "AVC",
1022            RecordType::DOA => "DOA",
1023            RecordType::AMTRELAY => "AMTRELAY",
1024            RecordType::RESINFO => "RESINFO",
1025            RecordType::TKEY => "TKEY",
1026            RecordType::TSIG => "TSIG",
1027            RecordType::IXFR => "IXFR",
1028            RecordType::AXFR => "AXFR",
1029            RecordType::MAILB => "MAILB",
1030            RecordType::MAILA => "MAILA",
1031            RecordType::ANY => "ANY",
1032            RecordType::TA => "TA",
1033            RecordType::DLV => "DLV",
1034            RecordType::ZERO => "ZERO",
1035            RecordType::Unknown(_) => "Unknown",
1036        }
1037    }
1038}
1039
1040impl Display for RecordType {
1041    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
1042        f.write_str(Into::<&str>::into(*self))
1043    }
1044}