1use alloc::vec;
4use alloc::vec::Vec;
5use core::net::Ipv4Addr;
6
7use crate::types::IpProtocol;
8use crate::util::{internet_checksum, read_u16be, read_u32be, write_u16be, write_u32be, BuildError};
9
10pub const IPV4_MIN_HEADER_LEN: usize = 20;
12
13#[derive(Debug, Clone)]
15pub struct Ipv4Packet<'a> {
16 buf: &'a [u8],
17}
18
19impl<'a> Ipv4Packet<'a> {
20 pub fn new(buf: &'a [u8]) -> Option<Self> {
23 if buf.len() < IPV4_MIN_HEADER_LEN {
24 return None;
25 }
26 let ihl = (buf[0] & 0x0F) as usize * 4;
27 if ihl < IPV4_MIN_HEADER_LEN || buf.len() < ihl {
28 return None;
29 }
30 Some(Self { buf })
31 }
32
33 #[inline]
34 pub fn version(&self) -> u8 {
35 self.buf[0] >> 4
36 }
37
38 #[inline]
39 pub fn ihl(&self) -> u8 {
40 self.buf[0] & 0x0F
41 }
42
43 #[inline]
44 pub fn dscp(&self) -> u8 {
45 self.buf[1] >> 2
46 }
47
48 #[inline]
49 pub fn ecn(&self) -> u8 {
50 self.buf[1] & 0x03
51 }
52
53 #[inline]
54 pub fn total_length(&self) -> u16 {
55 read_u16be(&self.buf[2..4])
56 }
57
58 #[inline]
59 pub fn identification(&self) -> u16 {
60 read_u16be(&self.buf[4..6])
61 }
62
63 #[inline]
64 pub fn flags(&self) -> u8 {
65 self.buf[6] >> 5
66 }
67
68 #[inline]
69 pub fn dont_fragment(&self) -> bool {
70 self.flags() & 0x02 != 0
71 }
72
73 #[inline]
74 pub fn more_fragments(&self) -> bool {
75 self.flags() & 0x01 != 0
76 }
77
78 #[inline]
79 pub fn fragment_offset(&self) -> u16 {
80 read_u16be(&self.buf[6..8]) & 0x1FFF
81 }
82
83 #[inline]
84 pub fn ttl(&self) -> u8 {
85 self.buf[8]
86 }
87
88 #[inline]
89 pub fn protocol(&self) -> IpProtocol {
90 IpProtocol::from(self.buf[9])
91 }
92
93 #[inline]
94 pub fn checksum(&self) -> u16 {
95 read_u16be(&self.buf[10..12])
96 }
97
98 #[inline]
99 pub fn source(&self) -> Ipv4Addr {
100 Ipv4Addr::from_bits(read_u32be(&self.buf[12..16]))
101 }
102
103 #[inline]
104 pub fn destination(&self) -> Ipv4Addr {
105 Ipv4Addr::from_bits(read_u32be(&self.buf[16..20]))
106 }
107
108 #[inline]
110 pub fn options(&self) -> &'a [u8] {
111 let hdr_len = self.ihl() as usize * 4;
112 if hdr_len > IPV4_MIN_HEADER_LEN {
113 &self.buf[IPV4_MIN_HEADER_LEN..hdr_len]
114 } else {
115 &[]
116 }
117 }
118
119 #[inline]
121 pub fn payload(&self) -> &'a [u8] {
122 &self.buf[self.ihl() as usize * 4..]
123 }
124
125 #[inline]
127 pub fn header_length(&self) -> usize {
128 self.ihl() as usize * 4
129 }
130
131 pub fn verify_checksum(&self) -> bool {
133 internet_checksum(&self.buf[..self.header_length()]) == 0
134 }
135}
136
137#[derive(Debug, Clone)]
143pub struct Ipv4PacketBuilder {
144 buf: Vec<u8>,
145 payload: Option<Vec<u8>>,
146}
147
148impl Default for Ipv4PacketBuilder {
149 fn default() -> Self {
150 Self::new()
151 }
152}
153
154impl Ipv4PacketBuilder {
155 pub fn new() -> Self {
157 let mut buf = vec![0u8; IPV4_MIN_HEADER_LEN];
158 buf[0] = 0x45; buf[8] = 64; Self { buf, payload: None }
161 }
162
163 pub fn dscp(mut self, dscp: u8) -> Self {
164 self.buf[1] = (self.buf[1] & 0x03) | (dscp << 2);
165 self
166 }
167
168 pub fn ecn(mut self, ecn: u8) -> Self {
169 self.buf[1] = (self.buf[1] & 0xFC) | (ecn & 0x03);
170 self
171 }
172
173 pub fn identification(mut self, id: u16) -> Self {
174 write_u16be(&mut self.buf[4..6], id);
175 self
176 }
177
178 pub fn dont_fragment(mut self, df: bool) -> Self {
179 if df {
180 self.buf[6] |= 0x40;
181 } else {
182 self.buf[6] &= !0x40;
183 }
184 self
185 }
186
187 pub fn more_fragments(mut self, mf: bool) -> Self {
188 if mf {
189 self.buf[6] |= 0x20;
190 } else {
191 self.buf[6] &= !0x20;
192 }
193 self
194 }
195
196 pub fn fragment_offset(mut self, offset: u16) -> Self {
197 let current = read_u16be(&self.buf[6..8]);
198 let new = (current & 0xE000) | (offset & 0x1FFF);
199 write_u16be(&mut self.buf[6..8], new);
200 self
201 }
202
203 pub fn ttl(mut self, ttl: u8) -> Self {
204 self.buf[8] = ttl;
205 self
206 }
207
208 pub fn protocol(mut self, proto: IpProtocol) -> Self {
209 self.buf[9] = proto.into();
210 self
211 }
212
213 pub fn source(mut self, addr: Ipv4Addr) -> Self {
214 write_u32be(&mut self.buf[12..16], addr.to_bits());
215 self
216 }
217
218 pub fn destination(mut self, addr: Ipv4Addr) -> Self {
219 write_u32be(&mut self.buf[16..20], addr.to_bits());
220 self
221 }
222
223 pub fn payload(mut self, data: &[u8]) -> Result<Self, BuildError> {
224 if data.len() > 65535 - self.buf.len() {
225 return Err(BuildError::PayloadTooLarge {
226 max: 65535 - self.buf.len(),
227 actual: data.len(),
228 });
229 }
230 self.payload = Some(data.to_vec());
231 Ok(self)
232 }
233
234 pub fn build(mut self) -> Vec<u8> {
236 let total_len = self.buf.len() + self.payload.as_ref().map_or(0, |p| p.len());
237 write_u16be(&mut self.buf[2..4], total_len as u16);
238
239 self.buf[10] = 0;
241 self.buf[11] = 0;
242 let checksum = internet_checksum(&self.buf);
243 write_u16be(&mut self.buf[10..12], checksum);
244
245 let mut packet = self.buf;
246 if let Some(p) = self.payload {
247 packet.extend_from_slice(&p);
248 }
249 packet
250 }
251}
252
253#[cfg(test)]
254mod tests {
255 use super::*;
256
257 const SAMPLE_IPV4: &[u8] = &[
259 0x45, 0x00, 0x00, 0x3C, 0x1C, 0x46, 0x40, 0x00,
260 0x40, 0x06, 0x00, 0x00, 0xAC, 0x10, 0x0A, 0x63,
261 0xAC, 0x10, 0x0A, 0x0C,
262 ];
263
264 #[test]
265 fn parse_ipv4() {
266 let pkt = Ipv4Packet::new(SAMPLE_IPV4).unwrap();
267 assert_eq!(pkt.version(), 4);
268 assert_eq!(pkt.ihl(), 5);
269 assert_eq!(pkt.header_length(), 20);
270 assert_eq!(pkt.protocol(), IpProtocol::Tcp);
271 assert_eq!(pkt.ttl(), 64);
272 assert_eq!(pkt.source(), Ipv4Addr::new(172, 16, 10, 99));
273 assert_eq!(pkt.destination(), Ipv4Addr::new(172, 16, 10, 12));
274 assert!(pkt.dont_fragment());
275 assert!(!pkt.more_fragments());
276 }
277
278 #[test]
279 fn parse_too_short() {
280 assert!(Ipv4Packet::new(&[0u8; 19]).is_none());
281 assert!(Ipv4Packet::new(&[]).is_none());
282 }
283
284 #[test]
285 fn parse_ihl_exceeds_buffer() {
286 let mut data = [0u8; 22];
288 data[0] = 0x46; assert!(Ipv4Packet::new(&data).is_none());
290 }
291
292 #[test]
293 fn verify_checksum() {
294 let pkt_bytes = Ipv4PacketBuilder::new()
296 .source(Ipv4Addr::new(10, 0, 0, 1))
297 .destination(Ipv4Addr::new(10, 0, 0, 2))
298 .protocol(IpProtocol::Tcp)
299 .ttl(64)
300 .build();
301
302 let pkt = Ipv4Packet::new(&pkt_bytes).unwrap();
303 assert!(pkt.verify_checksum());
304 }
305
306 #[test]
307 fn build_and_parse_roundtrip() {
308 let pkt_bytes = Ipv4PacketBuilder::new()
309 .source(Ipv4Addr::new(192, 168, 1, 1))
310 .destination(Ipv4Addr::new(192, 168, 1, 2))
311 .protocol(IpProtocol::Udp)
312 .ttl(128)
313 .dont_fragment(true)
314 .identification(0x1234)
315 .build();
316
317 let pkt = Ipv4Packet::new(&pkt_bytes).unwrap();
318 assert_eq!(pkt.source(), Ipv4Addr::new(192, 168, 1, 1));
319 assert_eq!(pkt.destination(), Ipv4Addr::new(192, 168, 1, 2));
320 assert_eq!(pkt.protocol(), IpProtocol::Udp);
321 assert_eq!(pkt.ttl(), 128);
322 assert!(pkt.dont_fragment());
323 assert_eq!(pkt.identification(), 0x1234);
324 assert!(pkt.verify_checksum());
325 }
326
327 #[test]
328 fn parse_with_options() {
329 let mut data = vec![0x46u8, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00,
331 0x40, 0x06, 0x00, 0x00,
332 0xC0, 0xA8, 0x01, 0x01, 0xC0, 0xA8, 0x01, 0x02,
333 0x01, 0x02, 0x03, 0x04, 0xAA, 0xBB, ];
336 let csum = internet_checksum(&data[..24]);
338 data[10..12].copy_from_slice(&csum.to_be_bytes());
339
340 let pkt = Ipv4Packet::new(&data).unwrap();
341 assert_eq!(pkt.ihl(), 6);
342 assert_eq!(pkt.header_length(), 24);
343 assert_eq!(pkt.options(), &[0x01, 0x02, 0x03, 0x04]);
344 assert_eq!(pkt.payload(), &[0xAA, 0xBB]);
345 assert!(pkt.verify_checksum());
346 }
347}