sniffnet_packet_parser/
headers.rs1use crate::igmp_type::IgmpType;
2use crate::link_type::LinkType;
3use crate::{ArpType, IcmpType, Protocol};
4use etherparse::{EtherType, LaxPacketHeaders};
5use std::net::IpAddr;
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
8pub struct LinkInfo {
10 pub src_mac: Option<[u8; 6]>,
12 pub dst_mac: Option<[u8; 6]>,
14 pub vlan_id: Option<u16>,
16 pub(crate) bytes: usize,
17}
18
19#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
20pub struct NetInfo {
22 pub src_ip: IpAddr,
24 pub dst_ip: IpAddr,
26 pub arp_type: Option<ArpType>,
28 pub ether_type: u16,
30 pub(crate) bytes: usize,
31}
32
33#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
34pub struct TransportInfo {
36 pub src_port: Option<u16>,
38 pub dst_port: Option<u16>,
40 pub protocol: Protocol,
42 pub icmp_type: Option<IcmpType>,
44 pub igmp_type: Option<IgmpType>,
46}
47
48#[must_use]
49pub(crate) fn get_sniffable_headers(
50 packet: &[u8],
51 link_type: LinkType,
52) -> Option<LaxPacketHeaders<'_>> {
53 match link_type {
54 LinkType::Ethernet(_) | LinkType::Unsupported(_) => {
55 LaxPacketHeaders::from_ethernet(packet).ok()
56 }
57 LinkType::RawIp(_) | LinkType::IPv4(_) | LinkType::IPv6(_) => {
58 LaxPacketHeaders::from_ip(packet).ok()
59 }
60 LinkType::LinuxSll(_) => from_linux_sll(packet, true),
61 LinkType::LinuxSll2(_) => from_linux_sll(packet, false),
62 LinkType::Null(_) | LinkType::Loop(_) => from_null(packet),
63 }
64}
65
66fn from_null(packet: &[u8]) -> Option<LaxPacketHeaders<'_>> {
67 if packet.len() <= 4 {
68 return None;
69 }
70
71 let is_valid_af_inet = {
72 fn matches(value: u32) -> bool {
74 match value {
75 2 | 24 | 28 | 30 => true,
78 _ => false,
79 }
80 }
81 let h = &packet[..4];
82 let b = [h[0], h[1], h[2], h[3]];
83 matches(u32::from_le_bytes(b)) || matches(u32::from_be_bytes(b))
86 };
87
88 if is_valid_af_inet {
89 LaxPacketHeaders::from_ip(&packet[4..]).ok()
90 } else {
91 None
92 }
93}
94
95fn from_linux_sll(packet: &[u8], is_v1: bool) -> Option<LaxPacketHeaders<'_>> {
97 let header_len = if is_v1 { 16 } else { 20 };
98 if packet.len() <= header_len {
99 return None;
100 }
101
102 let protocol_type = u16::from_be_bytes(if is_v1 {
103 [packet[14], packet[15]]
104 } else {
105 [packet[0], packet[1]]
106 });
107 let payload = &packet[header_len..];
108
109 Some(LaxPacketHeaders::from_ether_type(
110 EtherType(protocol_type),
111 payload,
112 ))
113}