rust-dnsbox/lib/dnsbox-base/src/common_types/eui.rs

152 lines
3.5 KiB
Rust

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 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
}
}