domain/base/
rdata.rs

1//! Resource record data.
2//!
3//! Each resource record type has it’s own definition of the content and
4//! formatting of its data. This module provides the basics for implementing
5//! specific types for this record data. The concrete implementations for
6//! well-known record types live in the top-level [`domain::rdata`] module.
7//!
8//! There are three traits herein: Any type that represents record data
9//! implements [`RecordData`]. Such a type can be added to a message. If
10//! the data can also be parsed from an existing message, the type in addition
11//! implements [`ParseRecordData`].
12//!
13//! The module also provides a type, [`UnknownRecordData`], that can be used
14//! to deal with record types whose specification is not known (or has not
15//! been implemented yet).
16//!
17//! [`domain::rdata`]: crate::rdata
18use super::cmp::CanonicalOrd;
19use super::iana::Rtype;
20use super::scan::{Scan, Scanner, ScannerError, Symbol};
21use super::wire::{Compose, Composer, ParseError};
22use super::zonefile_fmt::{self, Formatter, ZonefileFmt};
23use crate::utils::base16;
24use core::cmp::Ordering;
25use core::fmt;
26use octseq::octets::{Octets, OctetsFrom};
27use octseq::parse::Parser;
28
29//----------- RecordData -----------------------------------------------------
30
31/// A type that represents record data.
32///
33/// The type needs to be able to to be able to provide the record type of a
34/// record with a value’s data via the [`rtype`][RecordData::rtype] method.
35pub trait RecordData {
36    /// Returns the record type associated with this record data instance.
37    ///
38    /// This is a method rather than an associated function to allow one
39    /// type to be used for several real record types.
40    fn rtype(&self) -> Rtype;
41}
42
43impl<T: RecordData> RecordData for &T {
44    fn rtype(&self) -> Rtype {
45        (*self).rtype()
46    }
47}
48
49//----------- ComposeRecordData ----------------------------------------------
50
51/// A type of record data that can be composed.
52pub trait ComposeRecordData: RecordData {
53    /// Returns the length of the record data if available.
54    ///
55    /// The method should return `None`, if the length is not known or is not
56    /// the same for all targets.
57    ///
58    /// If `compress` is `true`, name compression is available in the target.
59    /// If name compression would be used in `compose_rdata`, the method
60    /// should `None` if `compress` is `true` since it can’t know the final
61    /// size.
62    fn rdlen(&self, compress: bool) -> Option<u16>;
63
64    /// Appends the wire format of the record data into `target`.
65    fn compose_rdata<Target: Composer + ?Sized>(
66        &self,
67        target: &mut Target,
68    ) -> Result<(), Target::AppendError>;
69
70    /// Appends the canonical wire format of the record data into `target`.
71    fn compose_canonical_rdata<Target: Composer + ?Sized>(
72        &self,
73        target: &mut Target,
74    ) -> Result<(), Target::AppendError>;
75
76    /// Appends the record data prefixed with its length.
77    fn compose_len_rdata<Target: Composer + ?Sized>(
78        &self,
79        target: &mut Target,
80    ) -> Result<(), Target::AppendError> {
81        if let Some(rdlen) = self.rdlen(target.can_compress()) {
82            rdlen.compose(target)?;
83            self.compose_rdata(target)
84        } else {
85            compose_prefixed(target, |target| self.compose_rdata(target))
86        }
87    }
88
89    /// Appends the record data prefixed with its length.
90    fn compose_canonical_len_rdata<Target: Composer + ?Sized>(
91        &self,
92        target: &mut Target,
93    ) -> Result<(), Target::AppendError> {
94        if let Some(rdlen) = self.rdlen(false) {
95            rdlen.compose(target)?;
96            self.compose_canonical_rdata(target)
97        } else {
98            compose_prefixed(target, |target| {
99                self.compose_canonical_rdata(target)
100            })
101        }
102    }
103}
104
105fn compose_prefixed<Target: Composer + ?Sized, F>(
106    target: &mut Target,
107    op: F,
108) -> Result<(), Target::AppendError>
109where
110    F: FnOnce(&mut Target) -> Result<(), Target::AppendError>,
111{
112    target.append_slice(&[0; 2])?;
113    let pos = target.as_ref().len();
114    match op(target) {
115        Ok(_) => {
116            let len = u16::try_from(target.as_ref().len() - pos)
117                .expect("long data");
118            target.as_mut()[pos - 2..pos]
119                .copy_from_slice(&(len).to_be_bytes());
120            Ok(())
121        }
122        Err(err) => {
123            target.truncate(pos);
124            Err(err)
125        }
126    }
127}
128
129impl<T: ComposeRecordData> ComposeRecordData for &T {
130    fn rdlen(&self, compress: bool) -> Option<u16> {
131        (*self).rdlen(compress)
132    }
133
134    fn compose_rdata<Target: Composer + ?Sized>(
135        &self,
136        target: &mut Target,
137    ) -> Result<(), Target::AppendError> {
138        (*self).compose_rdata(target)
139    }
140
141    fn compose_canonical_rdata<Target: Composer + ?Sized>(
142        &self,
143        target: &mut Target,
144    ) -> Result<(), Target::AppendError> {
145        (*self).compose_canonical_rdata(target)
146    }
147}
148
149//------------ ParseRecordData and ParseAllRecordData ------------------------
150
151/// A record data type that can be parsed from a message.
152///
153/// This trait allows a record data type to express whether it is able to
154/// parse record data for a specific record type. It is thus implemented by
155/// all record data types included in the [`rdata`][crate::rdata] module.
156pub trait ParseRecordData<'a, Octs: ?Sized>: RecordData + Sized {
157    /// Parses the record data.
158    ///
159    /// The record data is for a record of type `rtype`. The function may
160    /// decide whether it wants to parse data for that type. It should return
161    /// `Ok(None)` if it doesn’t.
162    ///
163    /// The `parser` is positioned at the beginning of the record data and is
164    /// is limited to the length of the data. The function only needs to parse
165    /// as much data as it needs. The caller has to make sure to deal with
166    /// data remaining in the parser.
167    ///
168    /// If the function doesn’t want to process the data, it must not touch
169    /// the parser. In particular, it must not advance it.
170    fn parse_rdata(
171        rtype: Rtype,
172        parser: &mut Parser<'a, Octs>,
173    ) -> Result<Option<Self>, ParseError>;
174}
175
176/// A record data type that can parse and represent any type of record.
177///
178/// While [`ParseRecordData`] allows a type to signal that it doesn’t
179/// actually cover a certain record type, this trait is for types that can
180/// parse and represent record data of any type.
181///
182/// When implementing a type for this trait, keep in mind that some record
183/// types – specifically those defined by [RFC 1035][crate::rdata::rfc1035] –
184/// can contain compressed domain names. Thus, this trait cannot be
185/// implemented by [`UnknownRecordData`] which just takes the raw data
186/// uninterpreted.
187pub trait ParseAnyRecordData<'a, Octs: ?Sized>: RecordData + Sized {
188    /// Parses the record data.
189    ///
190    /// The record data is for a record of type `rtype`.
191    ///
192    /// The `parser` is positioned at the beginning of the record data and is
193    /// is limited to the length of the data. The function only needs to parse
194    /// as much data as it needs. The caller has to make sure to deal with
195    /// data remaining in the parser.
196    fn parse_any_rdata(
197        rtype: Rtype,
198        parser: &mut Parser<'a, Octs>,
199    ) -> Result<Self, ParseError>;
200}
201
202//------------ UnknownRecordData ---------------------------------------------
203
204/// A type for parsing any type of record data.
205///
206/// This type accepts any record type and stores the plain, unparsed record
207/// data as an octets sequence.
208///
209/// Because some record types allow compressed domain names in their record
210/// data, this type cannot be used safely with these record types. For these
211/// record types, the structure of the content needs to be known.
212///
213/// [RFC 3597] limits the types for which compressed names are allowed in the
214/// record data to those defined in [RFC 1035] itself. Specific types for all
215/// these record types exist in
216/// [`domain::rdata::rfc1035`][crate::rdata::rfc1035].
217///
218/// Ultimately, you should only use this type for record types for which there
219/// is no implementation available in this crate. The two types
220/// [`AllRecordData`] and [`ZoneRecordData`] provide a convenient way to
221/// always use the correct record data type.
222///
223/// [`AllRecordData`]: crate::rdata::AllRecordData
224/// [`ZoneRecordData`]: crate::rdata::ZoneRecordData
225/// [RFC 1035]: https://tools.ietf.org/html/rfc1035
226/// [RFC 3597]: https://tools.ietf.org/html/rfc3597
227/// [`domain::rdata::rfc1035]: ../../rdata/rfc1035/index.html
228#[derive(Clone)]
229#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
230pub struct UnknownRecordData<Octs> {
231    /// The record type of this data.
232    rtype: Rtype,
233
234    /// The record data.
235    #[cfg_attr(
236        feature = "serde",
237        serde(
238            serialize_with = "crate::utils::base16::serde::serialize",
239            deserialize_with = "crate::utils::base16::serde::deserialize",
240            bound(
241                serialize = "Octs: AsRef<[u8]> + octseq::serde::SerializeOctets",
242                deserialize = "\
243                    Octs: \
244                        octseq::builder::FromBuilder + \
245                        octseq::serde::DeserializeOctets<'de>, \
246                    <Octs as octseq::builder::FromBuilder>::Builder: \
247                        octseq::builder::EmptyBuilder, \
248                ",
249            )
250        )
251    )]
252    data: Octs,
253}
254
255impl<Octs> UnknownRecordData<Octs> {
256    /// Creates generic record data from a bytes value contain the data.
257    pub fn from_octets(
258        rtype: Rtype,
259        data: Octs,
260    ) -> Result<Self, LongRecordData>
261    where
262        Octs: AsRef<[u8]>,
263    {
264        LongRecordData::check_len(data.as_ref().len())?;
265        Ok(UnknownRecordData { rtype, data })
266    }
267
268    /// Returns the record type this data is for.
269    pub fn rtype(&self) -> Rtype {
270        self.rtype
271    }
272
273    /// Returns a reference to the record data.
274    pub fn data(&self) -> &Octs {
275        &self.data
276    }
277
278    /// Scans the record data.
279    ///
280    /// This isn’t implemented via [`Scan`], because we need the record type.
281    pub fn scan<S: Scanner<Octets = Octs>>(
282        rtype: Rtype,
283        scanner: &mut S,
284    ) -> Result<Self, S::Error>
285    where
286        Octs: AsRef<[u8]>,
287    {
288        // First token is literal "\#".
289        let mut first = true;
290        scanner.scan_symbols(|symbol| {
291            if first {
292                first = false;
293                match symbol {
294                    Symbol::SimpleEscape(b'#') => Ok(()),
295                    _ => Err(S::Error::custom("'\\#' expected")),
296                }
297            } else {
298                Err(S::Error::custom("'\\#' expected"))
299            }
300        })?;
301        Self::scan_without_marker(rtype, scanner)
302    }
303
304    /// Scans the record data assuming that the marker has been skipped.
305    pub fn scan_without_marker<S: Scanner<Octets = Octs>>(
306        rtype: Rtype,
307        scanner: &mut S,
308    ) -> Result<Self, S::Error>
309    where
310        Octs: AsRef<[u8]>,
311    {
312        // Second token is the rdata length.
313        let len = u16::scan(scanner)?;
314
315        // The rest is the actual data.
316        let data = scanner.convert_entry(base16::SymbolConverter::new())?;
317
318        if data.as_ref().len() != usize::from(len) {
319            return Err(S::Error::custom(
320                "generic data has incorrect length",
321            ));
322        }
323
324        Ok(UnknownRecordData { rtype, data })
325    }
326
327    /// Parses any record type as unknown record data.
328    ///
329    /// This is an associated function rather than an impl of
330    /// [`ParseAnyRecordData`] because some record types must not be parsed
331    /// as unknown data as they can contain compressed domain names.
332    pub fn parse_any_rdata<'a, SrcOcts>(
333        rtype: Rtype,
334        parser: &mut Parser<'a, SrcOcts>,
335    ) -> Result<Self, ParseError>
336    where
337        SrcOcts: Octets<Range<'a> = Octs> + ?Sized + 'a,
338    {
339        let rdlen = parser.remaining();
340        parser
341            .parse_octets(rdlen)
342            .map(|data| Self { rtype, data })
343            .map_err(Into::into)
344    }
345}
346
347//--- OctetsFrom
348
349impl<Octs, SrcOcts> OctetsFrom<UnknownRecordData<SrcOcts>>
350    for UnknownRecordData<Octs>
351where
352    Octs: OctetsFrom<SrcOcts>,
353{
354    type Error = Octs::Error;
355
356    fn try_octets_from(
357        source: UnknownRecordData<SrcOcts>,
358    ) -> Result<Self, Self::Error> {
359        Ok(UnknownRecordData {
360            rtype: source.rtype,
361            data: Octs::try_octets_from(source.data)?,
362        })
363    }
364}
365
366//--- PartialEq and Eq
367
368impl<Octs, Other> PartialEq<UnknownRecordData<Other>>
369    for UnknownRecordData<Octs>
370where
371    Octs: AsRef<[u8]>,
372    Other: AsRef<[u8]>,
373{
374    fn eq(&self, other: &UnknownRecordData<Other>) -> bool {
375        self.data.as_ref().eq(other.data.as_ref())
376    }
377}
378
379impl<Octs: AsRef<[u8]>> Eq for UnknownRecordData<Octs> {}
380
381//--- PartialOrd, CanonicalOrd, and Ord
382
383impl<Octs, Other> PartialOrd<UnknownRecordData<Other>>
384    for UnknownRecordData<Octs>
385where
386    Octs: AsRef<[u8]>,
387    Other: AsRef<[u8]>,
388{
389    fn partial_cmp(
390        &self,
391        other: &UnknownRecordData<Other>,
392    ) -> Option<Ordering> {
393        self.data.as_ref().partial_cmp(other.data.as_ref())
394    }
395}
396
397impl<Octs, Other> CanonicalOrd<UnknownRecordData<Other>>
398    for UnknownRecordData<Octs>
399where
400    Octs: AsRef<[u8]>,
401    Other: AsRef<[u8]>,
402{
403    fn canonical_cmp(&self, other: &UnknownRecordData<Other>) -> Ordering {
404        self.data.as_ref().cmp(other.data.as_ref())
405    }
406}
407
408impl<Octs: AsRef<[u8]>> Ord for UnknownRecordData<Octs> {
409    fn cmp(&self, other: &Self) -> Ordering {
410        self.data.as_ref().cmp(other.data.as_ref())
411    }
412}
413
414//--- ComposeRecordData
415
416impl<Octs: AsRef<[u8]>> ComposeRecordData for UnknownRecordData<Octs> {
417    fn rdlen(&self, _compress: bool) -> Option<u16> {
418        Some(u16::try_from(self.data.as_ref().len()).expect("long rdata"))
419    }
420
421    fn compose_rdata<Target: Composer + ?Sized>(
422        &self,
423        target: &mut Target,
424    ) -> Result<(), Target::AppendError> {
425        target.append_slice(self.data.as_ref())
426    }
427
428    fn compose_canonical_rdata<Target: Composer + ?Sized>(
429        &self,
430        target: &mut Target,
431    ) -> Result<(), Target::AppendError> {
432        self.compose_rdata(target)
433    }
434}
435
436//--- RecordData and ParseRecordData
437
438impl<Octs: AsRef<[u8]>> RecordData for UnknownRecordData<Octs> {
439    fn rtype(&self) -> Rtype {
440        self.rtype
441    }
442}
443
444impl<'a, Octs: Octets + ?Sized> ParseRecordData<'a, Octs>
445    for UnknownRecordData<Octs::Range<'a>>
446{
447    fn parse_rdata(
448        rtype: Rtype,
449        parser: &mut Parser<'a, Octs>,
450    ) -> Result<Option<Self>, ParseError> {
451        let rdlen = parser.remaining();
452        parser
453            .parse_octets(rdlen)
454            .map(|data| Some(Self { rtype, data }))
455            .map_err(Into::into)
456    }
457}
458
459//--- Display
460
461impl<Octs: AsRef<[u8]>> fmt::Display for UnknownRecordData<Octs> {
462    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
463        write!(f, "\\# {}", self.data.as_ref().len())?;
464        for ch in self.data.as_ref() {
465            write!(f, " {:02x}", *ch)?
466        }
467        Ok(())
468    }
469}
470
471//--- Debug
472
473impl<Octs: AsRef<[u8]>> fmt::Debug for UnknownRecordData<Octs> {
474    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
475        f.write_str("UnknownRecordData(")?;
476        fmt::Display::fmt(self, f)?;
477        f.write_str(")")
478    }
479}
480
481//--- ZonefileFmt
482
483impl<Octs: AsRef<[u8]>> ZonefileFmt for UnknownRecordData<Octs> {
484    fn fmt(&self, p: &mut impl Formatter) -> zonefile_fmt::Result {
485        struct Data<'a>(&'a [u8]);
486
487        impl fmt::Display for Data<'_> {
488            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
489                write!(f, "\\# {}", self.0.len())?;
490                for ch in self.0 {
491                    write!(f, " {:02x}", *ch)?
492                }
493                Ok(())
494            }
495        }
496
497        p.write_token(Data(self.data.as_ref()))
498    }
499}
500
501//============ Errors ========================================================
502
503//------------ LongRecordData ------------------------------------------------
504
505/// The octets sequence to be used for record data is too long.
506#[derive(Clone, Copy, Debug)]
507pub struct LongRecordData(());
508
509impl LongRecordData {
510    #[must_use]
511    pub fn as_str(self) -> &'static str {
512        "record data too long"
513    }
514
515    pub fn check_len(len: usize) -> Result<(), Self> {
516        if len > usize::from(u16::MAX) {
517            Err(Self(()))
518        } else {
519            Ok(())
520        }
521    }
522
523    pub fn check_append_len(
524        len: usize,
525        extra_len: usize,
526    ) -> Result<(), Self> {
527        // This version is safe on 16 bit systems.
528        Self::check_len(len.checked_add(extra_len).ok_or(Self(()))?)
529    }
530}
531
532impl fmt::Display for LongRecordData {
533    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
534        f.write_str(self.as_str())
535    }
536}
537
538#[cfg(feature = "std")]
539impl std::error::Error for LongRecordData {}
540
541//============ Testing ======================================================
542
543#[cfg(test)]
544#[cfg(all(feature = "std", feature = "bytes"))]
545pub(crate) mod test {
546    use super::super::scan::IterScanner;
547    use super::*;
548    use bytes::{Bytes, BytesMut};
549    use core::fmt::Debug;
550    use octseq::builder::infallible;
551    use std::vec::Vec;
552
553    /// Check that `rdlen` produces the correct length.
554    ///
555    /// The test composes `data` both regularly and cannonically and checks
556    /// that the length of the composed data matches what `rdlen` returns.
557    ///
558    /// This test expects that `rdlen` returns some value if `compress`
559    /// is false. This isn’t required but all our record types are supposed
560    /// to do this, anyway.
561    pub fn test_rdlen<R: ComposeRecordData>(data: R) {
562        let mut buf = Vec::new();
563        infallible(data.compose_rdata(&mut buf));
564        assert_eq!(buf.len(), usize::from(data.rdlen(false).unwrap()));
565        buf.clear();
566        infallible(data.compose_canonical_rdata(&mut buf));
567        assert_eq!(buf.len(), usize::from(data.rdlen(false).unwrap()));
568    }
569
570    /// Check that composing and parsing are reverse operations.
571    pub fn test_compose_parse<In, F, Out>(data: &In, parse: F)
572    where
573        In: ComposeRecordData + PartialEq<Out> + Debug,
574        F: FnOnce(&mut Parser<Bytes>) -> Result<Out, ParseError>,
575        Out: Debug,
576    {
577        let mut buf = BytesMut::new();
578        infallible(data.compose_rdata(&mut buf));
579        let buf = buf.freeze();
580        let mut parser = Parser::from_ref(&buf);
581        let parsed = (parse)(&mut parser).unwrap();
582        assert_eq!(parser.remaining(), 0);
583        assert_eq!(*data, parsed);
584    }
585
586    type TestScanner =
587        IterScanner<std::vec::IntoIter<std::string::String>, Vec<u8>>;
588
589    /// Checks scanning.
590    pub fn test_scan<F, T, X>(input: &[&str], scan: F, expected: &X)
591    where
592        F: FnOnce(
593            &mut TestScanner,
594        ) -> Result<T, <TestScanner as Scanner>::Error>,
595        T: Debug,
596        X: Debug + PartialEq<T>,
597    {
598        let mut scanner = IterScanner::new(
599            input
600                .iter()
601                .map(|s| std::string::String::from(*s))
602                .collect::<Vec<_>>(),
603        );
604        assert_eq!(*expected, scan(&mut scanner).unwrap(),);
605        assert!(scanner.is_exhausted());
606    }
607}