simple_dns/dns/rdata/
macros.rs

1macro_rules! rr_wrapper {
2    (#[doc=$doc:expr] $t:ident: $w:ident = $c:literal) => {
3        #[derive(Debug, PartialEq, Eq, Hash, Clone)]
4        #[doc = $doc]
5        pub struct $t<'a>(pub $w<'a>);
6
7        impl<'a> RR for $t<'a> {
8            const TYPE_CODE: u16 = $c;
9        }
10
11        impl<'a> From<$w<'a>> for $t<'a> {
12            fn from(value: $w<'a>) -> Self {
13                $t(value)
14            }
15        }
16
17        impl<'a> $t<'a> {
18            /// Transforms the inner data into its owned type
19            pub fn into_owned<'b>(self) -> $t<'b> {
20                $t(self.0.into_owned())
21            }
22        }
23
24        impl<'a> WireFormat<'a> for $t<'a> {
25            fn parse(data: &'a [u8], position: &mut usize) -> crate::Result<Self>
26            where
27                Self: Sized,
28            {
29                $w::parse(data, position).map(|n| $t(n))
30            }
31
32            fn write_to<T: std::io::Write>(&self, out: &mut T) -> crate::Result<()> {
33                self.0.write_to(out)
34            }
35
36            fn write_compressed_to<T: std::io::Write + std::io::Seek>(
37                &'a self,
38                out: &mut T,
39                name_refs: &mut std::collections::HashMap<&'a [crate::dns::name::Label<'a>], usize>,
40            ) -> crate::Result<()> {
41                self.0.write_compressed_to(out, name_refs)
42            }
43
44            fn len(&self) -> usize {
45                self.0.len()
46            }
47        }
48
49        impl<'a> std::ops::Deref for $t<'a> {
50            type Target = $w<'a>;
51
52            fn deref(&self) -> &Self::Target {
53                &self.0
54            }
55        }
56
57        impl<'a> std::ops::DerefMut for $t<'a> {
58            fn deref_mut(&mut self) -> &mut Self::Target {
59                &mut self.0
60            }
61        }
62    };
63}
64
65macro_rules! rdata_enum {
66    ($($i:tt$(<$x:lifetime>)?,)+) => {
67        /// Represents the RData of each [`TYPE`]
68        #[derive(Debug, Eq, PartialEq, Hash, Clone)]
69        #[allow(missing_docs)]
70        pub enum RData<'a> {
71            $(
72                $i($i$(<$x>)?),
73            )+
74
75            NULL(u16, NULL<'a>),
76            Empty(TYPE)
77        }
78
79        impl<'a> WireFormat<'a> for RData<'a> {
80            fn parse(data: &'a [u8], position: &mut usize) -> crate::Result<Self>
81            where
82                Self: Sized,
83            {
84                if *position + 10 > data.len() {
85                    return Err(crate::SimpleDnsError::InsufficientData);
86                }
87
88                let rdatatype = u16::from_be_bytes(data[*position..*position + 2].try_into()?).into();
89                let rdatalen = u16::from_be_bytes(data[*position + 8..*position + 10].try_into()?) as usize;
90
91                // OPT needs to look the ttl and class values, hence position will be advanced by OPT
92                // parsing code
93                if rdatatype == TYPE::OPT {
94                    return Ok(RData::OPT(OPT::parse(&data[..*position + rdatalen + 10], position)?))
95                }
96                *position += 10;
97
98                if rdatalen == 0 {
99                    return Ok(RData::Empty(rdatatype));
100                }
101
102                if *position + rdatalen > data.len() {
103                    return Err(crate::SimpleDnsError::InsufficientData);
104                }
105
106                parse_rdata(&data[..*position + rdatalen], position, rdatatype)
107            }
108
109            fn write_to<T: std::io::Write>(
110                &self,
111                out: &mut T,
112            ) -> crate::Result<()> {
113                match &self {
114                    $(
115                        RData::$i(data) => data.write_to(out),
116                    )+
117
118                    RData::NULL(_, data) => data.write_to(out),
119                    RData::Empty(_) => { Ok(()) },
120                }
121            }
122
123            fn write_compressed_to<T: std::io::Write + std::io::Seek>(
124                &'a self,
125                out: &mut T,
126                name_refs: &mut  HashMap<&'a [crate::dns::name::Label<'a>], usize>,
127            ) -> crate::Result<()> {
128                match &self {
129                    $(
130                        RData::$i(data) => data.write_compressed_to(out, name_refs),
131                    )+
132
133                    RData::NULL(_, data) => data.write_compressed_to(out, name_refs),
134                    RData::Empty(_) => { Ok(()) },
135                }
136            }
137
138            fn len(&self) -> usize {
139                match &self {
140                    $(
141                        RData::$i(data) => data.len(),
142                    )+
143
144                    RData::NULL(_, data) => data.len(),
145                    RData::Empty(_) => 0,
146                }
147            }
148        }
149
150
151
152        impl<'a> RData<'a> {
153            /// Returns the [`TYPE`] of this RData
154            pub fn type_code(&self) -> TYPE {
155                match self {
156                    $(
157                        RData::$i(_) => TYPE::$i,
158                    )+
159
160                    RData::NULL(type_code, _) => TYPE::Unknown(*type_code),
161                    RData::Empty(ty) => *ty
162                }
163            }
164
165            /// Transforms the inner data into its owned type
166            pub fn into_owned<'b>(self) -> RData<'b> {
167                match self {
168                    $(
169                        RData::$i(data) => RData::$i(data.into_owned()),
170                    )+
171
172                    RData::NULL(rdatatype, data) => RData::NULL(rdatatype, data.into_owned()),
173                    RData::Empty(ty) => RData::Empty(ty)
174                }
175            }
176        }
177
178        fn parse_rdata<'a>(data: &'a [u8], position: &mut usize, rdatatype: TYPE) -> crate::Result<RData<'a>> {
179            let rdata = match rdatatype {
180                $(
181                    TYPE::$i => RData::$i($i::parse(data, position)?),
182                )+
183
184                TYPE::NULL => RData::NULL(rdatatype.into(), NULL::parse(data, position)?),
185                TYPE::Unknown(rdatatype) => RData::NULL(rdatatype, NULL::parse(data, position)?),
186            };
187
188            Ok(rdata)
189        }
190
191
192        /// Possible TYPE values in DNS Resource Records
193        /// Each value is described according to its own RFC
194        #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
195        #[allow(missing_docs)]
196        #[non_exhaustive]
197        pub enum TYPE {
198            $( $i,)+
199
200            NULL,
201            Unknown(u16)
202        }
203
204
205        impl From<TYPE> for u16 {
206            fn from(value: TYPE) -> Self {
207                match value {
208                    $(
209                        TYPE::$i => $i::TYPE_CODE,
210                    )+
211
212                    TYPE::NULL => NULL::TYPE_CODE,
213                    TYPE::Unknown(x) => x,
214                }
215            }
216        }
217
218        impl From<u16> for TYPE {
219            fn from(value: u16) -> Self {
220                match value {
221                    $(
222                        $i::TYPE_CODE => TYPE::$i,
223                    )+
224
225                    NULL::TYPE_CODE => TYPE::NULL,
226                    v => TYPE::Unknown(v),
227                }
228            }
229        }
230    }
231}
232
233pub(crate) use rdata_enum;
234pub(crate) use rr_wrapper;