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)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -253,4 +316,33 @@ mod test {
|
||||||
packet.set_target_protocol_addr(&[0x41, 0x42, 0x43, 0x44]);
|
packet.set_target_protocol_addr(&[0x41, 0x42, 0x43, 0x44]);
|
||||||
assert_eq!(&packet.into_inner()[..], &PACKET_BYTES[..]);
|
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 ethernet;
|
||||||
mod arp;
|
mod arp;
|
||||||
|
mod ipv4;
|
||||||
|
|
||||||
pub use ethernet::ProtocolType as EthernetProtocolType;
|
pub use ethernet::ProtocolType as EthernetProtocolType;
|
||||||
pub use ethernet::Address as EthernetAddress;
|
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::ProtocolType as ArpProtocolType;
|
||||||
pub use arp::Operation as ArpOperation;
|
pub use arp::Operation as ArpOperation;
|
||||||
pub use arp::Packet as ArpPacket;
|
pub use arp::Packet as ArpPacket;
|
||||||
|
pub use arp::Repr as ArpRepr;
|
||||||
|
|
||||||
|
pub use ipv4::Address as Ipv4Address;
|
||||||
|
|
Loading…
Reference in New Issue