1#[allow(unused_imports)]
10use alloc::vec::Vec;
11use core::num::NonZeroU16;
12use core::ops::Range;
13use zerocopy::SplitByteSlice;
14
15use log::debug;
16use net_types::ethernet::Mac;
17use net_types::ip::{Ipv4Addr, Ipv6Addr};
18use packet::{ParsablePacket, ParseBuffer, SliceBufViewMut};
19
20use crate::arp::{ArpOp, ArpPacket};
21use crate::error::{IpParseResult, ParseError, ParseResult};
22use crate::ethernet::{EtherType, EthernetFrame, EthernetFrameLengthCheck};
23use crate::icmp::{IcmpIpExt, IcmpMessage, IcmpPacket, IcmpParseArgs, Icmpv6PacketRaw};
24use crate::ip::{DscpAndEcn, IpExt, Ipv4Proto};
25use crate::ipv4::{Ipv4FragmentType, Ipv4Header, Ipv4Packet};
26use crate::ipv6::{Ipv6Header, Ipv6Packet};
27use crate::tcp::options::TcpOption;
28use crate::tcp::TcpSegment;
29use crate::udp::UdpPacket;
30
31#[cfg(test)]
32pub(crate) use crateonly::*;
33
34#[allow(missing_docs)]
36pub struct EthernetFrameMetadata {
37 pub src_mac: Mac,
38 pub dst_mac: Mac,
39 pub ethertype: Option<EtherType>,
40}
41
42#[allow(missing_docs)]
44pub struct Ipv4PacketMetadata {
45 pub id: u16,
46 pub dscp_and_ecn: DscpAndEcn,
47 pub dont_fragment: bool,
48 pub more_fragments: bool,
49 pub fragment_offset: u16,
50 pub fragment_type: Ipv4FragmentType,
51 pub ttl: u8,
52 pub proto: Ipv4Proto,
53 pub src_ip: Ipv4Addr,
54 pub dst_ip: Ipv4Addr,
55}
56
57#[allow(missing_docs)]
59pub struct Ipv6PacketMetadata {
60 pub dscp_and_ecn: DscpAndEcn,
61 pub flowlabel: u32,
62 pub hop_limit: u8,
63 pub src_ip: Ipv6Addr,
64 pub dst_ip: Ipv6Addr,
65}
66
67#[allow(missing_docs)]
69pub struct TcpSegmentMetadata {
70 pub src_port: u16,
71 pub dst_port: u16,
72 pub seq_num: u32,
73 pub ack_num: Option<u32>,
74 pub flags: u16,
75 pub psh: bool,
76 pub rst: bool,
77 pub syn: bool,
78 pub fin: bool,
79 pub window_size: u16,
80 pub options: &'static [TcpOption<'static>],
81}
82
83#[allow(missing_docs)]
85pub struct UdpPacketMetadata {
86 pub src_port: u16,
87 pub dst_port: u16,
88}
89
90#[allow(missing_docs)]
95pub struct TestPacket<M> {
96 pub bytes: &'static [u8],
97 pub metadata: M,
98 pub body_range: Range<usize>,
99}
100
101pub fn verify_ethernet_frame(
105 frame: &EthernetFrame<&[u8]>,
106 expected: TestPacket<EthernetFrameMetadata>,
107) {
108 assert_eq!(frame.src_mac(), expected.metadata.src_mac);
109 assert_eq!(frame.dst_mac(), expected.metadata.dst_mac);
110 assert_eq!(frame.ethertype(), expected.metadata.ethertype);
111 assert_eq!(frame.body(), &expected.bytes[expected.body_range]);
112}
113
114pub fn verify_ipv4_packet(packet: &Ipv4Packet<&[u8]>, expected: TestPacket<Ipv4PacketMetadata>) {
118 assert_eq!(packet.dscp_and_ecn(), expected.metadata.dscp_and_ecn);
119 assert_eq!(packet.id(), expected.metadata.id);
120 assert_eq!(packet.df_flag(), expected.metadata.dont_fragment);
121 assert_eq!(packet.mf_flag(), expected.metadata.more_fragments);
122 assert_eq!(packet.fragment_offset().into_raw(), expected.metadata.fragment_offset);
123 assert_eq!(packet.ttl(), expected.metadata.ttl);
124 assert_eq!(packet.proto(), expected.metadata.proto);
125 assert_eq!(packet.src_ip(), expected.metadata.src_ip);
126 assert_eq!(packet.dst_ip(), expected.metadata.dst_ip);
127 assert_eq!(packet.body(), &expected.bytes[expected.body_range]);
128}
129
130pub fn verify_ipv6_packet(packet: &Ipv6Packet<&[u8]>, expected: TestPacket<Ipv6PacketMetadata>) {
134 assert_eq!(packet.dscp_and_ecn(), expected.metadata.dscp_and_ecn);
135 assert_eq!(packet.flowlabel(), expected.metadata.flowlabel);
136 assert_eq!(packet.hop_limit(), expected.metadata.hop_limit);
137 assert_eq!(packet.src_ip(), expected.metadata.src_ip);
138 assert_eq!(packet.dst_ip(), expected.metadata.dst_ip);
139 assert_eq!(packet.body(), &expected.bytes[expected.body_range]);
140}
141
142pub fn verify_udp_packet(packet: &UdpPacket<&[u8]>, expected: TestPacket<UdpPacketMetadata>) {
146 assert_eq!(packet.src_port().map(NonZeroU16::get).unwrap_or(0), expected.metadata.src_port);
147 assert_eq!(packet.dst_port().get(), expected.metadata.dst_port);
148 assert_eq!(packet.body(), &expected.bytes[expected.body_range]);
149}
150
151pub fn verify_tcp_segment(segment: &TcpSegment<&[u8]>, expected: TestPacket<TcpSegmentMetadata>) {
155 assert_eq!(segment.src_port().get(), expected.metadata.src_port);
156 assert_eq!(segment.dst_port().get(), expected.metadata.dst_port);
157 assert_eq!(segment.seq_num(), expected.metadata.seq_num);
158 assert_eq!(segment.ack_num(), expected.metadata.ack_num);
159 assert_eq!(segment.rst(), expected.metadata.rst);
160 assert_eq!(segment.syn(), expected.metadata.syn);
161 assert_eq!(segment.fin(), expected.metadata.fin);
162 assert_eq!(segment.window_size(), expected.metadata.window_size);
163 assert_eq!(segment.iter_options().collect::<Vec<_>>().as_slice(), expected.metadata.options);
164 assert_eq!(segment.body(), &expected.bytes[expected.body_range]);
165}
166
167pub fn parse_ethernet_frame(
172 mut buf: &[u8],
173 ethernet_length_check: EthernetFrameLengthCheck,
174) -> ParseResult<(&[u8], Mac, Mac, Option<EtherType>)> {
175 let frame = (&mut buf).parse_with::<_, EthernetFrame<_>>(ethernet_length_check)?;
176 let src_mac = frame.src_mac();
177 let dst_mac = frame.dst_mac();
178 let ethertype = frame.ethertype();
179 Ok((buf, src_mac, dst_mac, ethertype))
180}
181
182#[allow(missing_docs)]
184pub struct ArpPacketInfo {
185 pub sender_hardware_address: Mac,
186 pub sender_protocol_address: Ipv4Addr,
187 pub target_hardware_address: Mac,
188 pub target_protocol_address: Ipv4Addr,
189 pub operation: ArpOp,
190}
191
192impl<B: SplitByteSlice> From<ArpPacket<B, Mac, Ipv4Addr>> for ArpPacketInfo {
193 fn from(packet: ArpPacket<B, Mac, Ipv4Addr>) -> ArpPacketInfo {
194 ArpPacketInfo {
195 sender_hardware_address: packet.sender_hardware_address(),
196 sender_protocol_address: packet.sender_protocol_address(),
197 target_hardware_address: packet.target_hardware_address(),
198 target_protocol_address: packet.target_protocol_address(),
199 operation: packet.operation(),
200 }
201 }
202}
203
204pub fn parse_arp_packet(mut buf: &[u8]) -> ParseResult<ArpPacketInfo> {
206 (&mut buf).parse::<ArpPacket<_, Mac, Ipv4Addr>>().map(ArpPacketInfo::from)
207}
208
209pub fn parse_arp_packet_in_ethernet_frame(
211 buf: &[u8],
212 ethernet_length_check: EthernetFrameLengthCheck,
213) -> ParseResult<ArpPacketInfo> {
214 let (body, _src_mac, _dst_mac, ethertype) = parse_ethernet_frame(buf, ethernet_length_check)?;
215 if ethertype != Some(EtherType::Arp) {
216 debug!("unexpected ethertype: {:?}", ethertype);
217 return Err(ParseError::NotExpected.into());
218 }
219
220 parse_arp_packet(body)
221}
222
223#[allow(clippy::type_complexity)]
228pub fn parse_ip_packet<I: IpExt>(
229 mut buf: &[u8],
230) -> IpParseResult<I, (&[u8], I::Addr, I::Addr, I::Proto, u8)> {
231 use crate::ip::IpPacket;
232
233 let packet = (&mut buf).parse::<I::Packet<_>>()?;
234 let src_ip = packet.src_ip();
235 let dst_ip = packet.dst_ip();
236 let proto = packet.proto();
237 let ttl = packet.ttl();
238 core::mem::drop(packet);
244 Ok((buf, src_ip, dst_ip, proto, ttl))
245}
246
247pub fn parse_icmp_packet<
253 I: IcmpIpExt,
254 C,
255 M: IcmpMessage<I, Code = C>,
256 F: for<'a> FnOnce(&IcmpPacket<I, &'a [u8], M>),
257>(
258 mut buf: &[u8],
259 src_ip: I::Addr,
260 dst_ip: I::Addr,
261 f: F,
262) -> ParseResult<(M, C)>
263where
264 for<'a> IcmpPacket<I, &'a [u8], M>:
265 ParsablePacket<&'a [u8], IcmpParseArgs<I::Addr>, Error = ParseError>,
266{
267 let packet =
268 (&mut buf).parse_with::<_, IcmpPacket<I, _, M>>(IcmpParseArgs::new(src_ip, dst_ip))?;
269 let message = *packet.message();
270 let code = packet.code();
271 f(&packet);
272 Ok((message, code))
273}
274
275#[allow(clippy::type_complexity)]
281pub fn parse_ip_packet_in_ethernet_frame<I: IpExt>(
282 buf: &[u8],
283 ethernet_length_check: EthernetFrameLengthCheck,
284) -> IpParseResult<I, (&[u8], Mac, Mac, I::Addr, I::Addr, I::Proto, u8)> {
285 let (body, src_mac, dst_mac, ethertype) = parse_ethernet_frame(buf, ethernet_length_check)?;
286 if ethertype != Some(I::ETHER_TYPE) {
287 debug!("unexpected ethertype: {:?}", ethertype);
288 return Err(ParseError::NotExpected.into());
289 }
290
291 let (body, src_ip, dst_ip, proto, ttl) = parse_ip_packet::<I>(body)?;
292 Ok((body, src_mac, dst_mac, src_ip, dst_ip, proto, ttl))
293}
294
295#[allow(clippy::type_complexity)]
302pub fn parse_icmp_packet_in_ip_packet_in_ethernet_frame<
303 I: IpExt,
304 C,
305 M: IcmpMessage<I, Code = C>,
306 F: for<'a> FnOnce(&IcmpPacket<I, &'a [u8], M>),
307>(
308 buf: &[u8],
309 ethernet_length_check: EthernetFrameLengthCheck,
310 f: F,
311) -> IpParseResult<I, (Mac, Mac, I::Addr, I::Addr, u8, M, C)>
312where
313 for<'a> IcmpPacket<I, &'a [u8], M>:
314 ParsablePacket<&'a [u8], IcmpParseArgs<I::Addr>, Error = ParseError>,
315{
316 let (body, src_mac, dst_mac, src_ip, dst_ip, proto, ttl) =
317 parse_ip_packet_in_ethernet_frame::<I>(buf, ethernet_length_check)?;
318 if proto != I::ICMP_IP_PROTO {
319 debug!("unexpected IP protocol: {} (wanted {})", proto, I::ICMP_IP_PROTO);
320 return Err(ParseError::NotExpected.into());
321 }
322 let (message, code) = parse_icmp_packet(body, src_ip, dst_ip, f)?;
323 Ok((src_mac, dst_mac, src_ip, dst_ip, ttl, message, code))
324}
325
326pub fn overwrite_icmpv6_checksum(buf: &mut [u8], checksum: [u8; 2]) -> ParseResult<[u8; 2]> {
330 let buf = SliceBufViewMut::new(buf);
331 let mut message = Icmpv6PacketRaw::parse_mut(buf, ())?;
332 Ok(message.overwrite_checksum(checksum))
333}
334
335#[cfg(test)]
336mod crateonly {
337 use std::sync::Once;
338
339 pub(crate) fn set_logger_for_test() {
345 struct Logger;
349
350 impl log::Log for Logger {
351 fn enabled(&self, _metadata: &log::Metadata<'_>) -> bool {
352 true
353 }
354
355 fn log(&self, record: &log::Record<'_>) {
356 println!("{}", record.args())
357 }
358
359 fn flush(&self) {}
360 }
361 static LOGGER_ONCE: Once = Once::new();
362
363 LOGGER_ONCE.call_once(|| {
366 log::set_logger(&Logger).unwrap();
367 log::set_max_level(log::LevelFilter::Trace);
368 })
369 }
370
371 pub(crate) mod benchmarks {
380 pub(crate) trait Bencher {
382 fn iter<T, F: FnMut() -> T>(&mut self, inner: F);
383 }
384
385 #[cfg(feature = "benchmark")]
386 impl Bencher for test::Bencher {
387 fn iter<T, F: FnMut() -> T>(&mut self, inner: F) {
388 test::Bencher::iter(self, inner)
389 }
390 }
391
392 #[cfg(not(feature = "benchmark"))]
394 pub(crate) struct TestBencher;
395
396 #[cfg(not(feature = "benchmark"))]
397 impl Bencher for TestBencher {
398 fn iter<T, F: FnMut() -> T>(&mut self, mut inner: F) {
399 super::set_logger_for_test();
400 let _: T = inner();
401 }
402 }
403
404 #[inline(always)]
405 pub(crate) fn black_box<T>(dummy: T) -> T {
406 #[cfg(feature = "benchmark")]
407 return test::black_box(dummy);
408 #[cfg(not(feature = "benchmark"))]
409 return dummy;
410 }
411 }
412}
413
414#[cfg(test)]
415mod tests {
416 use net_types::ip::{Ipv4, Ipv6};
417
418 use crate::icmp::{IcmpDestUnreachable, IcmpEchoReply, Icmpv4DestUnreachableCode};
419 use crate::ip::Ipv6Proto;
420
421 use super::*;
422
423 #[test]
424 fn test_parse_ethernet_frame() {
425 use crate::testdata::arp_request::*;
426 let (body, src_mac, dst_mac, ethertype) =
427 parse_ethernet_frame(ETHERNET_FRAME.bytes, EthernetFrameLengthCheck::Check).unwrap();
428 assert_eq!(body, ÐERNET_FRAME.bytes[14..]);
429 assert_eq!(src_mac, ETHERNET_FRAME.metadata.src_mac);
430 assert_eq!(dst_mac, ETHERNET_FRAME.metadata.dst_mac);
431 assert_eq!(ethertype, ETHERNET_FRAME.metadata.ethertype);
432 }
433
434 #[test]
435 fn test_parse_ip_packet() {
436 use crate::testdata::icmp_redirect::IP_PACKET_BYTES;
437 let (body, src_ip, dst_ip, proto, ttl) = parse_ip_packet::<Ipv4>(IP_PACKET_BYTES).unwrap();
438 assert_eq!(body, &IP_PACKET_BYTES[20..]);
439 assert_eq!(src_ip, Ipv4Addr::new([10, 123, 0, 2]));
440 assert_eq!(dst_ip, Ipv4Addr::new([10, 123, 0, 1]));
441 assert_eq!(proto, Ipv4Proto::Icmp);
442 assert_eq!(ttl, 255);
443
444 use crate::testdata::icmp_echo_v6::REQUEST_IP_PACKET_BYTES;
445 let (body, src_ip, dst_ip, proto, ttl) =
446 parse_ip_packet::<Ipv6>(REQUEST_IP_PACKET_BYTES).unwrap();
447 assert_eq!(body, &REQUEST_IP_PACKET_BYTES[40..]);
448 assert_eq!(src_ip, Ipv6Addr::new([0, 0, 0, 0, 0, 0, 0, 1]));
449 assert_eq!(dst_ip, Ipv6Addr::new([0xfec0, 0, 0, 0, 0, 0, 0, 0]));
450 assert_eq!(proto, Ipv6Proto::Icmpv6);
451 assert_eq!(ttl, 64);
452 }
453
454 #[test]
455 fn test_parse_ip_packet_in_ethernet_frame() {
456 use crate::testdata::tls_client_hello_v4::*;
457 let (body, src_mac, dst_mac, src_ip, dst_ip, proto, ttl) =
458 parse_ip_packet_in_ethernet_frame::<Ipv4>(
459 ETHERNET_FRAME.bytes,
460 EthernetFrameLengthCheck::Check,
461 )
462 .unwrap();
463 assert_eq!(body, &IPV4_PACKET.bytes[IPV4_PACKET.body_range]);
464 assert_eq!(src_mac, ETHERNET_FRAME.metadata.src_mac);
465 assert_eq!(dst_mac, ETHERNET_FRAME.metadata.dst_mac);
466 assert_eq!(src_ip, IPV4_PACKET.metadata.src_ip);
467 assert_eq!(dst_ip, IPV4_PACKET.metadata.dst_ip);
468 assert_eq!(proto, IPV4_PACKET.metadata.proto);
469 assert_eq!(ttl, IPV4_PACKET.metadata.ttl);
470 }
471
472 #[test]
473 fn test_parse_icmp_packet() {
474 set_logger_for_test();
475 use crate::testdata::icmp_dest_unreachable::*;
476 let (body, ..) = parse_ip_packet::<Ipv4>(&IP_PACKET_BYTES).unwrap();
477 let (_, code) = parse_icmp_packet::<Ipv4, _, IcmpDestUnreachable, _>(
478 body,
479 Ipv4Addr::new([172, 217, 6, 46]),
480 Ipv4Addr::new([192, 168, 0, 105]),
481 |_| {},
482 )
483 .unwrap();
484 assert_eq!(code, Icmpv4DestUnreachableCode::DestHostUnreachable);
485 }
486
487 #[test]
488 fn test_parse_icmp_packet_in_ip_packet_in_ethernet_frame() {
489 set_logger_for_test();
490 use crate::testdata::icmp_echo_ethernet::*;
491 let (src_mac, dst_mac, src_ip, dst_ip, _, _, _) =
492 parse_icmp_packet_in_ip_packet_in_ethernet_frame::<Ipv4, _, IcmpEchoReply, _>(
493 &REPLY_ETHERNET_FRAME_BYTES,
494 EthernetFrameLengthCheck::Check,
495 |_| {},
496 )
497 .unwrap();
498 assert_eq!(src_mac, Mac::new([0x50, 0xc7, 0xbf, 0x1d, 0xf4, 0xd2]));
499 assert_eq!(dst_mac, Mac::new([0x8c, 0x85, 0x90, 0xc9, 0xc9, 0x00]));
500 assert_eq!(src_ip, Ipv4Addr::new([172, 217, 6, 46]));
501 assert_eq!(dst_ip, Ipv4Addr::new([192, 168, 0, 105]));
502 }
503}