simple_dns/dns/
name.rs

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;
13const MAX_COMPRESSION_OFFSET: u64 = !POINTER_MASK_U16 as u64;
14
15// NOTE: there are no extend labels implemented today
16// const EXTENDED_LABEL: u8 = 0b0100_0000;
17// const EXTENDED_LABEL_U16: u16 = 0b0100_0000_0000_0000;
18
19/// A Name represents a domain-name, which consists of character strings separated by dots.  
20/// Each section of a name is called label  
21/// ex: `google.com` consists of two labels `google` and `com`
22///
23/// A valid name contains only alphanumeric characters, hyphen (-), underscore (_) or dots (.) and must not exceed 255 characters.
24/// Each label must not exceed 63 characters.
25///
26/// Microsoft implementation allows unicode characters in the name content.
27/// To create a name with unicode characters, use [`Name::new_unchecked`] or
28/// [`Name::new_with_labels`]
29#[derive(Eq, Clone)]
30pub struct Name<'a> {
31    labels: Vec<Label<'a>>,
32}
33
34impl<'a> Name<'a> {
35    /// Creates a new Name. Returns [`Result::<Name>::Ok`] if given `name` contents are valid.
36    pub fn new(name: &'a str) -> crate::Result<Self> {
37        let labels = LabelsIter::new(name.as_bytes())
38            .map(Label::new)
39            .collect::<Result<Vec<Label>, _>>()?;
40
41        let name = Self { labels };
42
43        if name.len() > MAX_NAME_LENGTH {
44            Err(crate::SimpleDnsError::InvalidServiceName)
45        } else {
46            Ok(name)
47        }
48    }
49
50    /// Create a new Name without checking for size limits or contents
51    pub fn new_unchecked(name: &'a str) -> Self {
52        let labels = LabelsIter::new(name.as_bytes())
53            .map(Label::new_unchecked)
54            .collect();
55
56        Self { labels }
57    }
58
59    /// Creates a new Name with given labels
60    ///
61    /// Allows construction of labels with `.` in them.
62    pub fn new_with_labels(labels: &[Label<'a>]) -> Self {
63        Self {
64            labels: labels.to_vec(),
65        }
66    }
67
68    /// Verify if name ends with .local.
69    pub fn is_link_local(&self) -> bool {
70        match self.iter().last() {
71            Some(label) => b"local".eq_ignore_ascii_case(&label.data),
72            None => false,
73        }
74    }
75
76    /// Returns an Iter of this Name Labels
77    pub fn iter(&'a self) -> Iter<'a, Label<'a>> {
78        self.labels.iter()
79    }
80
81    /// Returns true if self is a subdomain of other
82    pub fn is_subdomain_of(&self, other: &Name) -> bool {
83        self.labels.len() > other.labels.len()
84            && other
85                .iter()
86                .rev()
87                .zip(self.iter().rev())
88                .all(|(o, s)| *o == *s)
89    }
90
91    /// Transforms the inner data into its owned type
92    pub fn into_owned<'b>(self) -> Name<'b> {
93        Name {
94            labels: self.labels.into_iter().map(|l| l.into_owned()).collect(),
95        }
96    }
97
98    /// Returns the subdomain part of self, based on `domain`.
99    /// If self is not a subdomain of `domain`, returns None
100    ///
101    /// Example:
102    /// ```
103    /// # use simple_dns::Name;
104    /// let name = Name::new_unchecked("sub.domain.local");
105    /// let domain = Name::new_unchecked("domain.local");
106    ///
107    /// assert!(domain.without(&name).is_none());
108    ///
109    /// let sub = name.without(&domain).unwrap();
110    /// assert_eq!(sub.to_string(), "sub")
111    /// ```
112    pub fn without(&'_ self, domain: &Name) -> Option<Name<'_>> {
113        if self.is_subdomain_of(domain) {
114            let labels = self.labels[..self.labels.len() - domain.labels.len()].to_vec();
115
116            Some(Name { labels })
117        } else {
118            None
119        }
120    }
121
122    /// Get the labels that compose this name
123    pub fn get_labels(&'_ self) -> &'_ [Label<'a>] {
124        &self.labels[..]
125    }
126
127    fn plain_append<T: Write>(&self, out: &mut T) -> crate::Result<()> {
128        for label in self.iter() {
129            out.write_all(&[label.len() as u8])?;
130            out.write_all(&label.data)?;
131        }
132
133        out.write_all(&[0])?;
134        Ok(())
135    }
136
137    fn compress_append<T: Write + Seek>(
138        &'a self,
139        out: &mut T,
140        name_refs: &mut crate::lib::BTreeMap<&[Label<'a>], u16>,
141    ) -> crate::Result<()> {
142        for (i, label) in self.iter().enumerate() {
143            match name_refs.entry(&self.labels[i..]) {
144                crate::lib::BTreeEntry::Occupied(e) => {
145                    let p = *e.get();
146                    out.write_all(&(p | POINTER_MASK_U16).to_be_bytes())?;
147
148                    return Ok(());
149                }
150                crate::lib::BTreeEntry::Vacant(e) => {
151                    let pos = out.stream_position()?;
152                    if pos <= MAX_COMPRESSION_OFFSET {
153                        e.insert(pos as u16);
154                    }
155                    out.write_all(&[label.len() as u8])?;
156                    out.write_all(&label.data)?;
157                }
158            }
159        }
160
161        out.write_all(&[0])?;
162        Ok(())
163    }
164
165    /// Returns `true` if the name is valid.
166    pub fn is_valid(&self) -> bool {
167        self.labels.iter().all(|label| label.is_valid())
168    }
169
170    /// Returns the bytes of each of the labels that compose this Name
171    pub fn as_bytes(&self) -> impl Iterator<Item = &[u8]> {
172        self.labels.iter().map(|label| label.as_ref())
173    }
174}
175
176impl<'a> WireFormat<'a> for Name<'a> {
177    const MINIMUM_LEN: usize = 1;
178
179    fn parse(data: &mut BytesBuffer<'a>) -> crate::Result<Self>
180    where
181        Self: Sized,
182    {
183        // Parse labels will extract labels until it finds a 0 len label
184        // or a pointer  to another label
185        fn parse_labels<'a>(
186            data: &mut BytesBuffer<'a>,
187            name_len: &mut usize,
188            labels: &mut Vec<Label<'a>>,
189        ) -> crate::Result<Option<usize>> {
190            loop {
191                match data.get_u8()? {
192                    0 => break Ok(None),
193                    len if len & POINTER_MASK == POINTER_MASK => {
194                        let mut pointer = len as u16;
195                        pointer <<= 8;
196                        pointer += data.get_u8()? as u16;
197                        pointer &= !POINTER_MASK_U16;
198
199                        break Ok(Some(pointer as usize));
200                    }
201                    len => {
202                        *name_len += 1 + len as usize;
203
204                        // Checking the full name len to avoid circular pointers
205                        if *name_len >= MAX_NAME_LENGTH {
206                            return Err(crate::SimpleDnsError::InvalidDnsPacket);
207                        }
208
209                        if len as usize > MAX_LABEL_LENGTH {
210                            return Err(crate::SimpleDnsError::InvalidServiceLabel);
211                        }
212
213                        // Parsing allow invalid characters in the label.
214                        // However, the length of the label must be validated (above)
215                        labels.push(Label::new_unchecked(data.get_slice(len as usize)?));
216                    }
217                }
218            }
219        }
220
221        let mut labels = Vec::new();
222        let mut name_len = 0usize;
223
224        let mut pointer = parse_labels(data, &mut name_len, &mut labels)?;
225
226        let mut data = data.clone();
227        while let Some(p) = pointer {
228            // By creating a new buffer, it is possible to simplify the parse routine since
229            // the original buffer position will remain intact when iterating throught the
230            // pointers
231            data = data.new_at(p)?;
232            pointer = parse_labels(&mut data, &mut name_len, &mut labels)?;
233        }
234
235        Ok(Self { labels })
236    }
237
238    fn write_to<T: Write>(&self, out: &mut T) -> crate::Result<()> {
239        self.plain_append(out)
240    }
241
242    fn write_compressed_to<T: Write + Seek>(
243        &'a self,
244        out: &mut T,
245        name_refs: &mut crate::lib::BTreeMap<&[Label<'a>], u16>,
246    ) -> crate::Result<()> {
247        self.compress_append(out, name_refs)
248    }
249
250    fn len(&self) -> usize {
251        self.labels
252            .iter()
253            .map(|label| label.len() + 1)
254            .sum::<usize>()
255            + Self::MINIMUM_LEN
256    }
257}
258
259impl<'a> TryFrom<&'a str> for Name<'a> {
260    type Error = crate::SimpleDnsError;
261
262    fn try_from(value: &'a str) -> Result<Self, Self::Error> {
263        Name::new(value)
264    }
265}
266
267impl<'a> From<&'a [Label<'a>]> for Name<'a> {
268    fn from(labels: &'a [Label<'a>]) -> Self {
269        Name::new_with_labels(labels)
270    }
271}
272
273impl<'a, const N: usize> From<[Label<'a>; N]> for Name<'a> {
274    fn from(labels: [Label<'a>; N]) -> Self {
275        Name::new_with_labels(&labels)
276    }
277}
278
279impl Display for Name<'_> {
280    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
281        let mut labels = self.labels.iter();
282
283        if let Some(label) = labels.next() {
284            f.write_fmt(format_args!("{label}"))?;
285        }
286
287        for label in labels {
288            f.write_fmt(format_args!(".{label}"))?;
289        }
290
291        Ok(())
292    }
293}
294
295impl Debug for Name<'_> {
296    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
297        f.debug_tuple("Name")
298            .field(&format!("{self}"))
299            .field(&format!("{}", self.len()))
300            .finish()
301    }
302}
303
304impl PartialEq for Name<'_> {
305    fn eq(&self, other: &Self) -> bool {
306        self.labels == other.labels
307    }
308}
309
310impl Hash for Name<'_> {
311    fn hash<H: Hasher>(&self, state: &mut H) {
312        self.labels.hash(state);
313    }
314}
315
316/// An iterator over the labels in a domain name
317struct LabelsIter<'a> {
318    bytes: &'a [u8],
319    current: usize,
320}
321
322impl<'a> LabelsIter<'a> {
323    fn new(bytes: &'a [u8]) -> Self {
324        Self { bytes, current: 0 }
325    }
326}
327
328impl<'a> Iterator for LabelsIter<'a> {
329    type Item = Cow<'a, [u8]>;
330
331    fn next(&mut self) -> Option<Self::Item> {
332        for i in self.current..self.bytes.len() {
333            if self.bytes[i] == b'.' {
334                let current = crate::lib::mem::replace(&mut self.current, i + 1);
335                if i - current == 0 {
336                    continue;
337                }
338                return Some(self.bytes[current..i].into());
339            }
340        }
341
342        if self.current < self.bytes.len() {
343            let current = crate::lib::mem::replace(&mut self.current, self.bytes.len());
344            Some(self.bytes[current..].into())
345        } else {
346            None
347        }
348    }
349}
350
351/// Represents a label in a domain name
352///
353/// A valid label is consists of A-Z, a-z, 0-9, and hyphen (-), and must be at most 63 characters
354/// in length.
355/// This library also considers valid any label starting with underscore (_), to be able to parse mDNS domain names.
356///
357/// Microsoft implementation allows unicode characters in the label content.
358/// To create a label with unicode characters, use [`Label::new_unchecked`]
359///
360/// The `Display` implementation uses [`std::string::String::from_utf8_lossy`] to display the
361/// label.
362#[derive(Eq, PartialEq, Hash, Clone, PartialOrd, Ord)]
363pub struct Label<'a> {
364    data: Cow<'a, [u8]>,
365}
366
367impl<'a> Label<'a> {
368    /// Create a new [`Label`] if given data is valid and within the limits
369    pub fn new<T: Into<Cow<'a, [u8]>>>(data: T) -> crate::Result<Self> {
370        let label = Self::new_unchecked(data);
371        if !label.is_valid() {
372            return Err(crate::SimpleDnsError::InvalidServiceLabel);
373        }
374
375        Ok(label)
376    }
377
378    /// Create a new Label without checking for size limits or valid content.
379    /// This function can be used to create labels with unicode characters
380    pub fn new_unchecked<T: Into<Cow<'a, [u8]>>>(data: T) -> Self {
381        Self { data: data.into() }
382    }
383
384    /// Returns the length of the label
385    pub fn len(&self) -> usize {
386        self.data.len()
387    }
388
389    /// Returns true if the label is empty
390    pub fn is_empty(&self) -> bool {
391        self.data.is_empty()
392    }
393
394    /// Transforms the inner data into its owned type
395    pub fn into_owned<'b>(self) -> Label<'b> {
396        Label {
397            data: self.data.into_owned().into(),
398        }
399    }
400
401    /// Returns `true` if the label is valid.
402    pub fn is_valid(&self) -> bool {
403        if self.data.is_empty() || self.data.len() > MAX_LABEL_LENGTH {
404            return false;
405        }
406
407        if let Some(first) = self.data.first() {
408            if !first.is_ascii_alphanumeric() && *first != b'_' {
409                return false;
410            }
411        }
412
413        if !self
414            .data
415            .iter()
416            .skip(1)
417            .all(|c| c.is_ascii_alphanumeric() || *c == b'-' || *c == b'_')
418        {
419            return false;
420        }
421
422        if let Some(last) = self.data.last() {
423            if !last.is_ascii_alphanumeric() {
424                return false;
425            }
426        }
427
428        true
429    }
430}
431
432impl Display for Label<'_> {
433    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
434        let s = String::from_utf8_lossy(&self.data);
435        f.write_str(&s)
436    }
437}
438
439impl Debug for Label<'_> {
440    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
441        f.debug_struct("Label")
442            .field("data", &self.to_string())
443            .finish()
444    }
445}
446
447impl AsRef<[u8]> for Label<'_> {
448    fn as_ref(&self) -> &[u8] {
449        self.data.as_ref()
450    }
451}
452
453#[cfg(test)]
454mod tests {
455    use super::*;
456    use crate::lib::Cursor;
457    use crate::{lib::Vec, SimpleDnsError};
458
459    #[test]
460    fn construct_valid_names() {
461        assert!(Name::new("some").is_ok());
462        assert!(Name::new("some.local").is_ok());
463        assert!(Name::new("some.local.").is_ok());
464        assert!(Name::new("some-dash.local.").is_ok());
465        assert!(Name::new("_sync_miss._tcp.local").is_ok());
466        assert!(Name::new("1sync_miss._tcp.local").is_ok());
467
468        assert_eq!(Name::new_unchecked("\u{1F600}.local.").labels.len(), 2);
469    }
470
471    #[test]
472    fn label_validate() {
473        assert!(Name::new("\u{1F600}.local.").is_err());
474        assert!(Name::new("@.local.").is_err());
475        assert!(Name::new("\\.local.").is_err());
476    }
477
478    #[test]
479    fn is_link_local() {
480        assert!(!Name::new("some.example.com").unwrap().is_link_local());
481        assert!(Name::new("some.example.local.").unwrap().is_link_local());
482    }
483
484    #[test]
485    fn parse_without_compression() {
486        let mut data = BytesBuffer::new(
487            b"\x00\x00\x00\x01F\x03ISI\x04ARPA\x00\x03FOO\x01F\x03ISI\x04ARPA\x00\x04ARPA\x00",
488        );
489        data.advance(3).unwrap();
490        let name = Name::parse(&mut data).unwrap();
491        assert_eq!("F.ISI.ARPA", name.to_string());
492
493        let name = Name::parse(&mut data).unwrap();
494        assert_eq!("FOO.F.ISI.ARPA", name.to_string());
495    }
496
497    #[test]
498    fn parse_with_compression() {
499        let mut data = BytesBuffer::new(b"\x00\x00\x00\x01F\x03ISI\x04ARPA\x00\x03FOO\xc0\x03\x03BAR\xc0\x03\x07INVALID\xc0\x1b" );
500        data.advance(3).unwrap();
501
502        let name = Name::parse(&mut data).unwrap();
503        assert_eq!("F.ISI.ARPA", name.to_string());
504
505        let name = Name::parse(&mut data).unwrap();
506        assert_eq!("FOO.F.ISI.ARPA", name.to_string());
507
508        let name = Name::parse(&mut data).unwrap();
509        assert_eq!("BAR.F.ISI.ARPA", name.to_string());
510
511        assert!(Name::parse(&mut data).is_err());
512    }
513
514    #[test]
515    fn parse_handle_circular_pointers() {
516        let mut data = BytesBuffer::new(&[249, 0, 37, 1, 1, 139, 192, 6, 1, 1, 1, 139, 192, 6]);
517        data.advance(12).unwrap();
518
519        assert_eq!(
520            Name::parse(&mut data),
521            Err(SimpleDnsError::InvalidDnsPacket)
522        );
523    }
524
525    #[test]
526    fn test_write() {
527        let mut bytes = Vec::with_capacity(30);
528        Name::new_unchecked("_srv._udp.local")
529            .write_to(&mut bytes)
530            .unwrap();
531
532        assert_eq!(b"\x04_srv\x04_udp\x05local\x00", &bytes[..]);
533
534        let mut bytes = Vec::with_capacity(30);
535        Name::new_unchecked("_srv._udp.local2.")
536            .write_to(&mut bytes)
537            .unwrap();
538
539        assert_eq!(b"\x04_srv\x04_udp\x06local2\x00", &bytes[..]);
540    }
541
542    #[test]
543    fn root_name_should_generate_no_labels() {
544        assert_eq!(Name::new_unchecked("").labels.len(), 0);
545        assert_eq!(Name::new_unchecked(".").labels.len(), 0);
546    }
547
548    #[test]
549    fn dot_sequence_should_generate_no_labels() {
550        assert_eq!(Name::new_unchecked(".....").labels.len(), 0);
551        assert_eq!(Name::new_unchecked("example.....com").labels.len(), 2);
552    }
553
554    #[test]
555    fn root_name_should_write_zero() {
556        let mut bytes = Vec::with_capacity(30);
557        Name::new_unchecked(".").write_to(&mut bytes).unwrap();
558
559        assert_eq!(b"\x00", &bytes[..]);
560    }
561
562    #[test]
563    fn append_to_vec_with_compression() {
564        let mut buf = Cursor::new(crate::lib::vec![0, 0, 0]);
565        buf.set_position(3);
566
567        let mut name_refs = Default::default();
568
569        let f_isi_arpa = Name::new_unchecked("F.ISI.ARPA");
570        f_isi_arpa
571            .write_compressed_to(&mut buf, &mut name_refs)
572            .expect("failed to add F.ISI.ARPA");
573        let foo_f_isi_arpa = Name::new_unchecked("FOO.F.ISI.ARPA");
574        foo_f_isi_arpa
575            .write_compressed_to(&mut buf, &mut name_refs)
576            .expect("failed to add FOO.F.ISI.ARPA");
577
578        Name::new_unchecked("BAR.F.ISI.ARPA")
579            .write_compressed_to(&mut buf, &mut name_refs)
580            .expect("failed to add FOO.F.ISI.ARPA");
581
582        let data = b"\x00\x00\x00\x01F\x03ISI\x04ARPA\x00\x03FOO\xc0\x03\x03BAR\xc0\x03";
583        assert_eq!(data[..], buf.get_ref()[..]);
584    }
585
586    #[test]
587    fn append_to_vec_with_compression_mult_names() {
588        let mut buf = Cursor::new(Vec::new());
589        let mut name_refs = Default::default();
590
591        let isi_arpa = Name::new_unchecked("ISI.ARPA");
592        isi_arpa
593            .write_compressed_to(&mut buf, &mut name_refs)
594            .expect("failed to add ISI.ARPA");
595
596        let f_isi_arpa = Name::new_unchecked("F.ISI.ARPA");
597        f_isi_arpa
598            .write_compressed_to(&mut buf, &mut name_refs)
599            .expect("failed to add F.ISI.ARPA");
600        let foo_f_isi_arpa = Name::new_unchecked("FOO.F.ISI.ARPA");
601        foo_f_isi_arpa
602            .write_compressed_to(&mut buf, &mut name_refs)
603            .expect("failed to add F.ISI.ARPA");
604        Name::new_unchecked("BAR.F.ISI.ARPA")
605            .write_compressed_to(&mut buf, &mut name_refs)
606            .expect("failed to add F.ISI.ARPA");
607
608        let expected = b"\x03ISI\x04ARPA\x00\x01F\xc0\x00\x03FOO\xc0\x0a\x03BAR\xc0\x0a";
609        assert_eq!(expected[..], buf.get_ref()[..]);
610
611        let mut data = BytesBuffer::new(buf.get_ref());
612
613        let first = Name::parse(&mut data).unwrap();
614        assert_eq!("ISI.ARPA", first.to_string());
615        let second = Name::parse(&mut data).unwrap();
616        assert_eq!("F.ISI.ARPA", second.to_string());
617        let third = Name::parse(&mut data).unwrap();
618        assert_eq!("FOO.F.ISI.ARPA", third.to_string());
619        let fourth = Name::parse(&mut data).unwrap();
620        assert_eq!("BAR.F.ISI.ARPA", fourth.to_string());
621    }
622
623    #[test]
624    fn ensure_different_domains_are_not_compressed() {
625        let mut buf = Cursor::new(Vec::new());
626        let mut name_refs = Default::default();
627
628        let foo_bar_baz = Name::new_unchecked("FOO.BAR.BAZ");
629        foo_bar_baz
630            .write_compressed_to(&mut buf, &mut name_refs)
631            .expect("failed to add FOO.BAR.BAZ");
632
633        let foo_bar_buz = Name::new_unchecked("FOO.BAR.BUZ");
634        foo_bar_buz
635            .write_compressed_to(&mut buf, &mut name_refs)
636            .expect("failed to add FOO.BAR.BUZ");
637
638        Name::new_unchecked("FOO.BAR")
639            .write_compressed_to(&mut buf, &mut name_refs)
640            .expect("failed to add FOO.BAR");
641
642        let expected = b"\x03FOO\x03BAR\x03BAZ\x00\x03FOO\x03BAR\x03BUZ\x00\x03FOO\x03BAR\x00";
643        assert_eq!(expected[..], buf.get_ref()[..]);
644    }
645
646    #[test]
647    fn eq_other_name() -> Result<(), SimpleDnsError> {
648        assert_eq!(Name::new("example.com")?, Name::new("example.com")?);
649        assert_ne!(Name::new("some.example.com")?, Name::new("example.com")?);
650        assert_ne!(Name::new("example.co")?, Name::new("example.com")?);
651        assert_ne!(Name::new("example.com.org")?, Name::new("example.com")?);
652
653        let mut data =
654            BytesBuffer::new(b"\x00\x00\x00\x01F\x03ISI\x04ARPA\x00\x03FOO\xc0\x03\x03BAR\xc0\x03");
655        data.advance(3)?;
656        assert_eq!(Name::new("F.ISI.ARPA")?, Name::parse(&mut data)?);
657        assert_eq!(Name::new("FOO.F.ISI.ARPA")?, Name::parse(&mut data)?);
658        Ok(())
659    }
660
661    #[test]
662    fn len() -> crate::Result<()> {
663        let mut bytes = Vec::new();
664        let name_one = Name::new_unchecked("ex.com.");
665        name_one.write_to(&mut bytes)?;
666
667        assert_eq!(8, bytes.len());
668        assert_eq!(bytes.len(), name_one.len());
669        assert_eq!(8, Name::parse(&mut BytesBuffer::new(&bytes))?.len());
670
671        Ok(())
672    }
673
674    #[test]
675    fn len_compressed() -> crate::Result<()> {
676        let name_one = Name::new_unchecked("ex.com.");
677        let mut name_refs = Default::default();
678        let mut bytes = Cursor::new(Vec::new());
679        name_one.write_compressed_to(&mut bytes, &mut name_refs)?;
680        name_one.write_compressed_to(&mut bytes, &mut name_refs)?;
681
682        assert_eq!(10, bytes.get_ref().len());
683        Ok(())
684    }
685
686    #[test]
687    #[cfg(feature = "std")]
688    fn hash() -> crate::Result<()> {
689        fn get_hash(name: &Name) -> u64 {
690            let mut hasher = std::hash::DefaultHasher::default();
691            name.hash(&mut hasher);
692            hasher.finish()
693        }
694
695        let mut data =
696            BytesBuffer::new(b"\x00\x00\x00\x01F\x03ISI\x04ARPA\x00\x03FOO\xc0\x03\x03BAR\xc0\x03");
697        data.advance(3)?;
698
699        assert_eq!(
700            get_hash(&Name::new("F.ISI.ARPA")?),
701            get_hash(&Name::parse(&mut data)?)
702        );
703
704        assert_eq!(
705            get_hash(&Name::new("FOO.F.ISI.ARPA")?),
706            get_hash(&Name::parse(&mut data)?)
707        );
708
709        Ok(())
710    }
711
712    #[test]
713    fn is_subdomain_of() {
714        assert!(Name::new_unchecked("sub.example.com")
715            .is_subdomain_of(&Name::new_unchecked("example.com")));
716
717        assert!(!Name::new_unchecked("example.com")
718            .is_subdomain_of(&Name::new_unchecked("example.com")));
719
720        assert!(Name::new_unchecked("foo.sub.example.com")
721            .is_subdomain_of(&Name::new_unchecked("example.com")));
722
723        assert!(!Name::new_unchecked("example.com")
724            .is_subdomain_of(&Name::new_unchecked("example.xom")));
725
726        assert!(!Name::new_unchecked("domain.com")
727            .is_subdomain_of(&Name::new_unchecked("other.domain")));
728
729        assert!(!Name::new_unchecked("domain.com")
730            .is_subdomain_of(&Name::new_unchecked("domain.com.br")));
731    }
732
733    #[test]
734    fn subtract_domain() {
735        let domain = Name::new_unchecked("_srv3._tcp.local");
736        assert_eq!(
737            Name::new_unchecked("a._srv3._tcp.local")
738                .without(&domain)
739                .unwrap()
740                .to_string(),
741            "a"
742        );
743
744        assert!(Name::new_unchecked("unrelated").without(&domain).is_none(),);
745
746        assert_eq!(
747            Name::new_unchecked("some.longer.domain._srv3._tcp.local")
748                .without(&domain)
749                .unwrap()
750                .to_string(),
751            "some.longer.domain"
752        );
753    }
754
755    #[test]
756    fn display_invalid_label() {
757        let input = b"invalid\xF0\x90\x80label";
758        let label = Label::new_unchecked(input);
759
760        assert_eq!(label.to_string(), "invalid�label");
761    }
762
763    #[test]
764    fn test_compress_append_near_boundary() -> crate::Result<()> {
765        let mut buf = Cursor::new(Vec::new());
766        let mut name_refs = Default::default();
767
768        let before_boundary_pos = (MAX_COMPRESSION_OFFSET - 5) as usize;
769        let padding = vec![0u8; before_boundary_pos];
770        buf.write_all(&padding)?;
771
772        let name1 = Name::new_unchecked("foo.example.com");
773        let name2 = Name::new_unchecked("bar.test.net");
774
775        // before the boundary
776        let old_pos = buf.position();
777        name1.write_compressed_to(&mut buf, &mut name_refs)?;
778        assert_eq!(buf.position() - old_pos, name1.len() as u64);
779
780        // after the boundary
781        let old_pos = buf.position();
782        name2.write_compressed_to(&mut buf, &mut name_refs)?;
783        assert_eq!(buf.position() - old_pos, name2.len() as u64);
784
785        // should be compressed
786        let old_pos = buf.position();
787        name1.write_compressed_to(&mut buf, &mut name_refs)?;
788        assert_eq!(buf.position() - old_pos, 2);
789
790        // should not be compressed
791        let old_pos = buf.position();
792        name2.write_compressed_to(&mut buf, &mut name_refs)?;
793        assert_eq!(buf.position() - old_pos, name2.len() as u64);
794
795        Ok(())
796    }
797}