Implement ARP representation parsing and emission.
This commit is contained in:
parent
adff3c0069
commit
d966c1870b
92
src/arp.rs
92
src/arp.rs
|
@ -209,6 +209,69 @@ impl<T: AsRef<[u8]> + AsMut<[u8]>> Packet<T> {
|
|||
}
|
||||
}
|
||||
|
||||
/// A high-level representation of an Address Resolution Protocol packet.
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
pub enum Repr {
|
||||
/// An Ethernet and IPv4 Address Resolution Protocol packet.
|
||||
EthernetIpv4 {
|
||||
operation: Operation,
|
||||
source_hardware_addr: ::EthernetAddress,
|
||||
source_protocol_addr: ::Ipv4Address,
|
||||
target_hardware_addr: ::EthernetAddress,
|
||||
target_protocol_addr: ::Ipv4Address
|
||||
},
|
||||
#[doc(hidden)]
|
||||
__Nonexhaustive
|
||||
}
|
||||
|
||||
impl Repr {
|
||||
/// Parse an Address Resolution Packet and return a high-level representation,
|
||||
/// or return `Err(())` if the packet is not recognized.
|
||||
pub fn parse<T: AsRef<[u8]>>(packet: &Packet<T>) -> Result<Repr, ()> {
|
||||
match (packet.hardware_type(), packet.protocol_type(),
|
||||
packet.hardware_length(), packet.protocol_length()) {
|
||||
(HardwareType::Ethernet, ProtocolType::Ipv4, 6, 4) => {
|
||||
Ok(Repr::EthernetIpv4 {
|
||||
operation: packet.operation(),
|
||||
source_hardware_addr:
|
||||
::EthernetAddress::from_bytes(packet.source_hardware_addr()),
|
||||
source_protocol_addr:
|
||||
::Ipv4Address::from_bytes(packet.source_protocol_addr()),
|
||||
target_hardware_addr:
|
||||
::EthernetAddress::from_bytes(packet.target_hardware_addr()),
|
||||
target_protocol_addr:
|
||||
::Ipv4Address::from_bytes(packet.target_protocol_addr())
|
||||
})
|
||||
},
|
||||
_ => Err(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Emit a high-level representation into an Address Resolution Packet.
|
||||
pub fn emit<T: AsRef<[u8]> + AsMut<[u8]>>(&self, packet: &mut Packet<T>) {
|
||||
match self {
|
||||
&Repr::EthernetIpv4 {
|
||||
operation,
|
||||
source_hardware_addr,
|
||||
source_protocol_addr,
|
||||
target_hardware_addr,
|
||||
target_protocol_addr
|
||||
} => {
|
||||
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);
|
||||
packet.set_source_hardware_addr(source_hardware_addr.as_bytes());
|
||||
packet.set_source_protocol_addr(source_protocol_addr.as_bytes());
|
||||
packet.set_target_hardware_addr(target_hardware_addr.as_bytes());
|
||||
packet.set_target_protocol_addr(target_protocol_addr.as_bytes());
|
||||
},
|
||||
&Repr::__Nonexhaustive => unreachable!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
@ -253,4 +316,33 @@ mod test {
|
|||
packet.set_target_protocol_addr(&[0x41, 0x42, 0x43, 0x44]);
|
||||
assert_eq!(&packet.into_inner()[..], &PACKET_BYTES[..]);
|
||||
}
|
||||
|
||||
fn packet_repr() -> Repr {
|
||||
Repr::EthernetIpv4 {
|
||||
operation: Operation::Request,
|
||||
source_hardware_addr:
|
||||
::EthernetAddress::from_bytes(&[0x11, 0x12, 0x13, 0x14, 0x15, 0x16]),
|
||||
source_protocol_addr:
|
||||
::Ipv4Address::from_bytes(&[0x21, 0x22, 0x23, 0x24]),
|
||||
target_hardware_addr:
|
||||
::EthernetAddress::from_bytes(&[0x31, 0x32, 0x33, 0x34, 0x35, 0x36]),
|
||||
target_protocol_addr:
|
||||
::Ipv4Address::from_bytes(&[0x41, 0x42, 0x43, 0x44])
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse() {
|
||||
let packet = Packet::new(&PACKET_BYTES[..]).unwrap();
|
||||
let repr = Repr::parse(&packet).unwrap();
|
||||
assert_eq!(repr, packet_repr());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_emit() {
|
||||
let mut bytes = vec![0; 28];
|
||||
let mut packet = Packet::new(&mut bytes).unwrap();
|
||||
packet_repr().emit(&mut packet);
|
||||
assert_eq!(&packet.into_inner()[..], &PACKET_BYTES[..]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
use core::fmt;
|
||||
|
||||
/// A four-octet IPv4 address.
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
|
||||
pub struct Address(pub [u8; 4]);
|
||||
|
||||
impl Address {
|
||||
/// Construct an IPv4 address from a sequence of octets, in big-endian.
|
||||
///
|
||||
/// # Panics
|
||||
/// The function panics if `data` is not four octets long.
|
||||
pub fn from_bytes(data: &[u8]) -> Address {
|
||||
let mut bytes = [0; 4];
|
||||
bytes.copy_from_slice(data);
|
||||
Address(bytes)
|
||||
}
|
||||
|
||||
/// Return an IPv4 address as a sequence of octets, in big-endian.
|
||||
pub fn as_bytes(&self) -> &[u8] {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Address {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let bytes = self.0;
|
||||
write!(f, "{:02x}.{:02x}.{:02x}.{:02x}",
|
||||
bytes[0], bytes[1], bytes[2], bytes[3])
|
||||
}
|
||||
}
|
|
@ -44,6 +44,7 @@ mod field {
|
|||
|
||||
mod ethernet;
|
||||
mod arp;
|
||||
mod ipv4;
|
||||
|
||||
pub use ethernet::ProtocolType as EthernetProtocolType;
|
||||
pub use ethernet::Address as EthernetAddress;
|
||||
|
@ -53,3 +54,6 @@ pub use arp::HardwareType as ArpHardwareType;
|
|||
pub use arp::ProtocolType as ArpProtocolType;
|
||||
pub use arp::Operation as ArpOperation;
|
||||
pub use arp::Packet as ArpPacket;
|
||||
pub use arp::Repr as ArpRepr;
|
||||
|
||||
pub use ipv4::Address as Ipv4Address;
|
||||
|
|
Loading…
Reference in New Issue