1use crate::{
2 bytes_buffer::BytesBuffer,
3 lib::{
4 fmt::{Debug, Display, Formatter, Result as FmtResult},
5 format, Cow, Hash, Hasher, Iter, Seek, String, ToString, TryFrom, Vec, Write,
6 },
7};
8
9use super::{WireFormat, MAX_LABEL_LENGTH, MAX_NAME_LENGTH};
10
11const POINTER_MASK: u8 = 0b1100_0000;
12const POINTER_MASK_U16: u16 = 0b1100_0000_0000_0000;
13
14#[derive(Eq, Clone)]
29pub struct Name<'a> {
30 labels: Vec<Label<'a>>,
31}
32
33impl<'a> Name<'a> {
34 pub fn new(name: &'a str) -> crate::Result<Self> {
36 let labels = LabelsIter::new(name.as_bytes())
37 .map(Label::new)
38 .collect::<Result<Vec<Label>, _>>()?;
39
40 let name = Self { labels };
41
42 if name.len() > MAX_NAME_LENGTH {
43 Err(crate::SimpleDnsError::InvalidServiceName)
44 } else {
45 Ok(name)
46 }
47 }
48
49 pub fn new_unchecked(name: &'a str) -> Self {
51 let labels = LabelsIter::new(name.as_bytes())
52 .map(Label::new_unchecked)
53 .collect();
54
55 Self { labels }
56 }
57
58 pub fn new_with_labels(labels: &[Label<'a>]) -> Self {
62 Self {
63 labels: labels.to_vec(),
64 }
65 }
66
67 pub fn is_link_local(&self) -> bool {
69 match self.iter().last() {
70 Some(label) => b"local".eq_ignore_ascii_case(&label.data),
71 None => false,
72 }
73 }
74
75 pub fn iter(&'a self) -> Iter<'a, Label<'a>> {
77 self.labels.iter()
78 }
79
80 pub fn is_subdomain_of(&self, other: &Name) -> bool {
82 self.labels.len() > other.labels.len()
83 && other
84 .iter()
85 .rev()
86 .zip(self.iter().rev())
87 .all(|(o, s)| *o == *s)
88 }
89
90 pub fn into_owned<'b>(self) -> Name<'b> {
92 Name {
93 labels: self.labels.into_iter().map(|l| l.into_owned()).collect(),
94 }
95 }
96
97 pub fn without(&'_ self, domain: &Name) -> Option<Name<'_>> {
112 if self.is_subdomain_of(domain) {
113 let labels = self.labels[..self.labels.len() - domain.labels.len()].to_vec();
114
115 Some(Name { labels })
116 } else {
117 None
118 }
119 }
120
121 pub fn get_labels(&'_ self) -> &'_ [Label<'a>] {
123 &self.labels[..]
124 }
125
126 fn plain_append<T: Write>(&self, out: &mut T) -> crate::Result<()> {
127 for label in self.iter() {
128 out.write_all(&[label.len() as u8])?;
129 out.write_all(&label.data)?;
130 }
131
132 out.write_all(&[0])?;
133 Ok(())
134 }
135
136 fn compress_append<T: Write + Seek>(
137 &'a self,
138 out: &mut T,
139 name_refs: &mut crate::lib::BTreeMap<&[Label<'a>], u16>,
140 ) -> crate::Result<()> {
141 for (i, label) in self.iter().enumerate() {
142 match name_refs.entry(&self.labels[i..]) {
143 crate::lib::BTreeEntry::Occupied(e) => {
144 let p = *e.get();
145 out.write_all(&(p | POINTER_MASK_U16).to_be_bytes())?;
146
147 return Ok(());
148 }
149 crate::lib::BTreeEntry::Vacant(e) => {
150 e.insert(out.stream_position()? as u16);
151 out.write_all(&[label.len() as u8])?;
152 out.write_all(&label.data)?;
153 }
154 }
155 }
156
157 out.write_all(&[0])?;
158 Ok(())
159 }
160
161 pub fn is_valid(&self) -> bool {
163 self.labels.iter().all(|label| label.is_valid())
164 }
165
166 pub fn as_bytes(&self) -> impl Iterator<Item = &[u8]> {
168 self.labels.iter().map(|label| label.as_ref())
169 }
170}
171
172impl<'a> WireFormat<'a> for Name<'a> {
173 const MINIMUM_LEN: usize = 1;
174
175 fn parse(data: &mut BytesBuffer<'a>) -> crate::Result<Self>
176 where
177 Self: Sized,
178 {
179 fn parse_labels<'a>(
182 data: &mut BytesBuffer<'a>,
183 name_len: &mut usize,
184 labels: &mut Vec<Label<'a>>,
185 ) -> crate::Result<Option<usize>> {
186 loop {
187 match data.get_u8()? {
188 0 => break Ok(None),
189 len if len & POINTER_MASK == POINTER_MASK => {
190 let mut pointer = len as u16;
191 pointer <<= 8;
192 pointer += data.get_u8()? as u16;
193 pointer &= !POINTER_MASK_U16;
194
195 break Ok(Some(pointer as usize));
196 }
197 len => {
198 *name_len += 1 + len as usize;
199
200 if *name_len >= MAX_NAME_LENGTH {
202 return Err(crate::SimpleDnsError::InvalidDnsPacket);
203 }
204
205 if len as usize > MAX_LABEL_LENGTH {
206 return Err(crate::SimpleDnsError::InvalidServiceLabel);
207 }
208
209 labels.push(Label::new_unchecked(data.get_slice(len as usize)?));
212 }
213 }
214 }
215 }
216
217 let mut labels = Vec::new();
218 let mut name_len = 0usize;
219
220 let mut pointer = parse_labels(data, &mut name_len, &mut labels)?;
221
222 let mut data = data.clone();
223 while let Some(p) = pointer {
224 data = data.new_at(p)?;
228 pointer = parse_labels(&mut data, &mut name_len, &mut labels)?;
229 }
230
231 Ok(Self { labels })
232 }
233
234 fn write_to<T: Write>(&self, out: &mut T) -> crate::Result<()> {
235 self.plain_append(out)
236 }
237
238 fn write_compressed_to<T: Write + Seek>(
239 &'a self,
240 out: &mut T,
241 name_refs: &mut crate::lib::BTreeMap<&[Label<'a>], u16>,
242 ) -> crate::Result<()> {
243 self.compress_append(out, name_refs)
244 }
245
246 fn len(&self) -> usize {
247 self.labels
248 .iter()
249 .map(|label| label.len() + 1)
250 .sum::<usize>()
251 + Self::MINIMUM_LEN
252 }
253}
254
255impl<'a> TryFrom<&'a str> for Name<'a> {
256 type Error = crate::SimpleDnsError;
257
258 fn try_from(value: &'a str) -> Result<Self, Self::Error> {
259 Name::new(value)
260 }
261}
262
263impl<'a> From<&'a [Label<'a>]> for Name<'a> {
264 fn from(labels: &'a [Label<'a>]) -> Self {
265 Name::new_with_labels(labels)
266 }
267}
268
269impl<'a, const N: usize> From<[Label<'a>; N]> for Name<'a> {
270 fn from(labels: [Label<'a>; N]) -> Self {
271 Name::new_with_labels(&labels)
272 }
273}
274
275impl Display for Name<'_> {
276 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
277 let mut labels = self.labels.iter();
278
279 if let Some(label) = labels.next() {
280 f.write_fmt(format_args!("{label}"))?;
281 }
282
283 for label in labels {
284 f.write_fmt(format_args!(".{label}"))?;
285 }
286
287 Ok(())
288 }
289}
290
291impl Debug for Name<'_> {
292 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
293 f.debug_tuple("Name")
294 .field(&format!("{self}"))
295 .field(&format!("{}", self.len()))
296 .finish()
297 }
298}
299
300impl PartialEq for Name<'_> {
301 fn eq(&self, other: &Self) -> bool {
302 self.labels == other.labels
303 }
304}
305
306impl Hash for Name<'_> {
307 fn hash<H: Hasher>(&self, state: &mut H) {
308 self.labels.hash(state);
309 }
310}
311
312struct LabelsIter<'a> {
314 bytes: &'a [u8],
315 current: usize,
316}
317
318impl<'a> LabelsIter<'a> {
319 fn new(bytes: &'a [u8]) -> Self {
320 Self { bytes, current: 0 }
321 }
322}
323
324impl<'a> Iterator for LabelsIter<'a> {
325 type Item = Cow<'a, [u8]>;
326
327 fn next(&mut self) -> Option<Self::Item> {
328 for i in self.current..self.bytes.len() {
329 if self.bytes[i] == b'.' {
330 let current = crate::lib::mem::replace(&mut self.current, i + 1);
331 if i - current == 0 {
332 continue;
333 }
334 return Some(self.bytes[current..i].into());
335 }
336 }
337
338 if self.current < self.bytes.len() {
339 let current = crate::lib::mem::replace(&mut self.current, self.bytes.len());
340 Some(self.bytes[current..].into())
341 } else {
342 None
343 }
344 }
345}
346
347#[derive(Eq, PartialEq, Hash, Clone, PartialOrd, Ord)]
359pub struct Label<'a> {
360 data: Cow<'a, [u8]>,
361}
362
363impl<'a> Label<'a> {
364 pub fn new<T: Into<Cow<'a, [u8]>>>(data: T) -> crate::Result<Self> {
366 let label = Self::new_unchecked(data);
367 if !label.is_valid() {
368 return Err(crate::SimpleDnsError::InvalidServiceLabel);
369 }
370
371 Ok(label)
372 }
373
374 pub fn new_unchecked<T: Into<Cow<'a, [u8]>>>(data: T) -> Self {
377 Self { data: data.into() }
378 }
379
380 pub fn len(&self) -> usize {
382 self.data.len()
383 }
384
385 pub fn is_empty(&self) -> bool {
387 self.data.is_empty()
388 }
389
390 pub fn into_owned<'b>(self) -> Label<'b> {
392 Label {
393 data: self.data.into_owned().into(),
394 }
395 }
396
397 pub fn is_valid(&self) -> bool {
399 if self.data.is_empty() || self.data.len() > MAX_LABEL_LENGTH {
400 return false;
401 }
402
403 if let Some(first) = self.data.first() {
404 if !first.is_ascii_alphanumeric() && *first != b'_' {
405 return false;
406 }
407 }
408
409 if !self
410 .data
411 .iter()
412 .skip(1)
413 .all(|c| c.is_ascii_alphanumeric() || *c == b'-' || *c == b'_')
414 {
415 return false;
416 }
417
418 if let Some(last) = self.data.last() {
419 if !last.is_ascii_alphanumeric() {
420 return false;
421 }
422 }
423
424 true
425 }
426}
427
428impl Display for Label<'_> {
429 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
430 let s = String::from_utf8_lossy(&self.data);
431 f.write_str(&s)
432 }
433}
434
435impl Debug for Label<'_> {
436 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
437 f.debug_struct("Label")
438 .field("data", &self.to_string())
439 .finish()
440 }
441}
442
443impl AsRef<[u8]> for Label<'_> {
444 fn as_ref(&self) -> &[u8] {
445 self.data.as_ref()
446 }
447}
448
449#[cfg(test)]
450mod tests {
451 use super::*;
452 use crate::lib::Cursor;
453 use crate::{lib::Vec, SimpleDnsError};
454
455 #[test]
456 fn construct_valid_names() {
457 assert!(Name::new("some").is_ok());
458 assert!(Name::new("some.local").is_ok());
459 assert!(Name::new("some.local.").is_ok());
460 assert!(Name::new("some-dash.local.").is_ok());
461 assert!(Name::new("_sync_miss._tcp.local").is_ok());
462 assert!(Name::new("1sync_miss._tcp.local").is_ok());
463
464 assert_eq!(Name::new_unchecked("\u{1F600}.local.").labels.len(), 2);
465 }
466
467 #[test]
468 fn label_validate() {
469 assert!(Name::new("\u{1F600}.local.").is_err());
470 assert!(Name::new("@.local.").is_err());
471 assert!(Name::new("\\.local.").is_err());
472 }
473
474 #[test]
475 fn is_link_local() {
476 assert!(!Name::new("some.example.com").unwrap().is_link_local());
477 assert!(Name::new("some.example.local.").unwrap().is_link_local());
478 }
479
480 #[test]
481 fn parse_without_compression() {
482 let mut data = BytesBuffer::new(
483 b"\x00\x00\x00\x01F\x03ISI\x04ARPA\x00\x03FOO\x01F\x03ISI\x04ARPA\x00\x04ARPA\x00",
484 );
485 data.advance(3).unwrap();
486 let name = Name::parse(&mut data).unwrap();
487 assert_eq!("F.ISI.ARPA", name.to_string());
488
489 let name = Name::parse(&mut data).unwrap();
490 assert_eq!("FOO.F.ISI.ARPA", name.to_string());
491 }
492
493 #[test]
494 fn parse_with_compression() {
495 let mut data = BytesBuffer::new(b"\x00\x00\x00\x01F\x03ISI\x04ARPA\x00\x03FOO\xc0\x03\x03BAR\xc0\x03\x07INVALID\xc0\x1b" );
496 data.advance(3).unwrap();
497
498 let name = Name::parse(&mut data).unwrap();
499 assert_eq!("F.ISI.ARPA", name.to_string());
500
501 let name = Name::parse(&mut data).unwrap();
502 assert_eq!("FOO.F.ISI.ARPA", name.to_string());
503
504 let name = Name::parse(&mut data).unwrap();
505 assert_eq!("BAR.F.ISI.ARPA", name.to_string());
506
507 assert!(Name::parse(&mut data).is_err());
508 }
509
510 #[test]
511 fn parse_handle_circular_pointers() {
512 let mut data = BytesBuffer::new(&[249, 0, 37, 1, 1, 139, 192, 6, 1, 1, 1, 139, 192, 6]);
513 data.advance(12).unwrap();
514
515 assert_eq!(
516 Name::parse(&mut data),
517 Err(SimpleDnsError::InvalidDnsPacket)
518 );
519 }
520
521 #[test]
522 fn test_write() {
523 let mut bytes = Vec::with_capacity(30);
524 Name::new_unchecked("_srv._udp.local")
525 .write_to(&mut bytes)
526 .unwrap();
527
528 assert_eq!(b"\x04_srv\x04_udp\x05local\x00", &bytes[..]);
529
530 let mut bytes = Vec::with_capacity(30);
531 Name::new_unchecked("_srv._udp.local2.")
532 .write_to(&mut bytes)
533 .unwrap();
534
535 assert_eq!(b"\x04_srv\x04_udp\x06local2\x00", &bytes[..]);
536 }
537
538 #[test]
539 fn root_name_should_generate_no_labels() {
540 assert_eq!(Name::new_unchecked("").labels.len(), 0);
541 assert_eq!(Name::new_unchecked(".").labels.len(), 0);
542 }
543
544 #[test]
545 fn dot_sequence_should_generate_no_labels() {
546 assert_eq!(Name::new_unchecked(".....").labels.len(), 0);
547 assert_eq!(Name::new_unchecked("example.....com").labels.len(), 2);
548 }
549
550 #[test]
551 fn root_name_should_write_zero() {
552 let mut bytes = Vec::with_capacity(30);
553 Name::new_unchecked(".").write_to(&mut bytes).unwrap();
554
555 assert_eq!(b"\x00", &bytes[..]);
556 }
557
558 #[test]
559 fn append_to_vec_with_compression() {
560 let mut buf = Cursor::new(crate::lib::vec![0, 0, 0]);
561 buf.set_position(3);
562
563 let mut name_refs = Default::default();
564
565 let f_isi_arpa = Name::new_unchecked("F.ISI.ARPA");
566 f_isi_arpa
567 .write_compressed_to(&mut buf, &mut name_refs)
568 .expect("failed to add F.ISI.ARPA");
569 let foo_f_isi_arpa = Name::new_unchecked("FOO.F.ISI.ARPA");
570 foo_f_isi_arpa
571 .write_compressed_to(&mut buf, &mut name_refs)
572 .expect("failed to add FOO.F.ISI.ARPA");
573
574 Name::new_unchecked("BAR.F.ISI.ARPA")
575 .write_compressed_to(&mut buf, &mut name_refs)
576 .expect("failed to add FOO.F.ISI.ARPA");
577
578 let data = b"\x00\x00\x00\x01F\x03ISI\x04ARPA\x00\x03FOO\xc0\x03\x03BAR\xc0\x03";
579 assert_eq!(data[..], buf.get_ref()[..]);
580 }
581
582 #[test]
583 fn append_to_vec_with_compression_mult_names() {
584 let mut buf = Cursor::new(Vec::new());
585 let mut name_refs = Default::default();
586
587 let isi_arpa = Name::new_unchecked("ISI.ARPA");
588 isi_arpa
589 .write_compressed_to(&mut buf, &mut name_refs)
590 .expect("failed to add ISI.ARPA");
591
592 let f_isi_arpa = Name::new_unchecked("F.ISI.ARPA");
593 f_isi_arpa
594 .write_compressed_to(&mut buf, &mut name_refs)
595 .expect("failed to add F.ISI.ARPA");
596 let foo_f_isi_arpa = Name::new_unchecked("FOO.F.ISI.ARPA");
597 foo_f_isi_arpa
598 .write_compressed_to(&mut buf, &mut name_refs)
599 .expect("failed to add F.ISI.ARPA");
600 Name::new_unchecked("BAR.F.ISI.ARPA")
601 .write_compressed_to(&mut buf, &mut name_refs)
602 .expect("failed to add F.ISI.ARPA");
603
604 let expected = b"\x03ISI\x04ARPA\x00\x01F\xc0\x00\x03FOO\xc0\x0a\x03BAR\xc0\x0a";
605 assert_eq!(expected[..], buf.get_ref()[..]);
606
607 let mut data = BytesBuffer::new(buf.get_ref());
608
609 let first = Name::parse(&mut data).unwrap();
610 assert_eq!("ISI.ARPA", first.to_string());
611 let second = Name::parse(&mut data).unwrap();
612 assert_eq!("F.ISI.ARPA", second.to_string());
613 let third = Name::parse(&mut data).unwrap();
614 assert_eq!("FOO.F.ISI.ARPA", third.to_string());
615 let fourth = Name::parse(&mut data).unwrap();
616 assert_eq!("BAR.F.ISI.ARPA", fourth.to_string());
617 }
618
619 #[test]
620 fn ensure_different_domains_are_not_compressed() {
621 let mut buf = Cursor::new(Vec::new());
622 let mut name_refs = Default::default();
623
624 let foo_bar_baz = Name::new_unchecked("FOO.BAR.BAZ");
625 foo_bar_baz
626 .write_compressed_to(&mut buf, &mut name_refs)
627 .expect("failed to add FOO.BAR.BAZ");
628
629 let foo_bar_buz = Name::new_unchecked("FOO.BAR.BUZ");
630 foo_bar_buz
631 .write_compressed_to(&mut buf, &mut name_refs)
632 .expect("failed to add FOO.BAR.BUZ");
633
634 Name::new_unchecked("FOO.BAR")
635 .write_compressed_to(&mut buf, &mut name_refs)
636 .expect("failed to add FOO.BAR");
637
638 let expected = b"\x03FOO\x03BAR\x03BAZ\x00\x03FOO\x03BAR\x03BUZ\x00\x03FOO\x03BAR\x00";
639 assert_eq!(expected[..], buf.get_ref()[..]);
640 }
641
642 #[test]
643 fn eq_other_name() -> Result<(), SimpleDnsError> {
644 assert_eq!(Name::new("example.com")?, Name::new("example.com")?);
645 assert_ne!(Name::new("some.example.com")?, Name::new("example.com")?);
646 assert_ne!(Name::new("example.co")?, Name::new("example.com")?);
647 assert_ne!(Name::new("example.com.org")?, Name::new("example.com")?);
648
649 let mut data =
650 BytesBuffer::new(b"\x00\x00\x00\x01F\x03ISI\x04ARPA\x00\x03FOO\xc0\x03\x03BAR\xc0\x03");
651 data.advance(3)?;
652 assert_eq!(Name::new("F.ISI.ARPA")?, Name::parse(&mut data)?);
653 assert_eq!(Name::new("FOO.F.ISI.ARPA")?, Name::parse(&mut data)?);
654 Ok(())
655 }
656
657 #[test]
658 fn len() -> crate::Result<()> {
659 let mut bytes = Vec::new();
660 let name_one = Name::new_unchecked("ex.com.");
661 name_one.write_to(&mut bytes)?;
662
663 assert_eq!(8, bytes.len());
664 assert_eq!(bytes.len(), name_one.len());
665 assert_eq!(8, Name::parse(&mut BytesBuffer::new(&bytes))?.len());
666
667 Ok(())
668 }
669
670 #[test]
671 fn len_compressed() -> crate::Result<()> {
672 let name_one = Name::new_unchecked("ex.com.");
673 let mut name_refs = Default::default();
674 let mut bytes = Cursor::new(Vec::new());
675 name_one.write_compressed_to(&mut bytes, &mut name_refs)?;
676 name_one.write_compressed_to(&mut bytes, &mut name_refs)?;
677
678 assert_eq!(10, bytes.get_ref().len());
679 Ok(())
680 }
681
682 #[test]
683 #[cfg(feature = "std")]
684 fn hash() -> crate::Result<()> {
685 fn get_hash(name: &Name) -> u64 {
686 let mut hasher = std::hash::DefaultHasher::default();
687 name.hash(&mut hasher);
688 hasher.finish()
689 }
690
691 let mut data =
692 BytesBuffer::new(b"\x00\x00\x00\x01F\x03ISI\x04ARPA\x00\x03FOO\xc0\x03\x03BAR\xc0\x03");
693 data.advance(3)?;
694
695 assert_eq!(
696 get_hash(&Name::new("F.ISI.ARPA")?),
697 get_hash(&Name::parse(&mut data)?)
698 );
699
700 assert_eq!(
701 get_hash(&Name::new("FOO.F.ISI.ARPA")?),
702 get_hash(&Name::parse(&mut data)?)
703 );
704
705 Ok(())
706 }
707
708 #[test]
709 fn is_subdomain_of() {
710 assert!(Name::new_unchecked("sub.example.com")
711 .is_subdomain_of(&Name::new_unchecked("example.com")));
712
713 assert!(!Name::new_unchecked("example.com")
714 .is_subdomain_of(&Name::new_unchecked("example.com")));
715
716 assert!(Name::new_unchecked("foo.sub.example.com")
717 .is_subdomain_of(&Name::new_unchecked("example.com")));
718
719 assert!(!Name::new_unchecked("example.com")
720 .is_subdomain_of(&Name::new_unchecked("example.xom")));
721
722 assert!(!Name::new_unchecked("domain.com")
723 .is_subdomain_of(&Name::new_unchecked("other.domain")));
724
725 assert!(!Name::new_unchecked("domain.com")
726 .is_subdomain_of(&Name::new_unchecked("domain.com.br")));
727 }
728
729 #[test]
730 fn subtract_domain() {
731 let domain = Name::new_unchecked("_srv3._tcp.local");
732 assert_eq!(
733 Name::new_unchecked("a._srv3._tcp.local")
734 .without(&domain)
735 .unwrap()
736 .to_string(),
737 "a"
738 );
739
740 assert!(Name::new_unchecked("unrelated").without(&domain).is_none(),);
741
742 assert_eq!(
743 Name::new_unchecked("some.longer.domain._srv3._tcp.local")
744 .without(&domain)
745 .unwrap()
746 .to_string(),
747 "some.longer.domain"
748 );
749 }
750
751 #[test]
752 fn display_invalid_label() {
753 let input = b"invalid\xF0\x90\x80label";
754 let label = Label::new_unchecked(input);
755
756 assert_eq!(label.to_string(), "invalid�label");
757 }
758}