adns_proto/types/
data.rs

1use std::net::{Ipv4Addr, Ipv6Addr};
2
3use smallvec::{smallvec, SmallVec};
4
5use crate::{
6    context::{DeserializeContext, SerializeContext},
7    Name, PacketParseError, Type,
8};
9
10#[derive(Clone, PartialEq, Eq, Debug, PartialOrd, Ord)]
11#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
12pub enum TypeData {
13    A(Ipv4Addr),
14    NS(Name),
15    CNAME(Name),
16    SOA(SoaData),
17    PTR(Name),
18    HINFO {
19        cpu: String,
20        os: String,
21    },
22    MX {
23        preference: u16,
24        exchange: Name,
25    },
26    TXT(SmallVec<[String; 1]>),
27
28    AAAA(Ipv6Addr),
29    LOC {
30        version: u8,
31        size: u8,
32        horiz_pre: u8,
33        vert_pre: u8,
34        latitude: i32,
35        longitude: i32,
36        altitude: i32,
37    },
38
39    SRV {
40        priority: u16,
41        weight: u16,
42        port: u16,
43        target: Name,
44    },
45
46    CERT {
47        type_: u16,
48        key_tag: u16,
49        algorithm: u8,
50        data: Vec<u8>,
51    },
52
53    DNAME(Name),
54
55    SSHFP {
56        algorithm: u8,
57        fp_type: u8,
58        fingerprint: Vec<u8>,
59    },
60
61    TSIG(TsigData),
62
63    URI {
64        priority: u16,
65        weight: u16,
66        target: String,
67    },
68
69    Other(Type, SmallVec<[u8; 32]>),
70}
71
72#[derive(Clone, PartialEq, Eq, Debug, PartialOrd, Ord)]
73#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
74pub struct SoaData {
75    pub mname: Name,
76    pub rname: Name,
77    pub serial: u32,
78    pub refresh: u32,
79    pub retry: u32,
80    pub expire: u32,
81    pub minimum: u32,
82}
83
84#[derive(Clone, PartialEq, Eq, Debug, PartialOrd, Ord)]
85#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
86pub struct TsigData {
87    pub algorithm: Name,
88    pub time_signed: u64, // only a u48
89    pub fudge: u16,
90    pub mac: Vec<u8>,
91    pub original_id: u16,
92    pub error: TsigResponseCode,
93    pub other_data: Vec<u8>,
94}
95
96#[derive(Default, Clone, Copy, PartialEq, Eq, Debug, PartialOrd, Ord)]
97#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
98#[repr(u8)]
99pub enum TsigResponseCode {
100    #[default]
101    NoError,
102    BadSig,
103    BadKey,
104    BadTime,
105    Other(u16),
106}
107
108impl From<u16> for TsigResponseCode {
109    fn from(value: u16) -> Self {
110        match value {
111            0 => TsigResponseCode::NoError,
112            16 => TsigResponseCode::BadSig,
113            17 => TsigResponseCode::BadKey,
114            18 => TsigResponseCode::BadTime,
115            _ => TsigResponseCode::Other(value),
116        }
117    }
118}
119
120impl From<TsigResponseCode> for u16 {
121    fn from(value: TsigResponseCode) -> Self {
122        match value {
123            TsigResponseCode::NoError => 0,
124            TsigResponseCode::BadSig => 16,
125            TsigResponseCode::BadKey => 17,
126            TsigResponseCode::BadTime => 18,
127            TsigResponseCode::Other(x) => x,
128        }
129    }
130}
131
132impl TypeData {
133    pub fn dns_type(&self) -> Type {
134        match self {
135            TypeData::A(..) => Type::A,
136            TypeData::NS(..) => Type::NS,
137            TypeData::CNAME(..) => Type::CNAME,
138            TypeData::SOA { .. } => Type::SOA,
139            TypeData::PTR(..) => Type::PTR,
140            TypeData::HINFO { .. } => Type::HINFO,
141            TypeData::MX { .. } => Type::MX,
142            TypeData::TXT(..) => Type::TXT,
143            TypeData::AAAA(..) => Type::AAAA,
144            TypeData::LOC { .. } => Type::LOC,
145            TypeData::SRV { .. } => Type::SRV,
146            TypeData::CERT { .. } => Type::CERT,
147            TypeData::DNAME(..) => Type::DNAME,
148            TypeData::SSHFP { .. } => Type::SSHFP,
149            TypeData::TSIG { .. } => Type::TSIG,
150            TypeData::URI { .. } => Type::URI,
151            TypeData::Other(type_, ..) => *type_,
152        }
153    }
154
155    pub(crate) fn serialize(&self, context: &mut SerializeContext) {
156        match self {
157            TypeData::A(x) => context.write_blob(x.octets()),
158            TypeData::DNAME(x) | TypeData::NS(x) | TypeData::CNAME(x) | TypeData::PTR(x) => {
159                context.write_name(x)
160            }
161            TypeData::SOA(SoaData {
162                mname,
163                rname,
164                serial,
165                refresh,
166                retry,
167                expire,
168                minimum,
169            }) => {
170                context.write_name(mname);
171                context.write_name(rname);
172                context.write_blob(serial.to_be_bytes());
173                context.write_blob(refresh.to_be_bytes());
174                context.write_blob(retry.to_be_bytes());
175                context.write_blob(expire.to_be_bytes());
176                context.write_blob(minimum.to_be_bytes());
177            }
178            TypeData::HINFO { cpu, os } => {
179                context.write_cstring(cpu);
180                context.write_cstring(os);
181            }
182            TypeData::MX {
183                preference,
184                exchange,
185            } => {
186                context.write_blob(preference.to_be_bytes());
187                context.write_name(exchange);
188            }
189            TypeData::TXT(texts) => {
190                for text in texts {
191                    context.write_cstring(text);
192                }
193            }
194            TypeData::AAAA(x) => context.write_blob(x.octets()),
195            TypeData::LOC {
196                version,
197                size,
198                horiz_pre,
199                vert_pre,
200                latitude,
201                longitude,
202                altitude,
203            } => {
204                context.write_blob(version.to_be_bytes());
205                context.write_blob(size.to_be_bytes());
206                context.write_blob(horiz_pre.to_be_bytes());
207                context.write_blob(vert_pre.to_be_bytes());
208                context.write_blob(latitude.to_be_bytes());
209                context.write_blob(longitude.to_be_bytes());
210                context.write_blob(altitude.to_be_bytes());
211            }
212            TypeData::SRV {
213                priority,
214                weight,
215                port,
216                target,
217            } => {
218                context.write_blob(priority.to_be_bytes());
219                context.write_blob(weight.to_be_bytes());
220                context.write_blob(port.to_be_bytes());
221                context.write_name(target);
222            }
223            TypeData::CERT {
224                type_,
225                key_tag,
226                algorithm,
227                data,
228            } => {
229                context.write_blob(type_.to_be_bytes());
230                context.write_blob(key_tag.to_be_bytes());
231                context.write_blob(algorithm.to_be_bytes());
232                context.write_blob(data);
233            }
234            TypeData::SSHFP {
235                algorithm,
236                fp_type,
237                fingerprint,
238            } => {
239                context.write_blob(algorithm.to_be_bytes());
240                context.write_blob(fp_type.to_be_bytes());
241                context.write_blob(fingerprint);
242            }
243            TypeData::TSIG(TsigData {
244                algorithm,
245                time_signed,
246                fudge,
247                mac,
248                original_id,
249                error,
250                other_data,
251            }) => {
252                context.write_name(algorithm);
253                context.write_blob(&time_signed.to_be_bytes()[2..8]);
254                context.write_blob(fudge.to_be_bytes());
255                context.write_blob((mac.len() as u16).to_be_bytes());
256                context.write_blob(mac);
257                context.write_blob(original_id.to_be_bytes());
258                context.write_blob(<TsigResponseCode as Into<u16>>::into(*error).to_be_bytes());
259                context.write_blob((other_data.len() as u16).to_be_bytes());
260                context.write_blob(other_data);
261            }
262            TypeData::URI {
263                priority,
264                weight,
265                target,
266            } => {
267                context.write_blob(priority.to_be_bytes());
268                context.write_blob(weight.to_be_bytes());
269                context.write_blob(target);
270            }
271            TypeData::Other(_, x) => context.write_blob(x),
272        }
273    }
274
275    pub(crate) fn parse_infallible(context: &mut DeserializeContext<'_>, type_: Type) -> Self {
276        context
277            .attempt(|context| Self::parse(context, type_).ok())
278            .unwrap_or_else(|| Self::Other(type_, Default::default()))
279    }
280
281    pub(crate) fn parse(
282        context: &mut DeserializeContext<'_>,
283        type_: Type,
284    ) -> Result<Self, PacketParseError> {
285        Ok(match type_ {
286            Type::A => TypeData::A(context.read(<Ipv4Addr as From<[u8; 4]>>::from)?),
287            Type::NS => TypeData::NS(context.read_name()?),
288            Type::CNAME => TypeData::CNAME(context.read_name()?),
289            Type::SOA => TypeData::SOA(SoaData {
290                mname: context.read_name()?,
291                rname: context.read_name()?,
292                serial: context.read(u32::from_be_bytes)?,
293                refresh: context.read(u32::from_be_bytes)?,
294                retry: context.read(u32::from_be_bytes)?,
295                expire: context.read(u32::from_be_bytes)?,
296                minimum: context.read(u32::from_be_bytes)?,
297            }),
298            Type::PTR => TypeData::PTR(context.read_name()?),
299            Type::HINFO => TypeData::HINFO {
300                cpu: context.read_cstring()?,
301                os: context.read_cstring()?,
302            },
303            Type::MX => TypeData::MX {
304                preference: context.read(u16::from_be_bytes)?,
305                exchange: context.read_name()?,
306            },
307            Type::TXT => {
308                let mut out = smallvec![];
309                while context.remaining() > 0 {
310                    out.push(context.read_cstring()?);
311                }
312                TypeData::TXT(out)
313            }
314            Type::AAAA => TypeData::AAAA(context.read(<Ipv6Addr as From<[u8; 16]>>::from)?),
315            Type::LOC => TypeData::LOC {
316                version: context.read_u8()?,
317                size: context.read_u8()?,
318                horiz_pre: context.read_u8()?,
319                vert_pre: context.read_u8()?,
320                latitude: context.read(i32::from_be_bytes)?,
321                longitude: context.read(i32::from_be_bytes)?,
322                altitude: context.read(i32::from_be_bytes)?,
323            },
324            Type::SRV => TypeData::SRV {
325                priority: context.read(u16::from_be_bytes)?,
326                weight: context.read(u16::from_be_bytes)?,
327                port: context.read(u16::from_be_bytes)?,
328                target: context.read_name()?,
329            },
330            Type::CERT => TypeData::CERT {
331                type_: context.read(u16::from_be_bytes)?,
332                key_tag: context.read(u16::from_be_bytes)?,
333                algorithm: context.read_u8()?,
334                data: {
335                    let mut out = vec![0u8; context.remaining()];
336                    context.read_all(&mut out)?;
337                    out
338                },
339            },
340            Type::DNAME => TypeData::DNAME(context.read_name()?),
341            Type::SSHFP => TypeData::SSHFP {
342                algorithm: context.read_u8()?,
343                fp_type: context.read_u8()?,
344                fingerprint: {
345                    let mut out = vec![0u8; context.remaining()];
346                    context.read_all(&mut out)?;
347                    out
348                },
349            },
350            Type::TSIG => TypeData::TSIG(TsigData {
351                algorithm: context.read_name()?,
352                time_signed: {
353                    let [a, b, c, d, e, f] = context.read_n::<6>()?;
354                    u64::from_be_bytes([0, 0, a, b, c, d, e, f])
355                },
356                fudge: context.read(u16::from_be_bytes)?,
357                mac: {
358                    let len = context.read(u16::from_be_bytes)?;
359                    let mut out = vec![0u8; len as usize];
360                    context.read_all(&mut out)?;
361                    out
362                },
363                original_id: context.read(u16::from_be_bytes)?,
364                error: context.read(u16::from_be_bytes)?.into(),
365                other_data: {
366                    if context.remaining() == 0 {
367                        vec![]
368                    } else {
369                        let len = context.read(u16::from_be_bytes)?;
370                        let mut out = vec![0u8; len as usize];
371                        context.read_all(&mut out)?;
372                        out
373                    }
374                },
375            }),
376            Type::URI => TypeData::URI {
377                priority: context.read(u16::from_be_bytes)?,
378                weight: context.read(u16::from_be_bytes)?,
379                target: {
380                    let mut out = vec![0u8; context.remaining()];
381                    context.read_all(&mut out)?;
382                    String::from_utf8(out).map_err(|e| e.utf8_error())?
383                },
384            },
385            type_ => {
386                let mut all = smallvec![0u8; context.remaining()];
387                context.read_all(&mut all)?;
388                TypeData::Other(type_, all)
389            }
390        })
391    }
392}