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