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}