feat: added the ability to respond to ARP requests
This commit is contained in:
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user