144 lines
3.4 KiB
Rust
144 lines
3.4 KiB
Rust
use bytes::Bytes;
|
|
use errors::*;
|
|
use ser::packet::{DnsPacketData, DnsPacketWriteContext};
|
|
use ser::text::{DnsTextData, DnsTextFormatter, DnsTextContext, next_field};
|
|
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('-') {
|
|
ensure!(pos < dest.len(), "too many octets for EUI{}", dest.len() * 8);
|
|
ensure!(octet.len() == 2, "invalid octet {:?}", octet);
|
|
match u8::from_str_radix(octet, 16) {
|
|
Ok(o) => {
|
|
dest[pos] = o;
|
|
pos += 1;
|
|
},
|
|
Err(_) => {
|
|
bail!("invalid octet {:?}", octet);
|
|
},
|
|
}
|
|
}
|
|
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 DnsPacketData for EUI48Addr {
|
|
fn deserialize(data: &mut Cursor<Bytes>) -> Result<Self> {
|
|
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<u8>) -> Result<()> {
|
|
packet.extend_from_slice(&self.0);
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
impl DnsTextData for EUI48Addr {
|
|
fn dns_parse(_context: &DnsTextContext, data: &mut &str) -> Result<Self> {
|
|
let field = next_field(data)?;
|
|
let mut buf = [0u8; 6];
|
|
parse_eui_hyphens(&mut buf, field)?;
|
|
Ok(EUI48Addr(buf))
|
|
}
|
|
|
|
// format might fail if there is no (known) text representation.
|
|
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 DnsPacketData for EUI64Addr {
|
|
fn deserialize(data: &mut Cursor<Bytes>) -> Result<Self> {
|
|
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<u8>) -> Result<()> {
|
|
packet.extend_from_slice(&self.0);
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
impl DnsTextData for EUI64Addr {
|
|
fn dns_parse(_context: &DnsTextContext, data: &mut &str) -> Result<Self> {
|
|
let field = next_field(data)?;
|
|
let mut buf = [0u8; 8];
|
|
parse_eui_hyphens(&mut buf, field)?;
|
|
Ok(EUI64Addr(buf))
|
|
}
|
|
|
|
// format might fail if there is no (known) text representation.
|
|
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
|
|
}
|
|
}
|