simple_dns/dns/rdata/
loc.rs

1use crate::{bytes_buffer::BytesBuffer, dns::WireFormat, SimpleDnsError};
2
3use super::RR;
4
5///  A Means for Expressing Location Information in the Domain Name System [RFC 1876](https://datatracker.ietf.org/doc/html/rfc1876)
6#[derive(Debug, PartialEq, Eq, Hash, Clone)]
7pub struct LOC {
8    /// Version number of the representation.  This must be zero.
9    pub version: u8,
10    /// The diameter of a sphere enclosing the described entity, in centimeters, expressed as a pair of four-bit unsigned integers
11    pub size: u8,
12    /// The horizontal precision of the data, in centimeters, expressed using the same representation as SIZE
13    pub horizontal_precision: u8,
14    /// The vertical precision of the data, in centimeters, expressed using the sane representation as for SIZE
15    pub vertical_precision: u8,
16    /// The latitude of the center of the sphere described by the SIZE field
17    pub latitude: i32,
18    /// The longitude of the center of the sphere described by the SIZE field
19    pub longitude: i32,
20    /// The altitude of the center of the sphere described by the SIZE field
21    pub altitude: i32,
22}
23
24impl RR for LOC {
25    const TYPE_CODE: u16 = 29;
26}
27
28impl LOC {
29    /// Transforms the inner data into its owned type
30    pub fn into_owned(self) -> Self {
31        self
32    }
33}
34
35impl<'a> WireFormat<'a> for LOC {
36    const MINIMUM_LEN: usize = 16;
37
38    fn parse(data: &mut BytesBuffer<'a>) -> crate::Result<Self>
39    where
40        Self: Sized,
41    {
42        let version = data.get_u8()?;
43        if version != 0 {
44            return Err(SimpleDnsError::InvalidDnsPacket);
45        }
46
47        let size = data.get_u8()?;
48        let horizontal_precision = data.get_u8()?;
49        let vertical_precision = data.get_u8()?;
50        let latitude = data.get_i32()?;
51        let longitude = data.get_i32()?;
52        let altitude = data.get_i32()?;
53
54        Ok(LOC {
55            version,
56            size,
57            horizontal_precision,
58            vertical_precision,
59            latitude,
60            longitude,
61            altitude,
62        })
63    }
64
65    fn write_to<T: std::io::Write>(&self, out: &mut T) -> crate::Result<()> {
66        if self.version != 0 {
67            return Err(SimpleDnsError::InvalidDnsPacket);
68        }
69
70        out.write_all(&[
71            self.version.to_be(),
72            self.size.to_be(),
73            self.horizontal_precision.to_be(),
74            self.vertical_precision.to_be(),
75        ])?;
76        out.write_all(&self.latitude.to_be_bytes())?;
77        out.write_all(&self.longitude.to_be_bytes())?;
78        out.write_all(&self.altitude.to_be_bytes())?;
79
80        Ok(())
81    }
82}
83
84#[cfg(test)]
85mod tests {
86    use crate::{rdata::RData, ResourceRecord};
87
88    use super::*;
89
90    #[test]
91    fn parse_and_write_loc() {
92        let loc = LOC {
93            version: 0,
94            size: 0x10,
95            vertical_precision: 0x11,
96            horizontal_precision: 0x12,
97            altitude: 1000,
98            longitude: 2000,
99            latitude: 3000,
100        };
101
102        let mut data = Vec::new();
103        assert!(loc.write_to(&mut data).is_ok());
104
105        let loc = LOC::parse(&mut (&data[..]).into());
106        assert!(loc.is_ok());
107        let loc = loc.unwrap();
108
109        assert_eq!(0x10, loc.size);
110        assert_eq!(0x11, loc.vertical_precision);
111        assert_eq!(0x12, loc.horizontal_precision);
112        assert_eq!(1000, loc.altitude);
113        assert_eq!(2000, loc.longitude);
114        assert_eq!(3000, loc.latitude);
115
116        assert_eq!(data.len(), loc.len());
117    }
118
119    #[test]
120    fn parse_sample() -> Result<(), Box<dyn std::error::Error>> {
121        let sample_file = std::fs::read("samples/zonefile/LOC.sample")?;
122
123        let sample_rdata = match ResourceRecord::parse(&mut (&sample_file[..]).into())?.rdata {
124            RData::LOC(rdata) => rdata,
125            _ => unreachable!(),
126        };
127
128        // 60 09 00.000 N 24 39 00.000 E 10.00m 20.00m ( 2000.00m 20.00m )
129        assert_eq!(35, sample_rdata.size);
130        assert_eq!(35, sample_rdata.vertical_precision);
131        assert_eq!(37, sample_rdata.horizontal_precision);
132        assert_eq!(10001000, sample_rdata.altitude);
133        assert_eq!(-2058743648, sample_rdata.longitude);
134        assert_eq!(-1930943648, sample_rdata.latitude);
135        Ok(())
136    }
137}