simple_dns/dns/rdata/
nsec.rs1use crate::{
2 bytes_buffer::BytesBuffer,
3 dns::WireFormat,
4 lib::Write,
5 lib::{Cow, Vec},
6 Name,
7};
8
9use super::RR;
10
11#[derive(Debug, PartialEq, Eq, Hash, Clone)]
13pub struct NSEC<'a> {
14 pub next_name: Name<'a>,
16 pub type_bit_maps: Vec<NsecTypeBitMap<'a>>,
18}
19
20#[derive(Debug, PartialEq, Eq, Hash, Clone)]
22pub struct NsecTypeBitMap<'a> {
23 pub window_block: u8,
25 pub bitmap: Cow<'a, [u8]>,
27}
28
29impl RR for NSEC<'_> {
30 const TYPE_CODE: u16 = 47;
31}
32
33impl<'a> WireFormat<'a> for NSEC<'a> {
34 const MINIMUM_LEN: usize = 0;
35 fn parse(data: &mut BytesBuffer<'a>) -> crate::Result<Self>
36 where
37 Self: Sized,
38 {
39 let next_name = Name::parse(data)?;
40 let mut type_bit_maps = Vec::new();
41 let mut prev_window_block = None;
42
43 while data.has_remaining() {
44 let window_block = data.get_u8()?;
45 if let Some(prev_window_block) = prev_window_block {
46 if window_block <= prev_window_block {
47 return Err(crate::SimpleDnsError::InvalidDnsPacket);
48 }
49 }
50
51 prev_window_block = Some(window_block);
52
53 let bitmap_length = data.get_u8()? as usize;
54 if bitmap_length > 32 {
55 return Err(crate::SimpleDnsError::InvalidDnsPacket);
56 }
57
58 let bitmap = data.get_slice(bitmap_length)?;
59
60 type_bit_maps.push(NsecTypeBitMap {
61 window_block,
62 bitmap: Cow::Borrowed(bitmap),
63 });
64 }
65
66 Ok(Self {
67 next_name,
68 type_bit_maps,
69 })
70 }
71
72 fn write_to<T: Write>(&self, out: &mut T) -> crate::Result<()> {
73 self.next_name.write_to(out)?;
74
75 let mut sorted = self.type_bit_maps.clone();
76 sorted.sort_by_key(|a| a.window_block);
77
78 for record in sorted.iter() {
79 out.write_all(&[record.window_block])?;
80 out.write_all(&[record.bitmap.len() as u8])?;
81 out.write_all(&record.bitmap)?;
82 }
83
84 Ok(())
85 }
86
87 fn len(&self) -> usize {
88 self.next_name.len()
91 + self
92 .type_bit_maps
93 .iter()
94 .map(|el| el.bitmap.len() + 2) .sum::<usize>()
96 }
97}
98
99impl NSEC<'_> {
100 pub fn into_owned<'b>(self) -> NSEC<'b> {
102 let type_bit_maps = self
103 .type_bit_maps
104 .into_iter()
105 .map(|x| NsecTypeBitMap {
106 window_block: x.window_block,
107 bitmap: x.bitmap.into_owned().into(),
108 })
109 .collect();
110 NSEC {
111 next_name: self.next_name.into_owned(),
112 type_bit_maps,
113 }
114 }
115}
116
117#[cfg(test)]
118mod tests {
119
120 use super::*;
121 use crate::lib::vec;
122
123 #[test]
124 fn parse_and_write_nsec() {
125 let nsec = NSEC {
126 next_name: Name::new("host.example.com.").unwrap(),
127 type_bit_maps: vec![NsecTypeBitMap {
128 window_block: 0,
129 bitmap: vec![64, 1, 0, 0, 0, 1].into(),
130 }],
131 };
132 let mut data = Vec::new();
133 nsec.write_to(&mut data).unwrap();
134
135 let nsec = NSEC::parse(&mut data[..].into()).unwrap();
136 assert_eq!(nsec.next_name, Name::new("host.example.com.").unwrap());
137 assert_eq!(nsec.type_bit_maps.len(), 1);
138 assert_eq!(nsec.type_bit_maps[0].window_block, 0);
139 assert_eq!(nsec.type_bit_maps[0].bitmap, vec![64, 1, 0, 0, 0, 1]);
140 }
141
142 #[test]
143 fn nsec_reports_correct_len() {
144 let nsec = NSEC {
145 next_name: Name::new("host.example.com.").unwrap(),
146 type_bit_maps: vec![
147 NsecTypeBitMap {
148 window_block: 0,
149 bitmap: vec![0x40, 0x01, 0x00, 0x00, 0x00, 0x01].into(),
150 },
151 NsecTypeBitMap {
152 window_block: 1,
153 bitmap: vec![0x40, 0x01, 0x00, 0x00, 0x00, 0x01].into(),
154 },
155 ],
156 };
157
158 let mut buffer = Vec::new();
159 nsec.write_to(&mut buffer).unwrap();
160 assert_eq!(buffer.len(), nsec.len());
161 }
162
163 #[test]
164 #[cfg(feature = "std")]
165 fn parse_sample() -> Result<(), Box<dyn std::error::Error>> {
166 use crate::{rdata::RData, ResourceRecord};
167 let sample_file = std::fs::read("samples/zonefile/NSEC.sample")?;
168
169 let sample_rdata = match ResourceRecord::parse(&mut sample_file[..].into())?.rdata {
170 RData::NSEC(rdata) => rdata,
171 _ => unreachable!(),
172 };
173
174 assert_eq!(
175 sample_rdata.next_name,
176 Name::new("host.example.com.").unwrap()
177 );
178 assert_eq!(sample_rdata.type_bit_maps.len(), 1);
179 assert_eq!(sample_rdata.type_bit_maps[0].window_block, 0);
180 assert_eq!(
181 sample_rdata.type_bit_maps[0].bitmap,
182 vec![64, 1, 0, 0, 0, 1]
183 );
184
185 Ok(())
186 }
187}