Sfoglia il codice sorgente

Support EUI48 records

Benjamin Sago 4 anni fa
parent
commit
e5b940bcc2
6 ha cambiato i file con 129 aggiunte e 0 eliminazioni
  1. 109 0
      dns/src/record/eui48.rs
  2. 6 0
      dns/src/record/mod.rs
  3. 2 0
      dns/src/wire.rs
  4. 2 0
      src/colours.rs
  5. 9 0
      src/output.rs
  6. 1 0
      src/table.rs

+ 109 - 0
dns/src/record/eui48.rs

@@ -0,0 +1,109 @@
+use log::*;
+
+use crate::wire::*;
+
+/// A **EUI48** record, which holds a six-octet (48-bit) Extended Unique
+/// Identifier. These identifiers can be used as MAC addresses.
+///
+/// # References
+///
+/// - [RFC 7043](https://tools.ietf.org/html/rfc7043) — Resource Records for
+///   EUI-48 and EUI-64 Addresses in the DNS (October 2013)
+#[derive(PartialEq, Debug, Copy, Clone)]
+pub struct EUI48 {
+
+    /// The six octets that make up the identifier.
+    pub octets: [u8; 6],
+}
+
+impl Wire for EUI48 {
+    const NAME: &'static str = "EUI48";
+    const RR_TYPE: u16 = 108;
+
+    #[cfg_attr(feature = "with_mutagen", ::mutagen::mutate)]
+    fn read(stated_length: u16, c: &mut Cursor<&[u8]>) -> Result<Self, WireError> {
+        if stated_length !=  6 {
+            warn!("Length is incorrect (record length {:?}, but should be six)", stated_length);
+            let mandated_length = MandatedLength::Exactly(6);
+            return Err(WireError::WrongRecordLength { stated_length, mandated_length });
+        }
+
+        let mut octets = [0_u8; 6];
+        c.read_exact(&mut octets)?;
+
+        Ok(Self { octets })
+    }
+}
+
+
+impl EUI48 {
+
+    /// Returns this EUI as hexadecimal numbers, separated by dashes.
+    pub fn formatted_address(&self) -> String {
+        format!("{:02x}-{:02x}-{:02x}-{:02x}-{:02x}-{:02x}",
+                self.octets[0], self.octets[1], self.octets[2],
+                self.octets[3], self.octets[4], self.octets[5])
+    }
+}
+
+
+#[cfg(test)]
+mod test {
+    use super::*;
+    use pretty_assertions::assert_eq;
+
+    #[test]
+    fn parses() {
+        let buf = &[
+            0x00, 0x7F, 0x23, 0x12, 0x34, 0x56,  // identifier
+        ];
+
+        assert_eq!(EUI48::read(buf.len() as _, &mut Cursor::new(buf)).unwrap(),
+                   EUI48 { octets: [ 0x00, 0x7F, 0x23, 0x12, 0x34, 0x56 ] });
+    }
+
+    #[test]
+    fn record_too_short() {
+        let buf = &[
+            0x00, 0x7F, 0x23,  // a mere OUI
+        ];
+
+        assert_eq!(EUI48::read(buf.len() as _, &mut Cursor::new(buf)),
+                   Err(WireError::WrongRecordLength { stated_length: 3, mandated_length: MandatedLength::Exactly(6) }));
+    }
+
+    #[test]
+    fn record_too_long() {
+        let buf = &[
+            0x00, 0x7F, 0x23, 0x12, 0x34, 0x56,  // identifier
+            0x01,  // an unexpected extra byte
+        ];
+
+        assert_eq!(EUI48::read(buf.len() as _, &mut Cursor::new(buf)),
+                   Err(WireError::WrongRecordLength { stated_length: 7, mandated_length: MandatedLength::Exactly(6) }));
+    }
+
+    #[test]
+    fn record_empty() {
+        assert_eq!(EUI48::read(0, &mut Cursor::new(&[])),
+                   Err(WireError::WrongRecordLength { stated_length: 0, mandated_length: MandatedLength::Exactly(6) }));
+    }
+
+    #[test]
+    fn buffer_ends_abruptly() {
+        let buf = &[
+            0x00, 0x7F, 0x23,  // a mere OUI
+        ];
+
+        assert_eq!(EUI48::read(6, &mut Cursor::new(buf)),
+                   Err(WireError::IO));
+    }
+
+    #[test]
+    fn hex_rep() {
+        let record = EUI48 { octets: [ 0x00, 0x7F, 0x23, 0x12, 0x34, 0x56 ] };
+
+        assert_eq!(record.formatted_address(),
+                   "00-7f-23-12-34-56");
+    }
+}

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

@@ -13,6 +13,9 @@ pub use self::caa::CAA;
 mod cname;
 pub use self::cname::CNAME;
 
+mod eui48;
+pub use self::eui48::EUI48;
+
 mod hinfo;
 pub use self::hinfo::HINFO;
 
@@ -76,6 +79,9 @@ pub enum Record {
     /// A **CNAME** record.
     CNAME(CNAME),
 
+    /// An **EUI48** record.
+    EUI48(EUI48),
+
     /// A **HINFO** record.
     HINFO(HINFO),
 

+ 2 - 0
dns/src/wire.rs

@@ -179,6 +179,7 @@ impl Record {
         try_record!(AAAA);
         try_record!(CAA);
         try_record!(CNAME);
+        try_record!(EUI48);
         try_record!(HINFO);
         try_record!(LOC);
         try_record!(MX);
@@ -244,6 +245,7 @@ pub fn find_qtype_number(record_type: &str) -> Option<TypeInt> {
     try_record!(AAAA);
     try_record!(CAA);
     try_record!(CNAME);
+    try_record!(EUI48);
     try_record!(HINFO);
     try_record!(LOC);
     try_record!(MX);

+ 2 - 0
src/colours.rs

@@ -17,6 +17,7 @@ pub struct Colours {
     pub aaaa: Style,
     pub caa: Style,
     pub cname: Style,
+    pub eui48: Style,
     pub hinfo: Style,
     pub loc: Style,
     pub mx: Style,
@@ -50,6 +51,7 @@ impl Colours {
             aaaa: Green.bold(),
             caa: Red.normal(),
             cname: Yellow.normal(),
+            eui48: Yellow.normal(),
             hinfo: Yellow.normal(),
             loc: Yellow.normal(),
             mx: Cyan.normal(),

+ 9 - 0
src/output.rs

@@ -194,6 +194,9 @@ impl TextFormat {
             Record::CNAME(ref cname) => {
                 format!("{:?}", cname.domain.to_string())
             }
+            Record::EUI48(ref eui48) => {
+                format!("{:?}", eui48.formatted_address())
+            }
             Record::HINFO(ref hinfo) => {
                 format!("{:?} {:?}", hinfo.cpu, hinfo.os)
             }
@@ -390,6 +393,12 @@ fn json_record(record: &Record) -> JsonValue {
                 "domain": rec.domain.to_string(),
             })
         }
+        Record::EUI48(rec) => {
+            json!({
+                "type": "EUI48",
+                "identifier": rec.formatted_address(),
+            })
+        }
         Record::HINFO(rec) => {
             json!({
                 "type": "HINFO",

+ 1 - 0
src/table.rs

@@ -118,6 +118,7 @@ impl Table {
             Record::AAAA(_)        => self.colours.aaaa.paint("AAAA"),
             Record::CAA(_)         => self.colours.caa.paint("CAA"),
             Record::CNAME(_)       => self.colours.cname.paint("CNAME"),
+            Record::EUI48(_)       => self.colours.eui48.paint("EUI48"),
             Record::HINFO(_)       => self.colours.hinfo.paint("HINFO"),
             Record::LOC(_)         => self.colours.loc.paint("LOC"),
             Record::MX(_)          => self.colours.mx.paint("MX"),