packet_strata/packet/
header.rs

1//! Header enum wrapper for all supported packet headers
2//!
3//! This module provides the [`Header`] enum which wraps all supported protocol headers
4//! and [`UnknownProto`] for representing unknown/unsupported protocols.
5
6use std::net::{Ipv4Addr, Ipv6Addr};
7
8use crate::packet::ether::EthAddr;
9
10use super::arp::ArpHeaderFull;
11use super::ether::EtherHeaderVlan;
12use super::icmp::IcmpHeader;
13use super::icmp6::Icmp6Header;
14use super::ipv4::Ipv4HeaderOpt;
15use super::ipv6::Ipv6HeaderExt;
16use super::null::NullHeader;
17use super::protocol::{EtherProto, IpProto};
18use super::sctp::SctpHeader;
19use super::sll::{SllHeader, Sllv2Header};
20use super::tcp::TcpHeaderOpt;
21use super::tunnel::geneve::GeneveHeaderOpt;
22use super::tunnel::gre::GreHeaderOpt;
23use super::tunnel::gtpv1::Gtpv1HeaderOpt;
24use super::tunnel::gtpv2::Gtpv2HeaderOpt;
25use super::tunnel::ipip::IpipTunnel;
26use super::tunnel::l2tp::{L2tpv2HeaderOpt, L2tpv3SessionHeaderCookie};
27use super::tunnel::mpls::MplsLabelStack;
28use super::tunnel::nvgre::NvgreHeader;
29use super::tunnel::pbb::PbbHeader;
30use super::tunnel::pptp::PptpGreHeaderOpt;
31use super::tunnel::stt::SttPacket;
32use super::tunnel::teredo::TeredoPacket;
33use super::tunnel::vxlan::VxlanHeader;
34use super::udp::UdpHeader;
35
36/// Represents an unknown/unsupported protocol
37#[derive(Debug, Clone, Copy, PartialEq, Eq)]
38pub enum UnknownProto {
39    /// Unknown Ethernet protocol type
40    Ether(EtherProto),
41    /// Unknown IP protocol number
42    Ip(IpProto),
43    /// Unknown tunnel encapsulation
44    Tunnel(&'static str),
45}
46
47impl std::fmt::Display for UnknownProto {
48    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
49        match self {
50            UnknownProto::Ether(p) => write!(f, "EtherType(0x{:04x})", p.0.get()),
51            UnknownProto::Ip(p) => write!(f, "IpProto({})", u8::from(*p)),
52            UnknownProto::Tunnel(name) => write!(f, "Tunnel({})", name),
53        }
54    }
55}
56
57/// Enum wrapper for all supported packet headers
58///
59/// This enum provides a unified way to handle different protocol headers
60/// when iterating through a packet's protocol stack.
61pub enum Header<'a> {
62    /// Ethernet II header (possibly with VLAN tags)
63    Ethernet(EtherHeaderVlan<'a>),
64
65    /// Linux cooked capture v1 header
66    Sll(&'a SllHeader),
67
68    /// Linux cooked capture v2 header
69    Sllv2(&'a Sllv2Header),
70
71    /// BSD Null/Loopback header
72    Null(&'a NullHeader),
73
74    /// IPv4 header with options
75    Ipv4(Ipv4HeaderOpt<'a>),
76
77    /// IPv6 header with extension headers
78    Ipv6(Ipv6HeaderExt<'a>),
79
80    /// ARP header with addresses
81    Arp(ArpHeaderFull<'a>),
82
83    /// TCP header with options
84    Tcp(TcpHeaderOpt<'a>),
85
86    /// UDP header
87    Udp(&'a UdpHeader),
88
89    /// SCTP header
90    Sctp(&'a SctpHeader),
91
92    /// ICMPv4 header
93    Icmp(&'a IcmpHeader),
94
95    /// ICMPv6 header
96    Icmp6(&'a Icmp6Header),
97
98    /// VXLAN tunnel header
99    Vxlan(&'a VxlanHeader),
100
101    /// Geneve tunnel header with options
102    Geneve(GeneveHeaderOpt<'a>),
103
104    /// GRE tunnel header with options
105    Gre(GreHeaderOpt<'a>),
106
107    /// MPLS label stack
108    Mpls(MplsLabelStack<'a>),
109
110    /// Teredo tunnel (parsed packet includes auth/origin indicators)
111    /// Boxed to reduce Header enum size (TeredoPacket is 96 bytes)
112    Teredo(Box<TeredoPacket<'a>>),
113
114    /// GTPv1 header with options
115    Gtpv1(Gtpv1HeaderOpt<'a>),
116
117    /// GTPv2 header with options
118    Gtpv2(Gtpv2HeaderOpt<'a>),
119
120    /// L2TPv2 header with options
121    L2tpv2(L2tpv2HeaderOpt<'a>),
122
123    /// L2TPv3 session header with cookie
124    L2tpv3(L2tpv3SessionHeaderCookie<'a>),
125
126    /// NVGRE header (Network Virtualization using GRE)
127    Nvgre(&'a NvgreHeader),
128
129    /// PBB header (Provider Backbone Bridge / MAC-in-MAC)
130    Pbb(PbbHeader<'a>),
131
132    /// STT packet (Stateless Transport Tunneling)
133    Stt(SttPacket<'a>),
134
135    /// PPTP GRE header with options
136    Pptp(PptpGreHeaderOpt<'a>),
137
138    /// IP-in-IP tunnel (IPIP, SIT, IP4in6, IP6Tnl)
139    Ipip(IpipTunnel<'a>),
140
141    /// Unknown/unsupported protocol
142    ///
143    /// Contains the protocol identifier and the remaining unparsed data.
144    Unknown {
145        /// The protocol that couldn't be parsed
146        proto: UnknownProto,
147        /// The remaining unparsed data
148        data: &'a [u8],
149    },
150}
151
152impl<'a> Header<'a> {
153    /// Returns the name of the protocol
154    pub fn name(&self) -> &'static str {
155        match self {
156            Header::Ethernet(_) => "Ethernet",
157            Header::Sll(_) => "SLL",
158            Header::Sllv2(_) => "SLLv2",
159            Header::Null(_) => "Null/Loopback",
160            Header::Ipv4(_) => "IPv4",
161            Header::Ipv6(_) => "IPv6",
162            Header::Arp(_) => "ARP",
163            Header::Tcp(_) => "TCP",
164            Header::Udp(_) => "UDP",
165            Header::Sctp(_) => "SCTP",
166            Header::Icmp(_) => "ICMP",
167            Header::Icmp6(_) => "ICMPv6",
168            Header::Vxlan(_) => "VXLAN",
169            Header::Geneve(_) => "Geneve",
170            Header::Gre(_) => "GRE",
171            Header::Mpls(_) => "MPLS",
172            Header::Teredo(_) => "Teredo",
173            Header::Gtpv1(_) => "GTPv1",
174            Header::Gtpv2(_) => "GTPv2",
175            Header::L2tpv2(_) => "L2TPv2",
176            Header::L2tpv3(_) => "L2TPv3",
177            Header::Nvgre(_) => "NVGRE",
178            Header::Pbb(_) => "PBB",
179            Header::Stt(_) => "STT",
180            Header::Pptp(_) => "PPTP",
181            Header::Ipip(t) => t.name(),
182            Header::Unknown { .. } => "Unknown",
183        }
184    }
185
186    /// Returns true if this is a link layer header
187    pub fn is_link_layer(&self) -> bool {
188        matches!(
189            self,
190            Header::Ethernet(_) | Header::Sll(_) | Header::Sllv2(_) | Header::Null(_)
191        )
192    }
193
194    /// Returns true if this is a network layer header
195    pub fn is_network_layer(&self) -> bool {
196        matches!(self, Header::Ipv4(_) | Header::Ipv6(_) | Header::Arp(_))
197    }
198
199    /// Returns true if this is a transport layer header
200    pub fn is_transport_layer(&self) -> bool {
201        matches!(
202            self,
203            Header::Tcp(_) | Header::Udp(_) | Header::Sctp(_) | Header::Icmp(_) | Header::Icmp6(_)
204        )
205    }
206
207    /// Returns true if this is a tunnel header
208    pub fn is_tunnel(&self) -> bool {
209        matches!(
210            self,
211            Header::Vxlan(_)
212                | Header::Geneve(_)
213                | Header::Gre(_)
214                | Header::Mpls(_)
215                | Header::Teredo(_)
216                | Header::Gtpv1(_)
217                | Header::Gtpv2(_)
218                | Header::L2tpv2(_)
219                | Header::L2tpv3(_)
220                | Header::Nvgre(_)
221                | Header::Pbb(_)
222                | Header::Stt(_)
223                | Header::Pptp(_)
224                | Header::Ipip(_)
225        )
226    }
227
228    /// Returns true if this is an unknown protocol
229    pub fn is_unknown(&self) -> bool {
230        matches!(self, Header::Unknown { .. })
231    }
232}
233
234impl std::fmt::Debug for Header<'_> {
235    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
236        match self {
237            Header::Ethernet(h) => f.debug_tuple("Ethernet").field(h).finish(),
238            Header::Sll(h) => f.debug_tuple("Sll").field(h).finish(),
239            Header::Sllv2(h) => f.debug_tuple("Sllv2").field(h).finish(),
240            Header::Null(h) => f.debug_tuple("Null").field(h).finish(),
241            Header::Ipv4(h) => f.debug_tuple("Ipv4").field(h).finish(),
242            Header::Ipv6(h) => f.debug_tuple("Ipv6").field(h).finish(),
243            Header::Arp(h) => f.debug_tuple("Arp").field(h).finish(),
244            Header::Tcp(h) => f.debug_tuple("Tcp").field(h).finish(),
245            Header::Udp(h) => f.debug_tuple("Udp").field(h).finish(),
246            Header::Sctp(h) => f.debug_tuple("Sctp").field(h).finish(),
247            Header::Icmp(h) => f.debug_tuple("Icmp").field(h).finish(),
248            Header::Icmp6(h) => f.debug_tuple("Icmp6").field(h).finish(),
249            Header::Vxlan(h) => f.debug_tuple("Vxlan").field(h).finish(),
250            Header::Geneve(h) => f.debug_tuple("Geneve").field(h).finish(),
251            Header::Gre(h) => f.debug_tuple("Gre").field(h).finish(),
252            Header::Mpls(h) => f.debug_tuple("Mpls").field(h).finish(),
253            Header::Teredo(h) => f.debug_tuple("Teredo").field(h).finish(),
254            Header::Gtpv1(h) => f.debug_tuple("Gtpv1").field(h).finish(),
255            Header::Gtpv2(h) => f.debug_tuple("Gtpv2").field(h).finish(),
256            Header::L2tpv2(h) => f.debug_tuple("L2tpv2").field(h).finish(),
257            Header::L2tpv3(h) => f.debug_tuple("L2tpv3").field(h).finish(),
258            Header::Nvgre(h) => f.debug_tuple("Nvgre").field(h).finish(),
259            Header::Pbb(h) => f.debug_tuple("Pbb").field(h).finish(),
260            Header::Stt(h) => f.debug_tuple("Stt").field(h).finish(),
261            Header::Pptp(h) => f.debug_tuple("Pptp").field(h).finish(),
262            Header::Ipip(h) => f.debug_tuple("Ipip").field(h).finish(),
263            Header::Unknown { proto, data } => f
264                .debug_struct("Unknown")
265                .field("proto", proto)
266                .field("data_len", &data.len())
267                .finish(),
268        }
269    }
270}
271
272impl std::fmt::Display for Header<'_> {
273    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
274        match self {
275            Header::Ethernet(h) => write!(f, "{}", h),
276            Header::Sll(h) => write!(f, "{}", h),
277            Header::Sllv2(h) => write!(f, "{}", h),
278            Header::Null(h) => write!(f, "{}", h),
279            Header::Ipv4(h) => write!(f, "{}", h),
280            Header::Ipv6(h) => write!(f, "{}", h),
281            Header::Arp(h) => write!(f, "{}", h),
282            Header::Tcp(h) => write!(f, "{}", h),
283            Header::Udp(h) => write!(f, "{}", h),
284            Header::Sctp(h) => write!(f, "{}", h),
285            Header::Icmp(h) => write!(f, "{}", h),
286            Header::Icmp6(h) => write!(f, "{}", h),
287            Header::Vxlan(h) => write!(f, "{}", h),
288            Header::Geneve(h) => write!(f, "{}", h),
289            Header::Gre(h) => write!(f, "{}", h),
290            Header::Mpls(h) => write!(f, "{}", h),
291            Header::Teredo(h) => write!(f, "{}", h),
292            Header::Gtpv1(h) => write!(f, "{}", h),
293            Header::Gtpv2(h) => write!(f, "{}", h),
294            Header::L2tpv2(h) => write!(f, "{}", h),
295            Header::L2tpv3(h) => write!(f, "{}", h),
296            Header::Nvgre(h) => write!(f, "{}", h),
297            Header::Pbb(h) => write!(f, "{}", h),
298            Header::Stt(h) => write!(f, "{}", h),
299            Header::Pptp(h) => write!(f, "{}", h),
300            Header::Ipip(t) => write!(f, "{}", t),
301            Header::Unknown { proto, data } => {
302                write!(f, "Unknown({}, {} bytes)", proto, data.len())
303            }
304        }
305    }
306}
307
308#[derive(Debug, Clone)]
309pub enum LinkLayer<'a> {
310    Ethernet(EtherHeaderVlan<'a>),
311    Sll(&'a SllHeader),
312    Sllv2(&'a Sllv2Header),
313    Null(&'a NullHeader),
314}
315
316impl LinkLayer<'_> {
317    #[inline]
318    pub fn protocol(&self) -> EtherProto {
319        match self {
320            LinkLayer::Ethernet(h) => h.protocol(),
321            LinkLayer::Sll(h) => h.protocol(),
322            LinkLayer::Sllv2(h) => h.protocol(),
323            LinkLayer::Null(h) => h.protocol(),
324        }
325    }
326
327    #[inline]
328    pub fn source(&self) -> EthAddr {
329        match self {
330            crate::packet::header::LinkLayer::Ethernet(ether) => *ether.source(),
331            _ => EthAddr::default(),
332        }
333    }
334
335    #[inline]
336    pub fn dest(&self) -> EthAddr {
337        match self {
338            crate::packet::header::LinkLayer::Ethernet(ether) => *ether.dest(),
339            _ => EthAddr::default(),
340        }
341    }
342}
343
344impl std::fmt::Display for LinkLayer<'_> {
345    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
346        match self {
347            LinkLayer::Ethernet(h) => write!(f, "{}", h),
348            LinkLayer::Sll(h) => write!(f, "{}", h),
349            LinkLayer::Sllv2(h) => write!(f, "{}", h),
350            LinkLayer::Null(h) => write!(f, "{}", h),
351        }
352    }
353}
354
355#[derive(Debug, Clone)]
356pub enum NetworkLayer<'a> {
357    Ipv4(Ipv4HeaderOpt<'a>),
358    Ipv6(Ipv6HeaderExt<'a>),
359    Mpls(MplsLabelStack<'a>),
360}
361
362impl std::fmt::Display for NetworkLayer<'_> {
363    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
364        match self {
365            NetworkLayer::Ipv4(h) => write!(f, "{}", h),
366            NetworkLayer::Ipv6(h) => write!(f, "{}", h),
367            NetworkLayer::Mpls(h) => write!(f, "{}", h),
368        }
369    }
370}
371
372/// Trait for extracting source and destination fields from packet headers.
373///
374/// This trait provides a generic interface for accessing source and destination
375/// information from different types of network headers, regardless of whether
376/// they contain IP addresses, ports, or other address types.
377///
378/// # Type Parameters
379/// * `T` - The type of address/port information to extract (e.g., Ipv4Addr, Ipv6Addr, u16)
380pub trait SourceDestLayer<T> {
381    /// Extracts the source address/port from the header.
382    ///
383    /// Returns `None` if the header doesn't contain source information
384    /// or if the source field is not applicable for this header type.
385    fn source(&self) -> Option<T>;
386
387    /// Extracts the destination address/port from the header.
388    ///
389    /// Returns `None` if the header doesn't contain destination information
390    /// or if the destination field is not applicable for this header type.
391    fn dest(&self) -> Option<T>;
392}
393
394impl SourceDestLayer<EthAddr> for LinkLayer<'_> {
395    /// Extracts the source Ethernet MAC address from the link layer header.
396    ///
397    /// Returns the source MAC address if this is an Ethernet header,
398    /// otherwise returns `None` for other link layer types (SLL, SLLv2, NULL).
399    ///
400    /// # Returns
401    /// * `Some(EthAddr)` - The source MAC address for Ethernet frames
402    /// * `None` - No MAC address available for non-Ethernet link layers
403    #[inline]
404    fn source(&self) -> Option<EthAddr> {
405        match self {
406            LinkLayer::Ethernet(h) => Some(*h.source()),
407            _ => None,
408        }
409    }
410
411    /// Extracts the destination Ethernet MAC address from the link layer header.
412    ///
413    /// Returns the destination MAC address if this is an Ethernet header,
414    /// otherwise returns `None` for other link layer types (SLL, SLLv2, NULL).
415    ///
416    /// # Returns
417    /// * `Some(EthAddr)` - The destination MAC address for Ethernet frames
418    /// * `None` - No MAC address available for non-Ethernet link layers
419    #[inline]
420    fn dest(&self) -> Option<EthAddr> {
421        match self {
422            LinkLayer::Ethernet(h) => Some(*h.dest()),
423            _ => None,
424        }
425    }
426}
427
428impl SourceDestLayer<Ipv4Addr> for NetworkLayer<'_> {
429    /// Extracts the source IPv4 address from the network layer header.
430    ///
431    /// Returns the source IPv4 address if this is an IPv4 header,
432    /// otherwise returns `None` for IPv6, MPLS, or other network layers.
433    #[inline]
434    fn source(&self) -> Option<Ipv4Addr> {
435        match self {
436            NetworkLayer::Ipv4(h) => Some(h.header.src_ip()),
437            _ => None,
438        }
439    }
440
441    /// Extracts the destination IPv4 address from the network layer header.
442    ///
443    /// Returns the destination IPv4 address if this is an IPv4 header,
444    /// otherwise returns `None` for IPv6, MPLS, or other network layers.
445    #[inline]
446    fn dest(&self) -> Option<Ipv4Addr> {
447        match self {
448            NetworkLayer::Ipv4(h) => Some(h.header.dst_ip()),
449            _ => None,
450        }
451    }
452}
453
454impl SourceDestLayer<Ipv6Addr> for NetworkLayer<'_> {
455    /// Extracts the source IPv6 address from the network layer header.
456    ///
457    /// Returns the source IPv6 address if this is an IPv6 header,
458    /// otherwise returns `None` for IPv4, MPLS, or other network layers.
459    #[inline]
460    fn source(&self) -> Option<Ipv6Addr> {
461        match self {
462            NetworkLayer::Ipv6(h) => Some(h.header.src_ip()),
463            _ => None,
464        }
465    }
466
467    /// Extracts the destination IPv6 address from the network layer header.
468    ///
469    /// Returns the destination IPv6 address if this is an IPv6 header,
470    /// otherwise returns `None` for IPv4, MPLS, or other network layers.
471    #[inline]
472    fn dest(&self) -> Option<Ipv6Addr> {
473        match self {
474            NetworkLayer::Ipv6(h) => Some(h.header.dst_ip()),
475            _ => None,
476        }
477    }
478}
479
480#[derive(Debug, Clone)]
481pub enum TransportLayer<'a> {
482    Tcp(TcpHeaderOpt<'a>),
483    Udp(&'a UdpHeader),
484    Sctp(&'a SctpHeader),
485    Icmp(&'a IcmpHeader),
486    Icmp6(&'a Icmp6Header),
487}
488
489impl TransportLayer<'_> {
490    /// Extracts the source and destination ports from the transport layer header.
491    ///
492    /// For TCP, UDP, and SCTP headers, returns the actual source and destination ports.
493    /// For ICMP and ICMPv6 headers, which don't have port numbers, returns (0, 0).
494    ///
495    /// # Returns
496    /// A tuple containing (source_port, destination_port). For protocols without
497    /// port numbers, both values will be 0.
498    #[inline]
499    pub fn ports(&self) -> (u16, u16) {
500        match self {
501            TransportLayer::Tcp(h) => {
502                (h.source().unwrap_or_default(), h.dest().unwrap_or_default())
503            }
504            TransportLayer::Udp(h) => {
505                (h.source().unwrap_or_default(), h.dest().unwrap_or_default())
506            }
507            TransportLayer::Sctp(h) => {
508                (h.source().unwrap_or_default(), h.dest().unwrap_or_default())
509            }
510            TransportLayer::Icmp(_) => (0, 0),
511            TransportLayer::Icmp6(_) => (0, 0),
512        }
513    }
514}
515
516impl SourceDestLayer<u16> for TcpHeaderOpt<'_> {
517    /// Extracts the source port from the TCP header.
518    ///
519    /// TCP headers always contain both source and destination ports,
520    /// so this method always returns `Some(port)`.
521    #[inline]
522    fn source(&self) -> Option<u16> {
523        Some(self.header.src_port())
524    }
525
526    /// Extracts the destination port from the TCP header.
527    ///
528    /// TCP headers always contain both source and destination ports,
529    /// so this method always returns `Some(port)`.
530    #[inline]
531    fn dest(&self) -> Option<u16> {
532        Some(self.header.dst_port())
533    }
534}
535
536impl SourceDestLayer<u16> for UdpHeader {
537    /// Extracts the source port from the UDP header.
538    ///
539    /// UDP headers always contain both source and destination ports,
540    /// so this method always returns `Some(port)`.
541    #[inline]
542    fn source(&self) -> Option<u16> {
543        Some(self.src_port())
544    }
545
546    /// Extracts the destination port from the UDP header.
547    ///
548    /// UDP headers always contain both source and destination ports,
549    /// so this method always returns `Some(port)`.
550    #[inline]
551    fn dest(&self) -> Option<u16> {
552        Some(self.dst_port())
553    }
554}
555
556impl SourceDestLayer<u16> for SctpHeader {
557    /// Extracts the source port from the SCTP header.
558    ///
559    /// SCTP headers always contain both source and destination ports,
560    /// so this method always returns `Some(port)`.
561    #[inline]
562    fn source(&self) -> Option<u16> {
563        Some(self.src_port())
564    }
565
566    /// Extracts the destination port from the SCTP header.
567    ///
568    /// SCTP headers always contain both source and destination ports,
569    /// so this method always returns `Some(port)`.
570    #[inline]
571    fn dest(&self) -> Option<u16> {
572        Some(self.dst_port())
573    }
574}
575
576impl SourceDestLayer<u16> for TransportLayer<'_> {
577    /// Extracts the source port from the transport layer header.
578    ///
579    /// Returns the source port for TCP, UDP, and SCTP headers.
580    /// Returns `None` for ICMP and ICMPv6 headers, which don't have port numbers.
581    #[inline]
582    fn source(&self) -> Option<u16> {
583        match self {
584            TransportLayer::Tcp(h) => Some(h.src_port()),
585            TransportLayer::Udp(h) => Some(h.src_port()),
586            TransportLayer::Sctp(h) => Some(h.src_port()),
587            TransportLayer::Icmp(_) => None,
588            TransportLayer::Icmp6(_) => None,
589        }
590    }
591
592    /// Extracts the destination port from the transport layer header.
593    ///
594    /// Returns the destination port for TCP, UDP, and SCTP headers.
595    /// Returns `None` for ICMP and ICMPv6 headers, which don't have port numbers.
596    #[inline]
597    fn dest(&self) -> Option<u16> {
598        match self {
599            TransportLayer::Tcp(h) => Some(h.dst_port()),
600            TransportLayer::Udp(h) => Some(h.dst_port()),
601            TransportLayer::Sctp(h) => Some(h.dst_port()),
602            TransportLayer::Icmp(_) => None,
603            TransportLayer::Icmp6(_) => None,
604        }
605    }
606}
607
608impl std::fmt::Display for TransportLayer<'_> {
609    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
610        match self {
611            TransportLayer::Tcp(h) => write!(f, "{}", h),
612            TransportLayer::Udp(h) => write!(f, "{}", h),
613            TransportLayer::Sctp(h) => write!(f, "{}", h),
614            TransportLayer::Icmp(h) => write!(f, "{}", h),
615            TransportLayer::Icmp6(h) => write!(f, "{}", h),
616        }
617    }
618}
619
620#[derive(Debug, Clone)]
621pub enum TunnelLayer<'a> {
622    Vxlan(&'a VxlanHeader),
623    Geneve(GeneveHeaderOpt<'a>),
624    Gre(GreHeaderOpt<'a>),
625    Teredo(Box<TeredoPacket<'a>>),
626    Gtpv1(Gtpv1HeaderOpt<'a>),
627    Gtpv2(Gtpv2HeaderOpt<'a>),
628    L2tpv2(L2tpv2HeaderOpt<'a>),
629    L2tpv3(L2tpv3SessionHeaderCookie<'a>),
630    Nvgre(&'a NvgreHeader),
631    Pbb(PbbHeader<'a>),
632    Stt(SttPacket<'a>),
633    Pptp(PptpGreHeaderOpt<'a>),
634    Ipip(IpipTunnel<'a>),
635}
636
637/// IP Tunnel Layer - combines outer IP encapsulation with tunnel protocol
638///
639/// Most tunnel protocols are encapsulated in IP (e.g., VXLAN over UDP/IP, GRE over IP).
640/// This structure preserves the outer IP header that encapsulates the tunnel.
641///
642/// Some tunnels like PBB (MAC-in-MAC) operate at layer 2 and don't have an outer IP header,
643/// so the `outer` field is optional.
644#[derive(Debug, Clone)]
645pub struct NetworkTunnelLayer<'a> {
646    /// Outer IP header (IPv4 or IPv6) that encapsulates the tunnel.
647    /// None for layer 2 tunnels like PBB.
648    pub outer: Option<NetworkLayer<'a>>,
649    /// The tunnel protocol layer
650    pub tunnel: TunnelLayer<'a>,
651}
652
653impl<'a> NetworkTunnelLayer<'a> {
654    /// Creates a new IP tunnel layer with an outer IP header.
655    ///
656    /// This constructor is used for tunnel protocols that are encapsulated in IP,
657    /// such as VXLAN over UDP/IP, GRE over IP, or GTP over IP.
658    ///
659    /// # Arguments
660    /// * `outer` - The outer IP header (IPv4 or IPv6) that encapsulates the tunnel
661    /// * `tunnel` - The tunnel protocol layer
662    #[inline]
663    pub fn new(outer: NetworkLayer<'a>, tunnel: TunnelLayer<'a>) -> Self {
664        Self {
665            outer: Some(outer),
666            tunnel,
667        }
668    }
669
670    /// Creates a new tunnel layer without an outer IP header.
671    ///
672    /// This constructor is used for layer 2 tunnel protocols that don't have
673    /// an outer IP header, such as PBB (MAC-in-MAC) or other layer 2 encapsulations.
674    ///
675    /// # Arguments
676    /// * `tunnel` - The tunnel protocol layer
677    #[inline]
678    pub fn new_l2(tunnel: TunnelLayer<'a>) -> Self {
679        Self {
680            outer: None,
681            tunnel,
682        }
683    }
684
685    /// Returns a reference to the outer IP header, if present.
686    ///
687    /// For IP-based tunnels (VXLAN, GRE, GTP, etc.), this returns the outer IP header
688    /// that encapsulates the tunnel protocol. For layer 2 tunnels like PBB, this returns `None`.
689    ///
690    /// # Returns
691    /// * `Some(&NetworkLayer)` - The outer IP header for IP-based tunnels
692    /// * `None` - No outer IP header for layer 2 tunnels
693    #[inline]
694    pub fn outer(&self) -> Option<&NetworkLayer<'a>> {
695        self.outer.as_ref()
696    }
697
698    /// Returns a reference to the tunnel layer.
699    ///
700    /// This provides access to the actual tunnel protocol header (VXLAN, GRE, GTP, etc.).
701    ///
702    /// # Returns
703    /// A reference to the tunnel protocol layer contained within this network tunnel.
704    #[inline]
705    pub fn tunnel(&self) -> &TunnelLayer<'a> {
706        &self.tunnel
707    }
708}
709
710impl std::fmt::Display for NetworkTunnelLayer<'_> {
711    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
712        if let Some(ref outer) = self.outer {
713            write!(f, "{} > {}", outer, self.tunnel)
714        } else {
715            write!(f, "{}", self.tunnel)
716        }
717    }
718}
719
720impl std::fmt::Display for TunnelLayer<'_> {
721    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
722        match self {
723            TunnelLayer::Vxlan(h) => write!(f, "{}", h),
724            TunnelLayer::Geneve(h) => write!(f, "{}", h),
725            TunnelLayer::Gre(h) => write!(f, "{}", h),
726            TunnelLayer::Teredo(h) => write!(f, "{}", h),
727            TunnelLayer::Gtpv1(h) => write!(f, "{}", h),
728            TunnelLayer::Gtpv2(h) => write!(f, "{}", h),
729            TunnelLayer::L2tpv2(h) => write!(f, "{}", h),
730            TunnelLayer::L2tpv3(h) => write!(f, "{}", h),
731            TunnelLayer::Nvgre(h) => write!(f, "{}", h),
732            TunnelLayer::Pbb(h) => write!(f, "{}", h),
733            TunnelLayer::Stt(h) => write!(f, "{}", h),
734            TunnelLayer::Pptp(h) => write!(f, "{}", h),
735            TunnelLayer::Ipip(h) => write!(f, "{}", h),
736        }
737    }
738}