1use crate::packet::ip::IpNextLevelProtocol;
2use pnet::packet::Packet;
3use std::net::Ipv4Addr;
4
5pub const IPV4_HEADER_LEN: usize = pnet::packet::ipv4::MutableIpv4Packet::minimum_packet_size();
7pub const IPV4_HEADER_BYTES: usize = 4;
9
10#[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#[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 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 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#[derive(Clone, Debug, PartialEq)]
129pub struct Ipv4Packet {
130 pub version: u8,
132 pub header_length: u8,
134 pub dscp: u8,
136 pub ecn: u8,
138 pub total_length: u16,
140 pub identification: u16,
142 pub flags: u8,
144 pub fragment_offset: u16,
146 pub ttl: u8,
148 pub next_protocol: IpNextLevelProtocol,
150 pub checksum: u16,
152 pub source: Ipv4Addr,
154 pub destination: Ipv4Addr,
156 pub options: Vec<Ipv4Option>,
158 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 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
192pub(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#[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 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 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}