simple_dns/dns/rdata/
naptr.rs

1use crate::{
2    bytes_buffer::BytesBuffer,
3    dns::{CharacterString, Name, WireFormat},
4    lib::Write,
5};
6
7use super::RR;
8
9/// RFC 3403: Used to map a domain name to a set of services. The fields determine
10///           the order of processing, specify the protocol and service to be used,
11///           and transform the original domain name into a new domain name or URI.
12
13#[derive(Debug, PartialEq, Eq, Hash, Clone)]
14pub struct NAPTR<'a> {
15    /// Order in which NAPTR records must be processed
16    pub order: u16,
17    /// Order in which NAPTR records with equal Order values should be processed
18    pub preference: u16,
19    /// Control rewriting and interpretation of the fields in the record
20    pub flags: CharacterString<'a>,
21    /// Service Parameters applicable to this this delegation path
22    pub services: CharacterString<'a>,
23    /// Regular expression applied to original string from client
24    pub regexp: CharacterString<'a>,
25    /// Next domain-name to query for
26    pub replacement: Name<'a>,
27}
28
29impl RR for NAPTR<'_> {
30    const TYPE_CODE: u16 = 35;
31}
32
33impl NAPTR<'_> {
34    /// Transforms the inner data into it owned type
35    pub fn into_owned<'b>(self) -> NAPTR<'b> {
36        NAPTR {
37            order: self.order,
38            preference: self.preference,
39            flags: self.flags.into_owned(),
40            services: self.services.into_owned(),
41            regexp: self.regexp.into_owned(),
42            replacement: self.replacement.into_owned(),
43        }
44    }
45}
46
47impl<'a> WireFormat<'a> for NAPTR<'a> {
48    const MINIMUM_LEN: usize = 4;
49
50    fn parse(data: &mut BytesBuffer<'a>) -> crate::Result<Self>
51    where
52        Self: Sized,
53    {
54        let order = data.get_u16()?;
55        let preference = data.get_u16()?;
56        let flags = CharacterString::parse(data)?;
57        let services = CharacterString::parse(data)?;
58        let regexp = CharacterString::parse(data)?;
59        let replacement = Name::parse(data)?;
60
61        Ok(Self {
62            order,
63            preference,
64            flags,
65            services,
66            regexp,
67            replacement,
68        })
69    }
70
71    fn write_to<T: Write>(&self, out: &mut T) -> crate::Result<()> {
72        out.write_all(&self.order.to_be_bytes())?;
73        out.write_all(&self.preference.to_be_bytes())?;
74        self.flags.write_to(out)?;
75        self.services.write_to(out)?;
76        self.regexp.write_to(out)?;
77        self.replacement.write_to(out)
78    }
79
80    fn len(&self) -> usize {
81        self.flags.len()
82            + self.services.len()
83            + self.regexp.len()
84            + self.replacement.len()
85            + Self::MINIMUM_LEN
86    }
87}
88
89#[cfg(test)]
90mod tests {
91    use super::*;
92    use crate::lib::{ToString, Vec};
93
94    #[test]
95    fn parse_and_write_naptr() {
96        let naptr = NAPTR {
97            order: 0,
98            preference: 1,
99            flags: CharacterString::new(b"123abc").unwrap(),
100            services: CharacterString::new(b"test").unwrap(),
101            regexp: CharacterString::new(b"@\\w+\\.\\w{2,3}(\\.\\w{2,3})?").unwrap(),
102            replacement: Name::new("e.exchange.com").unwrap(),
103        };
104
105        let mut data = Vec::new();
106        assert!(naptr.write_to(&mut data).is_ok());
107
108        let naptr = NAPTR::parse(&mut data[..].into());
109        assert!(naptr.is_ok());
110        let naptr = naptr.unwrap();
111
112        assert_eq!(data.len(), naptr.len());
113        assert_eq!(0, naptr.order);
114        assert_eq!(1, naptr.preference);
115        assert_eq!("123abc", naptr.flags.to_string());
116        assert_eq!("test", naptr.services.to_string());
117        assert_eq!("@\\w+\\.\\w{2,3}(\\.\\w{2,3})?", naptr.regexp.to_string());
118        assert_eq!("e.exchange.com", naptr.replacement.to_string());
119    }
120}