1use super::address::Ipv4Address;
4use super::protocol::Ipv4Protocol;
5use crate::{error::ParseError, internet_checksum};
6
7pub(super) const HEADER_LENGTH: usize = 20;
8
9#[derive(Clone, Copy, Debug, Eq, PartialEq)]
15pub struct Ipv4Packet<'a> {
16 bytes: &'a [u8],
17 header_length: usize,
18}
19impl<'a> Ipv4Packet<'a> {
20 #[inline]
22 pub fn parse(bytes: &'a [u8]) -> Result<Self, ParseError> {
23 let (header_length, total_length) = validate(bytes)?;
24 Ok(Self {
25 bytes: &bytes[..total_length],
26 header_length,
27 })
28 }
29 #[inline]
31 pub fn dscp_ecn(&self) -> u8 {
32 self.bytes[1]
33 }
34 #[inline]
36 pub fn total_length(&self) -> u16 {
37 read_u16(self.bytes, 2)
38 }
39 #[inline]
41 pub fn identification(&self) -> u16 {
42 read_u16(self.bytes, 4)
43 }
44 #[inline]
46 pub fn flags_fragment_offset(&self) -> u16 {
47 read_u16(self.bytes, 6)
48 }
49 #[inline]
51 pub fn ttl(&self) -> u8 {
52 self.bytes[8]
53 }
54 #[inline]
56 pub fn protocol(&self) -> Ipv4Protocol {
57 Ipv4Protocol::new(self.bytes[9])
58 }
59 #[inline]
61 pub fn header_checksum(&self) -> u16 {
62 read_u16(self.bytes, 10)
63 }
64 #[inline]
66 pub fn source(&self) -> Ipv4Address {
67 Ipv4Address::new(
68 self.bytes[12..16]
69 .try_into()
70 .expect("validated IPv4 header"),
71 )
72 }
73 #[inline]
75 pub fn destination(&self) -> Ipv4Address {
76 Ipv4Address::new(
77 self.bytes[16..20]
78 .try_into()
79 .expect("validated IPv4 header"),
80 )
81 }
82 #[inline]
84 pub fn options(&self) -> &'a [u8] {
85 &self.bytes[HEADER_LENGTH..self.header_length]
86 }
87 #[inline]
89 pub fn payload(&self) -> &'a [u8] {
90 &self.bytes[self.header_length..]
91 }
92 #[inline]
94 pub fn as_bytes(&self) -> &'a [u8] {
95 self.bytes
96 }
97 #[inline]
99 pub fn checksum_is_valid(&self) -> bool {
100 internet_checksum::sum(&self.bytes[..self.header_length]) == 0xffff
101 }
102}
103#[derive(Debug, Eq, PartialEq)]
105pub struct Ipv4PacketMut<'a> {
106 bytes: &'a mut [u8],
107 header_length: usize,
108}
109impl<'a> Ipv4PacketMut<'a> {
110 #[inline]
112 pub fn parse(bytes: &'a mut [u8]) -> Result<Self, ParseError> {
113 let (header_length, total_length) = validate(bytes)?;
114 Ok(Self::from_validated(
115 &mut bytes[..total_length],
116 header_length,
117 ))
118 }
119 pub(super) fn from_validated(bytes: &'a mut [u8], header_length: usize) -> Self {
120 Self {
121 bytes,
122 header_length,
123 }
124 }
125 #[inline]
127 pub fn dscp_ecn(&self) -> u8 {
128 self.bytes[1]
129 }
130 #[inline]
132 pub fn total_length(&self) -> u16 {
133 read_u16(self.bytes, 2)
134 }
135 #[inline]
137 pub fn identification(&self) -> u16 {
138 read_u16(self.bytes, 4)
139 }
140 #[inline]
142 pub fn flags_fragment_offset(&self) -> u16 {
143 read_u16(self.bytes, 6)
144 }
145 #[inline]
147 pub fn ttl(&self) -> u8 {
148 self.bytes[8]
149 }
150 #[inline]
152 pub fn protocol(&self) -> Ipv4Protocol {
153 Ipv4Protocol::new(self.bytes[9])
154 }
155 #[inline]
157 pub fn header_checksum(&self) -> u16 {
158 read_u16(self.bytes, 10)
159 }
160 #[inline]
162 pub fn source(&self) -> Ipv4Address {
163 Ipv4Address::new(
164 self.bytes[12..16]
165 .try_into()
166 .expect("validated IPv4 header"),
167 )
168 }
169 #[inline]
171 pub fn destination(&self) -> Ipv4Address {
172 Ipv4Address::new(
173 self.bytes[16..20]
174 .try_into()
175 .expect("validated IPv4 header"),
176 )
177 }
178 #[inline]
180 pub fn options(&self) -> &[u8] {
181 &self.bytes[HEADER_LENGTH..self.header_length]
182 }
183 #[inline]
185 pub fn payload(&self) -> &[u8] {
186 &self.bytes[self.header_length..]
187 }
188 #[inline]
190 pub fn options_mut(&mut self) -> &mut [u8] {
191 &mut self.bytes[HEADER_LENGTH..self.header_length]
192 }
193 #[inline]
195 pub fn payload_mut(&mut self) -> &mut [u8] {
196 &mut self.bytes[self.header_length..]
197 }
198 #[inline]
200 pub fn as_bytes(&self) -> &[u8] {
201 self.bytes
202 }
203 #[inline]
205 pub fn as_bytes_mut(&mut self) -> &mut [u8] {
206 self.bytes
207 }
208 #[inline]
210 pub fn set_dscp_ecn(&mut self, v: u8) {
211 self.bytes[1] = v
212 }
213 #[inline]
215 pub fn set_identification(&mut self, v: u16) {
216 write_u16(self.bytes, 4, v)
217 }
218 #[inline]
220 pub fn set_flags_fragment_offset(&mut self, v: u16) {
221 write_u16(self.bytes, 6, v)
222 }
223 #[inline]
225 pub fn set_ttl(&mut self, v: u8) {
226 self.bytes[8] = v
227 }
228 #[inline]
230 pub fn set_protocol(&mut self, v: Ipv4Protocol) {
231 self.bytes[9] = v.raw()
232 }
233 #[inline]
235 pub fn set_header_checksum(&mut self, v: u16) {
236 write_u16(self.bytes, 10, v)
237 }
238 #[inline]
240 pub fn set_source(&mut self, v: Ipv4Address) {
241 self.bytes[12..16].copy_from_slice(&v.octets())
242 }
243 #[inline]
245 pub fn set_destination(&mut self, v: Ipv4Address) {
246 self.bytes[16..20].copy_from_slice(&v.octets())
247 }
248 #[inline]
250 pub fn update_header_checksum(&mut self) {
251 self.bytes[10] = 0;
252 self.bytes[11] = 0;
253 write_u16(
254 self.bytes,
255 10,
256 !internet_checksum::sum(&self.bytes[..self.header_length]),
257 )
258 }
259 #[inline]
261 pub fn checksum_is_valid(&self) -> bool {
262 internet_checksum::sum(&self.bytes[..self.header_length]) == 0xffff
263 }
264}
265#[inline]
266fn read_u16(bytes: &[u8], offset: usize) -> u16 {
267 u16::from_be_bytes(
268 bytes[offset..offset + 2]
269 .try_into()
270 .expect("validated IPv4 header"),
271 )
272}
273#[inline]
274fn write_u16(bytes: &mut [u8], offset: usize, value: u16) {
275 bytes[offset..offset + 2].copy_from_slice(&value.to_be_bytes())
276}
277#[inline]
278fn validate(bytes: &[u8]) -> Result<(usize, usize), ParseError> {
279 if bytes.len() < HEADER_LENGTH {
280 return Err(ParseError::Truncated {
281 minimum: HEADER_LENGTH,
282 available: bytes.len(),
283 });
284 }
285 let version = bytes[0] >> 4;
286 if version != 4 {
287 return Err(ParseError::InvalidVersion {
288 expected: 4,
289 actual: version,
290 });
291 }
292 let header_length = usize::from(bytes[0] & 15) * 4;
293 if header_length < HEADER_LENGTH {
294 return Err(ParseError::InvalidHeaderLength {
295 minimum: HEADER_LENGTH,
296 actual: header_length,
297 });
298 }
299 if bytes.len() < header_length {
300 return Err(ParseError::Truncated {
301 minimum: header_length,
302 available: bytes.len(),
303 });
304 }
305 let total_length = usize::from(read_u16(bytes, 2));
306 if total_length < header_length {
307 return Err(ParseError::InvalidTotalLength {
308 header_length,
309 total_length,
310 });
311 }
312 if bytes.len() < total_length {
313 return Err(ParseError::Truncated {
314 minimum: total_length,
315 available: bytes.len(),
316 });
317 }
318 Ok((header_length, total_length))
319}