adns_proto/
record.rs

1use std::fmt;
2
3use crate::{
4    context::{DeserializeContext, SerializeContext},
5    Name, PacketParseError, Type, TypeData,
6};
7
8#[derive(Clone, Debug)]
9#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
10pub struct Record {
11    #[serde(rename = "domain")]
12    pub name: Name,
13    #[serde(rename = "type")]
14    pub type_: Type,
15    pub class: Class,
16    pub ttl: u32,
17    pub data: TypeData,
18}
19
20impl fmt::Display for Record {
21    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
22        write!(f, "{} {} {} {}", self.name, self.type_, self.ttl, self.data)
23    }
24}
25
26impl Record {
27    pub fn new(name: impl AsRef<str>, ttl: u32, data: TypeData) -> Self {
28        Self {
29            name: name.as_ref().parse().unwrap(),
30            type_: data.dns_type(),
31            class: Class::IN,
32            ttl,
33            data,
34        }
35    }
36
37    pub(crate) fn parse(context: &mut DeserializeContext<'_>) -> Result<Self, PacketParseError> {
38        let name = context.read_name()?;
39        let type_ = context.read(u16::from_be_bytes)?.into();
40        Ok(Self {
41            name,
42            type_,
43            class: context.read(u16::from_be_bytes)?.into(),
44            ttl: context.read(u32::from_be_bytes)?,
45            data: {
46                let length = context.read(u16::from_be_bytes)?;
47                context.restrict(length as usize, |context| {
48                    Ok(TypeData::parse_infallible(context, type_))
49                })?
50            },
51        })
52    }
53
54    pub(crate) fn serialize(&self, context: &mut SerializeContext) {
55        context.write_name(&self.name);
56        context.write_blob(<Type as Into<u16>>::into(self.type_).to_be_bytes());
57        context.write_blob(<Class as Into<u16>>::into(self.class).to_be_bytes());
58        context.write_blob(self.ttl.to_be_bytes());
59        context.capture_len_u16(|context| {
60            self.data.serialize(context);
61        });
62    }
63}
64
65#[derive(Clone, Copy, PartialEq, Eq, Debug, Default, strum::IntoStaticStr)]
66#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
67#[repr(u16)]
68pub enum Class {
69    #[default]
70    IN = 1,
71    // CS,
72    // CH,
73    // HS,
74    NONE = 254,
75    ALL = 255,
76    Other(u16),
77}
78
79impl fmt::Display for Class {
80    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
81        match self {
82            Class::IN => write!(f, "IN"),
83            Class::NONE => write!(f, "NONE"),
84            Class::ALL => write!(f, "ALL"),
85            Class::Other(class) => write!(f, "CLASS{class:03}"),
86        }
87    }
88}
89
90impl From<u16> for Class {
91    fn from(value: u16) -> Self {
92        match value {
93            1 => Class::IN,
94            254 => Class::NONE,
95            255 => Class::ALL,
96            _ => Class::Other(value),
97        }
98    }
99}
100
101impl From<Class> for u16 {
102    fn from(value: Class) -> Self {
103        match value {
104            Class::IN => 1,
105            Class::NONE => 254,
106            Class::ALL => 255,
107            Class::Other(x) => x,
108        }
109    }
110}