1mod a;
5mod aaaa;
6mod cname;
7mod nsec;
8mod ptr;
9mod srv;
10mod txt;
11
12pub use a::A;
13pub use aaaa::AAAA;
14pub use cname::Cname;
15pub use nsec::Nsec;
16pub use ptr::Ptr;
17pub use srv::Srv;
18#[allow(unused_imports)]
19pub use txt::{Txt, TxtSegments};
20
21cfg_heap! {
22 use crate::backend::{RdataBuf, rdata_from_vec};
23}
24
25use super::{NameRef, ResourceClass, ResourceType};
26use crate::error::{BufferTooShortDetail, ParseError, RdlengthOverrunDetail};
27
28#[derive(Debug, Copy, Clone, Eq, PartialEq)]
32pub struct Ref<'a> {
33 message: &'a [u8],
34 name: NameRef<'a>,
35 rtype: ResourceType,
36 rclass: ResourceClass,
37 cache_flush: bool,
38 ttl: u32,
39 rdata_start: usize,
40 rdata_len: usize,
41}
42
43impl<'a> Ref<'a> {
44 pub fn try_parse(message: &'a [u8], offset: usize) -> Result<(Self, usize), ParseError> {
47 use super::resource_class::CACHE_FLUSH_BIT;
48 let (name, name_bytes) = NameRef::try_parse(message, offset)?;
49 let after_name = offset.saturating_add(name_bytes);
50
51 let hdr = message
53 .get(after_name..after_name.saturating_add(10))
54 .ok_or_else(|| {
55 ParseError::BufferTooShort(BufferTooShortDetail::new(
56 10,
57 after_name,
58 message.len().saturating_sub(after_name),
59 ))
60 })?;
61
62 let rtype_arr: &[u8; 2] = hdr.first_chunk::<2>().ok_or_else(|| {
63 ParseError::BufferTooShort(BufferTooShortDetail::new(2, after_name, hdr.len()))
64 })?;
65 let rtype = ResourceType::from_u16(u16::from_be_bytes(*rtype_arr));
66
67 let rclass_raw_arr: &[u8; 2] = hdr
68 .get(2..4)
69 .and_then(|s| s.first_chunk::<2>())
70 .ok_or_else(|| {
71 ParseError::BufferTooShort(BufferTooShortDetail::new(
72 2,
73 after_name.saturating_add(2),
74 hdr.len(),
75 ))
76 })?;
77 let rclass_raw = u16::from_be_bytes(*rclass_raw_arr);
78 let cache_flush = (rclass_raw & CACHE_FLUSH_BIT) != 0;
79 let rclass = ResourceClass::from_u16(rclass_raw);
80
81 let ttl_arr: &[u8; 4] = hdr
82 .get(4..8)
83 .and_then(|s| s.first_chunk::<4>())
84 .ok_or_else(|| {
85 ParseError::BufferTooShort(BufferTooShortDetail::new(
86 4,
87 after_name.saturating_add(4),
88 hdr.len(),
89 ))
90 })?;
91 let ttl = u32::from_be_bytes(*ttl_arr);
92
93 let rdlen_arr: &[u8; 2] = hdr
94 .get(8..10)
95 .and_then(|s| s.first_chunk::<2>())
96 .ok_or_else(|| {
97 ParseError::BufferTooShort(BufferTooShortDetail::new(
98 2,
99 after_name.saturating_add(8),
100 hdr.len(),
101 ))
102 })?;
103 let rdlen = u16::from_be_bytes(*rdlen_arr);
104
105 let rdata_start = after_name.saturating_add(10);
106 let rdata_end = rdata_start.saturating_add(rdlen as usize);
107 if rdata_end > message.len() {
108 let remaining = message.len().saturating_sub(rdata_start);
109 return Err(ParseError::RdlengthOverrun(RdlengthOverrunDetail::new(
110 rdlen,
111 rdata_start,
112 remaining,
113 )));
114 }
115
116 Ok((
117 Self {
118 message,
119 name,
120 rtype,
121 rclass,
122 cache_flush,
123 ttl,
124 rdata_start,
125 rdata_len: rdlen as usize,
126 },
127 rdata_end,
128 ))
129 }
130
131 #[inline(always)]
133 pub const fn name(&self) -> &NameRef<'a> {
134 &self.name
135 }
136
137 #[inline(always)]
139 pub const fn rtype(&self) -> ResourceType {
140 self.rtype
141 }
142
143 #[inline(always)]
145 pub const fn rclass(&self) -> ResourceClass {
146 self.rclass
147 }
148
149 #[inline(always)]
151 pub const fn cache_flush(&self) -> bool {
152 self.cache_flush
153 }
154
155 #[inline(always)]
157 pub const fn ttl(&self) -> u32 {
158 self.ttl
159 }
160
161 pub fn rdata(&self) -> &'a [u8] {
163 self
164 .message
165 .get(self.rdata_start..self.rdata_start.saturating_add(self.rdata_len))
166 .unwrap_or(&[])
167 }
168
169 pub fn rdata_view(&self) -> Result<Rdata<'a>, ParseError> {
174 match self.rtype {
175 ResourceType::A => Ok(Rdata::A(A::try_from_rdata(self.rdata())?)),
176 ResourceType::AAAA => Ok(Rdata::AAAA(AAAA::try_from_rdata(self.rdata())?)),
177 ResourceType::Ptr => Ok(Rdata::Ptr(Ptr::try_from_message(
178 self.message,
179 self.rdata_start,
180 self.rdata_len,
181 )?)),
182 ResourceType::Cname => Ok(Rdata::Cname(Cname::try_from_message(
183 self.message,
184 self.rdata_start,
185 self.rdata_len,
186 )?)),
187 ResourceType::Srv => Ok(Rdata::Srv(Srv::try_from_message(
188 self.message,
189 self.rdata_start,
190 self.rdata_len,
191 )?)),
192 ResourceType::Txt => Ok(Rdata::Txt(Txt::from_rdata(self.rdata()))),
193 ResourceType::Nsec => Ok(Rdata::Nsec(Nsec::try_from_message(
194 self.message,
195 self.rdata_start,
196 self.rdata_len,
197 )?)),
198 _ => Ok(Rdata::Other(self.rdata())),
199 }
200 }
201
202 cfg_heap! {
203 pub(crate) fn canonical_rdata(&self) -> Result<RdataBuf, ParseError> {
218 self.canonical_rdata_inner(false)
219 }
220
221 pub(crate) fn canonical_rdata_folded(&self) -> Result<RdataBuf, ParseError> {
230 self.canonical_rdata_inner(true)
231 }
232
233 fn canonical_rdata_inner(&self, fold_case: bool) -> Result<RdataBuf, ParseError> {
234 match self.rdata_view()? {
235 Rdata::Ptr(p) => {
236 let mut out = std::vec::Vec::new();
237 p.target().write_wire(&mut out, fold_case)?;
238 Ok(rdata_from_vec(out))
239 }
240 Rdata::Cname(c) => {
241 let mut out = std::vec::Vec::new();
242 c.target().write_wire(&mut out, fold_case)?;
243 Ok(rdata_from_vec(out))
244 }
245 Rdata::Srv(s) => {
246 let mut out = std::vec::Vec::new();
247 out.extend_from_slice(&s.priority().to_be_bytes());
248 out.extend_from_slice(&s.weight().to_be_bytes());
249 out.extend_from_slice(&s.port().to_be_bytes());
250 s.target().write_wire(&mut out, fold_case)?;
251 Ok(rdata_from_vec(out))
252 }
253 Rdata::Nsec(n) => {
254 let mut out = std::vec::Vec::new();
255 n.next_name().write_wire(&mut out, fold_case)?;
256 out.extend_from_slice(n.type_bitmap_slice());
257 Ok(rdata_from_vec(out))
258 }
259 Rdata::Other(bytes) => {
265 if self.rtype.is_unhandled_compressible_name() {
266 return Err(ParseError::UnsupportedNameBearingType(self.rtype.to_u16()));
267 }
268 Ok(rdata_from_vec(bytes.to_vec()))
269 }
270 Rdata::Txt(t) => {
271 let mut out = std::vec::Vec::new();
281 let mut wrote_any = false;
282 for seg in t.segments() {
283 let seg = seg?;
284 #[allow(clippy::cast_possible_truncation)]
286 out.push(seg.len() as u8);
287 out.extend_from_slice(seg);
288 wrote_any = true;
289 }
290 if !wrote_any {
291 out.push(0);
292 }
293 Ok(rdata_from_vec(out))
294 }
295 _ => Ok(rdata_from_vec(self.rdata().to_vec())),
298 }
299 }
300 }
301}
302
303#[derive(
305 Debug, Copy, Clone, derive_more::IsVariant, derive_more::Unwrap, derive_more::TryUnwrap,
306)]
307#[unwrap(ref)]
308#[try_unwrap(ref)]
309#[non_exhaustive]
310#[allow(clippy::upper_case_acronyms)]
312pub enum Rdata<'a> {
313 A(A),
315 AAAA(AAAA),
317 Ptr(Ptr<'a>),
319 Cname(Cname<'a>),
321 Srv(Srv<'a>),
323 Txt(Txt<'a>),
325 Nsec(Nsec<'a>),
327 Other(&'a [u8]),
330}
331
332#[cfg(all(test, any(feature = "alloc", feature = "std")))]
333#[allow(
334 clippy::unwrap_used,
335 clippy::expect_used,
336 clippy::panic,
337 clippy::indexing_slicing,
338 clippy::arithmetic_side_effects
339)]
340mod tests;