domain/base/
wire.rs

1//! Creating and consuming data in wire format.
2
3use super::name::ToDname;
4use super::net::{Ipv4Addr, Ipv6Addr};
5use core::fmt;
6use octseq::builder::{OctetsBuilder, Truncate};
7use octseq::parse::{Parser, ShortInput};
8
9//------------ Composer ------------------------------------------------------
10
11pub trait Composer:
12    OctetsBuilder + AsRef<[u8]> + AsMut<[u8]> + Truncate
13{
14    /// Appends a domain name using name compression if supported.
15    ///
16    /// Domain name compression attempts to lower the size of a DNS message
17    /// by avoiding to include repeated domain name suffixes. Instead of
18    /// adding the full suffix, a pointer to the location of the previous
19    /// occurence is added. Since that occurence may itself contain a
20    /// compressed suffix, doing name compression isn’t cheap and therefore
21    /// optional. However, in order to be able to opt in, we need to know
22    /// if we are dealing with a domain name that ought to be compressed.
23    ///
24    /// The trait provides a default implementation which simply appends the
25    /// name uncompressed.
26    fn append_compressed_dname<N: ToDname + ?Sized>(
27        &mut self,
28        name: &N,
29    ) -> Result<(), Self::AppendError> {
30        name.compose(self)
31    }
32
33    fn can_compress(&self) -> bool {
34        false
35    }
36}
37
38#[cfg(feature = "std")]
39impl Composer for std::vec::Vec<u8> {}
40
41impl<const N: usize> Composer for octseq::array::Array<N> {}
42
43#[cfg(feature = "bytes")]
44impl Composer for bytes::BytesMut {}
45
46#[cfg(feature = "smallvec")]
47impl<A: smallvec::Array<Item = u8>> Composer for smallvec::SmallVec<A> {}
48
49#[cfg(feature = "heapless")]
50impl<const N: usize> Composer for heapless::Vec<u8, N> {}
51
52impl<T: Composer> Composer for &mut T {
53    fn append_compressed_dname<N: ToDname + ?Sized>(
54        &mut self,
55        name: &N,
56    ) -> Result<(), Self::AppendError> {
57        Composer::append_compressed_dname(*self, name)
58    }
59
60    fn can_compress(&self) -> bool {
61        Composer::can_compress(*self)
62    }
63}
64
65//------------ Compose -------------------------------------------------------
66
67/// An extension trait to add composing to foreign types.
68///
69/// This trait can be used to add the `compose` method to a foreign type. For
70/// local types, the method should be added directly to the type instead.
71///
72/// The trait can only be used for types that have a fixed-size wire
73/// representation.
74pub trait Compose {
75    /// The length in octets of the wire representation of a value.
76    ///
77    /// Because all wire format lengths are limited to 16 bit, this is a
78    /// `u16` rather than a `usize`.
79    const COMPOSE_LEN: u16 = 0;
80
81    /// Appends the wire format representation of the value to the target.
82    fn compose<Target: OctetsBuilder + ?Sized>(
83        &self,
84        target: &mut Target,
85    ) -> Result<(), Target::AppendError>;
86}
87
88impl<'a, T: Compose + ?Sized> Compose for &'a T {
89    const COMPOSE_LEN: u16 = T::COMPOSE_LEN;
90
91    fn compose<Target: OctetsBuilder + ?Sized>(
92        &self,
93        target: &mut Target,
94    ) -> Result<(), Target::AppendError> {
95        (*self).compose(target)
96    }
97}
98
99impl Compose for i8 {
100    const COMPOSE_LEN: u16 = 1;
101
102    fn compose<Target: OctetsBuilder + ?Sized>(
103        &self,
104        target: &mut Target,
105    ) -> Result<(), Target::AppendError> {
106        target.append_slice(&[*self as u8])
107    }
108}
109
110impl Compose for u8 {
111    const COMPOSE_LEN: u16 = 1;
112
113    fn compose<Target: OctetsBuilder + ?Sized>(
114        &self,
115        target: &mut Target,
116    ) -> Result<(), Target::AppendError> {
117        target.append_slice(&[*self])
118    }
119}
120
121macro_rules! compose_to_be_bytes {
122    ( $type:ident ) => {
123        impl Compose for $type {
124            const COMPOSE_LEN: u16 = ($type::BITS >> 3) as u16;
125
126            fn compose<Target: OctetsBuilder + ?Sized>(
127                &self,
128                target: &mut Target,
129            ) -> Result<(), Target::AppendError> {
130                target.append_slice(&self.to_be_bytes())
131            }
132        }
133    };
134}
135
136compose_to_be_bytes!(i16);
137compose_to_be_bytes!(u16);
138compose_to_be_bytes!(i32);
139compose_to_be_bytes!(u32);
140compose_to_be_bytes!(i64);
141compose_to_be_bytes!(u64);
142compose_to_be_bytes!(i128);
143compose_to_be_bytes!(u128);
144
145impl Compose for Ipv4Addr {
146    const COMPOSE_LEN: u16 = 4;
147
148    fn compose<Target: OctetsBuilder + ?Sized>(
149        &self,
150        target: &mut Target,
151    ) -> Result<(), Target::AppendError> {
152        target.append_slice(&self.octets())
153    }
154}
155
156impl Compose for Ipv6Addr {
157    const COMPOSE_LEN: u16 = 16;
158
159    fn compose<Target: OctetsBuilder + ?Sized>(
160        &self,
161        target: &mut Target,
162    ) -> Result<(), Target::AppendError> {
163        target.append_slice(&self.octets())
164    }
165}
166
167// No impl for [u8; const N: usize] because we can’t guarantee a correct
168// COMPOSE_LEN -- it may be longer than a u16 can hold.
169
170//------------ Parse ------------------------------------------------------
171
172/// An extension trait to add parsing to foreign types.
173///
174/// This trait can be used to add the `parse` method to a foreign type. For
175/// local types, the method should be added directly to the type instead.
176pub trait Parse<'a, Octs: ?Sized>: Sized {
177    /// Extracts a value from the beginning of `parser`.
178    ///
179    /// If parsing fails and an error is returned, the parser’s position
180    /// should be considered to be undefined. If it is supposed to be reused
181    /// in this case, you should store the position before attempting to parse
182    /// and seek to that position again before continuing.
183    fn parse(parser: &mut Parser<'a, Octs>) -> Result<Self, ParseError>;
184}
185
186impl<'a, Octs: AsRef<[u8]> + ?Sized> Parse<'a, Octs> for i8 {
187    fn parse(parser: &mut Parser<'a, Octs>) -> Result<Self, ParseError> {
188        parser.parse_i8().map_err(Into::into)
189    }
190}
191
192impl<'a, Octs: AsRef<[u8]> + ?Sized> Parse<'a, Octs> for u8 {
193    fn parse(parser: &mut Parser<'a, Octs>) -> Result<Self, ParseError> {
194        parser.parse_u8().map_err(Into::into)
195    }
196}
197
198impl<'a, Octs: AsRef<[u8]> + ?Sized> Parse<'a, Octs> for i16 {
199    fn parse(parser: &mut Parser<'a, Octs>) -> Result<Self, ParseError> {
200        parser.parse_i16_be().map_err(Into::into)
201    }
202}
203
204impl<'a, Octs: AsRef<[u8]> + ?Sized> Parse<'a, Octs> for u16 {
205    fn parse(parser: &mut Parser<'a, Octs>) -> Result<Self, ParseError> {
206        parser.parse_u16_be().map_err(Into::into)
207    }
208}
209
210impl<'a, Octs: AsRef<[u8]> + ?Sized> Parse<'a, Octs> for i32 {
211    fn parse(parser: &mut Parser<'a, Octs>) -> Result<Self, ParseError> {
212        parser.parse_i32_be().map_err(Into::into)
213    }
214}
215
216impl<'a, Octs: AsRef<[u8]> + ?Sized> Parse<'a, Octs> for u32 {
217    fn parse(parser: &mut Parser<'a, Octs>) -> Result<Self, ParseError> {
218        parser.parse_u32_be().map_err(Into::into)
219    }
220}
221
222impl<'a, Octs: AsRef<[u8]> + ?Sized> Parse<'a, Octs> for u64 {
223    fn parse(parser: &mut Parser<'a, Octs>) -> Result<Self, ParseError> {
224        parser.parse_u64_be().map_err(Into::into)
225    }
226}
227
228impl<'a, Octs: AsRef<[u8]> + ?Sized> Parse<'a, Octs> for i64 {
229    fn parse(parser: &mut Parser<'a, Octs>) -> Result<Self, ParseError> {
230        parser.parse_i64_be().map_err(Into::into)
231    }
232}
233
234impl<'a, Octs: AsRef<[u8]> + ?Sized> Parse<'a, Octs> for Ipv4Addr {
235    fn parse(parser: &mut Parser<'a, Octs>) -> Result<Self, ParseError> {
236        Ok(Self::new(
237            u8::parse(parser)?,
238            u8::parse(parser)?,
239            u8::parse(parser)?,
240            u8::parse(parser)?,
241        ))
242    }
243}
244
245impl<'a, Octs: AsRef<[u8]> + ?Sized> Parse<'a, Octs> for Ipv6Addr {
246    fn parse(parser: &mut Parser<'a, Octs>) -> Result<Self, ParseError> {
247        let mut buf = [0u8; 16];
248        parser.parse_buf(&mut buf)?;
249        Ok(buf.into())
250    }
251}
252
253impl<'a, Octs: AsRef<[u8]> + ?Sized, const N: usize> Parse<'a, Octs>
254    for [u8; N]
255{
256    fn parse(parser: &mut Parser<'a, Octs>) -> Result<Self, ParseError> {
257        let mut res = [0u8; N];
258        parser.parse_buf(&mut res)?;
259        Ok(res)
260    }
261}
262
263//============ Helpful Function ==============================================
264
265/// Parses something from a `Vec<u8>`.
266///
267/// The actual parsing happens in the provided closure. Returns an error if
268/// the closure returns an error or if there is unparsed data left over after
269/// the closure returns. Otherwise returns whatever the closure returned.
270#[cfg(feature = "std")]
271pub fn parse_slice<F, T>(data: &[u8], op: F) -> Result<T, ParseError>
272where
273    F: FnOnce(&mut Parser<[u8]>) -> Result<T, ParseError>,
274{
275    let mut parser = Parser::from_ref(data);
276    let res = op(&mut parser)?;
277    if parser.remaining() > 0 {
278        Err(ParseError::form_error("trailing data"))
279    } else {
280        Ok(res)
281    }
282}
283
284/// Composes something into a `Vec<u8>`.
285///
286/// The actual composing happens in the provided closure.
287/// This function is mostly useful in testing so you can construct this vec
288/// directly inside an asserting.
289#[cfg(feature = "std")]
290pub fn compose_vec(
291    op: impl FnOnce(
292        &mut std::vec::Vec<u8>,
293    ) -> Result<(), core::convert::Infallible>,
294) -> std::vec::Vec<u8> {
295    let mut res = std::vec::Vec::new();
296    octseq::builder::infallible(op(&mut res));
297    res
298}
299
300//============ Error Types ===================================================
301
302//------------ ParseError ----------------------------------------------------
303
304/// An error happened while parsing data.
305#[derive(Clone, Copy, Debug, Eq, PartialEq)]
306pub enum ParseError {
307    /// An attempt was made to go beyond the end of the parser.
308    ShortInput,
309
310    /// A formatting error occurred.
311    Form(FormError),
312}
313
314impl ParseError {
315    /// Creates a new parse error as a form error with the given message.
316    #[must_use]
317    pub fn form_error(msg: &'static str) -> Self {
318        FormError::new(msg).into()
319    }
320}
321
322//--- From
323
324impl From<ShortInput> for ParseError {
325    fn from(_: ShortInput) -> Self {
326        ParseError::ShortInput
327    }
328}
329
330impl From<FormError> for ParseError {
331    fn from(err: FormError) -> Self {
332        ParseError::Form(err)
333    }
334}
335
336//--- Display and Error
337
338impl fmt::Display for ParseError {
339    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
340        match *self {
341            ParseError::ShortInput => f.write_str("unexpected end of input"),
342            ParseError::Form(ref err) => err.fmt(f),
343        }
344    }
345}
346
347#[cfg(feature = "std")]
348impl std::error::Error for ParseError {}
349
350//------------ FormError -----------------------------------------------------
351
352/// A formatting error occured.
353///
354/// This is a generic error for all kinds of error cases that result in data
355/// not being accepted. For diagnostics, the error is being given a static
356/// string describing the error.
357#[derive(Clone, Copy, Debug, Eq, PartialEq)]
358pub struct FormError(&'static str);
359
360impl FormError {
361    /// Creates a new form error value with the given diagnostics string.
362    #[must_use]
363    pub fn new(msg: &'static str) -> Self {
364        FormError(msg)
365    }
366}
367
368//--- Display and Error
369
370impl fmt::Display for FormError {
371    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
372        f.write_str(self.0)
373    }
374}
375
376#[cfg(feature = "std")]
377impl std::error::Error for FormError {}