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, 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}