1#[derive(Debug, Clone, Copy, PartialEq, Eq)]
3#[cfg_attr(feature = "defmt", derive(defmt::Format))]
4pub(crate) enum Qr {
5 Query,
6 Response,
7}
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15#[cfg_attr(feature = "defmt", derive(defmt::Format))]
16#[repr(u8)]
17pub enum ResponseCode {
18 NoError = 0,
22 FormatError = 1,
26 ServerFailure = 2,
31 NameError = 3,
37 NotImplemented = 4,
41 Refused = 5,
49}
50
51impl TryFrom<u8> for ResponseCode {
52 type Error = u8;
53
54 fn try_from(value: u8) -> Result<Self, Self::Error> {
55 match value {
56 x if x == ResponseCode::NoError as u8 => Ok(ResponseCode::NoError),
57 x if x == ResponseCode::FormatError as u8 => Ok(ResponseCode::FormatError),
58 x if x == ResponseCode::ServerFailure as u8 => Ok(ResponseCode::ServerFailure),
59 x if x == ResponseCode::NameError as u8 => Ok(ResponseCode::NameError),
60 x if x == ResponseCode::NotImplemented as u8 => Ok(ResponseCode::NotImplemented),
61 x if x == ResponseCode::Refused as u8 => Ok(ResponseCode::Refused),
62 x => Err(x),
63 }
64 }
65}
66
67#[derive(Debug)]
73#[cfg_attr(feature = "defmt", derive(defmt::Format))]
74pub(crate) struct Header {
75 buf: [u8; Self::LEN_USIZE],
76}
77
78impl Header {
79 pub(crate) const LEN: u16 = 12;
80 pub(crate) const LEN_USIZE: usize = Self::LEN as usize;
81
82 pub(crate) fn new_query(id: u16) -> Self {
83 Self {
84 buf: Default::default(),
85 }
86 .set_id(id)
87 .set_qr(Qr::Query)
88 .set_rd(true)
89 }
90
91 #[inline]
92 pub(crate) fn new_buf() -> [u8; Self::LEN_USIZE] {
93 [0; Self::LEN_USIZE]
94 }
95
96 #[must_use]
98 pub(crate) fn id(&self) -> u16 {
99 u16::from_be_bytes(self.buf[..2].try_into().unwrap())
100 }
101
102 #[must_use = "set_id returns a modified Header"]
104 pub(crate) fn set_id(mut self, id: u16) -> Self {
105 self.buf[..2].copy_from_slice(id.to_be_bytes().as_slice());
106 self
107 }
108
109 #[must_use]
110 pub(crate) const fn qr(&self) -> Qr {
111 if self.buf[2] & 0x80 == 0x00 {
112 Qr::Query
113 } else {
114 Qr::Response
115 }
116 }
117
118 #[must_use]
119 pub(crate) const fn set_qr(mut self, qr: Qr) -> Self {
120 match qr {
121 Qr::Query => self.buf[2] &= !0x80,
122 Qr::Response => self.buf[2] |= 0x80,
123 };
124 self
125 }
126
127 #[must_use]
128 pub(crate) fn set_rd(mut self, rd: bool) -> Self {
129 if rd {
130 self.buf[2] |= 0x01;
131 } else {
132 self.buf[2] &= !0x1;
133 };
134 self
135 }
136
137 pub(crate) fn rcode(&self) -> Result<ResponseCode, u8> {
138 ResponseCode::try_from(self.buf[3] & 0xF)
139 }
140
141 #[must_use]
142 pub(crate) fn qdcount(&self) -> u16 {
143 u16::from_be_bytes(self.buf[4..6].try_into().unwrap())
144 }
145
146 pub(crate) fn set_qdcount(&mut self, qdcount: u16) {
147 self.buf[4..6].copy_from_slice(qdcount.to_be_bytes().as_slice());
148 }
149
150 pub(crate) fn increment_qdcount(&mut self) {
151 let qdcount: u16 = self.qdcount().saturating_add(1);
152 self.set_qdcount(qdcount)
153 }
154
155 #[must_use]
156 pub(crate) fn ancount(&self) -> u16 {
157 u16::from_be_bytes(self.buf[6..8].try_into().unwrap())
158 }
159
160 #[must_use]
161 pub(crate) fn nscount(&self) -> u16 {
162 u16::from_be_bytes(self.buf[8..10].try_into().unwrap())
163 }
164
165 #[must_use]
166 pub(crate) fn arcount(&self) -> u16 {
167 u16::from_be_bytes(self.buf[10..12].try_into().unwrap())
168 }
169
170 #[must_use]
171 pub(crate) fn as_bytes(&self) -> &[u8; Self::LEN_USIZE] {
172 &self.buf
173 }
174}
175
176impl From<[u8; Header::LEN_USIZE]> for Header {
177 #[inline]
178 fn from(buf: [u8; Self::LEN_USIZE]) -> Self {
179 Header { buf }
180 }
181}
182
183#[cfg(test)]
184mod tests {
185 use super::Header;
186
187 #[test]
188 fn qdcount() {
189 let mut header: Header = Header { buf: [0; 12] };
190
191 header.set_qdcount(0xABCD);
192 assert_eq!(header.qdcount(), 0xABCD);
193
194 header.increment_qdcount();
195 assert_eq!(header.qdcount(), 0xABCE);
196 }
197}