use byteorder::{ByteOrder, NetworkEndian}; pub use ::ethernet::ProtocolType as ProtocolType; enum_with_unknown! { /// ARP network protocol type. pub enum HardwareType(u16) { Ethernet = 1 } } enum_with_unknown! { /// ARP operation type. pub enum Operation(u16) { Request = 1, Reply = 2 } } /// A read/write wrapper around an Address Resolution Protocol packet. #[derive(Debug)] pub struct Packet>(T); mod field { #![allow(non_snake_case)] use ::field::*; pub const HTYPE: Field = 0..2; pub const PTYPE: Field = 2..4; pub const HLEN: usize = 4; pub const PLEN: usize = 5; pub const OPER: Field = 6..8; #[inline(always)] pub fn SHA(hardware_length: u8, _protocol_length: u8) -> Field { let start = OPER.end; start..(start + hardware_length as usize) } #[inline(always)] pub fn SPA(hardware_length: u8, protocol_length: u8) -> Field { let start = SHA(hardware_length, protocol_length).end; start..(start + protocol_length as usize) } #[inline(always)] pub fn THA(hardware_length: u8, protocol_length: u8) -> Field { let start = SPA(hardware_length, protocol_length).end; start..(start + hardware_length as usize) } #[inline(always)] pub fn TPA(hardware_length: u8, protocol_length: u8) -> Field { let start = THA(hardware_length, protocol_length).end; start..(start + protocol_length as usize) } } impl> Packet { /// Wrap a buffer with an ARP packet. Returns an error if the buffer /// is too small to contain one. pub fn new(storage: T) -> Result, ()> { let len = storage.as_ref().len(); if len < field::OPER.end { Err(()) } else { let packet = Packet(storage); if len < field::TPA(packet.hardware_length(), packet.protocol_length()).end { Err(()) } else { Ok(packet) } } } /// Consumes the packet, returning the underlying buffer. pub fn into_inner(self) -> T { self.0 } /// Return the hardware type field. pub fn hardware_type(&self) -> HardwareType { let bytes = self.0.as_ref(); let raw = NetworkEndian::read_u16(&bytes[field::HTYPE]); HardwareType::from(raw) } /// Return the protocol type field. pub fn protocol_type(&self) -> ProtocolType { let bytes = self.0.as_ref(); let raw = NetworkEndian::read_u16(&bytes[field::PTYPE]); ProtocolType::from(raw) } /// Return the hardware length field. pub fn hardware_length(&self) -> u8 { let bytes = self.0.as_ref(); bytes[field::HLEN] } /// Return the protocol length field. pub fn protocol_length(&self) -> u8 { let bytes = self.0.as_ref(); bytes[field::PLEN] } /// Return the operation field. pub fn operation(&self) -> Operation { let bytes = self.0.as_ref(); let raw = NetworkEndian::read_u16(&bytes[field::OPER]); Operation::from(raw) } /// Return the source hardware address field. pub fn source_hardware_addr(&self) -> &[u8] { let bytes = self.0.as_ref(); &bytes[field::SHA(self.hardware_length(), self.protocol_length())] } /// Return the source protocol address field. pub fn source_protocol_addr(&self) -> &[u8] { let bytes = self.0.as_ref(); &bytes[field::SPA(self.hardware_length(), self.protocol_length())] } /// Return the target hardware address field. pub fn target_hardware_addr(&self) -> &[u8] { let bytes = self.0.as_ref(); &bytes[field::THA(self.hardware_length(), self.protocol_length())] } /// Return the target protocol address field. pub fn target_protocol_addr(&self) -> &[u8] { let bytes = self.0.as_ref(); &bytes[field::TPA(self.hardware_length(), self.protocol_length())] } } impl + AsMut<[u8]>> Packet { /// Set the hardware type field. pub fn set_hardware_type(&mut self, value: HardwareType) { let bytes = self.0.as_mut(); NetworkEndian::write_u16(&mut bytes[field::HTYPE], value.into()) } /// Set the protocol type field. pub fn set_protocol_type(&mut self, value: ProtocolType) { let bytes = self.0.as_mut(); NetworkEndian::write_u16(&mut bytes[field::PTYPE], value.into()) } /// Set the hardware length field. pub fn set_hardware_length(&mut self, value: u8) { let bytes = self.0.as_mut(); bytes[field::HLEN] = value } /// Set the protocol length field. pub fn set_protocol_length(&mut self, value: u8) { let bytes = self.0.as_mut(); bytes[field::PLEN] = value } /// Set the operation field. pub fn set_operation(&mut self, value: Operation) { let bytes = self.0.as_mut(); NetworkEndian::write_u16(&mut bytes[field::OPER], value.into()) } /// Set the source hardware address field. /// /// # Panics /// The function panics if `value` is not `self.hardware_length()` long. pub fn set_source_hardware_addr(&mut self, value: &[u8]) { let (hardware_length, protocol_length) = (self.hardware_length(), self.protocol_length()); let bytes = self.0.as_mut(); bytes[field::SHA(hardware_length, protocol_length)].copy_from_slice(value) } /// Set the source protocol address field. /// /// # Panics /// The function panics if `value` is not `self.protocol_length()` long. pub fn set_source_protocol_addr(&mut self, value: &[u8]) { let (hardware_length, protocol_length) = (self.hardware_length(), self.protocol_length()); let bytes = self.0.as_mut(); bytes[field::SPA(hardware_length, protocol_length)].copy_from_slice(value) } /// Set the target hardware address field. /// /// # Panics /// The function panics if `value` is not `self.hardware_length()` long. pub fn set_target_hardware_addr(&mut self, value: &[u8]) { let (hardware_length, protocol_length) = (self.hardware_length(), self.protocol_length()); let bytes = self.0.as_mut(); bytes[field::THA(hardware_length, protocol_length)].copy_from_slice(value) } /// Set the target protocol address field. /// /// # Panics /// The function panics if `value` is not `self.protocol_length()` long. pub fn set_target_protocol_addr(&mut self, value: &[u8]) { let (hardware_length, protocol_length) = (self.hardware_length(), self.protocol_length()); let bytes = self.0.as_mut(); bytes[field::TPA(hardware_length, protocol_length)].copy_from_slice(value) } } #[cfg(test)] mod test { use super::*; static PACKET_BYTES: [u8; 28] = [0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x01, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x21, 0x22, 0x23, 0x24, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x41, 0x42, 0x43, 0x44]; #[test] fn test_deconstruct() { let packet = Packet::new(&PACKET_BYTES[..]).unwrap(); assert_eq!(packet.hardware_type(), HardwareType::Ethernet); assert_eq!(packet.protocol_type(), ProtocolType::Ipv4); assert_eq!(packet.hardware_length(), 6); assert_eq!(packet.protocol_length(), 4); assert_eq!(packet.operation(), Operation::Request); assert_eq!(packet.source_hardware_addr(), &[0x11, 0x12, 0x13, 0x14, 0x15, 0x16]); assert_eq!(packet.source_protocol_addr(), &[0x21, 0x22, 0x23, 0x24]); assert_eq!(packet.target_hardware_addr(), &[0x31, 0x32, 0x33, 0x34, 0x35, 0x36]); assert_eq!(packet.target_protocol_addr(), &[0x41, 0x42, 0x43, 0x44]); } #[test] fn test_construct() { let mut bytes = vec![0; 28]; let mut packet = Packet::new(&mut bytes).unwrap(); packet.set_hardware_type(HardwareType::Ethernet); packet.set_protocol_type(ProtocolType::Ipv4); packet.set_hardware_length(6); packet.set_protocol_length(4); packet.set_operation(Operation::Request); packet.set_source_hardware_addr(&[0x11, 0x12, 0x13, 0x14, 0x15, 0x16]); packet.set_source_protocol_addr(&[0x21, 0x22, 0x23, 0x24]); packet.set_target_hardware_addr(&[0x31, 0x32, 0x33, 0x34, 0x35, 0x36]); packet.set_target_protocol_addr(&[0x41, 0x42, 0x43, 0x44]); assert_eq!(&packet.into_inner()[..], &PACKET_BYTES[..]); } }