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