simple_dns/dns/rdata/
route_through.rs

1use std::collections::HashMap;
2
3use crate::{
4    bytes_buffer::BytesBuffer,
5    dns::{name::Label, Name, WireFormat},
6};
7
8use super::RR;
9
10/// The RT resource record provides a route-through binding for hosts that do not have their own direct wide area network addresses
11#[derive(Debug, PartialEq, Eq, Hash, Clone)]
12pub struct RouteThrough<'a> {
13    /// A 16 bit integer which specifies the preference given to this RR among others at the same owner.  
14    /// Lower values are preferred.
15    pub preference: u16,
16
17    /// A [Name](`Name`) which specifies a host which will serve as an intermediate in reaching the host specified by **owner**.
18    pub intermediate_host: Name<'a>,
19}
20
21impl RR for RouteThrough<'_> {
22    const TYPE_CODE: u16 = 21;
23}
24
25impl RouteThrough<'_> {
26    /// Transforms the inner data into its owned type
27    pub fn into_owned<'b>(self) -> RouteThrough<'b> {
28        RouteThrough {
29            preference: self.preference,
30            intermediate_host: self.intermediate_host.into_owned(),
31        }
32    }
33}
34
35impl<'a> WireFormat<'a> for RouteThrough<'a> {
36    const MINIMUM_LEN: usize = 2;
37    fn parse(data: &mut BytesBuffer<'a>) -> crate::Result<Self>
38    where
39        Self: Sized,
40    {
41        let preference = data.get_u16()?;
42        let intermediate_host = Name::parse(data)?;
43
44        Ok(Self {
45            preference,
46            intermediate_host,
47        })
48    }
49
50    fn write_to<T: std::io::Write>(&self, out: &mut T) -> crate::Result<()> {
51        out.write_all(&self.preference.to_be_bytes())?;
52        self.intermediate_host.write_to(out)
53    }
54
55    fn write_compressed_to<T: std::io::Write + std::io::Seek>(
56        &'a self,
57        out: &mut T,
58        name_refs: &mut HashMap<&'a [Label<'a>], usize>,
59    ) -> crate::Result<()> {
60        out.write_all(&self.preference.to_be_bytes())?;
61        self.intermediate_host.write_compressed_to(out, name_refs)
62    }
63
64    fn len(&self) -> usize {
65        self.intermediate_host.len() + Self::MINIMUM_LEN
66    }
67}
68
69#[cfg(test)]
70mod tests {
71    use crate::{rdata::RData, ResourceRecord};
72
73    use super::*;
74
75    #[test]
76    fn parse_and_write_route_through() {
77        let rt = RouteThrough {
78            preference: 10,
79            intermediate_host: Name::new("e.exchange.com").unwrap(),
80        };
81
82        let mut data = Vec::new();
83        assert!(rt.write_to(&mut data).is_ok());
84
85        let rt = RouteThrough::parse(&mut data[..].into());
86        assert!(rt.is_ok());
87        let rt = rt.unwrap();
88
89        assert_eq!(data.len(), rt.len());
90        assert_eq!(10, rt.preference);
91        assert_eq!("e.exchange.com", rt.intermediate_host.to_string());
92    }
93
94    #[test]
95    fn parse_sample() -> Result<(), Box<dyn std::error::Error>> {
96        let sample_file = std::fs::read("samples/zonefile/RT.sample")?;
97
98        let sample_rdata = match ResourceRecord::parse(&mut sample_file[..].into())?.rdata {
99            RData::RouteThrough(rdata) => rdata,
100            _ => unreachable!(),
101        };
102
103        assert_eq!(sample_rdata.preference, 0);
104        assert_eq!(
105            sample_rdata.intermediate_host,
106            "intermediate-host.sample".try_into()?
107        );
108        Ok(())
109    }
110}