trust_dns_proto/op/
edns.rs1use std::fmt;
20
21use crate::error::*;
22use crate::rr::rdata::opt::{self, EdnsCode, EdnsOption};
23use crate::rr::rdata::OPT;
24use crate::rr::{DNSClass, Name, RData, Record, RecordType};
25
26use crate::serialize::binary::{BinEncodable, BinEncoder};
27
28#[derive(Debug, PartialEq, Eq, Clone)]
31pub struct Edns {
32 rcode_high: u8,
35 version: u8,
37 dnssec_ok: bool,
39 max_payload: u16,
41
42 options: OPT,
43}
44
45impl Default for Edns {
46 fn default() -> Self {
47 Self {
48 rcode_high: 0,
49 version: 0,
50 dnssec_ok: false,
51 max_payload: 512,
52 options: OPT::default(),
53 }
54 }
55}
56
57impl Edns {
58 pub fn new() -> Self {
60 Self::default()
61 }
62
63 pub fn rcode_high(&self) -> u8 {
65 self.rcode_high
66 }
67
68 pub fn version(&self) -> u8 {
70 self.version
71 }
72
73 pub fn dnssec_ok(&self) -> bool {
75 self.dnssec_ok
76 }
77
78 pub fn max_payload(&self) -> u16 {
80 self.max_payload
81 }
82
83 pub fn option(&self, code: EdnsCode) -> Option<&EdnsOption> {
85 self.options.get(code)
86 }
87
88 pub fn options(&self) -> &OPT {
90 &self.options
91 }
92
93 pub fn options_mut(&mut self) -> &mut OPT {
95 &mut self.options
96 }
97
98 pub fn set_rcode_high(&mut self, rcode_high: u8) -> &mut Self {
100 self.rcode_high = rcode_high;
101 self
102 }
103
104 pub fn set_version(&mut self, version: u8) -> &mut Self {
106 self.version = version;
107 self
108 }
109
110 pub fn set_dnssec_ok(&mut self, dnssec_ok: bool) -> &mut Self {
112 self.dnssec_ok = dnssec_ok;
113 self
114 }
115
116 pub fn set_max_payload(&mut self, max_payload: u16) -> &mut Self {
119 self.max_payload = max_payload.max(512);
120 self
121 }
122
123 #[deprecated(note = "Please use options_mut().insert() to modify")]
125 pub fn set_option(&mut self, option: EdnsOption) {
126 self.options.insert(option);
127 }
128}
129
130impl<'a> From<&'a Record> for Edns {
132 fn from(value: &'a Record) -> Self {
133 assert!(value.rr_type() == RecordType::OPT);
134
135 let rcode_high: u8 = ((value.ttl() & 0xFF00_0000u32) >> 24) as u8;
136 let version: u8 = ((value.ttl() & 0x00FF_0000u32) >> 16) as u8;
137 let dnssec_ok: bool = value.ttl() & 0x0000_8000 == 0x0000_8000;
138 let max_payload: u16 = u16::from(value.dns_class());
139
140 let options: OPT = match value.data() {
141 Some(RData::NULL(..)) | None => {
142 OPT::default()
144 }
145 Some(RData::OPT(ref option_data)) => {
146 option_data.clone() }
148 _ => {
149 panic!("rr_type doesn't match the RData: {:?}", value.data()) }
152 };
153
154 Self {
155 rcode_high,
156 version,
157 dnssec_ok,
158 max_payload,
159 options,
160 }
161 }
162}
163
164impl<'a> From<&'a Edns> for Record {
165 fn from(value: &'a Edns) -> Self {
168 let mut record = Self::new();
169
170 record.set_name(Name::root());
171 record.set_rr_type(RecordType::OPT);
172 record.set_dns_class(DNSClass::for_opt(value.max_payload()));
173
174 let mut ttl: u32 = u32::from(value.rcode_high()) << 24;
176 ttl |= u32::from(value.version()) << 16;
177
178 if value.dnssec_ok() {
179 ttl |= 0x0000_8000;
180 }
181 record.set_ttl(ttl);
182
183 record.set_data(Some(RData::OPT(value.options().clone())));
188
189 record
190 }
191}
192
193impl BinEncodable for Edns {
194 fn emit(&self, encoder: &mut BinEncoder<'_>) -> ProtoResult<()> {
195 encoder.emit(0)?; RecordType::OPT.emit(encoder)?; DNSClass::for_opt(self.max_payload()).emit(encoder)?; let mut ttl: u32 = u32::from(self.rcode_high()) << 24;
201 ttl |= u32::from(self.version()) << 16;
202
203 if self.dnssec_ok() {
204 ttl |= 0x0000_8000;
205 }
206
207 encoder.emit_u32(ttl)?;
208
209 let place = encoder.place::<u16>()?;
211 opt::emit(encoder, &self.options)?;
212 let len = encoder.len_since_place(&place);
213 assert!(len <= u16::max_value() as usize);
214
215 place.replace(encoder, len as u16)?;
216 Ok(())
217 }
218}
219
220impl fmt::Display for Edns {
221 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
222 let version = self.version;
223 let dnssec_ok = self.dnssec_ok;
224 let max_payload = self.max_payload;
225
226 write!(
227 f,
228 "version: {version} dnssec_ok: {dnssec_ok} max_payload: {max_payload} opts: {opts_len}",
229 version = version,
230 dnssec_ok = dnssec_ok,
231 max_payload = max_payload,
232 opts_len = self.options().as_ref().len()
233 )
234 }
235}
236
237#[cfg(feature = "dnssec")]
238#[test]
239fn test_encode_decode() {
240 use crate::rr::dnssec::SupportedAlgorithms;
241
242 let mut edns: Edns = Edns::new();
243
244 edns.set_dnssec_ok(true);
245 edns.set_max_payload(0x8008);
246 edns.set_version(0x40);
247 edns.set_rcode_high(0x01);
248 edns.options_mut()
249 .insert(EdnsOption::DAU(SupportedAlgorithms::all()));
250
251 let record: Record = (&edns).into();
252 let edns_decode: Edns = (&record).into();
253
254 assert_eq!(edns.dnssec_ok(), edns_decode.dnssec_ok());
255 assert_eq!(edns.max_payload(), edns_decode.max_payload());
256 assert_eq!(edns.version(), edns_decode.version());
257 assert_eq!(edns.rcode_high(), edns_decode.rcode_high());
258 assert_eq!(edns.options(), edns_decode.options());
259
260 edns.options_mut()
262 .insert(EdnsOption::DAU(SupportedAlgorithms::all()));
263 edns.options_mut().remove(EdnsCode::DAU);
264 assert!(edns.option(EdnsCode::DAU).is_none());
265}