Skip to main content

packet_strata/
packet.rs

1use smallvec::SmallVec;
2use std::fmt;
3use std::mem;
4use thiserror::Error;
5use zerocopy::{FromBytes, Immutable, KnownLayout, Ref, Unaligned};
6
7use crate::packet::{
8    arp::{ArpHeader, ArpHeaderFull},
9    detect::{
10        detect_gre_variant, detect_mpls_inner_protocol, detect_udp_tunnel,
11        find_ipv6_upper_protocol, is_stt_port, NextLayer, TunnelType,
12    },
13    ether::EtherHeader,
14    header::{LinkLayer, NetworkLayer, NetworkTunnelLayer, TransportLayer, TunnelLayer},
15    icmp::IcmpHeader,
16    icmp6::Icmp6Header,
17    ipv4::Ipv4Header,
18    ipv6::Ipv6Header,
19    iter::LinkType,
20    null::NullHeader,
21    protocol::{EtherProto, IpProto},
22    sctp::SctpHeader,
23    sll::{SllHeader, Sllv2Header},
24    tcp::TcpHeader,
25    tunnel::{
26        geneve::GeneveHeader,
27        gre::GreHeader,
28        gtpv1::Gtpv1Header,
29        gtpv2::Gtpv2Header,
30        ipip::IpipTunnel,
31        l2tp::{L2tpv2Header, L2tpv3SessionHeader},
32        mpls::MplsLabelStack,
33        nvgre::NvgreHeader,
34        pbb::PbbHeader,
35        pptp::PptpGreHeader,
36        stt::SttPacket,
37        teredo::TeredoPacket,
38        vxlan::VxlanHeader,
39    },
40    udp::UdpHeader,
41};
42
43pub mod arp;
44pub mod detect;
45pub mod dhcp;
46pub mod ether;
47pub mod header;
48pub mod icmp;
49pub mod icmp6;
50pub mod ipv4;
51pub mod ipv6;
52pub mod iter;
53pub mod null;
54pub mod protocol;
55pub mod sctp;
56pub mod sll;
57pub mod tcp;
58pub mod tunnel;
59pub mod udp;
60
61#[derive(Debug, Clone, Error)]
62pub enum PacketHeaderError {
63    #[error("buffer too short for {0}")]
64    TooShort(&'static str),
65    #[error("invalid {0}")]
66    Invalid(&'static str),
67    #[error("insufficient buffer length for {0}")]
68    InsufficientLength(&'static str),
69    #[error("{0}")]
70    Other(&'static str),
71}
72
73pub trait PacketHeader: Sized {
74    const FIXED_LEN: usize = mem::size_of::<Self>();
75    const NAME: &'static str;
76    type InnerType;
77
78    /// return the inner type of the header
79    fn inner_type(&self) -> Self::InnerType;
80
81    /// Returns the length of the network layer header
82    /// For protocols with variable-length headers (like IPv6 with extensions),
83    /// the buffer is needed to calculate the correct length
84    fn total_len(&self, buf: &[u8]) -> usize {
85        let _ = buf; // Suppress unused warning for implementations that don't need it
86        Self::FIXED_LEN
87    }
88
89    /// check whether the network layer header is valid
90    #[inline]
91    fn is_valid(&self) -> bool {
92        true
93    }
94}
95
96pub trait HeaderParser: PacketHeader + FromBytes + KnownLayout + Immutable + Unaligned {
97    /// The high-level view returned to the user.
98    /// Can be `&'a Self` for fixed headers or a custom wrapper<'a> for variable ones.
99    type Output<'a>
100    where
101        Self: 'a;
102
103    /// Transform the raw struct and the options slice into the Output type.
104    fn into_view<'a>(header: &'a Self, options: &'a [u8]) -> Self::Output<'a>;
105
106    /// parse the network layer, ensuring validity and length
107    #[inline]
108    fn from_bytes<'a>(buf: &'a [u8]) -> Result<(Self::Output<'a>, &'a [u8]), PacketHeaderError> {
109        // 1. Parse fixed part
110        let (header_ref, rest_buf) = Ref::<_, Self>::from_prefix(buf)
111            .map_err(|_| PacketHeaderError::TooShort(Self::NAME))?;
112
113        if !header_ref.is_valid() {
114            return Err(PacketHeaderError::Invalid(Self::NAME));
115        }
116
117        let header = Ref::into_ref(header_ref);
118
119        // 3. Calculate dynamic length
120        // We use the header itself to figure out how big it is
121        let total_len = header.total_len(buf);
122
123        let options_len = total_len - Self::FIXED_LEN;
124
125        // 4. Check if we have enough bytes for the options
126        if rest_buf.len() < options_len {
127            return Err(PacketHeaderError::TooShort(Self::NAME));
128        }
129
130        // 5. Split options and payload
131        let (options, payload) = rest_buf.split_at(options_len);
132
133        // 6. Construct the specific view using the hook
134        let view = Self::into_view(header, options);
135
136        Ok((view, payload))
137    }
138}
139
140/// Maximum number of tunnel layers stored inline (without heap allocation)
141const MAX_INLINE_TUNNELS: usize = 4;
142
143/// Parse mode for packet parsing
144#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
145pub enum ParseMode {
146    /// Keep outermost headers only. Tunnels are ignored and treated as payload.
147    /// The tunnel vector will be empty.
148    #[default]
149    Outermost,
150    /// Parse through tunnels and keep innermost headers.
151    /// Tunnel headers are accumulated in the tunnel vector.
152    /// Network and transport layers are overwritten with inner packet headers.
153    Innermost,
154}
155
156/// Result from network layer parsing
157enum NetworkResult<'a> {
158    Network(NetworkLayer<'a>, NextLayer, &'a [u8]),
159    Arp(ArpHeaderFull<'a>, &'a [u8]),
160    Tunnel(NextLayer, &'a [u8]),
161    IpipTunnel(IpipTunnel<'a>, NextLayer, &'a [u8]),
162    Mpls(MplsLabelStack<'a>, NextLayer, &'a [u8]),
163    Done(&'a [u8]),
164}
165
166/// Result from transport layer parsing
167enum TransportResult<'a> {
168    Transport(TransportLayer<'a>, NextLayer, &'a [u8]),
169    Icmp(&'a IcmpHeader, &'a [u8]),
170    Icmp6(&'a Icmp6Header, &'a [u8]),
171    Tunnel(NextLayer, &'a [u8]),
172    Done(&'a [u8]),
173}
174
175#[derive(Debug, Clone)]
176pub struct Packet<'a> {
177    link: LinkLayer<'a>,
178    arp: Option<ArpHeaderFull<'a>>,
179    network: Option<NetworkLayer<'a>>,
180    transport: Option<TransportLayer<'a>>,
181    tunnel: SmallVec<[NetworkTunnelLayer<'a>; MAX_INLINE_TUNNELS]>,
182    data: &'a [u8],
183}
184
185impl<'a> Packet<'a> {
186    /// Parse a packet from raw bytes using the specified link type and parse mode.
187    ///
188    /// This method directly parses all protocol layers without using an iterator,
189    /// collecting them into a structured `Packet`.
190    ///
191    /// # Arguments
192    ///
193    /// * `buf` - The raw packet bytes
194    /// * `link_type` - The link layer type of the packet
195    /// * `mode` - Parse mode: `Outermost` ignores tunnels, `Innermost` parses through them
196    #[inline]
197    pub fn from_bytes(
198        buf: &'a [u8],
199        link_type: LinkType,
200        mode: ParseMode,
201    ) -> Result<Self, PacketHeaderError> {
202        let mut remaining = buf;
203        let mut next_layer = NextLayer::Link(link_type);
204
205        let mut link: Option<LinkLayer<'a>> = None;
206        let mut arp: Option<ArpHeaderFull<'a>> = None;
207        let mut network: Option<NetworkLayer<'a>> = None;
208        let mut transport: Option<TransportLayer<'a>> = None;
209        let mut tunnel: SmallVec<[NetworkTunnelLayer<'a>; MAX_INLINE_TUNNELS]> = SmallVec::new();
210
211        // Track outer IP for tunnel encapsulation
212        let mut outer_ip_for_tunnel: Option<NetworkLayer<'a>> = None;
213
214        loop {
215            match next_layer {
216                NextLayer::Link(lt) => {
217                    let (link_layer, next, rest) = Self::parse_link(remaining, lt)?;
218                    link = Some(link_layer);
219                    next_layer = next;
220                    remaining = rest;
221                }
222                NextLayer::Network(ether_proto) => {
223                    match Self::parse_network(remaining, ether_proto)? {
224                        NetworkResult::Network(net, next, rest) => {
225                            network = Some(net.clone());
226                            outer_ip_for_tunnel = Some(net);
227                            next_layer = next;
228                            remaining = rest;
229                        }
230                        NetworkResult::Arp(a, rest) => {
231                            arp = Some(a);
232                            next_layer = NextLayer::Done;
233                            remaining = rest;
234                        }
235                        NetworkResult::Tunnel(next, rest) => {
236                            // In Outermost mode, treat tunnel as end of parsing
237                            if mode == ParseMode::Outermost {
238                                next_layer = NextLayer::Done;
239                                remaining = rest;
240                            } else {
241                                next_layer = next;
242                                remaining = rest;
243                            }
244                        }
245                        NetworkResult::IpipTunnel(tun, next, rest) => {
246                            // In Outermost mode, don't enter the tunnel
247                            if mode == ParseMode::Outermost {
248                                // Store the outer IP header as network layer
249                                // The tunnel's outer header is the network layer
250                                next_layer = NextLayer::Done;
251                                remaining = rest;
252                            } else {
253                                // IPIP tunnel already contains outer IP, wrap in IpTunnelLayer
254                                tunnel.push(NetworkTunnelLayer::new_l2(TunnelLayer::Ipip(tun)));
255                                // Reset outer IP since we consumed it
256                                outer_ip_for_tunnel = None;
257                                next_layer = next;
258                                remaining = rest;
259                            }
260                        }
261                        NetworkResult::Mpls(mpls, next, rest) => {
262                            network = Some(NetworkLayer::Mpls(mpls));
263                            // In Outermost mode, stop after MPLS
264                            if mode == ParseMode::Outermost {
265                                next_layer = NextLayer::Done;
266                            } else {
267                                next_layer = next;
268                            }
269                            remaining = rest;
270                        }
271                        NetworkResult::Done(rest) => {
272                            next_layer = NextLayer::Done;
273                            remaining = rest;
274                        }
275                    }
276                }
277                NextLayer::Transport(ip_proto) => {
278                    match Self::parse_transport(remaining, ip_proto, mode)? {
279                        TransportResult::Transport(t, next, rest) => {
280                            transport = Some(t);
281                            next_layer = next;
282                            remaining = rest;
283                        }
284                        TransportResult::Icmp(icmp, rest) => {
285                            transport = Some(TransportLayer::Icmp(icmp));
286                            next_layer = NextLayer::Done;
287                            remaining = rest;
288                        }
289                        TransportResult::Icmp6(icmp6, rest) => {
290                            transport = Some(TransportLayer::Icmp6(icmp6));
291                            next_layer = NextLayer::Done;
292                            remaining = rest;
293                        }
294                        TransportResult::Tunnel(next, rest) => {
295                            // Keep outer_ip_for_tunnel for the upcoming tunnel parsing
296                            next_layer = next;
297                            remaining = rest;
298                        }
299                        TransportResult::Done(rest) => {
300                            next_layer = NextLayer::Done;
301                            remaining = rest;
302                        }
303                    }
304                }
305                NextLayer::Tunnel(tunnel_type) => {
306                    let (tun, next, rest) = Self::parse_tunnel(remaining, tunnel_type)?;
307
308                    // Wrap tunnel with outer IP (if available)
309                    let ip_tunnel = if let Some(outer) = outer_ip_for_tunnel.take() {
310                        NetworkTunnelLayer::new(outer, tun)
311                    } else {
312                        // Layer 2 tunnel (e.g., PBB) without IP encapsulation
313                        NetworkTunnelLayer::new_l2(tun)
314                    };
315
316                    tunnel.push(ip_tunnel);
317
318                    // If we're continuing to parse inner packet, reset network tracking
319                    network = None;
320                    transport = None;
321
322                    next_layer = next;
323                    remaining = rest;
324                }
325                NextLayer::Done => break,
326            }
327        }
328
329        let link = link.ok_or(PacketHeaderError::TooShort("link layer"))?;
330
331        Ok(Packet {
332            link,
333            arp,
334            network,
335            transport,
336            tunnel,
337            data: remaining,
338        })
339    }
340
341    /// Parse link layer
342    #[inline]
343    fn parse_link(
344        buf: &'a [u8],
345        link_type: LinkType,
346    ) -> Result<(LinkLayer<'a>, NextLayer, &'a [u8]), PacketHeaderError> {
347        match link_type {
348            LinkType::Ethernet => {
349                let (eth, rest) = EtherHeader::from_bytes(buf)?;
350                let next_proto = eth.inner_type();
351                Ok((
352                    LinkLayer::Ethernet(eth),
353                    NextLayer::Network(next_proto),
354                    rest,
355                ))
356            }
357            LinkType::Sll => {
358                let (sll, rest) = SllHeader::from_bytes(buf)?;
359                let next_proto = sll.protocol();
360                Ok((LinkLayer::Sll(sll), NextLayer::Network(next_proto), rest))
361            }
362            LinkType::Sllv2 => {
363                let (sll, rest) = Sllv2Header::from_bytes(buf)?;
364                let next_proto = sll.protocol();
365                Ok((LinkLayer::Sllv2(sll), NextLayer::Network(next_proto), rest))
366            }
367            LinkType::Null => {
368                let (null, rest) = NullHeader::from_bytes(buf)?;
369                let next_proto = null.protocol();
370                Ok((LinkLayer::Null(null), NextLayer::Network(next_proto), rest))
371            }
372            LinkType::RawIpv4 => {
373                // Create a dummy null header for raw IP
374                // Actually we need to handle this differently - parse network directly
375                // For RawIpv4/RawIpv6, we don't have a link layer header
376                // We'll create a special case
377                Err(PacketHeaderError::Other(
378                    "RawIpv4 requires special handling",
379                ))
380            }
381            LinkType::RawIpv6 => Err(PacketHeaderError::Other(
382                "RawIpv6 requires special handling",
383            )),
384        }
385    }
386
387    /// Parse network layer
388    #[inline]
389    fn parse_network(
390        buf: &'a [u8],
391        ether_proto: EtherProto,
392    ) -> Result<NetworkResult<'a>, PacketHeaderError> {
393        match ether_proto {
394            EtherProto::IPV4 => {
395                let (ipv4, rest) = Ipv4Header::from_bytes(buf)?;
396                let proto = ipv4.protocol();
397
398                if proto == IpProto::IP_ENCAP {
399                    // IPv4-in-IPv4 tunnel
400                    Ok(NetworkResult::IpipTunnel(
401                        IpipTunnel::ipip(ipv4),
402                        NextLayer::Network(EtherProto::IPV4),
403                        rest,
404                    ))
405                } else if proto == IpProto::IPV6 {
406                    // IPv6-in-IPv4 (SIT) tunnel
407                    Ok(NetworkResult::IpipTunnel(
408                        IpipTunnel::sit(ipv4),
409                        NextLayer::Network(EtherProto::IPV6),
410                        rest,
411                    ))
412                } else {
413                    Ok(NetworkResult::Network(
414                        NetworkLayer::Ipv4(ipv4),
415                        NextLayer::Transport(proto),
416                        rest,
417                    ))
418                }
419            }
420            EtherProto::IPV6 => {
421                let (ipv6, rest) = Ipv6Header::from_bytes(buf)?;
422                let next_proto = find_ipv6_upper_protocol(&ipv6);
423
424                if next_proto == IpProto::IP_ENCAP {
425                    // IPv4-in-IPv6 (IP4in6) tunnel
426                    Ok(NetworkResult::IpipTunnel(
427                        IpipTunnel::ip4in6(ipv6),
428                        NextLayer::Network(EtherProto::IPV4),
429                        rest,
430                    ))
431                } else if next_proto == IpProto::IPV6 {
432                    // IPv6-in-IPv6 (IP6Tnl) tunnel
433                    Ok(NetworkResult::IpipTunnel(
434                        IpipTunnel::ip6tnl(ipv6),
435                        NextLayer::Network(EtherProto::IPV6),
436                        rest,
437                    ))
438                } else {
439                    Ok(NetworkResult::Network(
440                        NetworkLayer::Ipv6(ipv6),
441                        NextLayer::Transport(next_proto),
442                        rest,
443                    ))
444                }
445            }
446            EtherProto::ARP => {
447                let (arp, rest) = ArpHeader::from_bytes(buf)?;
448                Ok(NetworkResult::Arp(arp, rest))
449            }
450            EtherProto::MPLS_UC | EtherProto::MPLS_MC => {
451                // Parse MPLS directly here since it goes into NetworkLayer
452                match MplsLabelStack::parse(buf) {
453                    Some((mpls_stack, payload)) => {
454                        let next = detect_mpls_inner_protocol(payload).unwrap_or(NextLayer::Done);
455                        Ok(NetworkResult::Mpls(mpls_stack, next, payload))
456                    }
457                    None => Err(PacketHeaderError::TooShort("MPLS")),
458                }
459            }
460            EtherProto::TEB => {
461                // Transparent Ethernet Bridging - inner Ethernet frame
462                Ok(NetworkResult::Tunnel(
463                    NextLayer::Link(LinkType::Ethernet),
464                    buf,
465                ))
466            }
467            EtherProto::VLAN_8021AH | EtherProto::VLAN_8021AD => {
468                // PBB (Provider Backbone Bridge / MAC-in-MAC)
469                Ok(NetworkResult::Tunnel(
470                    NextLayer::Tunnel(TunnelType::Pbb),
471                    buf,
472                ))
473            }
474            _ => {
475                // Unknown network protocol - stop parsing
476                Ok(NetworkResult::Done(buf))
477            }
478        }
479    }
480
481    /// Parse transport layer
482    #[inline]
483    fn parse_transport(
484        buf: &'a [u8],
485        ip_proto: IpProto,
486        mode: ParseMode,
487    ) -> Result<TransportResult<'a>, PacketHeaderError> {
488        match ip_proto {
489            IpProto::TCP => {
490                let (tcp, rest) = TcpHeader::from_bytes(buf)?;
491
492                // In Outermost mode, don't detect tunnels
493                if mode == ParseMode::Outermost {
494                    return Ok(TransportResult::Transport(
495                        TransportLayer::Tcp(tcp),
496                        NextLayer::Done,
497                        rest,
498                    ));
499                }
500
501                let src_port = tcp.src_port();
502                let dst_port = tcp.dst_port();
503
504                // Check for STT tunnel (TCP port 7471)
505                if is_stt_port(dst_port) || is_stt_port(src_port) {
506                    Ok(TransportResult::Transport(
507                        TransportLayer::Tcp(tcp),
508                        NextLayer::Tunnel(TunnelType::Stt),
509                        rest,
510                    ))
511                } else {
512                    Ok(TransportResult::Transport(
513                        TransportLayer::Tcp(tcp),
514                        NextLayer::Done,
515                        rest,
516                    ))
517                }
518            }
519            IpProto::UDP => {
520                let (udp, rest) = UdpHeader::from_bytes(buf)?;
521
522                // In Outermost mode, don't detect tunnels
523                if mode == ParseMode::Outermost {
524                    return Ok(TransportResult::Transport(
525                        TransportLayer::Udp(udp),
526                        NextLayer::Done,
527                        rest,
528                    ));
529                }
530
531                let src_port = udp.src_port();
532                let dst_port = udp.dst_port();
533
534                // Check for tunnel protocols based on UDP ports
535                if let Some(tunnel_type) = detect_udp_tunnel(src_port, dst_port, rest) {
536                    Ok(TransportResult::Transport(
537                        TransportLayer::Udp(udp),
538                        NextLayer::Tunnel(tunnel_type),
539                        rest,
540                    ))
541                } else {
542                    Ok(TransportResult::Transport(
543                        TransportLayer::Udp(udp),
544                        NextLayer::Done,
545                        rest,
546                    ))
547                }
548            }
549            IpProto::SCTP => {
550                let (sctp, rest) = SctpHeader::from_bytes(buf)?;
551                Ok(TransportResult::Transport(
552                    TransportLayer::Sctp(sctp),
553                    NextLayer::Done,
554                    rest,
555                ))
556            }
557            IpProto::ICMP => {
558                let (icmp, rest) = IcmpHeader::from_bytes(buf)?;
559                Ok(TransportResult::Icmp(icmp, rest))
560            }
561            IpProto::IPV6_ICMP => {
562                let (icmp6, rest) = Icmp6Header::from_bytes(buf)?;
563                Ok(TransportResult::Icmp6(icmp6, rest))
564            }
565            IpProto::GRE => {
566                // In Outermost mode, treat GRE as end of parsing
567                if mode == ParseMode::Outermost {
568                    return Ok(TransportResult::Done(buf));
569                }
570                let tunnel_type = detect_gre_variant(buf);
571                Ok(TransportResult::Tunnel(NextLayer::Tunnel(tunnel_type), buf))
572            }
573            IpProto::L2TP => {
574                // In Outermost mode, treat L2TP as end of parsing
575                if mode == ParseMode::Outermost {
576                    return Ok(TransportResult::Done(buf));
577                }
578                // L2TPv3 over IP (protocol 115)
579                Ok(TransportResult::Tunnel(
580                    NextLayer::Tunnel(TunnelType::L2tpv3),
581                    buf,
582                ))
583            }
584            IpProto::IPV6_NONXT => {
585                // No next header - we're done
586                Ok(TransportResult::Done(buf))
587            }
588            _ => {
589                // Unknown transport protocol - stop parsing
590                Ok(TransportResult::Done(buf))
591            }
592        }
593    }
594
595    /// Parse tunnel layer
596    #[inline]
597    fn parse_tunnel(
598        buf: &'a [u8],
599        tunnel_type: TunnelType,
600    ) -> Result<(TunnelLayer<'a>, NextLayer, &'a [u8]), PacketHeaderError> {
601        match tunnel_type {
602            TunnelType::Vxlan => {
603                let (vxlan, rest) = VxlanHeader::from_bytes(buf)?;
604                Ok((
605                    TunnelLayer::Vxlan(vxlan),
606                    NextLayer::Link(LinkType::Ethernet),
607                    rest,
608                ))
609            }
610            TunnelType::Geneve => {
611                let (geneve, rest) = GeneveHeader::from_bytes(buf)?;
612                let inner_proto = geneve.protocol_type();
613                Ok((
614                    TunnelLayer::Geneve(geneve),
615                    NextLayer::Network(inner_proto),
616                    rest,
617                ))
618            }
619            TunnelType::Gre => {
620                let (gre, rest) = GreHeader::from_bytes(buf)?;
621                let inner_proto = gre.protocol_type();
622                let next = if inner_proto == EtherProto::TEB {
623                    NextLayer::Link(LinkType::Ethernet)
624                } else {
625                    NextLayer::Network(inner_proto)
626                };
627                Ok((TunnelLayer::Gre(gre), next, rest))
628            }
629            TunnelType::Mpls => {
630                // MPLS is handled in parse_network via NetworkResult::Mpls
631                // This should not be reached, but handle it gracefully
632                Err(PacketHeaderError::Other(
633                    "MPLS should be handled in network layer",
634                ))
635            }
636            TunnelType::Teredo => {
637                let teredo = TeredoPacket::parse(buf)?;
638                let payload = teredo.ipv6_payload();
639                Ok((
640                    TunnelLayer::Teredo(Box::new(teredo)),
641                    NextLayer::Network(EtherProto::IPV6),
642                    payload,
643                ))
644            }
645            TunnelType::Gtpv1 => {
646                let (gtpv1, rest) = Gtpv1Header::from_bytes(buf)?;
647                let next = if gtpv1.is_gpdu() && !rest.is_empty() {
648                    let version = (rest[0] & 0xF0) >> 4;
649                    match version {
650                        4 => NextLayer::Network(EtherProto::IPV4),
651                        6 => NextLayer::Network(EtherProto::IPV6),
652                        _ => NextLayer::Done,
653                    }
654                } else {
655                    NextLayer::Done
656                };
657                Ok((TunnelLayer::Gtpv1(gtpv1), next, rest))
658            }
659            TunnelType::Gtpv2 => {
660                let (gtpv2, rest) = Gtpv2Header::from_bytes(buf)?;
661                Ok((TunnelLayer::Gtpv2(gtpv2), NextLayer::Done, rest))
662            }
663            TunnelType::L2tpv2 => {
664                let (l2tpv2, rest) = L2tpv2Header::from_bytes(buf)?;
665                Ok((TunnelLayer::L2tpv2(l2tpv2), NextLayer::Done, rest))
666            }
667            TunnelType::L2tpv3 => {
668                let (l2tpv3, rest) = L2tpv3SessionHeader::parse_with_cookie_len(buf, 0)?;
669                let next = if !rest.is_empty() {
670                    let first_byte = rest[0];
671                    if first_byte == 0x00 || (first_byte & 0xF0) == 0x00 {
672                        NextLayer::Link(LinkType::Ethernet)
673                    } else {
674                        NextLayer::Done
675                    }
676                } else {
677                    NextLayer::Done
678                };
679                Ok((TunnelLayer::L2tpv3(l2tpv3), next, rest))
680            }
681            TunnelType::Nvgre => {
682                let (nvgre, rest) = NvgreHeader::from_bytes(buf)?;
683                Ok((
684                    TunnelLayer::Nvgre(nvgre),
685                    NextLayer::Link(LinkType::Ethernet),
686                    rest,
687                ))
688            }
689            TunnelType::Pbb => {
690                let (pbb, rest) = PbbHeader::parse(buf)?;
691                Ok((
692                    TunnelLayer::Pbb(pbb),
693                    NextLayer::Link(LinkType::Ethernet),
694                    rest,
695                ))
696            }
697            TunnelType::Stt => match SttPacket::parse(buf) {
698                Some(stt) => {
699                    let payload = stt.payload;
700                    Ok((
701                        TunnelLayer::Stt(stt),
702                        NextLayer::Link(LinkType::Ethernet),
703                        payload,
704                    ))
705                }
706                None => Err(PacketHeaderError::TooShort("STT")),
707            },
708            TunnelType::Pptp => {
709                let (pptp, rest) = PptpGreHeader::from_bytes(buf)?;
710                Ok((TunnelLayer::Pptp(pptp), NextLayer::Done, rest))
711            }
712        }
713    }
714
715    /// Returns a reference to the link layer header.
716    #[inline]
717    pub fn link(&self) -> &LinkLayer<'a> {
718        &self.link
719    }
720
721    /// Returns a reference to the ARP header, if present.
722    #[inline]
723    pub fn arp(&self) -> Option<&ArpHeaderFull<'a>> {
724        self.arp.as_ref()
725    }
726
727    /// Returns a reference to the network layer header, if present.
728    #[inline]
729    pub fn network(&self) -> Option<&NetworkLayer<'a>> {
730        self.network.as_ref()
731    }
732
733    /// Returns a reference to the transport layer header, if present.
734    #[inline]
735    pub fn transport(&self) -> Option<&TransportLayer<'a>> {
736        self.transport.as_ref()
737    }
738
739    /// Returns a slice of IP tunnel layer headers.
740    #[inline]
741    pub fn tunnels(&self) -> &[NetworkTunnelLayer<'a>] {
742        &self.tunnel
743    }
744
745    /// Returns the remaining payload data after all parsed headers.
746    #[inline]
747    pub fn data(&self) -> &'a [u8] {
748        self.data
749    }
750}
751
752impl<'a> fmt::Display for Packet<'a> {
753    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
754        // Link layer
755        writeln!(f, "        {}", self.link)?;
756
757        // ARP (if present)
758        if let Some(ref arp) = self.arp {
759            writeln!(f, "        {}", arp)?;
760        }
761
762        // Tunnel layers
763        for tunnel in &self.tunnel {
764            writeln!(f, "        {}", tunnel)?;
765        }
766
767        // Network layer (if present)
768        if let Some(ref network) = self.network {
769            writeln!(f, "        {}", network)?;
770        }
771
772        // Transport layer (if present)
773        if let Some(ref transport) = self.transport {
774            writeln!(f, "        {}", transport)?;
775        }
776
777        Ok(())
778    }
779}
780
781#[cfg(test)]
782mod tests {
783    use super::*;
784    use crate::packet::iter::LinkType;
785
786    /// Create Ethernet + IPv4 + UDP + VXLAN + inner Ethernet + inner IPv4 packet
787    fn create_vxlan_packet() -> Vec<u8> {
788        let mut packet = Vec::new();
789
790        // Outer Ethernet header (14 bytes)
791        packet.extend_from_slice(&[0x00, 0x11, 0x22, 0x33, 0x44, 0x55]); // Dest MAC
792        packet.extend_from_slice(&[0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb]); // Src MAC
793        packet.extend_from_slice(&[0x08, 0x00]); // EtherType: IPv4
794
795        // Outer IPv4 header (20 bytes)
796        packet.push(0x45); // Version 4, IHL 5
797        packet.push(0x00); // DSCP, ECN
798        packet.extend_from_slice(&72u16.to_be_bytes()); // Total length
799        packet.extend_from_slice(&[0x00, 0x00]); // ID
800        packet.extend_from_slice(&[0x00, 0x00]); // Flags, Fragment offset
801        packet.push(64); // TTL
802        packet.push(17); // Protocol: UDP
803        packet.extend_from_slice(&[0x00, 0x00]); // Checksum
804        packet.extend_from_slice(&[10, 0, 0, 1]); // Src IP
805        packet.extend_from_slice(&[10, 0, 0, 2]); // Dst IP
806
807        // Outer UDP header (8 bytes)
808        packet.extend_from_slice(&12345u16.to_be_bytes()); // Src port
809        packet.extend_from_slice(&4789u16.to_be_bytes()); // Dst port (VXLAN)
810        packet.extend_from_slice(&52u16.to_be_bytes()); // Length
811        packet.extend_from_slice(&[0x00, 0x00]); // Checksum
812
813        // VXLAN header (8 bytes)
814        packet.extend_from_slice(&[0x08, 0x00, 0x00, 0x00]); // Flags (I=1)
815        packet.extend_from_slice(&[0x00, 0x00, 0x64, 0x00]); // VNI = 100
816
817        // Inner Ethernet header (14 bytes)
818        packet.extend_from_slice(&[0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff]); // Dest MAC
819        packet.extend_from_slice(&[0x11, 0x22, 0x33, 0x44, 0x55, 0x66]); // Src MAC
820        packet.extend_from_slice(&[0x08, 0x00]); // EtherType: IPv4
821
822        // Inner IPv4 header (20 bytes)
823        packet.push(0x45); // Version 4, IHL 5
824        packet.push(0x00); // DSCP, ECN
825        packet.extend_from_slice(&28u16.to_be_bytes()); // Total length (20 + 8 ICMP)
826        packet.extend_from_slice(&[0x00, 0x00]); // ID
827        packet.extend_from_slice(&[0x00, 0x00]); // Flags, Fragment offset
828        packet.push(64); // TTL
829        packet.push(1); // Protocol: ICMP
830        packet.extend_from_slice(&[0x00, 0x00]); // Checksum
831        packet.extend_from_slice(&[192, 168, 1, 1]); // Src IP
832        packet.extend_from_slice(&[192, 168, 1, 2]); // Dst IP
833
834        // ICMP Echo Request (8 bytes)
835        packet.push(8); // Type: Echo Request
836        packet.push(0); // Code
837        packet.extend_from_slice(&[0x00, 0x00]); // Checksum
838        packet.extend_from_slice(&[0x00, 0x01]); // Identifier
839        packet.extend_from_slice(&[0x00, 0x01]); // Sequence number
840
841        packet
842    }
843
844    #[test]
845    fn test_vxlan_tunnel_parsing_innermost() {
846        let packet_bytes = create_vxlan_packet();
847        let packet = Packet::from_bytes(&packet_bytes, LinkType::Ethernet, ParseMode::Innermost)
848            .expect("Should parse VXLAN packet");
849
850        // Should have exactly one tunnel (VXLAN)
851        assert_eq!(
852            packet.tunnels().len(),
853            1,
854            "Expected 1 tunnel, got {}",
855            packet.tunnels().len()
856        );
857
858        // The tunnel should be VXLAN
859        assert!(
860            matches!(packet.tunnels()[0].tunnel(), TunnelLayer::Vxlan(_)),
861            "Expected VXLAN tunnel, got {:?}",
862            packet.tunnels()[0].tunnel()
863        );
864
865        // The outer IP should be present
866        assert!(
867            packet.tunnels()[0].outer().is_some(),
868            "Expected outer IP header"
869        );
870        assert!(
871            matches!(packet.tunnels()[0].outer().unwrap(), NetworkLayer::Ipv4(_)),
872            "Expected outer IPv4"
873        );
874
875        // Network should be the inner IPv4
876        assert!(packet.network().is_some(), "Expected network layer");
877        assert!(matches!(packet.network().unwrap(), NetworkLayer::Ipv4(_)));
878    }
879
880    #[test]
881    fn test_vxlan_tunnel_parsing_outermost() {
882        let packet_bytes = create_vxlan_packet();
883        let packet = Packet::from_bytes(&packet_bytes, LinkType::Ethernet, ParseMode::Outermost)
884            .expect("Should parse VXLAN packet");
885
886        // Outermost mode should NOT parse tunnels
887        assert_eq!(
888            packet.tunnels().len(),
889            0,
890            "Outermost mode should have 0 tunnels"
891        );
892
893        // Network should be the outer IPv4
894        assert!(packet.network().is_some(), "Expected network layer");
895    }
896
897    #[test]
898    fn test_ip_tunnel_layer_structure() {
899        let packet_bytes = create_vxlan_packet();
900        let packet = Packet::from_bytes(&packet_bytes, LinkType::Ethernet, ParseMode::Innermost)
901            .expect("Should parse VXLAN packet");
902
903        // Verify IpTunnelLayer structure
904        assert_eq!(packet.tunnels().len(), 1);
905        let ip_tunnel = &packet.tunnels()[0];
906
907        // Check outer IP header exists and is IPv4
908        assert!(
909            ip_tunnel.outer().is_some(),
910            "Outer IP should be present for VXLAN"
911        );
912        match ip_tunnel.outer().unwrap() {
913            NetworkLayer::Ipv4(ipv4) => {
914                // Verify outer IPs match what we created
915                assert_eq!(ipv4.src_ip().to_string(), "10.0.0.1");
916                assert_eq!(ipv4.dst_ip().to_string(), "10.0.0.2");
917            }
918            _ => panic!("Expected IPv4 outer header"),
919        }
920
921        // Check tunnel layer is VXLAN
922        match ip_tunnel.tunnel() {
923            TunnelLayer::Vxlan(vxlan) => {
924                assert_eq!(vxlan.vni(), 100, "Expected VNI 100");
925            }
926            _ => panic!("Expected VXLAN tunnel"),
927        }
928
929        // Verify Display format includes both outer and tunnel
930        let display = format!("{}", ip_tunnel);
931        assert!(display.contains("IPv4"), "Display should show outer IPv4");
932        assert!(
933            display.contains("VXLAN"),
934            "Display should show VXLAN tunnel"
935        );
936    }
937}