1 //! Parsing the DNS wire protocol.
2
3 pub(crate) use std::io::Cursor;
4 pub(crate) use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
5
6 use std::io;
7 use log::*;
8
9 use crate::record::{Record, OPT};
10 use crate::strings::{Labels, ReadLabels, WriteLabels};
11 use crate::types::*;
12
13
14 impl Request {
15
16 /// Converts this request to a vector of bytes.
to_bytes(&self) -> io::Result<Vec<u8>>17 pub fn to_bytes(&self) -> io::Result<Vec<u8>> {
18 let mut bytes = Vec::with_capacity(32);
19
20 bytes.write_u16::<BigEndian>(self.transaction_id)?;
21 bytes.write_u16::<BigEndian>(self.flags.to_u16())?;
22
23 bytes.write_u16::<BigEndian>(1)?; // query count
24 bytes.write_u16::<BigEndian>(0)?; // answer count
25 bytes.write_u16::<BigEndian>(0)?; // authority RR count
26 bytes.write_u16::<BigEndian>(if self.additional.is_some() { 1 } else { 0 })?; // additional RR count
27
28 bytes.write_labels(&self.query.qname)?;
29 bytes.write_u16::<BigEndian>(self.query.qtype)?;
30 bytes.write_u16::<BigEndian>(self.query.qclass.to_u16())?;
31
32 if let Some(opt) = &self.additional {
33 bytes.write_u8(0)?; // usually a name
34 bytes.write_u16::<BigEndian>(OPT::RR_TYPE)?;
35 bytes.extend(opt.to_bytes()?);
36 }
37
38 Ok(bytes)
39 }
40
41 /// Returns the OPT record to be sent as part of requests.
additional_record() -> OPT42 pub fn additional_record() -> OPT {
43 OPT {
44 udp_payload_size: 512,
45 higher_bits: 0,
46 edns0_version: 0,
47 flags: 0,
48 data: Vec::new(),
49 }
50 }
51 }
52
53
54 impl Response {
55
56 /// Reads bytes off of the given slice, parsing them into a response.
57 #[cfg_attr(all(test, feature = "with_mutagen"), ::mutagen::mutate)]
from_bytes(bytes: &[u8]) -> Result<Self, WireError>58 pub fn from_bytes(bytes: &[u8]) -> Result<Self, WireError> {
59 info!("Parsing response");
60 trace!("Bytes -> {:?}", bytes);
61 let mut c = Cursor::new(bytes);
62
63 let transaction_id = c.read_u16::<BigEndian>()?;
64 trace!("Read txid -> {:?}", transaction_id);
65
66 let flags = Flags::from_u16(c.read_u16::<BigEndian>()?);
67 trace!("Read flags -> {:#?}", flags);
68
69 let query_count = c.read_u16::<BigEndian>()?;
70 let answer_count = c.read_u16::<BigEndian>()?;
71 let authority_count = c.read_u16::<BigEndian>()?;
72 let additional_count = c.read_u16::<BigEndian>()?;
73
74 let mut queries = Vec::new();
75 debug!("Reading {}x query from response", query_count);
76 for _ in 0 .. query_count {
77 let (qname, _) = c.read_labels()?;
78 queries.push(Query::from_bytes(qname, &mut c)?);
79 }
80
81 let mut answers = Vec::new();
82 debug!("Reading {}x answer from response", answer_count);
83 for _ in 0 .. answer_count {
84 let (qname, _) = c.read_labels()?;
85 answers.push(Answer::from_bytes(qname, &mut c)?);
86 }
87
88 let mut authorities = Vec::new();
89 debug!("Reading {}x authority from response", authority_count);
90 for _ in 0 .. authority_count {
91 let (qname, _) = c.read_labels()?;
92 authorities.push(Answer::from_bytes(qname, &mut c)?);
93 }
94
95 let mut additionals = Vec::new();
96 debug!("Reading {}x additional answer from response", additional_count);
97 for _ in 0 .. additional_count {
98 let (qname, _) = c.read_labels()?;
99 additionals.push(Answer::from_bytes(qname, &mut c)?);
100 }
101
102 Ok(Self { transaction_id, flags, queries, answers, authorities, additionals })
103 }
104 }
105
106
107 impl Query {
108
109 /// Reads bytes from the given cursor, and parses them into a query with
110 /// the given domain name.
111 #[cfg_attr(all(test, feature = "with_mutagen"), ::mutagen::mutate)]
from_bytes(qname: Labels, c: &mut Cursor<&[u8]>) -> Result<Self, WireError>112 fn from_bytes(qname: Labels, c: &mut Cursor<&[u8]>) -> Result<Self, WireError> {
113 let qtype = c.read_u16::<BigEndian>()?;
114 trace!("Read qtype -> {:?}", qtype);
115
116 let qclass = QClass::from_u16(c.read_u16::<BigEndian>()?);
117 trace!("Read qclass -> {:?}", qtype);
118
119 Ok(Self { qtype, qclass, qname })
120 }
121 }
122
123
124 impl Answer {
125
126 /// Reads bytes from the given cursor, and parses them into an answer with
127 /// the given domain name.
128 #[cfg_attr(all(test, feature = "with_mutagen"), ::mutagen::mutate)]
from_bytes(qname: Labels, c: &mut Cursor<&[u8]>) -> Result<Self, WireError>129 fn from_bytes(qname: Labels, c: &mut Cursor<&[u8]>) -> Result<Self, WireError> {
130 let qtype = c.read_u16::<BigEndian>()?;
131 trace!("Read qtype -> {:?}", qtype);
132
133 if qtype == OPT::RR_TYPE {
134 let opt = OPT::read(c)?;
135 Ok(Self::Pseudo { qname, opt })
136 }
137 else {
138 let qclass = QClass::from_u16(c.read_u16::<BigEndian>()?);
139 trace!("Read qclass -> {:?}", qtype);
140
141 let ttl = c.read_u32::<BigEndian>()?;
142 trace!("Read TTL -> {:?}", ttl);
143
144 let record_length = c.read_u16::<BigEndian>()?;
145 trace!("Read record length -> {:?}", record_length);
146
147 let record = Record::from_bytes(qtype, record_length, c)?;
148 Ok(Self::Standard { qclass, qname, record, ttl })
149 }
150
151 }
152 }
153
154
155 impl Record {
156
157 /// Reads at most `len` bytes from the given curser, and parses them into
158 /// a record structure depending on the type number, which has already been read.
159 #[cfg_attr(all(test, feature = "with_mutagen"), ::mutagen::mutate)]
from_bytes(qtype: TypeInt, len: u16, c: &mut Cursor<&[u8]>) -> Result<Self, WireError>160 fn from_bytes(qtype: TypeInt, len: u16, c: &mut Cursor<&[u8]>) -> Result<Self, WireError> {
161 use crate::record::*;
162
163 macro_rules! try_record {
164 ($record:tt) => {
165 if $record::RR_TYPE == qtype {
166 info!("Parsing {} record (type {}, len {})", $record::NAME, qtype, len);
167 return Wire::read(len, c).map(Self::$record)
168 }
169 }
170 }
171
172 // Try all the records, one type at a time, returning early if the
173 // type number matches.
174 try_record!(A);
175 try_record!(AAAA);
176 try_record!(CAA);
177 try_record!(CNAME);
178 try_record!(HINFO);
179 try_record!(LOC);
180 try_record!(MX);
181 try_record!(NAPTR);
182 try_record!(NS);
183 // OPT is handled separately
184 try_record!(PTR);
185 try_record!(SSHFP);
186 try_record!(SOA);
187 try_record!(SRV);
188 try_record!(TLSA);
189 try_record!(TXT);
190
191 // Otherwise, collect the bytes into a vector and return an unknown
192 // record type.
193 let mut bytes = Vec::new();
194 for _ in 0 .. len {
195 bytes.push(c.read_u8()?);
196 }
197
198 let type_number = UnknownQtype::from(qtype);
199 Ok(Self::Other { type_number, bytes })
200 }
201 }
202
203
204 impl QClass {
from_u16(uu: u16) -> Self205 fn from_u16(uu: u16) -> Self {
206 match uu {
207 0x0001 => Self::IN,
208 0x0003 => Self::CH,
209 0x0004 => Self::HS,
210 _ => Self::Other(uu),
211 }
212 }
213
to_u16(self) -> u16214 fn to_u16(self) -> u16 {
215 match self {
216 Self::IN => 0x0001,
217 Self::CH => 0x0003,
218 Self::HS => 0x0004,
219 Self::Other(uu) => uu,
220 }
221 }
222 }
223
224
225 /// Determines the record type number to signify a record with the given name.
find_qtype_number(record_type: &str) -> Option<TypeInt>226 pub fn find_qtype_number(record_type: &str) -> Option<TypeInt> {
227 use crate::record::*;
228
229 macro_rules! try_record {
230 ($record:tt) => {
231 if $record::NAME == record_type {
232 return Some($record::RR_TYPE);
233 }
234 }
235 }
236
237 try_record!(A);
238 try_record!(AAAA);
239 try_record!(CAA);
240 try_record!(CNAME);
241 try_record!(HINFO);
242 try_record!(LOC);
243 try_record!(MX);
244 try_record!(NAPTR);
245 try_record!(NS);
246 // OPT is elsewhere
247 try_record!(PTR);
248 try_record!(SSHFP);
249 try_record!(SOA);
250 try_record!(SRV);
251 try_record!(TLSA);
252 try_record!(TXT);
253
254 None
255 }
256
257
258 impl Flags {
259
260 /// The set of flags that represents a query packet.
query() -> Self261 pub fn query() -> Self {
262 Self::from_u16(0b_0000_0001_0000_0000)
263 }
264
265 /// The set of flags that represents a successful response.
standard_response() -> Self266 pub fn standard_response() -> Self {
267 Self::from_u16(0b_1000_0001_1000_0000)
268 }
269
270 /// Converts the flags into a two-byte number.
to_u16(self) -> u16271 pub fn to_u16(self) -> u16 { // 0123 4567 89AB CDEF
272 let mut bits = 0b_0000_0000_0000_0000;
273 if self.response { bits += 0b_1000_0000_0000_0000; }
274 match self.opcode {
275 Opcode::Query => { bits += 0b_0000_0000_0000_0000; }
276 Opcode::Other(_) => { unimplemented!(); }
277 }
278 if self.authoritative { bits += 0b_0000_0100_0000_0000; }
279 if self.truncated { bits += 0b_0000_0010_0000_0000; }
280 if self.recursion_desired { bits += 0b_0000_0001_0000_0000; }
281 if self.recursion_available { bits += 0b_0000_0000_1000_0000; }
282 // (the Z bit is reserved) 0b_0000_0000_0100_0000
283 if self.authentic_data { bits += 0b_0000_0000_0010_0000; }
284 if self.checking_disabled { bits += 0b_0000_0000_0001_0000; }
285
286 bits
287 }
288
289 /// Extracts the flags from the given two-byte number.
from_u16(bits: u16) -> Self290 pub fn from_u16(bits: u16) -> Self {
291 let has_bit = |bit| { bits & bit == bit };
292
293 Self {
294 response: has_bit(0b_1000_0000_0000_0000),
295 opcode: Opcode::from_bits((bits.to_be_bytes()[0] & 0b_0111_1000) >> 3),
296 authoritative: has_bit(0b_0000_0100_0000_0000),
297 truncated: has_bit(0b_0000_0010_0000_0000),
298 recursion_desired: has_bit(0b_0000_0001_0000_0000),
299 recursion_available: has_bit(0b_0000_0000_1000_0000),
300 authentic_data: has_bit(0b_0000_0000_0010_0000),
301 checking_disabled: has_bit(0b_0000_0000_0001_0000),
302 error_code: ErrorCode::from_bits(bits & 0b_1111),
303 }
304 }
305 }
306
307
308 impl Opcode {
309
310 /// Extracts the opcode from this four-bit number, which should have been
311 /// extracted from the packet and shifted to be in the range 0–15.
from_bits(bits: u8) -> Self312 fn from_bits(bits: u8) -> Self {
313 if bits == 0 {
314 Self::Query
315 }
316 else {
317 assert!(bits <= 15, "bits {:#08b} out of range", bits);
318 Self::Other(bits)
319 }
320 }
321 }
322
323
324 impl ErrorCode {
325
326 /// Extracts the rcode from the last four bits of the flags field.
from_bits(bits: u16) -> Option<Self>327 fn from_bits(bits: u16) -> Option<Self> {
328 if (0x0F01 .. 0x0FFF).contains(&bits) {
329 return Some(Self::Private(bits));
330 }
331
332 match bits {
333 0 => None,
334 1 => Some(Self::FormatError),
335 2 => Some(Self::ServerFailure),
336 3 => Some(Self::NXDomain),
337 4 => Some(Self::NotImplemented),
338 5 => Some(Self::QueryRefused),
339 16 => Some(Self::BadVersion),
340 n => Some(Self::Other(n)),
341 }
342 }
343 }
344
345
346 /// Trait for decoding DNS record structures from bytes read over the wire.
347 pub trait Wire: Sized {
348
349 /// This record’s type as a string, such as `"A"` or `"CNAME"`.
350 const NAME: &'static str;
351
352 /// The number signifying that a record is of this type.
353 /// See <https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-4>
354 const RR_TYPE: u16;
355
356 /// Read at most `len` bytes from the given `Cursor`. This cursor travels
357 /// throughout the complete data — by this point, we have read the entire
358 /// response into a buffer.
read(len: u16, c: &mut Cursor<&[u8]>) -> Result<Self, WireError>359 fn read(len: u16, c: &mut Cursor<&[u8]>) -> Result<Self, WireError>;
360 }
361
362
363 /// Helper macro to get the qtype number of a record type at compile-time.
364 ///
365 /// # Examples
366 ///
367 /// ```
368 /// use dns::{qtype, record::MX};
369 ///
370 /// assert_eq!(15, qtype!(MX));
371 /// ```
372 #[macro_export]
373 macro_rules! qtype {
374 ($type:ty) => {
375 <$type as $crate::Wire>::RR_TYPE
376 }
377 }
378
379
380 /// Something that can go wrong deciphering a record.
381 #[derive(PartialEq, Debug)]
382 pub enum WireError {
383
384 /// There was an IO error reading from the cursor.
385 /// Almost all the time, this means that the buffer was too short.
386 IO,
387 // (io::Error is not PartialEq so we don’t propagate it)
388
389 /// When the DNS standard requires records of this type to have a certain
390 /// fixed length, but the response specified a different length.
391 ///
392 /// This error should be returned regardless of the _content_ of the
393 /// record, whatever it is.
394 WrongRecordLength {
395
396 /// The length of the record’s data, as specified in the packet.
397 stated_length: u16,
398
399 /// The length of the record that the DNS specification mandates.
400 mandated_length: MandatedLength,
401 },
402
403 /// When the length of this record as specified in the packet differs from
404 /// the computed length, as determined by reading labels.
405 ///
406 /// There are two ways, in general, to read arbitrary-length data from a
407 /// stream of bytes: length-prefixed (read the length, then read that many
408 /// bytes) or sentinel-terminated (keep reading bytes until you read a
409 /// certain value, usually zero). The DNS protocol uses both: each
410 /// record’s size is specified up-front in the packet, but inside the
411 /// record, there exist arbitrary-length strings that must be read until a
412 /// zero is read, indicating there is no more string.
413 ///
414 /// Consider the case of a packet, with a specified length, containing a
415 /// string of arbitrary length (such as the CNAME or TXT records). A DNS
416 /// client has to deal with this in one of two ways:
417 ///
418 /// 1. Read exactly the specified length of bytes from the record, raising
419 /// an error if the contents are too short or a string keeps going past
420 /// the length (assume the length is correct but the contents are wrong).
421 ///
422 /// 2. Read as many bytes from the record as the string requests, raising
423 /// an error if the number of bytes read at the end differs from the
424 /// expected length of the record (assume the length is wrong but the
425 /// contents are correct).
426 ///
427 /// Note that no matter which way is picked, the record will still be
428 /// incorrect — it only impacts the parsing of records that occur after it
429 /// in the packet. Knowing which method should be used requires knowing
430 /// what caused the DNS packet to be erroneous, which we cannot know.
431 ///
432 /// dog picks the second way. If a record ends up reading more or fewer
433 /// bytes than it is ‘supposed’ to, it will raise this error, but _after_
434 /// having read a different number of bytes than the specified length.
435 WrongLabelLength {
436
437 /// The length of the record’s data, as specified in the packet.
438 stated_length: u16,
439
440 /// The computed length of the record’s data, based on the number of
441 /// bytes consumed by reading labels from the packet.
442 length_after_labels: u16,
443 },
444
445 /// When the data contained a string containing a cycle of pointers.
446 /// Contains the vector of indexes that was being checked.
447 TooMuchRecursion(Vec<u16>),
448
449 /// When the data contained a string with a pointer to an index outside of
450 /// the packet. Contains the invalid index.
451 OutOfBounds(u16),
452
453 /// When a record in the packet contained a version field that specifies
454 /// the format of its remaining fields, but this version is too recent to
455 /// be supported, so we cannot parse it.
456 WrongVersion {
457
458 /// The version of the record layout, as specified in the packet
459 stated_version: u8,
460
461 /// The maximum version that this version of dog supports.
462 maximum_supported_version: u8,
463 }
464 }
465
466 /// The rule for how long a record in a packet should be.
467 #[derive(PartialEq, Debug, Copy, Clone)]
468 pub enum MandatedLength {
469
470 /// The record should be exactly this many bytes in length.
471 Exactly(u16),
472
473 /// The record should be _at least_ this many bytes in length.
474 AtLeast(u16),
475 }
476
477 impl From<io::Error> for WireError {
from(ioe: io::Error) -> Self478 fn from(ioe: io::Error) -> Self {
479 error!("IO error -> {:?}", ioe);
480 Self::IO
481 }
482 }
483
484
485 #[cfg(test)]
486 mod test {
487 use super::*;
488 use crate::record::{Record, A, SOA, OPT, UnknownQtype};
489 use std::net::Ipv4Addr;
490 use pretty_assertions::assert_eq;
491
492 #[test]
build_request()493 fn build_request() {
494 let request = Request {
495 transaction_id: 0xceac,
496 flags: Flags::query(),
497 query: Query {
498 qname: Labels::encode("rfcs.io").unwrap(),
499 qclass: QClass::Other(0x42),
500 qtype: 0x1234,
501 },
502 additional: Some(Request::additional_record()),
503 };
504
505 let result = vec![
506 0xce, 0xac, // transaction ID
507 0x01, 0x00, // flags (standard query)
508 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, // counts (1, 0, 0, 1)
509
510 // query:
511 0x04, 0x72, 0x66, 0x63, 0x73, 0x02, 0x69, 0x6f, 0x00, // qname
512 0x12, 0x34, // type
513 0x00, 0x42, // class
514
515 // OPT record:
516 0x00, // name
517 0x00, 0x29, // type OPT
518 0x02, 0x00, // UDP payload size
519 0x00, // higher bits
520 0x00, // EDNS(0) version
521 0x00, 0x00, // more flags
522 0x00, 0x00, // no data
523 ];
524
525 assert_eq!(request.to_bytes().unwrap(), result);
526 }
527
528 #[test]
complete_response()529 fn complete_response() {
530
531 // This is an artifical amalgam of DNS, not a real-world response!
532 let buf = &[
533 0xce, 0xac, // transaction ID
534 0x81, 0x80, // flags (standard query, response, no error)
535 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, // counts (1, 1, 1, 2)
536
537 // query:
538 0x05, 0x62, 0x73, 0x61, 0x67, 0x6f, 0x02, 0x6d, 0x65, 0x00, // name
539 0x00, 0x01, // type A
540 0x00, 0x01, // class IN
541
542 // answer:
543 0xc0, 0x0c, // name (backreference)
544 0x00, 0x01, // type A
545 0x00, 0x01, // class IN
546 0x00, 0x00, 0x03, 0x77, // TTL
547 0x00, 0x04, // data length 4
548 0x8a, 0x44, 0x75, 0x5e, // IP address
549
550 // authoritative:
551 0x00, // name
552 0x00, 0x06, // type SOA
553 0x00, 0x01, // class IN
554 0xFF, 0xFF, 0xFF, 0xFF, // TTL (maximum possible!)
555 0x00, 0x1B, // data length
556 0x01, 0x61, 0x00, // primary name server ("a")
557 0x02, 0x6d, 0x78, 0x00, // mailbox ("mx")
558 0x78, 0x68, 0x52, 0x2c, // serial number
559 0x00, 0x00, 0x07, 0x08, // refresh interval
560 0x00, 0x00, 0x03, 0x84, // retry interval
561 0x00, 0x09, 0x3a, 0x80, // expire limit
562 0x00, 0x01, 0x51, 0x80, // minimum TTL
563
564 // additional 1:
565 0x00, // name
566 0x00, 0x99, // unknown type
567 0x00, 0x99, // unknown class
568 0x12, 0x34, 0x56, 0x78, // TTL
569 0x00, 0x04, // data length 4
570 0x12, 0x34, 0x56, 0x78, // data
571
572 // additional 2:
573 0x00, // name
574 0x00, 0x29, // type OPT
575 0x02, 0x00, // UDP payload size
576 0x00, // higher bits
577 0x00, // EDNS(0) version
578 0x00, 0x00, // more flags
579 0x00, 0x00, // no data
580 ];
581
582 let response = Response {
583 transaction_id: 0xceac,
584 flags: Flags::standard_response(),
585 queries: vec![
586 Query {
587 qname: Labels::encode("bsago.me").unwrap(),
588 qclass: QClass::IN,
589 qtype: qtype!(A),
590 },
591 ],
592 answers: vec![
593 Answer::Standard {
594 qname: Labels::encode("bsago.me").unwrap(),
595 qclass: QClass::IN,
596 ttl: 887,
597 record: Record::A(A {
598 address: Ipv4Addr::new(138, 68, 117, 94),
599 }),
600 }
601 ],
602 authorities: vec![
603 Answer::Standard {
604 qname: Labels::root(),
605 qclass: QClass::IN,
606 ttl: 4294967295,
607 record: Record::SOA(SOA {
608 mname: Labels::encode("a").unwrap(),
609 rname: Labels::encode("mx").unwrap(),
610 serial: 2020102700,
611 refresh_interval: 1800,
612 retry_interval: 900,
613 expire_limit: 604800,
614 minimum_ttl: 86400,
615 }),
616 }
617 ],
618 additionals: vec![
619 Answer::Standard {
620 qname: Labels::root(),
621 qclass: QClass::Other(153),
622 ttl: 305419896,
623 record: Record::Other {
624 type_number: UnknownQtype::UnheardOf(153),
625 bytes: vec![ 0x12, 0x34, 0x56, 0x78 ],
626 },
627 },
628 Answer::Pseudo {
629 qname: Labels::root(),
630 opt: OPT {
631 udp_payload_size: 512,
632 higher_bits: 0,
633 edns0_version: 0,
634 flags: 0,
635 data: vec![],
636 },
637 },
638 ],
639 };
640
641 assert_eq!(Response::from_bytes(buf), Ok(response));
642 }
643 }
644