1use std::i32;
2
3use byteorder::{BigEndian, ByteOrder};
4
5use {Header, Packet, Error, Question, Name, QueryType, QueryClass};
6use {Type, Class, ResourceRecord, OptRecord, RRData};
7
8const OPT_RR_START: [u8; 3] = [0, 0, 41];
9
10impl<'a> Packet<'a> {
11 pub fn parse(data: &[u8]) -> Result<Packet, Error> {
12 let header = try!(Header::parse(data));
13 let mut offset = Header::size();
14 let mut questions = Vec::with_capacity(header.questions as usize);
15 for _ in 0..header.questions {
16 let name = try!(Name::scan(&data[offset..], data));
17 offset += name.byte_len();
18 if offset + 4 > data.len() {
19 return Err(Error::UnexpectedEOF);
20 }
21 let qtype = try!(QueryType::parse(
22 BigEndian::read_u16(&data[offset..offset+2])));
23 offset += 2;
24
25 let (prefer_unicast, qclass) = try!(parse_qclass_code(
26 BigEndian::read_u16(&data[offset..offset+2])));
27 offset += 2;
28
29 questions.push(Question {
30 qname: name,
31 qtype: qtype,
32 prefer_unicast: prefer_unicast,
33 qclass: qclass,
34 });
35 }
36 let mut answers = Vec::with_capacity(header.answers as usize);
37 for _ in 0..header.answers {
38 answers.push(try!(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(try!(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(try!(parse_opt_record(data, &mut offset)));
50 } else {
51 return Err(Error::AdditionalOPT);
52 }
53 } else {
54 additional.push(try!(parse_record(data, &mut offset)));
55 }
56 }
57 Ok(Packet {
58 header: header,
59 questions: questions,
60 answers: answers,
61 nameservers: nameservers,
62 additional: additional,
63 opt: 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 = try!(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 = try!(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 = try!(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 = try!(Type::parse(
92 BigEndian::read_u16(&data[*offset..*offset+2])));
93 *offset += 2;
94
95 let class_code = BigEndian::read_u16(&data[*offset..*offset+2]);
96 let (multicast_unique, cls) = try!(parse_class_code(class_code));
97 *offset += 2;
98
99 let mut ttl = BigEndian::read_u32(&data[*offset..*offset+4]);
100 if ttl > i32::MAX as u32 {
101 ttl = 0;
102 }
103 *offset += 4;
104 let rdlen = BigEndian::read_u16(&data[*offset..*offset+2]) as usize;
105 *offset += 2;
106 if *offset + rdlen > data.len() {
107 return Err(Error::UnexpectedEOF);
108 }
109 let data = try!(RRData::parse(typ,
110 &data[*offset..*offset+rdlen], data));
111 *offset += rdlen;
112 Ok(ResourceRecord {
113 name: name,
114 multicast_unique: multicast_unique,
115 cls: cls,
116 ttl: ttl,
117 data: data,
118 })
119}
120
121fn parse_opt_record<'a>(data: &'a [u8], offset: &mut usize) -> Result<OptRecord<'a>, Error> {
123 if *offset + 11 > data.len() {
124 return Err(Error::UnexpectedEOF);
125 }
126 *offset += 1;
127 let typ = try!(Type::parse(
128 BigEndian::read_u16(&data[*offset..*offset+2])));
129 if typ != Type::OPT {
130 return Err(Error::InvalidType(typ as u16));
131 }
132 *offset += 2;
133 let udp = BigEndian::read_u16(&data[*offset..*offset+2]);
134 *offset += 2;
135 let extrcode = data[*offset];
136 *offset += 1;
137 let version = data[*offset];
138 *offset += 1;
139 let flags = BigEndian::read_u16(&data[*offset..*offset+2]);
140 *offset += 2;
141 let rdlen = BigEndian::read_u16(&data[*offset..*offset+2]) as usize;
142 *offset += 2;
143 if *offset + rdlen > data.len() {
144 return Err(Error::UnexpectedEOF);
145 }
146 let data = try!(RRData::parse(typ,
147 &data[*offset..*offset+rdlen], data));
148 *offset += rdlen;
149
150 Ok(OptRecord {
151 udp: udp,
152 extrcode: extrcode,
153 version: version,
154 flags: flags,
155 data: data,
156 })
157}
158
159#[cfg(test)]
160mod test {
161
162 use std::net::{Ipv4Addr, Ipv6Addr};
163 use {Packet, Header};
164 use Opcode::*;
165 use ResponseCode::{NameError, NoError};
166 use QueryType as QT;
167 use QueryClass as QC;
168 use Class as C;
169 use RRData;
170
171 #[test]
172 fn parse_example_query() {
173 let query = b"\x06%\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\
174 \x07example\x03com\x00\x00\x01\x00\x01";
175 let packet = Packet::parse(query).unwrap();
176 assert_eq!(packet.header, Header {
177 id: 1573,
178 query: true,
179 opcode: StandardQuery,
180 authoritative: false,
181 truncated: false,
182 recursion_desired: true,
183 recursion_available: false,
184 authenticated_data: false,
185 checking_disabled: false,
186 response_code: NoError,
187 questions: 1,
188 answers: 0,
189 nameservers: 0,
190 additional: 0,
191 });
192 assert_eq!(packet.questions.len(), 1);
193 assert_eq!(packet.questions[0].qtype, QT::A);
194 assert_eq!(packet.questions[0].qclass, QC::IN);
195 assert_eq!(&packet.questions[0].qname.to_string()[..], "example.com");
196 assert_eq!(packet.answers.len(), 0);
197 }
198
199 #[test]
200 fn parse_example_response() {
201 let response = b"\x06%\x81\x80\x00\x01\x00\x01\x00\x00\x00\x00\
202 \x07example\x03com\x00\x00\x01\x00\x01\
203 \xc0\x0c\x00\x01\x00\x01\x00\x00\x04\xf8\
204 \x00\x04]\xb8\xd8\"";
205 let packet = Packet::parse(response).unwrap();
206 assert_eq!(packet.header, Header {
207 id: 1573,
208 query: false,
209 opcode: StandardQuery,
210 authoritative: false,
211 truncated: false,
212 recursion_desired: true,
213 recursion_available: true,
214 authenticated_data: false,
215 checking_disabled: false,
216 response_code: NoError,
217 questions: 1,
218 answers: 1,
219 nameservers: 0,
220 additional: 0,
221 });
222 assert_eq!(packet.questions.len(), 1);
223 assert_eq!(packet.questions[0].qtype, QT::A);
224 assert_eq!(packet.questions[0].qclass, QC::IN);
225 assert_eq!(&packet.questions[0].qname.to_string()[..], "example.com");
226 assert_eq!(packet.answers.len(), 1);
227 assert_eq!(&packet.answers[0].name.to_string()[..], "example.com");
228 assert_eq!(packet.answers[0].multicast_unique, false);
229 assert_eq!(packet.answers[0].cls, C::IN);
230 assert_eq!(packet.answers[0].ttl, 1272);
231 match packet.answers[0].data {
232 RRData::A(addr) => {
233 assert_eq!(addr, Ipv4Addr::new(93, 184, 216, 34));
234 }
235 ref x => panic!("Wrong rdata {:?}", x),
236 }
237 }
238
239 #[test]
240 fn parse_txt_response_multiple_strings() {
241 let response = b"\x06%\x81\x80\x00\x01\x00\x01\x00\x00\x00\x00\
242 \x08facebook\x03com\x00\x00\x10\x00\x01\
243 \xc0\x0c\x00\x10\x00\x01\x00\x01\x51\x3d\x00\x23\
244 \x15\x76\x3d\x73\x70\x66\x31\x20\x72\x65\x64\x69\
245 \x72\x65\x63\x74\x3d\x5f\x73\x70\x66\x2e\
246 \x0c\x66\x61\x63\x65\x62\x6f\x6f\x6b\x2e\x63\x6f\x6d";
247
248 let packet = Packet::parse(response).unwrap();
249 assert_eq!(packet.header, Header {
250 id: 1573,
251 query: false,
252 opcode: StandardQuery,
253 authoritative: false,
254 truncated: false,
255 recursion_desired: true,
256 recursion_available: true,
257 authenticated_data: false,
258 checking_disabled: false,
259 response_code: NoError,
260 questions: 1,
261 answers: 1,
262 nameservers: 0,
263 additional: 0,
264 });
265 assert_eq!(packet.questions.len(), 1);
266 assert_eq!(packet.questions[0].qtype, QT::TXT);
267 assert_eq!(packet.questions[0].qclass, QC::IN);
268 assert_eq!(&packet.questions[0].qname.to_string()[..], "facebook.com");
269 assert_eq!(packet.answers.len(), 1);
270 assert_eq!(&packet.answers[0].name.to_string()[..], "facebook.com");
271 assert_eq!(packet.answers[0].multicast_unique, false);
272 assert_eq!(packet.answers[0].cls, C::IN);
273 assert_eq!(packet.answers[0].ttl, 86333);
274 match packet.answers[0].data {
275 RRData::TXT(ref text) => {
276 assert_eq!(text, "v=spf1 redirect=_spf.facebook.com")
277 }
278 ref x => panic!("Wrong rdata {:?}", x),
279 }
280 }
281
282 #[test]
283 fn parse_response_with_multicast_unique() {
284 let response = b"\x06%\x81\x80\x00\x01\x00\x01\x00\x00\x00\x00\
285 \x07example\x03com\x00\x00\x01\x00\x01\
286 \xc0\x0c\x00\x01\x80\x01\x00\x00\x04\xf8\
287 \x00\x04]\xb8\xd8\"";
288 let packet = Packet::parse(response).unwrap();
289
290 assert_eq!(packet.answers.len(), 1);
291 assert_eq!(packet.answers[0].multicast_unique, true);
292 assert_eq!(packet.answers[0].cls, C::IN);
293 }
294
295 #[test]
296 fn parse_ns_response() {
297 let response = b"\x4a\xf0\x81\x80\x00\x01\x00\x01\x00\x01\x00\x00\
298 \x03www\x05skype\x03com\x00\x00\x01\x00\x01\
299 \xc0\x0c\x00\x05\x00\x01\x00\x00\x0e\x10\
300 \x00\x1c\x07\x6c\x69\x76\x65\x63\x6d\x73\x0e\x74\
301 \x72\x61\x66\x66\x69\x63\x6d\x61\x6e\x61\x67\x65\
302 \x72\x03\x6e\x65\x74\x00\
303 \xc0\x42\x00\x02\x00\x01\x00\x01\xd5\xd3\x00\x11\
304 \x01\x67\x0c\x67\x74\x6c\x64\x2d\x73\x65\x72\x76\x65\x72\x73\
305 \xc0\x42";
306 let packet = Packet::parse(response).unwrap();
307 assert_eq!(packet.header, Header {
308 id: 19184,
309 query: false,
310 opcode: StandardQuery,
311 authoritative: false,
312 truncated: false,
313 recursion_desired: true,
314 recursion_available: true,
315 authenticated_data: false,
316 checking_disabled: false,
317 response_code: NoError,
318 questions: 1,
319 answers: 1,
320 nameservers: 1,
321 additional: 0,
322 });
323 assert_eq!(packet.questions.len(), 1);
324 assert_eq!(packet.questions[0].qtype, QT::A);
325 assert_eq!(packet.questions[0].qclass, QC::IN);
326 assert_eq!(&packet.questions[0].qname.to_string()[..], "www.skype.com");
327 assert_eq!(packet.answers.len(), 1);
328 assert_eq!(&packet.answers[0].name.to_string()[..], "www.skype.com");
329 assert_eq!(packet.answers[0].cls, C::IN);
330 assert_eq!(packet.answers[0].ttl, 3600);
331 match packet.answers[0].data {
332 RRData::CNAME(cname) => {
333 assert_eq!(&cname.to_string()[..], "livecms.trafficmanager.net");
334 }
335 ref x => panic!("Wrong rdata {:?}", x),
336 }
337 assert_eq!(packet.nameservers.len(), 1);
338 assert_eq!(&packet.nameservers[0].name.to_string()[..], "net");
339 assert_eq!(packet.nameservers[0].cls, C::IN);
340 assert_eq!(packet.nameservers[0].ttl, 120275);
341 match packet.nameservers[0].data {
342 RRData::NS(ns) => {
343 assert_eq!(&ns.to_string()[..], "g.gtld-servers.net");
344 }
345 ref x => panic!("Wrong rdata {:?}", x),
346 }
347 }
348
349 #[test]
350 fn parse_soa_response() {
351 let response = b"\x9f\xc5\x85\x83\x00\x01\x00\x00\x00\x01\x00\x00\
352 \x0edlkfjkdjdslfkj\x07youtube\x03com\x00\x00\x01\x00\x01\
353 \xc0\x1b\x00\x06\x00\x01\x00\x00\x2a\x30\x00\x1e\xc0\x1b\
354 \x05admin\xc0\x1b\x77\xed\x2a\x73\x00\x00\x51\x80\x00\x00\
355 \x0e\x10\x00\x00\x3a\x80\x00\x00\x2a\x30";
356 let packet = Packet::parse(response).unwrap();
357 assert_eq!(packet.header, Header {
358 id: 40901,
359 query: false,
360 opcode: StandardQuery,
361 authoritative: true,
362 truncated: false,
363 recursion_desired: true,
364 recursion_available: true,
365 authenticated_data: false,
366 checking_disabled: false,
367 response_code: NameError,
368 questions: 1,
369 answers: 0,
370 nameservers: 1,
371 additional: 0,
372 });
373 assert_eq!(packet.questions.len(), 1);
374 assert_eq!(packet.questions[0].qtype, QT::A);
375 assert_eq!(packet.questions[0].qclass, QC::IN);
376 assert_eq!(&packet.questions[0].qname.to_string()[..], "dlkfjkdjdslfkj.youtube.com");
377 assert_eq!(packet.answers.len(), 0);
378
379 assert_eq!(packet.nameservers.len(), 1);
380 assert_eq!(&packet.nameservers[0].name.to_string()[..], "youtube.com");
381 assert_eq!(packet.nameservers[0].cls, C::IN);
382 assert_eq!(packet.nameservers[0].multicast_unique, false);
383 assert_eq!(packet.nameservers[0].ttl, 10800);
384 match packet.nameservers[0].data {
385 RRData::SOA(ref soa_rec) => {
386 assert_eq!(&soa_rec.primary_ns.to_string()[..], "youtube.com");
387 assert_eq!(&soa_rec.mailbox.to_string()[..], "admin.youtube.com");
388 assert_eq!(soa_rec.serial, 2012031603);
389 assert_eq!(soa_rec.refresh, 20864);
390 assert_eq!(soa_rec.retry, 3600);
391 assert_eq!(soa_rec.expire, 14976);
392 assert_eq!(soa_rec.minimum_ttl, 10800);
393 }
394 ref x => panic!("Wrong rdata {:?}", x),
395 }
396 }
397 #[test]
398 fn parse_ptr_response() {
399 let response = b"\x53\xd6\x81\x80\x00\x01\x00\x01\x00\x00\x00\x00\
400 \x0269\x0293\x0275\x0272\x07in-addr\x04arpa\x00\
401 \x00\x0c\x00\x01\
402 \xc0\x0c\x00\x0c\x00\x01\x00\x01\x51\x80\x00\x1e\
403 \x10pool-72-75-93-69\x07verizon\x03net\x00";
404 let packet = Packet::parse(response).unwrap();
405 assert_eq!(packet.header, Header {
406 id: 21462,
407 query: false,
408 opcode: StandardQuery,
409 authoritative: false,
410 truncated: false,
411 recursion_desired: true,
412 recursion_available: true,
413 authenticated_data: false,
414 checking_disabled: false,
415 response_code: NoError,
416 questions: 1,
417 answers: 1,
418 nameservers: 0,
419 additional: 0,
420 });
421 assert_eq!(packet.questions.len(), 1);
422 assert_eq!(packet.questions[0].qtype, QT::PTR);
423 assert_eq!(packet.questions[0].qclass, QC::IN);
424 assert_eq!(&packet.questions[0].qname.to_string()[..], "69.93.75.72.in-addr.arpa");
425 assert_eq!(packet.answers.len(), 1);
426 assert_eq!(&packet.answers[0].name.to_string()[..], "69.93.75.72.in-addr.arpa");
427 assert_eq!(packet.answers[0].cls, C::IN);
428 assert_eq!(packet.answers[0].ttl, 86400);
429 match packet.answers[0].data {
430 RRData::PTR(name) => {
431 assert_eq!(&name.to_string()[..], "pool-72-75-93-69.verizon.net");
432 }
433 ref x => panic!("Wrong rdata {:?}", x),
434 }
435 }
436
437 #[test]
438 fn parse_additional_record_response() {
439 let response = b"\x4a\xf0\x81\x80\x00\x01\x00\x01\x00\x01\x00\x01\
440 \x03www\x05skype\x03com\x00\x00\x01\x00\x01\
441 \xc0\x0c\x00\x05\x00\x01\x00\x00\x0e\x10\
442 \x00\x1c\x07\x6c\x69\x76\x65\x63\x6d\x73\x0e\x74\
443 \x72\x61\x66\x66\x69\x63\x6d\x61\x6e\x61\x67\x65\
444 \x72\x03\x6e\x65\x74\x00\
445 \xc0\x42\x00\x02\x00\x01\x00\x01\xd5\xd3\x00\x11\
446 \x01\x67\x0c\x67\x74\x6c\x64\x2d\x73\x65\x72\x76\x65\x72\x73\
447 \xc0\x42\
448 \x01\x61\xc0\x55\x00\x01\x00\x01\x00\x00\xa3\x1c\
449 \x00\x04\xc0\x05\x06\x1e";
450 let packet = Packet::parse(response).unwrap();
451 assert_eq!(packet.header, Header {
452 id: 19184,
453 query: false,
454 opcode: StandardQuery,
455 authoritative: false,
456 truncated: false,
457 recursion_desired: true,
458 recursion_available: true,
459 authenticated_data: false,
460 checking_disabled: false,
461 response_code: NoError,
462 questions: 1,
463 answers: 1,
464 nameservers: 1,
465 additional: 1,
466 });
467 assert_eq!(packet.questions.len(), 1);
468 assert_eq!(packet.questions[0].qtype, QT::A);
469 assert_eq!(packet.questions[0].qclass, QC::IN);
470 assert_eq!(&packet.questions[0].qname.to_string()[..], "www.skype.com");
471 assert_eq!(packet.answers.len(), 1);
472 assert_eq!(&packet.answers[0].name.to_string()[..], "www.skype.com");
473 assert_eq!(packet.answers[0].cls, C::IN);
474 assert_eq!(packet.answers[0].ttl, 3600);
475 match packet.answers[0].data {
476 RRData::CNAME(cname) => {
477 assert_eq!(&cname.to_string()[..], "livecms.trafficmanager.net");
478 }
479 ref x => panic!("Wrong rdata {:?}", x),
480 }
481 assert_eq!(packet.nameservers.len(), 1);
482 assert_eq!(&packet.nameservers[0].name.to_string()[..], "net");
483 assert_eq!(packet.nameservers[0].cls, C::IN);
484 assert_eq!(packet.nameservers[0].ttl, 120275);
485 match packet.nameservers[0].data {
486 RRData::NS(ns) => {
487 assert_eq!(&ns.to_string()[..], "g.gtld-servers.net");
488 }
489 ref x => panic!("Wrong rdata {:?}", x),
490 }
491 assert_eq!(packet.additional.len(), 1);
492 assert_eq!(&packet.additional[0].name.to_string()[..], "a.gtld-servers.net");
493 assert_eq!(packet.additional[0].cls, C::IN);
494 assert_eq!(packet.additional[0].ttl, 41756);
495 match packet.additional[0].data {
496 RRData::A(addr) => {
497 assert_eq!(addr, Ipv4Addr::new(192, 5, 6, 30));
498 }
499 ref x => panic!("Wrong rdata {:?}", x),
500 }
501 }
502
503 #[test]
504 fn parse_multiple_answers() {
505 let response = b"\x9d\xe9\x81\x80\x00\x01\x00\x06\x00\x00\x00\x00\
506 \x06google\x03com\x00\x00\x01\x00\x01\xc0\x0c\
507 \x00\x01\x00\x01\x00\x00\x00\xef\x00\x04@\xe9\
508 \xa4d\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\xef\
509 \x00\x04@\xe9\xa4\x8b\xc0\x0c\x00\x01\x00\x01\
510 \x00\x00\x00\xef\x00\x04@\xe9\xa4q\xc0\x0c\x00\
511 \x01\x00\x01\x00\x00\x00\xef\x00\x04@\xe9\xa4f\
512 \xc0\x0c\x00\x01\x00\x01\x00\x00\x00\xef\x00\x04@\
513 \xe9\xa4e\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\xef\
514 \x00\x04@\xe9\xa4\x8a";
515 let packet = Packet::parse(response).unwrap();
516 assert_eq!(packet.header, Header {
517 id: 40425,
518 query: false,
519 opcode: StandardQuery,
520 authoritative: false,
521 truncated: false,
522 recursion_desired: true,
523 recursion_available: true,
524 authenticated_data: false,
525 checking_disabled: false,
526 response_code: NoError,
527 questions: 1,
528 answers: 6,
529 nameservers: 0,
530 additional: 0,
531 });
532 assert_eq!(packet.questions.len(), 1);
533 assert_eq!(packet.questions[0].qtype, QT::A);
534 assert_eq!(packet.questions[0].qclass, QC::IN);
535 assert_eq!(&packet.questions[0].qname.to_string()[..], "google.com");
536 assert_eq!(packet.answers.len(), 6);
537 let ips = vec![
538 Ipv4Addr::new(64, 233, 164, 100),
539 Ipv4Addr::new(64, 233, 164, 139),
540 Ipv4Addr::new(64, 233, 164, 113),
541 Ipv4Addr::new(64, 233, 164, 102),
542 Ipv4Addr::new(64, 233, 164, 101),
543 Ipv4Addr::new(64, 233, 164, 138),
544 ];
545 for i in 0..6 {
546 assert_eq!(&packet.answers[i].name.to_string()[..], "google.com");
547 assert_eq!(packet.answers[i].cls, C::IN);
548 assert_eq!(packet.answers[i].ttl, 239);
549 match packet.answers[i].data {
550 RRData::A(addr) => {
551 assert_eq!(addr, ips[i]);
552 }
553 ref x => panic!("Wrong rdata {:?}", x),
554 }
555 }
556 }
557
558 #[test]
559 fn parse_srv_query() {
560 let query = b"[\xd9\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\
561 \x0c_xmpp-server\x04_tcp\x05gmail\x03com\x00\x00!\x00\x01";
562 let packet = Packet::parse(query).unwrap();
563 assert_eq!(packet.header, Header {
564 id: 23513,
565 query: true,
566 opcode: StandardQuery,
567 authoritative: false,
568 truncated: false,
569 recursion_desired: true,
570 recursion_available: false,
571 authenticated_data: false,
572 checking_disabled: false,
573 response_code: NoError,
574 questions: 1,
575 answers: 0,
576 nameservers: 0,
577 additional: 0,
578 });
579 assert_eq!(packet.questions.len(), 1);
580 assert_eq!(packet.questions[0].qtype, QT::SRV);
581 assert_eq!(packet.questions[0].qclass, QC::IN);
582 assert_eq!(packet.questions[0].prefer_unicast, false);
583 assert_eq!(&packet.questions[0].qname.to_string()[..],
584 "_xmpp-server._tcp.gmail.com");
585 assert_eq!(packet.answers.len(), 0);
586 }
587
588 #[test]
589 fn parse_multicast_prefer_unicast_query() {
590 let query = b"\x06%\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\
591 \x07example\x03com\x00\x00\x01\x80\x01";
592 let packet = Packet::parse(query).unwrap();
593
594 assert_eq!(packet.questions.len(), 1);
595 assert_eq!(packet.questions[0].qtype, QT::A);
596 assert_eq!(packet.questions[0].qclass, QC::IN);
597 assert_eq!(packet.questions[0].prefer_unicast, true);
598 }
599
600 #[test]
601 fn parse_srv_response() {
602 let response = b"[\xd9\x81\x80\x00\x01\x00\x05\x00\x00\x00\x00\
603 \x0c_xmpp-server\x04_tcp\x05gmail\x03com\x00\x00!\x00\x01\
604 \xc0\x0c\x00!\x00\x01\x00\x00\x03\x84\x00 \x00\x05\x00\x00\
605 \x14\x95\x0bxmpp-server\x01l\x06google\x03com\x00\xc0\x0c\x00!\
606 \x00\x01\x00\x00\x03\x84\x00%\x00\x14\x00\x00\x14\x95\
607 \x04alt3\x0bxmpp-server\x01l\x06google\x03com\x00\
608 \xc0\x0c\x00!\x00\x01\x00\x00\x03\x84\x00%\x00\x14\x00\x00\
609 \x14\x95\x04alt1\x0bxmpp-server\x01l\x06google\x03com\x00\
610 \xc0\x0c\x00!\x00\x01\x00\x00\x03\x84\x00%\x00\x14\x00\x00\
611 \x14\x95\x04alt2\x0bxmpp-server\x01l\x06google\x03com\x00\
612 \xc0\x0c\x00!\x00\x01\x00\x00\x03\x84\x00%\x00\x14\x00\x00\
613 \x14\x95\x04alt4\x0bxmpp-server\x01l\x06google\x03com\x00";
614 let packet = Packet::parse(response).unwrap();
615 assert_eq!(packet.header, Header {
616 id: 23513,
617 query: false,
618 opcode: StandardQuery,
619 authoritative: false,
620 truncated: false,
621 recursion_desired: true,
622 recursion_available: true,
623 authenticated_data: false,
624 checking_disabled: false,
625 response_code: NoError,
626 questions: 1,
627 answers: 5,
628 nameservers: 0,
629 additional: 0,
630 });
631 assert_eq!(packet.questions.len(), 1);
632 assert_eq!(packet.questions[0].qtype, QT::SRV);
633 assert_eq!(packet.questions[0].qclass, QC::IN);
634 assert_eq!(&packet.questions[0].qname.to_string()[..],
635 "_xmpp-server._tcp.gmail.com");
636 assert_eq!(packet.answers.len(), 5);
637 let items = vec![
638 (5, 0, 5269, "xmpp-server.l.google.com"),
639 (20, 0, 5269, "alt3.xmpp-server.l.google.com"),
640 (20, 0, 5269, "alt1.xmpp-server.l.google.com"),
641 (20, 0, 5269, "alt2.xmpp-server.l.google.com"),
642 (20, 0, 5269, "alt4.xmpp-server.l.google.com"),
643 ];
644 for i in 0..5 {
645 assert_eq!(&packet.answers[i].name.to_string()[..],
646 "_xmpp-server._tcp.gmail.com");
647 assert_eq!(packet.answers[i].cls, C::IN);
648 assert_eq!(packet.answers[i].ttl, 900);
649 match *&packet.answers[i].data {
650 RRData::SRV { priority, weight, port, target } => {
651 assert_eq!(priority, items[i].0);
652 assert_eq!(weight, items[i].1);
653 assert_eq!(port, items[i].2);
654 assert_eq!(target.to_string(), (items[i].3).to_string());
655 }
656 ref x => panic!("Wrong rdata {:?}", x),
657 }
658 }
659 }
660
661 #[test]
662 fn parse_mx_response() {
663 let response = b"\xe3\xe8\x81\x80\x00\x01\x00\x05\x00\x00\x00\x00\
664 \x05gmail\x03com\x00\x00\x0f\x00\x01\xc0\x0c\x00\x0f\x00\x01\
665 \x00\x00\x04|\x00\x1b\x00\x05\rgmail-smtp-in\x01l\x06google\xc0\
666 \x12\xc0\x0c\x00\x0f\x00\x01\x00\x00\x04|\x00\t\x00\
667 \n\x04alt1\xc0)\xc0\x0c\x00\x0f\x00\x01\x00\x00\x04|\
668 \x00\t\x00(\x04alt4\xc0)\xc0\x0c\x00\x0f\x00\x01\x00\
669 \x00\x04|\x00\t\x00\x14\x04alt2\xc0)\xc0\x0c\x00\x0f\
670 \x00\x01\x00\x00\x04|\x00\t\x00\x1e\x04alt3\xc0)";
671 let packet = Packet::parse(response).unwrap();
672 assert_eq!(packet.header, Header {
673 id: 58344,
674 query: false,
675 opcode: StandardQuery,
676 authoritative: false,
677 truncated: false,
678 recursion_desired: true,
679 recursion_available: true,
680 authenticated_data: false,
681 checking_disabled: false,
682 response_code: NoError,
683 questions: 1,
684 answers: 5,
685 nameservers: 0,
686 additional: 0,
687 });
688 assert_eq!(packet.questions.len(), 1);
689 assert_eq!(packet.questions[0].qtype, QT::MX);
690 assert_eq!(packet.questions[0].qclass, QC::IN);
691 assert_eq!(&packet.questions[0].qname.to_string()[..],
692 "gmail.com");
693 assert_eq!(packet.answers.len(), 5);
694 let items = vec![
695 ( 5, "gmail-smtp-in.l.google.com"),
696 (10, "alt1.gmail-smtp-in.l.google.com"),
697 (40, "alt4.gmail-smtp-in.l.google.com"),
698 (20, "alt2.gmail-smtp-in.l.google.com"),
699 (30, "alt3.gmail-smtp-in.l.google.com"),
700 ];
701 for i in 0..5 {
702 assert_eq!(&packet.answers[i].name.to_string()[..],
703 "gmail.com");
704 assert_eq!(packet.answers[i].cls, C::IN);
705 assert_eq!(packet.answers[i].ttl, 1148);
706 match *&packet.answers[i].data {
707 RRData::MX { preference, exchange } => {
708 assert_eq!(preference, items[i].0);
709 assert_eq!(exchange.to_string(), (items[i].1).to_string());
710 }
711 ref x => panic!("Wrong rdata {:?}", x),
712 }
713 }
714 }
715
716 #[test]
717 fn parse_aaaa_response() {
718 let response = b"\xa9\xd9\x81\x80\x00\x01\x00\x01\x00\x00\x00\x00\x06\
719 google\x03com\x00\x00\x1c\x00\x01\xc0\x0c\x00\x1c\x00\x01\x00\x00\
720 \x00\x8b\x00\x10*\x00\x14P@\t\x08\x12\x00\x00\x00\x00\x00\x00 \x0e";
721
722 let packet = Packet::parse(response).unwrap();
723 assert_eq!(packet.header, Header {
724 id: 43481,
725 query: false,
726 opcode: StandardQuery,
727 authoritative: false,
728 truncated: false,
729 recursion_desired: true,
730 recursion_available: true,
731 authenticated_data: false,
732 checking_disabled: false,
733 response_code: NoError,
734 questions: 1,
735 answers: 1,
736 nameservers: 0,
737 additional: 0,
738 });
739
740 assert_eq!(packet.questions.len(), 1);
741 assert_eq!(packet.questions[0].qtype, QT::AAAA);
742 assert_eq!(packet.questions[0].qclass, QC::IN);
743 assert_eq!(&packet.questions[0].qname.to_string()[..], "google.com");
744 assert_eq!(packet.answers.len(), 1);
745 assert_eq!(&packet.answers[0].name.to_string()[..], "google.com");
746 assert_eq!(packet.answers[0].cls, C::IN);
747 assert_eq!(packet.answers[0].ttl, 139);
748 match packet.answers[0].data {
749 RRData::AAAA(addr) => {
750 assert_eq!(addr, Ipv6Addr::new(
751 0x2A00, 0x1450, 0x4009, 0x812, 0, 0, 0, 0x200e)
752 );
753 }
754 ref x => panic!("Wrong rdata {:?}", x),
755 }
756 }
757
758 #[test]
759 fn parse_cname_response() {
760 let response = b"\xfc\x9d\x81\x80\x00\x01\x00\x06\x00\x02\x00\x02\x03\
761 cdn\x07sstatic\x03net\x00\x00\x01\x00\x01\xc0\x0c\x00\x05\x00\x01\
762 \x00\x00\x00f\x00\x02\xc0\x10\xc0\x10\x00\x01\x00\x01\x00\x00\x00\
763 f\x00\x04h\x10g\xcc\xc0\x10\x00\x01\x00\x01\x00\x00\x00f\x00\x04h\
764 \x10k\xcc\xc0\x10\x00\x01\x00\x01\x00\x00\x00f\x00\x04h\x10h\xcc\
765 \xc0\x10\x00\x01\x00\x01\x00\x00\x00f\x00\x04h\x10j\xcc\xc0\x10\
766 \x00\x01\x00\x01\x00\x00\x00f\x00\x04h\x10i\xcc\xc0\x10\x00\x02\
767 \x00\x01\x00\x00\x99L\x00\x0b\x08cf-dns02\xc0\x10\xc0\x10\x00\x02\
768 \x00\x01\x00\x00\x99L\x00\x0b\x08cf-dns01\xc0\x10\xc0\xa2\x00\x01\
769 \x00\x01\x00\x00\x99L\x00\x04\xad\xf5:5\xc0\x8b\x00\x01\x00\x01\x00\
770 \x00\x99L\x00\x04\xad\xf5;\x04";
771
772 let packet = Packet::parse(response).unwrap();
773 assert_eq!(packet.header, Header {
774 id: 64669,
775 query: false,
776 opcode: StandardQuery,
777 authoritative: false,
778 truncated: false,
779 recursion_desired: true,
780 recursion_available: true,
781 authenticated_data: false,
782 checking_disabled: false,
783 response_code: NoError,
784 questions: 1,
785 answers: 6,
786 nameservers: 2,
787 additional: 2,
788 });
789
790 assert_eq!(packet.questions.len(), 1);
791 assert_eq!(packet.questions[0].qtype, QT::A);
792 assert_eq!(packet.questions[0].qclass, QC::IN);
793 assert_eq!(&packet.questions[0].qname.to_string()[..], "cdn.sstatic.net");
794 assert_eq!(packet.answers.len(), 6);
795 assert_eq!(&packet.answers[0].name.to_string()[..], "cdn.sstatic.net");
796 assert_eq!(packet.answers[0].cls, C::IN);
797 assert_eq!(packet.answers[0].ttl, 102);
798 match packet.answers[0].data {
799 RRData::CNAME(cname) => {
800 assert_eq!(&cname.to_string(), "sstatic.net");
801 }
802 ref x => panic!("Wrong rdata {:?}", x),
803 }
804
805 let ips = vec![
806 Ipv4Addr::new(104, 16, 103, 204),
807 Ipv4Addr::new(104, 16, 107, 204),
808 Ipv4Addr::new(104, 16, 104, 204),
809 Ipv4Addr::new(104, 16, 106, 204),
810 Ipv4Addr::new(104, 16, 105, 204),
811 ];
812 for i in 1..6 {
813 assert_eq!(&packet.answers[i].name.to_string()[..], "sstatic.net");
814 assert_eq!(packet.answers[i].cls, C::IN);
815 assert_eq!(packet.answers[i].ttl, 102);
816 match packet.answers[i].data {
817 RRData::A(addr) => {
818 assert_eq!(addr, ips[i-1]);
819 }
820 ref x => panic!("Wrong rdata {:?}", x),
821 }
822 }
823 }
824
825 #[test]
826 fn parse_example_query_edns() {
827 let query = b"\x95\xce\x01\x00\x00\x01\x00\x00\x00\x00\x00\x01\
828 \x06google\x03com\x00\x00\x01\x00\
829 \x01\x00\x00\x29\x10\x00\x00\x00\x00\x00\x00\x00";
830 let packet = Packet::parse(query).unwrap();
831 assert_eq!(packet.header, Header {
832 id: 38350,
833 query: true,
834 opcode: StandardQuery,
835 authoritative: false,
836 truncated: false,
837 recursion_desired: true,
838 recursion_available: false,
839 authenticated_data: false,
840 checking_disabled: false,
841 response_code: NoError,
842 questions: 1,
843 answers: 0,
844 nameservers: 0,
845 additional: 1,
846 });
847 assert_eq!(packet.questions.len(), 1);
848 assert_eq!(packet.questions[0].qtype, QT::A);
849 assert_eq!(packet.questions[0].qclass, QC::IN);
850 assert_eq!(&packet.questions[0].qname.to_string()[..], "google.com");
851 assert_eq!(packet.answers.len(), 0);
852 match packet.opt {
853 Some(opt) => {
854 assert_eq!(opt.udp, 4096);
855 assert_eq!(opt.extrcode, 0);
856 assert_eq!(opt.version, 0);
857 assert_eq!(opt.flags, 0);
858 },
859 None => panic!("Missing OPT RR")
860 }
861 }
862}