Skip to main content

iris_core/protocols/packet/
ipv4.rs

1//! IPv4 packet.
2
3use crate::memory::mbuf::Mbuf;
4use crate::protocols::packet::{Packet, PacketHeader, PacketParseError};
5use crate::utils::types::*;
6
7use std::net::Ipv4Addr;
8
9/// IPv4 EtherType
10const IPV4_PROTOCOL: usize = 0x0800;
11/// Flag: "Reserved bit"
12const IPV4_RF: u16 = 0x8000;
13/// Flag: "Don't fragment"
14const IPV4_DF: u16 = 0x4000;
15/// Flag: "More fragments"
16const IPV4_MF: u16 = 0x2000;
17/// Fragment offset part
18const IPV4_FRAG_OFFSET: u16 = 0x1FFF;
19
20/// An IPv4 packet.
21///
22/// IPv4 options are not parsed by default.
23#[derive(Debug)]
24pub struct Ipv4<'a> {
25    /// Fixed header.
26    header: Ipv4Header,
27    /// Offset to `header` from the start of `mbuf`.
28    offset: usize,
29    /// Packet buffer.
30    mbuf: &'a Mbuf,
31}
32
33impl Ipv4<'_> {
34    /// Returns the IP protocol version.
35    #[inline]
36    pub fn version(&self) -> u8 {
37        (self.header.version_ihl & 0xf0) >> 4
38    }
39
40    /// Returns the header length measured in 32-bit words (IHL).
41    #[inline]
42    pub fn ihl(&self) -> u8 {
43        self.header.version_ihl & 0x0f
44    }
45
46    /// Returns the 8-bit field containing the version and IHL.
47    #[inline]
48    pub fn version_ihl(&self) -> u8 {
49        self.header.version_ihl
50    }
51
52    /// Returns the differentiated services code point (DSCP).
53    #[inline]
54    pub fn dscp(&self) -> u8 {
55        self.header.dscp_ecn >> 2
56    }
57
58    /// Returns the explicit congestion notification (ECN).
59    #[inline]
60    pub fn ecn(&self) -> u8 {
61        self.header.dscp_ecn & 0x03
62    }
63
64    /// Returns the differentiated services field.
65    #[inline]
66    pub fn dscp_ecn(&self) -> u8 {
67        self.header.dscp_ecn
68    }
69
70    /// Returns the type of service (former name of the differentiated services field).
71    #[inline]
72    pub fn type_of_service(&self) -> u8 {
73        self.dscp_ecn()
74    }
75
76    /// Returns the total length of the packet in bytes, including the header and data.
77    #[inline]
78    pub fn total_length(&self) -> u16 {
79        self.header.total_length.into()
80    }
81
82    /// Returns the identification field.
83    #[inline]
84    pub fn identification(&self) -> u16 {
85        self.header.identification.into()
86    }
87
88    /// Returns the 16-bit field containing the 3-bit flags and 13-bit fragment offset.
89    #[inline]
90    pub fn flags_to_fragment_offset(&self) -> u16 {
91        self.header.flags_to_fragment_offset.into()
92    }
93
94    /// Returns the 3-bit IP flags.
95    #[inline]
96    pub fn flags(&self) -> u8 {
97        (self.flags_to_fragment_offset() >> 13) as u8
98    }
99
100    /// Returns `true` if the Reserved flag is set.
101    #[inline]
102    pub fn rf(&self) -> bool {
103        (self.flags_to_fragment_offset() & IPV4_RF) != 0
104    }
105
106    /// Returns `true` if the Don't Fragment flag is set.
107    #[inline]
108    pub fn df(&self) -> bool {
109        (self.flags_to_fragment_offset() & IPV4_DF) != 0
110    }
111
112    /// Returns `true` if the More Fragments flag is set.
113    #[inline]
114    pub fn mf(&self) -> bool {
115        (self.flags_to_fragment_offset() & IPV4_MF) != 0
116    }
117
118    /// Returns the fragment offset in units of 8 bytes.
119    #[inline]
120    pub fn fragment_offset(&self) -> u16 {
121        self.flags_to_fragment_offset() & IPV4_FRAG_OFFSET
122    }
123
124    /// Returns the time to live (TTL) of the packet.
125    #[inline]
126    pub fn time_to_live(&self) -> u8 {
127        self.header.time_to_live
128    }
129
130    /// Returns the encapsulated protocol identifier.
131    #[inline]
132    pub fn protocol(&self) -> u8 {
133        self.header.protocol
134    }
135
136    /// Returns the IPv4 header checksum.
137    #[inline]
138    pub fn header_checksum(&self) -> u16 {
139        self.header.header_checksum.into()
140    }
141
142    /// Returns the sender's IPv4 address.
143    #[inline]
144    pub fn src_addr(&self) -> Ipv4Addr {
145        self.header.src_addr
146    }
147
148    /// Returns the receiver's IPv4 address.
149    #[inline]
150    pub fn dst_addr(&self) -> Ipv4Addr {
151        self.header.dst_addr
152    }
153}
154
155impl<'a> Packet<'a> for Ipv4<'a> {
156    fn mbuf(&self) -> &Mbuf {
157        self.mbuf
158    }
159
160    fn header_len(&self) -> usize {
161        self.header.length()
162    }
163
164    fn next_header_offset(&self) -> usize {
165        self.offset + self.header_len()
166    }
167
168    fn next_header(&self) -> Option<usize> {
169        Some(self.protocol().into())
170    }
171
172    fn parse_from(outer: &'a impl Packet<'a>) -> Result<Self, PacketParseError>
173    where
174        Self: Sized,
175    {
176        let offset = outer.next_header_offset();
177        if let Ok(header) = outer.mbuf().get_data(offset) {
178            match outer.next_header() {
179                Some(IPV4_PROTOCOL) => Ok(Ipv4 {
180                    header: unsafe { *header },
181                    offset,
182                    mbuf: outer.mbuf(),
183                }),
184                _ => Err(PacketParseError::InvalidProtocol),
185            }
186        } else {
187            Err(PacketParseError::InvalidRead)
188        }
189    }
190}
191
192/// Fixed portion of an IPv4 header.
193#[derive(Debug, Clone, Copy)]
194#[repr(C, packed)]
195struct Ipv4Header {
196    version_ihl: u8,
197    dscp_ecn: u8,
198    total_length: u16be,
199    identification: u16be,
200    flags_to_fragment_offset: u16be,
201    time_to_live: u8,
202    protocol: u8,
203    header_checksum: u16be,
204    src_addr: Ipv4Addr,
205    dst_addr: Ipv4Addr,
206}
207
208impl PacketHeader for Ipv4Header {
209    /// Header length measured in bytes. Equivalent to the payload offset.
210    ///
211    /// This differs from the value of the `IHL` field, which measures header length in 32-bit
212    /// words.
213    fn length(&self) -> usize {
214        ((self.version_ihl & 0xf) << 2).into()
215    }
216}