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}