use crate::utils::TimestampResolution;
use crate::writer::Encodable;
use crate::{
enums::{PacketDirection, ReceptionType},
utils::pad_to_32,
};
use byteorder::{ByteOrder, WriteBytesExt};
use std::convert::TryInto;
use std::io;
use std::io::Write;
use std::net::{Ipv4Addr, Ipv6Addr};
#[derive(Debug)]
pub enum BlockOption {
OptEndOfOpt(OptionEndOfOpt),
OptComment(OptionComment),
OptCustom(u16),
ShbHardware,
ShbOs,
ShbUserAppl,
IfName(OptionIfName),
IfDescription(OptionIfDescription),
IfIpv4Addr(OptionIfIpv4Addr),
IfIpv6Addr(OptionIfIpv6Addr),
IfMacAddr(OptionIfMacAddr),
IfEuiAddr,
IfSpeed,
IfTsResol(OptionIfTsResol),
IfTZone,
IfFilter,
IfOs,
IfFcsLen,
IfTsOffset,
IfHardware,
EpbFlags(OptionEpbFlags),
EpbHash,
EpbDropCount,
Raw(RawOption),
}
impl BlockOption {
pub fn code(&self) -> u16 {
match self {
Self::OptEndOfOpt(_) => 0,
Self::OptComment(_) => 1,
Self::OptCustom(x) => *x,
Self::ShbHardware => 2,
Self::ShbOs => 3,
Self::ShbUserAppl => 4,
Self::IfName(_) => 2,
Self::IfDescription(_) => 3,
Self::IfIpv4Addr(_) => 4,
Self::IfIpv6Addr(_) => 5,
Self::IfMacAddr(_) => 6,
Self::IfEuiAddr => 7,
Self::IfSpeed => 8,
Self::IfTsResol(_) => 9,
Self::IfTZone => 10,
Self::IfFilter => 11,
Self::IfOs => 12,
Self::IfFcsLen => 13,
Self::IfTsOffset => 14,
Self::IfHardware => 15,
Self::EpbFlags(_) => 2,
Self::EpbHash => 3,
Self::EpbDropCount => 4,
Self::Raw(_) => unimplemented!(),
}
}
fn bytes<B: ByteOrder>(&self) -> Vec<u8> {
match self {
Self::OptEndOfOpt(o) => o.bytes::<B>(),
Self::OptComment(o) => o.bytes::<B>(),
Self::IfName(o) => o.bytes::<B>(),
Self::IfDescription(o) => o.bytes::<B>(),
Self::IfIpv4Addr(o) => o.bytes::<B>(),
Self::IfIpv6Addr(o) => o.bytes::<B>(),
Self::IfMacAddr(o) => o.bytes::<B>(),
Self::IfTsResol(o) => o.bytes::<B>(),
Self::EpbFlags(o) => o.bytes::<B>(),
Self::Raw(r) => r.bytes::<B>(),
_ => unimplemented!(),
}
}
fn length(&self) -> u16 {
match self {
Self::OptEndOfOpt(o) => o.length(),
Self::OptComment(o) => o.length(),
Self::IfName(o) => o.length(),
Self::IfDescription(o) => o.length(),
Self::IfIpv4Addr(o) => o.length(),
Self::IfIpv6Addr(o) => o.length(),
Self::IfMacAddr(o) => o.length(),
Self::IfTsResol(o) => o.length(),
Self::EpbFlags(o) => o.length(),
Self::Raw(r) => r.length,
_ => unimplemented!(),
}
}
fn padding(&self) -> Vec<u8> {
let n = pad_to_32(self.length().into());
vec![0u8; n]
}
}
impl<W: Write> Encodable<W> for BlockOption {
fn encode<B: ByteOrder>(&self, w: &mut W) -> io::Result<()> {
if let Self::Raw(_) = self {
w.write_all(&self.bytes::<B>())?;
w.write_all(&self.padding())?;
Ok(())
} else {
w.write_u16::<B>(self.code())?;
w.write_u16::<B>(self.length())?;
w.write_all(&self.bytes::<B>())?;
w.write_all(&self.padding())?;
Ok(())
}
}
}
#[derive(Debug, Default)]
pub struct Options<'a>(Vec<&'a BlockOption>);
impl<'a, W: Write> Encodable<W> for Options<'a> {
fn encode<B: ByteOrder>(&self, w: &mut W) -> io::Result<()> {
for opt in &self.0 {
opt.encode::<B>(w)?;
}
Ok(())
}
}
impl<'a> Options<'a> {
pub fn new() -> Options<'a> {
Default::default()
}
pub fn add_option(&mut self, opt: &'a BlockOption) {
self.0.push(opt);
}
pub fn length(&self) -> u32 {
self.0
.iter()
.map(|opt| opt.length() as u32 + opt.padding().len() as u32 + 4)
.sum()
}
pub fn clear(&mut self) {
self.0.clear();
}
}
#[derive(Debug)]
pub struct RawOption {
code: u16,
length: u16,
value: Vec<u8>,
}
impl RawOption {
pub fn new(code: u16, length: u16, value: Vec<u8>) -> RawOption {
RawOption {
code,
length,
value,
}
}
fn bytes<B: ByteOrder>(&self) -> Vec<u8> {
let mut buf: Vec<u8> = vec![];
buf.write_u16::<B>(self.code).unwrap();
buf.write_u16::<B>(self.length).unwrap();
buf.write_all(&self.value).unwrap();
buf
}
}
#[derive(Debug, Default)]
pub struct OptionEndOfOpt;
impl OptionEndOfOpt {
pub fn new() -> Self {
Default::default()
}
pub fn new_option() -> BlockOption {
BlockOption::OptEndOfOpt(Self::new())
}
fn length(&self) -> u16 {
0
}
fn bytes<B: ByteOrder>(&self) -> Vec<u8> {
vec![]
}
}
#[derive(Debug)]
pub struct OptionComment {
comment: String,
}
impl OptionComment {
pub fn new(comment: &str) -> Self {
Self {
comment: comment.to_string(),
}
}
pub fn new_option(comment: &str) -> BlockOption {
BlockOption::OptComment(Self::new(comment))
}
fn length(&self) -> u16 {
self.comment.len().try_into().unwrap()
}
fn bytes<B: ByteOrder>(&self) -> Vec<u8> {
self.comment.as_bytes().to_vec()
}
}
#[derive(Debug)]
pub struct OptionIfName {
if_name: String,
}
impl OptionIfName {
pub fn new(name: &str) -> Self {
Self {
if_name: name.to_string(),
}
}
pub fn new_option(name: &str) -> BlockOption {
BlockOption::IfName(Self::new(name))
}
fn length(&self) -> u16 {
self.if_name.len().try_into().unwrap()
}
fn bytes<B: ByteOrder>(&self) -> Vec<u8> {
self.if_name.as_bytes().to_vec()
}
}
#[derive(Debug)]
pub struct OptionIfDescription {
if_description: String,
}
impl OptionIfDescription {
pub fn new(description: &str) -> Self {
Self {
if_description: description.to_string(),
}
}
pub fn new_option(description: &str) -> BlockOption {
BlockOption::IfDescription(Self::new(description))
}
fn length(&self) -> u16 {
self.if_description.len().try_into().unwrap()
}
fn bytes<B: ByteOrder>(&self) -> Vec<u8> {
self.if_description.as_bytes().to_vec()
}
}
#[derive(Debug)]
pub struct OptionIfIpv4Addr {
ip: Ipv4Addr,
netmask: Ipv4Addr,
}
impl OptionIfIpv4Addr {
pub fn new(ip: &str, netmask: &str) -> Self {
Self {
ip: ip.parse().unwrap(),
netmask: netmask.parse().unwrap(),
}
}
pub fn new_option(ip: &str, netmask: &str) -> BlockOption {
BlockOption::IfIpv4Addr(Self::new(ip, netmask))
}
fn length(&self) -> u16 {
4 + 4
}
fn bytes<B: ByteOrder>(&self) -> Vec<u8> {
let mut buf = self.ip.octets().to_vec();
buf.extend(&self.netmask.octets());
buf
}
}
#[derive(Debug)]
pub struct OptionIfIpv6Addr {
ip: Ipv6Addr,
prefix_len: u8,
}
impl OptionIfIpv6Addr {
pub fn new(ip: &str, prefix_len: u8) -> Self {
Self {
ip: ip.parse().unwrap(),
prefix_len,
}
}
pub fn new_option(ip: &str, prefix_len: u8) -> BlockOption {
BlockOption::IfIpv6Addr(Self::new(ip, prefix_len))
}
fn length(&self) -> u16 {
16 + 1
}
fn bytes<B: ByteOrder>(&self) -> Vec<u8> {
let mut buf = self.ip.octets().to_vec();
buf.push(self.prefix_len);
buf
}
}
#[derive(Debug)]
pub struct OptionIfMacAddr {
mac_addr: [u8; 6],
}
impl OptionIfMacAddr {
pub fn new(mac_addr: &str) -> Self {
let split = mac_addr
.split('.')
.map(|x| x.parse().unwrap())
.collect::<Vec<u8>>();
Self {
mac_addr: split.try_into().unwrap(),
}
}
pub fn new_option(mac_addr: &str) -> BlockOption {
BlockOption::IfMacAddr(Self::new(mac_addr))
}
fn length(&self) -> u16 {
6
}
fn bytes<B: ByteOrder>(&self) -> Vec<u8> {
self.mac_addr.to_vec()
}
}
#[derive(Debug)]
pub struct OptionIfTsResol {
tsresol: u8,
}
impl OptionIfTsResol {
pub fn new(tsresol: u8) -> Self {
Self { tsresol }
}
pub fn new_option(tsresol: &TimestampResolution) -> BlockOption {
BlockOption::IfTsResol(Self::new(tsresol.to_tsresol()))
}
fn length(&self) -> u16 {
1
}
fn bytes<B: ByteOrder>(&self) -> Vec<u8> {
[self.tsresol].to_vec()
}
}
#[derive(Debug)]
pub struct OptionEpbFlags {
flags: u32,
}
impl OptionEpbFlags {
pub fn new(
dir: PacketDirection,
reception: ReceptionType,
fcs_length: Option<u8>,
error_flags: u16,
) -> Self {
let dir_bits = dir.value() & 0b11;
let rec_bits = reception.value() & 0b111;
let fcs_bits = fcs_length.map_or(0, |x| x & 0b1111);
let flags: u32 = dir_bits as u32
| ((rec_bits as u32) << 2)
| ((fcs_bits as u32) << 5)
| ((error_flags as u32) << 16);
Self { flags }
}
pub fn new_option(
dir: PacketDirection,
reception: ReceptionType,
fcs_length: Option<u8>,
error_flags: u16,
) -> BlockOption {
BlockOption::EpbFlags(Self::new(dir, reception, fcs_length, error_flags))
}
pub fn from_u32(flags: u32) -> Self {
Self { flags }
}
fn length(&self) -> u16 {
4
}
fn bytes<B: ByteOrder>(&self) -> Vec<u8> {
let mut buf: Vec<u8> = vec![];
buf.write_u32::<B>(self.flags).unwrap();
buf
}
}
#[cfg(test)]
mod tests {
use super::*;
use byteorder::{BigEndian, LittleEndian};
#[test]
fn option_encode() {
let data = vec![9u8; 10];
let raw = BlockOption::Raw(RawOption::new(2, data.len() as u16, data));
let mut buf = vec![];
raw.encode::<LittleEndian>(&mut buf).unwrap();
assert_eq!(buf.len(), 16);
assert_eq!(&buf[14..], &[0, 0]);
}
#[test]
fn padding() {
for i in 9..=12 {
let data = vec![9u8; i];
let raw = BlockOption::Raw(RawOption::new(2, data.len() as u16, data));
let mut buf = vec![];
raw.encode::<LittleEndian>(&mut buf).unwrap();
assert_eq!(buf.len(), 16);
assert_eq!(raw.padding().len(), 12 - i);
}
}
#[test]
fn opt_comment() {
let opt = BlockOption::OptComment(OptionComment::new("Hello World!!"));
let mut buf = vec![];
opt.encode::<BigEndian>(&mut buf).unwrap();
assert_eq!(
buf,
[0, 1, 0, 13, 72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33, 33, 0, 0, 0]
);
let opt = BlockOption::OptComment(OptionComment::new("Hello World!!"));
let mut buf = vec![];
opt.encode::<LittleEndian>(&mut buf).unwrap();
assert_eq!(
buf,
[1, 0, 13, 0, 72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100, 33, 33, 0, 0, 0]
);
}
}