simple_dns/dns/rdata/
opt.rs1use crate::{
2 bytes_buffer::BytesBuffer,
3 dns::{header::Header, WireFormat},
4 lib::Cow,
5 lib::Vec,
6 lib::Write,
7 RCODE,
8};
9
10use super::RR;
11
12pub mod masks {
13 pub const RCODE_MASK: u32 = 0b0000_0000_0000_0000_0000_0000_1111_1111;
14 pub const VERSION_MASK: u32 = 0b0000_0000_0000_0000_1111_1111_0000_0000;
15}
16
17#[derive(Debug, PartialEq, Eq, Hash, Clone)]
24pub struct OPT<'a> {
25 pub opt_codes: Vec<OPTCode<'a>>,
27 pub udp_packet_size: u16,
29
30 pub version: u8,
32}
33
34impl RR for OPT<'_> {
35 const TYPE_CODE: u16 = 41;
36}
37
38impl<'a> WireFormat<'a> for OPT<'a> {
39 const MINIMUM_LEN: usize = 10;
40
41 fn parse(data: &mut BytesBuffer<'a>) -> crate::Result<Self>
42 where
43 Self: Sized,
44 {
45 let udp_packet_size = data.get_u16()?;
49 let ttl = data.get_u32()?;
51 let version = ((ttl & masks::VERSION_MASK) >> masks::VERSION_MASK.trailing_zeros()) as u8;
52
53 data.advance(2)?;
54
55 let mut opt_codes = Vec::new();
56 while data.has_remaining() {
57 let code = data.get_u16()?;
58 let length = data.get_u16()? as usize; let inner_data = Cow::Borrowed(data.get_slice(length)?);
61 opt_codes.push(OPTCode {
62 code,
63 data: inner_data,
64 });
65 }
66
67 Ok(Self {
68 opt_codes,
69 udp_packet_size,
70 version,
71 })
72 }
73
74 fn write_to<T: Write>(&self, out: &mut T) -> crate::Result<()> {
75 for code in self.opt_codes.iter() {
76 out.write_all(&code.code.to_be_bytes())?;
77 out.write_all(&(code.data.len() as u16).to_be_bytes())?;
78 out.write_all(&code.data)?;
79 }
80
81 Ok(())
82 }
83
84 fn len(&self) -> usize {
85 self.opt_codes.iter().map(|o| o.data.len() + 4).sum()
86 }
87}
88
89impl OPT<'_> {
90 pub(crate) fn extract_rcode_from_ttl(ttl: u32, header: &Header) -> RCODE {
91 let mut rcode = (ttl & masks::RCODE_MASK) << 4;
92 rcode |= header.response_code as u32;
93 RCODE::from(rcode as u16)
94 }
95
96 pub(crate) fn encode_ttl(&self, header: &Header) -> u32 {
97 let mut ttl: u32 = (header.response_code as u32 & masks::RCODE_MASK) >> 4;
98 ttl |= (self.version as u32) << masks::VERSION_MASK.trailing_zeros();
99 ttl
100 }
101 pub fn into_owned<'b>(self) -> OPT<'b> {
103 OPT {
104 udp_packet_size: self.udp_packet_size,
106 version: self.version,
107 opt_codes: self.opt_codes.into_iter().map(|o| o.into_owned()).collect(),
108 }
109 }
110}
111
112#[derive(Debug, PartialEq, Eq, Hash, Clone)]
114pub struct OPTCode<'a> {
115 pub code: u16,
118 pub data: Cow<'a, [u8]>,
120}
121
122impl OPTCode<'_> {
123 pub fn into_owned<'b>(self) -> OPTCode<'b> {
125 OPTCode {
126 code: self.code,
127 data: self.data.into_owned().into(),
128 }
129 }
130}
131
132#[cfg(test)]
133mod tests {
134 use crate::lib::vec;
135 use crate::{rdata::RData, Name, ResourceRecord};
136
137 use super::*;
138
139 #[test]
140 fn parse_and_write_opt_empty() {
141 let header = Header::new_reply(1, crate::OPCODE::StandardQuery);
142
143 let opt = OPT {
144 udp_packet_size: 500,
145 version: 2,
146 opt_codes: Vec::new(),
147 };
148 let opt_rr = ResourceRecord {
149 ttl: opt.encode_ttl(&header),
150 name: Name::new_unchecked("."),
151 class: crate::CLASS::IN,
152 cache_flush: false,
153 rdata: RData::OPT(opt),
154 };
155
156 let mut data = Vec::new();
157 assert!(opt_rr.write_to(&mut data).is_ok());
158
159 let opt = match ResourceRecord::parse(&mut data[..].into())
160 .expect("failed to parse")
161 .rdata
162 {
163 RData::OPT(rdata) => rdata,
164 _ => unreachable!(),
165 };
166
167 assert_eq!(data.len(), opt_rr.len());
168 assert_eq!(500, opt.udp_packet_size);
169 assert_eq!(2, opt.version);
170 assert!(opt.opt_codes.is_empty());
171 }
172
173 #[test]
174 fn parse_and_write_opt() {
175 let header = Header::new_reply(1, crate::OPCODE::StandardQuery);
176
177 let opt = OPT {
178 udp_packet_size: 500,
179 version: 2,
180 opt_codes: vec![
181 OPTCode {
182 code: 1,
183 data: Cow::Owned(vec![255, 255]),
184 },
185 OPTCode {
186 code: 2,
187 data: Cow::Owned(vec![255, 255, 255]),
188 },
189 ],
190 };
191
192 let opt_rr = ResourceRecord {
193 ttl: opt.encode_ttl(&header),
194 name: Name::new_unchecked("."),
195 class: crate::CLASS::IN,
196 cache_flush: false,
197 rdata: RData::OPT(opt),
198 };
199
200 let mut data = Vec::new();
201 assert!(opt_rr.write_to(&mut data).is_ok());
202
203 let mut opt = match ResourceRecord::parse(&mut data[..].into())
204 .expect("failed to parse")
205 .rdata
206 {
207 RData::OPT(rdata) => rdata,
208 _ => unreachable!(),
209 };
210
211 assert_eq!(data.len(), opt_rr.len());
212 assert_eq!(500, opt.udp_packet_size);
213 assert_eq!(2, opt.version);
214 assert_eq!(2, opt.opt_codes.len());
215
216 let opt_code = opt.opt_codes.pop().unwrap();
217 assert_eq!(2, opt_code.code);
218 assert_eq!(vec![255, 255, 255], *opt_code.data);
219
220 let opt_code = opt.opt_codes.pop().unwrap();
221 assert_eq!(1, opt_code.code);
222 assert_eq!(vec![255, 255], *opt_code.data);
223 }
224}