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