1use crate::dns_parser::{Error, Opcode, ResponseCode};
2use byteorder::{BigEndian, ByteOrder};
3
4mod flag {
5 pub const QUERY: u16 = 0b1000_0000_0000_0000;
6 pub const OPCODE_MASK: u16 = 0b0111_1000_0000_0000;
7 pub const AUTHORITATIVE: u16 = 0b0000_0100_0000_0000;
8 pub const TRUNCATED: u16 = 0b0000_0010_0000_0000;
9 pub const RECURSION_DESIRED: u16 = 0b0000_0001_0000_0000;
10 pub const RECURSION_AVAILABLE: u16 = 0b0000_0000_1000_0000;
11 pub const AUTHENTICATED_DATA: u16 = 0b0000_0000_0010_0000;
12 pub const CHECKING_DISABLED: u16 = 0b0000_0000_0001_0000;
13 pub const RESERVED_MASK: u16 = 0b0000_0000_0100_0000;
14 pub const RESPONSE_CODE_MASK: u16 = 0b0000_0000_0000_1111;
15}
16
17#[derive(Debug, PartialEq, Eq, Clone, Copy)]
19#[allow(missing_docs)] pub struct Header {
21 pub id: u16,
22 pub query: bool,
23 pub opcode: Opcode,
24 pub authoritative: bool,
25 pub truncated: bool,
26 pub recursion_desired: bool,
27 pub recursion_available: bool,
28 pub authenticated_data: bool,
29 pub checking_disabled: bool,
30 pub response_code: ResponseCode,
31 pub questions: u16,
32 pub answers: u16,
33 pub nameservers: u16,
34 pub additional: u16,
35}
36
37impl Header {
38 pub fn parse(data: &[u8]) -> Result<Header, Error> {
40 if data.len() < 12 {
41 return Err(Error::HeaderTooShort);
42 }
43 let flags = BigEndian::read_u16(&data[2..4]);
44 if flags & flag::RESERVED_MASK != 0 {
45 return Err(Error::ReservedBitsAreNonZero);
46 }
47 let header = Header {
48 id: BigEndian::read_u16(&data[..2]),
49 query: flags & flag::QUERY == 0,
50 opcode: ((flags & flag::OPCODE_MASK) >> flag::OPCODE_MASK.trailing_zeros()).into(),
51 authoritative: flags & flag::AUTHORITATIVE != 0,
52 truncated: flags & flag::TRUNCATED != 0,
53 recursion_desired: flags & flag::RECURSION_DESIRED != 0,
54 recursion_available: flags & flag::RECURSION_AVAILABLE != 0,
55 authenticated_data: flags & flag::AUTHENTICATED_DATA != 0,
56 checking_disabled: flags & flag::CHECKING_DISABLED != 0,
57 response_code: From::from((flags & flag::RESPONSE_CODE_MASK) as u8),
58 questions: BigEndian::read_u16(&data[4..6]),
59 answers: BigEndian::read_u16(&data[6..8]),
60 nameservers: BigEndian::read_u16(&data[8..10]),
61 additional: BigEndian::read_u16(&data[10..12]),
62 };
63 Ok(header)
64 }
65 pub fn write(&self, data: &mut [u8]) {
71 if data.len() != 12 {
72 panic!("Header size is exactly 12 bytes");
73 }
74 let mut flags = 0u16;
75 flags |= Into::<u16>::into(self.opcode) << flag::OPCODE_MASK.trailing_zeros();
76 flags |= Into::<u8>::into(self.response_code) as u16;
77 if !self.query {
78 flags |= flag::QUERY;
79 }
80 if self.authoritative {
81 flags |= flag::AUTHORITATIVE;
82 }
83 if self.recursion_desired {
84 flags |= flag::RECURSION_DESIRED;
85 }
86 if self.recursion_available {
87 flags |= flag::RECURSION_AVAILABLE;
88 }
89 if self.truncated {
90 flags |= flag::TRUNCATED;
91 }
92 BigEndian::write_u16(&mut data[..2], self.id);
93 BigEndian::write_u16(&mut data[2..4], flags);
94 BigEndian::write_u16(&mut data[4..6], self.questions);
95 BigEndian::write_u16(&mut data[6..8], self.answers);
96 BigEndian::write_u16(&mut data[8..10], self.nameservers);
97 BigEndian::write_u16(&mut data[10..12], self.additional);
98 }
99 pub fn set_truncated(data: &mut [u8]) {
102 let oldflags = BigEndian::read_u16(&data[2..4]);
103 BigEndian::write_u16(&mut data[2..4], oldflags & flag::TRUNCATED);
104 }
105 pub fn size() -> usize {
107 12
108 }
109}
110
111#[cfg(test)]
112mod test {
113
114 use crate::dns_parser::Header;
115 use crate::dns_parser::Opcode::*;
116 use crate::dns_parser::ResponseCode::NoError;
117
118 #[test]
119 fn parse_example_query() {
120 let query = b"\x06%\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\
121 \x07example\x03com\x00\x00\x01\x00\x01";
122 let header = Header::parse(query).unwrap();
123 assert_eq!(
124 header,
125 Header {
126 id: 1573,
127 query: true,
128 opcode: StandardQuery,
129 authoritative: false,
130 truncated: false,
131 recursion_desired: true,
132 recursion_available: false,
133 authenticated_data: false,
134 checking_disabled: false,
135 response_code: NoError,
136 questions: 1,
137 answers: 0,
138 nameservers: 0,
139 additional: 0,
140 }
141 );
142 }
143
144 #[test]
145 fn parse_example_response() {
146 let response = b"\x06%\x81\x80\x00\x01\x00\x01\x00\x00\x00\x00\
147 \x07example\x03com\x00\x00\x01\x00\x01\
148 \xc0\x0c\x00\x01\x00\x01\x00\x00\x04\xf8\
149 \x00\x04]\xb8\xd8\"";
150 let header = Header::parse(response).unwrap();
151 assert_eq!(
152 header,
153 Header {
154 id: 1573,
155 query: false,
156 opcode: StandardQuery,
157 authoritative: false,
158 truncated: false,
159 recursion_desired: true,
160 recursion_available: true,
161 authenticated_data: false,
162 checking_disabled: false,
163 response_code: NoError,
164 questions: 1,
165 answers: 1,
166 nameservers: 0,
167 additional: 0,
168 }
169 );
170 }
171
172 #[test]
173 fn parse_query_with_ad_set() {
174 let query = b"\x06%\x01\x20\x00\x01\x00\x00\x00\x00\x00\x00\
175 \x07example\x03com\x00\x00\x01\x00\x01";
176 let header = Header::parse(query).unwrap();
177 assert_eq!(
178 header,
179 Header {
180 id: 1573,
181 query: true,
182 opcode: StandardQuery,
183 authoritative: false,
184 truncated: false,
185 recursion_desired: true,
186 recursion_available: false,
187 authenticated_data: true,
188 checking_disabled: false,
189 response_code: NoError,
190 questions: 1,
191 answers: 0,
192 nameservers: 0,
193 additional: 0,
194 }
195 );
196 }
197
198 #[test]
199 fn parse_query_with_cd_set() {
200 let query = b"\x06%\x01\x10\x00\x01\x00\x00\x00\x00\x00\x00\
201 \x07example\x03com\x00\x00\x01\x00\x01";
202 let header = Header::parse(query).unwrap();
203 assert_eq!(
204 header,
205 Header {
206 id: 1573,
207 query: true,
208 opcode: StandardQuery,
209 authoritative: false,
210 truncated: false,
211 recursion_desired: true,
212 recursion_available: false,
213 authenticated_data: false,
214 checking_disabled: true,
215 response_code: NoError,
216 questions: 1,
217 answers: 0,
218 nameservers: 0,
219 additional: 0,
220 }
221 );
222 }
223}