dnssector/
parsed_packet.rs

1use byteorder::{BigEndian, ByteOrder};
2use rand::prelude::*;
3
4use crate::compress::*;
5use crate::constants::*;
6use crate::dns_sector::*;
7use crate::edns_iterator::*;
8use crate::errors::*;
9use crate::question_iterator::*;
10use crate::renamer::*;
11use crate::response_iterator::*;
12use crate::rr_iterator::*;
13use crate::synth::gen;
14
15/// A `ParsedPacket` structure contains information about a successfully parsed
16/// DNS packet, that allows quick access to (extended) flags and to individual
17/// sections.
18#[derive(Debug)]
19pub struct ParsedPacket {
20    pub packet: Option<Vec<u8>>,
21    pub offset_question: Option<usize>,
22    pub offset_answers: Option<usize>,
23    pub offset_nameservers: Option<usize>,
24    pub offset_additional: Option<usize>,
25    pub offset_edns: Option<usize>,
26    pub edns_count: u16,
27    pub ext_rcode: Option<u8>,
28    pub edns_version: Option<u8>,
29    pub ext_flags: Option<u16>,
30    pub maybe_compressed: bool,
31    pub max_payload: usize,
32    pub cached: Option<(Vec<u8>, u16, u16)>,
33}
34
35impl ParsedPacket {
36    /// Creates an empty parsed_packet
37    pub fn empty() -> Self {
38        let mut parsed_packet = ParsedPacket {
39            packet: Some(vec![0; 12]),
40            offset_question: None,
41            offset_answers: None,
42            offset_nameservers: None,
43            offset_additional: None,
44            offset_edns: None,
45            edns_count: 0,
46            ext_rcode: None,
47            edns_version: None,
48            ext_flags: None,
49            maybe_compressed: false,
50            max_payload: DNS_MAX_UNCOMPRESSED_SIZE,
51            cached: None,
52        };
53        let mut rng = thread_rng();
54        let tid: u16 = rng.gen();
55        parsed_packet.set_tid(tid);
56        parsed_packet.set_flags(DNS_FLAG_RD);
57        parsed_packet.set_response(false);
58        parsed_packet
59    }
60
61    /// Converts a `ParsedPacket` back into a raw packet.
62    #[inline]
63    pub fn into_packet(self) -> Vec<u8> {
64        self.packet.unwrap()
65    }
66
67    /// Returns a reference to the packet
68    #[inline]
69    pub fn packet(&self) -> &[u8] {
70        self.packet.as_ref().unwrap()
71    }
72
73    #[inline]
74    pub fn packet_mut(&mut self) -> &mut Vec<u8> {
75        self.packet.as_mut().unwrap()
76    }
77
78    /// Iterates over the question section.
79    pub fn into_iter_question(&mut self) -> Option<QuestionIterator<'_>> {
80        QuestionIterator::new(RRIterator::new(self, Section::Question)).next()
81    }
82
83    /// Iterates over the answer section.
84    pub fn into_iter_answer(&mut self) -> Option<AnswerIterator<'_>> {
85        AnswerIterator::new(RRIterator::new(self, Section::Answer)).next()
86    }
87
88    /// Iterates over the list of name servers.
89    pub fn into_iter_nameservers(&mut self) -> Option<NameServersIterator<'_>> {
90        NameServersIterator::new(RRIterator::new(self, Section::NameServers)).next()
91    }
92
93    /// Iterates over the additional section - OPT RRs are skipped.
94    pub fn into_iter_additional(&mut self) -> Option<AdditionalIterator<'_>> {
95        AdditionalIterator::new(RRIterator::new(self, Section::Additional)).next()
96    }
97
98    /// Iterates over the additional section - OPT RRs are included.
99    pub fn into_iter_additional_including_opt(&mut self) -> Option<AdditionalIterator<'_>> {
100        AdditionalIterator::new(RRIterator::new(self, Section::Additional)).next_including_opt()
101    }
102
103    /// Iterates over the records from the optional edns pseudo-section.
104    pub fn into_iter_edns(&mut self) -> Option<EdnsIterator<'_>> {
105        EdnsIterator::new(RRIterator::new(self, Section::Edns)).next()
106    }
107
108    /// Copy the packet header
109    pub fn copy_header(&self, header: &mut Vec<u8>) {
110        header.extend(&self.packet()[..DNS_HEADER_SIZE]);
111    }
112
113    /// Copy the EDNS section
114    pub fn copy_raw_edns_section(&self, raw_edns: &mut Vec<u8>) -> usize {
115        let offset_edns = match self.offset_edns {
116            None => return 0,
117            Some(offset_edns) => offset_edns,
118        };
119        debug_assert!(offset_edns >= 1 + DNS_RR_HEADER_SIZE);
120        if offset_edns < 1 + DNS_RR_HEADER_SIZE {
121            return 0;
122        }
123        let offset_edns_header = offset_edns - (1 + DNS_RR_HEADER_SIZE);
124        debug_assert_eq!(self.packet()[offset_edns_header], 0);
125        let edns_len = self.packet().len() - offset_edns_header;
126        raw_edns.extend_from_slice(&self.packet()[offset_edns_header..]);
127        edns_len
128    }
129
130    /// Returns the transaction ID.
131    #[inline]
132    pub fn tid(&self) -> u16 {
133        BigEndian::read_u16(&self.packet()[DNS_TID_OFFSET..])
134    }
135
136    /// Changes the transaction ID.
137    pub fn set_tid(&mut self, tid: u16) {
138        BigEndian::write_u16(&mut self.packet_mut()[DNS_TID_OFFSET..], tid)
139    }
140
141    /// Returns the flags, including extended flags.
142    /// The extended flags optionally obtained using edns are exposed as the
143    /// highest 16 bits, instead of having distinct sets of flags.
144    /// The opcode and rcode are intentionally masked in order to prevent
145    /// misuse: these bits are never supposed to be accessed individually.
146    pub fn flags(&self) -> u32 {
147        let mut rflags = BigEndian::read_u16(&self.packet()[DNS_FLAGS_OFFSET..]);
148        rflags &= !0x7800; // mask opcode
149        rflags &= !0x000f; // mask rcode
150        (self.ext_flags.unwrap_or(0) as u32) << 16 | (rflags as u32)
151    }
152
153    /// Changes the flags.
154    /// Extended flags from the OPT section are currently ignored.
155    pub fn set_flags(&mut self, flags: u32) {
156        let mut rflags = (flags & 0xffff) as u16;
157        rflags &= !0x7800; // mask opcode
158        rflags &= !0x000f; // mask rcode
159        let mut v = BigEndian::read_u16(&self.packet()[DNS_FLAGS_OFFSET..]);
160        v &= !0x7800;
161        v &= !0x000f;
162        v |= rflags;
163        BigEndian::write_u16(&mut self.packet_mut()[DNS_FLAGS_OFFSET..], v);
164    }
165
166    /// Check if this is a question with the DO bit, or a response with the AD
167    /// bit
168    pub fn dnssec(&self) -> bool {
169        let flags = self.flags();
170        if flags & DNS_FLAG_QR == 0 {
171            (flags & DNS_FLAG_DO) != 0
172        } else {
173            (flags & DNS_FLAG_AD) != 0
174        }
175    }
176
177    /// Check if this is a response
178    #[inline]
179    pub fn is_response(&self) -> bool {
180        self.flags() & DNS_FLAG_QR == DNS_FLAG_QR
181    }
182
183    /// Set the response bit
184    #[inline]
185    pub fn set_response(&mut self, is_response: bool) {
186        let mut oll = BigEndian::read_u16(&self.packet()[DNS_FLAGS_OFFSET..]);
187        if is_response {
188            oll |= DNS_FLAG_QR as u16
189        } else {
190            oll &= !(DNS_FLAG_QR as u16)
191        }
192        BigEndian::write_u16(&mut self.packet_mut()[DNS_FLAGS_OFFSET..], oll);
193    }
194
195    /// Returns the return code.
196    #[inline]
197    pub fn rcode(&self) -> u8 {
198        let rflags = self.packet()[DNS_FLAGS_OFFSET + 1];
199        rflags & 0x0f
200    }
201
202    /// Changes the return code.
203    pub fn set_rcode(&mut self, rcode: u8) {
204        let p = &mut self.packet_mut()[DNS_FLAGS_OFFSET + 1];
205        *p &= !0x0f;
206        *p |= rcode & 0x0f;
207    }
208
209    /// Returns the opcode.
210    #[inline]
211    pub fn opcode(&self) -> u8 {
212        let rflags = self.packet()[DNS_FLAGS_OFFSET];
213        (rflags & 0x78) >> 3
214    }
215
216    /// Changes the operation code.
217    pub fn set_opcode(&mut self, opcode: u8) {
218        let p = &mut self.packet_mut()[DNS_FLAGS_OFFSET];
219        *p &= !0x78;
220        *p |= (opcode << 3) & 0x78;
221    }
222
223    /// Maximum payload size when using UDP
224    #[inline]
225    pub fn max_payload(&self) -> usize {
226        self.max_payload
227    }
228
229    /// Increments the number of records in a given section
230    pub fn rrcount_inc(&mut self, section: Section) -> Result<u16, Error> {
231        let packet = &mut self.packet_mut();
232        let mut rrcount = match section {
233            Section::Question => {
234                let rrcount = DNSSector::qdcount(packet);
235                if rrcount >= 1 {
236                    bail!(DSError::InvalidPacket(
237                        "A DNS packet can only contain up to one question"
238                    ));
239                }
240                rrcount
241            }
242            Section::Answer => DNSSector::ancount(packet),
243            Section::NameServers => DNSSector::nscount(packet),
244            Section::Additional => DNSSector::arcount(packet),
245            _ => panic!("Trying to increment a the number of records in a pseudosection"),
246        };
247        if rrcount >= 0xffff {
248            bail!(DSError::InvalidPacket(
249                "Too many records in the same question"
250            ));
251        }
252        rrcount += 1;
253        match section {
254            Section::Question => DNSSector::set_qdcount(packet, rrcount),
255            Section::Answer => DNSSector::set_ancount(packet, rrcount),
256            Section::NameServers => DNSSector::set_nscount(packet, rrcount),
257            Section::Additional => DNSSector::set_arcount(packet, rrcount),
258            _ => panic!("EDNS section doesn't have a records count"),
259        }
260        Ok(rrcount)
261    }
262
263    /// Decrements the number of records in a given section
264    pub fn rrcount_dec(&mut self, section: Section) -> Result<u16, Error> {
265        let packet = &mut self.packet_mut();
266        let mut rrcount = match section {
267            Section::Question => DNSSector::qdcount(packet),
268            Section::Answer => DNSSector::ancount(packet),
269            Section::NameServers => DNSSector::nscount(packet),
270            Section::Additional => DNSSector::arcount(packet),
271            _ => panic!("Trying to decrement a the number of records in a pseudosection"),
272        };
273        if rrcount <= 0 {
274            panic!(
275                "Trying to decrement a number of records that was already 0 in section {:?}",
276                section
277            );
278        }
279        rrcount -= 1;
280        match section {
281            Section::Question => DNSSector::set_qdcount(packet, rrcount),
282            Section::Answer => DNSSector::set_ancount(packet, rrcount),
283            Section::NameServers => DNSSector::set_nscount(packet, rrcount),
284            Section::Additional => DNSSector::set_arcount(packet, rrcount),
285            _ => panic!("EDNS section doesn't have a records count"),
286        }
287
288        Ok(rrcount)
289    }
290
291    fn insertion_offset(&self, section: Section) -> Result<usize, Error> {
292        let offset = match section {
293            Section::Question => self
294                .offset_answers
295                .or(self.offset_nameservers)
296                .or(self.offset_additional)
297                .unwrap_or_else(|| self.packet().len()),
298            Section::Answer => self
299                .offset_nameservers
300                .or(self.offset_additional)
301                .unwrap_or_else(|| self.packet().len()),
302            Section::NameServers => self
303                .offset_additional
304                .unwrap_or_else(|| self.packet().len()),
305            Section::Additional => self.packet().len(),
306            _ => panic!("insertion_offset() is not suitable to adding EDNS pseudorecords"),
307        };
308        Ok(offset)
309    }
310
311    pub fn insert_rr(&mut self, section: Section, rr: gen::RR) -> Result<(), Error> {
312        if self.maybe_compressed {
313            let uncompressed = Compress::uncompress(self.packet())?;
314            self.packet = Some(uncompressed);
315            self.recompute()?;
316            debug_assert!(!self.maybe_compressed);
317        }
318        let rr_len = rr.packet.len();
319        if DNS_MAX_UNCOMPRESSED_SIZE - self.packet().len() < rr_len {
320            bail!(DSError::PacketTooLarge)
321        }
322        let insertion_offset = self.insertion_offset(section)?;
323        let packet_len = self.packet().len();
324        let new_len = packet_len + rr_len;
325        self.packet_mut().reserve(rr_len);
326        if insertion_offset == new_len {
327            self.packet_mut().extend_from_slice(&rr.packet);
328        } else {
329            let packet = self.packet_mut();
330            packet.resize(new_len, 0);
331            packet.copy_within(insertion_offset..packet_len, insertion_offset + rr_len);
332            packet[insertion_offset..insertion_offset + rr_len].copy_from_slice(&rr.packet);
333        }
334        self.rrcount_inc(section)?;
335        match section {
336            Section::Question => {
337                self.offset_question = self.offset_question.or(Some(insertion_offset));
338
339                self.offset_answers = self.offset_answers.map(|x| x + rr_len);
340                self.offset_nameservers = self.offset_nameservers.map(|x| x + rr_len);
341                self.offset_additional = self.offset_additional.map(|x| x + rr_len);
342                self.offset_edns = self.offset_edns.map(|x| x + rr_len);
343            }
344            Section::Answer => {
345                self.offset_answers = self.offset_answers.or(Some(insertion_offset));
346
347                self.offset_nameservers = self.offset_nameservers.map(|x| x + rr_len);
348                self.offset_additional = self.offset_additional.map(|x| x + rr_len);
349                self.offset_edns = self.offset_edns.map(|x| x + rr_len);
350            }
351            Section::NameServers => {
352                self.offset_nameservers = self.offset_nameservers.or(Some(insertion_offset));
353
354                self.offset_additional = self.offset_additional.map(|x| x + rr_len);
355                self.offset_edns = self.offset_edns.map(|x| x + rr_len);
356            }
357            Section::Additional => {
358                self.offset_additional = self.offset_additional.or(Some(insertion_offset));
359            }
360            _ => panic!("insertion_offset() is not suitable to adding EDNS pseudorecords"),
361        }
362        Ok(())
363    }
364
365    pub fn insert_rr_from_string(&mut self, section: Section, rr_str: &str) -> Result<(), Error> {
366        let rr = gen::RR::from_string(rr_str)?;
367        self.insert_rr(section, rr)
368    }
369
370    /// Recomputes all section offsets after an in-place decompression of the
371    /// packet. It is currently re-parsing everything by calling `parse()`,
372    /// but this can be optimized later to skip over RDATA, and by assuming
373    /// that the input is always well-formed.
374    pub fn recompute(&mut self) -> Result<(), Error> {
375        if !self.maybe_compressed {
376            return Ok(());
377        }
378        let dns_sector = DNSSector::new(self.packet.take().expect("self.packet is None"))?;
379        let parsed_packet = dns_sector.parse()?;
380        self.offset_question = parsed_packet.offset_question;
381        self.offset_answers = parsed_packet.offset_answers;
382        self.offset_nameservers = parsed_packet.offset_nameservers;
383        self.offset_additional = parsed_packet.offset_additional;
384        self.offset_edns = parsed_packet.offset_edns;
385        assert_eq!(self.edns_count, parsed_packet.edns_count);
386        assert_eq!(self.ext_rcode, parsed_packet.ext_rcode);
387        assert_eq!(self.edns_version, parsed_packet.edns_version);
388        assert_eq!(self.ext_flags, parsed_packet.ext_flags);
389        self.maybe_compressed = false;
390        self.packet = Some(parsed_packet.into_packet());
391        self.cached = None;
392        Ok(())
393    }
394
395    /// Returns the question as a raw vector, without case conversion, as well
396    /// as the query type and class Names include a trailing `0`
397    pub fn question_raw0(&mut self) -> Option<(&[u8], u16, u16)> {
398        if let Some(ref cached) = self.cached {
399            return Some((&cached.0, cached.1, cached.2));
400        }
401        let offset = match self.offset_question {
402            None => return None,
403            Some(offset) => offset,
404        };
405        let mut name = Vec::with_capacity(DNS_MAX_HOSTNAME_LEN);
406        let uncompressed_name_result =
407            Compress::copy_uncompressed_name(&mut name, self.packet(), offset);
408        let offset = uncompressed_name_result.final_offset;
409        let (rr_type, rr_class) = {
410            let rdata = &self.packet()[offset..];
411            let rr_type = BigEndian::read_u16(&rdata[DNS_RR_TYPE_OFFSET..]);
412            let rr_class = BigEndian::read_u16(&rdata[DNS_RR_CLASS_OFFSET..]);
413            (rr_type, rr_class)
414        };
415        self.cached = Some((name, rr_type, rr_class));
416        let cached = self.cached.as_ref().unwrap();
417        Some((&cached.0, cached.1, cached.2))
418    }
419
420    /// Returns the question as a raw vector, without case conversion, as well
421    /// as the query type and class Names do not include trailing `0`
422    pub fn question_raw(&mut self) -> Option<(&[u8], u16, u16)> {
423        self.question_raw0()
424            .map(|(name, rr_type, rr_class)| (&name[..name.len() - 1], rr_type, rr_class))
425    }
426
427    /// Returns the question as a string, without case conversion, as well as
428    /// the query type and class
429    pub fn question(&mut self) -> Option<(Vec<u8>, u16, u16)> {
430        if let Some(ref cached) = self.cached {
431            let mut name_str = Compress::raw_name_to_str(&cached.0, 0);
432            name_str.make_ascii_lowercase();
433            return Some((name_str, cached.1, cached.2));
434        }
435        let offset = match self.offset_question {
436            None => return None,
437            Some(offset) => offset,
438        };
439        let mut name_str = Compress::raw_name_to_str(self.packet(), offset);
440        name_str.make_ascii_lowercase();
441        let offset = offset + Compress::raw_name_len(&self.packet()[offset..]);
442        let (rr_type, rr_class) = {
443            let rdata = &self.packet()[offset..];
444            let rr_type = BigEndian::read_u16(&rdata[DNS_RR_TYPE_OFFSET..]);
445            let rr_class = BigEndian::read_u16(&rdata[DNS_RR_CLASS_OFFSET..]);
446            (rr_type, rr_class)
447        };
448        Some((name_str, rr_type, rr_class))
449    }
450
451    /// Return the query type and class
452    pub fn qtype_qclass(&self) -> Option<(u16, u16)> {
453        if let Some(ref cached) = self.cached {
454            return Some((cached.1, cached.2));
455        }
456        let offset = match self.offset_question {
457            None => return None,
458            Some(offset) => offset,
459        };
460        let offset = offset + Compress::raw_name_len(&self.packet()[offset..]);
461        let (rr_type, rr_class) = {
462            let rdata = &self.packet()[offset..];
463            let rr_type = BigEndian::read_u16(&rdata[DNS_RR_TYPE_OFFSET..]);
464            let rr_class = BigEndian::read_u16(&rdata[DNS_RR_CLASS_OFFSET..]);
465            (rr_type, rr_class)
466        };
467        Some((rr_type, rr_class))
468    }
469
470    /// Replaces `source_name` with `target_name` in all names, in all records.
471    /// If `match_suffix` is `true`, do suffix matching instead of exact
472    /// matching This allows renaming `*.example.com` into `*.example.net`.
473    pub fn rename_with_raw_names(
474        &mut self,
475        target_name: &[u8],
476        source_name: &[u8],
477        match_suffix: bool,
478    ) -> Result<(), Error> {
479        let packet = Renamer::rename_with_raw_names(self, target_name, source_name, match_suffix)?;
480        self.packet = Some(packet);
481        let dns_sector = DNSSector::new(self.packet.take().unwrap())?;
482        let parsed_packet = dns_sector.parse()?; // XXX - This can be recomputed on the fly by Renamer::rename_with_raw_names()
483        self.offset_question = parsed_packet.offset_question;
484        self.offset_answers = parsed_packet.offset_answers;
485        self.offset_nameservers = parsed_packet.offset_nameservers;
486        self.offset_additional = parsed_packet.offset_additional;
487        self.offset_edns = parsed_packet.offset_edns;
488        assert_eq!(self.edns_count, parsed_packet.edns_count);
489        assert_eq!(self.ext_rcode, parsed_packet.ext_rcode);
490        assert_eq!(self.edns_version, parsed_packet.edns_version);
491        assert_eq!(self.ext_flags, parsed_packet.ext_flags);
492        self.maybe_compressed = true;
493        Ok(())
494    }
495}