domain_core/bits/
rdata.rs

1//! Resource record data handling.
2//!
3//! DNS resource records consist of some common data defining the domain
4//! name they pertain to, their type and class, and finally record data
5//! the format of which depends on the specific record type. As there are
6//! currently more than eighty record types, having a giant enum for record
7//! data seemed like a bad idea. Instead, resource records are generic over
8//! two traits defined by this module. All types representimg resource record
9//! data implement [`RecordData`]. Types that can be parsed out of messages
10//! also implement [`ParseRecordData`]. This distinction is only relevant for
11//! types that contain and are generic over domain names: for these, parsing
12//! is only available if the names use [`ParsedDname`].
13//!
14//! While [`RecordData`] allows types to provide different record types for
15//! different values, most types actually implement one specific record type.
16//! For these types, implementing [`RtypeRecordData`] provides a shortcut to
17//! implementin both [`RecordData`] and [`ParseRecordDate`] with a constant
18//! record type.
19//!
20//! All such implementations for a specific record type shipped with the
21//! domain crate are collected in the [`domain::rdata`] module.
22//!
23//! A type implementing the traits for any record type is available in here
24//! too: [`UnknownRecordData`]. It stores the actual record data in its
25//! encoded form in a bytes value.
26//!
27//! [`RecordData`]: trait.RecordData.html
28//! [`ParseRecordData`]: trait.ParseRecordData.html
29//! [`RtypeRecordData`]: trait.RtypeRecordData.html
30//! [`domain::rdata`]: ../../rdata/index.html
31//! [`UnknownRecordData`]: struct.UnknownRecordData.html
32
33use std::fmt;
34use bytes::{BufMut, Bytes, BytesMut};
35use failure::Fail;
36use ::iana::Rtype;
37use ::master::scan::{CharSource, Scan, Scanner, ScanError, SyntaxError};
38use super::compose::{Compose, Compress, Compressor};
39use super::parse::{ParseAll, Parser, ShortBuf};
40
41
42//----------- RecordData -----------------------------------------------------
43
44/// A type that represents record data.
45///
46/// The type needs to be able to encode the record data into a DNS message
47/// via the [`Compose`] and [`Compress`] traits. In addition, it needs to be
48/// able to provide the record type of a record with a value’s data via the
49/// [`rtype`] method.
50///
51/// [`Compose`]: ../compose/trait.Compose.html
52/// [`Compress`]: ../compose/trait.Compress.html
53/// [`rtype`]: #method.rtype
54pub trait RecordData: Compose + Compress + Sized {
55    /// Returns the record type associated with this record data instance.
56    ///
57    /// This is a method rather than an associated function to allow one
58    /// type to be used for several real record types.
59    fn rtype(&self) -> Rtype;
60}
61
62
63//------------ ParseRecordData -----------------------------------------------
64
65/// A record data type that can be parsed from a message.
66///
67/// When record data types are generic – typically over a domain name type –,
68/// they may not in all cases be parseable. They may still represent record
69/// data to be used when constructing the message.
70///
71/// To reflect this asymmetry, parsing of record data has its own trait.
72pub trait ParseRecordData: RecordData {
73    /// The type of an error returned when parsing fails.
74    type Err: Fail;
75
76    /// Parses the record data.
77    ///
78    /// The record data is for a record of type `rtype`. The function may
79    /// decide whether it wants to parse data for that type. It should return
80    /// `Ok(None)` if it doesn’t. The data is `rdlen` bytes long and starts
81    /// at the current position of `parser`. There is no guarantee that the
82    /// parser will have `rdlen` bytes left. If it doesn’t, the function
83    /// should produce an error.
84    ///
85    /// If the function doesn’t want to process the data, it must not touch
86    /// the parser. In particual, it must not advance it.
87    fn parse_data(rtype: Rtype, parser: &mut Parser, rdlen: usize)
88                  -> Result<Option<Self>, Self::Err>;
89}
90
91
92//------------ RtypeRecordData -----------------------------------------------
93
94/// A type for record data for a single specific record type.
95///
96/// If a record data type only ever processes one single record type, things
97/// can be a lot simpler. The type can be given as an associated constant
98/// which can be used to implement [`RecordData`]. In addition, parsing can
99/// be done atop an implementation of the [`ParseAll`] trait.
100///
101/// This trait provides such a simplification by providing [`RecordData`]
102/// for all types implementing it and the other requirements for
103/// [`RecordData`]. If the type additionally implements [`ParseAll`], it will
104/// also receive a [`ParseRecordData`] implementation.
105///
106/// [`RecordData`]: trait.RecordData.html
107/// [`ParseRecordData`]: trait.ParseRecordData.html
108/// [`ParseAll`]: ../parse/trait.ParseAll.html
109pub trait RtypeRecordData {
110    /// The record type of a value of this type.
111    const RTYPE: Rtype;
112}
113
114impl<T: RtypeRecordData + Compose + Compress + Sized> RecordData for T {
115    fn rtype(&self) -> Rtype { Self::RTYPE }
116}
117
118impl<T: RtypeRecordData + ParseAll + Compose + Compress + Sized>
119            ParseRecordData for T {
120    type Err = <Self as ParseAll>::Err;
121
122    fn parse_data(rtype: Rtype, parser: &mut Parser, rdlen: usize)
123                  -> Result<Option<Self>, Self::Err> {
124        if rtype == Self::RTYPE {
125            Self::parse_all(parser, rdlen).map(Some)
126        }
127        else {
128            Ok(None)
129        }
130    }
131}
132
133
134//------------ UnknownRecordData ---------------------------------------------
135
136/// A type for parsing any type of record data.
137///
138/// This type accepts any record type and stores a reference to the plain
139/// binary record data in the message.
140///
141/// Because some record types allow compressed domain names in their record
142/// data yet values only contain the data’s own bytes, this type cannot be
143/// used safely with these record types.
144///
145/// [RFC 3597] limits the types for which compressed names are allowed in the
146/// record data to those efined in [RFC 1035] itself. Specific types for all
147/// these record types exist in [`domain::rdata::rfc1035`].
148///
149/// Ultimately, you should only use this type for record types for which there
150/// is no implementation available in this crate.
151///
152/// [RFC 1035]: https://tools.ietf.org/html/rfc1035
153/// [RFC 3597]: https://tools.ietf.org/html/rfc3597
154/// [`domain::rdata::rfc1035]: ../../rdata/rfc1035/index.html
155#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
156pub struct UnknownRecordData {
157    /// The record type of this data.
158    rtype: Rtype,
159
160    /// The record data.
161    data: Bytes,
162}
163
164impl UnknownRecordData {
165    /// Creates generic record data from a bytes value contain the data.
166    pub fn from_bytes(rtype: Rtype, data: Bytes) -> Self {
167        UnknownRecordData { rtype, data }
168    }
169
170    /// Returns the record type this data is for.
171    pub fn rtype(&self) -> Rtype {
172        self.rtype
173    }
174
175    /// Returns a reference to the record data.
176    pub fn data(&self) -> &Bytes {
177        &self.data
178    }
179
180    /// Scans the record data.
181    ///
182    /// This isn’t implemented via `Scan`, because we need the record type.
183    pub fn scan<C: CharSource>(rtype: Rtype, scanner: &mut Scanner<C>)
184                               -> Result<Self, ScanError> {
185        scanner.skip_literal("\\#")?;
186        let mut len = u16::scan(scanner)? as usize;
187        let mut res = BytesMut::with_capacity(len);
188        while len > 0 {
189            len = scanner.scan_word(
190                (&mut res, len, None), // buffer and optional first char
191                |&mut (ref mut res, ref mut len, ref mut first), symbol| {
192                    if *len == 0 {
193                        return Err(SyntaxError::LongGenericData)
194                    }
195                    let ch = symbol.into_digit(16)? as u8;
196                    if let Some(ch1) = *first {
197                        res.put_u8(ch1 << 4 | ch);
198                        *len -= 1;
199                    }
200                    else {
201                        *first = Some(ch)
202                    }
203                    Ok(())
204                },
205                |(_, len, first)| {
206                    if first.is_some() {
207                        Err(SyntaxError::UnevenHexString)
208                    }
209                    else {
210                        Ok(len)
211                    }
212                }
213            )?
214        }
215        Ok(UnknownRecordData::from_bytes(rtype, res.freeze()))
216    }
217}
218
219
220//--- Compose, and Compress
221
222impl Compose for UnknownRecordData {
223    fn compose_len(&self) -> usize {
224        self.data.len()
225    }
226
227    fn compose<B: BufMut>(&self, buf: &mut B) {
228        buf.put_slice(self.data.as_ref())
229    }
230}
231
232impl Compress for UnknownRecordData {
233    fn compress(&self, buf: &mut Compressor) -> Result<(), ShortBuf> {
234        buf.compose(self)
235    }
236}
237
238
239//--- RecordData and ParseRecordData
240
241impl RecordData for UnknownRecordData {
242    fn rtype(&self) -> Rtype {
243        self.rtype
244    }
245}
246
247impl ParseRecordData for UnknownRecordData {
248    type Err = ShortBuf;
249
250    fn parse_data(rtype: Rtype, parser: &mut Parser, rdlen: usize)
251                  -> Result<Option<Self>, Self::Err> {
252        parser.parse_bytes(rdlen)
253              .map(|data| Some(Self::from_bytes(rtype, data)))
254    }
255}
256
257
258//--- Display
259
260impl fmt::Display for UnknownRecordData {
261    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
262        write!(f, "\\# {}", self.data.len())?;
263        for ch in self.data.as_ref() {
264            write!(f, " {:02x}", *ch)?
265        }
266        Ok(())
267    }
268}
269