arcbox_packet/ethernet/
mod.rs1mod checksum;
9mod tcp;
10mod udp;
11
12#[cfg(test)]
13mod tests;
14
15pub use checksum::{ipv4_header_checksum, tcp_checksum};
16pub use tcp::{
17 SynAckParams, SynParams, TcpFrameParams, TcpSynOptions, build_tcp_ack_frame,
18 build_tcp_data_frame, build_tcp_data_frame_partial_csum, build_tcp_fin_frame,
19 build_tcp_rst_frame, build_tcp_syn_ack_frame, build_tcp_syn_frame, parse_tcp_syn_options,
20 tcp_pseudo_header_checksum,
21};
22pub use udp::{MAX_UDP_PAYLOAD, build_udp_ip_ethernet};
23
24use std::net::Ipv4Addr;
25
26pub const ETH_HEADER_LEN: usize = 14;
28
29const ARP_FRAME_MIN_LEN: usize = ETH_HEADER_LEN + 28;
31
32#[derive(Debug, Clone, Copy, PartialEq, Eq)]
34pub enum EtherType {
35 Ipv4,
36 Arp,
37 Ipv6,
38 Unknown(u16),
39}
40
41impl EtherType {
42 #[must_use]
44 pub fn from_raw(raw: u16) -> Self {
45 match raw {
46 0x0800 => Self::Ipv4,
47 0x0806 => Self::Arp,
48 0x86DD => Self::Ipv6,
49 other => Self::Unknown(other),
50 }
51 }
52
53 #[must_use]
55 pub fn to_raw(self) -> u16 {
56 match self {
57 Self::Ipv4 => 0x0800,
58 Self::Arp => 0x0806,
59 Self::Ipv6 => 0x86DD,
60 Self::Unknown(v) => v,
61 }
62 }
63}
64
65#[derive(Debug, Clone, Copy)]
67pub struct EthernetHeader {
68 pub dst_mac: [u8; 6],
69 pub src_mac: [u8; 6],
70 pub ethertype: EtherType,
71}
72
73impl EthernetHeader {
74 #[must_use]
78 pub fn parse(data: &[u8]) -> Option<Self> {
79 if data.len() < ETH_HEADER_LEN {
80 return None;
81 }
82 let mut dst_mac = [0u8; 6];
83 let mut src_mac = [0u8; 6];
84 dst_mac.copy_from_slice(&data[0..6]);
85 src_mac.copy_from_slice(&data[6..12]);
86 let raw_type = u16::from_be_bytes([data[12], data[13]]);
87 Some(Self {
88 dst_mac,
89 src_mac,
90 ethertype: EtherType::from_raw(raw_type),
91 })
92 }
93
94 #[must_use]
96 pub fn to_bytes(&self) -> [u8; ETH_HEADER_LEN] {
97 let mut buf = [0u8; ETH_HEADER_LEN];
98 buf[0..6].copy_from_slice(&self.dst_mac);
99 buf[6..12].copy_from_slice(&self.src_mac);
100 buf[12..14].copy_from_slice(&self.ethertype.to_raw().to_be_bytes());
101 buf
102 }
103}
104
105#[must_use]
107pub fn strip_ethernet_header(frame: &[u8]) -> &[u8] {
108 if frame.len() <= ETH_HEADER_LEN {
109 return &[];
110 }
111 &frame[ETH_HEADER_LEN..]
112}
113
114#[must_use]
116pub fn prepend_ethernet_header(ip_packet: &[u8], dst_mac: [u8; 6], src_mac: [u8; 6]) -> Vec<u8> {
117 let hdr = EthernetHeader {
118 dst_mac,
119 src_mac,
120 ethertype: EtherType::Ipv4,
121 };
122 let mut frame = Vec::with_capacity(ETH_HEADER_LEN + ip_packet.len());
123 frame.extend_from_slice(&hdr.to_bytes());
124 frame.extend_from_slice(ip_packet);
125 frame
126}
127
128pub struct ArpResponder {
130 gateway_ip: Ipv4Addr,
131 gateway_mac: [u8; 6],
132}
133
134impl ArpResponder {
135 #[must_use]
137 pub fn new(gateway_ip: Ipv4Addr, gateway_mac: [u8; 6]) -> Self {
138 Self {
139 gateway_ip,
140 gateway_mac,
141 }
142 }
143
144 #[must_use]
147 pub fn handle_arp(&self, frame: &[u8]) -> Option<Vec<u8>> {
148 if frame.len() < ARP_FRAME_MIN_LEN {
149 return None;
150 }
151
152 let arp = &frame[ETH_HEADER_LEN..];
153
154 if u16::from_be_bytes([arp[0], arp[1]]) != 1
156 || u16::from_be_bytes([arp[2], arp[3]]) != 0x0800
157 {
158 return None;
159 }
160
161 if arp[4] != 6 || arp[5] != 4 || u16::from_be_bytes([arp[6], arp[7]]) != 1 {
163 return None;
164 }
165
166 let target_ip = Ipv4Addr::new(arp[24], arp[25], arp[26], arp[27]);
168 if target_ip != self.gateway_ip {
169 return None;
170 }
171
172 let mut sender_mac = [0u8; 6];
174 sender_mac.copy_from_slice(&arp[8..14]);
175 let sender_ip_bytes: [u8; 4] = [arp[14], arp[15], arp[16], arp[17]];
176
177 let mut reply = Vec::with_capacity(ARP_FRAME_MIN_LEN);
179
180 reply.extend_from_slice(&sender_mac);
182 reply.extend_from_slice(&self.gateway_mac);
183 reply.extend_from_slice(&0x0806u16.to_be_bytes());
184
185 reply.extend_from_slice(&1u16.to_be_bytes()); reply.extend_from_slice(&0x0800u16.to_be_bytes()); reply.push(6); reply.push(4); reply.extend_from_slice(&2u16.to_be_bytes()); reply.extend_from_slice(&self.gateway_mac); reply.extend_from_slice(&self.gateway_ip.octets()); reply.extend_from_slice(&sender_mac); reply.extend_from_slice(&sender_ip_bytes); Some(reply)
197 }
198}