Skip to main content

hickory_proto/rr/domain/
name.rs

1// Copyright 2015-2017 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 alloc::string::ToString;
11use alloc::{string::String, vec::Vec};
12use core::char;
13use core::cmp::{Ordering, PartialEq};
14use core::fmt::{self, Write};
15use core::hash::{Hash, Hasher};
16use core::net::{IpAddr, Ipv4Addr, Ipv6Addr};
17use core::str::FromStr;
18
19use ipnet::{IpNet, Ipv4Net, Ipv6Net};
20#[cfg(feature = "serde")]
21use serde::{Deserialize, Deserializer, Serialize, Serializer, de};
22use tinyvec::TinyVec;
23
24use crate::error::{ProtoError, ProtoResult};
25use crate::rr::domain::label::{CaseInsensitive, CaseSensitive, IntoLabel, Label, LabelCmp};
26use crate::rr::domain::usage::LOCALHOST as LOCALHOST_usage;
27use crate::serialize::binary::{
28    BinDecodable, BinDecoder, BinEncodable, BinEncoder, DecodeError, NameEncoding, Restrict,
29};
30use crate::serialize::txt::ParseError;
31
32/// A domain name
33#[derive(Clone, Default, Eq)]
34pub struct Name {
35    is_fqdn: bool,
36    label_data: TinyVec<[u8; 32]>,
37    // This 24 is chosen because TinyVec accommodates an inline buffer up to 24 bytes without
38    // increasing its stack footprint
39    label_ends: TinyVec<[u8; 24]>,
40}
41
42impl Name {
43    /// Maximum legal length of a domain name
44    pub const MAX_LENGTH: usize = 255;
45
46    /// Create a new domain::Name, i.e. label
47    pub fn new() -> Self {
48        Self::default()
49    }
50
51    /// Returns the root label, i.e. no labels, can probably make this better in the future.
52    pub fn root() -> Self {
53        let mut this = Self::new();
54        this.is_fqdn = true;
55        this
56    }
57
58    /// Extend the name with the offered label, and ensure maximum name length is not exceeded.
59    fn extend_name(&mut self, label: &[u8]) -> Result<(), DecodeError> {
60        let new_len = self.encoded_len() + label.len() + 1;
61
62        if new_len > Self::MAX_LENGTH {
63            return Err(DecodeError::DomainNameTooLong(new_len));
64        };
65
66        self.label_data.extend_from_slice(label);
67        self.label_ends.push(self.label_data.len() as u8);
68
69        Ok(())
70    }
71
72    /// Randomize the case of ASCII alpha characters in a name
73    #[cfg(feature = "std")]
74    pub fn randomize_label_case(&mut self) {
75        // Generate randomness 32 bits at a time, because this is the smallest unit on which the
76        // `rand` crate operates. One RNG call should be enough for most queries.
77        let mut rand_bits: u32 = 0;
78
79        for (i, b) in self.label_data.iter_mut().enumerate() {
80            // Generate fresh random bits on the zeroth and then every 32nd iteration.
81            if i % 32 == 0 {
82                rand_bits = rand::random();
83            }
84
85            let flip_case = rand_bits & 1 == 1;
86
87            if b.is_ascii_alphabetic() && flip_case {
88                *b ^= 0x20; // toggle the case bit (0x20)
89            }
90
91            rand_bits >>= 1;
92        }
93    }
94
95    /// Returns true if there are no labels, i.e. it's empty.
96    ///
97    /// In DNS the root is represented by `.`
98    ///
99    /// # Examples
100    ///
101    /// ```
102    /// use hickory_proto::rr::domain::Name;
103    ///
104    /// let root = Name::root();
105    /// assert_eq!(&root.to_string(), ".");
106    /// ```
107    pub fn is_root(&self) -> bool {
108        self.label_ends.is_empty() && self.is_fqdn()
109    }
110
111    /// Returns true if the name is a fully qualified domain name.
112    ///
113    /// If this is true, it has effects like only querying for this single name, as opposed to building
114    ///  up a search list in resolvers.
115    ///
116    /// *warning: this interface is unstable and may change in the future*
117    ///
118    /// # Examples
119    ///
120    /// ```
121    /// use std::str::FromStr;
122    /// use hickory_proto::rr::domain::Name;
123    ///
124    /// let name = Name::from_str("www").unwrap();
125    /// assert!(!name.is_fqdn());
126    ///
127    /// let name = Name::from_str("www.example.com").unwrap();
128    /// assert!(!name.is_fqdn());
129    ///
130    /// let name = Name::from_str("www.example.com.").unwrap();
131    /// assert!(name.is_fqdn());
132    /// ```
133    pub fn is_fqdn(&self) -> bool {
134        self.is_fqdn
135    }
136
137    /// Specifies this name is a fully qualified domain name
138    ///
139    /// *warning: this interface is unstable and may change in the future*
140    pub fn set_fqdn(&mut self, val: bool) {
141        self.is_fqdn = val
142    }
143
144    /// Returns an iterator over the labels
145    pub fn iter(&self) -> LabelIter<'_> {
146        LabelIter {
147            name: self,
148            start: 0,
149            end: self.label_ends.len() as u8,
150        }
151    }
152
153    /// Appends the label to the end of this name
154    ///
155    /// # Example
156    ///
157    /// ```rust
158    /// use std::str::FromStr;
159    /// use hickory_proto::rr::domain::Name;
160    ///
161    /// let name = Name::from_str("www.example").unwrap();
162    /// let name = name.append_label("com").unwrap();
163    /// assert_eq!(name, Name::from_str("www.example.com").unwrap());
164    /// ```
165    pub fn append_label<L: IntoLabel>(mut self, label: L) -> ProtoResult<Self> {
166        self.extend_name(label.into_label()?.as_bytes())?;
167        Ok(self)
168    }
169
170    /// Prepends the label to the beginning of this name
171    ///
172    /// # Example
173    ///
174    /// ```rust
175    /// use std::str::FromStr;
176    /// use hickory_proto::rr::domain::Name;
177    ///
178    /// let name = Name::from_str("example.com").unwrap();
179    /// let name = name.prepend_label("www").unwrap();
180    /// assert_eq!(name, Name::from_str("www.example.com").unwrap());
181    /// ```
182    pub fn prepend_label<L: IntoLabel>(&self, label: L) -> ProtoResult<Self> {
183        let mut name = Self::new().append_label(label)?;
184
185        for label in self.into_iter() {
186            name.extend_name(label)?;
187        }
188
189        name.set_fqdn(self.is_fqdn);
190
191        Ok(name)
192    }
193
194    /// Creates a new Name from the specified labels
195    ///
196    /// # Arguments
197    ///
198    /// * `labels` - vector of items which will be stored as Strings.
199    ///
200    /// # Examples
201    ///
202    /// ```rust
203    /// use std::str::FromStr;
204    /// use hickory_proto::rr::domain::Name;
205    ///
206    /// // From strings, uses utf8 conversion
207    /// let from_labels = Name::from_labels(vec!["www", "example", "com"]).unwrap();
208    /// assert_eq!(from_labels, Name::from_str("www.example.com.").unwrap());
209    ///
210    /// // Force a set of bytes into labels (this is none-standard and potentially dangerous)
211    /// let from_labels = Name::from_labels(vec!["bad chars".as_bytes(), "example".as_bytes(), "com".as_bytes()]).unwrap();
212    /// assert_eq!(from_labels.iter().next(), Some(&b"bad chars"[..]));
213    ///
214    /// let root = Name::from_labels(Vec::<&str>::new()).unwrap();
215    /// assert!(root.is_root());
216    /// ```
217    pub fn from_labels<I, L>(labels: I) -> ProtoResult<Self>
218    where
219        I: IntoIterator<Item = L>,
220        L: IntoLabel,
221    {
222        let (labels, errors): (Vec<_>, Vec<_>) = labels
223            .into_iter()
224            .map(IntoLabel::into_label)
225            .partition(Result::is_ok);
226        let labels: Vec<_> = labels.into_iter().map(Result::unwrap).collect();
227        let errors: Vec<_> = errors.into_iter().map(Result::unwrap_err).collect();
228
229        if labels.len() > 255 {
230            return Err(DecodeError::DomainNameTooLong(labels.len()).into());
231        };
232        if !errors.is_empty() {
233            return Err(format!("error converting some labels: {errors:?}").into());
234        };
235
236        let mut name = Self {
237            is_fqdn: true,
238            ..Self::default()
239        };
240        for label in labels {
241            name = name.append_label(label)?;
242        }
243
244        Ok(name)
245    }
246
247    /// Appends `other` to `self`, returning a new `Name`
248    ///
249    /// Carries forward `is_fqdn` from `other`.
250    ///
251    /// # Examples
252    ///
253    /// ```rust
254    /// use std::str::FromStr;
255    /// use hickory_proto::rr::domain::Name;
256    ///
257    /// let local = Name::from_str("www").unwrap();
258    /// let domain = Name::from_str("example.com").unwrap();
259    /// assert!(!domain.is_fqdn());
260    ///
261    /// let name = local.clone().append_name(&domain).unwrap();
262    /// assert_eq!(name, Name::from_str("www.example.com").unwrap());
263    /// assert!(!name.is_fqdn());
264    ///
265    /// // see also `Name::append_domain`
266    /// let domain = Name::from_str("example.com.").unwrap();
267    /// assert!(domain.is_fqdn());
268    /// let name = local.append_name(&domain).unwrap();
269    /// assert_eq!(name, Name::from_str("www.example.com.").unwrap());
270    /// assert!(name.is_fqdn());
271    /// ```
272    pub fn append_name(mut self, other: &Self) -> Result<Self, ProtoError> {
273        for label in other.iter() {
274            self.extend_name(label)?;
275        }
276
277        self.is_fqdn = other.is_fqdn;
278        Ok(self)
279    }
280
281    /// Appends the `domain` to `self`, making the new `Name` an FQDN
282    ///
283    /// This is an alias for `append_name` with the added effect of marking the new `Name` as
284    /// a fully-qualified-domain-name.
285    ///
286    /// # Examples
287    ///
288    /// ```rust
289    /// use std::str::FromStr;
290    /// use hickory_proto::rr::domain::Name;
291    ///
292    /// let local = Name::from_str("www").unwrap();
293    /// let domain = Name::from_str("example.com").unwrap();
294    /// let name = local.append_domain(&domain).unwrap();
295    /// assert_eq!(name, Name::from_str("www.example.com.").unwrap());
296    /// assert!(name.is_fqdn())
297    /// ```
298    pub fn append_domain(self, domain: &Self) -> Result<Self, ProtoError> {
299        let mut this = self.append_name(domain)?;
300        this.set_fqdn(true);
301        Ok(this)
302    }
303
304    /// Creates a new Name with all labels lowercased
305    ///
306    /// # Examples
307    ///
308    /// ```
309    /// use std::cmp::Ordering;
310    /// use std::str::FromStr;
311    ///
312    /// use hickory_proto::rr::domain::{Label, Name};
313    ///
314    /// let example_com = Name::from_ascii("Example.Com").unwrap();
315    /// assert_eq!(example_com.cmp_case(&Name::from_str("example.com").unwrap()), Ordering::Less);
316    /// assert!(example_com.to_lowercase().eq_case(&Name::from_str("example.com").unwrap()));
317    /// ```
318    pub fn to_lowercase(&self) -> Self {
319        let new_label_data = self
320            .label_data
321            .iter()
322            .map(|c| c.to_ascii_lowercase())
323            .collect();
324        Self {
325            is_fqdn: self.is_fqdn,
326            label_data: new_label_data,
327            label_ends: self.label_ends.clone(),
328        }
329    }
330
331    /// Trims off the first part of the name, to help with searching for the domain piece
332    ///
333    /// # Examples
334    ///
335    /// ```
336    /// use std::str::FromStr;
337    /// use hickory_proto::rr::domain::Name;
338    ///
339    /// let example_com = Name::from_str("example.com.").unwrap();
340    /// assert_eq!(example_com.base_name(), Name::from_str("com.").unwrap());
341    /// assert_eq!(Name::from_str("com.").unwrap().base_name(), Name::root());
342    /// assert_eq!(Name::root().base_name(), Name::root());
343    /// ```
344    pub fn base_name(&self) -> Self {
345        let length = self.label_ends.len();
346        if length > 0 {
347            return self.trim_to(length - 1);
348        }
349        self.clone()
350    }
351
352    /// Trims to the number of labels specified
353    ///
354    /// # Examples
355    ///
356    /// ```
357    /// use std::str::FromStr;
358    /// use hickory_proto::rr::domain::Name;
359    ///
360    /// let example_com = Name::from_str("example.com.").unwrap();
361    /// assert_eq!(example_com.trim_to(2), Name::from_str("example.com.").unwrap());
362    /// assert_eq!(example_com.trim_to(1), Name::from_str("com.").unwrap());
363    /// assert_eq!(example_com.trim_to(0), Name::root());
364    /// assert_eq!(example_com.trim_to(3), Name::from_str("example.com.").unwrap());
365    /// ```
366    pub fn trim_to(&self, num_labels: usize) -> Self {
367        if num_labels > self.label_ends.len() {
368            self.clone()
369        } else {
370            Self::from_labels(self.iter().skip(self.label_ends.len() - num_labels)).unwrap()
371        }
372    }
373
374    /// same as `zone_of` allows for case sensitive call
375    pub fn zone_of_case(&self, name: &Self) -> bool {
376        self.zone_of_with(name, <[u8]>::eq)
377    }
378
379    /// returns true if the name components of self are all present at the end of name
380    ///
381    /// # Example
382    ///
383    /// ```rust
384    /// use std::str::FromStr;
385    /// use hickory_proto::rr::domain::Name;
386    ///
387    /// let name = Name::from_str("www.example.com").unwrap();
388    /// let zone = Name::from_str("example.com").unwrap();
389    /// let another = Name::from_str("example.net").unwrap();
390    /// assert!(zone.zone_of(&name));
391    /// assert!(!name.zone_of(&zone));
392    /// assert!(!another.zone_of(&name));
393    /// ```
394    pub fn zone_of(&self, name: &Self) -> bool {
395        self.zone_of_with(name, <[u8]>::eq_ignore_ascii_case)
396    }
397
398    fn zone_of_with(&self, name: &Self, label_eq: fn(&[u8], &[u8]) -> bool) -> bool {
399        let self_len = self.label_ends.len();
400        let name_len = name.label_ends.len();
401        match (self_len, name_len) {
402            (0, _) => return true,
403            (_, 0) => return false,
404            _ if self_len > name_len => return false,
405            _ => {}
406        }
407
408        self.iter()
409            .rev()
410            .zip(name.iter().rev())
411            .all(|(a, b)| label_eq(a, b))
412    }
413
414    /// Returns the number of labels in the name, discounting `*`.
415    ///
416    /// # Examples
417    ///
418    /// ```
419    /// use std::str::FromStr;
420    /// use hickory_proto::rr::domain::Name;
421    ///
422    /// let root = Name::root();
423    /// assert_eq!(root.num_labels(), 0);
424    ///
425    /// let example_com = Name::from_str("example.com").unwrap();
426    /// assert_eq!(example_com.num_labels(), 2);
427    ///
428    /// let star_example_com = Name::from_str("*.example.com.").unwrap();
429    /// assert_eq!(star_example_com.num_labels(), 2);
430    /// ```
431    pub fn num_labels(&self) -> u8 {
432        // it is illegal to have more than 256 labels.
433
434        let num = self.label_ends.len() as u8;
435
436        self.iter()
437            .next()
438            .map(|l| if l == b"*" { num - 1 } else { num })
439            .unwrap_or(num)
440    }
441
442    /// returns the length in bytes of the labels. '.' counts as 1
443    ///
444    /// This can be used as an estimate, when serializing labels, though
445    /// escaping may cause the exact length to be different.
446    ///
447    /// # Examples
448    ///
449    /// ```
450    /// use std::str::FromStr;
451    /// use hickory_proto::rr::domain::Name;
452    ///
453    /// assert_eq!(Name::from_str("www.example.com.").unwrap().len(), 16);
454    /// assert_eq!(Name::from_str(".").unwrap().len(), 1);
455    /// assert_eq!(Name::root().len(), 1);
456    /// ```
457    pub fn len(&self) -> usize {
458        let dots = if !self.label_ends.is_empty() {
459            self.label_ends.len()
460        } else {
461            1
462        };
463        dots + self.label_data.len()
464    }
465
466    /// Returns the encoded length of this name, ignoring compression.
467    ///
468    /// The `is_fqdn` flag is ignored, and the root label at the end is assumed to always be
469    /// present, since it terminates the name in the DNS message format.
470    fn encoded_len(&self) -> usize {
471        self.label_ends.len() + self.label_data.len() + 1
472    }
473
474    /// Returns whether the length of the labels, in bytes is 0. In practice, since '.' counts as
475    /// 1, this is never the case so the method returns false.
476    pub fn is_empty(&self) -> bool {
477        false
478    }
479
480    /// Parse the RData from a set of Tokens
481    pub(crate) fn from_tokens<'i, I: Iterator<Item = &'i str>>(
482        mut tokens: I,
483        origin: Option<&Self>,
484    ) -> Result<Self, ParseError> {
485        let name = tokens
486            .next()
487            .ok_or_else(|| ParseError::MissingToken("name".to_string()))
488            .and_then(|s| Self::parse(s, origin).map_err(ParseError::from))?;
489        Ok(name)
490    }
491
492    /// attempts to parse a name such as `"example.com."` or `"subdomain.example.com."`
493    ///
494    /// # Examples
495    ///
496    /// ```rust
497    /// use std::str::FromStr;
498    /// use hickory_proto::rr::domain::Name;
499    ///
500    /// let name = Name::from_str("example.com.").unwrap();
501    /// assert_eq!(name.base_name(), Name::from_str("com.").unwrap());
502    /// assert_eq!(name.iter().next(), Some(&b"example"[..]));
503    /// ```
504    pub fn parse(local: &str, origin: Option<&Self>) -> ProtoResult<Self> {
505        Self::from_encoded_str::<LabelEncUtf8>(local, origin)
506    }
507
508    /// Will convert the string to a name only allowing ascii as valid input
509    ///
510    /// This method will also preserve the case of the name where that's desirable
511    ///
512    /// # Examples
513    ///
514    /// ```
515    /// use hickory_proto::rr::Name;
516    ///
517    /// let bytes_name = Name::from_labels(vec!["WWW".as_bytes(), "example".as_bytes(), "COM".as_bytes()]).unwrap();
518    /// let ascii_name = Name::from_ascii("WWW.example.COM.").unwrap();
519    /// let lower_name = Name::from_ascii("www.example.com.").unwrap();
520    ///
521    /// assert!(bytes_name.eq_case(&ascii_name));
522    /// assert!(!lower_name.eq_case(&ascii_name));
523    ///
524    /// // escaped values
525    /// let bytes_name = Name::from_labels(vec!["email.name".as_bytes(), "example".as_bytes(), "com".as_bytes()]).unwrap();
526    /// let name = Name::from_ascii("email\\.name.example.com.").unwrap();
527    ///
528    /// assert_eq!(bytes_name, name);
529    ///
530    /// let bytes_name = Name::from_labels(vec!["bad.char".as_bytes(), "example".as_bytes(), "com".as_bytes()]).unwrap();
531    /// let name = Name::from_ascii("bad\\056char.example.com.").unwrap();
532    ///
533    /// assert_eq!(bytes_name, name);
534    /// ```
535    pub fn from_ascii<S: AsRef<str>>(name: S) -> ProtoResult<Self> {
536        Self::from_encoded_str::<LabelEncAscii>(name.as_ref(), None)
537    }
538
539    // TODO: currently reserved to be private to the crate, due to confusion of IDNA vs. utf8 in https://tools.ietf.org/html/rfc6762#appendix-F
540    /// Will convert the string to a name using IDNA, punycode, to encode the UTF8 as necessary
541    ///
542    /// When making names IDNA compatible, there is a side-effect of lowercasing the name.
543    ///
544    /// # Examples
545    ///
546    /// ```
547    /// use std::str::FromStr;
548    /// use hickory_proto::rr::Name;
549    ///
550    /// let bytes_name = Name::from_labels(vec!["WWW".as_bytes(), "example".as_bytes(), "COM".as_bytes()]).unwrap();
551    ///
552    /// // from_str calls through to from_utf8
553    /// let utf8_name = Name::from_str("WWW.example.COM.").unwrap();
554    /// let lower_name = Name::from_str("www.example.com.").unwrap();
555    ///
556    /// assert!(!bytes_name.eq_case(&utf8_name));
557    /// assert!(lower_name.eq_case(&utf8_name));
558    /// ```
559    pub fn from_utf8<S: AsRef<str>>(name: S) -> ProtoResult<Self> {
560        Self::from_encoded_str::<LabelEncUtf8>(name.as_ref(), None)
561    }
562
563    /// First attempts to decode via `from_utf8`, if that fails IDNA checks, then falls back to
564    /// ascii decoding.
565    ///
566    /// # Examples
567    ///
568    /// ```
569    /// use std::str::FromStr;
570    /// use hickory_proto::rr::Name;
571    ///
572    /// // Ok, underscore in the beginning of a name
573    /// assert!(Name::from_utf8("_allows.example.com.").is_ok());
574    ///
575    /// // Error, underscore in the end
576    /// assert!(Name::from_utf8("dis_allowed.example.com.").is_err());
577    ///
578    /// // Ok, relaxed mode
579    /// assert!(Name::from_str_relaxed("allow_in_.example.com.").is_ok());
580    /// ```
581    pub fn from_str_relaxed<S: AsRef<str>>(name: S) -> ProtoResult<Self> {
582        let name = name.as_ref();
583        Self::from_utf8(name).or_else(|_| Self::from_ascii(name))
584    }
585
586    fn from_encoded_str<E: LabelEnc>(local: &str, origin: Option<&Self>) -> ProtoResult<Self> {
587        let mut name = Self::new();
588        let mut label = String::new();
589
590        let mut state = ParseState::Label;
591
592        // short circuit root parse
593        if local == "." {
594            name.set_fqdn(true);
595            return Ok(name);
596        }
597
598        // TODO: it would be nice to relocate this to Label, but that is hard because the label boundary can only be detected after processing escapes...
599        // evaluate all characters
600        for ch in local.chars() {
601            match state {
602                ParseState::Label => match ch {
603                    '.' => {
604                        name = name.append_label(E::to_label(&label)?)?;
605                        label.clear();
606                    }
607                    '\\' => state = ParseState::Escape1,
608                    ch if !ch.is_control() && !ch.is_whitespace() => label.push(ch),
609                    _ => return Err(format!("unrecognized char: {ch}").into()),
610                },
611                ParseState::Escape1 => {
612                    if ch.is_numeric() {
613                        state = ParseState::Escape2(
614                            ch.to_digit(8)
615                                .ok_or_else(|| ProtoError::from(format!("illegal char: {ch}")))?,
616                        );
617                    } else {
618                        // it's a single escaped char
619                        label.push(ch);
620                        state = ParseState::Label;
621                    }
622                }
623                ParseState::Escape2(i) => {
624                    if ch.is_numeric() {
625                        state = ParseState::Escape3(
626                            i,
627                            ch.to_digit(8)
628                                .ok_or_else(|| ProtoError::from(format!("illegal char: {ch}")))?,
629                        );
630                    } else {
631                        return Err(ProtoError::from(format!("unrecognized char: {ch}")));
632                    }
633                }
634                ParseState::Escape3(i, ii) => {
635                    if ch.is_numeric() {
636                        // octal conversion
637                        let val: u32 = (i * 8 * 8)
638                            + (ii * 8)
639                            + ch.to_digit(8)
640                                .ok_or_else(|| ProtoError::from(format!("illegal char: {ch}")))?;
641                        let new: char = char::from_u32(val)
642                            .ok_or_else(|| ProtoError::from(format!("illegal char: {ch}")))?;
643                        label.push(new);
644                        state = ParseState::Label;
645                    } else {
646                        return Err(format!("unrecognized char: {ch}").into());
647                    }
648                }
649            }
650        }
651
652        if !label.is_empty() {
653            name = name.append_label(E::to_label(&label)?)?;
654        }
655
656        // Check if the last character processed was an unescaped `.`
657        if label.is_empty() && !local.is_empty() {
658            name.set_fqdn(true);
659        } else if let Some(other) = origin {
660            return name.append_domain(other);
661        }
662
663        Ok(name)
664    }
665
666    /// compares with the other label, ignoring case
667    fn cmp_with_f<F: LabelCmp>(&self, other: &Self) -> Ordering {
668        match (self.is_fqdn(), other.is_fqdn()) {
669            (false, true) => Ordering::Less,
670            (true, false) => Ordering::Greater,
671            _ => self.cmp_labels::<F>(other),
672        }
673    }
674
675    /// Compare two Names, not considering FQDN-ness.
676    fn cmp_labels<F: LabelCmp>(&self, other: &Self) -> Ordering {
677        // Compare from root to local (reversed)
678        for (l, r) in self.iter().rev().zip(other.iter().rev()) {
679            for (&a, &b) in l.iter().zip(r.iter()) {
680                match F::cmp_u8(a, b) {
681                    Ordering::Equal => {}
682                    ord => return ord,
683                }
684            }
685            match l.len().cmp(&r.len()) {
686                Ordering::Equal => {}
687                ord => return ord,
688            }
689        }
690        self.label_ends.len().cmp(&other.label_ends.len())
691    }
692
693    /// Case sensitive comparison
694    pub fn cmp_case(&self, other: &Self) -> Ordering {
695        self.cmp_with_f::<CaseSensitive>(other)
696    }
697
698    /// Compares the Names, in a case sensitive manner
699    pub fn eq_case(&self, other: &Self) -> bool {
700        self.cmp_with_f::<CaseSensitive>(other) == Ordering::Equal
701    }
702
703    /// Non-FQDN-aware case-insensitive comparison
704    ///
705    /// This will return true if names are equal, or if an otherwise equal relative and
706    /// non-relative name are compared.
707    ///
708    /// # Examples
709    ///
710    /// ```
711    /// use std::str::FromStr;
712    /// use hickory_proto::rr::domain::Name;
713    ///
714    /// let name1 = Name::from_str("a.com.").unwrap();
715    /// let name2 = name1.clone();
716    /// assert_eq!(&name1, &name2);
717    /// assert!(name1.eq_ignore_root(&name2));
718    ///
719    /// // Make name2 uppercase.
720    /// let name2 = Name::from_str("A.CoM.").unwrap();
721    /// assert_eq!(&name1, &name2);
722    /// assert!(name1.eq_ignore_root(&name2));
723    ///
724    /// // Make name2 a relative name.
725    /// // Note that standard equality testing now returns false.
726    /// let name2 = Name::from_str("a.com").unwrap();
727    /// assert!(&name1 != &name2);
728    /// assert!(name1.eq_ignore_root(&name2));
729    ///
730    /// // Make name2 a completely unrelated name.
731    /// let name2 = Name::from_str("b.com.").unwrap();
732    /// assert!(&name1 != &name2);
733    /// assert!(!name1.eq_ignore_root(&name2));
734    ///
735    /// ```
736    pub fn eq_ignore_root(&self, other: &Self) -> bool {
737        self.cmp_labels::<CaseInsensitive>(other) == Ordering::Equal
738    }
739
740    /// Non-FQDN-aware case-sensitive comparison
741    ///
742    /// This will return true if names are equal, or if an otherwise equal relative and
743    /// non-relative name are compared.
744    ///
745    /// # Examples
746    ///
747    /// ```
748    /// use std::str::FromStr;
749    /// use hickory_proto::rr::domain::Name;
750    ///
751    /// let name1 = Name::from_str("a.com.").unwrap();
752    /// let name2 = Name::from_ascii("A.CoM.").unwrap();
753    /// let name3 = Name::from_ascii("A.CoM").unwrap();
754    ///
755    /// assert_eq!(&name1, &name2);
756    /// assert!(name1.eq_ignore_root(&name2));
757    /// assert!(!name1.eq_ignore_root_case(&name2));
758    /// assert!(name2.eq_ignore_root_case(&name3));
759    ///
760    /// ```
761    pub fn eq_ignore_root_case(&self, other: &Self) -> bool {
762        self.cmp_labels::<CaseSensitive>(other) == Ordering::Equal
763    }
764
765    /// Converts this name into an ascii safe string.
766    ///
767    /// If the name is an IDNA name, then the name labels will be returned with the `xn--` prefix.
768    ///  see `to_utf8` or the `Display` impl for methods which convert labels to utf8.
769    pub fn to_ascii(&self) -> String {
770        let mut s = String::with_capacity(self.len());
771        self.write_labels::<String, LabelEncAscii>(&mut s)
772            .expect("string conversion of name should not fail");
773        s
774    }
775
776    /// Converts the Name labels to the utf8 String form.
777    ///
778    /// This converts the name to an unescaped format, that could be used with parse. If, the name is
779    ///  is followed by the final `.`, e.g. as in `www.example.com.`, which represents a fully
780    ///  qualified Name.
781    pub fn to_utf8(&self) -> String {
782        format!("{self}")
783    }
784
785    /// Converts a *.arpa Name in a PTR record back into an IpNet if possible.
786    pub fn parse_arpa_name(&self) -> Result<IpNet, ProtoError> {
787        if !self.is_fqdn() {
788            return Err("PQDN cannot be valid arpa name".into());
789        }
790        let mut iter = self.iter().rev();
791        let first = iter
792            .next()
793            .ok_or_else(|| ProtoError::from("not an arpa address"))?;
794        if !"arpa".eq_ignore_ascii_case(core::str::from_utf8(first)?) {
795            return Err("not an arpa address".into());
796        }
797        let second = iter
798            .next()
799            .ok_or_else(|| ProtoError::from("invalid arpa address"))?;
800        let mut prefix_len: u8 = 0;
801        match &core::str::from_utf8(second)?.to_ascii_lowercase()[..] {
802            "in-addr" => {
803                let mut octets: [u8; 4] = [0; 4];
804                for octet in octets.iter_mut() {
805                    match iter.next() {
806                        Some(label) => *octet = core::str::from_utf8(label)?.parse()?,
807                        None => break,
808                    }
809                    prefix_len += 8;
810                }
811                if iter.next().is_some() {
812                    return Err("unrecognized in-addr.arpa.".into());
813                }
814                Ok(IpNet::V4(
815                    Ipv4Net::new(octets.into(), prefix_len).expect("Ipv4Net::new"),
816                ))
817            }
818            "ip6" => {
819                let mut address: u128 = 0;
820                while prefix_len < 128 {
821                    match iter.next() {
822                        Some(label) => {
823                            if label.len() == 1 {
824                                prefix_len += 4;
825                                let hex = u8::from_str_radix(core::str::from_utf8(label)?, 16)?;
826                                address |= u128::from(hex) << (128 - prefix_len);
827                            } else {
828                                return Err("invalid label length for ip6.arpa".into());
829                            }
830                        }
831                        None => break,
832                    }
833                }
834                if iter.next().is_some() {
835                    return Err("unrecognized ip6.arpa.".into());
836                }
837                Ok(IpNet::V6(
838                    Ipv6Net::new(address.into(), prefix_len).expect("Ipv6Net::new"),
839                ))
840            }
841            _ => Err("unrecognized arpa address".into()),
842        }
843    }
844
845    fn write_labels<W: Write, E: LabelEnc>(&self, f: &mut W) -> Result<(), fmt::Error> {
846        let mut iter = self.iter().map(|b| Label::from_raw_bytes(b).unwrap());
847        if let Some(label) = iter.next() {
848            E::write_label(f, &label)?;
849        }
850
851        for label in iter {
852            write!(f, ".")?;
853            E::write_label(f, &label)?;
854        }
855
856        // if it was the root name
857        if self.is_root() || self.is_fqdn() {
858            write!(f, ".")?;
859        }
860        Ok(())
861    }
862
863    /// Returns true if the `Name` is either localhost or in the localhost zone.
864    ///
865    /// # Example
866    ///
867    /// ```
868    /// use std::str::FromStr;
869    /// use hickory_proto::rr::Name;
870    ///
871    /// let name = Name::from_str("localhost").unwrap();
872    /// assert!(name.is_localhost());
873    ///
874    /// let name = Name::from_str("localhost.").unwrap();
875    /// assert!(name.is_localhost());
876    ///
877    /// let name = Name::from_str("my.localhost.").unwrap();
878    /// assert!(name.is_localhost());
879    /// ```
880    pub fn is_localhost(&self) -> bool {
881        LOCALHOST_usage.zone_of(self)
882    }
883
884    /// True if the first label of this name is the wildcard, i.e. '*'
885    ///
886    /// # Example
887    ///
888    /// ```
889    /// use std::str::FromStr;
890    /// use hickory_proto::rr::Name;
891    ///
892    /// let name = Name::from_str("www.example.com").unwrap();
893    /// assert!(!name.is_wildcard());
894    ///
895    /// let name = Name::from_str("*.example.com").unwrap();
896    /// assert!(name.is_wildcard());
897    ///
898    /// let name = Name::root();
899    /// assert!(!name.is_wildcard());
900    /// ```
901    pub fn is_wildcard(&self) -> bool {
902        self.iter().next().is_some_and(|l| l == b"*")
903    }
904
905    /// Converts a name to a wildcard, by replacing the first label with `*`
906    ///
907    /// # Example
908    ///
909    /// ```
910    /// use std::str::FromStr;
911    /// use hickory_proto::rr::Name;
912    ///
913    /// let name = Name::from_str("www.example.com.").unwrap().into_wildcard();
914    /// assert_eq!(name, Name::from_str("*.example.com.").unwrap());
915    ///
916    /// // does nothing if the root
917    /// let name = Name::root().into_wildcard();
918    /// assert_eq!(name, Name::root());
919    /// ```
920    pub fn into_wildcard(self) -> Self {
921        if self.label_ends.is_empty() {
922            return Self::root();
923        }
924        let mut label_data = TinyVec::new();
925        label_data.push(b'*');
926        let mut label_ends = TinyVec::new();
927        label_ends.push(1);
928
929        // this is not using the Name::extend_name function as it should always be shorter than the original name, so length check is unnecessary
930        for label in self.iter().skip(1) {
931            label_data.extend_from_slice(label);
932            label_ends.push(label_data.len() as u8);
933        }
934        Self {
935            label_data,
936            label_ends,
937            is_fqdn: self.is_fqdn,
938        }
939    }
940}
941
942impl fmt::Debug for Name {
943    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
944        f.write_str("Name(\"")?;
945        self.write_labels::<_, LabelEncUtf8>(f)?;
946        f.write_str("\")")
947    }
948}
949
950trait LabelEnc {
951    fn to_label(name: &str) -> ProtoResult<Label>;
952    fn write_label<W: Write>(f: &mut W, label: &Label) -> Result<(), fmt::Error>;
953}
954
955struct LabelEncAscii;
956
957impl LabelEnc for LabelEncAscii {
958    fn to_label(name: &str) -> ProtoResult<Label> {
959        Label::from_ascii(name)
960    }
961
962    fn write_label<W: Write>(f: &mut W, label: &Label) -> Result<(), fmt::Error> {
963        label.write_ascii(f)
964    }
965}
966
967struct LabelEncUtf8;
968
969impl LabelEnc for LabelEncUtf8 {
970    fn to_label(name: &str) -> ProtoResult<Label> {
971        Label::from_utf8(name)
972    }
973
974    fn write_label<W: Write>(f: &mut W, label: &Label) -> Result<(), fmt::Error> {
975        write!(f, "{label}")
976    }
977}
978
979/// An iterator over labels in a name
980pub struct LabelIter<'a> {
981    name: &'a Name,
982    start: u8,
983    end: u8,
984}
985
986impl<'a> Iterator for LabelIter<'a> {
987    type Item = &'a [u8];
988
989    fn next(&mut self) -> Option<Self::Item> {
990        if self.start >= self.end {
991            return None;
992        }
993
994        let end = *self.name.label_ends.get(self.start as usize)?;
995        let start = match self.start {
996            0 => 0,
997            _ => self.name.label_ends[(self.start - 1) as usize],
998        };
999        self.start += 1;
1000        Some(&self.name.label_data[start as usize..end as usize])
1001    }
1002
1003    fn size_hint(&self) -> (usize, Option<usize>) {
1004        let len = self.end.saturating_sub(self.start) as usize;
1005        (len, Some(len))
1006    }
1007}
1008
1009impl ExactSizeIterator for LabelIter<'_> {}
1010
1011impl DoubleEndedIterator for LabelIter<'_> {
1012    fn next_back(&mut self) -> Option<Self::Item> {
1013        if self.end <= self.start {
1014            return None;
1015        }
1016
1017        self.end -= 1;
1018
1019        let end = *self.name.label_ends.get(self.end as usize)?;
1020        let start = match self.end {
1021            0 => 0,
1022            _ => self.name.label_ends[(self.end - 1) as usize],
1023        };
1024
1025        Some(&self.name.label_data[start as usize..end as usize])
1026    }
1027}
1028
1029impl<'a> IntoIterator for &'a Name {
1030    type Item = &'a [u8];
1031    type IntoIter = LabelIter<'a>;
1032
1033    fn into_iter(self) -> Self::IntoIter {
1034        self.iter()
1035    }
1036}
1037
1038impl From<IpAddr> for Name {
1039    fn from(addr: IpAddr) -> Self {
1040        match addr {
1041            IpAddr::V4(ip) => ip.into(),
1042            IpAddr::V6(ip) => ip.into(),
1043        }
1044    }
1045}
1046
1047impl From<Ipv4Addr> for Name {
1048    fn from(addr: Ipv4Addr) -> Self {
1049        let octets = addr.octets();
1050
1051        let mut labels =
1052            octets
1053                .iter()
1054                .rev()
1055                .fold(Vec::<Label>::with_capacity(6), |mut labels, o| {
1056                    let label: Label = format!("{o}")
1057                        .as_bytes()
1058                        .into_label()
1059                        .expect("IP octet to label should never fail");
1060                    labels.push(label);
1061                    labels
1062                });
1063
1064        labels.push(
1065            b"in-addr"
1066                .into_label()
1067                .expect("simple name should never fail"),
1068        );
1069        labels.push(b"arpa".into_label().expect("simple name should never fail"));
1070
1071        Self::from_labels(labels).expect("a translation of Ipv4Addr should never fail")
1072    }
1073}
1074
1075impl From<Ipv6Addr> for Name {
1076    fn from(addr: Ipv6Addr) -> Self {
1077        let segments = addr.segments();
1078
1079        let mut labels =
1080            segments
1081                .iter()
1082                .rev()
1083                .fold(Vec::<Label>::with_capacity(34), |mut labels, o| {
1084                    labels.push(
1085                        format!("{:x}", (*o & 0x000F) as u8)
1086                            .as_bytes()
1087                            .into_label()
1088                            .expect("IP octet to label should never fail"),
1089                    );
1090                    labels.push(
1091                        format!("{:x}", ((*o >> 4) & 0x000F) as u8)
1092                            .as_bytes()
1093                            .into_label()
1094                            .expect("IP octet to label should never fail"),
1095                    );
1096                    labels.push(
1097                        format!("{:x}", ((*o >> 8) & 0x000F) as u8)
1098                            .as_bytes()
1099                            .into_label()
1100                            .expect("IP octet to label should never fail"),
1101                    );
1102                    labels.push(
1103                        format!("{:x}", ((*o >> 12) & 0x000F) as u8)
1104                            .as_bytes()
1105                            .into_label()
1106                            .expect("IP octet to label should never fail"),
1107                    );
1108                    labels
1109                });
1110
1111        labels.push(b"ip6".into_label().expect("simple name should never fail"));
1112        labels.push(b"arpa".into_label().expect("simple name should never fail"));
1113
1114        Self::from_labels(labels).expect("a translation of Ipv6Addr should never fail")
1115    }
1116}
1117
1118impl PartialEq<Self> for Name {
1119    fn eq(&self, other: &Self) -> bool {
1120        match self.is_fqdn == other.is_fqdn {
1121            true => self.cmp_with_f::<CaseInsensitive>(other) == Ordering::Equal,
1122            false => false,
1123        }
1124    }
1125}
1126
1127impl Hash for Name {
1128    fn hash<H: Hasher>(&self, state: &mut H) {
1129        self.is_fqdn.hash(state);
1130        // Note: case-insensitive like `PartialEq`
1131        self.iter()
1132            .flatten()
1133            .for_each(|&b| state.write_u8(b.to_ascii_lowercase()));
1134    }
1135}
1136
1137enum ParseState {
1138    Label,
1139    Escape1,
1140    Escape2(u32),
1141    Escape3(u32, u32),
1142}
1143
1144impl BinEncodable for Name {
1145    fn emit(&self, encoder: &mut BinEncoder<'_>) -> ProtoResult<()> {
1146        let name;
1147        let name_ref = if matches!(encoder.name_encoding(), NameEncoding::UncompressedLowercase) {
1148            name = self.to_lowercase();
1149            &name
1150        } else {
1151            self
1152        };
1153        let compression = matches!(encoder.name_encoding(), NameEncoding::Compressed)
1154            && encoder.compressed_name_count < COMPRESSED_NAME_LIMIT;
1155
1156        let buf_len = encoder.len(); // lazily assert the size is less than 255...
1157        // lookup the label in the BinEncoder
1158        // if it exists, write the Pointer
1159        let labels = name_ref.iter();
1160
1161        // start index of each label
1162        let mut labels_written = Vec::with_capacity(name_ref.label_ends.len());
1163        // we're going to write out each label, tracking the indexes of the start to each label
1164        //   then we'll look to see if we can remove them and recapture the capacity in the buffer...
1165        for label in labels {
1166            if label.len() > 63 {
1167                return Err(DecodeError::LabelBytesTooLong(label.len()).into());
1168            }
1169
1170            labels_written.push(encoder.offset());
1171            encoder.emit_character_data(label)?;
1172        }
1173        let last_index = encoder.offset();
1174        // now search for other labels already stored matching from the beginning label, strip then to the end
1175        //   if it's not found, then store this as a new label
1176        if compression {
1177            encoder.compressed_name_count += 1;
1178            for label_idx in &labels_written {
1179                match encoder.get_label_pointer(*label_idx, last_index) {
1180                    Some(loc) if loc & 0xC000 == 0 => {
1181                        // reset back to the beginning of this label, and then write the pointer...
1182                        encoder.set_offset(*label_idx);
1183                        encoder.trim();
1184
1185                        // write out the pointer marker
1186                        //  or'd with the location which is less than 2^14
1187                        encoder.emit_u16(0xC000u16 | loc)?;
1188
1189                        // we found a pointer don't write more, break
1190                        return Ok(());
1191                    }
1192                    _ => {
1193                        // no existing label exists, store this new one.
1194                        encoder.store_label_pointer(*label_idx, last_index);
1195                    }
1196                }
1197            }
1198        } else {
1199            // Compression is disabled for either this name or the entire message. Just attempt to
1200            // store the label pointers, in case they'll be used by an eligible RData type later.
1201            for label_idx in &labels_written {
1202                encoder.store_label_pointer(*label_idx, last_index);
1203            }
1204        }
1205
1206        // if we're getting here, then we didn't write out a pointer and are ending the name
1207        // the end of the list of names
1208        encoder.emit(0)?;
1209
1210        // the entire name needs to be less than 256.
1211        let length = encoder.len() - buf_len;
1212        if length > 255 {
1213            return Err(DecodeError::DomainNameTooLong(length).into());
1214        }
1215
1216        Ok(())
1217    }
1218}
1219
1220/// Maximum number of names for which name compression will be attempted per message.
1221///
1222/// This limit matches that from Unbound, see
1223/// <https://nlnetlabs.nl/downloads/unbound/patch_CVE-2024-8508.diff>.
1224const COMPRESSED_NAME_LIMIT: usize = 120;
1225
1226impl<'r> BinDecodable<'r> for Name {
1227    /// parses the chain of labels
1228    ///  this has a max of 255 octets, with each label being less than 63.
1229    ///  all names will be stored lowercase internally.
1230    /// This will consume the portions of the `Vec` which it is reading...
1231    fn read(decoder: &mut BinDecoder<'r>) -> Result<Self, DecodeError> {
1232        let mut name = Self::default();
1233        read_inner(decoder, &mut name, None)?;
1234        Ok(name)
1235    }
1236}
1237
1238fn read_inner(
1239    decoder: &mut BinDecoder<'_>,
1240    name: &mut Name,
1241    max_idx: Option<usize>,
1242) -> Result<(), DecodeError> {
1243    let mut state: LabelParseState = LabelParseState::LabelLengthOrPointer;
1244    let name_start = decoder.index();
1245
1246    // assume all chars are utf-8. We're doing byte-by-byte operations, no endianness issues...
1247    // reserved: (1000 0000 aka 0800) && (0100 0000 aka 0400)
1248    // pointer: (slice == 1100 0000 aka C0) & C0 == true, then 03FF & slice = offset
1249    // label: 03FF & slice = length; slice.next(length) = label
1250    // root: 0000
1251    loop {
1252        // this protects against overlapping labels
1253        if let Some(max_idx) = max_idx {
1254            if decoder.index() >= max_idx {
1255                return Err(DecodeError::LabelOverlapsWithOther {
1256                    label: name_start,
1257                    other: max_idx,
1258                });
1259            }
1260        }
1261
1262        state = match state {
1263            LabelParseState::LabelLengthOrPointer => {
1264                // determine what the next label is
1265                match decoder
1266                    .peek()
1267                    .map(Restrict::unverified /*verified in this usage*/)
1268                {
1269                    Some(0) => {
1270                        // RFC 1035 Section 3.1 - Name space definitions
1271                        //
1272                        // Domain names in messages are expressed in terms of a sequence of labels.
1273                        // Each label is represented as a one octet length field followed by that
1274                        // number of octets.  **Since every domain name ends with the null label of
1275                        // the root, a domain name is terminated by a length byte of zero.**  The
1276                        // high order two bits of every length octet must be zero, and the
1277                        // remaining six bits of the length field limit the label to 63 octets or
1278                        // less.
1279                        name.set_fqdn(true);
1280                        LabelParseState::Root
1281                    }
1282                    None => {
1283                        // Valid names on the wire should end in a 0-octet, signifying the end of
1284                        // the name. If the last byte wasn't 00, the name is invalid.
1285                        return Err(DecodeError::InsufficientBytes);
1286                    }
1287                    Some(byte) if byte & 0b1100_0000 == 0b1100_0000 => LabelParseState::Pointer,
1288                    Some(byte) if byte & 0b1100_0000 == 0b0000_0000 => LabelParseState::Label,
1289                    Some(byte) => return Err(DecodeError::UnrecognizedLabelCode(byte)),
1290                }
1291            }
1292            // labels must have a maximum length of 63
1293            LabelParseState::Label => {
1294                let label = decoder
1295                    .read_character_data()?
1296                    .verify_unwrap(|l| l.len() <= 63)
1297                    .map_err(|l| DecodeError::LabelBytesTooLong(l.len()))?;
1298
1299                name.extend_name(label)
1300                    .map_err(|_| DecodeError::DomainNameTooLong(label.len()))?;
1301
1302                // reset to collect more data
1303                LabelParseState::LabelLengthOrPointer
1304            }
1305            //         4.1.4. Message compression
1306            //
1307            // In order to reduce the size of messages, the domain system utilizes a
1308            // compression scheme which eliminates the repetition of domain names in a
1309            // message.  In this scheme, an entire domain name or a list of labels at
1310            // the end of a domain name is replaced with a pointer to a prior occurrence
1311            // of the same name.
1312            //
1313            // The pointer takes the form of a two octet sequence:
1314            //
1315            //     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1316            //     | 1  1|                OFFSET                   |
1317            //     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
1318            //
1319            // The first two bits are ones.  This allows a pointer to be distinguished
1320            // from a label, since the label must begin with two zero bits because
1321            // labels are restricted to 63 octets or less.  (The 10 and 01 combinations
1322            // are reserved for future use.)  The OFFSET field specifies an offset from
1323            // the start of the message (i.e., the first octet of the ID field in the
1324            // domain header).  A zero offset specifies the first byte of the ID field,
1325            // etc.
1326            LabelParseState::Pointer => {
1327                let pointer_location = decoder.index();
1328                let location = decoder
1329                    .read_u16()?
1330                    .map(|u| {
1331                        // get rid of the two high order bits, they are markers for length or pointers
1332                        u & 0x3FFF
1333                    })
1334                    .verify_unwrap(|ptr| {
1335                        // all labels must appear "prior" to this Name
1336                        (*ptr as usize) < name_start
1337                    })
1338                    .map_err(|e| DecodeError::PointerNotPriorToLabel {
1339                        idx: pointer_location,
1340                        ptr: e,
1341                    })?;
1342
1343                let mut pointer = decoder.clone(location);
1344                read_inner(&mut pointer, name, Some(name_start))?;
1345
1346                // Pointers always finish the name, break like Root.
1347                break;
1348            }
1349            LabelParseState::Root => {
1350                // need to pop() the 0 off the stack...
1351                decoder.pop()?;
1352                break;
1353            }
1354        }
1355    }
1356
1357    // TODO: should we consider checking this while the name is parsed?
1358    let len = name.len();
1359    if len >= 255 {
1360        return Err(DecodeError::DomainNameTooLong(len));
1361    }
1362
1363    Ok(())
1364}
1365
1366impl fmt::Display for Name {
1367    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1368        self.write_labels::<fmt::Formatter<'_>, LabelEncUtf8>(f)
1369    }
1370}
1371
1372impl PartialOrd<Self> for Name {
1373    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
1374        Some(self.cmp(other))
1375    }
1376}
1377
1378impl Ord for Name {
1379    /// Case insensitive comparison, see [`Name::cmp_case`] for case sensitive comparisons
1380    ///
1381    /// RFC 4034                DNSSEC Resource Records               March 2005
1382    ///
1383    /// ```text
1384    /// 6.1.  Canonical DNS Name Order
1385    ///
1386    ///  For the purposes of DNS security, owner names are ordered by treating
1387    ///  individual labels as unsigned left-justified octet strings.  The
1388    ///  absence of a octet sorts before a zero value octet, and uppercase
1389    ///  US-ASCII letters are treated as if they were lowercase US-ASCII
1390    ///  letters.
1391    ///
1392    ///  To compute the canonical ordering of a set of DNS names, start by
1393    ///  sorting the names according to their most significant (rightmost)
1394    ///  labels.  For names in which the most significant label is identical,
1395    ///  continue sorting according to their next most significant label, and
1396    ///  so forth.
1397    ///
1398    ///  For example, the following names are sorted in canonical DNS name
1399    ///  order.  The most significant label is "example".  At this level,
1400    ///  "example" sorts first, followed by names ending in "a.example", then
1401    ///  by names ending "z.example".  The names within each level are sorted
1402    ///  in the same way.
1403    ///
1404    ///            example
1405    ///            a.example
1406    ///            yljkjljk.a.example
1407    ///            Z.a.example
1408    ///            zABC.a.EXAMPLE
1409    ///            z.example
1410    ///            \001.z.example
1411    ///            *.z.example
1412    ///            \200.z.example
1413    /// ```
1414    fn cmp(&self, other: &Self) -> Ordering {
1415        self.cmp_with_f::<CaseInsensitive>(other)
1416    }
1417}
1418
1419/// This is the list of states for the label parsing state machine
1420enum LabelParseState {
1421    LabelLengthOrPointer, // basically the start of the FSM
1422    Label,                // storing length of the label, must be < 63
1423    Pointer,              // location of pointer in slice,
1424    Root,                 // root is the end of the labels list for an FQDN
1425}
1426
1427impl FromStr for Name {
1428    type Err = ProtoError;
1429
1430    /// Uses the Name::from_utf8 conversion on this string, see [Name::from_ascii] for ascii only, or for preserving case
1431    fn from_str(s: &str) -> Result<Self, Self::Err> {
1432        Self::from_str_relaxed(s)
1433    }
1434}
1435
1436/// Conversion into a Name
1437pub trait IntoName: Sized {
1438    /// Convert this into Name
1439    fn into_name(self) -> ProtoResult<Name>;
1440
1441    /// Check if this value is a valid IP address
1442    fn to_ip(&self) -> Option<IpAddr>;
1443}
1444
1445impl IntoName for &str {
1446    /// Performs a utf8, IDNA or punycode, translation of the `str` into `Name`
1447    fn into_name(self) -> ProtoResult<Name> {
1448        Name::from_utf8(self)
1449    }
1450
1451    fn to_ip(&self) -> Option<IpAddr> {
1452        IpAddr::from_str(self).ok()
1453    }
1454}
1455
1456impl IntoName for String {
1457    /// Performs a utf8, IDNA or punycode, translation of the `String` into `Name`
1458    fn into_name(self) -> ProtoResult<Name> {
1459        Name::from_utf8(self)
1460    }
1461
1462    fn to_ip(&self) -> Option<IpAddr> {
1463        IpAddr::from_str(self).ok()
1464    }
1465}
1466
1467impl IntoName for &String {
1468    /// Performs a utf8, IDNA or punycode, translation of the `&String` into `Name`
1469    fn into_name(self) -> ProtoResult<Name> {
1470        Name::from_utf8(self)
1471    }
1472
1473    fn to_ip(&self) -> Option<IpAddr> {
1474        IpAddr::from_str(self).ok()
1475    }
1476}
1477
1478impl<T> IntoName for T
1479where
1480    T: Into<Name>,
1481{
1482    fn into_name(self) -> ProtoResult<Name> {
1483        Ok(self.into())
1484    }
1485
1486    fn to_ip(&self) -> Option<IpAddr> {
1487        None
1488    }
1489}
1490
1491#[cfg(feature = "serde")]
1492impl Serialize for Name {
1493    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1494    where
1495        S: Serializer,
1496    {
1497        serializer.serialize_str(&self.to_string())
1498    }
1499}
1500
1501#[cfg(feature = "serde")]
1502impl<'de> Deserialize<'de> for Name {
1503    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1504    where
1505        D: Deserializer<'de>,
1506    {
1507        let s = String::deserialize(deserializer)?;
1508        FromStr::from_str(&s).map_err(de::Error::custom)
1509    }
1510}
1511
1512#[cfg(test)]
1513mod tests {
1514    #![allow(clippy::dbg_macro, clippy::print_stdout)]
1515
1516    use alloc::string::ToString;
1517    use core::cmp::Ordering;
1518    #[cfg(feature = "std")]
1519    use std::{collections::hash_map::DefaultHasher, println};
1520
1521    use super::*;
1522    use crate::error::ProtoError;
1523    use crate::serialize::binary::bin_tests::{test_emit_data_set, test_read_data_set};
1524
1525    fn get_data() -> Vec<(Name, Vec<u8>)> {
1526        vec![
1527            (Name::from_str(".").unwrap(), vec![0]), // base case, only the root
1528            (Name::from_str("a.").unwrap(), vec![1, b'a', 0]), // a single 'a' label
1529            (
1530                Name::from_str("a.bc.").unwrap(),
1531                vec![1, b'a', 2, b'b', b'c', 0],
1532            ), // two labels, 'a.bc'
1533            (
1534                Name::from_str("a.♥.").unwrap(),
1535                vec![1, b'a', 7, b'x', b'n', b'-', b'-', b'g', b'6', b'h', 0],
1536            ), // two labels utf8, 'a.♥'
1537        ]
1538    }
1539
1540    #[test]
1541    fn test_num_labels() {
1542        assert_eq!(Name::from_str("*").unwrap().num_labels(), 0);
1543        assert_eq!(Name::from_str("a").unwrap().num_labels(), 1);
1544        assert_eq!(Name::from_str("*.b").unwrap().num_labels(), 1);
1545        assert_eq!(Name::from_str("a.b").unwrap().num_labels(), 2);
1546        assert_eq!(Name::from_str("*.b.c").unwrap().num_labels(), 2);
1547        assert_eq!(Name::from_str("a.b.c").unwrap().num_labels(), 3);
1548    }
1549
1550    #[test]
1551    fn test_read() {
1552        test_read_data_set(get_data(), |mut d| Name::read(&mut d));
1553    }
1554
1555    #[test]
1556    fn test_write_to() {
1557        test_emit_data_set(get_data(), |e, n| n.emit(e));
1558    }
1559
1560    #[test]
1561    fn test_pointer() {
1562        let mut bytes = Vec::with_capacity(512);
1563
1564        let first = Name::from_str("ra.rb.rc.").unwrap();
1565        let second = Name::from_str("rb.rc.").unwrap();
1566        let third = Name::from_str("rc.").unwrap();
1567        let fourth = Name::from_str("z.ra.rb.rc.").unwrap();
1568
1569        {
1570            let mut e = BinEncoder::new(&mut bytes);
1571
1572            first.emit(&mut e).unwrap();
1573            assert_eq!(e.len(), 10); // should be 7 u8s...
1574
1575            second.emit(&mut e).unwrap();
1576            // if this wrote the entire thing, then it would be +5... but a pointer should be +2
1577            assert_eq!(e.len(), 12);
1578
1579            third.emit(&mut e).unwrap();
1580            assert_eq!(e.len(), 14);
1581
1582            fourth.emit(&mut e).unwrap();
1583            assert_eq!(e.len(), 18);
1584        }
1585
1586        // now read them back
1587        let mut d = BinDecoder::new(&bytes);
1588
1589        let r_test = Name::read(&mut d).unwrap();
1590        assert_eq!(first, r_test);
1591
1592        let r_test = Name::read(&mut d).unwrap();
1593        assert_eq!(second, r_test);
1594
1595        let r_test = Name::read(&mut d).unwrap();
1596        assert_eq!(third, r_test);
1597
1598        let r_test = Name::read(&mut d).unwrap();
1599        assert_eq!(fourth, r_test);
1600    }
1601
1602    #[test]
1603    fn test_pointer_with_pointer_ending_labels() {
1604        let mut bytes: Vec<u8> = Vec::with_capacity(512);
1605
1606        let first = Name::from_str("ra.rb.rc.").unwrap();
1607        let second = Name::from_str("ra.rc.").unwrap();
1608        let third = Name::from_str("ra.rc.").unwrap();
1609
1610        {
1611            let mut e = BinEncoder::new(&mut bytes);
1612
1613            first.emit(&mut e).unwrap();
1614            assert_eq!(e.len(), 10);
1615
1616            second.emit(&mut e).unwrap();
1617            // +5 with the first +3 being the text form of "ra" and +2 for the pointer to "rc".
1618            assert_eq!(e.len(), 15);
1619
1620            // +2 with the pointer to "ra.rc" as previously seen.
1621            third.emit(&mut e).unwrap();
1622            assert_eq!(e.len(), 17);
1623        }
1624
1625        // now read them back
1626        let mut d = BinDecoder::new(&bytes);
1627
1628        let r_test = Name::read(&mut d).unwrap();
1629        assert_eq!(first, r_test);
1630
1631        let r_test = Name::read(&mut d).unwrap();
1632        assert_eq!(second, r_test);
1633
1634        let r_test = Name::read(&mut d).unwrap();
1635        assert_eq!(third, r_test);
1636    }
1637
1638    #[test]
1639    fn test_recursive_pointer() {
1640        // points to an invalid beginning label marker
1641        let bytes = vec![0xC0, 0x01];
1642        let mut d = BinDecoder::new(&bytes);
1643
1644        assert!(Name::read(&mut d).is_err());
1645
1646        // formerly a stack overflow, recursing back on itself
1647        let bytes = vec![0xC0, 0x00];
1648        let mut d = BinDecoder::new(&bytes);
1649
1650        assert!(Name::read(&mut d).is_err());
1651
1652        // formerly a stack overflow, recursing back on itself
1653        let bytes = vec![0x01, 0x41, 0xC0, 0x00];
1654        let mut d = BinDecoder::new(&bytes);
1655
1656        assert!(Name::read(&mut d).is_err());
1657
1658        // formerly a stack overflow, recursing by going past the end, then back to the beginning.
1659        //   this is disallowed based on the rule that all labels must be "prior" to the current label.
1660        let bytes = vec![0xC0, 0x02, 0xC0, 0x00];
1661        let mut d = BinDecoder::new(&bytes);
1662
1663        assert!(Name::read(&mut d).is_err());
1664    }
1665
1666    #[test]
1667    fn test_bin_overlap_enforced() {
1668        let mut bytes: Vec<u8> = Vec::with_capacity(512);
1669        let n: u8 = 31;
1670        for _ in 0..=5 {
1671            bytes.extend(core::iter::repeat_n(n, n as usize));
1672        }
1673        bytes.push(n + 1);
1674        for b in 0..n {
1675            bytes.push(1 + n + b);
1676        }
1677        bytes.extend_from_slice(&[1, 0]);
1678        for b in 0..n {
1679            bytes.extend_from_slice(&[0xC0, b]);
1680        }
1681        let mut d = BinDecoder::new(&bytes);
1682        d.read_slice(n as usize).unwrap();
1683        assert!(Name::read(&mut d).is_err());
1684    }
1685
1686    #[test]
1687    fn test_bin_max_octets() {
1688        let mut bytes = Vec::with_capacity(512);
1689        for _ in 0..256 {
1690            bytes.extend_from_slice(&[1, b'a']);
1691        }
1692        bytes.push(0);
1693
1694        let mut d = BinDecoder::new(&bytes);
1695        assert!(Name::read(&mut d).is_err());
1696    }
1697
1698    #[test]
1699    fn test_base_name() {
1700        let zone = Name::from_str("example.com.").unwrap();
1701
1702        assert_eq!(zone.base_name(), Name::from_str("com.").unwrap());
1703        assert!(zone.base_name().base_name().is_root());
1704        assert!(zone.base_name().base_name().base_name().is_root());
1705    }
1706
1707    #[test]
1708    fn test_zone_of() {
1709        let zone = Name::from_str("example.com").unwrap();
1710        let www = Name::from_str("www.example.com").unwrap();
1711        let none = Name::from_str("none.com").unwrap();
1712        let root = Name::root();
1713
1714        assert!(zone.zone_of(&zone));
1715        assert!(zone.zone_of(&www));
1716        assert!(!zone.zone_of(&none));
1717        assert!(root.zone_of(&zone));
1718        assert!(!zone.zone_of(&root));
1719    }
1720
1721    #[test]
1722    fn test_zone_of_case() {
1723        let zone = Name::from_ascii("examplE.cOm").unwrap();
1724        let www = Name::from_str("www.example.com").unwrap();
1725        let none = Name::from_str("none.com").unwrap();
1726
1727        assert!(zone.zone_of(&zone));
1728        assert!(zone.zone_of(&www));
1729        assert!(!zone.zone_of(&none))
1730    }
1731
1732    #[test]
1733    fn test_partial_cmp_eq() {
1734        let root = Some(Name::from_labels(Vec::<&str>::new()).unwrap());
1735        let comparisons: Vec<(Name, Name)> = vec![
1736            (root.clone().unwrap(), root.clone().unwrap()),
1737            (
1738                Name::parse("example.", root.as_ref()).unwrap(),
1739                Name::parse("example", root.as_ref()).unwrap(),
1740            ),
1741        ];
1742
1743        for (left, right) in comparisons {
1744            #[cfg(feature = "std")]
1745            println!("left: {left}, right: {right}");
1746            assert_eq!(left.partial_cmp(&right), Some(Ordering::Equal));
1747        }
1748    }
1749
1750    #[test]
1751    fn test_partial_cmp() {
1752        let comparisons: Vec<(Name, Name)> = vec![
1753            (
1754                Name::from_str("example.").unwrap(),
1755                Name::from_str("a.example.").unwrap(),
1756            ),
1757            (
1758                Name::from_str("a.example.").unwrap(),
1759                Name::from_str("yljkjljk.a.example.").unwrap(),
1760            ),
1761            (
1762                Name::from_str("yljkjljk.a.example.").unwrap(),
1763                Name::from_ascii("Z.a.example.").unwrap(),
1764            ),
1765            (
1766                Name::from_ascii("Z.a.example").unwrap(),
1767                Name::from_ascii("zABC.a.EXAMPLE.").unwrap(),
1768            ),
1769            (
1770                Name::from_ascii("zABC.a.EXAMPLE.").unwrap(),
1771                Name::from_str("z.example.").unwrap(),
1772            ),
1773            (
1774                Name::from_str("z.example").unwrap(),
1775                Name::from_labels(vec![&[1u8] as &[u8], b"z", b"example."]).unwrap(),
1776            ),
1777            (
1778                Name::from_labels(vec![&[1u8] as &[u8], b"z", b"example"]).unwrap(),
1779                Name::from_str("*.z.example.").unwrap(),
1780            ),
1781            (
1782                Name::from_str("*.z.example").unwrap(),
1783                Name::from_labels(vec![&[200u8] as &[u8], b"z", b"example."]).unwrap(),
1784            ),
1785        ];
1786
1787        for (left, right) in comparisons {
1788            #[cfg(feature = "std")]
1789            println!("left: {left}, right: {right}");
1790            assert_eq!(left.cmp(&right), Ordering::Less);
1791        }
1792    }
1793
1794    #[test]
1795    fn test_cmp_ignore_case() {
1796        let comparisons: Vec<(Name, Name)> = vec![
1797            (
1798                Name::from_ascii("ExAmPle.").unwrap(),
1799                Name::from_ascii("example.").unwrap(),
1800            ),
1801            (
1802                Name::from_ascii("A.example.").unwrap(),
1803                Name::from_ascii("a.example.").unwrap(),
1804            ),
1805        ];
1806
1807        for (left, right) in comparisons {
1808            #[cfg(feature = "std")]
1809            println!("left: {left}, right: {right}");
1810            assert_eq!(left, right);
1811        }
1812    }
1813
1814    #[test]
1815    fn test_from_ipv4() {
1816        let ip = IpAddr::V4(Ipv4Addr::new(26, 3, 0, 103));
1817        let name = Name::from_str("103.0.3.26.in-addr.arpa.").unwrap();
1818
1819        assert_eq!(Into::<Name>::into(ip), name);
1820    }
1821
1822    #[test]
1823    fn test_from_ipv6() {
1824        let ip = IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0x1));
1825        let name = Name::from_str(
1826            "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa.",
1827        )
1828        .unwrap();
1829
1830        assert_eq!(Into::<Name>::into(ip), name);
1831    }
1832
1833    #[test]
1834    fn test_from_str() {
1835        assert_eq!(
1836            Name::from_str("www.example.com.").unwrap(),
1837            Name::from_labels(vec![b"www" as &[u8], b"example", b"com"]).unwrap()
1838        );
1839        assert_eq!(
1840            Name::from_str(".").unwrap(),
1841            Name::from_labels(Vec::<&str>::new()).unwrap()
1842        );
1843    }
1844
1845    #[test]
1846    fn test_fqdn() {
1847        assert!(Name::root().is_fqdn());
1848        assert!(Name::from_str(".").unwrap().is_fqdn());
1849        assert!(Name::from_str("www.example.com.").unwrap().is_fqdn());
1850        assert!(
1851            Name::from_labels(vec![b"www" as &[u8], b"example", b"com"])
1852                .unwrap()
1853                .is_fqdn()
1854        );
1855
1856        assert!(!Name::new().is_fqdn());
1857        assert!(!Name::from_str("www.example.com").unwrap().is_fqdn());
1858        assert!(!Name::from_str("www.example").unwrap().is_fqdn());
1859        assert!(!Name::from_str("www").unwrap().is_fqdn());
1860    }
1861
1862    #[test]
1863    fn test_to_string() {
1864        assert_eq!(
1865            Name::from_str("www.example.com.").unwrap().to_string(),
1866            "www.example.com."
1867        );
1868        assert_eq!(
1869            Name::from_str("www.example.com").unwrap().to_string(),
1870            "www.example.com"
1871        );
1872    }
1873
1874    #[test]
1875    fn test_from_ascii() {
1876        let bytes_name = Name::from_labels(vec![b"WWW" as &[u8], b"example", b"COM"]).unwrap();
1877        let ascii_name = Name::from_ascii("WWW.example.COM.").unwrap();
1878        let lower_name = Name::from_ascii("www.example.com.").unwrap();
1879
1880        assert!(bytes_name.eq_case(&ascii_name));
1881        assert!(!lower_name.eq_case(&ascii_name));
1882    }
1883
1884    #[test]
1885    fn test_from_utf8() {
1886        let bytes_name = Name::from_labels(vec![b"WWW" as &[u8], b"example", b"COM"]).unwrap();
1887        let utf8_name = Name::from_utf8("WWW.example.COM.").unwrap();
1888        let lower_name = Name::from_utf8("www.example.com.").unwrap();
1889
1890        assert!(!bytes_name.eq_case(&utf8_name));
1891        assert!(lower_name.eq_case(&utf8_name));
1892    }
1893
1894    #[test]
1895    fn test_into_name() {
1896        let name = Name::from_utf8("www.example.com").unwrap();
1897        assert_eq!(Name::from_utf8("www.example.com").unwrap(), name);
1898        assert_eq!(
1899            Name::from_utf8("www.example.com").unwrap(),
1900            Name::from_utf8("www.example.com")
1901                .unwrap()
1902                .into_name()
1903                .unwrap()
1904        );
1905        assert_eq!(
1906            Name::from_utf8("www.example.com").unwrap(),
1907            "www.example.com".into_name().unwrap()
1908        );
1909        assert_eq!(
1910            Name::from_utf8("www.example.com").unwrap(),
1911            "www.example.com".to_string().into_name().unwrap()
1912        );
1913    }
1914
1915    #[test]
1916    fn test_encoding() {
1917        assert_eq!(
1918            Name::from_ascii("WWW.example.COM.").unwrap().to_ascii(),
1919            "WWW.example.COM."
1920        );
1921        assert_eq!(
1922            Name::from_utf8("WWW.example.COM.").unwrap().to_ascii(),
1923            "www.example.com."
1924        );
1925        assert_eq!(
1926            Name::from_ascii("WWW.example.COM.").unwrap().to_utf8(),
1927            "WWW.example.COM."
1928        );
1929    }
1930
1931    #[test]
1932    fn test_excessive_encoding_len() {
1933        use crate::error::ProtoError;
1934
1935        // u16 max value is where issues start being tickled...
1936        let mut buf = Vec::with_capacity(u16::MAX as usize);
1937        let mut encoder = BinEncoder::new(&mut buf);
1938
1939        let mut result = Ok(());
1940        for i in 0..10000 {
1941            let name = Name::from_ascii(format!("name{i}.example.com.")).unwrap();
1942            result = name.emit(&mut encoder);
1943            if result.is_err() {
1944                break;
1945            }
1946        }
1947
1948        match result.unwrap_err() {
1949            ProtoError::MaxBufferSizeExceeded(_) => (),
1950            _ => panic!(),
1951        }
1952    }
1953
1954    #[test]
1955    fn test_underscore() {
1956        Name::from_str("_begin.example.com").expect("failed at beginning");
1957        Name::from_str_relaxed("mid_dle.example.com").expect("failed in the middle");
1958        Name::from_str_relaxed("end_.example.com").expect("failed at the end");
1959    }
1960
1961    #[test]
1962    fn test_parse_arpa_name() {
1963        assert!(
1964            Name::from_ascii("168.192.in-addr.arpa")
1965                .unwrap()
1966                .parse_arpa_name()
1967                .is_err()
1968        );
1969        assert!(
1970            Name::from_ascii("host.example.com.")
1971                .unwrap()
1972                .parse_arpa_name()
1973                .is_err()
1974        );
1975        assert!(
1976            Name::from_ascii("caffee.ip6.arpa.")
1977                .unwrap()
1978                .parse_arpa_name()
1979                .is_err()
1980        );
1981        assert!(
1982            Name::from_ascii(
1983                "1.4.3.3.7.0.7.3.0.E.2.A.8.9.1.3.1.3.D.8.0.3.A.5.8.8.B.D.0.1.0.0.2.ip6.arpa."
1984            )
1985            .unwrap()
1986            .parse_arpa_name()
1987            .is_err()
1988        );
1989        assert!(
1990            Name::from_ascii("caffee.in-addr.arpa.")
1991                .unwrap()
1992                .parse_arpa_name()
1993                .is_err()
1994        );
1995        assert!(
1996            Name::from_ascii("1.2.3.4.5.in-addr.arpa.")
1997                .unwrap()
1998                .parse_arpa_name()
1999                .is_err()
2000        );
2001        assert!(
2002            Name::from_ascii("1.2.3.4.home.arpa.")
2003                .unwrap()
2004                .parse_arpa_name()
2005                .is_err()
2006        );
2007        assert_eq!(
2008            Name::from_ascii("168.192.in-addr.arpa.")
2009                .unwrap()
2010                .parse_arpa_name()
2011                .unwrap(),
2012            IpNet::V4(Ipv4Net::new("192.168.0.0".parse().unwrap(), 16).unwrap())
2013        );
2014        assert_eq!(
2015            Name::from_ascii("1.0.168.192.in-addr.arpa.")
2016                .unwrap()
2017                .parse_arpa_name()
2018                .unwrap(),
2019            IpNet::V4(Ipv4Net::new("192.168.0.1".parse().unwrap(), 32).unwrap())
2020        );
2021        assert_eq!(
2022            Name::from_ascii("0.1.0.0.2.ip6.arpa.")
2023                .unwrap()
2024                .parse_arpa_name()
2025                .unwrap(),
2026            IpNet::V6(Ipv6Net::new("2001::".parse().unwrap(), 20).unwrap())
2027        );
2028        assert_eq!(
2029            Name::from_ascii("D.0.1.0.0.2.ip6.arpa.")
2030                .unwrap()
2031                .parse_arpa_name()
2032                .unwrap(),
2033            IpNet::V6(Ipv6Net::new("2001:d00::".parse().unwrap(), 24).unwrap())
2034        );
2035        assert_eq!(
2036            Name::from_ascii("B.D.0.1.0.0.2.ip6.arpa.")
2037                .unwrap()
2038                .parse_arpa_name()
2039                .unwrap(),
2040            IpNet::V6(Ipv6Net::new("2001:db0::".parse().unwrap(), 28).unwrap())
2041        );
2042        assert_eq!(
2043            Name::from_ascii("8.B.D.0.1.0.0.2.ip6.arpa.")
2044                .unwrap()
2045                .parse_arpa_name()
2046                .unwrap(),
2047            IpNet::V6(Ipv6Net::new("2001:db8::".parse().unwrap(), 32).unwrap())
2048        );
2049        assert_eq!(
2050            Name::from_ascii(
2051                "4.3.3.7.0.7.3.0.E.2.A.8.9.1.3.1.3.D.8.0.3.A.5.8.8.B.D.0.1.0.0.2.ip6.arpa."
2052            )
2053            .unwrap()
2054            .parse_arpa_name()
2055            .unwrap(),
2056            IpNet::V6(
2057                Ipv6Net::new("2001:db8:85a3:8d3:1319:8a2e:370:7334".parse().unwrap(), 128).unwrap()
2058            )
2059        );
2060    }
2061
2062    #[test]
2063    fn test_prepend_label() {
2064        for name in ["foo.com", "foo.com."] {
2065            let name = Name::from_ascii(name).unwrap();
2066
2067            for label in ["bar", "baz", "quux"] {
2068                let sub = name.clone().prepend_label(label).unwrap();
2069                let expected = Name::from_ascii(format!("{label}.{name}")).unwrap();
2070                assert_eq!(expected, sub);
2071            }
2072        }
2073
2074        for name in ["", "."] {
2075            let name = Name::from_ascii(name).unwrap();
2076
2077            for label in ["bar", "baz", "quux"] {
2078                let sub = name.clone().prepend_label(label).unwrap();
2079                let expected = Name::from_ascii(format!("{label}{name}")).unwrap();
2080                assert_eq!(expected, sub);
2081            }
2082        }
2083    }
2084
2085    #[test]
2086    fn test_name_too_long_with_prepend() {
2087        let n = Name::from_ascii("Llocainvannnnnnaxgtezqzqznnnnnn1na.nnntnninvannnnnnaxgtezqzqznnnnnn1na.nnntnnnnnnnaxgtezqzqznnnnnn1na.nnntnaaaaaaaaaaaaaaaaaaaaaaaaiK.iaaaaaaaaaaaaaaaaaaaaaaaaiKa.innnnnaxgtezqzqznnnnnn1na.nnntnaaaaaaaaaaaaaaaaaaaaaaaaiK.iaaaaaaaaaaaaaaaaaaaaaaaaiKa.in").unwrap();
2088        let sfx = "xxxxxxx.yyyyy.zzz";
2089
2090        let error = n
2091            .prepend_label(sfx)
2092            .expect_err("should have errored, too long");
2093
2094        match error {
2095            ProtoError::Decode(DecodeError::DomainNameTooLong(_)) => (),
2096            _ => panic!("expected too long message"),
2097        }
2098    }
2099
2100    #[test]
2101    fn test_name_too_long_with_append() {
2102        // from https://github.com/hickory-dns/hickory-dns/issues/1447
2103        let n = Name::from_ascii("Llocainvannnnnnaxgtezqzqznnnnnn1na.nnntnninvannnnnnaxgtezqzqznnnnnn1na.nnntnnnnnnnaxgtezqzqznnnnnn1na.nnntnaaaaaaaaaaaaaaaaaaaaaaaaiK.iaaaaaaaaaaaaaaaaaaaaaaaaiKa.innnnnaxgtezqzqznnnnnn1na.nnntnaaaaaaaaaaaaaaaaaaaaaaaaiK.iaaaaaaaaaaaaaaaaaaaaaaaaiKa.in").unwrap();
2104        let sfx = Name::from_ascii("xxxxxxx.yyyyy.zzz").unwrap();
2105
2106        let error = n
2107            .append_domain(&sfx)
2108            .expect_err("should have errored, too long");
2109
2110        match error {
2111            ProtoError::Decode(DecodeError::DomainNameTooLong(_)) => (),
2112            _ => panic!("expected too long message"),
2113        }
2114    }
2115
2116    #[test]
2117    fn test_encoded_len() {
2118        for name in [
2119            // FQDN
2120            Name::parse("www.example.com.", None).unwrap(),
2121            // Non-FQDN
2122            Name::parse("www", None).unwrap(),
2123            // Root (FQDN)
2124            Name::root(),
2125            // Empty (non-FQDN)
2126            Name::new(),
2127        ] {
2128            let mut buffer = Vec::new();
2129            let mut encoder = BinEncoder::new(&mut buffer);
2130            name.emit(&mut encoder).unwrap();
2131
2132            assert_eq!(
2133                name.encoded_len(),
2134                buffer.len(),
2135                "encoded_len() was incorrect for {name:?}"
2136            );
2137        }
2138    }
2139
2140    #[test]
2141    fn test_length_limits() {
2142        // Labels are limited to 63 bytes, and names are limited to 255 bytes.
2143        // This name is composed of three labels of length 63, a label of length 61, and a label of
2144        // length 0 for the root zone. There are a total of five length bytes. Thus, the total
2145        // length is 63 + 63 + 63 + 61 + 5 = 255.
2146        let encoded_name_255_bytes: [u8; 255] = [
2147            63, b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a',
2148            b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a',
2149            b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a',
2150            b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a',
2151            b'a', b'a', b'a', b'a', b'a', b'a', b'a', 63, b'a', b'a', b'a', b'a', b'a', b'a', b'a',
2152            b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a',
2153            b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a',
2154            b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a',
2155            b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', 63,
2156            b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a',
2157            b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a',
2158            b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a',
2159            b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a',
2160            b'a', b'a', b'a', b'a', b'a', b'a', b'a', 61, b'a', b'a', b'a', b'a', b'a', b'a', b'a',
2161            b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a',
2162            b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a',
2163            b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a',
2164            b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', b'a', 0,
2165        ];
2166        let expected_name_str = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.\
2167        aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.\
2168        aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.\
2169        aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.";
2170
2171        let mut decoder = BinDecoder::new(&encoded_name_255_bytes);
2172        let decoded_name = Name::read(&mut decoder).unwrap();
2173        assert!(decoder.is_empty());
2174
2175        assert_eq!(decoded_name.to_string(), expected_name_str);
2176
2177        // Should not be able to construct a longer name from a string.
2178        let long_label_error = Name::parse(&format!("a{expected_name_str}"), None).unwrap_err();
2179        assert!(matches!(
2180            long_label_error,
2181            ProtoError::Decode(DecodeError::LabelBytesTooLong(64))
2182        ));
2183        let long_name_error =
2184            Name::parse(&format!("a.{}", &expected_name_str[1..]), None).unwrap_err();
2185        assert!(matches!(
2186            long_name_error,
2187            ProtoError::Decode(DecodeError::DomainNameTooLong(256))
2188        ))
2189    }
2190
2191    #[test]
2192    fn test_double_ended_iterator() {
2193        let name = Name::from_ascii("www.example.com").unwrap();
2194        let mut iter = name.iter();
2195
2196        assert_eq!(iter.next().unwrap(), b"www");
2197        assert_eq!(iter.next_back().unwrap(), b"com");
2198        assert_eq!(iter.next().unwrap(), b"example");
2199        assert!(iter.next_back().is_none());
2200        assert!(iter.next().is_none());
2201    }
2202
2203    #[test]
2204    fn test_size_hint() {
2205        let name = Name::from_ascii("www.example.com").unwrap();
2206        let mut iter = name.iter();
2207
2208        assert_eq!(iter.size_hint().0, 3);
2209        assert_eq!(iter.next().unwrap(), b"www");
2210        assert_eq!(iter.size_hint().0, 2);
2211        assert_eq!(iter.next_back().unwrap(), b"com");
2212        assert_eq!(iter.size_hint().0, 1);
2213        assert_eq!(iter.next().unwrap(), b"example");
2214        assert_eq!(iter.size_hint().0, 0);
2215        assert!(iter.next_back().is_none());
2216        assert_eq!(iter.size_hint().0, 0);
2217        assert!(iter.next().is_none());
2218        assert_eq!(iter.size_hint().0, 0);
2219    }
2220
2221    #[test]
2222    #[cfg(feature = "std")]
2223    fn test_label_randomization() {
2224        let mut name = Name::root();
2225        name.randomize_label_case();
2226        assert!(name.eq_case(&Name::root()));
2227
2228        for qname in [
2229            "x",
2230            "0",
2231            "aaaaaaaaaaaaaaaa",
2232            "AAAAAAAAAAAAAAAA",
2233            "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.",
2234            "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.",
2235            "abcdefghijklmnopqrstuvwxyz0123456789A.",
2236            "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.",
2237            "www01.example-site.com",
2238            "1234567890.e-1204089_043820-5.com.",
2239        ] {
2240            let mut name = Name::from_ascii(qname).unwrap();
2241            let name2 = name.clone();
2242            name.randomize_label_case();
2243            assert_eq!(name, name2);
2244            println!("{name2} == {name}: {}", name == name2);
2245        }
2246
2247        // 50k iterations gets us very close to a 50/50 uppercase/lowercase distribution in testing
2248        // without a long test runtime.
2249        let iterations = 50_000;
2250
2251        // This is a max length name (255 bytes) with the maximum number of possible flippable bytes
2252        // (nominal label length 63, except the last, with all label characters ASCII alpha)
2253        let test_str = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijk.lmnopqrstuvwxyzabcdefghjijklmnopqrstuvwxyzabcdefghijklmnopqrstu.vwxyzABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEF.GHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNO";
2254        let mut name = Name::from_ascii(test_str).unwrap();
2255        let name2 = name.clone();
2256
2257        let len = name.label_data.len();
2258        let mut cap_table: [u32; 255] = [0; 255];
2259        let mut lower_table: [u32; 255] = [0; 255];
2260        let mut mean_table: [f64; 255] = [0.0; 255];
2261
2262        for _ in 0..iterations {
2263            name.randomize_label_case();
2264            assert_eq!(name, name2);
2265
2266            for (j, &cbyte) in name.label_data.iter().enumerate() {
2267                if cbyte.is_ascii_lowercase() {
2268                    lower_table[j] += 1;
2269                } else if cbyte.is_ascii_uppercase() {
2270                    cap_table[j] += 1;
2271                }
2272            }
2273            name = Name::from_ascii(test_str).unwrap();
2274        }
2275
2276        println!("Distribution of lower case values by label offset");
2277        println!("-------------------------------------------------");
2278        for i in 0..len {
2279            let cap_ratio = cap_table[i] as f64 / iterations as f64;
2280            let lower_ratio = lower_table[i] as f64 / iterations as f64;
2281            let total_ratio = cap_ratio + lower_ratio;
2282            mean_table[i] = lower_ratio;
2283            println!(
2284                "{i:03} {:.3}% {:.3}% {:.3}%",
2285                cap_ratio * 100.0,
2286                lower_ratio * 100.0,
2287                total_ratio * 100.0,
2288            );
2289        }
2290        println!("-------------------------------------------------");
2291
2292        let data_mean = mean_table.iter().sum::<f64>() / len as f64;
2293        let data_std_deviation = std_deviation(data_mean, &mean_table);
2294
2295        let mut max_zscore = 0.0;
2296        for elem in mean_table.iter() {
2297            let zscore = (elem - data_mean) / data_std_deviation;
2298
2299            if zscore > max_zscore {
2300                max_zscore = zscore;
2301            }
2302        }
2303
2304        println!("μ: {data_mean:.4} σ: {data_std_deviation:.4}, max variance: {max_zscore:.4}σ");
2305
2306        // These levels are from observed test behavior; typical values for 50k iterations are:
2307        //
2308        //   mean: ~ 50% (this is the % of test iterations where the value is lower case)
2309        //   standard deviation: ~ 0.063
2310        //   largest z-score: ~ 0.10 (i.e., around 1/10 of a standard deviation)
2311        //
2312        // The values below are designed to avoid random CI test failures, but alert on any
2313        // significant variation from the observed randomization behavior during test development.
2314        //
2315        // Specifically, this test will fail if there is a single bit hole in the random bit stream
2316        assert!(data_mean > 0.485 && data_mean < 0.515);
2317        assert!(data_std_deviation < 0.18);
2318        assert!(max_zscore < 0.33);
2319    }
2320
2321    #[cfg(feature = "std")]
2322    fn std_deviation(mean: f64, data: &[f64]) -> f64 {
2323        match (mean, data.len()) {
2324            (data_mean, count) if count > 0 => {
2325                let variance = data
2326                    .iter()
2327                    .map(|value| {
2328                        let diff = data_mean - *value;
2329
2330                        diff * diff
2331                    })
2332                    .sum::<f64>()
2333                    / count as f64;
2334
2335                variance.sqrt()
2336            }
2337            _ => 0.0,
2338        }
2339    }
2340
2341    #[test]
2342    fn test_fqdn_escaped_dot() {
2343        let name = Name::from_utf8("test.").unwrap();
2344        assert!(name.is_fqdn());
2345
2346        let name = Name::from_utf8("test\\.").unwrap();
2347        assert!(!name.is_fqdn());
2348
2349        let name = Name::from_utf8("").unwrap();
2350        assert!(!name.is_fqdn());
2351
2352        let name = Name::from_utf8(".").unwrap();
2353        assert!(name.is_fqdn());
2354    }
2355
2356    #[test]
2357    #[allow(clippy::nonminimal_bool)]
2358    fn test_name_partialeq_constraints() {
2359        let example_fqdn = Name::from_utf8("example.com.").unwrap();
2360        let example_nonfqdn = Name::from_utf8("example.com").unwrap();
2361        let other_fqdn = Name::from_utf8("otherdomain.com.").unwrap();
2362
2363        assert_eq!(example_fqdn, example_fqdn);
2364        assert_eq!(example_nonfqdn, example_nonfqdn);
2365        assert!(example_fqdn != example_nonfqdn);
2366
2367        // a != b if and only if !(a == b).
2368        assert!(example_fqdn != example_nonfqdn && !(example_fqdn == example_nonfqdn));
2369        assert!(example_nonfqdn != example_fqdn && !(example_nonfqdn == example_fqdn));
2370        assert!(example_fqdn != other_fqdn && !(example_fqdn == other_fqdn));
2371        assert!(example_nonfqdn != other_fqdn && !(example_nonfqdn == other_fqdn));
2372    }
2373
2374    #[test]
2375    fn test_name_partialord_constraints() {
2376        use core::cmp::Ordering::*;
2377
2378        let example_fqdn = Name::from_utf8("example.com.").unwrap();
2379        let foo_example_fqdn = Name::from_utf8("foo.example.com.").unwrap();
2380        let example_nonfqdn = Name::from_utf8("example.com").unwrap();
2381        let foo_example_nonfqdn = Name::from_utf8("foo.example.com").unwrap();
2382
2383        // 1. a == b if and only if partial_cmp(a, b) == Some(Equal).
2384        assert_eq!(example_fqdn.partial_cmp(&example_fqdn), Some(Equal),);
2385        assert!(example_fqdn.partial_cmp(&example_nonfqdn) != Some(Equal));
2386
2387        // 2. a < b if and only if partial_cmp(a, b) == Some(Less)
2388        assert!(
2389            example_nonfqdn < example_fqdn
2390                && example_nonfqdn.partial_cmp(&example_fqdn) == Some(Less)
2391        );
2392
2393        assert!(
2394            example_fqdn < foo_example_fqdn
2395                && example_fqdn.partial_cmp(&foo_example_fqdn) == Some(Less)
2396        );
2397
2398        assert!(
2399            example_nonfqdn < foo_example_nonfqdn
2400                && example_nonfqdn.partial_cmp(&foo_example_nonfqdn) == Some(Less)
2401        );
2402
2403        // 3. a > b) if and only if partial_cmp(a, b) == Some(Greater)
2404        assert!(
2405            example_fqdn > example_nonfqdn
2406                && example_fqdn.partial_cmp(&example_nonfqdn) == Some(Greater)
2407        );
2408
2409        assert!(
2410            foo_example_fqdn > example_fqdn
2411                && foo_example_fqdn.partial_cmp(&example_fqdn) == Some(Greater)
2412        );
2413
2414        assert!(
2415            foo_example_nonfqdn > example_nonfqdn
2416                && foo_example_nonfqdn.partial_cmp(&example_nonfqdn) == Some(Greater)
2417        );
2418
2419        // 4. a <= b if and only if a < b || a == b
2420        assert!(example_nonfqdn <= example_fqdn);
2421        assert!(example_nonfqdn <= example_nonfqdn);
2422        assert!(example_fqdn <= example_fqdn);
2423        assert!(example_nonfqdn <= foo_example_nonfqdn);
2424        assert!(example_fqdn <= foo_example_fqdn);
2425        assert!(foo_example_nonfqdn <= foo_example_nonfqdn);
2426        assert!(foo_example_fqdn <= foo_example_fqdn);
2427
2428        // 5. a >= b if and only if a > b || a == b
2429        assert!(example_fqdn >= example_nonfqdn);
2430        assert!(example_nonfqdn >= example_nonfqdn);
2431        assert!(example_fqdn >= example_fqdn);
2432        assert!(foo_example_nonfqdn >= example_nonfqdn);
2433        assert!(foo_example_fqdn >= example_fqdn);
2434        assert!(foo_example_nonfqdn >= foo_example_nonfqdn);
2435        assert!(foo_example_fqdn >= foo_example_fqdn);
2436
2437        // 6. a != b if and only if !(a == b). -- Tested in test_name_partialeq_constraints.
2438    }
2439
2440    #[test]
2441    fn test_name_ord_constraints() {
2442        use core::cmp;
2443
2444        let example_fqdn = Name::from_utf8("example.com.").unwrap();
2445        let foo_example_fqdn = Name::from_utf8("foo.example.com.").unwrap();
2446        let example_nonfqdn = Name::from_utf8("example.com").unwrap();
2447        let foo_example_nonfqdn = Name::from_utf8("foo.example.com").unwrap();
2448
2449        // These are consistency checks between Ord and PartialOrd; therefore
2450        // we don't really care about picking the individual mappings and want
2451        // to test on all possible combinations.
2452        for pair in [
2453            (&example_fqdn, &example_fqdn),
2454            (&example_fqdn, &example_nonfqdn),
2455            (&example_fqdn, &foo_example_fqdn),
2456            (&example_fqdn, &foo_example_nonfqdn),
2457            (&example_nonfqdn, &example_nonfqdn),
2458            (&example_nonfqdn, &example_fqdn),
2459            (&example_nonfqdn, &foo_example_fqdn),
2460            (&example_nonfqdn, &foo_example_nonfqdn),
2461            (&foo_example_fqdn, &example_nonfqdn),
2462            (&foo_example_fqdn, &example_fqdn),
2463            (&foo_example_fqdn, &foo_example_fqdn),
2464            (&foo_example_fqdn, &foo_example_nonfqdn),
2465            (&foo_example_fqdn, &example_nonfqdn),
2466            (&foo_example_fqdn, &example_fqdn),
2467            (&foo_example_fqdn, &foo_example_fqdn),
2468            (&foo_example_fqdn, &foo_example_nonfqdn),
2469        ] {
2470            let name1 = pair.0;
2471            let name2 = pair.1;
2472
2473            // 1. partial_cmp(a, b) == Some(cmp(a, b)).
2474            assert_eq!(name1.partial_cmp(name2), Some(name1.cmp(name2)));
2475
2476            // 2. max(a, b) == max_by(a, b, cmp) (ensured by the default implementation).
2477            assert_eq!(
2478                name1.clone().max(name2.clone()),
2479                cmp::max_by(name1.clone(), name2.clone(), |x: &Name, y: &Name| x.cmp(y)),
2480            );
2481
2482            // 3. min(a, b) == min_by(a, b, cmp) (ensured by the default implementation).
2483            assert_eq!(
2484                name1.clone().min(name2.clone()),
2485                cmp::min_by(name1.clone(), name2.clone(), |x: &Name, y: &Name| x.cmp(y)),
2486            );
2487        }
2488
2489        // 4. For a.clamp(min, max), see the method docs (ensured by the default implementation).
2490        //
2491        // Restrict a value to a certain interval.
2492        // Returns max if self is greater than max, and min if self is less than min.
2493        // Otherwise this returns self.
2494        //
2495        // Panics if min > max -- tested in test_ord_clamp_panic
2496        let min_name = Name::from_utf8("com").unwrap();
2497        let max_name = Name::from_utf8("max.example.com.").unwrap();
2498
2499        assert_eq!(
2500            min_name
2501                .clone()
2502                .clamp(min_name.clone(), example_nonfqdn.clone()),
2503            min_name.clone(),
2504        );
2505
2506        assert_eq!(
2507            max_name
2508                .clone()
2509                .clamp(example_nonfqdn.clone(), example_fqdn.clone()),
2510            example_fqdn.clone(),
2511        );
2512
2513        assert_eq!(
2514            max_name
2515                .clone()
2516                .clamp(example_nonfqdn.clone(), max_name.clone()),
2517            max_name.clone(),
2518        );
2519
2520        // Transitivity tests
2521        // if A < B and B < C then A < C
2522        // if A > B and B > C then A > C
2523        let most_min_name = Name::from_utf8("").unwrap();
2524        let most_max_name = Name::from_utf8("most.max.example.com.").unwrap();
2525        assert_eq!(min_name.cmp(&example_nonfqdn), Ordering::Less);
2526        assert_eq!(most_min_name.cmp(&min_name), Ordering::Less);
2527        assert_eq!(most_min_name.cmp(&example_nonfqdn), Ordering::Less);
2528        assert_eq!(max_name.cmp(&example_fqdn), Ordering::Greater);
2529        assert_eq!(most_max_name.cmp(&max_name), Ordering::Greater);
2530        assert_eq!(most_max_name.cmp(&example_fqdn), Ordering::Greater);
2531    }
2532
2533    #[test]
2534    #[should_panic]
2535    fn test_ord_clamp_panic() {
2536        let min_name = Name::from_utf8("com").unwrap();
2537        let max_name = Name::from_utf8("max.example.com.").unwrap();
2538
2539        // this should panic since min > max
2540        let _ = min_name.clone().clamp(max_name, min_name);
2541    }
2542
2543    #[test]
2544    #[cfg(feature = "std")]
2545    fn test_hash() {
2546        // verify that two identical names with and without the trailing dot hashes to the same value
2547        let mut hasher = DefaultHasher::new();
2548        let with_dot = Name::from_utf8("com.").unwrap();
2549        with_dot.hash(&mut hasher);
2550        let hash_with_dot = hasher.finish();
2551
2552        let mut hasher = DefaultHasher::new();
2553        let without_dot = Name::from_utf8("com").unwrap();
2554        without_dot.hash(&mut hasher);
2555        let hash_without_dot = hasher.finish();
2556        assert_ne!(with_dot, without_dot);
2557        assert_ne!(hash_with_dot, hash_without_dot);
2558    }
2559
2560    #[test]
2561    fn eq_ignore_root_tests() {
2562        let fqdn_name = Name::from_utf8("host.example.com.").unwrap();
2563        let relative_name = Name::from_utf8("host.example.com").unwrap();
2564        let upper_relative_name = Name::from_ascii("HOST.EXAMPLE.COM").unwrap();
2565
2566        assert_ne!(fqdn_name, relative_name);
2567        assert!(fqdn_name.eq_ignore_root(&relative_name));
2568        assert!(!fqdn_name.eq_ignore_root_case(&upper_relative_name));
2569        assert!(fqdn_name.eq_ignore_root(&upper_relative_name));
2570    }
2571
2572    #[test]
2573    fn rfc4034_canonical_ordering_example() {
2574        // From section 6.1 of RFC 4034
2575        let names = Vec::from([
2576            Name::from_labels::<_, &[u8]>([b"example".as_slice()]).unwrap(),
2577            Name::from_labels::<_, &[u8]>([b"a".as_slice(), b"example".as_slice()]).unwrap(),
2578            Name::from_labels::<_, &[u8]>([
2579                b"yljkjljk".as_slice(),
2580                b"a".as_slice(),
2581                b"example".as_slice(),
2582            ])
2583            .unwrap(),
2584            Name::from_labels::<_, &[u8]>([
2585                b"Z".as_slice(),
2586                b"a".as_slice(),
2587                b"example".as_slice(),
2588            ])
2589            .unwrap(),
2590            Name::from_labels::<_, &[u8]>([
2591                b"zABC".as_slice(),
2592                b"a".as_slice(),
2593                b"EXAMPLE".as_slice(),
2594            ])
2595            .unwrap(),
2596            Name::from_labels::<_, &[u8]>([b"z".as_slice(), b"example".as_slice()]).unwrap(),
2597            Name::from_labels::<_, &[u8]>([
2598                b"\x01".as_slice(),
2599                b"z".as_slice(),
2600                b"example".as_slice(),
2601            ])
2602            .unwrap(),
2603            Name::from_labels::<_, &[u8]>([
2604                b"*".as_slice(),
2605                b"z".as_slice(),
2606                b"example".as_slice(),
2607            ])
2608            .unwrap(),
2609            Name::from_labels::<_, &[u8]>([
2610                b"\x80".as_slice(),
2611                b"z".as_slice(),
2612                b"example".as_slice(),
2613            ])
2614            .unwrap(),
2615        ]);
2616        let mut sorted = names.clone();
2617        sorted.sort();
2618        assert_eq!(names, sorted);
2619    }
2620}