webrtc_mdns/message/resource/
mod.rs1pub mod a;
2pub mod aaaa;
3pub mod cname;
4pub mod mx;
5pub mod ns;
6pub mod opt;
7pub mod ptr;
8pub mod soa;
9pub mod srv;
10pub mod txt;
11
12use std::collections::HashMap;
13use std::fmt;
14
15use a::*;
16use aaaa::*;
17use cname::*;
18use mx::*;
19use ns::*;
20use opt::*;
21use ptr::*;
22use soa::*;
23use srv::*;
24use txt::*;
25
26use super::name::*;
27use super::packer::*;
28use super::*;
29use crate::error::*;
30
31const EDNS0_VERSION: u32 = 0;
34const EDNS0_DNSSEC_OK: u32 = 0x00008000;
35const EDNS_VERSION_MASK: u32 = 0x00ff0000;
36const EDNS0_DNSSEC_OK_MASK: u32 = 0x00ff8000;
37
38#[derive(Default, Debug)]
40pub struct Resource {
41 pub header: ResourceHeader,
42 pub body: Option<Box<dyn ResourceBody>>,
43}
44
45impl fmt::Display for Resource {
46 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
47 write!(
48 f,
49 "dnsmessage.Resource{{Header: {}, Body: {}}}",
50 self.header,
51 if let Some(body) = &self.body {
52 body.to_string()
53 } else {
54 "None".to_owned()
55 }
56 )
57 }
58}
59
60impl Resource {
61 pub fn pack(
63 &mut self,
64 msg: Vec<u8>,
65 compression: &mut Option<HashMap<String, usize>>,
66 compression_off: usize,
67 ) -> Result<Vec<u8>> {
68 if let Some(body) = &self.body {
69 self.header.typ = body.real_type();
70 } else {
71 return Err(Error::ErrNilResourceBody);
72 }
73 let (mut msg, len_off) = self.header.pack(msg, compression, compression_off)?;
74 let pre_len = msg.len();
75 if let Some(body) = &self.body {
76 msg = body.pack(msg, compression, compression_off)?;
77 self.header.fix_len(&mut msg, len_off, pre_len)?;
78 }
79 Ok(msg)
80 }
81
82 pub fn unpack(&mut self, msg: &[u8], mut off: usize) -> Result<usize> {
83 off = self.header.unpack(msg, off, 0)?;
84 let (rb, off) =
85 unpack_resource_body(self.header.typ, msg, off, self.header.length as usize)?;
86 self.body = Some(rb);
87 Ok(off)
88 }
89
90 pub(crate) fn skip(msg: &[u8], off: usize) -> Result<usize> {
91 let mut new_off = Name::skip(msg, off)?;
92 new_off = DnsType::skip(msg, new_off)?;
93 new_off = DnsClass::skip(msg, new_off)?;
94 new_off = skip_uint32(msg, new_off)?;
95 let (length, mut new_off) = unpack_uint16(msg, new_off)?;
96 new_off += length as usize;
97 if new_off > msg.len() {
98 return Err(Error::ErrResourceLen);
99 }
100 Ok(new_off)
101 }
102}
103
104#[derive(Clone, Default, PartialEq, Eq, Debug)]
107pub struct ResourceHeader {
108 pub name: Name,
110
111 pub typ: DnsType,
115
116 pub class: DnsClass,
119
120 pub ttl: u32,
124
125 pub length: u16,
129}
130
131impl fmt::Display for ResourceHeader {
132 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
133 write!(
134 f,
135 "dnsmessage.ResourceHeader{{Name: {}, Type: {}, Class: {}, TTL: {}, Length: {}}}",
136 self.name, self.typ, self.class, self.ttl, self.length,
137 )
138 }
139}
140
141impl ResourceHeader {
142 pub fn pack(
146 &self,
147 mut msg: Vec<u8>,
148 compression: &mut Option<HashMap<String, usize>>,
149 compression_off: usize,
150 ) -> Result<(Vec<u8>, usize)> {
151 msg = self.name.pack(msg, compression, compression_off)?;
152 msg = self.typ.pack(msg);
153 msg = self.class.pack(msg);
154 msg = pack_uint32(msg, self.ttl);
155 let len_off = msg.len();
156 msg = pack_uint16(msg, self.length);
157 Ok((msg, len_off))
158 }
159
160 pub fn unpack(&mut self, msg: &[u8], off: usize, _length: usize) -> Result<usize> {
161 let mut new_off = off;
162 new_off = self.name.unpack(msg, new_off)?;
163 new_off = self.typ.unpack(msg, new_off)?;
164 new_off = self.class.unpack(msg, new_off)?;
165 let (ttl, new_off) = unpack_uint32(msg, new_off)?;
166 self.ttl = ttl;
167 let (l, new_off) = unpack_uint16(msg, new_off)?;
168 self.length = l;
169
170 Ok(new_off)
171 }
172
173 pub fn fix_len(&mut self, msg: &mut [u8], len_off: usize, pre_len: usize) -> Result<()> {
180 if msg.len() < pre_len || msg.len() > pre_len + u16::MAX as usize {
181 return Err(Error::ErrResTooLong);
182 }
183
184 let con_len = msg.len() - pre_len;
185
186 msg[len_off] = ((con_len >> 8) & 0xFF) as u8;
188 msg[len_off + 1] = (con_len & 0xFF) as u8;
189 self.length = con_len as u16;
190
191 Ok(())
192 }
193
194 pub fn set_edns0(
198 &mut self,
199 udp_payload_len: u16,
200 ext_rcode: u32,
201 dnssec_ok: bool,
202 ) -> Result<()> {
203 self.name = Name {
204 data: ".".to_owned(),
205 }; self.typ = DnsType::Opt;
207 self.class = DnsClass(udp_payload_len);
208 self.ttl = (ext_rcode >> 4) << 24;
209 if dnssec_ok {
210 self.ttl |= EDNS0_DNSSEC_OK;
211 }
212 Ok(())
213 }
214
215 pub fn dnssec_allowed(&self) -> bool {
217 self.ttl & EDNS0_DNSSEC_OK_MASK == EDNS0_DNSSEC_OK }
219
220 pub fn extended_rcode(&self, rcode: RCode) -> RCode {
224 if self.ttl & EDNS_VERSION_MASK == EDNS0_VERSION {
225 let ttl = ((self.ttl >> 24) << 4) as u8 | rcode as u8;
227 return RCode::from(ttl);
228 }
229 rcode
230 }
231}
232
233pub trait ResourceBody: fmt::Display + fmt::Debug {
235 fn real_type(&self) -> DnsType;
238
239 fn pack(
241 &self,
242 msg: Vec<u8>,
243 compression: &mut Option<HashMap<String, usize>>,
244 compression_off: usize,
245 ) -> Result<Vec<u8>>;
246
247 fn unpack(&mut self, msg: &[u8], off: usize, length: usize) -> Result<usize>;
248}
249
250pub fn unpack_resource_body(
251 typ: DnsType,
252 msg: &[u8],
253 mut off: usize,
254 length: usize,
255) -> Result<(Box<dyn ResourceBody>, usize)> {
256 let mut rb: Box<dyn ResourceBody> = match typ {
257 DnsType::A => Box::<AResource>::default(),
258 DnsType::Ns => Box::<NsResource>::default(),
259 DnsType::Cname => Box::<CnameResource>::default(),
260 DnsType::Soa => Box::<SoaResource>::default(),
261 DnsType::Ptr => Box::<PtrResource>::default(),
262 DnsType::Mx => Box::<MxResource>::default(),
263 DnsType::Txt => Box::<TxtResource>::default(),
264 DnsType::Aaaa => Box::<AaaaResource>::default(),
265 DnsType::Srv => Box::<SrvResource>::default(),
266 DnsType::Opt => Box::<OptResource>::default(),
267 _ => return Err(Error::ErrNilResourceBody),
268 };
269
270 off = rb.unpack(msg, off, length)?;
271
272 Ok((rb, off))
273}