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        self.label_ends.hash(state);
1131        // Note: case-insensitive like `PartialEq`
1132        self.iter()
1133            .flatten()
1134            .for_each(|&b| state.write_u8(b.to_ascii_lowercase()));
1135    }
1136}
1137
1138enum ParseState {
1139    Label,
1140    Escape1,
1141    Escape2(u32),
1142    Escape3(u32, u32),
1143}
1144
1145impl BinEncodable for Name {
1146    fn emit(&self, encoder: &mut BinEncoder<'_>) -> ProtoResult<()> {
1147        let name;
1148        let name_ref = if matches!(encoder.name_encoding(), NameEncoding::UncompressedLowercase) {
1149            name = self.to_lowercase();
1150            &name
1151        } else {
1152            self
1153        };
1154        let compression = matches!(encoder.name_encoding(), NameEncoding::Compressed)
1155            && encoder.compressed_name_count < COMPRESSED_NAME_LIMIT;
1156
1157        let buf_len = encoder.len(); // lazily assert the size is less than 255...
1158        // lookup the label in the BinEncoder
1159        // if it exists, write the Pointer
1160        let labels = name_ref.iter();
1161
1162        // start index of each label
1163        let mut labels_written = Vec::with_capacity(name_ref.label_ends.len());
1164        // we're going to write out each label, tracking the indexes of the start to each label
1165        //   then we'll look to see if we can remove them and recapture the capacity in the buffer...
1166        for label in labels {
1167            if label.len() > 63 {
1168                return Err(DecodeError::LabelBytesTooLong(label.len()).into());
1169            }
1170
1171            labels_written.push(encoder.offset());
1172            encoder.emit_character_data(label)?;
1173        }
1174        let last_index = encoder.offset();
1175        // now search for other labels already stored matching from the beginning label, strip then to the end
1176        //   if it's not found, then store this as a new label
1177        if compression {
1178            encoder.compressed_name_count += 1;
1179            for label_idx in &labels_written {
1180                match encoder.get_label_pointer(*label_idx, last_index) {
1181                    Some(loc) if loc & 0xC000 == 0 => {
1182                        // reset back to the beginning of this label, and then write the pointer...
1183                        encoder.set_offset(*label_idx);
1184                        encoder.trim();
1185
1186                        // write out the pointer marker
1187                        //  or'd with the location which is less than 2^14
1188                        encoder.emit_u16(0xC000u16 | loc)?;
1189
1190                        // we found a pointer don't write more, break
1191                        return Ok(());
1192                    }
1193                    _ => {
1194                        // no existing label exists, store this new one.
1195                        encoder.store_label_pointer(*label_idx, last_index);
1196                    }
1197                }
1198            }
1199        } else {
1200            // Compression is disabled for either this name or the entire message. Just attempt to
1201            // store the label pointers, in case they'll be used by an eligible RData type later.
1202            for label_idx in &labels_written {
1203                encoder.store_label_pointer(*label_idx, last_index);
1204            }
1205        }
1206
1207        // if we're getting here, then we didn't write out a pointer and are ending the name
1208        // the end of the list of names
1209        encoder.emit(0)?;
1210
1211        // the entire name needs to be less than 256.
1212        let length = encoder.len() - buf_len;
1213        if length > 255 {
1214            return Err(DecodeError::DomainNameTooLong(length).into());
1215        }
1216
1217        Ok(())
1218    }
1219}
1220
1221/// Maximum number of names for which name compression will be attempted per message.
1222///
1223/// This limit matches that from Unbound, see
1224/// <https://nlnetlabs.nl/downloads/unbound/patch_CVE-2024-8508.diff>.
1225const COMPRESSED_NAME_LIMIT: usize = 120;
1226
1227impl<'r> BinDecodable<'r> for Name {
1228    /// parses the chain of labels
1229    ///  this has a max of 255 octets, with each label being less than 63.
1230    ///  all names will be stored lowercase internally.
1231    /// This will consume the portions of the `Vec` which it is reading...
1232    fn read(decoder: &mut BinDecoder<'r>) -> Result<Self, DecodeError> {
1233        let mut name = Self::default();
1234        read_inner(decoder, &mut name)?;
1235        Ok(name)
1236    }
1237}
1238
1239fn read_inner(decoder: &mut BinDecoder<'_>, name: &mut Name) -> Result<(), DecodeError> {
1240    let mut state: LabelParseState = LabelParseState::LabelLengthOrPointer;
1241    let mut ptr_max_idx = None;
1242    let mut decoder_tmp;
1243    let mut decoder = &mut *decoder;
1244    let mut 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 when chasing pointers
1253        if let Some(max_idx) = ptr_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                // chase the pointer
1344                ptr_max_idx = Some(name_start);
1345                decoder_tmp = decoder.clone(location);
1346                decoder = &mut decoder_tmp;
1347                name_start = decoder.index();
1348                LabelParseState::LabelLengthOrPointer
1349            }
1350            LabelParseState::Root => {
1351                // need to pop() the 0 off the stack...
1352                decoder.pop()?;
1353                break;
1354            }
1355        }
1356    }
1357
1358    // TODO: should we consider checking this while the name is parsed?
1359    let len = name.len();
1360    if len >= 255 {
1361        return Err(DecodeError::DomainNameTooLong(len));
1362    }
1363
1364    Ok(())
1365}
1366
1367impl fmt::Display for Name {
1368    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1369        self.write_labels::<fmt::Formatter<'_>, LabelEncUtf8>(f)
1370    }
1371}
1372
1373impl PartialOrd<Self> for Name {
1374    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
1375        Some(self.cmp(other))
1376    }
1377}
1378
1379impl Ord for Name {
1380    /// Case insensitive comparison, see [`Name::cmp_case`] for case sensitive comparisons
1381    ///
1382    /// RFC 4034                DNSSEC Resource Records               March 2005
1383    ///
1384    /// ```text
1385    /// 6.1.  Canonical DNS Name Order
1386    ///
1387    ///  For the purposes of DNS security, owner names are ordered by treating
1388    ///  individual labels as unsigned left-justified octet strings.  The
1389    ///  absence of a octet sorts before a zero value octet, and uppercase
1390    ///  US-ASCII letters are treated as if they were lowercase US-ASCII
1391    ///  letters.
1392    ///
1393    ///  To compute the canonical ordering of a set of DNS names, start by
1394    ///  sorting the names according to their most significant (rightmost)
1395    ///  labels.  For names in which the most significant label is identical,
1396    ///  continue sorting according to their next most significant label, and
1397    ///  so forth.
1398    ///
1399    ///  For example, the following names are sorted in canonical DNS name
1400    ///  order.  The most significant label is "example".  At this level,
1401    ///  "example" sorts first, followed by names ending in "a.example", then
1402    ///  by names ending "z.example".  The names within each level are sorted
1403    ///  in the same way.
1404    ///
1405    ///            example
1406    ///            a.example
1407    ///            yljkjljk.a.example
1408    ///            Z.a.example
1409    ///            zABC.a.EXAMPLE
1410    ///            z.example
1411    ///            \001.z.example
1412    ///            *.z.example
1413    ///            \200.z.example
1414    /// ```
1415    fn cmp(&self, other: &Self) -> Ordering {
1416        self.cmp_with_f::<CaseInsensitive>(other)
1417    }
1418}
1419
1420/// This is the list of states for the label parsing state machine
1421enum LabelParseState {
1422    LabelLengthOrPointer, // basically the start of the FSM
1423    Label,                // storing length of the label, must be < 63
1424    Pointer,              // location of pointer in slice,
1425    Root,                 // root is the end of the labels list for an FQDN
1426}
1427
1428impl FromStr for Name {
1429    type Err = ProtoError;
1430
1431    /// Uses the Name::from_utf8 conversion on this string, see [Name::from_ascii] for ascii only, or for preserving case
1432    fn from_str(s: &str) -> Result<Self, Self::Err> {
1433        Self::from_str_relaxed(s)
1434    }
1435}
1436
1437/// Conversion into a Name
1438pub trait IntoName: Sized {
1439    /// Convert this into Name
1440    fn into_name(self) -> ProtoResult<Name>;
1441
1442    /// Check if this value is a valid IP address
1443    fn to_ip(&self) -> Option<IpAddr>;
1444}
1445
1446impl IntoName for &str {
1447    /// Performs a utf8, IDNA or punycode, translation of the `str` into `Name`
1448    fn into_name(self) -> ProtoResult<Name> {
1449        Name::from_utf8(self)
1450    }
1451
1452    fn to_ip(&self) -> Option<IpAddr> {
1453        IpAddr::from_str(self).ok()
1454    }
1455}
1456
1457impl IntoName for String {
1458    /// Performs a utf8, IDNA or punycode, translation of the `String` into `Name`
1459    fn into_name(self) -> ProtoResult<Name> {
1460        Name::from_utf8(self)
1461    }
1462
1463    fn to_ip(&self) -> Option<IpAddr> {
1464        IpAddr::from_str(self).ok()
1465    }
1466}
1467
1468impl IntoName for &String {
1469    /// Performs a utf8, IDNA or punycode, translation of the `&String` into `Name`
1470    fn into_name(self) -> ProtoResult<Name> {
1471        Name::from_utf8(self)
1472    }
1473
1474    fn to_ip(&self) -> Option<IpAddr> {
1475        IpAddr::from_str(self).ok()
1476    }
1477}
1478
1479impl<T> IntoName for T
1480where
1481    T: Into<Name>,
1482{
1483    fn into_name(self) -> ProtoResult<Name> {
1484        Ok(self.into())
1485    }
1486
1487    fn to_ip(&self) -> Option<IpAddr> {
1488        None
1489    }
1490}
1491
1492#[cfg(feature = "serde")]
1493impl Serialize for Name {
1494    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1495    where
1496        S: Serializer,
1497    {
1498        serializer.serialize_str(&self.to_string())
1499    }
1500}
1501
1502#[cfg(feature = "serde")]
1503impl<'de> Deserialize<'de> for Name {
1504    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1505    where
1506        D: Deserializer<'de>,
1507    {
1508        let s = String::deserialize(deserializer)?;
1509        FromStr::from_str(&s).map_err(de::Error::custom)
1510    }
1511}
1512
1513#[cfg(test)]
1514mod tests {
1515    #![allow(clippy::dbg_macro, clippy::print_stdout)]
1516
1517    use alloc::string::ToString;
1518    use core::cmp::Ordering;
1519    #[cfg(feature = "std")]
1520    use std::{collections::hash_map::DefaultHasher, println};
1521
1522    use super::*;
1523    use crate::error::ProtoError;
1524    use crate::serialize::binary::bin_tests::{test_emit_data_set, test_read_data_set};
1525
1526    fn get_data() -> Vec<(Name, Vec<u8>)> {
1527        vec![
1528            (Name::from_str(".").unwrap(), vec![0]), // base case, only the root
1529            (Name::from_str("a.").unwrap(), vec![1, b'a', 0]), // a single 'a' label
1530            (
1531                Name::from_str("a.bc.").unwrap(),
1532                vec![1, b'a', 2, b'b', b'c', 0],
1533            ), // two labels, 'a.bc'
1534            (
1535                Name::from_str("a.♥.").unwrap(),
1536                vec![1, b'a', 7, b'x', b'n', b'-', b'-', b'g', b'6', b'h', 0],
1537            ), // two labels utf8, 'a.♥'
1538        ]
1539    }
1540
1541    #[test]
1542    fn test_num_labels() {
1543        assert_eq!(Name::from_str("*").unwrap().num_labels(), 0);
1544        assert_eq!(Name::from_str("a").unwrap().num_labels(), 1);
1545        assert_eq!(Name::from_str("*.b").unwrap().num_labels(), 1);
1546        assert_eq!(Name::from_str("a.b").unwrap().num_labels(), 2);
1547        assert_eq!(Name::from_str("*.b.c").unwrap().num_labels(), 2);
1548        assert_eq!(Name::from_str("a.b.c").unwrap().num_labels(), 3);
1549    }
1550
1551    #[test]
1552    fn test_read() {
1553        test_read_data_set(get_data(), |mut d| Name::read(&mut d));
1554    }
1555
1556    #[test]
1557    fn test_write_to() {
1558        test_emit_data_set(get_data(), |e, n| n.emit(e));
1559    }
1560
1561    #[test]
1562    fn test_pointer() {
1563        let mut bytes = Vec::with_capacity(512);
1564
1565        let first = Name::from_str("ra.rb.rc.").unwrap();
1566        let second = Name::from_str("rb.rc.").unwrap();
1567        let third = Name::from_str("rc.").unwrap();
1568        let fourth = Name::from_str("z.ra.rb.rc.").unwrap();
1569
1570        {
1571            let mut e = BinEncoder::new(&mut bytes);
1572
1573            first.emit(&mut e).unwrap();
1574            assert_eq!(e.len(), 10); // should be 7 u8s...
1575
1576            second.emit(&mut e).unwrap();
1577            // if this wrote the entire thing, then it would be +5... but a pointer should be +2
1578            assert_eq!(e.len(), 12);
1579
1580            third.emit(&mut e).unwrap();
1581            assert_eq!(e.len(), 14);
1582
1583            fourth.emit(&mut e).unwrap();
1584            assert_eq!(e.len(), 18);
1585        }
1586
1587        // now read them back
1588        let mut d = BinDecoder::new(&bytes);
1589
1590        let r_test = Name::read(&mut d).unwrap();
1591        assert_eq!(first, r_test);
1592
1593        let r_test = Name::read(&mut d).unwrap();
1594        assert_eq!(second, r_test);
1595
1596        let r_test = Name::read(&mut d).unwrap();
1597        assert_eq!(third, r_test);
1598
1599        let r_test = Name::read(&mut d).unwrap();
1600        assert_eq!(fourth, r_test);
1601    }
1602
1603    #[test]
1604    fn test_pointer_with_pointer_ending_labels() {
1605        let mut bytes: Vec<u8> = Vec::with_capacity(512);
1606
1607        let first = Name::from_str("ra.rb.rc.").unwrap();
1608        let second = Name::from_str("ra.rc.").unwrap();
1609        let third = Name::from_str("ra.rc.").unwrap();
1610
1611        {
1612            let mut e = BinEncoder::new(&mut bytes);
1613
1614            first.emit(&mut e).unwrap();
1615            assert_eq!(e.len(), 10);
1616
1617            second.emit(&mut e).unwrap();
1618            // +5 with the first +3 being the text form of "ra" and +2 for the pointer to "rc".
1619            assert_eq!(e.len(), 15);
1620
1621            // +2 with the pointer to "ra.rc" as previously seen.
1622            third.emit(&mut e).unwrap();
1623            assert_eq!(e.len(), 17);
1624        }
1625
1626        // now read them back
1627        let mut d = BinDecoder::new(&bytes);
1628
1629        let r_test = Name::read(&mut d).unwrap();
1630        assert_eq!(first, r_test);
1631
1632        let r_test = Name::read(&mut d).unwrap();
1633        assert_eq!(second, r_test);
1634
1635        let r_test = Name::read(&mut d).unwrap();
1636        assert_eq!(third, r_test);
1637    }
1638
1639    #[test]
1640    fn test_recursive_pointer() {
1641        // points to an invalid beginning label marker
1642        let bytes = vec![0xC0, 0x01];
1643        let mut d = BinDecoder::new(&bytes);
1644
1645        assert!(Name::read(&mut d).is_err());
1646
1647        // formerly a stack overflow, recursing back on itself
1648        let bytes = vec![0xC0, 0x00];
1649        let mut d = BinDecoder::new(&bytes);
1650
1651        assert!(Name::read(&mut d).is_err());
1652
1653        // formerly a stack overflow, recursing back on itself
1654        let bytes = vec![0x01, 0x41, 0xC0, 0x00];
1655        let mut d = BinDecoder::new(&bytes);
1656
1657        assert!(Name::read(&mut d).is_err());
1658
1659        // formerly a stack overflow, recursing by going past the end, then back to the beginning.
1660        //   this is disallowed based on the rule that all labels must be "prior" to the current label.
1661        let bytes = vec![0xC0, 0x02, 0xC0, 0x00];
1662        let mut d = BinDecoder::new(&bytes);
1663
1664        assert!(Name::read(&mut d).is_err());
1665    }
1666
1667    #[test]
1668    #[cfg(feature = "std")]
1669    fn test_long_pointer_chain_small_stack() {
1670        // Build a buffer of the form: [0x00, ptr->0, ptr->prev, ptr->prev, ...]
1671        let mut bytes = vec![0x00, 0xC0, 0x00];
1672        let mut last_ptr_offset: u16 = 1;
1673        for _ in 1..8000 {
1674            last_ptr_offset = bytes.len() as u16 - 2;
1675            bytes.extend(&u16::to_be_bytes(0xC000 | last_ptr_offset));
1676        }
1677
1678        // Formerly a stack overflow
1679        let name = std::thread::Builder::new()
1680            .stack_size(256 * 1024)
1681            .spawn(move || {
1682                let mut decoder = BinDecoder::new(&bytes).clone(last_ptr_offset);
1683                Name::read(&mut decoder).unwrap()
1684            })
1685            .unwrap()
1686            .join()
1687            .unwrap();
1688
1689        assert_eq!(name, Name::root());
1690    }
1691
1692    #[test]
1693    fn test_bin_overlap_enforced() {
1694        let mut bytes: Vec<u8> = Vec::with_capacity(512);
1695        let n: u8 = 31;
1696        for _ in 0..=5 {
1697            bytes.extend(core::iter::repeat_n(n, n as usize));
1698        }
1699        bytes.push(n + 1);
1700        for b in 0..n {
1701            bytes.push(1 + n + b);
1702        }
1703        bytes.extend_from_slice(&[1, 0]);
1704        for b in 0..n {
1705            bytes.extend_from_slice(&[0xC0, b]);
1706        }
1707        let mut d = BinDecoder::new(&bytes);
1708        d.read_slice(n as usize).unwrap();
1709        assert!(Name::read(&mut d).is_err());
1710    }
1711
1712    #[test]
1713    fn test_bin_max_octets() {
1714        let mut bytes = Vec::with_capacity(512);
1715        for _ in 0..256 {
1716            bytes.extend_from_slice(&[1, b'a']);
1717        }
1718        bytes.push(0);
1719
1720        let mut d = BinDecoder::new(&bytes);
1721        assert!(Name::read(&mut d).is_err());
1722    }
1723
1724    #[test]
1725    fn test_base_name() {
1726        let zone = Name::from_str("example.com.").unwrap();
1727
1728        assert_eq!(zone.base_name(), Name::from_str("com.").unwrap());
1729        assert!(zone.base_name().base_name().is_root());
1730        assert!(zone.base_name().base_name().base_name().is_root());
1731    }
1732
1733    #[test]
1734    fn test_zone_of() {
1735        let zone = Name::from_str("example.com").unwrap();
1736        let www = Name::from_str("www.example.com").unwrap();
1737        let none = Name::from_str("none.com").unwrap();
1738        let root = Name::root();
1739
1740        assert!(zone.zone_of(&zone));
1741        assert!(zone.zone_of(&www));
1742        assert!(!zone.zone_of(&none));
1743        assert!(root.zone_of(&zone));
1744        assert!(!zone.zone_of(&root));
1745    }
1746
1747    #[test]
1748    fn test_zone_of_case() {
1749        let zone = Name::from_ascii("examplE.cOm").unwrap();
1750        let www = Name::from_str("www.example.com").unwrap();
1751        let none = Name::from_str("none.com").unwrap();
1752
1753        assert!(zone.zone_of(&zone));
1754        assert!(zone.zone_of(&www));
1755        assert!(!zone.zone_of(&none))
1756    }
1757
1758    #[test]
1759    fn test_partial_cmp_eq() {
1760        let root = Some(Name::from_labels(Vec::<&str>::new()).unwrap());
1761        let comparisons: Vec<(Name, Name)> = vec![
1762            (root.clone().unwrap(), root.clone().unwrap()),
1763            (
1764                Name::parse("example.", root.as_ref()).unwrap(),
1765                Name::parse("example", root.as_ref()).unwrap(),
1766            ),
1767        ];
1768
1769        for (left, right) in comparisons {
1770            #[cfg(feature = "std")]
1771            println!("left: {left}, right: {right}");
1772            assert_eq!(left.partial_cmp(&right), Some(Ordering::Equal));
1773        }
1774    }
1775
1776    #[test]
1777    fn test_partial_cmp() {
1778        let comparisons: Vec<(Name, Name)> = vec![
1779            (
1780                Name::from_str("example.").unwrap(),
1781                Name::from_str("a.example.").unwrap(),
1782            ),
1783            (
1784                Name::from_str("a.example.").unwrap(),
1785                Name::from_str("yljkjljk.a.example.").unwrap(),
1786            ),
1787            (
1788                Name::from_str("yljkjljk.a.example.").unwrap(),
1789                Name::from_ascii("Z.a.example.").unwrap(),
1790            ),
1791            (
1792                Name::from_ascii("Z.a.example").unwrap(),
1793                Name::from_ascii("zABC.a.EXAMPLE.").unwrap(),
1794            ),
1795            (
1796                Name::from_ascii("zABC.a.EXAMPLE.").unwrap(),
1797                Name::from_str("z.example.").unwrap(),
1798            ),
1799            (
1800                Name::from_str("z.example").unwrap(),
1801                Name::from_labels(vec![&[1u8] as &[u8], b"z", b"example."]).unwrap(),
1802            ),
1803            (
1804                Name::from_labels(vec![&[1u8] as &[u8], b"z", b"example"]).unwrap(),
1805                Name::from_str("*.z.example.").unwrap(),
1806            ),
1807            (
1808                Name::from_str("*.z.example").unwrap(),
1809                Name::from_labels(vec![&[200u8] as &[u8], b"z", b"example."]).unwrap(),
1810            ),
1811        ];
1812
1813        for (left, right) in comparisons {
1814            #[cfg(feature = "std")]
1815            println!("left: {left}, right: {right}");
1816            assert_eq!(left.cmp(&right), Ordering::Less);
1817        }
1818    }
1819
1820    #[test]
1821    fn test_cmp_ignore_case() {
1822        let comparisons: Vec<(Name, Name)> = vec![
1823            (
1824                Name::from_ascii("ExAmPle.").unwrap(),
1825                Name::from_ascii("example.").unwrap(),
1826            ),
1827            (
1828                Name::from_ascii("A.example.").unwrap(),
1829                Name::from_ascii("a.example.").unwrap(),
1830            ),
1831        ];
1832
1833        for (left, right) in comparisons {
1834            #[cfg(feature = "std")]
1835            println!("left: {left}, right: {right}");
1836            assert_eq!(left, right);
1837        }
1838    }
1839
1840    #[test]
1841    fn test_from_ipv4() {
1842        let ip = IpAddr::V4(Ipv4Addr::new(26, 3, 0, 103));
1843        let name = Name::from_str("103.0.3.26.in-addr.arpa.").unwrap();
1844
1845        assert_eq!(Into::<Name>::into(ip), name);
1846    }
1847
1848    #[test]
1849    fn test_from_ipv6() {
1850        let ip = IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0x1));
1851        let name = Name::from_str(
1852            "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.",
1853        )
1854        .unwrap();
1855
1856        assert_eq!(Into::<Name>::into(ip), name);
1857    }
1858
1859    #[test]
1860    fn test_from_str() {
1861        assert_eq!(
1862            Name::from_str("www.example.com.").unwrap(),
1863            Name::from_labels(vec![b"www" as &[u8], b"example", b"com"]).unwrap()
1864        );
1865        assert_eq!(
1866            Name::from_str(".").unwrap(),
1867            Name::from_labels(Vec::<&str>::new()).unwrap()
1868        );
1869    }
1870
1871    #[test]
1872    fn test_fqdn() {
1873        assert!(Name::root().is_fqdn());
1874        assert!(Name::from_str(".").unwrap().is_fqdn());
1875        assert!(Name::from_str("www.example.com.").unwrap().is_fqdn());
1876        assert!(
1877            Name::from_labels(vec![b"www" as &[u8], b"example", b"com"])
1878                .unwrap()
1879                .is_fqdn()
1880        );
1881
1882        assert!(!Name::new().is_fqdn());
1883        assert!(!Name::from_str("www.example.com").unwrap().is_fqdn());
1884        assert!(!Name::from_str("www.example").unwrap().is_fqdn());
1885        assert!(!Name::from_str("www").unwrap().is_fqdn());
1886    }
1887
1888    #[test]
1889    fn test_to_string() {
1890        assert_eq!(
1891            Name::from_str("www.example.com.").unwrap().to_string(),
1892            "www.example.com."
1893        );
1894        assert_eq!(
1895            Name::from_str("www.example.com").unwrap().to_string(),
1896            "www.example.com"
1897        );
1898    }
1899
1900    #[test]
1901    fn test_from_ascii() {
1902        let bytes_name = Name::from_labels(vec![b"WWW" as &[u8], b"example", b"COM"]).unwrap();
1903        let ascii_name = Name::from_ascii("WWW.example.COM.").unwrap();
1904        let lower_name = Name::from_ascii("www.example.com.").unwrap();
1905
1906        assert!(bytes_name.eq_case(&ascii_name));
1907        assert!(!lower_name.eq_case(&ascii_name));
1908    }
1909
1910    #[test]
1911    fn test_from_utf8() {
1912        let bytes_name = Name::from_labels(vec![b"WWW" as &[u8], b"example", b"COM"]).unwrap();
1913        let utf8_name = Name::from_utf8("WWW.example.COM.").unwrap();
1914        let lower_name = Name::from_utf8("www.example.com.").unwrap();
1915
1916        assert!(!bytes_name.eq_case(&utf8_name));
1917        assert!(lower_name.eq_case(&utf8_name));
1918    }
1919
1920    #[test]
1921    fn test_into_name() {
1922        let name = Name::from_utf8("www.example.com").unwrap();
1923        assert_eq!(Name::from_utf8("www.example.com").unwrap(), name);
1924        assert_eq!(
1925            Name::from_utf8("www.example.com").unwrap(),
1926            Name::from_utf8("www.example.com")
1927                .unwrap()
1928                .into_name()
1929                .unwrap()
1930        );
1931        assert_eq!(
1932            Name::from_utf8("www.example.com").unwrap(),
1933            "www.example.com".into_name().unwrap()
1934        );
1935        assert_eq!(
1936            Name::from_utf8("www.example.com").unwrap(),
1937            "www.example.com".to_string().into_name().unwrap()
1938        );
1939    }
1940
1941    #[test]
1942    fn test_encoding() {
1943        assert_eq!(
1944            Name::from_ascii("WWW.example.COM.").unwrap().to_ascii(),
1945            "WWW.example.COM."
1946        );
1947        assert_eq!(
1948            Name::from_utf8("WWW.example.COM.").unwrap().to_ascii(),
1949            "www.example.com."
1950        );
1951        assert_eq!(
1952            Name::from_ascii("WWW.example.COM.").unwrap().to_utf8(),
1953            "WWW.example.COM."
1954        );
1955    }
1956
1957    #[test]
1958    fn test_excessive_encoding_len() {
1959        use crate::error::ProtoError;
1960
1961        // u16 max value is where issues start being tickled...
1962        let mut buf = Vec::with_capacity(u16::MAX as usize);
1963        let mut encoder = BinEncoder::new(&mut buf);
1964
1965        let mut result = Ok(());
1966        for i in 0..10000 {
1967            let name = Name::from_ascii(format!("name{i}.example.com.")).unwrap();
1968            result = name.emit(&mut encoder);
1969            if result.is_err() {
1970                break;
1971            }
1972        }
1973
1974        match result.unwrap_err() {
1975            ProtoError::MaxBufferSizeExceeded(_) => (),
1976            _ => panic!(),
1977        }
1978    }
1979
1980    #[test]
1981    fn test_underscore() {
1982        Name::from_str("_begin.example.com").expect("failed at beginning");
1983        Name::from_str_relaxed("mid_dle.example.com").expect("failed in the middle");
1984        Name::from_str_relaxed("end_.example.com").expect("failed at the end");
1985    }
1986
1987    #[test]
1988    fn test_parse_arpa_name() {
1989        assert!(
1990            Name::from_ascii("168.192.in-addr.arpa")
1991                .unwrap()
1992                .parse_arpa_name()
1993                .is_err()
1994        );
1995        assert!(
1996            Name::from_ascii("host.example.com.")
1997                .unwrap()
1998                .parse_arpa_name()
1999                .is_err()
2000        );
2001        assert!(
2002            Name::from_ascii("caffee.ip6.arpa.")
2003                .unwrap()
2004                .parse_arpa_name()
2005                .is_err()
2006        );
2007        assert!(
2008            Name::from_ascii(
2009                "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."
2010            )
2011            .unwrap()
2012            .parse_arpa_name()
2013            .is_err()
2014        );
2015        assert!(
2016            Name::from_ascii("caffee.in-addr.arpa.")
2017                .unwrap()
2018                .parse_arpa_name()
2019                .is_err()
2020        );
2021        assert!(
2022            Name::from_ascii("1.2.3.4.5.in-addr.arpa.")
2023                .unwrap()
2024                .parse_arpa_name()
2025                .is_err()
2026        );
2027        assert!(
2028            Name::from_ascii("1.2.3.4.home.arpa.")
2029                .unwrap()
2030                .parse_arpa_name()
2031                .is_err()
2032        );
2033        assert_eq!(
2034            Name::from_ascii("168.192.in-addr.arpa.")
2035                .unwrap()
2036                .parse_arpa_name()
2037                .unwrap(),
2038            IpNet::V4(Ipv4Net::new("192.168.0.0".parse().unwrap(), 16).unwrap())
2039        );
2040        assert_eq!(
2041            Name::from_ascii("1.0.168.192.in-addr.arpa.")
2042                .unwrap()
2043                .parse_arpa_name()
2044                .unwrap(),
2045            IpNet::V4(Ipv4Net::new("192.168.0.1".parse().unwrap(), 32).unwrap())
2046        );
2047        assert_eq!(
2048            Name::from_ascii("0.1.0.0.2.ip6.arpa.")
2049                .unwrap()
2050                .parse_arpa_name()
2051                .unwrap(),
2052            IpNet::V6(Ipv6Net::new("2001::".parse().unwrap(), 20).unwrap())
2053        );
2054        assert_eq!(
2055            Name::from_ascii("D.0.1.0.0.2.ip6.arpa.")
2056                .unwrap()
2057                .parse_arpa_name()
2058                .unwrap(),
2059            IpNet::V6(Ipv6Net::new("2001:d00::".parse().unwrap(), 24).unwrap())
2060        );
2061        assert_eq!(
2062            Name::from_ascii("B.D.0.1.0.0.2.ip6.arpa.")
2063                .unwrap()
2064                .parse_arpa_name()
2065                .unwrap(),
2066            IpNet::V6(Ipv6Net::new("2001:db0::".parse().unwrap(), 28).unwrap())
2067        );
2068        assert_eq!(
2069            Name::from_ascii("8.B.D.0.1.0.0.2.ip6.arpa.")
2070                .unwrap()
2071                .parse_arpa_name()
2072                .unwrap(),
2073            IpNet::V6(Ipv6Net::new("2001:db8::".parse().unwrap(), 32).unwrap())
2074        );
2075        assert_eq!(
2076            Name::from_ascii(
2077                "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."
2078            )
2079            .unwrap()
2080            .parse_arpa_name()
2081            .unwrap(),
2082            IpNet::V6(
2083                Ipv6Net::new("2001:db8:85a3:8d3:1319:8a2e:370:7334".parse().unwrap(), 128).unwrap()
2084            )
2085        );
2086    }
2087
2088    #[test]
2089    fn test_prepend_label() {
2090        for name in ["foo.com", "foo.com."] {
2091            let name = Name::from_ascii(name).unwrap();
2092
2093            for label in ["bar", "baz", "quux"] {
2094                let sub = name.clone().prepend_label(label).unwrap();
2095                let expected = Name::from_ascii(format!("{label}.{name}")).unwrap();
2096                assert_eq!(expected, sub);
2097            }
2098        }
2099
2100        for name in ["", "."] {
2101            let name = Name::from_ascii(name).unwrap();
2102
2103            for label in ["bar", "baz", "quux"] {
2104                let sub = name.clone().prepend_label(label).unwrap();
2105                let expected = Name::from_ascii(format!("{label}{name}")).unwrap();
2106                assert_eq!(expected, sub);
2107            }
2108        }
2109    }
2110
2111    #[test]
2112    fn test_name_too_long_with_prepend() {
2113        let n = Name::from_ascii("Llocainvannnnnnaxgtezqzqznnnnnn1na.nnntnninvannnnnnaxgtezqzqznnnnnn1na.nnntnnnnnnnaxgtezqzqznnnnnn1na.nnntnaaaaaaaaaaaaaaaaaaaaaaaaiK.iaaaaaaaaaaaaaaaaaaaaaaaaiKa.innnnnaxgtezqzqznnnnnn1na.nnntnaaaaaaaaaaaaaaaaaaaaaaaaiK.iaaaaaaaaaaaaaaaaaaaaaaaaiKa.in").unwrap();
2114        let sfx = "xxxxxxx.yyyyy.zzz";
2115
2116        let error = n
2117            .prepend_label(sfx)
2118            .expect_err("should have errored, too long");
2119
2120        match error {
2121            ProtoError::Decode(DecodeError::DomainNameTooLong(_)) => (),
2122            _ => panic!("expected too long message"),
2123        }
2124    }
2125
2126    #[test]
2127    fn test_name_too_long_with_append() {
2128        // from https://github.com/hickory-dns/hickory-dns/issues/1447
2129        let n = Name::from_ascii("Llocainvannnnnnaxgtezqzqznnnnnn1na.nnntnninvannnnnnaxgtezqzqznnnnnn1na.nnntnnnnnnnaxgtezqzqznnnnnn1na.nnntnaaaaaaaaaaaaaaaaaaaaaaaaiK.iaaaaaaaaaaaaaaaaaaaaaaaaiKa.innnnnaxgtezqzqznnnnnn1na.nnntnaaaaaaaaaaaaaaaaaaaaaaaaiK.iaaaaaaaaaaaaaaaaaaaaaaaaiKa.in").unwrap();
2130        let sfx = Name::from_ascii("xxxxxxx.yyyyy.zzz").unwrap();
2131
2132        let error = n
2133            .append_domain(&sfx)
2134            .expect_err("should have errored, too long");
2135
2136        match error {
2137            ProtoError::Decode(DecodeError::DomainNameTooLong(_)) => (),
2138            _ => panic!("expected too long message"),
2139        }
2140    }
2141
2142    #[test]
2143    fn test_encoded_len() {
2144        for name in [
2145            // FQDN
2146            Name::parse("www.example.com.", None).unwrap(),
2147            // Non-FQDN
2148            Name::parse("www", None).unwrap(),
2149            // Root (FQDN)
2150            Name::root(),
2151            // Empty (non-FQDN)
2152            Name::new(),
2153        ] {
2154            let mut buffer = Vec::new();
2155            let mut encoder = BinEncoder::new(&mut buffer);
2156            name.emit(&mut encoder).unwrap();
2157
2158            assert_eq!(
2159                name.encoded_len(),
2160                buffer.len(),
2161                "encoded_len() was incorrect for {name:?}"
2162            );
2163        }
2164    }
2165
2166    #[test]
2167    fn test_length_limits() {
2168        // Labels are limited to 63 bytes, and names are limited to 255 bytes.
2169        // This name is composed of three labels of length 63, a label of length 61, and a label of
2170        // length 0 for the root zone. There are a total of five length bytes. Thus, the total
2171        // length is 63 + 63 + 63 + 61 + 5 = 255.
2172        let encoded_name_255_bytes: [u8; 255] = [
2173            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',
2174            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',
2175            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',
2176            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',
2177            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',
2178            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',
2179            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',
2180            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',
2181            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,
2182            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',
2183            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',
2184            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',
2185            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',
2186            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',
2187            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',
2188            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',
2189            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',
2190            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,
2191        ];
2192        let expected_name_str = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.\
2193        aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.\
2194        aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.\
2195        aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.";
2196
2197        let mut decoder = BinDecoder::new(&encoded_name_255_bytes);
2198        let decoded_name = Name::read(&mut decoder).unwrap();
2199        assert!(decoder.is_empty());
2200
2201        assert_eq!(decoded_name.to_string(), expected_name_str);
2202
2203        // Should not be able to construct a longer name from a string.
2204        let long_label_error = Name::parse(&format!("a{expected_name_str}"), None).unwrap_err();
2205        assert!(matches!(
2206            long_label_error,
2207            ProtoError::Decode(DecodeError::LabelBytesTooLong(64))
2208        ));
2209        let long_name_error =
2210            Name::parse(&format!("a.{}", &expected_name_str[1..]), None).unwrap_err();
2211        assert!(matches!(
2212            long_name_error,
2213            ProtoError::Decode(DecodeError::DomainNameTooLong(256))
2214        ))
2215    }
2216
2217    #[test]
2218    fn test_double_ended_iterator() {
2219        let name = Name::from_ascii("www.example.com").unwrap();
2220        let mut iter = name.iter();
2221
2222        assert_eq!(iter.next().unwrap(), b"www");
2223        assert_eq!(iter.next_back().unwrap(), b"com");
2224        assert_eq!(iter.next().unwrap(), b"example");
2225        assert!(iter.next_back().is_none());
2226        assert!(iter.next().is_none());
2227    }
2228
2229    #[test]
2230    fn test_size_hint() {
2231        let name = Name::from_ascii("www.example.com").unwrap();
2232        let mut iter = name.iter();
2233
2234        assert_eq!(iter.size_hint().0, 3);
2235        assert_eq!(iter.next().unwrap(), b"www");
2236        assert_eq!(iter.size_hint().0, 2);
2237        assert_eq!(iter.next_back().unwrap(), b"com");
2238        assert_eq!(iter.size_hint().0, 1);
2239        assert_eq!(iter.next().unwrap(), b"example");
2240        assert_eq!(iter.size_hint().0, 0);
2241        assert!(iter.next_back().is_none());
2242        assert_eq!(iter.size_hint().0, 0);
2243        assert!(iter.next().is_none());
2244        assert_eq!(iter.size_hint().0, 0);
2245    }
2246
2247    #[test]
2248    #[cfg(feature = "std")]
2249    fn test_label_randomization() {
2250        let mut name = Name::root();
2251        name.randomize_label_case();
2252        assert!(name.eq_case(&Name::root()));
2253
2254        for qname in [
2255            "x",
2256            "0",
2257            "aaaaaaaaaaaaaaaa",
2258            "AAAAAAAAAAAAAAAA",
2259            "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.",
2260            "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA.",
2261            "abcdefghijklmnopqrstuvwxyz0123456789A.",
2262            "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.",
2263            "www01.example-site.com",
2264            "1234567890.e-1204089_043820-5.com.",
2265        ] {
2266            let mut name = Name::from_ascii(qname).unwrap();
2267            let name2 = name.clone();
2268            name.randomize_label_case();
2269            assert_eq!(name, name2);
2270            println!("{name2} == {name}: {}", name == name2);
2271        }
2272
2273        // 50k iterations gets us very close to a 50/50 uppercase/lowercase distribution in testing
2274        // without a long test runtime.
2275        let iterations = 50_000;
2276
2277        // This is a max length name (255 bytes) with the maximum number of possible flippable bytes
2278        // (nominal label length 63, except the last, with all label characters ASCII alpha)
2279        let test_str = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijk.lmnopqrstuvwxyzabcdefghjijklmnopqrstuvwxyzabcdefghijklmnopqrstu.vwxyzABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEF.GHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNO";
2280        let mut name = Name::from_ascii(test_str).unwrap();
2281        let name2 = name.clone();
2282
2283        let len = name.label_data.len();
2284        let mut cap_table: [u32; 255] = [0; 255];
2285        let mut lower_table: [u32; 255] = [0; 255];
2286        let mut mean_table: [f64; 255] = [0.0; 255];
2287
2288        for _ in 0..iterations {
2289            name.randomize_label_case();
2290            assert_eq!(name, name2);
2291
2292            for (j, &cbyte) in name.label_data.iter().enumerate() {
2293                if cbyte.is_ascii_lowercase() {
2294                    lower_table[j] += 1;
2295                } else if cbyte.is_ascii_uppercase() {
2296                    cap_table[j] += 1;
2297                }
2298            }
2299            name = Name::from_ascii(test_str).unwrap();
2300        }
2301
2302        println!("Distribution of lower case values by label offset");
2303        println!("-------------------------------------------------");
2304        for i in 0..len {
2305            let cap_ratio = cap_table[i] as f64 / iterations as f64;
2306            let lower_ratio = lower_table[i] as f64 / iterations as f64;
2307            let total_ratio = cap_ratio + lower_ratio;
2308            mean_table[i] = lower_ratio;
2309            println!(
2310                "{i:03} {:.3}% {:.3}% {:.3}%",
2311                cap_ratio * 100.0,
2312                lower_ratio * 100.0,
2313                total_ratio * 100.0,
2314            );
2315        }
2316        println!("-------------------------------------------------");
2317
2318        let data_mean = mean_table.iter().sum::<f64>() / len as f64;
2319        let data_std_deviation = std_deviation(data_mean, &mean_table);
2320
2321        let mut max_zscore = 0.0;
2322        for elem in mean_table.iter() {
2323            let zscore = (elem - data_mean) / data_std_deviation;
2324
2325            if zscore > max_zscore {
2326                max_zscore = zscore;
2327            }
2328        }
2329
2330        println!("μ: {data_mean:.4} σ: {data_std_deviation:.4}, max variance: {max_zscore:.4}σ");
2331
2332        // These levels are from observed test behavior; typical values for 50k iterations are:
2333        //
2334        //   mean: ~ 50% (this is the % of test iterations where the value is lower case)
2335        //   standard deviation: ~ 0.063
2336        //   largest z-score: ~ 0.10 (i.e., around 1/10 of a standard deviation)
2337        //
2338        // The values below are designed to avoid random CI test failures, but alert on any
2339        // significant variation from the observed randomization behavior during test development.
2340        //
2341        // Specifically, this test will fail if there is a single bit hole in the random bit stream
2342        assert!(data_mean > 0.485 && data_mean < 0.515);
2343        assert!(data_std_deviation < 0.18);
2344        assert!(max_zscore < 0.33);
2345    }
2346
2347    #[cfg(feature = "std")]
2348    fn std_deviation(mean: f64, data: &[f64]) -> f64 {
2349        match (mean, data.len()) {
2350            (data_mean, count) if count > 0 => {
2351                let variance = data
2352                    .iter()
2353                    .map(|value| {
2354                        let diff = data_mean - *value;
2355
2356                        diff * diff
2357                    })
2358                    .sum::<f64>()
2359                    / count as f64;
2360
2361                variance.sqrt()
2362            }
2363            _ => 0.0,
2364        }
2365    }
2366
2367    #[test]
2368    fn test_fqdn_escaped_dot() {
2369        let name = Name::from_utf8("test.").unwrap();
2370        assert!(name.is_fqdn());
2371
2372        let name = Name::from_utf8("test\\.").unwrap();
2373        assert!(!name.is_fqdn());
2374
2375        let name = Name::from_utf8("").unwrap();
2376        assert!(!name.is_fqdn());
2377
2378        let name = Name::from_utf8(".").unwrap();
2379        assert!(name.is_fqdn());
2380    }
2381
2382    #[test]
2383    #[allow(clippy::nonminimal_bool)]
2384    fn test_name_partialeq_constraints() {
2385        let example_fqdn = Name::from_utf8("example.com.").unwrap();
2386        let example_nonfqdn = Name::from_utf8("example.com").unwrap();
2387        let other_fqdn = Name::from_utf8("otherdomain.com.").unwrap();
2388
2389        assert_eq!(example_fqdn, example_fqdn);
2390        assert_eq!(example_nonfqdn, example_nonfqdn);
2391        assert!(example_fqdn != example_nonfqdn);
2392
2393        // a != b if and only if !(a == b).
2394        assert!(example_fqdn != example_nonfqdn && !(example_fqdn == example_nonfqdn));
2395        assert!(example_nonfqdn != example_fqdn && !(example_nonfqdn == example_fqdn));
2396        assert!(example_fqdn != other_fqdn && !(example_fqdn == other_fqdn));
2397        assert!(example_nonfqdn != other_fqdn && !(example_nonfqdn == other_fqdn));
2398    }
2399
2400    #[test]
2401    fn test_name_partialord_constraints() {
2402        use core::cmp::Ordering::*;
2403
2404        let example_fqdn = Name::from_utf8("example.com.").unwrap();
2405        let foo_example_fqdn = Name::from_utf8("foo.example.com.").unwrap();
2406        let example_nonfqdn = Name::from_utf8("example.com").unwrap();
2407        let foo_example_nonfqdn = Name::from_utf8("foo.example.com").unwrap();
2408
2409        // 1. a == b if and only if partial_cmp(a, b) == Some(Equal).
2410        assert_eq!(example_fqdn.partial_cmp(&example_fqdn), Some(Equal),);
2411        assert!(example_fqdn.partial_cmp(&example_nonfqdn) != Some(Equal));
2412
2413        // 2. a < b if and only if partial_cmp(a, b) == Some(Less)
2414        assert!(
2415            example_nonfqdn < example_fqdn
2416                && example_nonfqdn.partial_cmp(&example_fqdn) == Some(Less)
2417        );
2418
2419        assert!(
2420            example_fqdn < foo_example_fqdn
2421                && example_fqdn.partial_cmp(&foo_example_fqdn) == Some(Less)
2422        );
2423
2424        assert!(
2425            example_nonfqdn < foo_example_nonfqdn
2426                && example_nonfqdn.partial_cmp(&foo_example_nonfqdn) == Some(Less)
2427        );
2428
2429        // 3. a > b) if and only if partial_cmp(a, b) == Some(Greater)
2430        assert!(
2431            example_fqdn > example_nonfqdn
2432                && example_fqdn.partial_cmp(&example_nonfqdn) == Some(Greater)
2433        );
2434
2435        assert!(
2436            foo_example_fqdn > example_fqdn
2437                && foo_example_fqdn.partial_cmp(&example_fqdn) == Some(Greater)
2438        );
2439
2440        assert!(
2441            foo_example_nonfqdn > example_nonfqdn
2442                && foo_example_nonfqdn.partial_cmp(&example_nonfqdn) == Some(Greater)
2443        );
2444
2445        // 4. a <= b if and only if a < b || a == b
2446        assert!(example_nonfqdn <= example_fqdn);
2447        assert!(example_nonfqdn <= example_nonfqdn);
2448        assert!(example_fqdn <= example_fqdn);
2449        assert!(example_nonfqdn <= foo_example_nonfqdn);
2450        assert!(example_fqdn <= foo_example_fqdn);
2451        assert!(foo_example_nonfqdn <= foo_example_nonfqdn);
2452        assert!(foo_example_fqdn <= foo_example_fqdn);
2453
2454        // 5. a >= b if and only if a > b || a == b
2455        assert!(example_fqdn >= example_nonfqdn);
2456        assert!(example_nonfqdn >= example_nonfqdn);
2457        assert!(example_fqdn >= example_fqdn);
2458        assert!(foo_example_nonfqdn >= example_nonfqdn);
2459        assert!(foo_example_fqdn >= example_fqdn);
2460        assert!(foo_example_nonfqdn >= foo_example_nonfqdn);
2461        assert!(foo_example_fqdn >= foo_example_fqdn);
2462
2463        // 6. a != b if and only if !(a == b). -- Tested in test_name_partialeq_constraints.
2464    }
2465
2466    #[test]
2467    fn test_name_ord_constraints() {
2468        use core::cmp;
2469
2470        let example_fqdn = Name::from_utf8("example.com.").unwrap();
2471        let foo_example_fqdn = Name::from_utf8("foo.example.com.").unwrap();
2472        let example_nonfqdn = Name::from_utf8("example.com").unwrap();
2473        let foo_example_nonfqdn = Name::from_utf8("foo.example.com").unwrap();
2474
2475        // These are consistency checks between Ord and PartialOrd; therefore
2476        // we don't really care about picking the individual mappings and want
2477        // to test on all possible combinations.
2478        for pair in [
2479            (&example_fqdn, &example_fqdn),
2480            (&example_fqdn, &example_nonfqdn),
2481            (&example_fqdn, &foo_example_fqdn),
2482            (&example_fqdn, &foo_example_nonfqdn),
2483            (&example_nonfqdn, &example_nonfqdn),
2484            (&example_nonfqdn, &example_fqdn),
2485            (&example_nonfqdn, &foo_example_fqdn),
2486            (&example_nonfqdn, &foo_example_nonfqdn),
2487            (&foo_example_fqdn, &example_nonfqdn),
2488            (&foo_example_fqdn, &example_fqdn),
2489            (&foo_example_fqdn, &foo_example_fqdn),
2490            (&foo_example_fqdn, &foo_example_nonfqdn),
2491            (&foo_example_fqdn, &example_nonfqdn),
2492            (&foo_example_fqdn, &example_fqdn),
2493            (&foo_example_fqdn, &foo_example_fqdn),
2494            (&foo_example_fqdn, &foo_example_nonfqdn),
2495        ] {
2496            let name1 = pair.0;
2497            let name2 = pair.1;
2498
2499            // 1. partial_cmp(a, b) == Some(cmp(a, b)).
2500            assert_eq!(name1.partial_cmp(name2), Some(name1.cmp(name2)));
2501
2502            // 2. max(a, b) == max_by(a, b, cmp) (ensured by the default implementation).
2503            assert_eq!(
2504                name1.clone().max(name2.clone()),
2505                cmp::max_by(name1.clone(), name2.clone(), |x: &Name, y: &Name| x.cmp(y)),
2506            );
2507
2508            // 3. min(a, b) == min_by(a, b, cmp) (ensured by the default implementation).
2509            assert_eq!(
2510                name1.clone().min(name2.clone()),
2511                cmp::min_by(name1.clone(), name2.clone(), |x: &Name, y: &Name| x.cmp(y)),
2512            );
2513        }
2514
2515        // 4. For a.clamp(min, max), see the method docs (ensured by the default implementation).
2516        //
2517        // Restrict a value to a certain interval.
2518        // Returns max if self is greater than max, and min if self is less than min.
2519        // Otherwise this returns self.
2520        //
2521        // Panics if min > max -- tested in test_ord_clamp_panic
2522        let min_name = Name::from_utf8("com").unwrap();
2523        let max_name = Name::from_utf8("max.example.com.").unwrap();
2524
2525        assert_eq!(
2526            min_name
2527                .clone()
2528                .clamp(min_name.clone(), example_nonfqdn.clone()),
2529            min_name.clone(),
2530        );
2531
2532        assert_eq!(
2533            max_name
2534                .clone()
2535                .clamp(example_nonfqdn.clone(), example_fqdn.clone()),
2536            example_fqdn.clone(),
2537        );
2538
2539        assert_eq!(
2540            max_name
2541                .clone()
2542                .clamp(example_nonfqdn.clone(), max_name.clone()),
2543            max_name.clone(),
2544        );
2545
2546        // Transitivity tests
2547        // if A < B and B < C then A < C
2548        // if A > B and B > C then A > C
2549        let most_min_name = Name::from_utf8("").unwrap();
2550        let most_max_name = Name::from_utf8("most.max.example.com.").unwrap();
2551        assert_eq!(min_name.cmp(&example_nonfqdn), Ordering::Less);
2552        assert_eq!(most_min_name.cmp(&min_name), Ordering::Less);
2553        assert_eq!(most_min_name.cmp(&example_nonfqdn), Ordering::Less);
2554        assert_eq!(max_name.cmp(&example_fqdn), Ordering::Greater);
2555        assert_eq!(most_max_name.cmp(&max_name), Ordering::Greater);
2556        assert_eq!(most_max_name.cmp(&example_fqdn), Ordering::Greater);
2557    }
2558
2559    #[test]
2560    #[should_panic]
2561    fn test_ord_clamp_panic() {
2562        let min_name = Name::from_utf8("com").unwrap();
2563        let max_name = Name::from_utf8("max.example.com.").unwrap();
2564
2565        // this should panic since min > max
2566        let _ = min_name.clone().clamp(max_name, min_name);
2567    }
2568
2569    #[test]
2570    #[cfg(feature = "std")]
2571    fn test_hash() {
2572        // verify that two identical names with and without the trailing dot don't hash to the same
2573        // value
2574        let with_dot = Name::from_utf8("com.").unwrap();
2575        let hash_with_dot = hash(&with_dot);
2576
2577        let without_dot = Name::from_utf8("com").unwrap();
2578        let hash_without_dot = hash(&without_dot);
2579        assert_ne!(with_dot, without_dot);
2580        assert_ne!(hash_with_dot, hash_without_dot);
2581    }
2582
2583    #[test]
2584    #[cfg(feature = "std")]
2585    fn test_name_hash_label_boundaries() {
2586        let ab_c = Name::parse("ab.c.", None).unwrap();
2587        let a_bc = Name::parse("a.bc.", None).unwrap();
2588        assert_ne!(ab_c, a_bc);
2589        assert_ne!(hash(&ab_c), hash(&a_bc));
2590    }
2591
2592    #[cfg(feature = "std")]
2593    fn hash(name: &Name) -> u64 {
2594        let mut hasher = DefaultHasher::new();
2595        name.hash(&mut hasher);
2596        hasher.finish()
2597    }
2598
2599    #[test]
2600    fn eq_ignore_root_tests() {
2601        let fqdn_name = Name::from_utf8("host.example.com.").unwrap();
2602        let relative_name = Name::from_utf8("host.example.com").unwrap();
2603        let upper_relative_name = Name::from_ascii("HOST.EXAMPLE.COM").unwrap();
2604
2605        assert_ne!(fqdn_name, relative_name);
2606        assert!(fqdn_name.eq_ignore_root(&relative_name));
2607        assert!(!fqdn_name.eq_ignore_root_case(&upper_relative_name));
2608        assert!(fqdn_name.eq_ignore_root(&upper_relative_name));
2609    }
2610
2611    #[test]
2612    fn rfc4034_canonical_ordering_example() {
2613        // From section 6.1 of RFC 4034
2614        let names = Vec::from([
2615            Name::from_labels::<_, &[u8]>([b"example".as_slice()]).unwrap(),
2616            Name::from_labels::<_, &[u8]>([b"a".as_slice(), b"example".as_slice()]).unwrap(),
2617            Name::from_labels::<_, &[u8]>([
2618                b"yljkjljk".as_slice(),
2619                b"a".as_slice(),
2620                b"example".as_slice(),
2621            ])
2622            .unwrap(),
2623            Name::from_labels::<_, &[u8]>([
2624                b"Z".as_slice(),
2625                b"a".as_slice(),
2626                b"example".as_slice(),
2627            ])
2628            .unwrap(),
2629            Name::from_labels::<_, &[u8]>([
2630                b"zABC".as_slice(),
2631                b"a".as_slice(),
2632                b"EXAMPLE".as_slice(),
2633            ])
2634            .unwrap(),
2635            Name::from_labels::<_, &[u8]>([b"z".as_slice(), b"example".as_slice()]).unwrap(),
2636            Name::from_labels::<_, &[u8]>([
2637                b"\x01".as_slice(),
2638                b"z".as_slice(),
2639                b"example".as_slice(),
2640            ])
2641            .unwrap(),
2642            Name::from_labels::<_, &[u8]>([
2643                b"*".as_slice(),
2644                b"z".as_slice(),
2645                b"example".as_slice(),
2646            ])
2647            .unwrap(),
2648            Name::from_labels::<_, &[u8]>([
2649                b"\x80".as_slice(),
2650                b"z".as_slice(),
2651                b"example".as_slice(),
2652            ])
2653            .unwrap(),
2654        ]);
2655        let mut sorted = names.clone();
2656        sorted.sort();
2657        assert_eq!(names, sorted);
2658    }
2659}