Skip to main content

dnssector/
rr_iterator.rs

1use std::marker;
2use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
3
4use byteorder::{BigEndian, ByteOrder};
5
6use crate::compress::*;
7use crate::constants::*;
8use crate::dns_sector::*;
9use crate::errors::*;
10use crate::parsed_packet::*;
11
12/// Accessor to the raw packet data.
13/// `offset` is the offset to the current RR.
14/// `name_end` is the offset to the data right after the name.
15#[derive(Copy, Clone, Debug)]
16pub struct RRRaw<'t> {
17    pub packet: &'t [u8],
18    pub offset: usize,
19    pub name_end: usize,
20}
21
22/// Mutable accessor to the raw packet data.
23/// `offset` is the offset to the current RR.
24/// `name_end` is the offset to the data right after the name.
25pub struct RRRawMut<'t> {
26    pub packet: &'t mut [u8],
27    pub offset: usize,
28    pub name_end: usize,
29}
30
31/// The `DNSIterable` trait represents a set of records that can be iterated
32/// over.
33pub trait DNSIterable {
34    /// Returns the next record, or `None` if there aren't any left.
35    fn next(self) -> Option<Self>
36    where
37        Self: marker::Sized;
38
39    /// Returns the offset of the current RR, or `None` if we haven't started
40    /// iterating yet or if the current record has been deleted.
41    ///
42    /// In order to check for the later, please use `is_tombstone()` instead for
43    /// clarity.
44    fn offset(&self) -> Option<usize>;
45
46    /// Returns the offset right after the current RR.
47    fn offset_next(&self) -> usize;
48
49    /// Sets the offset of the current RR.
50    fn set_offset(&mut self, offset: usize);
51
52    /// Sets the offset of the next RR.
53    fn set_offset_next(&mut self, offset: usize);
54
55    /// Prevents access to the current record.
56    /// This is useful after a delete operation: from a user perspective, the
57    /// current iterator doesn't point to a valid RR any more.
58    fn invalidate(&mut self);
59
60    /// Returns `true` if the record has been invalidated by a previous call to
61    /// `delete()`
62    fn is_tombstone(&self) -> bool {
63        self.offset().is_none()
64    }
65
66    /// Updates the precomputed RR information
67    fn recompute_rr(&mut self);
68
69    /// Updates the precomputed offsets of each section.
70    fn recompute_sections(&mut self);
71
72    /// Accesses the raw packet data.
73    fn raw(&self) -> RRRaw<'_>;
74
75    /// Accesses the mutable raw packet data.
76    fn raw_mut(&mut self) -> RRRawMut<'_>;
77
78    /// Accesses the parsed packet structure.
79    fn parsed_packet(&self) -> &ParsedPacket;
80
81    /// Accesses the parsed packet structure.
82    fn parsed_packet_mut(&mut self) -> &mut ParsedPacket;
83
84    /// Raw packet data.
85    #[inline]
86    fn packet(&self) -> &[u8] {
87        let raw = self.raw();
88        raw.packet
89    }
90
91    /// Accesses the raw packet data, starting from the name.
92    #[inline]
93    fn name_slice(&self) -> &[u8] {
94        let raw = self.raw();
95        &raw.packet[raw.offset..raw.name_end]
96    }
97
98    /// Access the raw packet data, starting from right after the name.
99    #[inline]
100    fn rdata_slice(&self) -> &[u8] {
101        let raw = self.raw();
102        &raw.packet[raw.name_end..]
103    }
104
105    /// Accesses the mutable raw packet data, starting from the name.
106    #[inline]
107    fn name_slice_mut(&mut self) -> &mut [u8] {
108        let raw = self.raw_mut();
109        &mut raw.packet[raw.offset..raw.name_end]
110    }
111
112    /// Accesses the mutable raw packet data, starting from right after the
113    /// name.
114    #[inline]
115    fn rdata_slice_mut(&mut self) -> &mut [u8] {
116        let raw = self.raw_mut();
117        &mut raw.packet[raw.name_end..]
118    }
119
120    /// Decompresses the whole packet while keeping the iterator available.
121    fn uncompress(&mut self) -> Result<(), Error> {
122        if !self.parsed_packet().maybe_compressed {
123            return Ok(());
124        }
125        let (uncompressed, new_offset_next) = {
126            let ref_offset_next = self.offset_next();
127            let compressed = self.raw_mut().packet;
128            Compress::uncompress_with_previous_offset(compressed, ref_offset_next)?
129        };
130        self.parsed_packet_mut().packet = Some(uncompressed);
131        self.set_offset_next(new_offset_next);
132        self.recompute_sections();
133        self.recompute_rr();
134        Ok(())
135    }
136}
137
138pub trait TypedIterable {
139    /// Returns the RR name (labels are dot-delimited), as a byte vector. The
140    /// name is not supposed to be valid UTF-8. It will be converted to
141    /// lower-case, though, using traditional DNS conversion rules
142    fn name(&self) -> Vec<u8>
143    where
144        Self: DNSIterable,
145    {
146        let raw = self.raw();
147        let offset = raw.offset;
148        if raw.name_end <= offset {
149            return Vec::new();
150        }
151        let packet = raw.packet;
152        let mut name = Compress::raw_name_to_str(packet, offset);
153        name.make_ascii_lowercase();
154        name
155    }
156
157    /// Appends the uncompressed RR name (raw format, with labels prefixed by
158    /// their length) to the given vector. Returns the length of the
159    /// uncompressed name.
160    fn copy_raw_name(&self, name: &mut Vec<u8>) -> usize
161    where
162        Self: DNSIterable,
163    {
164        let raw = self.raw();
165        if raw.name_end <= raw.offset {
166            return 0;
167        }
168        Compress::copy_uncompressed_name(name, raw.packet, raw.offset).name_len
169    }
170
171    /// Returns the section the current record belongs to.
172    fn current_section(&self) -> Result<Section, Error>
173    where
174        Self: DNSIterable,
175    {
176        let offset = self.offset();
177        let parsed_packet = self.parsed_packet();
178        if offset < parsed_packet.offset_question {
179            bail!(DSError::InternalError("name before the question section"));
180        }
181        let mut section = Section::Question;
182        if parsed_packet.offset_answers.is_some() && offset >= parsed_packet.offset_answers {
183            section = Section::Answer;
184        }
185        if parsed_packet.offset_nameservers.is_some() && offset >= parsed_packet.offset_nameservers
186        {
187            section = Section::NameServers
188        }
189        if parsed_packet.offset_additional.is_some() && offset >= parsed_packet.offset_additional {
190            section = Section::Additional;
191        }
192        Ok(section)
193    }
194
195    /// Resizes the current record, by growing or shrinking (with a negative
196    /// value) the current record size by `shift` bytes.
197    fn resize_rr(&mut self, shift: isize) -> Result<(), Error>
198    where
199        Self: DNSIterable,
200    {
201        {
202            if shift == 0 {
203                return Ok(());
204            }
205            let offset = self.offset().ok_or(DSError::VoidRecord)?;
206            let packet = &mut self.parsed_packet_mut().packet_mut();
207            let packet_len = packet.len();
208            if shift > 0 {
209                let new_packet_len = packet_len + shift as usize;
210                if new_packet_len > 0xffff {
211                    bail!(DSError::PacketTooLarge);
212                }
213                packet.resize(new_packet_len, 0);
214                debug_assert_eq!(
215                    new_packet_len,
216                    (offset as isize + shift) as usize + (packet_len - offset)
217                );
218                packet.copy_within(offset..offset + packet_len, offset + shift as usize);
219            } else if shift < 0 {
220                let shift = (-shift) as usize;
221                assert!(packet_len >= shift);
222                packet.copy_within(offset + shift.., offset);
223                packet.truncate(packet_len - shift);
224            }
225        }
226        let new_offset_next = (self.offset_next() as isize + shift) as usize;
227        self.set_offset_next(new_offset_next);
228        let section = self.current_section()?;
229        let parsed_packet = self.parsed_packet_mut();
230        if section == Section::NameServers
231            || section == Section::Answer
232            || section == Section::Question
233        {
234            parsed_packet.offset_additional = parsed_packet
235                .offset_additional
236                .map(|x| (x as isize + shift) as usize)
237        }
238        if section == Section::Answer || section == Section::Question {
239            parsed_packet.offset_nameservers = parsed_packet
240                .offset_nameservers
241                .map(|x| (x as isize + shift) as usize)
242        }
243        if section == Section::Question {
244            parsed_packet.offset_answers = parsed_packet
245                .offset_answers
246                .map(|x| (x as isize + shift) as usize)
247        }
248        Ok(())
249    }
250
251    /// Changes the name (raw format, untrusted content).
252    fn set_raw_name(&mut self, name: &[u8]) -> Result<(), Error>
253    where
254        Self: DNSIterable,
255    {
256        let new_name_len = DNSSector::check_uncompressed_name(name, 0)?;
257        let name = &name[..new_name_len];
258        if self.parsed_packet().maybe_compressed {
259            let (uncompressed, new_offset) = {
260                let ref_offset = self.offset().ok_or(DSError::VoidRecord)?;
261                let compressed = self.raw_mut().packet;
262                Compress::uncompress_with_previous_offset(compressed, ref_offset)?
263            };
264            self.parsed_packet_mut().packet = Some(uncompressed);
265            self.set_offset(new_offset);
266            self.recompute_rr(); // XXX - Just for sanity, but not strictly required here
267            self.recompute_sections();
268        }
269        let offset = self.offset().ok_or(DSError::VoidRecord)?;
270        debug_assert!(!self.parsed_packet().maybe_compressed);
271        let current_name_len = Compress::raw_name_len(self.name_slice());
272        let shift = new_name_len as isize - current_name_len as isize;
273        self.resize_rr(shift)?;
274        {
275            let packet = &mut self.parsed_packet_mut().packet_mut();
276            packet[offset..offset + new_name_len].copy_from_slice(name);
277        }
278        self.recompute_rr();
279
280        Ok(())
281    }
282
283    /// Deletes the record
284    fn delete(&mut self) -> Result<(), Error>
285    where
286        Self: DNSIterable,
287    {
288        self.offset().ok_or(DSError::VoidRecord)?;
289        let section = self.current_section()?;
290        if self.parsed_packet().maybe_compressed {
291            let (uncompressed, new_offset) = {
292                let ref_offset = self.offset().expect("delete() called on a tombstone");
293                let compressed = self.raw_mut().packet;
294                Compress::uncompress_with_previous_offset(compressed, ref_offset)?
295            };
296            self.parsed_packet_mut().packet = Some(uncompressed);
297            self.set_offset(new_offset);
298            self.recompute_rr(); // XXX - Just for sanity, but not strictly required here
299            self.recompute_sections();
300        }
301        let rr_len = self.offset_next()
302            - self
303                .offset()
304                .expect("Deleting record with no known offset after optional decompression");
305        assert!(rr_len > 0);
306        self.resize_rr(-(rr_len as isize))?;
307        let offset = self.offset().unwrap();
308        self.set_offset_next(offset);
309        self.invalidate();
310        let parsed_packet = self.parsed_packet_mut();
311        let rrcount = parsed_packet.rrcount_dec(section)?;
312        if rrcount <= 0 {
313            let offset = match section {
314                Section::Question => &mut parsed_packet.offset_question,
315                Section::Answer => &mut parsed_packet.offset_answers,
316                Section::NameServers => &mut parsed_packet.offset_nameservers,
317                Section::Additional => &mut parsed_packet.offset_additional,
318                _ => panic!("delete() cannot be used to delete EDNS pseudo-records"),
319            };
320            *offset = None;
321        }
322        Ok(())
323    }
324
325    /// Returns the query type for the current RR.
326    #[inline]
327    fn rr_type(&self) -> u16
328    where
329        Self: DNSIterable,
330    {
331        BigEndian::read_u16(&self.rdata_slice()[DNS_RR_TYPE_OFFSET..])
332    }
333
334    /// Returns the query class for the current RR.
335    #[inline]
336    fn rr_class(&self) -> u16
337    where
338        Self: DNSIterable,
339    {
340        BigEndian::read_u16(&self.rdata_slice()[DNS_RR_CLASS_OFFSET..])
341    }
342}
343
344/// Raw RR data.
345#[derive(Copy, Clone, Debug)]
346pub enum RawRRData<'t> {
347    IpAddr(IpAddr),
348    Data(&'t [u8]),
349}
350
351pub trait RdataIterable {
352    /// Returns the TTL for the current RR.
353    #[inline]
354    fn rr_ttl(&self) -> u32
355    where
356        Self: DNSIterable + TypedIterable,
357    {
358        BigEndian::read_u32(&self.rdata_slice()[DNS_RR_TTL_OFFSET..])
359    }
360
361    /// Changes the TTL of a record.
362    fn set_rr_ttl(&mut self, ttl: u32)
363    where
364        Self: DNSIterable + TypedIterable,
365    {
366        BigEndian::write_u32(&mut self.rdata_slice_mut()[DNS_RR_TTL_OFFSET..], ttl);
367    }
368
369    /// Returns the record length for the current RR.
370    #[inline]
371    fn rr_rdlen(&self) -> usize
372    where
373        Self: DNSIterable + TypedIterable,
374    {
375        BigEndian::read_u16(&self.rdata_slice()[DNS_RR_RDLEN_OFFSET..]) as usize
376    }
377
378    /// Returns the raw record data for the current RR.
379    fn rr_rd(&self) -> Result<RawRRData<'_>, Error>
380    where
381        Self: DNSIterable + TypedIterable,
382    {
383        if let Ok(ip_addr) = self.rr_ip() {
384            return Ok(RawRRData::IpAddr(ip_addr));
385        }
386        let rdata_len = self.rr_rdlen();
387        let rdata = &self.rdata_slice()[DNS_RR_HEADER_SIZE..DNS_RR_HEADER_SIZE + rdata_len];
388        Ok(RawRRData::Data(rdata))
389    }
390
391    /// Retrieves the IP address of an `A` or `AAAA` record.
392    fn rr_ip(&self) -> Result<IpAddr, Error>
393    where
394        Self: DNSIterable + TypedIterable,
395    {
396        match self.rr_type() {
397            x if x == Type::A.into() => {
398                let rdata = self.rdata_slice();
399                assert!(rdata.len() >= DNS_RR_HEADER_SIZE + 4);
400                let mut ip = [0u8; 4];
401                ip.copy_from_slice(&rdata[DNS_RR_HEADER_SIZE..DNS_RR_HEADER_SIZE + 4]);
402                Ok(IpAddr::V4(Ipv4Addr::from(ip)))
403            }
404            x if x == Type::AAAA.into() => {
405                let rdata = self.rdata_slice();
406                assert!(rdata.len() >= DNS_RR_HEADER_SIZE + 16);
407                let mut ip = [0u8; 16];
408                ip.copy_from_slice(&rdata[DNS_RR_HEADER_SIZE..DNS_RR_HEADER_SIZE + 16]);
409                Ok(IpAddr::V6(Ipv6Addr::from(ip)))
410            }
411            _ => bail!(DSError::PropertyNotFound),
412        }
413    }
414
415    /// Changes the IP address of an `A` or `AAAA` record.
416    fn set_rr_ip(&mut self, ip: &IpAddr) -> Result<(), Error>
417    where
418        Self: DNSIterable + TypedIterable,
419    {
420        match self.rr_type() {
421            x if x == Type::A.into() => match *ip {
422                IpAddr::V4(ip) => {
423                    let rdata = self.rdata_slice_mut();
424                    assert!(rdata.len() >= DNS_RR_HEADER_SIZE + 4);
425                    rdata[DNS_RR_HEADER_SIZE..DNS_RR_HEADER_SIZE + 4].copy_from_slice(&ip.octets());
426                    Ok(())
427                }
428                _ => bail!(DSError::WrongAddressFamily),
429            },
430            x if x == Type::AAAA.into() => match *ip {
431                IpAddr::V6(ip) => {
432                    let rdata = self.rdata_slice_mut();
433                    assert!(rdata.len() >= DNS_RR_HEADER_SIZE + 16);
434                    rdata[DNS_RR_HEADER_SIZE..DNS_RR_HEADER_SIZE + 16]
435                        .copy_from_slice(&ip.octets());
436                    Ok(())
437                }
438                _ => bail!(DSError::WrongAddressFamily),
439            },
440            _ => bail!(DSError::PropertyNotFound),
441        }
442    }
443}
444
445/// An `RRIterator` structure is a generic way to iterate over the records
446/// of a pre-parsed DNS packet. The packet is assumed to have been previously
447/// verified for conformance, so the functions provided here are optimized for
448/// speed instead of paranoia, and don't return catchable errors: out-of-bounds
449/// accesses will make the thread panic, which is exactly what we want: if this
450/// ever happens, it means that we failed at properly verifying the packet, so
451/// this is a bug, and it has to be fixed, not ignored.
452#[derive(Debug)]
453pub struct RRIterator<'t> {
454    pub parsed_packet: &'t mut ParsedPacket,
455    pub section: Section,
456    pub offset: Option<usize>,
457    pub offset_next: usize,
458    pub name_end: usize,
459    pub rrs_left: u16,
460}
461
462impl<'t> RRIterator<'t> {
463    /// Creates a new iterator over a pre-parsed packet, for the given
464    /// `section`.
465    pub fn new(parsed_packet: &'t mut ParsedPacket, section: Section) -> Self {
466        RRIterator {
467            parsed_packet,
468            section,
469            offset: None,
470            offset_next: 0,
471            name_end: 0,
472            rrs_left: 0,
473        }
474    }
475
476    pub fn recompute(&mut self) {
477        let offset = self
478            .offset
479            .expect("recompute() called prior to iterating over RRs");
480        let name_end = Self::skip_name(self.parsed_packet.packet(), offset);
481        let offset_next = Self::skip_rdata(self.parsed_packet.packet(), name_end);
482        self.name_end = name_end;
483        self.offset_next = offset_next;
484    }
485
486    /// Quickly skips over a DNS name, without validation/decompression.
487    /// Returns the location right after the name.
488    pub fn skip_name(packet: &[u8], mut offset: usize) -> usize {
489        let packet_len = packet.len();
490        loop {
491            let label_len = match packet[offset] {
492                len if len & 0xc0 == 0xc0 => {
493                    assert!(packet_len - offset > 2);
494                    offset += 2;
495                    break;
496                }
497                len => len,
498            } as usize;
499            assert!(label_len < packet_len - offset - 1);
500            offset += label_len + 1;
501            if label_len == 0 {
502                break;
503            }
504        }
505        offset
506    }
507
508    #[inline]
509    fn rr_rdlen(packet: &[u8], offset: usize) -> usize {
510        BigEndian::read_u16(&packet[offset + DNS_RR_RDLEN_OFFSET..]) as usize
511    }
512
513    #[inline]
514    pub fn skip_rdata(packet: &[u8], offset: usize) -> usize {
515        offset + DNS_RR_HEADER_SIZE + Self::rr_rdlen(packet, offset)
516    }
517
518    #[inline]
519    pub fn skip_rr(packet: &[u8], offset: usize) -> usize {
520        Self::skip_rdata(packet, Self::skip_name(packet, offset))
521    }
522
523    #[inline]
524    fn edns_rr_rdlen(packet: &[u8], offset: usize) -> usize {
525        BigEndian::read_u16(&packet[offset + DNS_EDNS_RR_RDLEN_OFFSET..]) as usize
526    }
527
528    pub fn edns_skip_rr(packet: &[u8], mut offset: usize) -> usize {
529        offset += DNS_EDNS_RR_HEADER_SIZE + Self::edns_rr_rdlen(packet, offset);
530        offset
531    }
532}