simple_dns/dns/rdata/
loc.rs1use crate::{bytes_buffer::BytesBuffer, dns::WireFormat, SimpleDnsError};
2
3use super::RR;
4
5#[derive(Debug, PartialEq, Eq, Hash, Clone)]
7pub struct LOC {
8 pub version: u8,
10 pub size: u8,
12 pub horizontal_precision: u8,
14 pub vertical_precision: u8,
16 pub latitude: i32,
18 pub longitude: i32,
20 pub altitude: i32,
22}
23
24impl RR for LOC {
25 const TYPE_CODE: u16 = 29;
26}
27
28impl LOC {
29 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 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}