simple_dns/dns/
header_buffer.rs1use crate::{PacketFlag, OPCODE, RCODE};
15
16use super::header::masks;
17
18pub fn id(buffer: &[u8]) -> crate::Result<u16> {
20 check_buffer_len(buffer).map(id_unchecked)
21}
22
23pub fn id_unchecked(buffer: &[u8]) -> u16 {
28 u16::from_be_bytes(buffer[..2].try_into().unwrap())
29}
30
31pub fn questions(buffer: &[u8]) -> crate::Result<u16> {
33 check_buffer_len(buffer).map(questions_unchecked)
34}
35
36pub fn questions_unchecked(buffer: &[u8]) -> u16 {
41 u16::from_be_bytes(buffer[4..6].try_into().unwrap())
42}
43
44#[cfg(test)]
45pub(crate) fn set_questions(buffer: &mut [u8], question_count: u16) {
50 buffer[4..6].copy_from_slice(&question_count.to_be_bytes());
51}
52
53pub fn answers(buffer: &[u8]) -> crate::Result<u16> {
55 check_buffer_len(buffer).map(answers_unchecked)
56}
57
58pub fn answers_unchecked(buffer: &[u8]) -> u16 {
63 u16::from_be_bytes(buffer[6..8].try_into().unwrap())
64}
65
66#[cfg(test)]
67pub(crate) fn set_answers(buffer: &mut [u8], answers_count: u16) {
72 buffer[6..8].copy_from_slice(&answers_count.to_be_bytes());
73}
74
75pub fn name_servers(buffer: &[u8]) -> crate::Result<u16> {
77 check_buffer_len(buffer).map(name_servers_unchecked)
78}
79
80pub fn name_servers_unchecked(buffer: &[u8]) -> u16 {
85 u16::from_be_bytes(buffer[8..10].try_into().unwrap())
86}
87
88#[cfg(test)]
89pub(crate) fn set_name_servers(buffer: &mut [u8], name_servers_count: u16) {
94 buffer[8..10].copy_from_slice(&name_servers_count.to_be_bytes());
95}
96
97pub fn additional_records(buffer: &[u8]) -> crate::Result<u16> {
99 check_buffer_len(buffer).map(additional_records_unchecked)
100}
101
102pub fn additional_records_unchecked(buffer: &[u8]) -> u16 {
107 u16::from_be_bytes(buffer[10..12].try_into().unwrap())
108}
109
110#[cfg(test)]
111pub(crate) fn set_additional_records(buffer: &mut [u8], additional_records_count: u16) {
116 buffer[10..12].copy_from_slice(&additional_records_count.to_be_bytes());
117}
118
119pub fn has_flags(buffer: &[u8], flags: PacketFlag) -> crate::Result<bool> {
122 check_buffer_len(buffer).map(|_| has_flags_unchecked(buffer, flags))
123}
124
125pub fn has_flags_unchecked(buffer: &[u8], flags: PacketFlag) -> bool {
131 let bits = u16::from_be_bytes(buffer[2..4].try_into().unwrap());
132 PacketFlag::from_bits_truncate(bits).contains(flags)
133}
134
135pub fn rcode(buffer: &[u8]) -> crate::Result<RCODE> {
138 check_buffer_len(buffer).map(rcode_unchecked)
139}
140
141pub fn rcode_unchecked(buffer: &[u8]) -> RCODE {
147 let flags = u16::from_be_bytes(buffer[2..4].try_into().unwrap());
148 (flags & masks::RESPONSE_CODE_MASK).into()
149}
150
151pub fn opcode(buffer: &[u8]) -> crate::Result<OPCODE> {
153 check_buffer_len(buffer).map(opcode_unchecked)
154}
155
156pub fn opcode_unchecked(buffer: &[u8]) -> OPCODE {
161 let flags = u16::from_be_bytes(buffer[2..4].try_into().unwrap());
162 ((flags & masks::OPCODE_MASK) >> masks::OPCODE_MASK.trailing_zeros()).into()
163}
164
165fn check_buffer_len(buffer: &[u8]) -> crate::Result<&[u8]> {
166 if buffer.len() < 12 {
167 Err(crate::SimpleDnsError::InvalidHeaderData)
168 } else {
169 Ok(buffer)
170 }
171}
172
173#[cfg(test)]
174mod tests {
175 use super::*;
176
177 #[test]
178 fn read_write_questions_count() {
179 let mut buffer = [0u8; 12];
180 set_questions(&mut buffer, 1);
181 assert_eq!(1, questions(&buffer).unwrap());
182 }
183
184 #[test]
185 fn read_write_answers_count() {
186 let mut buffer = [0u8; 12];
187 set_answers(&mut buffer, 1);
188 assert_eq!(1, answers(&buffer).unwrap());
189 }
190
191 #[test]
192 fn read_write_name_servers_count() {
193 let mut buffer = [0u8; 12];
194 set_name_servers(&mut buffer, 1);
195 assert_eq!(1, name_servers(&buffer).unwrap());
196 }
197
198 #[test]
199 fn read_write_additional_records_count() {
200 let mut buffer = [0u8; 12];
201 set_additional_records(&mut buffer, 1);
202 assert_eq!(1, additional_records(&buffer).unwrap());
203 }
204
205 #[test]
206 fn id_returns_error_for_short_buffer() {
207 assert!(id(&[0u8; 11]).is_err());
208 }
209
210 #[test]
211 fn questions_returns_error_for_short_buffer() {
212 assert!(questions(&[0u8; 11]).is_err());
213 }
214
215 #[test]
216 fn answers_returns_error_for_short_buffer() {
217 assert!(answers(&[0u8; 11]).is_err());
218 }
219
220 #[test]
221 fn name_servers_returns_error_for_short_buffer() {
222 assert!(name_servers(&[0u8; 11]).is_err());
223 }
224
225 #[test]
226 fn additional_records_returns_error_for_short_buffer() {
227 assert!(additional_records(&[0u8; 11]).is_err());
228 }
229
230 #[test]
231 fn has_flags_returns_error_for_short_buffer() {
232 assert!(has_flags(&[0u8; 11], PacketFlag::RESPONSE).is_err());
233 }
234
235 #[test]
236 fn rcode_returns_error_for_short_buffer() {
237 assert!(rcode(&[0u8; 11]).is_err());
238 }
239
240 #[test]
241 fn opcode_returns_error_for_short_buffer() {
242 assert!(opcode(&[0u8; 11]).is_err());
243 }
244
245 #[test]
246 #[should_panic]
247 fn id_unchecked_panics_for_short_buffer() {
248 id_unchecked(&[]);
249 }
250
251 #[test]
252 #[should_panic]
253 fn questions_unchecked_panics_for_short_buffer() {
254 questions_unchecked(&[0u8; 4]);
255 }
256
257 #[test]
258 #[should_panic]
259 fn answers_unchecked_panics_for_short_buffer() {
260 answers_unchecked(&[0u8; 6]);
261 }
262
263 #[test]
264 #[should_panic]
265 fn name_servers_unchecked_panics_for_short_buffer() {
266 name_servers_unchecked(&[0u8; 8]);
267 }
268
269 #[test]
270 #[should_panic]
271 fn additional_records_unchecked_panics_for_short_buffer() {
272 additional_records_unchecked(&[0u8; 10]);
273 }
274
275 #[test]
276 #[should_panic]
277 fn has_flags_unchecked_panics_for_short_buffer() {
278 has_flags_unchecked(&[0u8; 1], PacketFlag::RESPONSE);
279 }
280
281 #[test]
282 #[should_panic]
283 fn rcode_unchecked_panics_for_short_buffer() {
284 rcode_unchecked(&[0u8; 1]);
285 }
286
287 #[test]
288 #[should_panic]
289 fn opcode_unchecked_panics_for_short_buffer() {
290 opcode_unchecked(&[0u8; 1]);
291 }
292}