nonymous/view/
rdata.rs

1use core::ops::Range;
2
3use byteorder::{ByteOrder, NetworkEndian};
4
5use super::{assert, BoundsError, CharacterString, CharacterStrings, Name, NameError, View};
6use crate::zone::Format;
7
8macro_rules! declare_rdata {
9    ($($ty:ident,)*) => {
10        #[non_exhaustive]
11        pub enum Rdata<'s> {
12            $($ty($ty<'s>),)*
13        }
14        $(impl<'s> From<$ty<'s>> for Rdata<'s> {
15            fn from(inner: $ty<'s>) -> Self {
16                Self::$ty(inner)
17            }
18        })*
19        impl<'s> AsRef<dyn View<'s, Error = RdataError>> for Rdata<'s> {
20            fn as_ref(&self) -> &dyn View<'s, Error = RdataError> {
21                match self {
22                    $(Self::$ty(x) => x,)*
23                }
24            }
25        }
26        impl<'s> AsRef<dyn Format + 's> for Rdata<'s> {
27            fn as_ref(&self) -> &(dyn Format + 's) {
28                match self {
29                    $(Self::$ty(x) => x,)*
30                }
31            }
32        }
33    };
34}
35
36declare_rdata! {
37    Malformed,
38    Unknown,
39    Soa,
40    Mx,
41    Txt,
42    Caa,
43    CompressibleName,
44    InAddress,
45    InAaaa,
46}
47
48pub struct Soa<'s> {
49    pub source: &'s [u8],
50    pub offset: usize,
51    pub mname_len: usize,
52    pub rname_len: usize,
53}
54
55pub struct Mx<'s> {
56    pub source: &'s [u8],
57    pub offset: usize,
58    pub exchange_len: usize,
59}
60
61pub struct Txt<'s> {
62    pub source: &'s [u8],
63    pub offset: usize,
64    pub len: usize,
65}
66
67pub struct Caa<'s> {
68    pub source: &'s [u8],
69    pub offset: usize,
70    pub tag_len: usize,
71    pub value_len: usize,
72}
73
74pub struct CaaTag<'s> {
75    pub source: &'s [u8],
76    pub offset: usize,
77    pub len: usize,
78}
79
80pub struct CaaValue<'s> {
81    pub source: &'s [u8],
82    pub offset: usize,
83    pub len: usize,
84}
85
86pub struct CompressibleName<'s> {
87    pub name: Name<'s>,
88}
89
90pub struct InAddress<'s> {
91    pub source: &'s [u8],
92    pub offset: usize,
93}
94
95pub struct InAaaa<'s> {
96    pub source: &'s [u8],
97    pub offset: usize,
98}
99
100pub struct Malformed<'s> {
101    pub inner: Unknown<'s>,
102}
103
104pub struct Unknown<'s> {
105    pub source: &'s [u8],
106    pub offset: usize,
107    pub len: usize,
108}
109
110error!(RdataError(s(s.as_ref()), __));
111#[derive(Debug, displaydoc::Display)]
112/// failed to view RDATA ({1})
113pub struct RdataError(RdataError0, &'static str);
114
115#[cfg(feature = "std")]
116pub type RdataError0 = eyre::Error;
117#[cfg(not(feature = "std"))]
118pub type RdataError0 = ();
119
120error!(SoaError, Bounds, Name);
121/// failed to view SOA RDATA
122#[derive(Debug, displaydoc::Display)]
123#[prefix_enum_doc_attributes]
124pub enum SoaError {
125    /// eof while viewing SERIAL or REFRESH or RETRY or EXPIRE or MINIMUM
126    Bounds(BoundsError),
127
128    /// SOA RDATA has malformed MNAME or RNAME
129    Name(NameError),
130}
131
132impl RdataError {
133    #[cfg(feature = "std")]
134    fn new<E: 'static + Send + Sync + std::error::Error>(error: E, ty: &'static str) -> Self {
135        Self(error.into(), ty)
136    }
137    #[cfg(not(feature = "std"))]
138    fn new<E: 'static + Send + Sync>(_: E, ty: &'static str) -> Self {
139        Self((), ty)
140    }
141}
142
143trait RdataResultExt<T> {
144    fn into_rdata_error<V>(self) -> Result<T, RdataError>;
145}
146
147#[cfg(feature = "std")]
148impl<T, E: 'static + Send + Sync + std::error::Error> RdataResultExt<T> for Result<T, E> {
149    fn into_rdata_error<V>(self) -> Result<T, RdataError> {
150        self.map_err(|e| RdataError::new(e, core::any::type_name::<V>()))
151    }
152}
153#[cfg(not(feature = "std"))]
154impl<T, E: 'static + Send + Sync> RdataResultExt<T> for Result<T, E> {
155    fn into_rdata_error<V>(self) -> Result<T, RdataError> {
156        self.map_err(|e| RdataError::new(e, core::any::type_name::<V>()))
157    }
158}
159
160impl Soa<'_> {
161    pub fn mname(&self) -> Name {
162        Name {
163            source: self.source,
164            offset: self.offset,
165            len: self.mname_len,
166        }
167    }
168
169    pub fn rname(&self) -> Name {
170        Name {
171            source: self.source,
172            offset: self.offset + self.mname_len,
173            len: self.rname_len,
174        }
175    }
176
177    pub fn serial(&self) -> u32 {
178        let offset = self.mname_len + self.rname_len;
179
180        NetworkEndian::read_u32(&self.source[self.offset..][offset..])
181    }
182
183    pub fn refresh(&self) -> u32 {
184        let offset = self.mname_len + self.rname_len + 4;
185
186        NetworkEndian::read_u32(&self.source[self.offset..][offset..])
187    }
188
189    pub fn retry(&self) -> u32 {
190        let offset = self.mname_len + self.rname_len + 8;
191
192        NetworkEndian::read_u32(&self.source[self.offset..][offset..])
193    }
194
195    pub fn expire(&self) -> u32 {
196        let offset = self.mname_len + self.rname_len + 12;
197
198        NetworkEndian::read_u32(&self.source[self.offset..][offset..])
199    }
200
201    pub fn minimum(&self) -> u32 {
202        let offset = self.mname_len + self.rname_len + 16;
203
204        NetworkEndian::read_u32(&self.source[self.offset..][offset..])
205    }
206}
207
208impl Mx<'_> {
209    pub fn preference(&self) -> u16 {
210        NetworkEndian::read_u16(&self.source[self.offset..])
211    }
212
213    pub fn exchange(&self) -> Name {
214        Name {
215            source: self.source,
216            offset: self.offset + 2,
217            len: self.exchange_len,
218        }
219    }
220}
221
222impl Txt<'_> {
223    pub fn data(&self) -> CharacterStrings<'_> {
224        let start = self.offset;
225        let stop = self.offset + self.len;
226
227        CharacterStrings::new(self.source, start..stop)
228    }
229}
230
231impl Caa<'_> {
232    pub fn flags(&self) -> u8 {
233        self.source[self.offset]
234    }
235
236    pub fn critical(&self) -> bool {
237        self.flags() >> 7 & 1 == 1
238    }
239
240    pub fn tag(&self) -> CaaTag {
241        CaaTag {
242            source: self.source,
243            offset: self.offset + 2,
244            len: self.tag_len,
245        }
246    }
247
248    pub fn value(&self) -> CaaValue {
249        CaaValue {
250            source: self.source,
251            offset: self.offset + 2 + self.tag_len,
252            len: self.value_len,
253        }
254    }
255}
256
257impl<'s> View<'s> for Soa<'s> {
258    type Error = RdataError;
259
260    fn view(source: &'s [u8], range: Range<usize>) -> super::Result<Self, Self::Error> {
261        let (_, rest) = Name::view(source, range.clone())
262            .map_err(SoaError::Name)
263            .into_rdata_error::<Self>()?;
264        let mname_len = rest.start - range.start;
265
266        let (_, mut rest) = Name::view(source, rest)
267            .map_err(SoaError::Name)
268            .into_rdata_error::<Self>()?;
269        let rname_len = rest.start - range.start - mname_len;
270
271        assert(source, &rest, 20)
272            .map_err(SoaError::Bounds)
273            .into_rdata_error::<Self>()?;
274        rest.start += 20;
275
276        Ok((
277            Soa {
278                source,
279                offset: range.start,
280                mname_len,
281                rname_len,
282            },
283            rest,
284        ))
285    }
286
287    fn len(&self) -> usize {
288        self.mname_len + self.rname_len + 20
289    }
290}
291
292impl<'s> View<'s> for Mx<'s> {
293    type Error = RdataError;
294
295    fn view(source: &'s [u8], range: Range<usize>) -> super::Result<Self, Self::Error> {
296        let mut rest = range.clone();
297
298        assert(source, &rest, 2).into_rdata_error::<Self>()?;
299        rest.start += 2;
300
301        let (_, rest) = Name::view(source, rest)
302            .map_err(SoaError::Name)
303            .into_rdata_error::<Self>()?;
304        let exchange_len = rest.start - range.start - 2;
305
306        Ok((
307            Mx {
308                source,
309                offset: range.start,
310                exchange_len,
311            },
312            rest,
313        ))
314    }
315
316    fn len(&self) -> usize {
317        2 + self.exchange_len
318    }
319}
320
321impl<'s> View<'s> for Txt<'s> {
322    type Error = RdataError;
323
324    fn view(source: &'s [u8], range: Range<usize>) -> super::Result<Self, Self::Error> {
325        let mut next = range.clone();
326
327        while next.start != next.end {
328            let (_, rest) = CharacterString::view(source, next).into_rdata_error::<Self>()?;
329            next = rest;
330        }
331
332        let offset = range.start;
333        let len = next.start - offset;
334
335        Ok((
336            Txt {
337                source,
338                offset,
339                len,
340            },
341            next,
342        ))
343    }
344
345    fn len(&self) -> usize {
346        self.len
347    }
348}
349
350impl<'s> View<'s> for Caa<'s> {
351    type Error = RdataError;
352
353    fn view(source: &'s [u8], range: Range<usize>) -> super::Result<Self, Self::Error> {
354        let mut rest = range.clone();
355
356        assert(source, &rest, 1).into_rdata_error::<Self>()?;
357        rest.start += 1;
358
359        let (octet, mut rest) = u8::view(source, rest).into_rdata_error::<Self>()?;
360        let tag_len: usize = octet.into();
361
362        assert(source, &rest, tag_len).into_rdata_error::<Self>()?;
363        rest.start += tag_len;
364
365        // value implicitly consumes the rest of the RDATA
366        let value_len = rest.end - rest.start;
367        rest.start += value_len;
368
369        Ok((
370            Caa {
371                source,
372                offset: range.start,
373                tag_len,
374                value_len,
375            },
376            rest,
377        ))
378    }
379
380    fn len(&self) -> usize {
381        1 + 1 + self.tag_len + self.value_len
382    }
383}
384
385impl<'s> View<'s> for CompressibleName<'s> {
386    type Error = RdataError;
387
388    fn view(source: &'s [u8], range: Range<usize>) -> super::Result<Self, Self::Error> {
389        let (name, rest) = Name::view(source, range).into_rdata_error::<Self>()?;
390
391        Ok((Self { name }, rest))
392    }
393
394    fn len(&self) -> usize {
395        self.name.len()
396    }
397}
398
399impl<'s> View<'s> for InAddress<'s> {
400    type Error = RdataError;
401
402    fn view(source: &'s [u8], mut range: Range<usize>) -> super::Result<Self, Self::Error> {
403        let offset = range.start;
404
405        assert(source, &range, 4).into_rdata_error::<Self>()?;
406        range.start += 4;
407
408        Ok((InAddress { source, offset }, range))
409    }
410
411    fn len(&self) -> usize {
412        4
413    }
414}
415
416impl<'s> View<'s> for InAaaa<'s> {
417    type Error = RdataError;
418
419    fn view(source: &'s [u8], mut range: Range<usize>) -> super::Result<Self, Self::Error> {
420        let offset = range.start;
421
422        assert(source, &range, 16).into_rdata_error::<Self>()?;
423        range.start += 16;
424
425        Ok((InAaaa { source, offset }, range))
426    }
427
428    fn len(&self) -> usize {
429        16
430    }
431}
432
433impl<'s> View<'s> for Malformed<'s> {
434    type Error = RdataError;
435
436    fn view(source: &'s [u8], range: Range<usize>) -> super::Result<Self, Self::Error> {
437        let (inner, range) = Unknown::view(source, range)?;
438
439        Ok((Malformed { inner }, range))
440    }
441
442    fn len(&self) -> usize {
443        self.inner.len()
444    }
445}
446
447impl<'s> View<'s> for Unknown<'s> {
448    type Error = RdataError;
449
450    fn view(source: &'s [u8], mut range: Range<usize>) -> super::Result<Self, Self::Error> {
451        let offset = range.start;
452        let len = range.end - offset;
453
454        assert(source, &range, len).into_rdata_error::<Self>()?;
455        range.start += len;
456
457        Ok((
458            Unknown {
459                source,
460                offset,
461                len,
462            },
463            range,
464        ))
465    }
466
467    fn len(&self) -> usize {
468        self.len
469    }
470}