hickory_proto/rr/
lower_name.rs

1// Copyright 2015-2019 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//! domain name, aka labels, implementation
9
10use std::borrow::Borrow;
11use std::cmp::{Ordering, PartialEq};
12use std::fmt;
13use std::hash::{Hash, Hasher};
14use std::str::FromStr;
15
16use crate::error::*;
17#[cfg(feature = "serde-config")]
18use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
19
20use crate::rr::Name;
21use crate::serialize::binary::*;
22
23/// TODO: all LowerNames should be stored in a global "intern" space, and then everything that uses
24///  them should be through references. As a workaround the Strings are all Rc as well as the array
25#[derive(Default, Debug, Eq, Clone)]
26pub struct LowerName(Name);
27
28impl LowerName {
29    /// Create a new domain::LowerName, i.e. label
30    pub fn new(name: &Name) -> Self {
31        Self(name.to_lowercase())
32    }
33
34    /// Returns true if there are no labels, i.e. it's empty.
35    ///
36    /// In DNS the root is represented by `.`
37    ///
38    /// # Examples
39    ///
40    /// ```
41    /// use hickory_proto::rr::{LowerName, Name};
42    ///
43    /// let root = LowerName::from(Name::root());
44    /// assert_eq!(&root.to_string(), ".");
45    /// ```
46    pub fn is_root(&self) -> bool {
47        self.0.is_root()
48    }
49
50    /// Returns true if the name is a fully qualified domain name.
51    ///
52    /// If this is true, it has effects like only querying for this single name, as opposed to building
53    ///  up a search list in resolvers.
54    ///
55    /// *warning: this interface is unstable and may change in the future*
56    ///
57    /// # Examples
58    ///
59    /// ```
60    /// use std::str::FromStr;
61    /// use hickory_proto::rr::{LowerName, Name};
62    ///
63    /// let name = LowerName::from(Name::from_str("www").unwrap());
64    /// assert!(!name.is_fqdn());
65    ///
66    /// let name = LowerName::from(Name::from_str("www.example.com").unwrap());
67    /// assert!(!name.is_fqdn());
68    ///
69    /// let name = LowerName::from(Name::from_str("www.example.com.").unwrap());
70    /// assert!(name.is_fqdn());
71    /// ```
72    pub fn is_fqdn(&self) -> bool {
73        self.0.is_fqdn()
74    }
75
76    /// Trims off the first part of the name, to help with searching for the domain piece
77    ///
78    /// # Examples
79    ///
80    /// ```
81    /// use std::str::FromStr;
82    /// use hickory_proto::rr::{LowerName, Name};
83    ///
84    /// let example_com = LowerName::from(Name::from_str("example.com").unwrap());
85    /// assert_eq!(example_com.base_name(), LowerName::from(Name::from_str("com.").unwrap()));
86    /// assert_eq!(LowerName::from(Name::from_str("com.").unwrap().base_name()), LowerName::from(Name::root()));
87    /// assert_eq!(LowerName::from(Name::root().base_name()), LowerName::from(Name::root()));
88    /// ```
89    pub fn base_name(&self) -> Self {
90        Self(self.0.base_name())
91    }
92
93    /// returns true if the name components of self are all present at the end of name
94    ///
95    /// # Example
96    ///
97    /// ```rust
98    /// use std::str::FromStr;
99    /// use hickory_proto::rr::{LowerName, Name};
100    ///
101    /// let name = LowerName::from(Name::from_str("www.example.com").unwrap());
102    /// let zone = LowerName::from(Name::from_str("example.com").unwrap());
103    /// let another = LowerName::from(Name::from_str("example.net").unwrap());
104    /// assert!(zone.zone_of(&name));
105    /// assert!(!another.zone_of(&name));
106    /// ```
107    pub fn zone_of(&self, name: &Self) -> bool {
108        self.0.zone_of_case(&name.0)
109    }
110
111    /// Returns the number of labels in the name, discounting `*`.
112    ///
113    /// # Examples
114    ///
115    /// ```
116    /// use std::str::FromStr;
117    /// use hickory_proto::rr::{LowerName, Name};
118    ///
119    /// let root = LowerName::from(Name::root());
120    /// assert_eq!(root.num_labels(), 0);
121    ///
122    /// let example_com = LowerName::from(Name::from_str("example.com").unwrap());
123    /// assert_eq!(example_com.num_labels(), 2);
124    ///
125    /// let star_example_com = LowerName::from(Name::from_str("*.example.com").unwrap());
126    /// assert_eq!(star_example_com.num_labels(), 2);
127    /// ```
128    pub fn num_labels(&self) -> u8 {
129        self.0.num_labels()
130    }
131
132    /// returns the length in bytes of the labels. '.' counts as 1
133    ///
134    /// This can be used as an estimate, when serializing labels, they will often be compressed
135    /// and/or escaped causing the exact length to be different.
136    pub fn len(&self) -> usize {
137        self.0.len()
138    }
139
140    /// Returns true if the name is empty
141    pub fn is_empty(&self) -> bool {
142        self.0.is_empty()
143    }
144
145    /// Emits the canonical version of the name to the encoder.
146    ///
147    /// In canonical form, there will be no pointers written to the encoder (i.e. no compression).
148    pub fn emit_as_canonical(
149        &self,
150        encoder: &mut BinEncoder<'_>,
151        canonical: bool,
152    ) -> ProtoResult<()> {
153        self.0.emit_as_canonical(encoder, canonical)
154    }
155
156    /// Pass through for Name::is_wildcard
157    pub fn is_wildcard(&self) -> bool {
158        self.0.is_wildcard()
159    }
160
161    /// Replaces the first label with the wildcard character, "*"
162    pub fn into_wildcard(self) -> Self {
163        let name = self.0.into_wildcard();
164        Self(name)
165    }
166}
167
168impl Hash for LowerName {
169    fn hash<H>(&self, state: &mut H)
170    where
171        H: Hasher,
172    {
173        for label in &self.0 {
174            state.write(label);
175        }
176    }
177}
178
179impl PartialEq<Self> for LowerName {
180    fn eq(&self, other: &Self) -> bool {
181        self.0.eq_case(&other.0)
182    }
183}
184
185impl BinEncodable for LowerName {
186    fn emit(&self, encoder: &mut BinEncoder<'_>) -> ProtoResult<()> {
187        let is_canonical_names = encoder.is_canonical_names();
188        self.emit_as_canonical(encoder, is_canonical_names)
189    }
190}
191
192impl fmt::Display for LowerName {
193    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
194        self.0.fmt(f)
195    }
196}
197
198impl PartialOrd<Self> for LowerName {
199    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
200        Some(self.cmp(other))
201    }
202}
203
204impl Ord for LowerName {
205    /// Given two lower cased names, this performs a case sensitive comparison.
206    ///
207    /// ```text
208    /// RFC 4034                DNSSEC Resource Records               March 2005
209    ///
210    /// 6.1.  Canonical DNS LowerName Order
211    ///
212    ///  For the purposes of DNS security, owner names are ordered by treating
213    ///  individual labels as unsigned left-justified octet strings.  The
214    ///  absence of a octet sorts before a zero value octet, and uppercase
215    ///  US-ASCII letters are treated as if they were lowercase US-ASCII
216    ///  letters.
217    ///
218    ///  To compute the canonical ordering of a set of DNS names, start by
219    ///  sorting the names according to their most significant (rightmost)
220    ///  labels.  For names in which the most significant label is identical,
221    ///  continue sorting according to their next most significant label, and
222    ///  so forth.
223    ///
224    ///  For example, the following names are sorted in canonical DNS name
225    ///  order.  The most significant label is "example".  At this level,
226    ///  "example" sorts first, followed by names ending in "a.example", then
227    ///  by names ending "z.example".  The names within each level are sorted
228    ///  in the same way.
229    ///
230    ///            example
231    ///            a.example
232    ///            yljkjljk.a.example
233    ///            Z.a.example
234    ///            zABC.a.EXAMPLE
235    ///            z.example
236    ///            \001.z.example
237    ///            *.z.example
238    ///            \200.z.example
239    /// ```
240    fn cmp(&self, other: &Self) -> Ordering {
241        self.0.cmp_case(&other.0)
242    }
243}
244
245impl From<Name> for LowerName {
246    fn from(name: Name) -> Self {
247        Self::new(&name)
248    }
249}
250
251impl<'a> From<&'a Name> for LowerName {
252    fn from(name: &'a Name) -> Self {
253        Self::new(name)
254    }
255}
256
257impl From<LowerName> for Name {
258    fn from(name: LowerName) -> Self {
259        name.0
260    }
261}
262
263impl<'a> From<&'a LowerName> for Name {
264    fn from(name: &'a LowerName) -> Self {
265        name.0.clone()
266    }
267}
268
269impl Borrow<Name> for LowerName {
270    fn borrow(&self) -> &Name {
271        &self.0
272    }
273}
274
275impl<'r> BinDecodable<'r> for LowerName {
276    /// parses the chain of labels
277    ///  this has a max of 255 octets, with each label being less than 63.
278    ///  all names will be stored lowercase internally.
279    /// This will consume the portions of the Vec which it is reading...
280    fn read(decoder: &mut BinDecoder<'r>) -> ProtoResult<Self> {
281        let name = Name::read(decoder)?;
282        Ok(Self(name.to_lowercase()))
283    }
284}
285
286impl FromStr for LowerName {
287    type Err = ProtoError;
288
289    fn from_str(name: &str) -> Result<Self, Self::Err> {
290        Name::from_str(name).map(Self::from)
291    }
292}
293
294#[cfg(feature = "serde-config")]
295impl Serialize for LowerName {
296    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
297    where
298        S: Serializer,
299    {
300        serializer.serialize_str(&self.to_string())
301    }
302}
303
304#[cfg(feature = "serde-config")]
305impl<'de> Deserialize<'de> for LowerName {
306    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
307    where
308        D: Deserializer<'de>,
309    {
310        let s = String::deserialize(deserializer)?;
311        FromStr::from_str(&s).map_err(de::Error::custom)
312    }
313}