trust_dns_proto/rr/
type_bit_map.rs

1// Copyright 2015-2021 Benjamin Fry <benjaminfry@me.com>
2//
3// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
4// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5// http://opensource.org/licenses/MIT>, at your option. This file may not be
6// copied, modified, or distributed except according to those terms.
7
8//! type bit map helper definitions
9
10use crate::error::*;
11use crate::rr::RecordType;
12use crate::serialize::binary::*;
13use std::collections::BTreeMap;
14
15enum BitMapReadState {
16    Window,
17    Len {
18        window: u8,
19    },
20    RecordType {
21        window: u8,
22        len: Restrict<u8>,
23        left: Restrict<u8>,
24    },
25}
26
27/// Encode the bit map
28///
29/// # Arguments
30///
31/// * `encoder` - the encoder to write to
32/// * `type_bit_maps` - types to encode into the bitmap
33pub(crate) fn encode_type_bit_maps(
34    encoder: &mut BinEncoder<'_>,
35    type_bit_maps: &[RecordType],
36) -> ProtoResult<()> {
37    let mut hash: BTreeMap<u8, Vec<u8>> = BTreeMap::new();
38    let mut type_bit_maps = type_bit_maps.to_vec();
39    type_bit_maps.sort();
40
41    // collect the bitmaps
42    for rr_type in type_bit_maps {
43        let code: u16 = (rr_type).into();
44        let window: u8 = (code >> 8) as u8;
45        let low: u8 = (code & 0x00FF) as u8;
46
47        let bit_map: &mut Vec<u8> = hash.entry(window).or_insert_with(Vec::new);
48        // len + left is the block in the bitmap, divided by 8 for the bits, + the bit in the current_byte
49        let index: u8 = low / 8;
50        let bit: u8 = 0b1000_0000 >> (low % 8);
51
52        // adding necessary space to the vector
53        if bit_map.len() < (index as usize + 1) {
54            bit_map.resize(index as usize + 1, 0_u8);
55        }
56
57        bit_map[index as usize] |= bit;
58    }
59
60    // output bitmaps
61    for (window, bitmap) in hash {
62        encoder.emit(window)?;
63        // the hashset should never be larger that 255 based on above logic.
64        encoder.emit(bitmap.len() as u8)?;
65        for bits in bitmap {
66            encoder.emit(bits)?;
67        }
68    }
69
70    Ok(())
71}
72
73/// Decodes the array of RecordTypes covered by this NSEC record
74///
75/// # Arguments
76///
77/// * `decoder` - decoder to read from
78/// * `bit_map_len` - the number bytes in the bit map
79///
80/// # Returns
81///
82/// The Array of covered types
83pub(crate) fn decode_type_bit_maps(
84    decoder: &mut BinDecoder<'_>,
85    bit_map_len: Restrict<usize>,
86) -> ProtoResult<Vec<RecordType>> {
87    // 3.2.1.  Type Bit Maps Encoding
88    //
89    //  The encoding of the Type Bit Maps field is the same as that used by
90    //  the NSEC RR, described in [RFC4034].  It is explained and clarified
91    //  here for clarity.
92    //
93    //  The RR type space is split into 256 window blocks, each representing
94    //  the low-order 8 bits of the 16-bit RR type space.  Each block that
95    //  has at least one active RR type is encoded using a single octet
96    //  window number (from 0 to 255), a single octet bitmap length (from 1
97    //  to 32) indicating the number of octets used for the bitmap of the
98    //  window block, and up to 32 octets (256 bits) of bitmap.
99    //
100    //  Blocks are present in the NSEC3 RR RDATA in increasing numerical
101    //  order.
102    //
103    //     Type Bit Maps Field = ( Window Block # | Bitmap Length | Bitmap )+
104    //
105    //     where "|" denotes concatenation.
106    //
107    //  Each bitmap encodes the low-order 8 bits of RR types within the
108    //  window block, in network bit order.  The first bit is bit 0.  For
109    //  window block 0, bit 1 corresponds to RR type 1 (A), bit 2 corresponds
110    //  to RR type 2 (NS), and so forth.  For window block 1, bit 1
111    //  corresponds to RR type 257, bit 2 to RR type 258.  If a bit is set to
112    //  1, it indicates that an RRSet of that type is present for the
113    //  original owner name of the NSEC3 RR.  If a bit is set to 0, it
114    //  indicates that no RRSet of that type is present for the original
115    //  owner name of the NSEC3 RR.
116    //
117    //  Since bit 0 in window block 0 refers to the non-existing RR type 0,
118    //  it MUST be set to 0.  After verification, the validator MUST ignore
119    //  the value of bit 0 in window block 0.
120    //
121    //  Bits representing Meta-TYPEs or QTYPEs as specified in Section 3.1 of
122    //  [RFC2929] or within the range reserved for assignment only to QTYPEs
123    //  and Meta-TYPEs MUST be set to 0, since they do not appear in zone
124    //  data.  If encountered, they must be ignored upon reading.
125    //
126    //  Blocks with no types present MUST NOT be included.  Trailing zero
127    //  octets in the bitmap MUST be omitted.  The length of the bitmap of
128    //  each block is determined by the type code with the largest numerical
129    //  value, within that block, among the set of RR types present at the
130    //  original owner name of the NSEC3 RR.  Trailing octets not specified
131    //  MUST be interpreted as zero octets.
132    let mut record_types: Vec<RecordType> = Vec::new();
133    let mut state: BitMapReadState = BitMapReadState::Window;
134
135    // loop through all the bytes in the bitmap
136    for _ in 0..bit_map_len.unverified(/*bounded over any length of u16*/) {
137        let current_byte = decoder.read_u8()?;
138
139        state = match state {
140            BitMapReadState::Window => BitMapReadState::Len {
141                window: current_byte.unverified(/*window is any valid u8,*/),
142            },
143            BitMapReadState::Len { window } => BitMapReadState::RecordType {
144                window,
145                len: current_byte,
146                left: current_byte,
147            },
148            BitMapReadState::RecordType { window, len, left } => {
149                // window is the Window Block # from above
150                // len is the Bitmap Length
151                // current_byte is the Bitmap
152                let mut bit_map = current_byte.unverified(/*validated and restricted in usage in following usage*/);
153
154                // for all the bits in the current_byte
155                for i in 0..8 {
156                    // if the current_bytes most significant bit is set
157                    if bit_map & 0b1000_0000 == 0b1000_0000 {
158                        // len - left is the block in the bitmap, times 8 for the bits, + the bit in the current_byte
159                        let low_byte: u8 = len
160                            .checked_sub(left.unverified(/*will fail as param in this call if invalid*/))
161                            .checked_mul(8)
162                            .checked_add(i)
163                            .map_err(|_| "block len or left out of bounds in NSEC(3)")?
164                            .unverified(/*any u8 is valid at this point*/);
165                        let rr_type: u16 = (u16::from(window) << 8) | u16::from(low_byte);
166                        record_types.push(RecordType::from(rr_type));
167                    }
168                    // shift left and look at the next bit
169                    bit_map <<= 1;
170                }
171
172                // move to the next section of the bit_map
173                let left = left
174                    .checked_sub(1)
175                    .map_err(|_| ProtoError::from("block left out of bounds in NSEC(3)"))?;
176                if left.unverified(/*comparison is safe*/) == 0 {
177                    // we've exhausted this Window, move to the next
178                    BitMapReadState::Window
179                } else {
180                    // continue reading this Window
181                    BitMapReadState::RecordType { window, len, left }
182                }
183            }
184        };
185    }
186
187    Ok(record_types)
188}
189
190#[cfg(test)]
191mod tests {
192    #![allow(clippy::dbg_macro, clippy::print_stdout)]
193
194    use super::*;
195
196    #[test]
197    fn test_encode_decode() {
198        let types = vec![RecordType::A, RecordType::NS];
199
200        let mut bytes = Vec::new();
201        let mut encoder: BinEncoder<'_> = BinEncoder::new(&mut bytes);
202        assert!(encode_type_bit_maps(&mut encoder, &types).is_ok());
203        let bytes = encoder.into_bytes();
204
205        let mut decoder: BinDecoder<'_> = BinDecoder::new(bytes);
206        let restrict = Restrict::new(bytes.len());
207        let read_bit_map = decode_type_bit_maps(&mut decoder, restrict).expect("Decoding error");
208        assert_eq!(types, read_bit_map);
209    }
210}