use std::net::{Ipv4Addr, Ipv6Addr};
use crate::packet::ether::EthAddr;
use super::arp::ArpHeaderFull;
use super::ether::EtherHeaderVlan;
use super::icmp::IcmpHeader;
use super::icmp6::Icmp6Header;
use super::ipv4::Ipv4HeaderOpt;
use super::ipv6::Ipv6HeaderExt;
use super::null::NullHeader;
use super::protocol::{EtherProto, IpProto};
use super::sctp::SctpHeader;
use super::sll::{SllHeader, Sllv2Header};
use super::tcp::TcpHeaderOpt;
use super::tunnel::geneve::GeneveHeaderOpt;
use super::tunnel::gre::GreHeaderOpt;
use super::tunnel::gtpv1::Gtpv1HeaderOpt;
use super::tunnel::gtpv2::Gtpv2HeaderOpt;
use super::tunnel::ipip::IpipTunnel;
use super::tunnel::l2tp::{L2tpv2HeaderOpt, L2tpv3SessionHeaderCookie};
use super::tunnel::mpls::MplsLabelStack;
use super::tunnel::nvgre::NvgreHeader;
use super::tunnel::pbb::PbbHeader;
use super::tunnel::pptp::PptpGreHeaderOpt;
use super::tunnel::stt::SttPacket;
use super::tunnel::teredo::TeredoPacket;
use super::tunnel::vxlan::VxlanHeader;
use super::udp::UdpHeader;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum UnknownProto {
Ether(EtherProto),
Ip(IpProto),
Tunnel(&'static str),
}
impl std::fmt::Display for UnknownProto {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
UnknownProto::Ether(p) => write!(f, "EtherType(0x{:04x})", p.0.get()),
UnknownProto::Ip(p) => write!(f, "IpProto({})", u8::from(*p)),
UnknownProto::Tunnel(name) => write!(f, "Tunnel({})", name),
}
}
}
pub enum Header<'a> {
Ethernet(EtherHeaderVlan<'a>),
Sll(&'a SllHeader),
Sllv2(&'a Sllv2Header),
Null(&'a NullHeader),
Ipv4(Ipv4HeaderOpt<'a>),
Ipv6(Ipv6HeaderExt<'a>),
Arp(ArpHeaderFull<'a>),
Tcp(TcpHeaderOpt<'a>),
Udp(&'a UdpHeader),
Sctp(&'a SctpHeader),
Icmp(&'a IcmpHeader),
Icmp6(&'a Icmp6Header),
Vxlan(&'a VxlanHeader),
Geneve(GeneveHeaderOpt<'a>),
Gre(GreHeaderOpt<'a>),
Mpls(MplsLabelStack<'a>),
Teredo(Box<TeredoPacket<'a>>),
Gtpv1(Gtpv1HeaderOpt<'a>),
Gtpv2(Gtpv2HeaderOpt<'a>),
L2tpv2(L2tpv2HeaderOpt<'a>),
L2tpv3(L2tpv3SessionHeaderCookie<'a>),
Nvgre(&'a NvgreHeader),
Pbb(PbbHeader<'a>),
Stt(SttPacket<'a>),
Pptp(PptpGreHeaderOpt<'a>),
Ipip(IpipTunnel<'a>),
Unknown {
proto: UnknownProto,
data: &'a [u8],
},
}
impl<'a> Header<'a> {
pub fn name(&self) -> &'static str {
match self {
Header::Ethernet(_) => "Ethernet",
Header::Sll(_) => "SLL",
Header::Sllv2(_) => "SLLv2",
Header::Null(_) => "Null/Loopback",
Header::Ipv4(_) => "IPv4",
Header::Ipv6(_) => "IPv6",
Header::Arp(_) => "ARP",
Header::Tcp(_) => "TCP",
Header::Udp(_) => "UDP",
Header::Sctp(_) => "SCTP",
Header::Icmp(_) => "ICMP",
Header::Icmp6(_) => "ICMPv6",
Header::Vxlan(_) => "VXLAN",
Header::Geneve(_) => "Geneve",
Header::Gre(_) => "GRE",
Header::Mpls(_) => "MPLS",
Header::Teredo(_) => "Teredo",
Header::Gtpv1(_) => "GTPv1",
Header::Gtpv2(_) => "GTPv2",
Header::L2tpv2(_) => "L2TPv2",
Header::L2tpv3(_) => "L2TPv3",
Header::Nvgre(_) => "NVGRE",
Header::Pbb(_) => "PBB",
Header::Stt(_) => "STT",
Header::Pptp(_) => "PPTP",
Header::Ipip(t) => t.name(),
Header::Unknown { .. } => "Unknown",
}
}
pub fn is_link_layer(&self) -> bool {
matches!(
self,
Header::Ethernet(_) | Header::Sll(_) | Header::Sllv2(_) | Header::Null(_)
)
}
pub fn is_network_layer(&self) -> bool {
matches!(self, Header::Ipv4(_) | Header::Ipv6(_) | Header::Arp(_))
}
pub fn is_transport_layer(&self) -> bool {
matches!(
self,
Header::Tcp(_) | Header::Udp(_) | Header::Sctp(_) | Header::Icmp(_) | Header::Icmp6(_)
)
}
pub fn is_tunnel(&self) -> bool {
matches!(
self,
Header::Vxlan(_)
| Header::Geneve(_)
| Header::Gre(_)
| Header::Mpls(_)
| Header::Teredo(_)
| Header::Gtpv1(_)
| Header::Gtpv2(_)
| Header::L2tpv2(_)
| Header::L2tpv3(_)
| Header::Nvgre(_)
| Header::Pbb(_)
| Header::Stt(_)
| Header::Pptp(_)
| Header::Ipip(_)
)
}
pub fn is_unknown(&self) -> bool {
matches!(self, Header::Unknown { .. })
}
}
impl std::fmt::Debug for Header<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Header::Ethernet(h) => f.debug_tuple("Ethernet").field(h).finish(),
Header::Sll(h) => f.debug_tuple("Sll").field(h).finish(),
Header::Sllv2(h) => f.debug_tuple("Sllv2").field(h).finish(),
Header::Null(h) => f.debug_tuple("Null").field(h).finish(),
Header::Ipv4(h) => f.debug_tuple("Ipv4").field(h).finish(),
Header::Ipv6(h) => f.debug_tuple("Ipv6").field(h).finish(),
Header::Arp(h) => f.debug_tuple("Arp").field(h).finish(),
Header::Tcp(h) => f.debug_tuple("Tcp").field(h).finish(),
Header::Udp(h) => f.debug_tuple("Udp").field(h).finish(),
Header::Sctp(h) => f.debug_tuple("Sctp").field(h).finish(),
Header::Icmp(h) => f.debug_tuple("Icmp").field(h).finish(),
Header::Icmp6(h) => f.debug_tuple("Icmp6").field(h).finish(),
Header::Vxlan(h) => f.debug_tuple("Vxlan").field(h).finish(),
Header::Geneve(h) => f.debug_tuple("Geneve").field(h).finish(),
Header::Gre(h) => f.debug_tuple("Gre").field(h).finish(),
Header::Mpls(h) => f.debug_tuple("Mpls").field(h).finish(),
Header::Teredo(h) => f.debug_tuple("Teredo").field(h).finish(),
Header::Gtpv1(h) => f.debug_tuple("Gtpv1").field(h).finish(),
Header::Gtpv2(h) => f.debug_tuple("Gtpv2").field(h).finish(),
Header::L2tpv2(h) => f.debug_tuple("L2tpv2").field(h).finish(),
Header::L2tpv3(h) => f.debug_tuple("L2tpv3").field(h).finish(),
Header::Nvgre(h) => f.debug_tuple("Nvgre").field(h).finish(),
Header::Pbb(h) => f.debug_tuple("Pbb").field(h).finish(),
Header::Stt(h) => f.debug_tuple("Stt").field(h).finish(),
Header::Pptp(h) => f.debug_tuple("Pptp").field(h).finish(),
Header::Ipip(h) => f.debug_tuple("Ipip").field(h).finish(),
Header::Unknown { proto, data } => f
.debug_struct("Unknown")
.field("proto", proto)
.field("data_len", &data.len())
.finish(),
}
}
}
impl std::fmt::Display for Header<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Header::Ethernet(h) => write!(f, "{}", h),
Header::Sll(h) => write!(f, "{}", h),
Header::Sllv2(h) => write!(f, "{}", h),
Header::Null(h) => write!(f, "{}", h),
Header::Ipv4(h) => write!(f, "{}", h),
Header::Ipv6(h) => write!(f, "{}", h),
Header::Arp(h) => write!(f, "{}", h),
Header::Tcp(h) => write!(f, "{}", h),
Header::Udp(h) => write!(f, "{}", h),
Header::Sctp(h) => write!(f, "{}", h),
Header::Icmp(h) => write!(f, "{}", h),
Header::Icmp6(h) => write!(f, "{}", h),
Header::Vxlan(h) => write!(f, "{}", h),
Header::Geneve(h) => write!(f, "{}", h),
Header::Gre(h) => write!(f, "{}", h),
Header::Mpls(h) => write!(f, "{}", h),
Header::Teredo(h) => write!(f, "{}", h),
Header::Gtpv1(h) => write!(f, "{}", h),
Header::Gtpv2(h) => write!(f, "{}", h),
Header::L2tpv2(h) => write!(f, "{}", h),
Header::L2tpv3(h) => write!(f, "{}", h),
Header::Nvgre(h) => write!(f, "{}", h),
Header::Pbb(h) => write!(f, "{}", h),
Header::Stt(h) => write!(f, "{}", h),
Header::Pptp(h) => write!(f, "{}", h),
Header::Ipip(t) => write!(f, "{}", t),
Header::Unknown { proto, data } => {
write!(f, "Unknown({}, {} bytes)", proto, data.len())
}
}
}
}
#[derive(Debug, Clone)]
pub enum LinkLayer<'a> {
Ethernet(EtherHeaderVlan<'a>),
Sll(&'a SllHeader),
Sllv2(&'a Sllv2Header),
Null(&'a NullHeader),
}
impl LinkLayer<'_> {
#[inline]
pub fn protocol(&self) -> EtherProto {
match self {
LinkLayer::Ethernet(h) => h.protocol(),
LinkLayer::Sll(h) => h.protocol(),
LinkLayer::Sllv2(h) => h.protocol(),
LinkLayer::Null(h) => h.protocol(),
}
}
#[inline]
pub fn source(&self) -> EthAddr {
match self {
crate::packet::header::LinkLayer::Ethernet(ether) => *ether.source(),
_ => EthAddr::default(),
}
}
#[inline]
pub fn dest(&self) -> EthAddr {
match self {
crate::packet::header::LinkLayer::Ethernet(ether) => *ether.dest(),
_ => EthAddr::default(),
}
}
}
impl std::fmt::Display for LinkLayer<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
LinkLayer::Ethernet(h) => write!(f, "{}", h),
LinkLayer::Sll(h) => write!(f, "{}", h),
LinkLayer::Sllv2(h) => write!(f, "{}", h),
LinkLayer::Null(h) => write!(f, "{}", h),
}
}
}
#[derive(Debug, Clone)]
pub enum NetworkLayer<'a> {
Ipv4(Ipv4HeaderOpt<'a>),
Ipv6(Ipv6HeaderExt<'a>),
Mpls(MplsLabelStack<'a>),
}
impl std::fmt::Display for NetworkLayer<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
NetworkLayer::Ipv4(h) => write!(f, "{}", h),
NetworkLayer::Ipv6(h) => write!(f, "{}", h),
NetworkLayer::Mpls(h) => write!(f, "{}", h),
}
}
}
pub trait SourceDestLayer<T> {
fn source(&self) -> Option<T>;
fn dest(&self) -> Option<T>;
}
impl SourceDestLayer<EthAddr> for LinkLayer<'_> {
#[inline]
fn source(&self) -> Option<EthAddr> {
match self {
LinkLayer::Ethernet(h) => Some(*h.source()),
_ => None,
}
}
#[inline]
fn dest(&self) -> Option<EthAddr> {
match self {
LinkLayer::Ethernet(h) => Some(*h.dest()),
_ => None,
}
}
}
impl SourceDestLayer<Ipv4Addr> for NetworkLayer<'_> {
#[inline]
fn source(&self) -> Option<Ipv4Addr> {
match self {
NetworkLayer::Ipv4(h) => Some(h.header.src_ip()),
_ => None,
}
}
#[inline]
fn dest(&self) -> Option<Ipv4Addr> {
match self {
NetworkLayer::Ipv4(h) => Some(h.header.dst_ip()),
_ => None,
}
}
}
impl SourceDestLayer<Ipv6Addr> for NetworkLayer<'_> {
#[inline]
fn source(&self) -> Option<Ipv6Addr> {
match self {
NetworkLayer::Ipv6(h) => Some(h.header.src_ip()),
_ => None,
}
}
#[inline]
fn dest(&self) -> Option<Ipv6Addr> {
match self {
NetworkLayer::Ipv6(h) => Some(h.header.dst_ip()),
_ => None,
}
}
}
#[derive(Debug, Clone)]
pub enum TransportLayer<'a> {
Tcp(TcpHeaderOpt<'a>),
Udp(&'a UdpHeader),
Sctp(&'a SctpHeader),
Icmp(&'a IcmpHeader),
Icmp6(&'a Icmp6Header),
}
impl TransportLayer<'_> {
#[inline]
pub fn ports(&self) -> (u16, u16) {
match self {
TransportLayer::Tcp(h) => {
(h.source().unwrap_or_default(), h.dest().unwrap_or_default())
}
TransportLayer::Udp(h) => {
(h.source().unwrap_or_default(), h.dest().unwrap_or_default())
}
TransportLayer::Sctp(h) => {
(h.source().unwrap_or_default(), h.dest().unwrap_or_default())
}
TransportLayer::Icmp(_) => (0, 0),
TransportLayer::Icmp6(_) => (0, 0),
}
}
}
impl SourceDestLayer<u16> for TcpHeaderOpt<'_> {
#[inline]
fn source(&self) -> Option<u16> {
Some(self.header.src_port())
}
#[inline]
fn dest(&self) -> Option<u16> {
Some(self.header.dst_port())
}
}
impl SourceDestLayer<u16> for UdpHeader {
#[inline]
fn source(&self) -> Option<u16> {
Some(self.src_port())
}
#[inline]
fn dest(&self) -> Option<u16> {
Some(self.dst_port())
}
}
impl SourceDestLayer<u16> for SctpHeader {
#[inline]
fn source(&self) -> Option<u16> {
Some(self.src_port())
}
#[inline]
fn dest(&self) -> Option<u16> {
Some(self.dst_port())
}
}
impl SourceDestLayer<u16> for TransportLayer<'_> {
#[inline]
fn source(&self) -> Option<u16> {
match self {
TransportLayer::Tcp(h) => Some(h.src_port()),
TransportLayer::Udp(h) => Some(h.src_port()),
TransportLayer::Sctp(h) => Some(h.src_port()),
TransportLayer::Icmp(_) => None,
TransportLayer::Icmp6(_) => None,
}
}
#[inline]
fn dest(&self) -> Option<u16> {
match self {
TransportLayer::Tcp(h) => Some(h.dst_port()),
TransportLayer::Udp(h) => Some(h.dst_port()),
TransportLayer::Sctp(h) => Some(h.dst_port()),
TransportLayer::Icmp(_) => None,
TransportLayer::Icmp6(_) => None,
}
}
}
impl std::fmt::Display for TransportLayer<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
TransportLayer::Tcp(h) => write!(f, "{}", h),
TransportLayer::Udp(h) => write!(f, "{}", h),
TransportLayer::Sctp(h) => write!(f, "{}", h),
TransportLayer::Icmp(h) => write!(f, "{}", h),
TransportLayer::Icmp6(h) => write!(f, "{}", h),
}
}
}
#[derive(Debug, Clone)]
pub enum TunnelLayer<'a> {
Vxlan(&'a VxlanHeader),
Geneve(GeneveHeaderOpt<'a>),
Gre(GreHeaderOpt<'a>),
Teredo(Box<TeredoPacket<'a>>),
Gtpv1(Gtpv1HeaderOpt<'a>),
Gtpv2(Gtpv2HeaderOpt<'a>),
L2tpv2(L2tpv2HeaderOpt<'a>),
L2tpv3(L2tpv3SessionHeaderCookie<'a>),
Nvgre(&'a NvgreHeader),
Pbb(PbbHeader<'a>),
Stt(SttPacket<'a>),
Pptp(PptpGreHeaderOpt<'a>),
Ipip(IpipTunnel<'a>),
}
#[derive(Debug, Clone)]
pub struct NetworkTunnelLayer<'a> {
pub outer: Option<NetworkLayer<'a>>,
pub tunnel: TunnelLayer<'a>,
}
impl<'a> NetworkTunnelLayer<'a> {
#[inline]
pub fn new(outer: NetworkLayer<'a>, tunnel: TunnelLayer<'a>) -> Self {
Self {
outer: Some(outer),
tunnel,
}
}
#[inline]
pub fn new_l2(tunnel: TunnelLayer<'a>) -> Self {
Self {
outer: None,
tunnel,
}
}
#[inline]
pub fn outer(&self) -> Option<&NetworkLayer<'a>> {
self.outer.as_ref()
}
#[inline]
pub fn tunnel(&self) -> &TunnelLayer<'a> {
&self.tunnel
}
}
impl std::fmt::Display for NetworkTunnelLayer<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if let Some(ref outer) = self.outer {
write!(f, "{} > {}", outer, self.tunnel)
} else {
write!(f, "{}", self.tunnel)
}
}
}
impl std::fmt::Display for TunnelLayer<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
TunnelLayer::Vxlan(h) => write!(f, "{}", h),
TunnelLayer::Geneve(h) => write!(f, "{}", h),
TunnelLayer::Gre(h) => write!(f, "{}", h),
TunnelLayer::Teredo(h) => write!(f, "{}", h),
TunnelLayer::Gtpv1(h) => write!(f, "{}", h),
TunnelLayer::Gtpv2(h) => write!(f, "{}", h),
TunnelLayer::L2tpv2(h) => write!(f, "{}", h),
TunnelLayer::L2tpv3(h) => write!(f, "{}", h),
TunnelLayer::Nvgre(h) => write!(f, "{}", h),
TunnelLayer::Pbb(h) => write!(f, "{}", h),
TunnelLayer::Stt(h) => write!(f, "{}", h),
TunnelLayer::Pptp(h) => write!(f, "{}", h),
TunnelLayer::Ipip(h) => write!(f, "{}", h),
}
}
}