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