use crate::net::MacAddr;
use crate::packets::types::u16be;
use crate::packets::{EtherTypes, Ethernet, Internal, Packet};
use crate::{ensure, SizeOf};
use anyhow::{anyhow, Result};
use std::fmt;
use std::net::Ipv4Addr;
use std::ptr::NonNull;
pub struct Arp<H: HardwareAddr, P: ProtocolAddr> {
envelope: Ethernet,
header: NonNull<ArpHeader<H, P>>,
offset: usize,
}
impl<H: HardwareAddr, P: ProtocolAddr> Arp<H, P> {
#[inline]
fn header(&self) -> &ArpHeader<H, P> {
unsafe { self.header.as_ref() }
}
#[inline]
fn header_mut(&mut self) -> &mut ArpHeader<H, P> {
unsafe { self.header.as_mut() }
}
#[inline]
pub fn hardware_type(&self) -> HardwareType {
HardwareType::new(self.header().hardware_type.into())
}
#[inline]
fn set_hardware_type(&mut self, hardware_type: HardwareType) {
self.header_mut().hardware_type = hardware_type.0.into()
}
#[inline]
pub fn protocol_type(&self) -> ProtocolType {
ProtocolType::new(self.header().protocol_type.into())
}
#[inline]
fn set_protocol_type(&mut self, protocol_type: ProtocolType) {
self.header_mut().protocol_type = protocol_type.0.into()
}
#[inline]
pub fn hardware_addr_len(&self) -> u8 {
self.header().hardware_addr_len
}
#[inline]
fn set_hardware_addr_len(&mut self, len: u8) {
self.header_mut().hardware_addr_len = len
}
#[inline]
pub fn protocol_addr_len(&self) -> u8 {
self.header().protocol_addr_len
}
#[inline]
fn set_protocol_addr_len(&mut self, len: u8) {
self.header_mut().protocol_addr_len = len
}
#[inline]
pub fn operation_code(&self) -> OperationCode {
OperationCode::new(self.header().operation_code.into())
}
#[inline]
pub fn set_operation_code(&mut self, code: OperationCode) {
self.header_mut().operation_code = code.0.into()
}
#[inline]
pub fn sender_hardware_addr(&self) -> H {
self.header().sender_hardware_addr
}
#[inline]
pub fn set_sender_hardware_addr(&mut self, addr: H) {
self.header_mut().sender_hardware_addr = addr
}
#[inline]
pub fn sender_protocol_addr(&self) -> P {
self.header().sender_protocol_addr
}
#[inline]
pub fn set_sender_protocol_addr(&mut self, addr: P) {
self.header_mut().sender_protocol_addr = addr
}
#[inline]
pub fn target_hardware_addr(&self) -> H {
self.header().target_hardware_addr
}
#[inline]
pub fn set_target_hardware_addr(&mut self, addr: H) {
self.header_mut().target_hardware_addr = addr
}
#[inline]
pub fn target_protocol_addr(&self) -> P {
self.header().target_protocol_addr
}
#[inline]
pub fn set_target_protocol_addr(&mut self, addr: P) {
self.header_mut().target_protocol_addr = addr
}
}
impl<H: HardwareAddr, P: ProtocolAddr> fmt::Debug for Arp<H, P> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("arp")
.field("hardware_type", &format!("{}", self.hardware_type()))
.field("protocol_type", &format!("{}", self.protocol_type()))
.field("hardware_addr_len", &self.hardware_addr_len())
.field("protocol_addr_len", &self.protocol_addr_len())
.field("operation_code", &format!("{}", self.operation_code()))
.field(
"sender_hardware_addr",
&format!("{}", self.sender_hardware_addr()),
)
.field(
"sender_protocol_addr",
&format!("{}", self.sender_protocol_addr()),
)
.field(
"target_hardware_addr",
&format!("{}", self.target_hardware_addr()),
)
.field(
"target_protocol_addr",
&format!("{}", self.target_protocol_addr()),
)
.field("$offset", &self.offset())
.field("$len", &self.len())
.field("$header_len", &self.header_len())
.finish()
}
}
impl<H: HardwareAddr, P: ProtocolAddr> Packet for Arp<H, P> {
type Envelope = Ethernet;
#[inline]
fn envelope(&self) -> &Self::Envelope {
&self.envelope
}
#[inline]
fn envelope_mut(&mut self) -> &mut Self::Envelope {
&mut self.envelope
}
#[inline]
fn offset(&self) -> usize {
self.offset
}
#[inline]
fn header_len(&self) -> usize {
ArpHeader::<H, P>::size_of()
}
#[inline]
unsafe fn clone(&self, internal: Internal) -> Self {
Arp {
envelope: self.envelope.clone(internal),
header: self.header,
offset: self.offset,
}
}
#[inline]
fn try_parse(envelope: Self::Envelope, _internal: Internal) -> Result<Self> {
ensure!(
envelope.ether_type() == EtherTypes::Arp,
anyhow!("not an ARP packet.")
);
let mbuf = envelope.mbuf();
let offset = envelope.payload_offset();
let header = mbuf.read_data(offset)?;
let packet = Arp {
envelope,
header,
offset,
};
ensure!(
packet.hardware_type() == H::addr_type(),
anyhow!(
"hardware type {} does not match expected {}.",
packet.hardware_type(),
H::addr_type()
)
);
ensure!(
packet.protocol_type() == P::addr_type(),
anyhow!(
"protocol type {} does not match expected {}.",
packet.protocol_type(),
P::addr_type()
)
);
ensure!(
packet.hardware_addr_len() == H::size_of() as u8,
anyhow!(
"hardware address length {} does not match expected {}.",
packet.hardware_addr_len(),
H::size_of()
)
);
ensure!(
packet.protocol_addr_len() == P::size_of() as u8,
anyhow!(
"protocol address length {} does not match expected {}.",
packet.protocol_addr_len(),
P::size_of()
)
);
Ok(packet)
}
#[inline]
fn try_push(mut envelope: Self::Envelope, _internal: Internal) -> Result<Self> {
let offset = envelope.payload_offset();
let mbuf = envelope.mbuf_mut();
mbuf.extend(offset, ArpHeader::<H, P>::size_of())?;
let header = mbuf.write_data(offset, &ArpHeader::<H, P>::default())?;
envelope.set_ether_type(EtherTypes::Arp);
let mut packet = Arp {
envelope,
header,
offset,
};
packet.set_hardware_type(H::addr_type());
packet.set_protocol_type(P::addr_type());
packet.set_hardware_addr_len(H::size_of() as u8);
packet.set_protocol_addr_len(P::size_of() as u8);
Ok(packet)
}
#[inline]
fn deparse(self) -> Self::Envelope {
self.envelope
}
}
#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
#[repr(C, packed)]
pub struct HardwareType(u16);
impl HardwareType {
pub fn new(value: u16) -> Self {
HardwareType(value)
}
}
#[allow(non_snake_case)]
#[allow(non_upper_case_globals)]
pub mod HardwareTypes {
use super::HardwareType;
pub const Ethernet: HardwareType = HardwareType(0x0001);
}
impl fmt::Display for HardwareType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{}",
match *self {
HardwareTypes::Ethernet => "Ethernet".to_string(),
_ => {
let t = self.0;
format!("0x{:04x}", t)
}
}
)
}
}
#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
#[repr(C, packed)]
pub struct ProtocolType(u16);
impl ProtocolType {
pub fn new(value: u16) -> Self {
ProtocolType(value)
}
}
#[allow(non_snake_case)]
#[allow(non_upper_case_globals)]
pub mod ProtocolTypes {
use super::ProtocolType;
pub const Ipv4: ProtocolType = ProtocolType(0x0800);
}
impl fmt::Display for ProtocolType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{}",
match *self {
ProtocolTypes::Ipv4 => "IPv4".to_string(),
_ => {
let t = self.0;
format!("0x{:04x}", t)
}
}
)
}
}
#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
#[repr(C, packed)]
pub struct OperationCode(u16);
impl OperationCode {
pub fn new(value: u16) -> Self {
OperationCode(value)
}
}
#[allow(non_snake_case)]
#[allow(non_upper_case_globals)]
pub mod OperationCodes {
use super::OperationCode;
pub const Request: OperationCode = OperationCode(1);
pub const Reply: OperationCode = OperationCode(2);
pub const RequestReverse: OperationCode = OperationCode(3);
pub const ReplyReverse: OperationCode = OperationCode(4);
}
impl fmt::Display for OperationCode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{}",
match *self {
OperationCodes::Request => "Request".to_string(),
OperationCodes::Reply => "Reply".to_string(),
OperationCodes::RequestReverse => "Request reverse".to_string(),
OperationCodes::ReplyReverse => "Reply reverse".to_string(),
_ => {
let t = self.0;
format!("0x{:04x}", t)
}
}
)
}
}
pub trait HardwareAddr: SizeOf + Copy + fmt::Display {
fn addr_type() -> HardwareType;
fn default() -> Self;
}
impl SizeOf for MacAddr {
fn size_of() -> usize {
6
}
}
impl HardwareAddr for MacAddr {
fn addr_type() -> HardwareType {
HardwareTypes::Ethernet
}
fn default() -> Self {
Default::default()
}
}
pub trait ProtocolAddr: SizeOf + Copy + fmt::Display {
fn addr_type() -> ProtocolType;
fn default() -> Self;
}
impl SizeOf for Ipv4Addr {
fn size_of() -> usize {
4
}
}
impl ProtocolAddr for Ipv4Addr {
fn addr_type() -> ProtocolType {
ProtocolTypes::Ipv4
}
fn default() -> Self {
Ipv4Addr::UNSPECIFIED
}
}
pub type Arp4 = Arp<MacAddr, Ipv4Addr>;
#[allow(missing_debug_implementations)]
#[derive(Copy, SizeOf)]
#[repr(C, packed)]
struct ArpHeader<H: HardwareAddr, P: ProtocolAddr> {
hardware_type: u16be,
protocol_type: u16be,
hardware_addr_len: u8,
protocol_addr_len: u8,
operation_code: u16be,
sender_hardware_addr: H,
sender_protocol_addr: P,
target_hardware_addr: H,
target_protocol_addr: P,
}
impl<H: HardwareAddr, P: ProtocolAddr> Clone for ArpHeader<H, P> {
fn clone(&self) -> Self {
ArpHeader {
hardware_type: self.hardware_type,
protocol_type: self.protocol_type,
hardware_addr_len: self.hardware_addr_len,
protocol_addr_len: self.protocol_addr_len,
operation_code: self.operation_code,
sender_hardware_addr: self.sender_hardware_addr,
sender_protocol_addr: self.sender_protocol_addr,
target_hardware_addr: self.target_hardware_addr,
target_protocol_addr: self.target_protocol_addr,
}
}
}
impl<H: HardwareAddr, P: ProtocolAddr> Default for ArpHeader<H, P> {
fn default() -> Self {
ArpHeader {
hardware_type: u16be::default(),
protocol_type: u16be::default(),
hardware_addr_len: 0,
protocol_addr_len: 0,
operation_code: u16be::default(),
sender_hardware_addr: H::default(),
sender_protocol_addr: P::default(),
target_hardware_addr: H::default(),
target_protocol_addr: P::default(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::testils::byte_arrays::ARP4_PACKET;
use crate::Mbuf;
#[test]
fn size_of_arp_header() {
assert_eq!(28, ArpHeader::<MacAddr, Ipv4Addr>::size_of());
}
#[capsule::test]
fn parse_arp_packet() {
let packet = Mbuf::from_bytes(&ARP4_PACKET).unwrap();
let ethernet = packet.parse::<Ethernet>().unwrap();
let arp4 = ethernet.parse::<Arp4>().unwrap();
assert_eq!(HardwareTypes::Ethernet, arp4.hardware_type());
assert_eq!(ProtocolTypes::Ipv4, arp4.protocol_type());
assert_eq!(6, arp4.hardware_addr_len());
assert_eq!(4, arp4.protocol_addr_len());
assert_eq!(OperationCodes::Request, arp4.operation_code());
assert_eq!("00:00:00:00:00:01", arp4.sender_hardware_addr().to_string());
assert_eq!("139.133.217.110", arp4.sender_protocol_addr().to_string());
assert_eq!("00:00:00:00:00:00", arp4.target_hardware_addr().to_string());
assert_eq!("139.133.233.2", arp4.target_protocol_addr().to_string());
}
#[capsule::test]
fn push_arp_packet() {
let packet = Mbuf::new().unwrap();
let ethernet = packet.push::<Ethernet>().unwrap();
let mut arp4 = ethernet.push::<Arp4>().unwrap();
assert_eq!(ArpHeader::<MacAddr, Ipv4Addr>::size_of(), arp4.len());
assert_eq!(HardwareTypes::Ethernet, arp4.hardware_type());
assert_eq!(ProtocolTypes::Ipv4, arp4.protocol_type());
assert_eq!(6, arp4.hardware_addr_len());
assert_eq!(4, arp4.protocol_addr_len());
arp4.set_operation_code(OperationCodes::Reply);
assert_eq!(OperationCodes::Reply, arp4.operation_code());
arp4.set_sender_hardware_addr(MacAddr::new(0, 0, 0, 0, 0, 1));
assert_eq!("00:00:00:00:00:01", arp4.sender_hardware_addr().to_string());
arp4.set_sender_protocol_addr(Ipv4Addr::new(10, 0, 0, 1));
assert_eq!("10.0.0.1", arp4.sender_protocol_addr().to_string());
arp4.set_target_hardware_addr(MacAddr::new(0, 0, 0, 0, 0, 2));
assert_eq!("00:00:00:00:00:02", arp4.target_hardware_addr().to_string());
arp4.set_target_protocol_addr(Ipv4Addr::new(10, 0, 0, 2));
assert_eq!("10.0.0.2", arp4.target_protocol_addr().to_string());
assert_eq!(EtherTypes::Arp, arp4.envelope().ether_type());
}
}