Przeglądaj źródła

Support LOC records

The coordinate calculations are not done yet (it just shows the number) but the packet parsing is there.
Benjamin Sago 4 lat temu
rodzic
commit
6c897c2227
7 zmienionych plików z 190 dodań i 1 usunięć
  1. 154 0
      dns/src/record/loc.rs
  2. 6 0
      dns/src/record/mod.rs
  3. 0 1
      dns/src/record/others.rs
  4. 2 0
      dns/src/wire.rs
  5. 2 0
      src/colours.rs
  6. 25 0
      src/output.rs
  7. 1 0
      src/table.rs

+ 154 - 0
dns/src/record/loc.rs

@@ -0,0 +1,154 @@
+use std::fmt;
+
+use log::*;
+
+use crate::wire::*;
+
+
+/// A **LOC** _(location)_ record, which points to a location on Earth using
+/// its latitude, longitude, and altitude.
+///
+/// # References
+///
+/// - [RFC 1876](https://tools.ietf.org/html/rfc1876) — A Means for Expressing Location Information in the Domain Name System (January 1996)
+#[derive(PartialEq, Debug, Copy, Clone)]
+pub struct LOC {
+
+    /// The diameter of a sphere enclosing the entity at the location, as a
+    /// measure of its size, measured in centimetres.
+    pub size: Size,
+
+    /// The diameter of the “circle of error” that this location could be in,
+    /// measured in centimetres.
+    pub horizontal_precision: u8,
+
+    /// The amount of vertical space that this location could be in, measured
+    /// in centimetres.
+    pub vertical_precision: u8,
+
+    /// The latitude of the centre of the sphere, measured in thousandths of
+    /// an arcsecond, positive or negative with 2^31 as the equator.
+    pub latitude: u32,
+
+    /// The longitude of the centre of the sphere, measured in thousandths of
+    /// an arcsecond, positive or negative with 2^31 as the prime meridian.
+    pub longitude: u32,
+
+    /// The altitude of the centre of the sphere, measured in centimetres
+    /// above a base of 100,000 metres below the GPS reference spheroid.
+    pub altitude: u32,
+}
+
+#[derive(PartialEq, Debug, Copy, Clone)]
+pub struct Size {
+    base: u8,
+    power_of_ten: u8,
+}
+
+
+impl Wire for LOC {
+    const NAME: &'static str = "LOC";
+    const RR_TYPE: u16 = 29;
+
+    #[cfg_attr(all(test, feature = "with_mutagen"), ::mutagen::mutate)]
+    fn read(stated_length: u16, c: &mut Cursor<&[u8]>) -> Result<Self, WireError> {
+        if stated_length != 16 {
+            return Err(WireError::WrongRecordLength { stated_length, mandated_length: 16 });
+        }
+
+        let version = c.read_u8()?;
+        trace!("Parsed version -> {:?}", version);
+
+        if version != 0 {
+            warn!("LOC version is not 0");
+        }
+
+        let size_bits = c.read_u8()?;
+        trace!("Parsed size bits -> {:#08b}", size_bits);
+
+        let base = size_bits >> 4;
+        let power_of_ten = size_bits & 0b_0000_1111;
+        trace!("Split size into base {:?} and power of ten {:?}", base, power_of_ten);
+        let size = Size { base, power_of_ten };
+
+        let horizontal_precision = c.read_u8()?;
+        trace!("Parsed horizontal precision -> {:?}", horizontal_precision);
+
+        let vertical_precision = c.read_u8()?;
+        trace!("Parsed vertical precision -> {:?}", vertical_precision);
+
+        let latitude = c.read_u32::<BigEndian>()?;
+        trace!("Parsed latitude -> {:?}", version);
+
+        let longitude = c.read_u32::<BigEndian>()?;
+        trace!("Parsed longitude -> {:?}", longitude);
+
+        let altitude = c.read_u32::<BigEndian>()?;
+        trace!("Parsed altitude -> {:?}", altitude);
+
+        Ok(Self {
+            size, horizontal_precision, vertical_precision, latitude, longitude, altitude,
+        })
+    }
+}
+
+impl fmt::Display for Size {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "{}e{}", self.base, self.power_of_ten)
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+
+    #[test]
+    fn parses() {
+        let buf = &[
+            0x00,  // version
+            0x32,  // size,
+            0x00,  // horizontal precision
+            0x00,  // vertical precision
+            0x8b, 0x0d, 0x2c, 0x8c,  // latitude
+            0x7f, 0xf8, 0xfc, 0xa5,  // longitude
+            0x00, 0x98, 0x96, 0x80,  // altitude
+        ];
+
+        assert_eq!(LOC::read(buf.len() as _, &mut Cursor::new(buf)).unwrap(),
+                   LOC {
+                       size: Size { base: 3, power_of_ten: 2 },
+                       horizontal_precision: 0,
+                       vertical_precision: 0,
+                       latitude:  0x_8b_0d_2c_8c,
+                       longitude: 0x_7f_f8_fc_a5,
+                       altitude:  0x_00_98_96_80,
+                   });
+    }
+
+    #[test]
+    fn record_too_short() {
+        let buf = &[
+            0x00,  // version
+            0x00,  // size
+        ];
+
+        assert_eq!(LOC::read(buf.len() as _, &mut Cursor::new(buf)),
+                   Err(WireError::WrongRecordLength { stated_length: 2, mandated_length: 16 }));
+    }
+
+    #[test]
+    fn record_empty() {
+        assert_eq!(LOC::read(0, &mut Cursor::new(&[])),
+                   Err(WireError::WrongRecordLength { stated_length: 0, mandated_length: 16 }));
+    }
+
+    #[test]
+    fn buffer_ends_abruptly() {
+        let buf = &[
+            0x00,  // version
+        ];
+
+        assert_eq!(LOC::read(16, &mut Cursor::new(buf)),
+                   Err(WireError::IO));
+    }
+}

+ 6 - 0
dns/src/record/mod.rs

@@ -16,6 +16,9 @@ pub use self::cname::CNAME;
 mod hinfo;
 pub use self::hinfo::HINFO;
 
+mod loc;
+pub use self::loc::LOC;
+
 mod mx;
 pub use self::mx::MX;
 
@@ -64,6 +67,9 @@ pub enum Record {
     /// A **HINFO** record.
     HINFO(HINFO),
 
+    /// A **LOC** record.
+    LOC(LOC),
+
     /// A **MX** record.
     MX(MX),
 

+ 0 - 1
dns/src/record/others.rs

@@ -56,7 +56,6 @@ static TYPES: &[(&str, u16)] = &[
     ("IXFR",      251),
     ("KEY",        25),
     ("KX",         36),
-    ("LOC",        29),
     ("NAPTR",      35),
     ("NSEC",       47),
     ("NSEC3",      50),

+ 2 - 0
dns/src/wire.rs

@@ -176,6 +176,7 @@ impl Record {
         try_record!(CAA);
         try_record!(CNAME);
         try_record!(HINFO);
+        try_record!(LOC);
         try_record!(MX);
         try_record!(NS);
         // OPT is handled separately
@@ -236,6 +237,7 @@ pub fn find_qtype_number(record_type: &str) -> Option<TypeInt> {
     try_record!(CAA);
     try_record!(CNAME);
     try_record!(HINFO);
+    try_record!(LOC);
     try_record!(MX);
     try_record!(NS);
     // OPT is elsewhere

+ 2 - 0
src/colours.rs

@@ -18,6 +18,7 @@ pub struct Colours {
     pub caa: Style,
     pub cname: Style,
     pub hinfo: Style,
+    pub loc: Style,
     pub mx: Style,
     pub ns: Style,
     pub opt: Style,
@@ -46,6 +47,7 @@ impl Colours {
             caa: Red.normal(),
             cname: Yellow.normal(),
             hinfo: Yellow.normal(),
+            loc: Yellow.normal(),
             mx: Cyan.normal(),
             ns: Red.normal(),
             opt: Purple.normal(),

+ 25 - 0
src/output.rs

@@ -197,6 +197,16 @@ impl TextFormat {
             Record::HINFO(ref hinfo) => {
                 format!("{:?} {:?}", hinfo.cpu, hinfo.os)
             }
+            Record::LOC(ref loc) => {
+                format!("{} ({}, {}) ({}, {}, {})",
+                    loc.size,
+                    loc.horizontal_precision,
+                    loc.vertical_precision,
+                    loc.latitude,
+                    loc.longitude,
+                    loc.altitude,
+                )
+            }
             Record::MX(ref mx) => {
                 format!("{} {:?}", mx.preference, mx.exchange.to_string())
             }
@@ -362,6 +372,21 @@ fn json_record(record: &Record) -> JsonValue {
                 "os": rec.os,
             })
         }
+        Record::LOC(rec) => {
+            json!({
+                "type": "LOC",
+                "size": rec.size.to_string(),
+                "precision": {
+                    "horizontal": rec.horizontal_precision,
+                    "vertical": rec.vertical_precision,
+                },
+                "point": {
+                    "latitude": rec.latitude,
+                    "longitude": rec.longitude,
+                    "altitude": rec.altitude,
+                },
+            })
+        }
         Record::MX(rec) => {
             json!({
                 "type": "MX",

+ 1 - 0
src/table.rs

@@ -119,6 +119,7 @@ impl Table {
             Record::CAA(_)    => self.colours.caa.paint("CAA"),
             Record::CNAME(_)  => self.colours.cname.paint("CNAME"),
             Record::HINFO(_)  => self.colours.hinfo.paint("HINFO"),
+            Record::LOC(_)    => self.colours.loc.paint("LOC"),
             Record::MX(_)     => self.colours.mx.paint("MX"),
             Record::NS(_)     => self.colours.ns.paint("NS"),
             Record::PTR(_)    => self.colours.ptr.paint("PTR"),