cross_socket/packet/
ipv4.rs

1use crate::packet::ip::IpNextLevelProtocol;
2use pnet::packet::Packet;
3use std::net::Ipv4Addr;
4
5/// IPv4 Header Length
6pub const IPV4_HEADER_LEN: usize = pnet::packet::ipv4::MutableIpv4Packet::minimum_packet_size();
7/// IPv4 Header Bytes (32 bits)
8pub const IPV4_HEADER_BYTES: usize = 4;
9
10/// Represents the IPv4 flags.
11#[derive(Clone, Debug, PartialEq)]
12pub enum Ipv4Flags {
13    Reserved,
14    DontFragment,
15    MoreFragments,
16}
17
18impl Ipv4Flags {
19    pub fn from_u8(n: u8) -> Ipv4Flags {
20        match n {
21            0b010 => Ipv4Flags::DontFragment,
22            0b001 => Ipv4Flags::MoreFragments,
23            _ => Ipv4Flags::Reserved,
24        }
25    }
26}
27
28/// Represents the IPv4 options.
29#[derive(Clone, Debug, PartialEq)]
30pub enum Ipv4Option {
31    EndOfOptionsList,
32    NoOperation,
33    Security,
34    LooseSourceRoute,
35    TimeStamp,
36    ExtendedSecurity,
37    CommercialSecurity,
38    RecordRoute,
39    StreamId,
40    StrictSourceRoute,
41    ExperimentalMeasurement,
42    MtuProbe,
43    MtuReply,
44    ExperimentalFlowControl,
45    ExperimentalAccessControl,
46    Encode,
47    ImiTrafficDescriptor,
48    ExtendedInternetProtocol,
49    Traceroute,
50    AddressExtension,
51    RouterAlert,
52    SelectiveDirectedBroadcast,
53    DynamicPacketState,
54    UpstreamMulticastPacket,
55    QuickStart,
56    Rfc3692StyleExperiment,
57    Unknown(u8),
58}
59
60impl Ipv4Option {
61    /// Constructs a new Ipv4Option from u8
62    pub fn from_u8(n: u8) -> Ipv4Option {
63        match n {
64            0 => Ipv4Option::EndOfOptionsList,
65            1 => Ipv4Option::NoOperation,
66            2 => Ipv4Option::Security,
67            3 => Ipv4Option::LooseSourceRoute,
68            4 => Ipv4Option::TimeStamp,
69            5 => Ipv4Option::ExtendedSecurity,
70            6 => Ipv4Option::CommercialSecurity,
71            7 => Ipv4Option::RecordRoute,
72            8 => Ipv4Option::StreamId,
73            9 => Ipv4Option::StrictSourceRoute,
74            10 => Ipv4Option::ExperimentalMeasurement,
75            11 => Ipv4Option::MtuProbe,
76            12 => Ipv4Option::MtuReply,
77            13 => Ipv4Option::ExperimentalFlowControl,
78            14 => Ipv4Option::ExperimentalAccessControl,
79            15 => Ipv4Option::Encode,
80            16 => Ipv4Option::ImiTrafficDescriptor,
81            17 => Ipv4Option::ExtendedInternetProtocol,
82            18 => Ipv4Option::Traceroute,
83            19 => Ipv4Option::AddressExtension,
84            20 => Ipv4Option::RouterAlert,
85            21 => Ipv4Option::SelectiveDirectedBroadcast,
86            23 => Ipv4Option::DynamicPacketState,
87            24 => Ipv4Option::UpstreamMulticastPacket,
88            25 => Ipv4Option::QuickStart,
89            30 => Ipv4Option::Rfc3692StyleExperiment,
90            _ => Ipv4Option::Unknown(n),
91        }
92    }
93    /// Returns the number of the Ipv4Option
94    pub fn number(&self) -> u8 {
95        match *self {
96            Ipv4Option::EndOfOptionsList => 0,
97            Ipv4Option::NoOperation => 1,
98            Ipv4Option::Security => 2,
99            Ipv4Option::LooseSourceRoute => 3,
100            Ipv4Option::TimeStamp => 4,
101            Ipv4Option::ExtendedSecurity => 5,
102            Ipv4Option::CommercialSecurity => 6,
103            Ipv4Option::RecordRoute => 7,
104            Ipv4Option::StreamId => 8,
105            Ipv4Option::StrictSourceRoute => 9,
106            Ipv4Option::ExperimentalMeasurement => 10,
107            Ipv4Option::MtuProbe => 11,
108            Ipv4Option::MtuReply => 12,
109            Ipv4Option::ExperimentalFlowControl => 13,
110            Ipv4Option::ExperimentalAccessControl => 14,
111            Ipv4Option::Encode => 15,
112            Ipv4Option::ImiTrafficDescriptor => 16,
113            Ipv4Option::ExtendedInternetProtocol => 17,
114            Ipv4Option::Traceroute => 18,
115            Ipv4Option::AddressExtension => 19,
116            Ipv4Option::RouterAlert => 20,
117            Ipv4Option::SelectiveDirectedBroadcast => 21,
118            Ipv4Option::DynamicPacketState => 23,
119            Ipv4Option::UpstreamMulticastPacket => 24,
120            Ipv4Option::QuickStart => 25,
121            Ipv4Option::Rfc3692StyleExperiment => 30,
122            Ipv4Option::Unknown(n) => n,
123        }
124    }
125}
126
127/// Represents an IPv4 packet.
128#[derive(Clone, Debug, PartialEq)]
129pub struct Ipv4Packet {
130    /// IP version
131    pub version: u8,
132    /// IP header length
133    pub header_length: u8,
134    /// Differentiated Services Code Point (DSCP)
135    pub dscp: u8,
136    /// Explicit Congestion Notification (ECN)
137    pub ecn: u8,
138    /// Total length
139    pub total_length: u16,
140    /// Identification
141    pub identification: u16,
142    /// Flags
143    pub flags: u8,
144    /// Fragment offset
145    pub fragment_offset: u16,
146    /// Time to live
147    pub ttl: u8,
148    /// Next level protocol
149    pub next_protocol: IpNextLevelProtocol,
150    /// Checksum
151    pub checksum: u16,
152    /// Source IP address
153    pub source: Ipv4Addr,
154    /// Destination IP address
155    pub destination: Ipv4Addr,
156    /// Options
157    pub options: Vec<Ipv4Option>,
158    /// Payload
159    pub payload: Vec<u8>,
160}
161
162impl Ipv4Packet {
163    pub(crate) fn from_pnet_packet(packet: &pnet::packet::ipv4::Ipv4Packet) -> Ipv4Packet {
164        Ipv4Packet {
165            version: packet.get_version(),
166            header_length: packet.get_header_length(),
167            dscp: packet.get_dscp(),
168            ecn: packet.get_ecn(),
169            total_length: packet.get_total_length(),
170            identification: packet.get_identification(),
171            flags: packet.get_flags(),
172            fragment_offset: packet.get_fragment_offset(),
173            ttl: packet.get_ttl(),
174            next_protocol: IpNextLevelProtocol::from_u8(packet.get_next_level_protocol().0),
175            checksum: packet.get_checksum(),
176            source: packet.get_source(),
177            destination: packet.get_destination(),
178            options: packet
179                .get_options_iter()
180                .map(|opt| Ipv4Option::from_u8(opt.get_number().0))
181                .collect(),
182            payload: packet.payload().to_vec(),
183        }
184    }
185    /// Constructs a new Ipv4Packet from bytes
186    pub fn from_bytes(packet: &[u8]) -> Ipv4Packet {
187        let ipv4_packet = pnet::packet::ipv4::Ipv4Packet::new(packet).unwrap();
188        Ipv4Packet::from_pnet_packet(&ipv4_packet)
189    }
190}
191
192/// Build IPv4 packet
193pub(crate) fn build_ipv4_packet(
194    ipv4_packet: &mut pnet::packet::ipv4::MutableIpv4Packet,
195    src_ip: Ipv4Addr,
196    dst_ip: Ipv4Addr,
197    next_protocol: IpNextLevelProtocol,
198) {
199    ipv4_packet.set_header_length((IPV4_HEADER_LEN / IPV4_HEADER_BYTES) as u8);
200    ipv4_packet.set_source(src_ip);
201    ipv4_packet.set_destination(dst_ip);
202    ipv4_packet.set_identification(rand::random::<u16>());
203    ipv4_packet.set_ttl(64);
204    ipv4_packet.set_version(4);
205    ipv4_packet.set_flags(pnet::packet::ipv4::Ipv4Flags::DontFragment);
206    match next_protocol {
207        IpNextLevelProtocol::Tcp => {
208            ipv4_packet.set_total_length(52);
209            ipv4_packet.set_next_level_protocol(pnet::packet::ip::IpNextHeaderProtocols::Tcp);
210        }
211        IpNextLevelProtocol::Udp => {
212            ipv4_packet.set_total_length(28);
213            ipv4_packet.set_next_level_protocol(pnet::packet::ip::IpNextHeaderProtocols::Udp);
214        }
215        IpNextLevelProtocol::Icmp => {
216            ipv4_packet.set_total_length(28);
217            ipv4_packet.set_next_level_protocol(pnet::packet::ip::IpNextHeaderProtocols::Icmp);
218        }
219        _ => {}
220    }
221    let checksum = pnet::packet::ipv4::checksum(&ipv4_packet.to_immutable());
222    ipv4_packet.set_checksum(checksum);
223}
224
225/// IPv4 Packet Builder
226#[derive(Clone, Debug)]
227pub struct Ipv4PacketBuilder {
228    pub src_ip: Ipv4Addr,
229    pub dst_ip: Ipv4Addr,
230    pub next_protocol: IpNextLevelProtocol,
231    pub total_length: Option<u16>,
232    pub identification: Option<u16>,
233    pub ttl: Option<u8>,
234    pub flags: Option<Ipv4Flags>,
235}
236
237impl Ipv4PacketBuilder {
238    /// Constructs a new Ipv4PacketBuilder
239    pub fn new(src_ip: Ipv4Addr, dst_ip: Ipv4Addr, next_protocol: IpNextLevelProtocol) -> Self {
240        Ipv4PacketBuilder {
241            src_ip,
242            dst_ip,
243            next_protocol,
244            total_length: None,
245            identification: None,
246            ttl: None,
247            flags: None,
248        }
249    }
250    /// Builds IPv4 packet and return bytes
251    pub fn build(&self) -> Vec<u8> {
252        let mut buffer = vec![0; IPV4_HEADER_LEN];
253        let mut ipv4_packet = pnet::packet::ipv4::MutableIpv4Packet::new(&mut buffer).unwrap();
254        ipv4_packet.set_header_length((IPV4_HEADER_LEN / IPV4_HEADER_BYTES) as u8);
255        ipv4_packet.set_source(self.src_ip);
256        ipv4_packet.set_destination(self.dst_ip);
257        ipv4_packet.set_identification(self.identification.unwrap_or(rand::random::<u16>()));
258        ipv4_packet.set_ttl(self.ttl.unwrap_or(64));
259        ipv4_packet.set_version(4);
260        if let Some(flags) = &self.flags {
261            match flags {
262                Ipv4Flags::DontFragment => {
263                    ipv4_packet.set_flags(pnet::packet::ipv4::Ipv4Flags::DontFragment);
264                }
265                Ipv4Flags::MoreFragments => {
266                    ipv4_packet.set_flags(pnet::packet::ipv4::Ipv4Flags::MoreFragments);
267                }
268                _ => {}
269            }
270        } else {
271            ipv4_packet.set_flags(pnet::packet::ipv4::Ipv4Flags::DontFragment);
272        }
273        match self.next_protocol {
274            IpNextLevelProtocol::Tcp => {
275                if let Some(total_length) = self.total_length {
276                    ipv4_packet.set_total_length(total_length);
277                } else {
278                    ipv4_packet.set_total_length(52);
279                }
280                ipv4_packet.set_next_level_protocol(pnet::packet::ip::IpNextHeaderProtocols::Tcp);
281            }
282            IpNextLevelProtocol::Udp => {
283                if let Some(total_length) = self.total_length {
284                    ipv4_packet.set_total_length(total_length);
285                } else {
286                    ipv4_packet.set_total_length(28);
287                }
288                ipv4_packet.set_next_level_protocol(pnet::packet::ip::IpNextHeaderProtocols::Udp);
289            }
290            IpNextLevelProtocol::Icmp => {
291                if let Some(total_length) = self.total_length {
292                    ipv4_packet.set_total_length(total_length);
293                } else {
294                    ipv4_packet.set_total_length(28);
295                }
296                ipv4_packet.set_next_level_protocol(pnet::packet::ip::IpNextHeaderProtocols::Icmp);
297            }
298            _ => {}
299        }
300        let checksum = pnet::packet::ipv4::checksum(&ipv4_packet.to_immutable());
301        ipv4_packet.set_checksum(checksum);
302        ipv4_packet.packet().to_vec()
303    }
304}