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