trust_dns_proto/rr/
dns_class.rs

1// Copyright 2015-2017 Benjamin Fry <benjaminfry@me.com>
2//
3// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
4// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5// http://opensource.org/licenses/MIT>, at your option. This file may not be
6// copied, modified, or distributed except according to those terms.
7
8//! class of DNS operations, in general always IN for internet
9#![allow(clippy::use_self)]
10
11use std::cmp::Ordering;
12use std::convert::From;
13use std::fmt;
14use std::fmt::{Display, Formatter};
15use std::str::FromStr;
16
17#[cfg(feature = "serde-config")]
18use serde::{Deserialize, Serialize};
19
20use crate::error::*;
21use crate::serialize::binary::*;
22
23/// The DNS Record class
24#[cfg_attr(feature = "serde-config", derive(Deserialize, Serialize))]
25#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)]
26#[allow(dead_code)]
27pub enum DNSClass {
28    /// Internet
29    IN,
30    /// Chaos
31    CH,
32    /// Hesiod
33    HS,
34    /// QCLASS NONE
35    NONE,
36    /// QCLASS * (ANY)
37    ANY,
38    /// Special class for OPT Version, it was overloaded for EDNS - RFC 6891
39    /// From the RFC: `Values lower than 512 MUST be treated as equal to 512`
40    OPT(u16),
41}
42
43impl FromStr for DNSClass {
44    type Err = ProtoError;
45
46    /// Convert from `&str` to `DNSClass`
47    ///
48    /// ```
49    /// use std::str::FromStr;
50    /// use trust_dns_proto::rr::dns_class::DNSClass;
51    ///
52    /// let var: DNSClass = DNSClass::from_str("IN").unwrap();
53    /// assert_eq!(DNSClass::IN, var);
54    /// ```
55    fn from_str(str: &str) -> ProtoResult<Self> {
56        debug_assert!(str.chars().all(|x| char::is_ascii_uppercase(&x)));
57        match str {
58            "IN" => Ok(Self::IN),
59            "CH" => Ok(Self::CH),
60            "HS" => Ok(Self::HS),
61            "NONE" => Ok(Self::NONE),
62            "ANY" | "*" => Ok(Self::ANY),
63            _ => Err(ProtoErrorKind::UnknownDnsClassStr(str.to_string()).into()),
64        }
65    }
66}
67
68impl DNSClass {
69    /// Convert from `u16` to `DNSClass`
70    ///
71    /// ```
72    /// use trust_dns_proto::rr::dns_class::DNSClass;
73    ///
74    /// let var = DNSClass::from_u16(1).unwrap();
75    /// assert_eq!(DNSClass::IN, var);
76    /// ```
77    pub fn from_u16(value: u16) -> ProtoResult<Self> {
78        match value {
79            1 => Ok(Self::IN),
80            3 => Ok(Self::CH),
81            4 => Ok(Self::HS),
82            254 => Ok(Self::NONE),
83            255 => Ok(Self::ANY),
84            _ => Err(ProtoErrorKind::UnknownDnsClassValue(value).into()),
85        }
86    }
87
88    /// Return the OPT version from value
89    pub fn for_opt(value: u16) -> Self {
90        // From RFC 6891: `Values lower than 512 MUST be treated as equal to 512`
91        let value = value.max(512);
92        Self::OPT(value)
93    }
94}
95
96impl BinEncodable for DNSClass {
97    fn emit(&self, encoder: &mut BinEncoder<'_>) -> ProtoResult<()> {
98        encoder.emit_u16((*self).into())
99    }
100}
101
102impl<'r> BinDecodable<'r> for DNSClass {
103    fn read(decoder: &mut BinDecoder<'_>) -> ProtoResult<Self> {
104        Self::from_u16(
105            decoder.read_u16()?.unverified(/*DNSClass is verified as safe in processing this*/),
106        )
107    }
108}
109
110// TODO make these a macro or annotation
111
112/// Convert from `DNSClass` to `&str`
113///
114/// ```
115/// use trust_dns_proto::rr::dns_class::DNSClass;
116///
117/// let var: &'static str = DNSClass::IN.into();
118/// assert_eq!("IN", var);
119/// ```
120impl From<DNSClass> for &'static str {
121    fn from(rt: DNSClass) -> &'static str {
122        match rt {
123            DNSClass::IN => "IN",
124            DNSClass::CH => "CH",
125            DNSClass::HS => "HS",
126            DNSClass::NONE => "NONE",
127            DNSClass::ANY => "ANY",
128            DNSClass::OPT(_) => "OPT",
129        }
130    }
131}
132
133/// Convert from `DNSClass` to `u16`
134///
135/// ```
136/// use trust_dns_proto::rr::dns_class::DNSClass;
137///
138/// let var: u16 = DNSClass::IN.into();
139/// assert_eq!(1, var);
140/// ```
141impl From<DNSClass> for u16 {
142    fn from(rt: DNSClass) -> Self {
143        match rt {
144            DNSClass::IN => 1,
145            DNSClass::CH => 3,
146            DNSClass::HS => 4,
147            DNSClass::NONE => 254,
148            DNSClass::ANY => 255,
149            // see https://tools.ietf.org/html/rfc6891#section-6.1.2
150            DNSClass::OPT(max_payload_len) => max_payload_len.max(512),
151        }
152    }
153}
154
155impl PartialOrd<Self> for DNSClass {
156    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
157        Some(self.cmp(other))
158    }
159}
160
161impl Ord for DNSClass {
162    fn cmp(&self, other: &Self) -> Ordering {
163        u16::from(*self).cmp(&u16::from(*other))
164    }
165}
166
167impl Display for DNSClass {
168    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
169        f.write_str(Into::<&str>::into(*self))
170    }
171}
172
173#[test]
174fn test_order() {
175    let ordered = vec![
176        DNSClass::IN,
177        DNSClass::CH,
178        DNSClass::HS,
179        DNSClass::NONE,
180        DNSClass::ANY,
181    ];
182    let mut unordered = vec![
183        DNSClass::NONE,
184        DNSClass::HS,
185        DNSClass::CH,
186        DNSClass::IN,
187        DNSClass::ANY,
188    ];
189
190    unordered.sort();
191
192    assert_eq!(unordered, ordered);
193}