domain/base/name/
traits.rs

1//! Domain name-related traits.
2//!
3//! This is a private module. Its public traits are re-exported by the parent.
4
5use super::absolute::Name;
6use super::chain::{Chain, LongChainError};
7use super::label::Label;
8use super::relative::RelativeName;
9#[cfg(feature = "bytes")]
10use bytes::Bytes;
11use core::convert::Infallible;
12use core::{cmp, fmt};
13use octseq::builder::{
14    infallible, BuilderAppendError, EmptyBuilder, FreezeBuilder, FromBuilder,
15    OctetsBuilder, ShortBuf,
16};
17#[cfg(feature = "std")]
18use std::borrow::Cow;
19
20//------------ ToLabelIter ---------------------------------------------------
21
22/// A type that can produce an iterator over its labels.
23///
24/// This trait is used as a trait bound for both [`ToName`] and
25/// [`ToRelativeName`]. It is separate since it has to be generic over the
26/// lifetime of the label reference but we don’t want to have this lifetime
27/// parameter pollute those traits.
28pub trait ToLabelIter {
29    /// The type of the iterator over the labels.
30    ///
31    /// This iterator types needs to be double ended so that we can deal with
32    /// name suffixes. It needs to be cloneable to be able to cascade over
33    /// parents of a name.
34    type LabelIter<'a>: Iterator<Item = &'a Label>
35        + DoubleEndedIterator
36        + Clone
37    where
38        Self: 'a;
39
40    /// Returns an iterator over the labels.
41    fn iter_labels(&self) -> Self::LabelIter<'_>;
42
43    /// Returns the length in octets of the encoded name.
44    fn compose_len(&self) -> u16 {
45        self.iter_labels().map(|label| label.compose_len()).sum()
46    }
47
48    /// Determines whether `base` is a prefix of `self`.
49    fn starts_with<N: ToLabelIter + ?Sized>(&self, base: &N) -> bool {
50        let mut self_iter = self.iter_labels();
51        let mut base_iter = base.iter_labels();
52        loop {
53            match (self_iter.next(), base_iter.next()) {
54                (Some(sl), Some(bl)) => {
55                    if sl != bl {
56                        return false;
57                    }
58                }
59                (_, None) => return true,
60                (None, Some(_)) => return false,
61            }
62        }
63    }
64
65    /// Determines whether `base` is a suffix of `self`.
66    fn ends_with<N: ToLabelIter + ?Sized>(&self, base: &N) -> bool {
67        let mut self_iter = self.iter_labels();
68        let mut base_iter = base.iter_labels();
69        loop {
70            match (self_iter.next_back(), base_iter.next_back()) {
71                (Some(sl), Some(bl)) => {
72                    if sl != bl {
73                        return false;
74                    }
75                }
76                (_, None) => return true,
77                (None, Some(_)) => return false,
78            }
79        }
80    }
81}
82
83impl<'r, N: ToLabelIter + ?Sized> ToLabelIter for &'r N {
84    type LabelIter<'a>
85        = N::LabelIter<'a>
86    where
87        'r: 'a,
88        N: 'a;
89
90    fn iter_labels(&self) -> Self::LabelIter<'_> {
91        (*self).iter_labels()
92    }
93}
94
95//------------ ToName -------------------------------------------------------
96
97/// A type that represents an absolute domain name.
98///
99/// An absolute domain name is a sequence of labels where the last label is
100/// the root label and where the wire-format representation is not longer than
101/// 255 characters. Implementers of this trait need to provide access to the
102/// label sequence via an iterator and know how to compose the wire-format
103/// representation into a buffer.
104///
105/// The most common types implementing this trait are [`Name`],
106/// [`ParsedName`], and [`Chain<L, R>`] where `R` is [`ToName`] itself.
107///
108/// [`ParsedName`]: crate::base::name::ParsedName
109pub trait ToName: ToLabelIter {
110    /// Converts the name into a single, uncompressed name.
111    ///
112    /// The default implementation provided by the trait iterates over the
113    /// labels of the name and adds them one by one to [`Name`]. This will
114    /// work for any name but an optimized implementation can be provided for
115    /// some types of names.
116    fn try_to_name<Octets>(
117        &self,
118    ) -> Result<Name<Octets>, BuilderAppendError<Octets>>
119    where
120        Octets: FromBuilder,
121        <Octets as FromBuilder>::Builder: EmptyBuilder,
122    {
123        let mut builder =
124            Octets::Builder::with_capacity(self.compose_len().into());
125        self.iter_labels()
126            .try_for_each(|label| label.compose(&mut builder))?;
127        Ok(unsafe { Name::from_octets_unchecked(builder.freeze()) })
128    }
129
130    /// Converts the name into a single, uncompressed name.
131    ///
132    /// This is the same as [`try_to_name`][ToName::try_to_name] but for
133    /// builder types with an unrestricted buffer.
134    fn to_name<Octets>(&self) -> Name<Octets>
135    where
136        Octets: FromBuilder,
137        <Octets as FromBuilder>::Builder:
138            OctetsBuilder<AppendError = Infallible>,
139        <Octets as FromBuilder>::Builder: EmptyBuilder,
140    {
141        infallible(self.try_to_name())
142    }
143
144    /// Converts the name into a single name in canonical form.
145    fn try_to_canonical_name<Octets>(
146        &self,
147    ) -> Result<Name<Octets>, BuilderAppendError<Octets>>
148    where
149        Octets: FromBuilder,
150        <Octets as FromBuilder>::Builder: EmptyBuilder,
151    {
152        let mut builder =
153            Octets::Builder::with_capacity(self.compose_len().into());
154        self.iter_labels()
155            .try_for_each(|label| label.compose_canonical(&mut builder))?;
156        Ok(unsafe { Name::from_octets_unchecked(builder.freeze()) })
157    }
158
159    /// Converts the name into a single name in canonical form.
160    ///
161    /// This is the same as
162    /// [`try_to_canonical_name`][ToName::try_to_canonical_name] but for
163    /// builder types with an unrestricted buffer.
164    fn to_canonical_name<Octets>(&self) -> Name<Octets>
165    where
166        Octets: FromBuilder,
167        <Octets as FromBuilder>::Builder:
168            OctetsBuilder<AppendError = Infallible>,
169        <Octets as FromBuilder>::Builder: EmptyBuilder,
170    {
171        infallible(self.try_to_canonical_name())
172    }
173
174    /// Returns an octets slice of the content if possible.
175    ///
176    /// If a value stores the domain name as one single octets sequence, it
177    /// should return a reference to this sequence here. If the name is
178    /// composed from multiple such sequences, it should return `None`.
179    ///
180    /// This method is used to optimize comparision operations between
181    /// two values that are indeed flat names.
182    fn as_flat_slice(&self) -> Option<&[u8]> {
183        None
184    }
185
186    fn compose<Target: OctetsBuilder + ?Sized>(
187        &self,
188        target: &mut Target,
189    ) -> Result<(), Target::AppendError> {
190        if let Some(slice) = self.as_flat_slice() {
191            target.append_slice(slice)
192        } else {
193            for label in self.iter_labels() {
194                label.compose(target)?;
195            }
196            Ok(())
197        }
198    }
199
200    fn compose_canonical<Target: OctetsBuilder + ?Sized>(
201        &self,
202        target: &mut Target,
203    ) -> Result<(), Target::AppendError> {
204        for label in self.iter_labels() {
205            label.compose_canonical(target)?;
206        }
207        Ok(())
208    }
209
210    /// Returns a cow of the domain name.
211    ///
212    /// If the name is available as one single slice – i.e.,
213    /// [`as_flat_slice`] returns ‘some,’ creates the borrowed variant from
214    /// that slice. Otherwise assembles an owned variant via [`to_name`].
215    ///
216    /// [`as_flat_slice`]: ToName::as_flat_slice
217    /// [`to_name`]: ToName::to_name
218    #[cfg(feature = "std")]
219    fn to_cow(&self) -> Name<std::borrow::Cow<[u8]>> {
220        let octets = self
221            .as_flat_slice()
222            .map(Cow::Borrowed)
223            .unwrap_or_else(|| Cow::Owned(self.to_vec().into_octets()));
224        unsafe { Name::from_octets_unchecked(octets) }
225    }
226
227    /// Returns the domain name assembled into a `Vec<u8>`.
228    #[cfg(feature = "std")]
229    fn to_vec(&self) -> Name<std::vec::Vec<u8>> {
230        self.to_name()
231    }
232
233    /// Returns the domain name assembled into a bytes value.
234    #[cfg(feature = "bytes")]
235    fn to_bytes(&self) -> Name<Bytes> {
236        self.to_name()
237    }
238
239    /// Tests whether `self` and `other` are equal.
240    ///
241    /// This method can be used to implement [`PartialEq`] on types implementing
242    /// [`ToName`] since a blanket implementation for all pairs of `ToName`
243    /// is currently impossible.
244    ///
245    /// Domain names are compared ignoring ASCII case.
246    fn name_eq<N: ToName + ?Sized>(&self, other: &N) -> bool {
247        if let (Some(left), Some(right)) =
248            (self.as_flat_slice(), other.as_flat_slice())
249        {
250            // We can do this because the length octets of each label are in
251            // the ranged 0..64 which is before all ASCII letters.
252            left.eq_ignore_ascii_case(right)
253        } else {
254            self.iter_labels().eq(other.iter_labels())
255        }
256    }
257
258    /// Returns the ordering between `self` and `other`.
259    ///
260    /// This method can be used to implement both [`PartialOrd`] and [`Ord`] on
261    /// types implementing [`ToName`] since a blanket implementation for all
262    /// pairs of [`ToName`]s is currently not possible.
263    ///
264    /// Domain name order is determined according to the ‘canonical DNS
265    /// name order’ as defined in [section 6.1 of RFC 4034][RFC4034-6.1].
266    ///
267    /// [RFC4034-6.1]: https://tools.ietf.org/html/rfc4034#section-6.1
268    fn name_cmp<N: ToName + ?Sized>(&self, other: &N) -> cmp::Ordering {
269        let mut self_iter = self.iter_labels();
270        let mut other_iter = other.iter_labels();
271        loop {
272            match (self_iter.next_back(), other_iter.next_back()) {
273                (Some(left), Some(right)) => match left.cmp(right) {
274                    cmp::Ordering::Equal => {}
275                    res => return res,
276                },
277                (None, Some(_)) => return cmp::Ordering::Less,
278                (Some(_), None) => return cmp::Ordering::Greater,
279                (None, None) => return cmp::Ordering::Equal,
280            }
281        }
282    }
283
284    /// Returns the composed name ordering.
285    fn composed_cmp<N: ToName + ?Sized>(&self, other: &N) -> cmp::Ordering {
286        if let (Some(left), Some(right)) =
287            (self.as_flat_slice(), other.as_flat_slice())
288        {
289            return left.cmp(right);
290        }
291        let mut self_iter = self.iter_labels();
292        let mut other_iter = other.iter_labels();
293        loop {
294            match (self_iter.next(), other_iter.next()) {
295                (Some(left), Some(right)) => match left.composed_cmp(right) {
296                    cmp::Ordering::Equal => {}
297                    other => return other,
298                },
299                (None, None) => return cmp::Ordering::Equal,
300                _ => {
301                    // The root label sorts before any other label, so we
302                    // can never end up in a situation where one name runs
303                    // out of labels while comparing equal.
304                    unreachable!()
305                }
306            }
307        }
308    }
309
310    /// Returns the lowercase composed ordering.
311    fn lowercase_composed_cmp<N: ToName + ?Sized>(
312        &self,
313        other: &N,
314    ) -> cmp::Ordering {
315        // Since there isn’t a `cmp_ignore_ascii_case` on slice, we don’t
316        // gain much from the shortcut.
317        let mut self_iter = self.iter_labels();
318        let mut other_iter = other.iter_labels();
319        loop {
320            match (self_iter.next(), other_iter.next()) {
321                (Some(left), Some(right)) => {
322                    match left.lowercase_composed_cmp(right) {
323                        cmp::Ordering::Equal => {}
324                        other => return other,
325                    }
326                }
327                (None, None) => return cmp::Ordering::Equal,
328                _ => {
329                    // The root label sorts before any other label, so we
330                    // can never end up in a situation where one name runs
331                    // out of labels while comparing equal.
332                    unreachable!()
333                }
334            }
335        }
336    }
337
338    /// Returns the number of labels for the RRSIG Labels field.
339    ///
340    /// This is the actual number of labels without counting the root label
341    /// or a possible initial asterisk label.
342    fn rrsig_label_count(&self) -> u8 {
343        let mut labels = self.iter_labels();
344        if labels.next().unwrap().is_wildcard() {
345            (labels.count() - 1) as u8
346        } else {
347            labels.count() as u8
348        }
349    }
350
351    fn fmt_with_dot(&self) -> DisplayWithDot<'_, Self> {
352        DisplayWithDot(self)
353    }
354}
355
356pub struct DisplayWithDot<'a, T: ?Sized>(&'a T);
357
358impl<T> fmt::Display for DisplayWithDot<'_, T>
359where
360    T: ToLabelIter + ?Sized,
361{
362    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
363        let mut labels = self.0.iter_labels();
364        let first = match labels.next() {
365            Some(first) => first,
366            None => unreachable!("at least 1 label must be present"),
367        };
368
369        if first.is_root() {
370            f.write_str(".")
371        } else {
372            write!(f, "{}", first)?;
373            for label in labels {
374                write!(f, ".{}", label)?
375            }
376            Ok(())
377        }
378    }
379}
380
381impl<'a, N: ToName + ?Sized + 'a> ToName for &'a N {}
382
383//------------ ToRelativeName ------------------------------------------------
384
385/// A type that represents a relative domain name.
386///
387/// In order to be a relative domain name, a type needs to be able to
388/// provide a sequence of labels via an iterator where the last label is not
389/// the root label. The type also needs to be able to compose the wire-format
390/// representation of the domain name it represents which must not be longer
391/// than 254 characters. This limit has been chosen so that by attaching the
392/// one character long root label, a valid absolute name can be constructed
393/// from the relative name.
394///
395/// The most important types implementing this trait are [`RelativeName`]
396/// and [`Chain<L,R>`] where `R` is a [`ToRelativeName`] itself.
397pub trait ToRelativeName: ToLabelIter {
398    /// Converts the name into a single, continous name.
399    ///
400    /// The canonical implementation provided by the trait iterates over the
401    /// labels of the name and adds them one by one to [`RelativeName`].
402    /// This will work for any name but an optimized implementation can be
403    /// provided for some types of names.
404    fn try_to_relative_name<Octets>(
405        &self,
406    ) -> Result<RelativeName<Octets>, BuilderAppendError<Octets>>
407    where
408        Octets: FromBuilder,
409        <Octets as FromBuilder>::Builder: EmptyBuilder,
410    {
411        let mut builder =
412            Octets::Builder::with_capacity(self.compose_len().into());
413        self.iter_labels()
414            .try_for_each(|label| label.compose(&mut builder))?;
415        Ok(unsafe { RelativeName::from_octets_unchecked(builder.freeze()) })
416    }
417
418    /// Converts the name into a single, continous name.
419    ///
420    /// This is the same as
421    /// [`try_to_relative_name`][ToRelativeName::try_to_relative_name]
422    /// but for builder types with an unrestricted buffer.
423    fn to_relative_name<Octets>(&self) -> RelativeName<Octets>
424    where
425        Octets: FromBuilder,
426        <Octets as FromBuilder>::Builder:
427            OctetsBuilder<AppendError = Infallible>,
428        <Octets as FromBuilder>::Builder: EmptyBuilder,
429    {
430        infallible(self.try_to_relative_name())
431    }
432
433    /// Converts the name into a single name in canonical form.
434    fn try_to_canonical_relative_name<Octets>(
435        &self,
436    ) -> Result<RelativeName<Octets>, BuilderAppendError<Octets>>
437    where
438        Octets: FromBuilder,
439        <Octets as FromBuilder>::Builder: EmptyBuilder,
440    {
441        let mut builder =
442            Octets::Builder::with_capacity(self.compose_len().into());
443        self.iter_labels()
444            .try_for_each(|label| label.compose_canonical(&mut builder))?;
445        Ok(unsafe { RelativeName::from_octets_unchecked(builder.freeze()) })
446    }
447
448    /// Converts the name into a single name in canonical form.
449    ///
450    /// This is the same as
451    /// [`try_to_canonical_relative_name`][ToRelativeName::try_to_canonical_relative_name]
452    /// but for builder types with an unrestricted buffer.
453    fn to_canonical_relative_name<Octets>(&self) -> RelativeName<Octets>
454    where
455        Octets: FromBuilder,
456        <Octets as FromBuilder>::Builder:
457            OctetsBuilder<AppendError = Infallible>,
458        <Octets as FromBuilder>::Builder: EmptyBuilder,
459    {
460        infallible(self.try_to_canonical_relative_name())
461    }
462
463    /// Returns a byte slice of the content if possible.
464    ///
465    /// This method can is used to optimize comparision operations between
466    /// two values that are indeed flat names.
467    fn as_flat_slice(&self) -> Option<&[u8]> {
468        None
469    }
470
471    fn compose<Target: OctetsBuilder + ?Sized>(
472        &self,
473        target: &mut Target,
474    ) -> Result<(), Target::AppendError> {
475        if let Some(slice) = self.as_flat_slice() {
476            target.append_slice(slice)
477        } else {
478            for label in self.iter_labels() {
479                label.compose(target)?;
480            }
481            Ok(())
482        }
483    }
484
485    fn compose_canonical<Target: OctetsBuilder + ?Sized>(
486        &self,
487        target: &mut Target,
488    ) -> Result<(), Target::AppendError> {
489        for label in self.iter_labels() {
490            label.compose_canonical(target)?;
491        }
492        Ok(())
493    }
494
495    /// Returns a cow of the relative domain name.
496    ///
497    /// If the name is available as one single slice – i.e.,
498    /// [`as_flat_slice`] returns ‘some,’ creates the borrowed variant from
499    /// that slice. Otherwise assembles an owned variant via
500    /// [`to_relative_name`].
501    ///
502    /// [`as_flat_slice`]: ToRelativeName::as_flat_slice
503    /// [`to_relative_name`]: ToRelativeName::to_relative_name
504    #[cfg(feature = "std")]
505    fn to_cow(&self) -> RelativeName<std::borrow::Cow<[u8]>> {
506        let octets = self
507            .as_flat_slice()
508            .map(Cow::Borrowed)
509            .unwrap_or_else(|| Cow::Owned(self.to_vec().into_octets()));
510        unsafe { RelativeName::from_octets_unchecked(octets) }
511    }
512
513    /// Returns the domain name assembled into a `Vec<u8>`.
514    #[cfg(feature = "std")]
515    fn to_vec(&self) -> RelativeName<std::vec::Vec<u8>> {
516        self.to_relative_name()
517    }
518
519    /// Returns the domain name assembled into a bytes value.
520    #[cfg(feature = "bytes")]
521    fn to_bytes(&self) -> RelativeName<Bytes> {
522        self.to_relative_name()
523    }
524
525    /// Returns whether the name is empty.
526    fn is_empty(&self) -> bool {
527        self.iter_labels().next().is_none()
528    }
529
530    /// Returns a chain of this name and the provided name.
531    fn chain<N: ToLabelIter>(
532        self,
533        suffix: N,
534    ) -> Result<Chain<Self, N>, LongChainError>
535    where
536        Self: Sized,
537    {
538        Chain::new(self, suffix)
539    }
540
541    /// Returns the absolute name by chaining it with the root label.
542    fn chain_root(self) -> Chain<Self, Name<&'static [u8]>>
543    where
544        Self: Sized,
545    {
546        // Appending the root label will always work.
547        Chain::new(self, Name::root()).unwrap()
548    }
549
550    /// Tests whether `self` and `other` are equal.
551    ///
552    /// This method can be used to implement [`PartialEq`] on types implementing
553    /// [`ToName`] since a blanket implementation for all pairs of [`ToName`]
554    /// is currently impossible.
555    ///
556    /// Domain names are compared ignoring ASCII case.
557    fn name_eq<N: ToRelativeName + ?Sized>(&self, other: &N) -> bool {
558        if let (Some(left), Some(right)) =
559            (self.as_flat_slice(), other.as_flat_slice())
560        {
561            left.eq_ignore_ascii_case(right)
562        } else {
563            self.iter_labels().eq(other.iter_labels())
564        }
565    }
566
567    /// Returns the ordering between `self` and `other`.
568    ///
569    /// This method can be used to implement both `PartialOrd` and `Ord` on
570    /// types implementing `ToName` since a blanket implementation for all
571    /// pairs of `ToName`s is currently not possible.
572    ///
573    /// Domain name order is determined according to the ‘canonical DNS
574    /// name order’ as defined in [section 6.1 of RFC 4034][RFC4034-6.1].
575    /// This section describes how absolute domain names are ordered only.
576    /// We will order relative domain names according to these rules as if
577    /// they had the same origin, i.e., as if they were relative to the
578    /// same name.
579    ///
580    /// [RFC4034-6.1]: https://tools.ietf.org/html/rfc4034#section-6.1
581    fn name_cmp<N: ToRelativeName + ?Sized>(
582        &self,
583        other: &N,
584    ) -> cmp::Ordering {
585        let mut self_iter = self.iter_labels();
586        let mut other_iter = other.iter_labels();
587        loop {
588            match (self_iter.next_back(), other_iter.next_back()) {
589                (Some(left), Some(right)) => match left.cmp(right) {
590                    cmp::Ordering::Equal => {}
591                    res => return res,
592                },
593                (None, Some(_)) => return cmp::Ordering::Less,
594                (Some(_), None) => return cmp::Ordering::Greater,
595                (None, None) => return cmp::Ordering::Equal,
596            }
597        }
598    }
599}
600
601impl<'a, N: ToRelativeName + ?Sized + 'a> ToRelativeName for &'a N {}
602
603//------------ FlattenInto ---------------------------------------------------
604
605pub trait FlattenInto<Target>: Sized {
606    type AppendError: Into<ShortBuf>;
607
608    fn try_flatten_into(self) -> Result<Target, Self::AppendError>;
609
610    fn flatten_into(self) -> Target
611    where
612        Self::AppendError: Into<Infallible>,
613    {
614        infallible(self.try_flatten_into())
615    }
616}