simple_dns/dns/rdata/
rp.rs

1use std::collections::HashMap;
2
3use crate::dns::{name::Label, Name, WireFormat};
4
5use super::RR;
6
7/// RP Responsible Person, [RFC 1183](https://datatracker.ietf.org/doc/html/rfc1183#section-2.2)
8#[derive(Debug, PartialEq, Eq, Hash, Clone)]
9pub struct RP<'a> {
10    /// A [Name](`Name`) which specifies a mailbox for the responsble person.
11    pub mbox: Name<'a>,
12    /// A [Name](`Name`) which specifies a domain name the TXT records.
13    pub txt: Name<'a>,
14}
15
16impl<'a> RR for RP<'a> {
17    const TYPE_CODE: u16 = 17;
18}
19
20impl<'a> RP<'a> {
21    /// Transforms the inner data into its owned type
22    pub fn into_owned<'b>(self) -> RP<'b> {
23        RP {
24            mbox: self.mbox.into_owned(),
25            txt: self.txt.into_owned(),
26        }
27    }
28}
29
30impl<'a> WireFormat<'a> for RP<'a> {
31    fn parse(data: &'a [u8], position: &mut usize) -> crate::Result<Self>
32    where
33        Self: Sized,
34    {
35        let mbox = Name::parse(data, position)?;
36        let txt = Name::parse(data, position)?;
37        Ok(RP { mbox, txt })
38    }
39
40    fn write_to<T: std::io::Write>(&self, out: &mut T) -> crate::Result<()> {
41        self.mbox.write_to(out)?;
42        self.txt.write_to(out)
43    }
44
45    fn write_compressed_to<T: std::io::Write + std::io::Seek>(
46        &'a self,
47        out: &mut T,
48        name_refs: &mut HashMap<&'a [Label<'a>], usize>,
49    ) -> crate::Result<()> {
50        self.mbox.write_compressed_to(out, name_refs)?;
51        self.txt.write_compressed_to(out, name_refs)
52    }
53
54    fn len(&self) -> usize {
55        self.txt.len() + self.mbox.len()
56    }
57}
58
59#[cfg(test)]
60mod tests {
61    use crate::{rdata::RData, ResourceRecord};
62
63    use super::*;
64
65    #[test]
66    fn parse_and_write_rp() {
67        let rp = RP {
68            mbox: Name::new("mbox.rp.com").unwrap(),
69            txt: Name::new("txt.rp.com").unwrap(),
70        };
71
72        let mut data = Vec::new();
73        assert!(rp.write_to(&mut data).is_ok());
74
75        let rp = RP::parse(&data, &mut 0);
76        assert!(rp.is_ok());
77        let rp = rp.unwrap();
78
79        assert_eq!(data.len(), rp.len());
80        assert_eq!("mbox.rp.com", rp.mbox.to_string());
81        assert_eq!("txt.rp.com", rp.txt.to_string());
82    }
83
84    #[test]
85    fn parse_sample() -> Result<(), Box<dyn std::error::Error>> {
86        let sample_file = std::fs::read("samples/zonefile/RP.sample")?;
87
88        let sample_rdata = match ResourceRecord::parse(&sample_file, &mut 0)?.rdata {
89            RData::RP(rdata) => rdata,
90            _ => unreachable!(),
91        };
92
93        assert_eq!(sample_rdata.mbox, "mbox-dname.sample".try_into()?);
94        assert_eq!(sample_rdata.txt, "txt-dname.sample".try_into()?);
95        Ok(())
96    }
97}