1#[allow(unused_imports)]
10use alloc::vec::Vec;
11use core::num::NonZeroU16;
12use core::ops::Range;
13
14use log::debug;
15use net_types::ethernet::Mac;
16use net_types::ip::{Ipv4Addr, Ipv6Addr};
17use packet::{ParsablePacket, ParseBuffer, SliceBufViewMut};
18
19use crate::error::{IpParseResult, ParseError, ParseResult};
20use crate::ethernet::{EtherType, EthernetFrame, EthernetFrameLengthCheck};
21use crate::icmp::{IcmpIpExt, IcmpMessage, IcmpPacket, IcmpParseArgs, Icmpv6PacketRaw};
22use crate::ip::{DscpAndEcn, IpExt, Ipv4Proto};
23use crate::ipv4::{Ipv4FragmentType, Ipv4Header, Ipv4Packet};
24use crate::ipv6::{Ipv6Header, Ipv6Packet};
25use crate::tcp::options::TcpOption;
26use crate::tcp::TcpSegment;
27use crate::udp::UdpPacket;
28
29#[cfg(test)]
30pub(crate) use crateonly::*;
31
32#[allow(missing_docs)]
34pub struct EthernetFrameMetadata {
35 pub src_mac: Mac,
36 pub dst_mac: Mac,
37 pub ethertype: Option<EtherType>,
38}
39
40#[allow(missing_docs)]
42pub struct Ipv4PacketMetadata {
43 pub id: u16,
44 pub dscp_and_ecn: DscpAndEcn,
45 pub dont_fragment: bool,
46 pub more_fragments: bool,
47 pub fragment_offset: u16,
48 pub fragment_type: Ipv4FragmentType,
49 pub ttl: u8,
50 pub proto: Ipv4Proto,
51 pub src_ip: Ipv4Addr,
52 pub dst_ip: Ipv4Addr,
53}
54
55#[allow(missing_docs)]
57pub struct Ipv6PacketMetadata {
58 pub dscp_and_ecn: DscpAndEcn,
59 pub flowlabel: u32,
60 pub hop_limit: u8,
61 pub src_ip: Ipv6Addr,
62 pub dst_ip: Ipv6Addr,
63}
64
65#[allow(missing_docs)]
67pub struct TcpSegmentMetadata {
68 pub src_port: u16,
69 pub dst_port: u16,
70 pub seq_num: u32,
71 pub ack_num: Option<u32>,
72 pub flags: u16,
73 pub psh: bool,
74 pub rst: bool,
75 pub syn: bool,
76 pub fin: bool,
77 pub window_size: u16,
78 pub options: &'static [TcpOption<'static>],
79}
80
81#[allow(missing_docs)]
83pub struct UdpPacketMetadata {
84 pub src_port: u16,
85 pub dst_port: u16,
86}
87
88#[allow(missing_docs)]
93pub struct TestPacket<M> {
94 pub bytes: &'static [u8],
95 pub metadata: M,
96 pub body_range: Range<usize>,
97}
98
99pub fn verify_ethernet_frame(
103 frame: &EthernetFrame<&[u8]>,
104 expected: TestPacket<EthernetFrameMetadata>,
105) {
106 assert_eq!(frame.src_mac(), expected.metadata.src_mac);
107 assert_eq!(frame.dst_mac(), expected.metadata.dst_mac);
108 assert_eq!(frame.ethertype(), expected.metadata.ethertype);
109 assert_eq!(frame.body(), &expected.bytes[expected.body_range]);
110}
111
112pub fn verify_ipv4_packet(packet: &Ipv4Packet<&[u8]>, expected: TestPacket<Ipv4PacketMetadata>) {
116 assert_eq!(packet.dscp_and_ecn(), expected.metadata.dscp_and_ecn);
117 assert_eq!(packet.id(), expected.metadata.id);
118 assert_eq!(packet.df_flag(), expected.metadata.dont_fragment);
119 assert_eq!(packet.mf_flag(), expected.metadata.more_fragments);
120 assert_eq!(packet.fragment_offset().into_raw(), expected.metadata.fragment_offset);
121 assert_eq!(packet.ttl(), expected.metadata.ttl);
122 assert_eq!(packet.proto(), expected.metadata.proto);
123 assert_eq!(packet.src_ip(), expected.metadata.src_ip);
124 assert_eq!(packet.dst_ip(), expected.metadata.dst_ip);
125 assert_eq!(packet.body(), &expected.bytes[expected.body_range]);
126}
127
128pub fn verify_ipv6_packet(packet: &Ipv6Packet<&[u8]>, expected: TestPacket<Ipv6PacketMetadata>) {
132 assert_eq!(packet.dscp_and_ecn(), expected.metadata.dscp_and_ecn);
133 assert_eq!(packet.flowlabel(), expected.metadata.flowlabel);
134 assert_eq!(packet.hop_limit(), expected.metadata.hop_limit);
135 assert_eq!(packet.src_ip(), expected.metadata.src_ip);
136 assert_eq!(packet.dst_ip(), expected.metadata.dst_ip);
137 assert_eq!(packet.body(), &expected.bytes[expected.body_range]);
138}
139
140pub fn verify_udp_packet(packet: &UdpPacket<&[u8]>, expected: TestPacket<UdpPacketMetadata>) {
144 assert_eq!(packet.src_port().map(NonZeroU16::get).unwrap_or(0), expected.metadata.src_port);
145 assert_eq!(packet.dst_port().get(), expected.metadata.dst_port);
146 assert_eq!(packet.body(), &expected.bytes[expected.body_range]);
147}
148
149pub fn verify_tcp_segment(segment: &TcpSegment<&[u8]>, expected: TestPacket<TcpSegmentMetadata>) {
153 assert_eq!(segment.src_port().get(), expected.metadata.src_port);
154 assert_eq!(segment.dst_port().get(), expected.metadata.dst_port);
155 assert_eq!(segment.seq_num(), expected.metadata.seq_num);
156 assert_eq!(segment.ack_num(), expected.metadata.ack_num);
157 assert_eq!(segment.rst(), expected.metadata.rst);
158 assert_eq!(segment.syn(), expected.metadata.syn);
159 assert_eq!(segment.fin(), expected.metadata.fin);
160 assert_eq!(segment.window_size(), expected.metadata.window_size);
161 assert_eq!(segment.iter_options().collect::<Vec<_>>().as_slice(), expected.metadata.options);
162 assert_eq!(segment.body(), &expected.bytes[expected.body_range]);
163}
164
165pub fn parse_ethernet_frame(
170 mut buf: &[u8],
171 ethernet_length_check: EthernetFrameLengthCheck,
172) -> ParseResult<(&[u8], Mac, Mac, Option<EtherType>)> {
173 let frame = (&mut buf).parse_with::<_, EthernetFrame<_>>(ethernet_length_check)?;
174 let src_mac = frame.src_mac();
175 let dst_mac = frame.dst_mac();
176 let ethertype = frame.ethertype();
177 Ok((buf, src_mac, dst_mac, ethertype))
178}
179
180#[allow(clippy::type_complexity)]
185pub fn parse_ip_packet<I: IpExt>(
186 mut buf: &[u8],
187) -> IpParseResult<I, (&[u8], I::Addr, I::Addr, I::Proto, u8)> {
188 use crate::ip::IpPacket;
189
190 let packet = (&mut buf).parse::<I::Packet<_>>()?;
191 let src_ip = packet.src_ip();
192 let dst_ip = packet.dst_ip();
193 let proto = packet.proto();
194 let ttl = packet.ttl();
195 core::mem::drop(packet);
201 Ok((buf, src_ip, dst_ip, proto, ttl))
202}
203
204pub fn parse_icmp_packet<
210 I: IcmpIpExt,
211 C,
212 M: IcmpMessage<I, Code = C>,
213 F: for<'a> FnOnce(&IcmpPacket<I, &'a [u8], M>),
214>(
215 mut buf: &[u8],
216 src_ip: I::Addr,
217 dst_ip: I::Addr,
218 f: F,
219) -> ParseResult<(M, C)>
220where
221 for<'a> IcmpPacket<I, &'a [u8], M>:
222 ParsablePacket<&'a [u8], IcmpParseArgs<I::Addr>, Error = ParseError>,
223{
224 let packet =
225 (&mut buf).parse_with::<_, IcmpPacket<I, _, M>>(IcmpParseArgs::new(src_ip, dst_ip))?;
226 let message = *packet.message();
227 let code = packet.code();
228 f(&packet);
229 Ok((message, code))
230}
231
232#[allow(clippy::type_complexity)]
238pub fn parse_ip_packet_in_ethernet_frame<I: IpExt>(
239 buf: &[u8],
240 ethernet_length_check: EthernetFrameLengthCheck,
241) -> IpParseResult<I, (&[u8], Mac, Mac, I::Addr, I::Addr, I::Proto, u8)> {
242 let (body, src_mac, dst_mac, ethertype) = parse_ethernet_frame(buf, ethernet_length_check)?;
243 if ethertype != Some(I::ETHER_TYPE) {
244 debug!("unexpected ethertype: {:?}", ethertype);
245 return Err(ParseError::NotExpected.into());
246 }
247
248 let (body, src_ip, dst_ip, proto, ttl) = parse_ip_packet::<I>(body)?;
249 Ok((body, src_mac, dst_mac, src_ip, dst_ip, proto, ttl))
250}
251
252#[allow(clippy::type_complexity)]
259pub fn parse_icmp_packet_in_ip_packet_in_ethernet_frame<
260 I: IpExt,
261 C,
262 M: IcmpMessage<I, Code = C>,
263 F: for<'a> FnOnce(&IcmpPacket<I, &'a [u8], M>),
264>(
265 buf: &[u8],
266 ethernet_length_check: EthernetFrameLengthCheck,
267 f: F,
268) -> IpParseResult<I, (Mac, Mac, I::Addr, I::Addr, u8, M, C)>
269where
270 for<'a> IcmpPacket<I, &'a [u8], M>:
271 ParsablePacket<&'a [u8], IcmpParseArgs<I::Addr>, Error = ParseError>,
272{
273 let (body, src_mac, dst_mac, src_ip, dst_ip, proto, ttl) =
274 parse_ip_packet_in_ethernet_frame::<I>(buf, ethernet_length_check)?;
275 if proto != I::ICMP_IP_PROTO {
276 debug!("unexpected IP protocol: {} (wanted {})", proto, I::ICMP_IP_PROTO);
277 return Err(ParseError::NotExpected.into());
278 }
279 let (message, code) = parse_icmp_packet(body, src_ip, dst_ip, f)?;
280 Ok((src_mac, dst_mac, src_ip, dst_ip, ttl, message, code))
281}
282
283pub fn overwrite_icmpv6_checksum(buf: &mut [u8], checksum: [u8; 2]) -> ParseResult<[u8; 2]> {
287 let buf = SliceBufViewMut::new(buf);
288 let mut message = Icmpv6PacketRaw::parse_mut(buf, ())?;
289 Ok(message.overwrite_checksum(checksum))
290}
291
292#[cfg(test)]
293mod crateonly {
294 use std::sync::Once;
295
296 pub(crate) fn set_logger_for_test() {
302 struct Logger;
306
307 impl log::Log for Logger {
308 fn enabled(&self, _metadata: &log::Metadata<'_>) -> bool {
309 true
310 }
311
312 fn log(&self, record: &log::Record<'_>) {
313 println!("{}", record.args())
314 }
315
316 fn flush(&self) {}
317 }
318 static LOGGER_ONCE: Once = Once::new();
319
320 LOGGER_ONCE.call_once(|| {
323 log::set_logger(&Logger).unwrap();
324 log::set_max_level(log::LevelFilter::Trace);
325 })
326 }
327
328 pub(crate) mod benchmarks {
337 pub(crate) trait Bencher {
339 fn iter<T, F: FnMut() -> T>(&mut self, inner: F);
340 }
341
342 #[cfg(feature = "benchmark")]
343 impl Bencher for test::Bencher {
344 fn iter<T, F: FnMut() -> T>(&mut self, inner: F) {
345 test::Bencher::iter(self, inner)
346 }
347 }
348
349 #[cfg(not(feature = "benchmark"))]
351 pub(crate) struct TestBencher;
352
353 #[cfg(not(feature = "benchmark"))]
354 impl Bencher for TestBencher {
355 fn iter<T, F: FnMut() -> T>(&mut self, mut inner: F) {
356 super::set_logger_for_test();
357 let _: T = inner();
358 }
359 }
360
361 #[inline(always)]
362 pub(crate) fn black_box<T>(dummy: T) -> T {
363 #[cfg(feature = "benchmark")]
364 return test::black_box(dummy);
365 #[cfg(not(feature = "benchmark"))]
366 return dummy;
367 }
368 }
369}
370
371#[cfg(test)]
372mod tests {
373 use net_types::ip::{Ipv4, Ipv6};
374
375 use crate::icmp::{IcmpDestUnreachable, IcmpEchoReply, Icmpv4DestUnreachableCode};
376 use crate::ip::Ipv6Proto;
377
378 use super::*;
379
380 #[test]
381 fn test_parse_ethernet_frame() {
382 use crate::testdata::arp_request::*;
383 let (body, src_mac, dst_mac, ethertype) =
384 parse_ethernet_frame(ETHERNET_FRAME.bytes, EthernetFrameLengthCheck::Check).unwrap();
385 assert_eq!(body, ÐERNET_FRAME.bytes[14..]);
386 assert_eq!(src_mac, ETHERNET_FRAME.metadata.src_mac);
387 assert_eq!(dst_mac, ETHERNET_FRAME.metadata.dst_mac);
388 assert_eq!(ethertype, ETHERNET_FRAME.metadata.ethertype);
389 }
390
391 #[test]
392 fn test_parse_ip_packet() {
393 use crate::testdata::icmp_redirect::IP_PACKET_BYTES;
394 let (body, src_ip, dst_ip, proto, ttl) = parse_ip_packet::<Ipv4>(IP_PACKET_BYTES).unwrap();
395 assert_eq!(body, &IP_PACKET_BYTES[20..]);
396 assert_eq!(src_ip, Ipv4Addr::new([10, 123, 0, 2]));
397 assert_eq!(dst_ip, Ipv4Addr::new([10, 123, 0, 1]));
398 assert_eq!(proto, Ipv4Proto::Icmp);
399 assert_eq!(ttl, 255);
400
401 use crate::testdata::icmp_echo_v6::REQUEST_IP_PACKET_BYTES;
402 let (body, src_ip, dst_ip, proto, ttl) =
403 parse_ip_packet::<Ipv6>(REQUEST_IP_PACKET_BYTES).unwrap();
404 assert_eq!(body, &REQUEST_IP_PACKET_BYTES[40..]);
405 assert_eq!(src_ip, Ipv6Addr::new([0, 0, 0, 0, 0, 0, 0, 1]));
406 assert_eq!(dst_ip, Ipv6Addr::new([0xfec0, 0, 0, 0, 0, 0, 0, 0]));
407 assert_eq!(proto, Ipv6Proto::Icmpv6);
408 assert_eq!(ttl, 64);
409 }
410
411 #[test]
412 fn test_parse_ip_packet_in_ethernet_frame() {
413 use crate::testdata::tls_client_hello_v4::*;
414 let (body, src_mac, dst_mac, src_ip, dst_ip, proto, ttl) =
415 parse_ip_packet_in_ethernet_frame::<Ipv4>(
416 ETHERNET_FRAME.bytes,
417 EthernetFrameLengthCheck::Check,
418 )
419 .unwrap();
420 assert_eq!(body, &IPV4_PACKET.bytes[IPV4_PACKET.body_range]);
421 assert_eq!(src_mac, ETHERNET_FRAME.metadata.src_mac);
422 assert_eq!(dst_mac, ETHERNET_FRAME.metadata.dst_mac);
423 assert_eq!(src_ip, IPV4_PACKET.metadata.src_ip);
424 assert_eq!(dst_ip, IPV4_PACKET.metadata.dst_ip);
425 assert_eq!(proto, IPV4_PACKET.metadata.proto);
426 assert_eq!(ttl, IPV4_PACKET.metadata.ttl);
427 }
428
429 #[test]
430 fn test_parse_icmp_packet() {
431 set_logger_for_test();
432 use crate::testdata::icmp_dest_unreachable::*;
433 let (body, ..) = parse_ip_packet::<Ipv4>(&IP_PACKET_BYTES).unwrap();
434 let (_, code) = parse_icmp_packet::<Ipv4, _, IcmpDestUnreachable, _>(
435 body,
436 Ipv4Addr::new([172, 217, 6, 46]),
437 Ipv4Addr::new([192, 168, 0, 105]),
438 |_| {},
439 )
440 .unwrap();
441 assert_eq!(code, Icmpv4DestUnreachableCode::DestHostUnreachable);
442 }
443
444 #[test]
445 fn test_parse_icmp_packet_in_ip_packet_in_ethernet_frame() {
446 set_logger_for_test();
447 use crate::testdata::icmp_echo_ethernet::*;
448 let (src_mac, dst_mac, src_ip, dst_ip, _, _, _) =
449 parse_icmp_packet_in_ip_packet_in_ethernet_frame::<Ipv4, _, IcmpEchoReply, _>(
450 &REPLY_ETHERNET_FRAME_BYTES,
451 EthernetFrameLengthCheck::Check,
452 |_| {},
453 )
454 .unwrap();
455 assert_eq!(src_mac, Mac::new([0x50, 0xc7, 0xbf, 0x1d, 0xf4, 0xd2]));
456 assert_eq!(dst_mac, Mac::new([0x8c, 0x85, 0x90, 0xc9, 0xc9, 0x00]));
457 assert_eq!(src_ip, Ipv4Addr::new([172, 217, 6, 46]));
458 assert_eq!(dst_ip, Ipv4Addr::new([192, 168, 0, 105]));
459 }
460}