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