simple_dns/dns/rdata/
loc.rs1use crate::{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 fn parse(data: &'a [u8], position: &mut usize) -> crate::Result<Self>
37 where
38 Self: Sized,
39 {
40 if data.len() < *position + 16 {
41 return Err(SimpleDnsError::InsufficientData);
42 }
43
44 let data = &data[*position..*position + 16];
45 *position += 16;
46
47 let version = u8::from_be(data[0]);
48 if version != 0 {
49 return Err(SimpleDnsError::InvalidDnsPacket);
50 }
51
52 let size = u8::from_be(data[1]);
53 let horizontal_precision = u8::from_be(data[2]);
54 let vertical_precision = u8::from_be(data[3]);
55 let latitude = i32::from_be_bytes(data[4..8].try_into()?);
56 let longitude = i32::from_be_bytes(data[8..12].try_into()?);
57 let altitude = i32::from_be_bytes(data[12..16].try_into()?);
58
59 Ok(LOC {
60 version,
61 size,
62 horizontal_precision,
63 vertical_precision,
64 latitude,
65 longitude,
66 altitude,
67 })
68 }
69
70 fn write_to<T: std::io::Write>(&self, out: &mut T) -> crate::Result<()> {
71 if self.version != 0 {
72 return Err(SimpleDnsError::InvalidDnsPacket);
73 }
74
75 out.write_all(&[
76 self.version.to_be(),
77 self.size.to_be(),
78 self.horizontal_precision.to_be(),
79 self.vertical_precision.to_be(),
80 ])?;
81 out.write_all(&self.latitude.to_be_bytes())?;
82 out.write_all(&self.longitude.to_be_bytes())?;
83 out.write_all(&self.altitude.to_be_bytes())?;
84
85 Ok(())
86 }
87
88 fn len(&self) -> usize {
89 16
90 }
91}
92
93#[cfg(test)]
94mod tests {
95 use crate::{rdata::RData, ResourceRecord};
96
97 use super::*;
98
99 #[test]
100 fn parse_and_write_loc() {
101 let loc = LOC {
102 version: 0,
103 size: 0x10,
104 vertical_precision: 0x11,
105 horizontal_precision: 0x12,
106 altitude: 1000,
107 longitude: 2000,
108 latitude: 3000,
109 };
110
111 let mut data = Vec::new();
112 assert!(loc.write_to(&mut data).is_ok());
113
114 let loc = LOC::parse(&data, &mut 0);
115 assert!(loc.is_ok());
116 let loc = loc.unwrap();
117
118 assert_eq!(0x10, loc.size);
119 assert_eq!(0x11, loc.vertical_precision);
120 assert_eq!(0x12, loc.horizontal_precision);
121 assert_eq!(1000, loc.altitude);
122 assert_eq!(2000, loc.longitude);
123 assert_eq!(3000, loc.latitude);
124
125 assert_eq!(data.len(), loc.len());
126 }
127
128 #[test]
129 fn parse_sample() -> Result<(), Box<dyn std::error::Error>> {
130 let sample_file = std::fs::read("samples/zonefile/LOC.sample")?;
131
132 let sample_rdata = match ResourceRecord::parse(&sample_file, &mut 0)?.rdata {
133 RData::LOC(rdata) => rdata,
134 _ => unreachable!(),
135 };
136
137 assert_eq!(35, sample_rdata.size);
139 assert_eq!(35, sample_rdata.vertical_precision);
140 assert_eq!(37, sample_rdata.horizontal_precision);
141 assert_eq!(10001000, sample_rdata.altitude);
142 assert_eq!(-2058743648, sample_rdata.longitude);
143 assert_eq!(-1930943648, sample_rdata.latitude);
144 Ok(())
145 }
146}