feat: added the ability to respond to ARP requests

This commit is contained in:
Andrew Rioux
2023-09-26 01:57:10 -04:00
parent 0bda72491c
commit 0bb2871568
4 changed files with 219 additions and 45 deletions

View File

@@ -58,6 +58,17 @@ impl<'a> EthernetPkt<'a> {
Ok(Layer3Pkt::IPv4Pkt(pkt))
}
0x0806 => {
if self.data.len() < 42 {
return Err(error::Error::PacketLengthInvalid);
}
let pkt = ARPPkt {
data: &self.data[14..],
};
Ok(Layer3Pkt::ARP(pkt))
}
p => Err(error::Error::UnknownPacketType(p)),
}
}
@@ -71,6 +82,7 @@ impl<'a> EthernetPkt<'a> {
pub enum Layer3Pkt<'a> {
IPv4Pkt(IPv4Pkt<'a>),
ARP(ARPPkt<'a>),
}
pub struct IPv4Pkt<'a> {
@@ -160,6 +172,51 @@ impl<'a> IPv4Pkt<'a> {
}
}
pub struct ARPPkt<'a> {
data: &'a [u8],
}
impl<'a> ARPPkt<'a> {
pub fn htype(&self) -> u16 {
u16::from_be_bytes(self.data[0..2].try_into().unwrap())
}
pub fn ptype(&self) -> u16 {
u16::from_be_bytes(self.data[2..4].try_into().unwrap())
}
pub fn hwlen(&self) -> u8 {
self.data[4]
}
pub fn plen(&self) -> u8 {
self.data[5]
}
pub fn opcode(&self) -> u16 {
u16::from_be_bytes(self.data[6..8].try_into().unwrap())
}
pub fn srchwaddr(&self) -> &[u8] {
&self.data[8usize..8usize + self.hwlen() as usize]
}
pub fn srcprotoaddr(&self) -> &[u8] {
let start = self.hwlen() as usize + 8;
&self.data[start..start + self.plen() as usize]
}
pub fn targethwaddr(&self) -> &[u8] {
let start = self.hwlen() as usize + self.plen() as usize + 8;
&self.data[start..start + self.hwlen() as usize]
}
pub fn targetprotoaddr(&self) -> &[u8] {
let start = self.hwlen() as usize + self.plen() as usize + self.hwlen() as usize + 8;
&self.data[start..start + self.plen() as usize]
}
}
pub enum Layer4Pkt<'a> {
UDP(UDPPkt<'a>),
TCP(TCPPkt<'a>),
@@ -169,7 +226,7 @@ impl<'a> Layer4Pkt<'a> {
pub fn len(&self) -> u16 {
match self {
Layer4Pkt::UDP(pkt) => pkt.len(),
Layer4Pkt::TCP(_) => 0,
Layer4Pkt::TCP(pkt) => pkt.data.len() as u16,
}
}
@@ -358,6 +415,9 @@ impl EthernetPacket {
Layer3Packet::IPv4(pkt) => EthernetPacket {
data: [&dst[..], &src[..], &[0x08_u8, 0x00_u8][..], &*pkt.data].concat(),
},
Layer3Packet::ARP(pkt) => EthernetPacket {
data: [&dst[..], &src[..], &[0x08_u8, 0x06_u8][..], &*pkt.data].concat(),
},
}
}
@@ -370,13 +430,74 @@ impl EthernetPacket {
#[derive(Clone)]
pub enum Layer3Packet {
IPv4(IPv4Packet),
ARP(ARPPacket),
}
#[derive(Clone)]
pub struct ARPPacket {
data: Vec<u8>,
}
pub enum ARPMode {
Request,
Reply,
}
impl ARPMode {
fn opcode(&self) -> u16 {
match self {
Self::Request => 1,
Self::Reply => 2,
}
}
}
pub enum ARPProto {
IPv4,
}
impl ARPProto {
fn opcode(&self) -> u16 {
match self {
Self::IPv4 => 0x0800,
}
}
}
impl ARPPacket {
pub fn construct(
op: ARPMode,
proto: ARPProto,
srchwaddr: &[u8],
targethwaddr: &[u8],
srcprotoaddr: &[u8],
targetprotoaddr: &[u8],
) -> ARPPacket {
assert!(srchwaddr.len() == targethwaddr.len());
assert!(srcprotoaddr.len() == targetprotoaddr.len());
let data = [
&0x0001u16.to_be_bytes()[..],
&proto.opcode().to_be_bytes()[..],
&[srchwaddr.len() as u8],
&[srcprotoaddr.len() as u8],
&op.opcode().to_be_bytes(),
srchwaddr,
srcprotoaddr,
targethwaddr,
targetprotoaddr,
]
.concat();
ARPPacket { data }
}
}
static IPV4_ID: AtomicU16 = AtomicU16::new(0xabcd);
#[derive(Clone)]
pub struct IPv4Packet {
data: Vec<u8>,
pub data: Vec<u8>,
}
impl IPv4Packet {