1 use std::i32;
2
3 use byteorder::{BigEndian, ByteOrder};
4
5 use super::{Header, Packet, Error, Question, Name, QueryType, QueryClass};
6 use super::{Type, Class, ResourceRecord, RRData};
7
8
9 impl<'a> Packet<'a> {
parse(data: &[u8]) -> Result<Packet, Error>10 pub fn parse(data: &[u8]) -> Result<Packet, Error> {
11 let header = try!(Header::parse(data));
12 let mut offset = Header::size();
13 let mut questions = Vec::with_capacity(header.questions as usize);
14 for _ in 0..header.questions {
15 let (name, name_size) = try!(Name::scan(&data[offset..], data));
16 offset += name_size;
17 if offset + 4 > data.len() {
18 return Err(Error::UnexpectedEOF);
19 }
20 let qtype = try!(QueryType::parse(
21 BigEndian::read_u16(&data[offset..offset+2])));
22 offset += 2;
23 let qclass_qu = BigEndian::read_u16(&data[offset..offset+2]);
24 let qclass = try!(QueryClass::parse(qclass_qu & 0x7fff));
25 let qu = (qclass_qu & 0x8000) != 0;
26
27 offset += 2;
28 questions.push(Question {
29 qname: name,
30 qtype: qtype,
31 qclass: qclass,
32 qu: qu,
33 });
34 }
35 let mut answers = Vec::with_capacity(header.answers as usize);
36 for _ in 0..header.answers {
37 answers.push(try!(parse_record(data, &mut offset)));
38 }
39 let mut nameservers = Vec::with_capacity(header.nameservers as usize);
40 for _ in 0..header.nameservers {
41 nameservers.push(try!(parse_record(data, &mut offset)));
42 }
43 Ok(Packet {
44 header: header,
45 questions: questions,
46 answers: answers,
47 nameservers: nameservers,
48 additional: Vec::new(), // TODO(tailhook)
49 })
50 }
51 }
52
53 // Generic function to parse answer, nameservers, and additional records.
parse_record<'a>(data: &'a [u8], offset: &mut usize) -> Result<ResourceRecord<'a>, Error>54 fn parse_record<'a>(data: &'a [u8], offset: &mut usize) -> Result<ResourceRecord<'a>, Error> {
55 let (name, name_size) = try!(Name::scan(&data[*offset..], data));
56 *offset += name_size;
57 if *offset + 10 > data.len() {
58 return Err(Error::UnexpectedEOF);
59 }
60 let typ = try!(Type::parse(
61 BigEndian::read_u16(&data[*offset..*offset+2])));
62 *offset += 2;
63 let cls = try!(Class::parse(
64 BigEndian::read_u16(&data[*offset..*offset+2]) & 0x7fff ));
65 *offset += 2;
66 let mut ttl = BigEndian::read_u32(&data[*offset..*offset+4]);
67 if ttl > i32::MAX as u32 {
68 ttl = 0;
69 }
70 *offset += 4;
71 let rdlen = BigEndian::read_u16(&data[*offset..*offset+2]) as usize;
72 *offset += 2;
73 if *offset + rdlen > data.len() {
74 return Err(Error::UnexpectedEOF);
75 }
76 let data = try!(RRData::parse(typ,
77 &data[*offset..*offset+rdlen], data));
78 *offset += rdlen;
79 Ok(ResourceRecord {
80 name: name,
81 cls: cls,
82 ttl: ttl,
83 data: data,
84 })
85 }
86
87 #[cfg(test)]
88 mod test {
89
90 use std::net::{Ipv4Addr, Ipv6Addr};
91 use {super::Packet, super::Header};
92 use super::super::Opcode::*;
93 use super::super::ResponseCode::NoError;
94 use super::QueryType as QT;
95 use super::QueryClass as QC;
96 use super::Class as C;
97 use super::RRData;
98
99 #[test]
parse_example_query()100 fn parse_example_query() {
101 let query = b"\x06%\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\
102 \x07example\x03com\x00\x00\x01\x00\x01";
103 let packet = Packet::parse(query).unwrap();
104 assert_eq!(packet.header, Header {
105 id: 1573,
106 query: true,
107 opcode: StandardQuery,
108 authoritative: false,
109 truncated: false,
110 recursion_desired: true,
111 recursion_available: false,
112 response_code: NoError,
113 questions: 1,
114 answers: 0,
115 nameservers: 0,
116 additional: 0,
117 });
118 assert_eq!(packet.questions.len(), 1);
119 assert_eq!(packet.questions[0].qtype, QT::A);
120 assert_eq!(packet.questions[0].qclass, QC::IN);
121 assert_eq!(&packet.questions[0].qname.to_string()[..], "example.com");
122 assert_eq!(packet.answers.len(), 0);
123 }
124
125 #[test]
parse_example_response()126 fn parse_example_response() {
127 let response = b"\x06%\x81\x80\x00\x01\x00\x01\x00\x00\x00\x00\
128 \x07example\x03com\x00\x00\x01\x00\x01\
129 \xc0\x0c\x00\x01\x00\x01\x00\x00\x04\xf8\
130 \x00\x04]\xb8\xd8\"";
131 let packet = Packet::parse(response).unwrap();
132 assert_eq!(packet.header, Header {
133 id: 1573,
134 query: false,
135 opcode: StandardQuery,
136 authoritative: false,
137 truncated: false,
138 recursion_desired: true,
139 recursion_available: true,
140 response_code: NoError,
141 questions: 1,
142 answers: 1,
143 nameservers: 0,
144 additional: 0,
145 });
146 assert_eq!(packet.questions.len(), 1);
147 assert_eq!(packet.questions[0].qtype, QT::A);
148 assert_eq!(packet.questions[0].qclass, QC::IN);
149 assert_eq!(&packet.questions[0].qname.to_string()[..], "example.com");
150 assert_eq!(packet.answers.len(), 1);
151 assert_eq!(&packet.answers[0].name.to_string()[..], "example.com");
152 assert_eq!(packet.answers[0].cls, C::IN);
153 assert_eq!(packet.answers[0].ttl, 1272);
154 match packet.answers[0].data {
155 RRData::A(addr) => {
156 assert_eq!(addr, Ipv4Addr::new(93, 184, 216, 34));
157 }
158 ref x => panic!("Wrong rdata {:?}", x),
159 }
160 }
161
162 #[test]
parse_ns_response()163 fn parse_ns_response() {
164 let response = b"\x4a\xf0\x81\x80\x00\x01\x00\x01\x00\x01\x00\x00\
165 \x03www\x05skype\x03com\x00\x00\x01\x00\x01\
166 \xc0\x0c\x00\x05\x00\x01\x00\x00\x0e\x10\
167 \x00\x1c\x07\x6c\x69\x76\x65\x63\x6d\x73\x0e\x74\
168 \x72\x61\x66\x66\x69\x63\x6d\x61\x6e\x61\x67\x65\
169 \x72\x03\x6e\x65\x74\x00\
170 \xc0\x42\x00\x02\x00\x01\x00\x01\xd5\xd3\x00\x11\
171 \x01\x67\x0c\x67\x74\x6c\x64\x2d\x73\x65\x72\x76\x65\x72\x73\
172 \xc0\x42";
173 let packet = Packet::parse(response).unwrap();
174 assert_eq!(packet.header, Header {
175 id: 19184,
176 query: false,
177 opcode: StandardQuery,
178 authoritative: false,
179 truncated: false,
180 recursion_desired: true,
181 recursion_available: true,
182 response_code: NoError,
183 questions: 1,
184 answers: 1,
185 nameservers: 1,
186 additional: 0,
187 });
188 assert_eq!(packet.questions.len(), 1);
189 assert_eq!(packet.questions[0].qtype, QT::A);
190 assert_eq!(packet.questions[0].qclass, QC::IN);
191 assert_eq!(&packet.questions[0].qname.to_string()[..], "www.skype.com");
192 assert_eq!(packet.answers.len(), 1);
193 assert_eq!(&packet.answers[0].name.to_string()[..], "www.skype.com");
194 assert_eq!(packet.answers[0].cls, C::IN);
195 assert_eq!(packet.answers[0].ttl, 3600);
196 match packet.answers[0].data {
197 RRData::CNAME(ref cname) => {
198 assert_eq!(&cname.to_string()[..], "livecms.trafficmanager.net");
199 }
200 ref x => panic!("Wrong rdata {:?}", x),
201 }
202 assert_eq!(packet.nameservers.len(), 1);
203 assert_eq!(&packet.nameservers[0].name.to_string()[..], "net");
204 assert_eq!(packet.nameservers[0].cls, C::IN);
205 assert_eq!(packet.nameservers[0].ttl, 120275);
206 match packet.nameservers[0].data {
207 RRData::NS(ref ns) => {
208 assert_eq!(&ns.to_string()[..], "g.gtld-servers.net");
209 }
210 ref x => panic!("Wrong rdata {:?}", x),
211 }
212 }
213
214 #[test]
parse_multiple_answers()215 fn parse_multiple_answers() {
216 let response = b"\x9d\xe9\x81\x80\x00\x01\x00\x06\x00\x00\x00\x00\
217 \x06google\x03com\x00\x00\x01\x00\x01\xc0\x0c\
218 \x00\x01\x00\x01\x00\x00\x00\xef\x00\x04@\xe9\
219 \xa4d\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\xef\
220 \x00\x04@\xe9\xa4\x8b\xc0\x0c\x00\x01\x00\x01\
221 \x00\x00\x00\xef\x00\x04@\xe9\xa4q\xc0\x0c\x00\
222 \x01\x00\x01\x00\x00\x00\xef\x00\x04@\xe9\xa4f\
223 \xc0\x0c\x00\x01\x00\x01\x00\x00\x00\xef\x00\x04@\
224 \xe9\xa4e\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\xef\
225 \x00\x04@\xe9\xa4\x8a";
226 let packet = Packet::parse(response).unwrap();
227 assert_eq!(packet.header, Header {
228 id: 40425,
229 query: false,
230 opcode: StandardQuery,
231 authoritative: false,
232 truncated: false,
233 recursion_desired: true,
234 recursion_available: true,
235 response_code: NoError,
236 questions: 1,
237 answers: 6,
238 nameservers: 0,
239 additional: 0,
240 });
241 assert_eq!(packet.questions.len(), 1);
242 assert_eq!(packet.questions[0].qtype, QT::A);
243 assert_eq!(packet.questions[0].qclass, QC::IN);
244 assert_eq!(&packet.questions[0].qname.to_string()[..], "google.com");
245 assert_eq!(packet.answers.len(), 6);
246 let ips = vec![
247 Ipv4Addr::new(64, 233, 164, 100),
248 Ipv4Addr::new(64, 233, 164, 139),
249 Ipv4Addr::new(64, 233, 164, 113),
250 Ipv4Addr::new(64, 233, 164, 102),
251 Ipv4Addr::new(64, 233, 164, 101),
252 Ipv4Addr::new(64, 233, 164, 138),
253 ];
254 for i in 0..6 {
255 assert_eq!(&packet.answers[i].name.to_string()[..], "google.com");
256 assert_eq!(packet.answers[i].cls, C::IN);
257 assert_eq!(packet.answers[i].ttl, 239);
258 match packet.answers[i].data {
259 RRData::A(addr) => {
260 assert_eq!(addr, ips[i]);
261 }
262 ref x => panic!("Wrong rdata {:?}", x),
263 }
264 }
265 }
266
267 #[test]
parse_srv_query()268 fn parse_srv_query() {
269 let query = b"[\xd9\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\
270 \x0c_xmpp-server\x04_tcp\x05gmail\x03com\x00\x00!\x00\x01";
271 let packet = Packet::parse(query).unwrap();
272 assert_eq!(packet.header, Header {
273 id: 23513,
274 query: true,
275 opcode: StandardQuery,
276 authoritative: false,
277 truncated: false,
278 recursion_desired: true,
279 recursion_available: false,
280 response_code: NoError,
281 questions: 1,
282 answers: 0,
283 nameservers: 0,
284 additional: 0,
285 });
286 assert_eq!(packet.questions.len(), 1);
287 assert_eq!(packet.questions[0].qtype, QT::SRV);
288 assert_eq!(packet.questions[0].qclass, QC::IN);
289 assert_eq!(&packet.questions[0].qname.to_string()[..],
290 "_xmpp-server._tcp.gmail.com");
291 assert_eq!(packet.answers.len(), 0);
292 }
293
294 #[test]
parse_srv_response()295 fn parse_srv_response() {
296 let response = b"[\xd9\x81\x80\x00\x01\x00\x05\x00\x00\x00\x00\
297 \x0c_xmpp-server\x04_tcp\x05gmail\x03com\x00\x00!\x00\x01\
298 \xc0\x0c\x00!\x00\x01\x00\x00\x03\x84\x00 \x00\x05\x00\x00\
299 \x14\x95\x0bxmpp-server\x01l\x06google\x03com\x00\xc0\x0c\x00!\
300 \x00\x01\x00\x00\x03\x84\x00%\x00\x14\x00\x00\x14\x95\
301 \x04alt3\x0bxmpp-server\x01l\x06google\x03com\x00\
302 \xc0\x0c\x00!\x00\x01\x00\x00\x03\x84\x00%\x00\x14\x00\x00\
303 \x14\x95\x04alt1\x0bxmpp-server\x01l\x06google\x03com\x00\
304 \xc0\x0c\x00!\x00\x01\x00\x00\x03\x84\x00%\x00\x14\x00\x00\
305 \x14\x95\x04alt2\x0bxmpp-server\x01l\x06google\x03com\x00\
306 \xc0\x0c\x00!\x00\x01\x00\x00\x03\x84\x00%\x00\x14\x00\x00\
307 \x14\x95\x04alt4\x0bxmpp-server\x01l\x06google\x03com\x00";
308 let packet = Packet::parse(response).unwrap();
309 assert_eq!(packet.header, Header {
310 id: 23513,
311 query: false,
312 opcode: StandardQuery,
313 authoritative: false,
314 truncated: false,
315 recursion_desired: true,
316 recursion_available: true,
317 response_code: NoError,
318 questions: 1,
319 answers: 5,
320 nameservers: 0,
321 additional: 0,
322 });
323 assert_eq!(packet.questions.len(), 1);
324 assert_eq!(packet.questions[0].qtype, QT::SRV);
325 assert_eq!(packet.questions[0].qclass, QC::IN);
326 assert_eq!(&packet.questions[0].qname.to_string()[..],
327 "_xmpp-server._tcp.gmail.com");
328 assert_eq!(packet.answers.len(), 5);
329 let items = vec![
330 (5, 0, 5269, "xmpp-server.l.google.com"),
331 (20, 0, 5269, "alt3.xmpp-server.l.google.com"),
332 (20, 0, 5269, "alt1.xmpp-server.l.google.com"),
333 (20, 0, 5269, "alt2.xmpp-server.l.google.com"),
334 (20, 0, 5269, "alt4.xmpp-server.l.google.com"),
335 ];
336 for i in 0..5 {
337 assert_eq!(&packet.answers[i].name.to_string()[..],
338 "_xmpp-server._tcp.gmail.com");
339 assert_eq!(packet.answers[i].cls, C::IN);
340 assert_eq!(packet.answers[i].ttl, 900);
341 match *&packet.answers[i].data {
342 RRData::SRV { priority, weight, port, ref target } => {
343 assert_eq!(priority, items[i].0);
344 assert_eq!(weight, items[i].1);
345 assert_eq!(port, items[i].2);
346 assert_eq!(target.to_string(), (items[i].3).to_string());
347 }
348 ref x => panic!("Wrong rdata {:?}", x),
349 }
350 }
351 }
352
353 #[test]
parse_mx_response()354 fn parse_mx_response() {
355 let response = b"\xe3\xe8\x81\x80\x00\x01\x00\x05\x00\x00\x00\x00\
356 \x05gmail\x03com\x00\x00\x0f\x00\x01\xc0\x0c\x00\x0f\x00\x01\
357 \x00\x00\x04|\x00\x1b\x00\x05\rgmail-smtp-in\x01l\x06google\xc0\
358 \x12\xc0\x0c\x00\x0f\x00\x01\x00\x00\x04|\x00\t\x00\
359 \n\x04alt1\xc0)\xc0\x0c\x00\x0f\x00\x01\x00\x00\x04|\
360 \x00\t\x00(\x04alt4\xc0)\xc0\x0c\x00\x0f\x00\x01\x00\
361 \x00\x04|\x00\t\x00\x14\x04alt2\xc0)\xc0\x0c\x00\x0f\
362 \x00\x01\x00\x00\x04|\x00\t\x00\x1e\x04alt3\xc0)";
363 let packet = Packet::parse(response).unwrap();
364 assert_eq!(packet.header, Header {
365 id: 58344,
366 query: false,
367 opcode: StandardQuery,
368 authoritative: false,
369 truncated: false,
370 recursion_desired: true,
371 recursion_available: true,
372 response_code: NoError,
373 questions: 1,
374 answers: 5,
375 nameservers: 0,
376 additional: 0,
377 });
378 assert_eq!(packet.questions.len(), 1);
379 assert_eq!(packet.questions[0].qtype, QT::MX);
380 assert_eq!(packet.questions[0].qclass, QC::IN);
381 assert_eq!(&packet.questions[0].qname.to_string()[..],
382 "gmail.com");
383 assert_eq!(packet.answers.len(), 5);
384 let items = vec![
385 ( 5, "gmail-smtp-in.l.google.com"),
386 (10, "alt1.gmail-smtp-in.l.google.com"),
387 (40, "alt4.gmail-smtp-in.l.google.com"),
388 (20, "alt2.gmail-smtp-in.l.google.com"),
389 (30, "alt3.gmail-smtp-in.l.google.com"),
390 ];
391 for i in 0..5 {
392 assert_eq!(&packet.answers[i].name.to_string()[..],
393 "gmail.com");
394 assert_eq!(packet.answers[i].cls, C::IN);
395 assert_eq!(packet.answers[i].ttl, 1148);
396 match *&packet.answers[i].data {
397 RRData::MX { preference, ref exchange } => {
398 assert_eq!(preference, items[i].0);
399 assert_eq!(exchange.to_string(), (items[i].1).to_string());
400 }
401 ref x => panic!("Wrong rdata {:?}", x),
402 }
403 }
404 }
405
406 #[test]
parse_aaaa_response()407 fn parse_aaaa_response() {
408 let response = b"\xa9\xd9\x81\x80\x00\x01\x00\x01\x00\x00\x00\x00\x06\
409 google\x03com\x00\x00\x1c\x00\x01\xc0\x0c\x00\x1c\x00\x01\x00\x00\
410 \x00\x8b\x00\x10*\x00\x14P@\t\x08\x12\x00\x00\x00\x00\x00\x00 \x0e";
411
412 let packet = Packet::parse(response).unwrap();
413 assert_eq!(packet.header, Header {
414 id: 43481,
415 query: false,
416 opcode: StandardQuery,
417 authoritative: false,
418 truncated: false,
419 recursion_desired: true,
420 recursion_available: true,
421 response_code: NoError,
422 questions: 1,
423 answers: 1,
424 nameservers: 0,
425 additional: 0,
426 });
427
428 assert_eq!(packet.questions.len(), 1);
429 assert_eq!(packet.questions[0].qtype, QT::AAAA);
430 assert_eq!(packet.questions[0].qclass, QC::IN);
431 assert_eq!(&packet.questions[0].qname.to_string()[..], "google.com");
432 assert_eq!(packet.answers.len(), 1);
433 assert_eq!(&packet.answers[0].name.to_string()[..], "google.com");
434 assert_eq!(packet.answers[0].cls, C::IN);
435 assert_eq!(packet.answers[0].ttl, 139);
436 match packet.answers[0].data {
437 RRData::AAAA(addr) => {
438 assert_eq!(addr, Ipv6Addr::new(
439 0x2A00, 0x1450, 0x4009, 0x812, 0, 0, 0, 0x200e)
440 );
441 }
442 ref x => panic!("Wrong rdata {:?}", x),
443 }
444 }
445
446 #[test]
parse_cname_response()447 fn parse_cname_response() {
448 let response = b"\xfc\x9d\x81\x80\x00\x01\x00\x06\x00\x02\x00\x02\x03\
449 cdn\x07sstatic\x03net\x00\x00\x01\x00\x01\xc0\x0c\x00\x05\x00\x01\
450 \x00\x00\x00f\x00\x02\xc0\x10\xc0\x10\x00\x01\x00\x01\x00\x00\x00\
451 f\x00\x04h\x10g\xcc\xc0\x10\x00\x01\x00\x01\x00\x00\x00f\x00\x04h\
452 \x10k\xcc\xc0\x10\x00\x01\x00\x01\x00\x00\x00f\x00\x04h\x10h\xcc\
453 \xc0\x10\x00\x01\x00\x01\x00\x00\x00f\x00\x04h\x10j\xcc\xc0\x10\
454 \x00\x01\x00\x01\x00\x00\x00f\x00\x04h\x10i\xcc\xc0\x10\x00\x02\
455 \x00\x01\x00\x00\x99L\x00\x0b\x08cf-dns02\xc0\x10\xc0\x10\x00\x02\
456 \x00\x01\x00\x00\x99L\x00\x0b\x08cf-dns01\xc0\x10\xc0\xa2\x00\x01\
457 \x00\x01\x00\x00\x99L\x00\x04\xad\xf5:5\xc0\x8b\x00\x01\x00\x01\x00\
458 \x00\x99L\x00\x04\xad\xf5;\x04";
459
460 let packet = Packet::parse(response).unwrap();
461 assert_eq!(packet.header, Header {
462 id: 64669,
463 query: false,
464 opcode: StandardQuery,
465 authoritative: false,
466 truncated: false,
467 recursion_desired: true,
468 recursion_available: true,
469 response_code: NoError,
470 questions: 1,
471 answers: 6,
472 nameservers: 2,
473 additional: 2,
474 });
475
476 assert_eq!(packet.questions.len(), 1);
477 assert_eq!(packet.questions[0].qtype, QT::A);
478 assert_eq!(packet.questions[0].qclass, QC::IN);
479 assert_eq!(&packet.questions[0].qname.to_string()[..], "cdn.sstatic.net");
480 assert_eq!(packet.answers.len(), 6);
481 assert_eq!(&packet.answers[0].name.to_string()[..], "cdn.sstatic.net");
482 assert_eq!(packet.answers[0].cls, C::IN);
483 assert_eq!(packet.answers[0].ttl, 102);
484 match packet.answers[0].data {
485 RRData::CNAME(ref cname) => {
486 assert_eq!(&cname.to_string(), "sstatic.net");
487 }
488 ref x => panic!("Wrong rdata {:?}", x),
489 }
490
491 let ips = vec![
492 Ipv4Addr::new(104, 16, 103, 204),
493 Ipv4Addr::new(104, 16, 107, 204),
494 Ipv4Addr::new(104, 16, 104, 204),
495 Ipv4Addr::new(104, 16, 106, 204),
496 Ipv4Addr::new(104, 16, 105, 204),
497 ];
498 for i in 1..6 {
499 assert_eq!(&packet.answers[i].name.to_string()[..], "sstatic.net");
500 assert_eq!(packet.answers[i].cls, C::IN);
501 assert_eq!(packet.answers[i].ttl, 102);
502 match packet.answers[i].data {
503 RRData::A(addr) => {
504 assert_eq!(addr, ips[i-1]);
505 }
506 ref x => panic!("Wrong rdata {:?}", x),
507 }
508 }
509 }
510 }
511