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