1use core::fmt;
11
12#[cfg(feature = "serde")]
13use serde::{Deserialize, Serialize};
14
15#[cfg(feature = "__dnssec")]
16use crate::dnssec::{Algorithm, SupportedAlgorithms};
17use crate::{
18 error::*,
19 rr::{
20 DNSClass, Name, RData, Record, RecordType,
21 rdata::{
22 OPT,
23 opt::{EdnsCode, EdnsOption},
24 },
25 },
26 serialize::binary::{BinEncodable, BinEncoder},
27};
28
29#[derive(Debug, PartialEq, Eq, Clone)]
32#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
33pub struct Edns {
34 rcode_high: u8,
37 version: u8,
39 flags: EdnsFlags,
40 max_payload: u16,
42
43 options: OPT,
44}
45
46impl Default for Edns {
47 fn default() -> Self {
48 Self {
49 rcode_high: 0,
50 version: 0,
51 flags: EdnsFlags::default(),
52 max_payload: 512,
53 options: OPT::default(),
54 }
55 }
56}
57
58impl Edns {
59 pub fn new() -> Self {
61 Self::default()
62 }
63
64 pub fn rcode_high(&self) -> u8 {
66 self.rcode_high
67 }
68
69 pub fn version(&self) -> u8 {
71 self.version
72 }
73
74 pub fn flags(&self) -> &EdnsFlags {
76 &self.flags
77 }
78
79 pub fn flags_mut(&mut self) -> &mut EdnsFlags {
81 &mut self.flags
82 }
83
84 pub fn max_payload(&self) -> u16 {
86 self.max_payload
87 }
88
89 pub fn option(&self, code: EdnsCode) -> Option<&EdnsOption> {
91 self.options.get(code)
92 }
93
94 pub fn options(&self) -> &OPT {
96 &self.options
97 }
98
99 pub fn options_mut(&mut self) -> &mut OPT {
101 &mut self.options
102 }
103
104 pub fn set_rcode_high(&mut self, rcode_high: u8) -> &mut Self {
106 self.rcode_high = rcode_high;
107 self
108 }
109
110 pub fn set_version(&mut self, version: u8) -> &mut Self {
112 self.version = version;
113 self
114 }
115
116 #[cfg(feature = "__dnssec")]
118 pub fn enable_dnssec(&mut self) {
119 self.set_dnssec_ok(true);
120 self.set_default_algorithms();
121 }
122
123 #[cfg(feature = "__dnssec")]
125 pub fn set_default_algorithms(&mut self) -> &mut Self {
126 let mut algorithms = SupportedAlgorithms::new();
127
128 for algorithm in [
129 Algorithm::RSASHA256,
130 Algorithm::RSASHA512,
131 Algorithm::ECDSAP256SHA256,
132 Algorithm::ECDSAP384SHA384,
133 Algorithm::ED25519,
134 ] {
135 if algorithm.is_supported() {
136 algorithms.set(algorithm);
137 }
138 }
139
140 let dau = EdnsOption::DAU(algorithms);
141
142 self.options_mut().insert(dau);
143 self
144 }
145
146 pub fn set_dnssec_ok(&mut self, dnssec_ok: bool) -> &mut Self {
148 self.flags.dnssec_ok = dnssec_ok;
149 self
150 }
151
152 pub fn set_max_payload(&mut self, max_payload: u16) -> &mut Self {
155 self.max_payload = max_payload.max(512);
156 self
157 }
158}
159
160impl<'a> From<&'a Record> for Edns {
162 fn from(value: &'a Record) -> Self {
163 assert!(value.record_type() == RecordType::OPT);
164
165 let rcode_high = ((value.ttl & 0xFF00_0000u32) >> 24) as u8;
166 let version = ((value.ttl & 0x00FF_0000u32) >> 16) as u8;
167 let flags = EdnsFlags::from((value.ttl & 0x0000_FFFFu32) as u16);
168 let max_payload = u16::from(value.dns_class);
169
170 let options = match &value.data {
171 RData::Update0(..) | RData::NULL(..) => {
172 OPT::default()
174 }
175 RData::OPT(option_data) => {
176 option_data.clone() }
178 _ => {
179 panic!("rr_type doesn't match the RData: {:?}", value.data) }
182 };
183
184 Self {
185 rcode_high,
186 version,
187 flags,
188 max_payload,
189 options,
190 }
191 }
192}
193
194impl<'a> From<&'a Edns> for Record {
195 fn from(value: &'a Edns) -> Self {
198 let mut ttl: u32 = u32::from(value.rcode_high()) << 24;
200 ttl |= u32::from(value.version()) << 16;
201 ttl |= u32::from(u16::from(value.flags));
202
203 let mut record = Self::from_rdata(Name::root(), ttl, RData::OPT(value.options().clone()));
208 record.dns_class = DNSClass::for_opt(value.max_payload());
209 record
210 }
211}
212
213impl BinEncodable for Edns {
214 fn emit(&self, encoder: &mut BinEncoder<'_>) -> ProtoResult<()> {
215 encoder.emit(0)?; RecordType::OPT.emit(encoder)?; DNSClass::for_opt(self.max_payload()).emit(encoder)?; let mut ttl = u32::from(self.rcode_high()) << 24;
221 ttl |= u32::from(self.version()) << 16;
222 ttl |= u32::from(u16::from(self.flags));
223
224 encoder.emit_u32(ttl)?;
225
226 let place = encoder.place::<u16>()?;
228 self.options.emit(encoder)?;
229 let len = encoder.len_since_place(&place);
230 assert!(len <= u16::MAX as usize);
231
232 place.replace(encoder, len as u16)?;
233 Ok(())
234 }
235}
236
237impl fmt::Display for Edns {
238 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
239 let version = self.version;
240 let dnssec_ok = self.flags.dnssec_ok;
241 let z_flags = self.flags.z;
242 let max_payload = self.max_payload;
243
244 write!(
245 f,
246 "version: {version} dnssec_ok: {dnssec_ok} z_flags: {z_flags} max_payload: {max_payload} opts: {opts_len}",
247 opts_len = self.options().as_ref().len()
248 )
249 }
250}
251
252#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
256#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
257pub struct EdnsFlags {
258 pub dnssec_ok: bool,
260 pub z: u16,
267}
268
269impl From<u16> for EdnsFlags {
270 fn from(flags: u16) -> Self {
271 Self {
272 dnssec_ok: flags & 0x8000 == 0x8000,
273 z: flags & 0x7FFF,
274 }
275 }
276}
277
278impl From<EdnsFlags> for u16 {
279 fn from(flags: EdnsFlags) -> Self {
280 match flags.dnssec_ok {
281 true => 0x8000 | flags.z,
282 false => 0x7FFF & flags.z,
283 }
284 }
285}
286
287pub const DEFAULT_MAX_PAYLOAD_LEN: u16 = 1232;
293
294#[cfg(all(test, feature = "__dnssec"))]
295mod tests {
296 use super::*;
297
298 #[test]
299 fn test_encode_decode() {
300 let mut edns = Edns::new();
301
302 let flags = edns.flags_mut();
303 flags.dnssec_ok = true;
304 flags.z = 1;
305 edns.set_max_payload(0x8008);
306 edns.set_version(0x40);
307 edns.set_rcode_high(0x01);
308 edns.options_mut()
309 .insert(EdnsOption::DAU(SupportedAlgorithms::all()));
310
311 let record = Record::from(&edns);
312 let edns_decode = Edns::from(&record);
313
314 assert_eq!(edns.flags().dnssec_ok, edns_decode.flags().dnssec_ok);
315 assert_eq!(edns.flags().z, edns_decode.flags().z);
316 assert_eq!(edns.max_payload(), edns_decode.max_payload());
317 assert_eq!(edns.version(), edns_decode.version());
318 assert_eq!(edns.rcode_high(), edns_decode.rcode_high());
319 assert_eq!(edns.options(), edns_decode.options());
320
321 edns.options_mut()
323 .insert(EdnsOption::DAU(SupportedAlgorithms::all()));
324 edns.options_mut().remove(EdnsCode::DAU);
325 assert!(edns.option(EdnsCode::DAU).is_none());
326 }
327}