w5500_dns/
header.rs

1/// Query or Response flag.
2#[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/// DNS response code.
10///
11/// # References
12///
13/// * [RFC 1035 Section 4.1.1](https://www.rfc-editor.org/rfc/rfc1035#section-4.1.1)
14#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15#[cfg_attr(feature = "defmt", derive(defmt::Format))]
16#[repr(u8)]
17pub enum ResponseCode {
18    /// No Error.
19    ///
20    /// No error condition.
21    NoError = 0,
22    /// Format Error.
23    ///
24    /// The name server was unable to interpret the query.
25    FormatError = 1,
26    /// Server Failure.
27    ///
28    /// The name server was unable to process this query due to a problem with
29    /// the name server.
30    ServerFailure = 2,
31    /// Name Error.
32    ///
33    /// Meaningful only for responses from an authoritative name server,
34    /// this code signifies that the domain name referenced in the query does
35    /// not exist.
36    NameError = 3,
37    /// Not Implemented
38    ///
39    /// The name server does not support the requested kind of query.
40    NotImplemented = 4,
41    /// Refused.
42    ///
43    /// The name server refuses to perform the specified operation for policy
44    /// reasons.
45    /// For example, a name server may not wish to provide the information to
46    /// the particular requester, or a name server may not wish to perform
47    /// a particular operation (e.g., zone transfer) for particular data.
48    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/// DNS query header
68///
69/// # References
70///
71/// * [RFC 1035 Section 4.1.1](https://www.rfc-editor.org/rfc/rfc1035#section-4.1.1)
72#[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    /// Set the 16-bit identifier.
97    #[must_use]
98    pub(crate) fn id(&self) -> u16 {
99        u16::from_be_bytes(self.buf[..2].try_into().unwrap())
100    }
101
102    /// Get the 16-bit identifier.
103    #[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}