simple_dns/dns/rdata/
afsdb.rs

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