flex_dns/
header.rs

1/// A DNS header.
2#[derive(Copy, Clone)]
3#[repr(C)]
4pub struct DnsHeader {
5    id: [u8; 2],
6    flags: [u8; 2],
7    question_count: [u8; 2],
8    answer_count: [u8; 2],
9    name_server_count: [u8; 2],
10    additional_records_count: [u8; 2],
11}
12
13impl DnsHeader {
14    #[inline(always)]
15    pub(crate) fn from_bytes_mut(bytes: &mut [u8]) -> &mut Self {
16        unsafe { &mut *(bytes.as_mut_ptr() as *mut Self) }
17    }
18
19    #[inline(always)]
20    pub(crate) fn from_bytes(bytes: &[u8]) -> &Self {
21        unsafe { & *(bytes.as_ptr() as *const Self) }
22    }
23
24    /// The id of the DNS header.
25    #[inline(always)]
26    pub fn id(&self) -> u16 {
27        u16::from_be_bytes(self.id)
28    }
29
30    /// The kind of the DNS header.
31    #[inline(always)]
32    pub fn kind(&self) -> DnsHeaderKind {
33        if (self.flags[0] & 0b10000000) == 0 {
34            DnsHeaderKind::Query
35        } else {
36            DnsHeaderKind::Response
37        }
38    }
39
40    /// The opcode of the DNS header.
41    #[inline(always)]
42    pub fn opcode(&self) -> DnsHeaderOpcode {
43        (self.flags[0] & 0b01111000).into()
44    }
45
46    /// Whether the DNS header is an authoritative answer.
47    #[inline(always)]
48    pub fn authoritative_answer(&self) -> bool {
49        (self.flags[0] & 0b00000100) != 0
50    }
51
52    /// Whether the DNS header is truncated.
53    #[inline(always)]
54    pub fn truncated(&self) -> bool {
55        (self.flags[0] & 0b00000010) != 0
56    }
57
58    /// Whether the DNS header recursion is desired.
59    #[inline(always)]
60    pub fn recursion_desired(&self) -> bool {
61        (self.flags[0] & 0b00000001) != 0
62    }
63
64    /// Whether the DNS header recursion is available.
65    #[inline(always)]
66    pub fn recursion_available(&self) -> bool {
67        (self.flags[1] & 0b10000000) != 0
68    }
69
70    /// The response code of the DNS header.
71    #[inline(always)]
72    pub fn response_code(&self) -> DnsHeaderResponseCode {
73        (self.flags[1] & 0b00001111).into()
74    }
75
76    /// The number of questions in the DNS message.
77    #[inline(always)]
78    pub fn question_count(&self) -> u16 {
79        u16::from_be_bytes(self.question_count)
80    }
81
82    /// The number of answers in the DNS message.
83    #[inline(always)]
84    pub fn answer_count(&self) -> u16 {
85        u16::from_be_bytes(self.answer_count)
86    }
87
88    /// The number of name servers in the DNS message.
89    #[inline(always)]
90    pub fn name_server_count(&self) -> u16 {
91        u16::from_be_bytes(self.name_server_count)
92    }
93
94    /// The number of additional records in the DNS message.
95    #[inline(always)]
96    pub fn additional_records_count(&self) -> u16 {
97        u16::from_be_bytes(self.additional_records_count)
98    }
99
100    /// Set the id of the DNS header.
101    #[inline(always)]
102    pub fn set_id(&mut self, id: u16) {
103        self.id = id.to_be_bytes();
104    }
105
106    /// Set the kind of the DNS header.
107    #[inline(always)]
108    pub fn set_kind(&mut self, kind: DnsHeaderKind) {
109        match kind {
110            DnsHeaderKind::Query => self.flags[0] &= 0b01111111,
111            DnsHeaderKind::Response => self.flags[0] |= 0b10000000,
112        }
113    }
114
115    /// Set the opcode of the DNS header.
116    #[inline(always)]
117    pub fn set_opcode(&mut self, opcode: DnsHeaderOpcode) {
118        self.flags[0] &= 0b10000111;
119        self.flags[0] |= (u8::from(opcode) & 0b0000_1111) << 3;
120    }
121
122    /// Set whether the DNS header is an authoritative answer.
123    #[inline(always)]
124    pub fn set_authoritative_answer(&mut self, authoritative_answer: bool) {
125        if authoritative_answer {
126            self.flags[0] |= 0b00000100;
127        } else {
128            self.flags[0] &= 0b11111011;
129        }
130    }
131
132    /// Set whether the DNS header is truncated.
133    #[inline(always)]
134    pub fn set_truncated(&mut self, truncated: bool) {
135        if truncated {
136            self.flags[0] |= 0b00000010;
137        } else {
138            self.flags[0] &= 0b11111101;
139        }
140    }
141
142    /// Set whether recursion is desired.
143    #[inline(always)]
144    pub fn set_recursion_desired(&mut self, recursion_desired: bool) {
145        if recursion_desired {
146            self.flags[0] |= 0b00000001;
147        } else {
148            self.flags[0] &= 0b11111110;
149        }
150    }
151
152    /// Set whether recursion is available.
153    #[inline(always)]
154    pub fn set_recursion_available(&mut self, recursion_available: bool) {
155        if recursion_available {
156            self.flags[1] |= 0b10000000;
157        } else {
158            self.flags[1] &= 0b01111111;
159        }
160    }
161
162    /// Set the response code of the DNS header.
163    #[inline(always)]
164    pub fn set_response_code(&mut self, response_code: DnsHeaderResponseCode) {
165        self.flags[1] &= 0b11110000;
166        self.flags[1] |= u8::from(response_code) & 0b00001111;
167    }
168
169    #[inline(always)]
170    pub(crate) fn set_question_count(&mut self, question_count: u16) {
171        self.question_count = question_count.to_be_bytes();
172    }
173
174    #[inline(always)]
175    pub(crate) fn set_answer_count(&mut self, answer_count: u16) {
176        self.answer_count = answer_count.to_be_bytes();
177    }
178
179    #[inline(always)]
180    pub(crate) fn set_name_server_count(&mut self, name_server_count: u16) {
181        self.name_server_count = name_server_count.to_be_bytes();
182    }
183
184    #[inline(always)]
185    pub(crate) fn set_additional_records_count(&mut self, additional_records_count: u16) {
186        self.additional_records_count = additional_records_count.to_be_bytes();
187    }
188}
189
190impl core::fmt::Debug for DnsHeader {
191    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
192        f.debug_struct("Header")
193            .field("id", &self.id())
194            .field("kind", &self.kind())
195            .field("opcode", &self.opcode())
196            .field("authoritative_answer", &self.authoritative_answer())
197            .field("truncated", &self.truncated())
198            .field("recursion_desired", &self.recursion_desired())
199            .field("recursion_available", &self.recursion_available())
200            .field("response_code", &self.response_code())
201            .field("question_count", &self.question_count())
202            .field("answer_count", &self.answer_count())
203            .field("name_server_count", &self.name_server_count())
204            .field("additional_records_count", &self.additional_records_count())
205            .finish()
206    }
207}
208
209/// The kind of a DNS header.
210#[derive(Copy, Clone, Debug, PartialEq)]
211pub enum DnsHeaderKind {
212    /// A DNS query.
213    Query,
214    /// A DNS response.
215    Response,
216}
217
218/// A DNS opcode.
219#[derive(Copy, Clone, Debug, PartialEq)]
220pub enum DnsHeaderOpcode {
221    Query,
222    InverseQuery,
223    Status,
224    Notify,
225    Update,
226    Reserved(u8),
227}
228
229impl From<u8> for DnsHeaderOpcode {
230    fn from(value: u8) -> Self {
231        match value {
232            0 => DnsHeaderOpcode::Query,
233            1 => DnsHeaderOpcode::InverseQuery,
234            2 => DnsHeaderOpcode::Status,
235            4 => DnsHeaderOpcode::Notify,
236            5 => DnsHeaderOpcode::Update,
237            _ => DnsHeaderOpcode::Reserved(value),
238        }
239    }
240}
241
242impl From<DnsHeaderOpcode> for u8 {
243    fn from(value: DnsHeaderOpcode) -> Self {
244        match value {
245            DnsHeaderOpcode::Query => 0,
246            DnsHeaderOpcode::InverseQuery => 1,
247            DnsHeaderOpcode::Status => 2,
248            DnsHeaderOpcode::Notify => 4,
249            DnsHeaderOpcode::Update => 5,
250            DnsHeaderOpcode::Reserved(value) => value,
251        }
252    }
253}
254
255/// A DNS response code.
256#[derive(Copy, Clone, Debug, PartialEq)]
257pub enum DnsHeaderResponseCode {
258    NoError,
259    FormatError,
260    ServerFailure,
261    NonExistentDomain,
262    NotImplemented,
263    Refused,
264    ExistentDomain,
265    ExistentRrSet,
266    NonExistentRrSet,
267    NotAuthoritative,
268    NotZone,
269    BadOptVersionOrBadSignature,
270    BadKey,
271    BadTime,
272    BadMode,
273    BadName,
274    BadAlg,
275    Reserved(u8),
276}
277
278impl From<DnsHeaderResponseCode> for u8 {
279    fn from(r: DnsHeaderResponseCode) -> Self {
280        match r {
281            DnsHeaderResponseCode::NoError => 0,
282            DnsHeaderResponseCode::FormatError => 1,
283            DnsHeaderResponseCode::ServerFailure => 2,
284            DnsHeaderResponseCode::NonExistentDomain => 3,
285            DnsHeaderResponseCode::NotImplemented => 4,
286            DnsHeaderResponseCode::Refused => 5,
287            DnsHeaderResponseCode::ExistentDomain => 6,
288            DnsHeaderResponseCode::ExistentRrSet => 7,
289            DnsHeaderResponseCode::NonExistentRrSet => 8,
290            DnsHeaderResponseCode::NotAuthoritative => 9,
291            DnsHeaderResponseCode::NotZone => 10,
292            DnsHeaderResponseCode::BadOptVersionOrBadSignature => 16,
293            DnsHeaderResponseCode::BadKey => 17,
294            DnsHeaderResponseCode::BadTime => 18,
295            DnsHeaderResponseCode::BadMode => 19,
296            DnsHeaderResponseCode::BadName => 20,
297            DnsHeaderResponseCode::BadAlg => 21,
298            DnsHeaderResponseCode::Reserved(n) => n,
299        }
300    }
301}
302
303impl From<u8> for DnsHeaderResponseCode {
304    fn from(n: u8) -> Self {
305        match n {
306            0 => DnsHeaderResponseCode::NoError,
307            1 => DnsHeaderResponseCode::FormatError,
308            2 => DnsHeaderResponseCode::ServerFailure,
309            3 => DnsHeaderResponseCode::NonExistentDomain,
310            4 => DnsHeaderResponseCode::NotImplemented,
311            5 => DnsHeaderResponseCode::Refused,
312            6 => DnsHeaderResponseCode::ExistentDomain,
313            7 => DnsHeaderResponseCode::ExistentRrSet,
314            8 => DnsHeaderResponseCode::NonExistentRrSet,
315            9 => DnsHeaderResponseCode::NotAuthoritative,
316            10 => DnsHeaderResponseCode::NotZone,
317            16 => DnsHeaderResponseCode::BadOptVersionOrBadSignature,
318            17 => DnsHeaderResponseCode::BadKey,
319            18 => DnsHeaderResponseCode::BadTime,
320            19 => DnsHeaderResponseCode::BadMode,
321            20 => DnsHeaderResponseCode::BadName,
322            21 => DnsHeaderResponseCode::BadAlg,
323            n => DnsHeaderResponseCode::Reserved(n),
324        }
325    }
326}