use crate::errors::*; use crate::ser::packet::{DnsPacketData, DnsPacketWriteContext}; use crate::ser::text::{next_field, DnsTextContext, DnsTextData, DnsTextFormatter}; use bytes::Bytes; use std::fmt; use std::io::{Cursor, Read}; fn fmt_eui_hyphens(data: &[u8], f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{:02x}", data[0])?; for v in &data[1..] { write!(f, "-{:02x}", v)?; } Ok(()) } fn parse_eui_hyphens(dest: &mut [u8], source: &str) -> Result<()> { let mut pos = 0; for octet in source.split('-') { failure::ensure!( pos < dest.len(), "too many octets for EUI{}", dest.len() * 8 ); failure::ensure!(octet.len() == 2, "invalid octet {:?}", octet); match u8::from_str_radix(octet, 16) { Ok(o) => { dest[pos] = o; pos += 1; }, Err(_) => { failure::bail!("invalid octet {:?}", octet); }, } } failure::ensure!( pos == dest.len(), "not enough octets for EUI{}", dest.len() * 8 ); Ok(()) } #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub struct EUI48Addr(pub [u8; 6]); impl fmt::Display for EUI48Addr { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt_eui_hyphens(&self.0, f) } } impl fmt::Debug for EUI48Addr { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt_eui_hyphens(&self.0, f) } } impl std::str::FromStr for EUI48Addr { type Err = failure::Error; fn from_str(s: &str) -> Result { let mut buf = [0u8; 6]; parse_eui_hyphens(&mut buf, s)?; Ok(EUI48Addr(buf)) } } impl DnsPacketData for EUI48Addr { fn deserialize(data: &mut Cursor) -> Result { let mut buf = [0u8; 6]; check_enough_data!(data, 6, "not enough bytes for EUI48Addr"); data.read_exact(&mut buf)?; Ok(EUI48Addr(buf)) } fn serialize(&self, _context: &mut DnsPacketWriteContext, packet: &mut Vec) -> Result<()> { packet.extend_from_slice(&self.0); Ok(()) } } impl DnsTextData for EUI48Addr { fn dns_parse(_context: &DnsTextContext, data: &mut &str) -> Result { next_field(data)?.parse() } fn dns_format(&self, f: &mut DnsTextFormatter) -> fmt::Result { write!(f, "{}", self) } } impl From<[u8; 6]> for EUI48Addr { fn from(v: [u8; 6]) -> Self { EUI48Addr(v) } } impl Into<[u8; 6]> for EUI48Addr { fn into(self) -> [u8; 6] { self.0 } } #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub struct EUI64Addr(pub [u8; 8]); impl fmt::Display for EUI64Addr { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt_eui_hyphens(&self.0, f) } } impl fmt::Debug for EUI64Addr { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt_eui_hyphens(&self.0, f) } } impl std::str::FromStr for EUI64Addr { type Err = failure::Error; fn from_str(s: &str) -> Result { let mut buf = [0u8; 8]; parse_eui_hyphens(&mut buf, s)?; Ok(EUI64Addr(buf)) } } impl DnsPacketData for EUI64Addr { fn deserialize(data: &mut Cursor) -> Result { let mut buf = [0u8; 8]; check_enough_data!(data, 8, "not enough bytes for EUI64Addr"); data.read_exact(&mut buf)?; Ok(EUI64Addr(buf)) } fn serialize(&self, _context: &mut DnsPacketWriteContext, packet: &mut Vec) -> Result<()> { packet.extend_from_slice(&self.0); Ok(()) } } impl DnsTextData for EUI64Addr { fn dns_parse(_context: &DnsTextContext, data: &mut &str) -> Result { next_field(data)?.parse() } fn dns_format(&self, f: &mut DnsTextFormatter) -> fmt::Result { write!(f, "{}", self) } } impl From<[u8; 8]> for EUI64Addr { fn from(v: [u8; 8]) -> Self { EUI64Addr(v) } } impl Into<[u8; 8]> for EUI64Addr { fn into(self) -> [u8; 8] { self.0 } }