Imlpement ARP packet support.
This commit is contained in:
parent
c638f45373
commit
adff3c0069
|
@ -21,7 +21,7 @@ The only supported medium is Ethernet.
|
|||
* 802.1Q is not supported.
|
||||
* Jumbo frames are not supported.
|
||||
* CRC calculation is not supported.
|
||||
* ARP packets are not supported.
|
||||
* ARP packets are supported.
|
||||
* ARP probes or announcements are not supported.
|
||||
|
||||
### IP layer
|
||||
|
|
|
@ -0,0 +1,256 @@
|
|||
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: AsRef<[u8]>>(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<T: AsRef<[u8]>> Packet<T> {
|
||||
/// 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<Packet<T>, ()> {
|
||||
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<T: AsRef<[u8]> + AsMut<[u8]>> Packet<T> {
|
||||
/// 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[..]);
|
||||
}
|
||||
}
|
|
@ -43,7 +43,13 @@ mod field {
|
|||
}
|
||||
|
||||
mod ethernet;
|
||||
mod arp;
|
||||
|
||||
pub use ethernet::ProtocolType as EthernetProtocolType;
|
||||
pub use ethernet::Address as EthernetAddress;
|
||||
pub use ethernet::Frame as EthernetFrame;
|
||||
|
||||
pub use arp::HardwareType as ArpHardwareType;
|
||||
pub use arp::ProtocolType as ArpProtocolType;
|
||||
pub use arp::Operation as ArpOperation;
|
||||
pub use arp::Packet as ArpPacket;
|
||||
|
|
Loading…
Reference in New Issue