1use crate::binutils::*;
6use crate::ParseError;
7
8use thiserror::Error;
9
10use std::borrow::Cow;
11use std::fmt;
12use std::iter::zip;
13use std::ops::Deref;
14use std::str;
15
16const INIT_NUM_LABELS: usize = 8;
17
18pub(crate) const MAX_JUMPS: u8 = 5;
19
20pub(crate) const MAX_LABEL_SIZE: usize = 63;
21pub(crate) const MAX_NAME_SIZE: usize = 255;
22
23#[derive(Error, Debug)]
25pub enum NameError {
26 #[error(
28 "Specified label length ({0}) is empty or is bigger than DNS specification (maximum {}).",
29 MAX_LABEL_SIZE
30 )]
31 LabelLength(usize),
32 #[error("The provided label is not a valid domain name label")]
34 LabelContent,
35 #[error(
37 "Name length ({0}) is too long, is bigger than DNS specification (maximum {}).",
38 MAX_NAME_SIZE
39 )]
40 NameLength(usize),
41}
42
43#[derive(Clone)]
45pub struct Name<'a> {
46 labels: Vec<Cow<'a, str>>,
48 len: u8,
50}
51
52impl fmt::Display for Name<'_> {
53 #[inline]
54 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
55 for l in self.iter_human() {
56 write!(f, "{}.", l)?;
57 }
58 Ok(())
59 }
60}
61
62impl fmt::Debug for Name<'_> {
63 #[inline]
64 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
65 for l in self.iter_human() {
66 write!(f, "{}.", l)?;
67 }
68 Ok(())
69 }
70}
71
72impl Default for Name<'_> {
73 #[inline]
74 fn default() -> Self {
75 Self::new()
76 }
77}
78
79impl From<Name<'_>> for Vec<u8> {
80 #[inline]
81 fn from(name: Name<'_>) -> Self {
82 let mut out = Vec::with_capacity(name.len as _);
83 name.serialize(&mut out);
84 out
85 }
86}
87
88impl<'a> TryFrom<&'a str> for Name<'a> {
89 type Error = NameError;
90
91 fn try_from(value: &'a str) -> Result<Self, Self::Error> {
92 let mut name = Name::default();
93 for label in value.rsplit('.') {
94 name.push_label(label.into())?;
95 }
96 Ok(name)
97 }
98}
99
100impl<'a> Name<'a> {
101 #[inline]
109 pub fn parse(buff: &'a [u8], pos: usize) -> Result<(Self, usize), ParseError> {
110 let mut name = Name::new();
111 let blen = buff.len();
112 let (mut pos, mut size, mut jumps) = (pos, 0, 0);
113 loop {
114 if jumps > MAX_JUMPS {
115 Err(ParseError::ExcesiveJumps(jumps))?;
116 }
117 match read_label_metadata(buff, pos)? {
118 LabelMeta::Pointer(ptr) if ptr >= pos => Err(ParseError::InvalidJump)?,
119 LabelMeta::Size(s) if s > MAX_LABEL_SIZE => Err(NameError::LabelLength(s))?,
120 LabelMeta::Size(s) if blen <= pos + s => Err(NameError::LabelLength(s))?,
121 LabelMeta::Size(s) if name.len as usize + s > MAX_NAME_SIZE => {
122 Err(NameError::NameLength(name.len as usize + s))?
123 }
124 LabelMeta::Size(s) if jumps == 0 => {
125 name.push_bytes(&buff[pos + 1..pos + s + 1])?;
126 pos += s + 1;
127 size += s + 1;
128 }
129 LabelMeta::Size(s) => {
130 name.push_bytes(&buff[pos + 1..pos + s + 1])?;
131 pos += s + 1;
132 }
133 LabelMeta::Pointer(ptr) if jumps == 0 => {
134 (pos, size, jumps) = (ptr, size + 2, jumps + 1);
135 }
136 LabelMeta::Pointer(ptr) => (pos, jumps) = (ptr, jumps + 1),
137 LabelMeta::End if jumps == 0 => {
138 name.labels.reverse();
139 return Ok((name, size + 1));
140 }
141 LabelMeta::End => {
142 name.labels.reverse();
143 return Ok((name, size));
144 }
145 }
146 }
147 }
148
149 fn push_bytes(&mut self, bytes: &'a [u8]) -> Result<(), NameError> {
151 if valid_label(bytes) {
152 let label = unsafe { str::from_utf8_unchecked(bytes) };
155 self.labels.push(label.into());
156 self.len += bytes.len() as u8 + 1;
158 Ok(())
159 } else {
160 Err(NameError::LabelContent)
161 }
162 }
163
164 #[inline]
166 pub fn serialize(&self, packet: &mut Vec<u8>) {
167 for label in self.iter_human() {
168 packet.push(label.len() as _);
169 packet.extend(label.as_bytes());
170 }
171 packet.push(0u8);
172 }
173
174 #[inline]
182 pub fn new() -> Self {
183 Name {
184 labels: Vec::with_capacity(INIT_NUM_LABELS),
185 len: 0,
186 }
187 }
188
189 #[inline]
197 pub fn tld(&self) -> Option<&'_ str> {
198 self.labels.first().map(|cow| cow.deref())
199 }
200
201 #[inline]
215 pub fn push_label(&mut self, label: Cow<'a, str>) -> Result<(), NameError> {
216 let len = label.len();
217 if label.is_empty() || len > MAX_LABEL_SIZE {
218 Err(NameError::LabelLength(len))
219 } else if len + self.len as usize > MAX_NAME_SIZE {
220 Err(NameError::NameLength(len + self.len as usize))
221 } else if !valid_label(label.as_bytes()) {
222 Err(NameError::LabelContent)
223 } else {
224 self.len += len as u8;
226 self.labels.push(label);
227 Ok(())
228 }
229 }
230
231 #[inline]
239 pub fn label_count(&self) -> usize {
240 self.labels.len()
241 }
242
243 #[inline]
253 pub fn is_subdomain(&self, sub: &Name<'_>) -> bool {
254 if self.labels.len() >= sub.labels.len() {
255 false
256 } else {
257 zip(self.iter_hierarchy(), sub.iter_hierarchy()).fold(true, |acc, (x, y)| acc && x == y)
258 }
259 }
260
261 #[inline]
273 pub fn iter_human(&self) -> impl DoubleEndedIterator<Item = &'_ str> {
274 self.iter_hierarchy().rev()
275 }
276
277 #[inline]
289 pub fn iter_hierarchy(&self) -> impl DoubleEndedIterator<Item = &'_ str> {
290 self.labels.iter().map(|cow| cow.deref())
291 }
292}
293
294fn valid_label(label: &[u8]) -> bool {
296 label
297 .iter()
298 .all(|&b| b.is_ascii_alphanumeric() || b == b'-')
299}
300
301enum LabelMeta {
302 End,
303 Size(usize),
305 Pointer(usize),
307}
308
309#[inline]
310fn read_label_metadata(buff: &[u8], pos: usize) -> Result<LabelMeta, ParseError> {
311 let b = safe_u8_read(buff, pos)?;
312 match b {
313 0 => Ok(LabelMeta::End),
314 1..=0b0011_1111 => Ok(LabelMeta::Size(b as _)),
315 0b1100_0000..=0xFF => Ok(LabelMeta::Pointer(
316 (safe_u16_read(buff, pos)? ^ 0b1100_0000_0000_0000) as _,
317 )),
318 _ => Err(ParseError::LabelPrefix(b))?,
319 }
320}
321
322#[cfg(test)]
323mod tests {
324 use super::*;
325
326 #[test]
327 fn valid_labels() {
328 let valid = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-";
329 let invalid = "hello.world";
330 assert!(valid_label(valid.as_bytes()));
331 assert!(!valid_label(invalid.as_bytes()));
332 }
333
334 #[test]
335 fn no_jumps() {
336 let buff = [
337 5, 104, 101, 108, 108, 111, 5, 119, 111, 114, 108, 100, 3, 99, 111, 109, 0, 1, 1, 1, ];
342 let (name, n) = Name::parse(&buff[..], 0).unwrap();
343 assert_eq!(n, 17);
344 assert_eq!(name.to_string(), "hello.world.com.".to_string())
345 }
346
347 #[test]
348 fn with_jumps() {
349 let buff = [
350 5, 119, 111, 114, 108, 100, 3, 99, 111, 109, 0, 1, 1, 1, 5, 104, 101, 108, 108, 111, 192, 0, 1, 1, 1, 1, 1, 1, ];
356 let (name, n) = Name::parse(&buff[..], 14).unwrap();
357 assert_eq!(n, 8);
358 assert_eq!(name.to_string(), "hello.world.com.".to_string())
359 }
360
361 #[test]
362 fn name_parse_with_jumps() {
363 let buff = [
364 5, 119, 111, 114, 108, 100, 3, 99, 111, 109, 0, 1, 1, 1, 5, 104, 101, 108, 108, 111, 192, 0, 1, 1, 1, 1, 1, 1, ];
370 let (name, n) = Name::parse(&buff[..], 14).unwrap();
371 assert_eq!(n, 8);
372 assert_eq!(name.to_string(), "hello.world.com.".to_string())
373 }
374
375 #[test]
376 fn serialize() {
377 let buff = [
378 5, 104, 101, 108, 108, 111, 5, 119, 111, 114, 108, 100, 3, 99, 111, 109, 0, 1, 1, 1, ];
383 let (name, _) = Name::parse(&buff[..], 0).unwrap();
384 assert_eq!(name.to_string(), "hello.world.com.".to_string());
385 let out: Vec<u8> = name.into();
386 assert_eq!(&buff[..17], &out[..17])
387 }
388
389 #[test]
390 fn get_tld() {
391 let mut name = Name::new();
392 name.push_label("com".into()).unwrap();
393 name.push_label("world".into()).unwrap();
394 name.push_label("hello".into()).unwrap();
395
396 let tld = name.tld();
397 assert_eq!(tld, Some("com"));
398 }
399
400 #[test]
401 fn add_str_subdomain() {
402 let buff = [5, 119, 111, 114, 108, 100, 3, 99, 111, 109, 0, 1, 1, 1]; let (mut name, _) = Name::parse(&buff[..], 0).unwrap();
404 name.push_label("hello".into()).unwrap();
405 assert_eq!(name.to_string(), "hello.world.com.".to_string())
406 }
407
408 #[test]
409 fn add_string_subdomain() {
410 let sub = String::from("hello");
411 let buff = [5, 119, 111, 114, 108, 100, 3, 99, 111, 109, 0, 1, 1, 1]; let (mut name, _) = Name::parse(&buff[..], 0).unwrap();
413 name.push_label(sub.into()).unwrap();
414 assert_eq!(name.to_string(), "hello.world.com.".to_string())
415 }
416
417 #[test]
418 fn iterate_human() {
419 let mut name = Name::new();
420 name.push_label("com".into()).unwrap();
421 name.push_label("world".into()).unwrap();
422 name.push_label("hello".into()).unwrap();
423
424 let mut human = name.iter_human();
425 assert_eq!(human.next(), Some("hello"));
426 assert_eq!(human.next(), Some("world"));
427 assert_eq!(human.next(), Some("com"));
428 }
429
430 #[test]
431 fn iterate_hierarchy() {
432 let mut name = Name::new();
433 name.push_label("com".into()).unwrap();
434 name.push_label("world".into()).unwrap();
435 name.push_label("hello".into()).unwrap();
436
437 let mut human = name.iter_hierarchy();
438 assert_eq!(human.next(), Some("com"));
439 assert_eq!(human.next(), Some("world"));
440 assert_eq!(human.next(), Some("hello"));
441 }
442
443 #[test]
444 fn check_subdomain() {
445 let mut parent = Name::new();
446 parent.push_label("com".into()).unwrap();
447 parent.push_label("world".into()).unwrap();
448
449 let mut sub = Name::new();
450 sub.push_label("com".into()).unwrap();
451 sub.push_label("world".into()).unwrap();
452 sub.push_label("hello".into()).unwrap();
453
454 assert!(parent.is_subdomain(&sub));
455 assert!(!sub.is_subdomain(&parent));
456 }
457
458 #[test]
459 fn root_subdomain() {
460 let root = Name::default();
461 let subd = Name::try_from("example.com").unwrap();
462
463 assert!(root.is_subdomain(&subd));
464 assert!(!subd.is_subdomain(&root));
465 }
466}