1use byteorder::{BigEndian, ByteOrder};
2
3use crate::rdata::opt::Record as Opt;
4use crate::{Class, RData, ResourceRecord, Type};
5use crate::{Error, Header, Name, Packet, QueryClass, QueryType, Question};
6
7const OPT_RR_START: [u8; 3] = [0, 0, 41];
8
9impl Packet<'_> {
10 pub fn parse(data: &[u8]) -> Result<Packet, Error> {
13 let header = Header::parse(data)?;
14 let mut offset = Header::size();
15 let mut questions = Vec::with_capacity(header.questions as usize);
16 for _ in 0..header.questions {
17 let name = Name::scan(&data[offset..], data)?;
18 offset += name.byte_len();
19 if offset + 4 > data.len() {
20 return Err(Error::UnexpectedEOF);
21 }
22 let qtype = QueryType::parse(BigEndian::read_u16(&data[offset..offset + 2]))?;
23 offset += 2;
24
25 let (prefer_unicast, qclass) =
26 parse_qclass_code(BigEndian::read_u16(&data[offset..offset + 2]))?;
27 offset += 2;
28
29 questions.push(Question {
30 qname: name,
31 qtype,
32 prefer_unicast,
33 qclass,
34 });
35 }
36 let mut answers = Vec::with_capacity(header.answers as usize);
37 for _ in 0..header.answers {
38 answers.push(parse_record(data, &mut offset)?);
39 }
40 let mut nameservers = Vec::with_capacity(header.nameservers as usize);
41 for _ in 0..header.nameservers {
42 nameservers.push(parse_record(data, &mut offset)?);
43 }
44 let mut additional = Vec::with_capacity(header.additional as usize);
45 let mut opt = None;
46 for _ in 0..header.additional {
47 if offset + 3 <= data.len() && data[offset..offset + 3] == OPT_RR_START {
48 if opt.is_none() {
49 opt = Some(parse_opt_record(data, &mut offset)?);
50 } else {
51 return Err(Error::AdditionalOPT);
52 }
53 } else {
54 additional.push(parse_record(data, &mut offset)?);
55 }
56 }
57 Ok(Packet {
58 header,
59 questions,
60 answers,
61 nameservers,
62 additional,
63 opt,
64 })
65 }
66}
67
68fn parse_qclass_code(value: u16) -> Result<(bool, QueryClass), Error> {
69 let prefer_unicast = value & 0x8000 == 0x8000;
70 let qclass_code = value & 0x7FFF;
71
72 let qclass = QueryClass::parse(qclass_code)?;
73 Ok((prefer_unicast, qclass))
74}
75
76fn parse_class_code(value: u16) -> Result<(bool, Class), Error> {
77 let is_unique = value & 0x8000 == 0x8000;
78 let class_code = value & 0x7FFF;
79
80 let cls = Class::parse(class_code)?;
81 Ok((is_unique, cls))
82}
83
84fn parse_record<'a>(data: &'a [u8], offset: &mut usize) -> Result<ResourceRecord<'a>, Error> {
86 let name = Name::scan(&data[*offset..], data)?;
87 *offset += name.byte_len();
88 if *offset + 10 > data.len() {
89 return Err(Error::UnexpectedEOF);
90 }
91 let typ = Type::parse(BigEndian::read_u16(&data[*offset..*offset + 2]))?;
92 *offset += 2;
93
94 let class_code = BigEndian::read_u16(&data[*offset..*offset + 2]);
95 let (multicast_unique, cls) = parse_class_code(class_code)?;
96 *offset += 2;
97
98 let mut ttl = BigEndian::read_u32(&data[*offset..*offset + 4]);
99 if ttl > i32::MAX as u32 {
100 ttl = 0;
101 }
102 *offset += 4;
103 let rdlen = BigEndian::read_u16(&data[*offset..*offset + 2]) as usize;
104 *offset += 2;
105 if *offset + rdlen > data.len() {
106 return Err(Error::UnexpectedEOF);
107 }
108 let data = RData::parse(typ, &data[*offset..*offset + rdlen], data)?;
109 *offset += rdlen;
110 Ok(ResourceRecord {
111 name,
112 multicast_unique,
113 cls,
114 ttl,
115 data,
116 })
117}
118
119fn parse_opt_record<'a>(data: &'a [u8], offset: &mut usize) -> Result<Opt<'a>, Error> {
121 if *offset + 11 > data.len() {
122 return Err(Error::UnexpectedEOF);
123 }
124 *offset += 1;
125 let typ = Type::parse(BigEndian::read_u16(&data[*offset..*offset + 2]))?;
126 if typ != Type::OPT {
127 return Err(Error::InvalidType(typ as u16));
128 }
129 *offset += 2;
130 let udp = BigEndian::read_u16(&data[*offset..*offset + 2]);
131 *offset += 2;
132 let extrcode = data[*offset];
133 *offset += 1;
134 let version = data[*offset];
135 *offset += 1;
136 let flags = BigEndian::read_u16(&data[*offset..*offset + 2]);
137 *offset += 2;
138 let rdlen = BigEndian::read_u16(&data[*offset..*offset + 2]) as usize;
139 *offset += 2;
140 if *offset + rdlen > data.len() {
141 return Err(Error::UnexpectedEOF);
142 }
143 let data = RData::parse(typ, &data[*offset..*offset + rdlen], data)?;
144 *offset += rdlen;
145
146 Ok(Opt {
147 udp,
148 extrcode,
149 version,
150 flags,
151 data,
152 })
153}
154
155#[cfg(test)]
156mod test {
157
158 use crate::Class as C;
159 use crate::Opcode::*;
160 use crate::QueryClass as QC;
161 use crate::QueryType as QT;
162 use crate::RData;
163 use crate::ResponseCode::NoError;
164 use crate::{Header, Packet};
165 use std::net::Ipv4Addr;
166
167 #[test]
168 fn parse_example_query() {
169 let query = b"\x06%\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\
170 \x07example\x03com\x00\x00\x01\x00\x01";
171 let packet = Packet::parse(query).unwrap();
172 assert_eq!(
173 packet.header,
174 Header {
175 id: 1573,
176 query: true,
177 opcode: StandardQuery,
178 authoritative: false,
179 truncated: false,
180 recursion_desired: true,
181 recursion_available: false,
182 authenticated_data: false,
183 checking_disabled: false,
184 response_code: NoError,
185 questions: 1,
186 answers: 0,
187 nameservers: 0,
188 additional: 0,
189 }
190 );
191 assert_eq!(packet.questions.len(), 1);
192 assert_eq!(packet.questions[0].qtype, QT::A);
193 assert_eq!(packet.questions[0].qclass, QC::IN);
194 assert_eq!(&packet.questions[0].qname.to_string()[..], "example.com");
195 assert_eq!(packet.answers.len(), 0);
196 }
197
198 #[test]
199 fn parse_example_response() {
200 let response = b"\x06%\x81\x80\x00\x01\x00\x01\x00\x00\x00\x00\
201 \x07example\x03com\x00\x00\x01\x00\x01\
202 \xc0\x0c\x00\x01\x00\x01\x00\x00\x04\xf8\
203 \x00\x04]\xb8\xd8\"";
204 let packet = Packet::parse(response).unwrap();
205 assert_eq!(
206 packet.header,
207 Header {
208 id: 1573,
209 query: false,
210 opcode: StandardQuery,
211 authoritative: false,
212 truncated: false,
213 recursion_desired: true,
214 recursion_available: true,
215 authenticated_data: false,
216 checking_disabled: false,
217 response_code: NoError,
218 questions: 1,
219 answers: 1,
220 nameservers: 0,
221 additional: 0,
222 }
223 );
224 assert_eq!(packet.questions.len(), 1);
225 assert_eq!(packet.questions[0].qtype, QT::A);
226 assert_eq!(packet.questions[0].qclass, QC::IN);
227 assert_eq!(&packet.questions[0].qname.to_string()[..], "example.com");
228 assert_eq!(packet.answers.len(), 1);
229 assert_eq!(&packet.answers[0].name.to_string()[..], "example.com");
230 assert!(!packet.answers[0].multicast_unique);
231 assert_eq!(packet.answers[0].cls, C::IN);
232 assert_eq!(packet.answers[0].ttl, 1272);
233 match packet.answers[0].data {
234 RData::A(addr) => {
235 assert_eq!(addr.0, Ipv4Addr::new(93, 184, 216, 34));
236 }
237 ref x => panic!("Wrong rdata {:?}", x),
238 }
239 }
240
241 #[test]
242 fn parse_response_with_multicast_unique() {
243 let response = b"\x06%\x81\x80\x00\x01\x00\x01\x00\x00\x00\x00\
244 \x07example\x03com\x00\x00\x01\x00\x01\
245 \xc0\x0c\x00\x01\x80\x01\x00\x00\x04\xf8\
246 \x00\x04]\xb8\xd8\"";
247 let packet = Packet::parse(response).unwrap();
248
249 assert_eq!(packet.answers.len(), 1);
250 assert!(packet.answers[0].multicast_unique);
251 assert_eq!(packet.answers[0].cls, C::IN);
252 }
253
254 #[test]
255 fn parse_additional_record_response() {
256 let response = b"\x4a\xf0\x81\x80\x00\x01\x00\x01\x00\x01\x00\x01\
257 \x03www\x05skype\x03com\x00\x00\x01\x00\x01\
258 \xc0\x0c\x00\x05\x00\x01\x00\x00\x0e\x10\
259 \x00\x1c\x07\x6c\x69\x76\x65\x63\x6d\x73\x0e\x74\
260 \x72\x61\x66\x66\x69\x63\x6d\x61\x6e\x61\x67\x65\
261 \x72\x03\x6e\x65\x74\x00\
262 \xc0\x42\x00\x02\x00\x01\x00\x01\xd5\xd3\x00\x11\
263 \x01\x67\x0c\x67\x74\x6c\x64\x2d\x73\x65\x72\x76\x65\x72\x73\
264 \xc0\x42\
265 \x01\x61\xc0\x55\x00\x01\x00\x01\x00\x00\xa3\x1c\
266 \x00\x04\xc0\x05\x06\x1e";
267 let packet = Packet::parse(response).unwrap();
268 assert_eq!(
269 packet.header,
270 Header {
271 id: 19184,
272 query: false,
273 opcode: StandardQuery,
274 authoritative: false,
275 truncated: false,
276 recursion_desired: true,
277 recursion_available: true,
278 authenticated_data: false,
279 checking_disabled: false,
280 response_code: NoError,
281 questions: 1,
282 answers: 1,
283 nameservers: 1,
284 additional: 1,
285 }
286 );
287 assert_eq!(packet.questions.len(), 1);
288 assert_eq!(packet.questions[0].qtype, QT::A);
289 assert_eq!(packet.questions[0].qclass, QC::IN);
290 assert_eq!(&packet.questions[0].qname.to_string()[..], "www.skype.com");
291 assert_eq!(packet.answers.len(), 1);
292 assert_eq!(&packet.answers[0].name.to_string()[..], "www.skype.com");
293 assert_eq!(packet.answers[0].cls, C::IN);
294 assert_eq!(packet.answers[0].ttl, 3600);
295 match packet.answers[0].data {
296 RData::CNAME(cname) => {
297 assert_eq!(&cname.0.to_string()[..], "livecms.trafficmanager.net");
298 }
299 ref x => panic!("Wrong rdata {:?}", x),
300 }
301 assert_eq!(packet.nameservers.len(), 1);
302 assert_eq!(&packet.nameservers[0].name.to_string()[..], "net");
303 assert_eq!(packet.nameservers[0].cls, C::IN);
304 assert_eq!(packet.nameservers[0].ttl, 120275);
305 match packet.nameservers[0].data {
306 RData::NS(ns) => {
307 assert_eq!(&ns.0.to_string()[..], "g.gtld-servers.net");
308 }
309 ref x => panic!("Wrong rdata {:?}", x),
310 }
311 assert_eq!(packet.additional.len(), 1);
312 assert_eq!(
313 &packet.additional[0].name.to_string()[..],
314 "a.gtld-servers.net"
315 );
316 assert_eq!(packet.additional[0].cls, C::IN);
317 assert_eq!(packet.additional[0].ttl, 41756);
318 match packet.additional[0].data {
319 RData::A(addr) => {
320 assert_eq!(addr.0, Ipv4Addr::new(192, 5, 6, 30));
321 }
322 ref x => panic!("Wrong rdata {:?}", x),
323 }
324 }
325
326 #[test]
327 fn parse_multiple_answers() {
328 let response = b"\x9d\xe9\x81\x80\x00\x01\x00\x06\x00\x00\x00\x00\
329 \x06google\x03com\x00\x00\x01\x00\x01\xc0\x0c\
330 \x00\x01\x00\x01\x00\x00\x00\xef\x00\x04@\xe9\
331 \xa4d\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\xef\
332 \x00\x04@\xe9\xa4\x8b\xc0\x0c\x00\x01\x00\x01\
333 \x00\x00\x00\xef\x00\x04@\xe9\xa4q\xc0\x0c\x00\
334 \x01\x00\x01\x00\x00\x00\xef\x00\x04@\xe9\xa4f\
335 \xc0\x0c\x00\x01\x00\x01\x00\x00\x00\xef\x00\x04@\
336 \xe9\xa4e\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\xef\
337 \x00\x04@\xe9\xa4\x8a";
338 let packet = Packet::parse(response).unwrap();
339 assert_eq!(
340 packet.header,
341 Header {
342 id: 40425,
343 query: false,
344 opcode: StandardQuery,
345 authoritative: false,
346 truncated: false,
347 recursion_desired: true,
348 recursion_available: true,
349 authenticated_data: false,
350 checking_disabled: false,
351 response_code: NoError,
352 questions: 1,
353 answers: 6,
354 nameservers: 0,
355 additional: 0,
356 }
357 );
358 assert_eq!(packet.questions.len(), 1);
359 assert_eq!(packet.questions[0].qtype, QT::A);
360 assert_eq!(packet.questions[0].qclass, QC::IN);
361 assert_eq!(&packet.questions[0].qname.to_string()[..], "google.com");
362 assert_eq!(packet.answers.len(), 6);
363 let ips = [
364 Ipv4Addr::new(64, 233, 164, 100),
365 Ipv4Addr::new(64, 233, 164, 139),
366 Ipv4Addr::new(64, 233, 164, 113),
367 Ipv4Addr::new(64, 233, 164, 102),
368 Ipv4Addr::new(64, 233, 164, 101),
369 Ipv4Addr::new(64, 233, 164, 138),
370 ];
371 for (i, ip) in ips.iter().enumerate() {
372 assert_eq!(&packet.answers[i].name.to_string()[..], "google.com");
373 assert_eq!(packet.answers[i].cls, C::IN);
374 assert_eq!(packet.answers[i].ttl, 239);
375 match packet.answers[i].data {
376 RData::A(addr) => {
377 assert_eq!(addr.0, *ip);
378 }
379 ref x => panic!("Wrong rdata {:?}", x),
380 }
381 }
382 }
383
384 #[test]
385 fn parse_srv_query() {
386 let query = b"[\xd9\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\
387 \x0c_xmpp-server\x04_tcp\x05gmail\x03com\x00\x00!\x00\x01";
388 let packet = Packet::parse(query).unwrap();
389 assert_eq!(
390 packet.header,
391 Header {
392 id: 23513,
393 query: true,
394 opcode: StandardQuery,
395 authoritative: false,
396 truncated: false,
397 recursion_desired: true,
398 recursion_available: false,
399 authenticated_data: false,
400 checking_disabled: false,
401 response_code: NoError,
402 questions: 1,
403 answers: 0,
404 nameservers: 0,
405 additional: 0,
406 }
407 );
408 assert_eq!(packet.questions.len(), 1);
409 assert_eq!(packet.questions[0].qtype, QT::SRV);
410 assert_eq!(packet.questions[0].qclass, QC::IN);
411 assert!(!packet.questions[0].prefer_unicast);
412 assert_eq!(
413 &packet.questions[0].qname.to_string()[..],
414 "_xmpp-server._tcp.gmail.com"
415 );
416 assert_eq!(packet.answers.len(), 0);
417 }
418
419 #[test]
420 fn parse_multicast_prefer_unicast_query() {
421 let query = b"\x06%\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\
422 \x07example\x03com\x00\x00\x01\x80\x01";
423 let packet = Packet::parse(query).unwrap();
424
425 assert_eq!(packet.questions.len(), 1);
426 assert_eq!(packet.questions[0].qtype, QT::A);
427 assert_eq!(packet.questions[0].qclass, QC::IN);
428 assert!(packet.questions[0].prefer_unicast);
429 }
430
431 #[test]
432 fn parse_example_query_edns() {
433 let query = b"\x95\xce\x01\x00\x00\x01\x00\x00\x00\x00\x00\x01\
434 \x06google\x03com\x00\x00\x01\x00\
435 \x01\x00\x00\x29\x10\x00\x00\x00\x00\x00\x00\x00";
436 let packet = Packet::parse(query).unwrap();
437 assert_eq!(
438 packet.header,
439 Header {
440 id: 38350,
441 query: true,
442 opcode: StandardQuery,
443 authoritative: false,
444 truncated: false,
445 recursion_desired: true,
446 recursion_available: false,
447 authenticated_data: false,
448 checking_disabled: false,
449 response_code: NoError,
450 questions: 1,
451 answers: 0,
452 nameservers: 0,
453 additional: 1,
454 }
455 );
456 assert_eq!(packet.questions.len(), 1);
457 assert_eq!(packet.questions[0].qtype, QT::A);
458 assert_eq!(packet.questions[0].qclass, QC::IN);
459 assert_eq!(&packet.questions[0].qname.to_string()[..], "google.com");
460 assert_eq!(packet.answers.len(), 0);
461 match packet.opt {
462 Some(opt) => {
463 assert_eq!(opt.udp, 4096);
464 assert_eq!(opt.extrcode, 0);
465 assert_eq!(opt.version, 0);
466 assert_eq!(opt.flags, 0);
467 }
468 None => panic!("Missing OPT RR"),
469 }
470 }
471}