feat: add EtherType and IP Protocol enums for enhanced packet parsing and logging
All checks were successful
Build and Deploy MITM Webserver / build (push) Successful in 9s

This commit is contained in:
2025-12-01 21:04:37 +01:00
parent 0dbade8f91
commit 6e720859ff
3 changed files with 583 additions and 41 deletions

View File

@@ -0,0 +1,139 @@
from enum import Enum
from typing import Dict
"""
This module defines an enumeration for Ethernet frame types (EtherTypes) and provides a mapping
from numeric EtherType values to their corresponding enum representation.
Source: https://en.wikipedia.org/wiki/EtherType (01/12/2025)
"""
class EtherTypeEnum(str, Enum):
IPv4 = "Internet Protocol version 4"
CHAOSNET = "Chaosnet"
ARP = "Address Resolution Protocol"
WAKE_ON_LAN = "Wake-on-LAN"
SRP = "Stream Reservation Protocol"
AVTP = "Audio Video Transport Protocol"
TRILL = "IETF TRILL Protocol"
DEC_MOP_RC = "DEC MOP RC"
DECNET_PHASE_IV = "DECnet Phase IV / DNA Routing"
DEC_LAT = "DEC Local Area Transport"
RARP = "Reverse Address Resolution Protocol"
APPLETALK = "AppleTalk (EtherTalk)"
IBM_SNA = "IBM SNA / LLC PDU"
AARP = "AppleTalk Address Resolution Protocol"
VLAN_8021Q = "VLAN-tagged (802.1Q)"
SLPP = "Simple Loop Prevention Protocol"
VLACP = "Virtual Link Aggregation Control Protocol"
IPX = "IPX"
QNX_QNET = "QNX Qnet"
IPv6 = "Internet Protocol version 6"
FLOW_CONTROL = "Ethernet Flow Control"
SLOW_PROTOCOLS = "Ethernet Slow Protocols (LACP)"
COBRANET = "CobraNet"
MPLS_UNICAST = "MPLS Unicast"
MPLS_MULTICAST = "MPLS Multicast"
PPPoE_DISCOVERY = "PPPoE Discovery Stage"
PPPoE_SESSION = "PPPoE Session Stage"
HOMEPLUG = "HomePlug 1.0 MME"
EAPOL = "EAP over LAN (802.1X)"
PROFINET = "PROFINET Protocol"
HYPERSCSI = "HyperSCSI"
ATA_OVER_ETHERNET = "ATA over Ethernet"
ETHERCAT = "EtherCAT Protocol"
Q_IN_Q = "Service VLAN (Q-in-Q S-Tag)"
ETH_POWERLINK = "Ethernet Powerlink"
GOOSE = "Generic Substation Events (GOOSE)"
GSE = "GSE Management Services"
SV = "Sampled Value Transmission"
MIKROTIK_ROMON = "MikroTik RoMON"
LLDP = "Link Layer Discovery Protocol"
SERCOS_III = "SERCOS III"
HOMEPLUG_GREENPHY = "HomePlug Green PHY"
MRP = "Media Redundancy Protocol"
MACSEC = "MAC Security (MACsec)"
PBB = "Provider Backbone Bridges (PBB)"
PTP = "Precision Time Protocol over Ethernet"
NC_SI = "NC-SI"
PRP = "Parallel Redundancy Protocol"
CFM = "Connectivity Fault Management (802.1ag / Y.1731)"
FCoE = "Fibre Channel over Ethernet"
FCoE_INIT = "FCoE Initialization Protocol"
ROCE = "RDMA over Converged Ethernet (RoCE)"
TTE = "TTEthernet Protocol Control Frame"
IEEE_1905_1 = "1905.1 IEEE Protocol"
HSR = "High-availability Seamless Redundancy"
ETH_CONFIG_TEST = "Ethernet Configuration Testing Protocol"
REDUNDANCY_TAG = "Redundancy Tag (802.1CB)"
UNKNOWN = "Unknown EtherType"
# Mapping from integer EtherType → enum
ETHERTYPE_MAP: Dict[int, EtherTypeEnum] = {
0x0800: EtherTypeEnum.IPv4,
0x0804: EtherTypeEnum.CHAOSNET,
0x0806: EtherTypeEnum.ARP,
0x0842: EtherTypeEnum.WAKE_ON_LAN,
0x22EA: EtherTypeEnum.SRP,
0x22F0: EtherTypeEnum.AVTP,
0x22F3: EtherTypeEnum.TRILL,
0x6002: EtherTypeEnum.DEC_MOP_RC,
0x6003: EtherTypeEnum.DECNET_PHASE_IV,
0x6004: EtherTypeEnum.DEC_LAT,
0x8035: EtherTypeEnum.RARP,
0x809B: EtherTypeEnum.APPLETALK,
0x80D5: EtherTypeEnum.IBM_SNA,
0x80F3: EtherTypeEnum.AARP,
0x8100: EtherTypeEnum.VLAN_8021Q,
0x8102: EtherTypeEnum.SLPP,
0x8103: EtherTypeEnum.VLACP,
0x8137: EtherTypeEnum.IPX,
0x8204: EtherTypeEnum.QNX_QNET,
0x86DD: EtherTypeEnum.IPv6,
0x8808: EtherTypeEnum.FLOW_CONTROL,
0x8809: EtherTypeEnum.SLOW_PROTOCOLS,
0x8819: EtherTypeEnum.COBRANET,
0x8847: EtherTypeEnum.MPLS_UNICAST,
0x8848: EtherTypeEnum.MPLS_MULTICAST,
0x8863: EtherTypeEnum.PPPoE_DISCOVERY,
0x8864: EtherTypeEnum.PPPoE_SESSION,
0x887B: EtherTypeEnum.HOMEPLUG,
0x888E: EtherTypeEnum.EAPOL,
0x8892: EtherTypeEnum.PROFINET,
0x889A: EtherTypeEnum.HYPERSCSI,
0x88A2: EtherTypeEnum.ATA_OVER_ETHERNET,
0x88A4: EtherTypeEnum.ETHERCAT,
0x88A8: EtherTypeEnum.Q_IN_Q,
0x88AB: EtherTypeEnum.ETH_POWERLINK,
0x88B8: EtherTypeEnum.GOOSE,
0x88B9: EtherTypeEnum.GSE,
0x88BA: EtherTypeEnum.SV,
0x88BF: EtherTypeEnum.MIKROTIK_ROMON,
0x88CC: EtherTypeEnum.LLDP,
0x88CD: EtherTypeEnum.SERCOS_III,
0x88E1: EtherTypeEnum.HOMEPLUG_GREENPHY,
0x88E3: EtherTypeEnum.MRP,
0x88E5: EtherTypeEnum.MACSEC,
0x88E7: EtherTypeEnum.PBB,
0x88F7: EtherTypeEnum.PTP,
0x88F8: EtherTypeEnum.NC_SI,
0x88FB: EtherTypeEnum.PRP,
0x8902: EtherTypeEnum.CFM,
0x8906: EtherTypeEnum.FCoE,
0x8914: EtherTypeEnum.FCoE_INIT,
0x8915: EtherTypeEnum.ROCE,
0x891D: EtherTypeEnum.TTE,
0x893A: EtherTypeEnum.IEEE_1905_1,
0x892F: EtherTypeEnum.HSR,
0x9000: EtherTypeEnum.ETH_CONFIG_TEST,
0xF1C1: EtherTypeEnum.REDUNDANCY_TAG,
}
def ethertype_from_int(value: int) -> EtherTypeEnum:
"""
Map a numeric EtherType value to the corresponding enum.
Returns UNKNOWN if not found.
"""
return ETHERTYPE_MAP.get(value, EtherTypeEnum.UNKNOWN)

View File

@@ -0,0 +1,315 @@
from enum import Enum
"""
This module defines an enumeration for IP protocol types and provides a mapping
from numeric IP protocol values to their corresponding enum representation.
Source: https://en.wikipedia.org/wiki/List_of_IP_protocol_numbers (01/12/2025)
"""
class IPProtocolEnum(str, Enum):
HOPOPT = "IPv6 Hop-by-Hop Option"
ICMP = "Internet Control Message Protocol"
IGMP = "Internet Group Management Protocol"
GGP = "Gateway-to-Gateway Protocol"
IP_IN_IP = "IP in IP Encapsulation"
ST = "Internet Stream Protocol"
TCP = "Transmission Control Protocol"
CBT = "Core-based Trees"
EGP = "Exterior Gateway Protocol"
IGP = "Interior Gateway Protocol"
BBN_RCC_MON = "BBN RCC Monitoring"
NVP_II = "Network Voice Protocol"
PUP = "Xerox PUP"
ARGUS = "ARGUS"
EMCON = "EMCON"
XNET = "Cross Net Debugger"
CHAOS = "Chaos Protocol"
UDP = "User Datagram Protocol"
MUX = "Multiplexing"
DCN_MEAS = "DCN Measurement Subsystems"
HMP = "Host Monitoring Protocol"
PRM = "Packet Radio Measurement"
XNS_IDP = "XEROX NS IDP"
TRUNK_1 = "Trunk 1"
TRUNK_2 = "Trunk 2"
LEAF_1 = "Leaf 1"
LEAF_2 = "Leaf 2"
RDP = "Reliable Data Protocol"
IRTP = "Internet Reliable Transaction Protocol"
ISO_TP4 = "ISO Transport Protocol Class 4"
NETBLT = "Bulk Data Transfer Protocol"
MFE_NSP = "MFE Network Services Protocol"
MERIT_INP = "MERIT Internodal Protocol"
DCCP = "Datagram Congestion Control Protocol"
THREE_PC = "Third Party Connect Protocol"
IDPR = "Inter-Domain Policy Routing"
XTP = "Xpress Transport Protocol"
DDP = "Datagram Delivery Protocol"
IDPR_CMTP = "IDPR Control Message Transport Protocol"
TP_PP = "TP++ Transport Protocol"
IL = "IL Transport Protocol"
IPV6 = "IPv6 Encapsulation"
SDRP = "Source Demand Routing Protocol"
IPV6_ROUTE = "IPv6 Routing Header"
IPV6_FRAG = "IPv6 Fragment Header"
IDRP = "Inter-Domain Routing Protocol"
RSVP = "Resource Reservation Protocol"
GRE = "Generic Routing Encapsulation"
DSR = "Dynamic Source Routing"
BNA = "Burroughs Network Architecture"
ESP = "Encapsulating Security Payload"
AH = "Authentication Header"
I_NLSP = "Integrated Net Layer Security Protocol"
SWIPE = "SwIPe"
NARP = "NBMA Address Resolution Protocol"
MOBILE = "IP Mobility"
TLSP = "Transport Layer Security Protocol"
SKIP = "Simple Key-Management for IP"
IPV6_ICMP = "ICMP for IPv6"
IPV6_NONXT = "No Next Header for IPv6"
IPV6_OPTS = "Destination Options for IPv6"
PROTO_61 = "Any host internal protocol"
CFTP = "CFTP"
PROTO_63 = "Any local network"
SAT_EXPAK = "SATNET and Backroom EXPAK"
KRYPTOLAN = "Kryptolan"
RVD = "MIT Remote Virtual Disk Protocol"
IPPC = "Internet Pluribus Packet Core"
PROTO_68 = "Any distributed file system"
SAT_MON = "SATNET Monitoring"
VISA = "VISA Protocol"
IPCU = "Internet Packet Core Utility"
CPNX = "Computer Protocol Network Executive"
CPHB = "Computer Protocol Heart Beat"
WSN = "Wang Span Network"
PVP = "Packet Video Protocol"
BR_SAT_MON = "Backroom SATNET Monitoring"
SUN_ND = "SUN ND Protocol (temporary)"
WB_MON = "Wideband Monitoring"
WB_EXPAK = "Wideband EXPAK"
ISO_IP = "International Organization for Standardization Internet Protocol"
VMTP = "Versatile Message Transaction Protocol"
SECURE_VMTP = "Secure VMTP"
VINES = "VINES"
TTP = "TTP (Transaction Transport Protocol / IPTM)"
NSFNET_IGP = "NSFNET-IGP"
DGP = "Dissimilar Gateway Protocol"
TCF = "TCF"
EIGRP = "EIGRP"
OSPF = "Open Shortest Path First"
SPRITE_RPC = "Sprite RPC Protocol"
LARP = "Locus Address Resolution Protocol"
MTP = "Multicast Transport Protocol"
AX25 = "AX.25 Packet Radio"
OS = "KA9Q NOS compatible IP over IP tunneling"
MICP = "Mobile Internetworking Control Protocol"
SCC_SP = "Semaphore Communications Security Protocol"
ETHERIP = "Ethernet-within-IP Encapsulation"
ENCAP = "Encapsulation Header"
PROTO_99 = "Any private encryption scheme"
GMTP = "GMTP"
IFMP = "Ipsilon Flow Management Protocol"
PNNI = "PNNI over IP"
PIM = "Protocol Independent Multicast"
ARIS = "IBM ARIS"
SCPS = "Space Communications Protocol Standards"
QNX = "QNX"
AN = "Active Networks"
IPCOMP = "IP Payload Compression Protocol"
SNP = "Sitara Networks Protocol"
COMPAQ_PEER = "Compaq Peer Protocol"
IPX_IN_IP = "IPX in IP"
VRRP = "Virtual Router Redundancy Protocol"
PGM = "PGM Reliable Transport Protocol"
PROTO_114 = "Any 0-hop protocol"
L2TP = "Layer Two Tunneling Protocol Version 3"
DDX = "D-II Data Exchange"
IATP = "Interactive Agent Transfer Protocol"
STP = "Schedule Transfer Protocol"
SRP = "SpectraLink Radio Protocol"
UTI = "Universal Transport Interface Protocol"
SMP = "Simple Message Protocol"
SM = "Simple Multicast Protocol"
PTP = "Performance Transparency Protocol"
ISIS = "IS-IS over IPv4"
FIRE = "Flexible Intra-AS Routing Environment"
CRTP = "Combat Radio Transport Protocol"
CRUDP = "Combat Radio User Datagram"
SSCOPMCE = "Service-Specific Connection-Oriented Protocol"
IPLT = "IPLT"
SPS = "Secure Packet Shield"
PIPE = "Private IP Encapsulation within IP"
SCTP = "Stream Control Transmission Protocol"
FC = "Fibre Channel"
RSVP_E2E_IGNORE = "RSVP End-to-End Ignore"
MOBILITY_HEADER = "Mobility Extension Header for IPv6"
UDPLITE = "UDPLite"
MPLS_IN_IP = "MPLS-in-IP"
MANET = "MANET Protocols"
HIP = "Host Identity Protocol"
SHIM6 = "Shim6"
WESP = "Wrapped Encapsulating Security Payload"
ROHC = "Robust Header Compression"
SRV6 = "Segment Routing over IPv6"
AGGFRAG = "AGGFRAG Encapsulation Payload for ESP"
NSH = "Network Service Header"
HOMA = "Homa transport protocol"
BIT_EMU = "Bit-stream Emulation"
EXPERIMENTAL_253 = "Use for experimentation (RFC 3692)"
EXPERIMENTAL_254 = "Use for experimentation (RFC 3692)"
RESERVED = "Reserved"
UNKNOWN = "Unknown"
IP_PROTOCOL_MAP = {
0: IPProtocolEnum.HOPOPT,
1: IPProtocolEnum.ICMP,
2: IPProtocolEnum.IGMP,
3: IPProtocolEnum.GGP,
4: IPProtocolEnum.IP_IN_IP,
5: IPProtocolEnum.ST,
6: IPProtocolEnum.TCP,
7: IPProtocolEnum.CBT,
8: IPProtocolEnum.EGP,
9: IPProtocolEnum.IGP,
10: IPProtocolEnum.BBN_RCC_MON,
11: IPProtocolEnum.NVP_II,
12: IPProtocolEnum.PUP,
13: IPProtocolEnum.ARGUS,
14: IPProtocolEnum.EMCON,
15: IPProtocolEnum.XNET,
16: IPProtocolEnum.CHAOS,
17: IPProtocolEnum.UDP,
18: IPProtocolEnum.MUX,
19: IPProtocolEnum.DCN_MEAS,
20: IPProtocolEnum.HMP,
21: IPProtocolEnum.PRM,
22: IPProtocolEnum.XNS_IDP,
23: IPProtocolEnum.TRUNK_1,
24: IPProtocolEnum.TRUNK_2,
25: IPProtocolEnum.LEAF_1,
26: IPProtocolEnum.LEAF_2,
27: IPProtocolEnum.RDP,
28: IPProtocolEnum.IRTP,
29: IPProtocolEnum.ISO_TP4,
30: IPProtocolEnum.NETBLT,
31: IPProtocolEnum.MFE_NSP,
32: IPProtocolEnum.MERIT_INP,
33: IPProtocolEnum.DCCP,
34: IPProtocolEnum.THREE_PC,
35: IPProtocolEnum.IDPR,
36: IPProtocolEnum.XTP,
37: IPProtocolEnum.DDP,
38: IPProtocolEnum.IDPR_CMTP,
39: IPProtocolEnum.TP_PP,
40: IPProtocolEnum.IL,
41: IPProtocolEnum.IPV6,
42: IPProtocolEnum.SDRP,
43: IPProtocolEnum.IPV6_ROUTE,
44: IPProtocolEnum.IPV6_FRAG,
45: IPProtocolEnum.IDRP,
46: IPProtocolEnum.RSVP,
47: IPProtocolEnum.GRE,
48: IPProtocolEnum.DSR,
49: IPProtocolEnum.BNA,
50: IPProtocolEnum.ESP,
51: IPProtocolEnum.AH,
52: IPProtocolEnum.I_NLSP,
53: IPProtocolEnum.SWIPE,
54: IPProtocolEnum.NARP,
55: IPProtocolEnum.MOBILE,
56: IPProtocolEnum.TLSP,
57: IPProtocolEnum.SKIP,
58: IPProtocolEnum.IPV6_ICMP,
59: IPProtocolEnum.IPV6_NONXT,
60: IPProtocolEnum.IPV6_OPTS,
62: IPProtocolEnum.CFTP,
64: IPProtocolEnum.SAT_EXPAK,
65: IPProtocolEnum.KRYPTOLAN,
66: IPProtocolEnum.RVD,
67: IPProtocolEnum.IPPC,
69: IPProtocolEnum.SAT_MON,
70: IPProtocolEnum.VISA,
71: IPProtocolEnum.IPCU,
72: IPProtocolEnum.CPNX,
73: IPProtocolEnum.CPHB,
74: IPProtocolEnum.WSN,
75: IPProtocolEnum.PVP,
76: IPProtocolEnum.BR_SAT_MON,
77: IPProtocolEnum.SUN_ND,
78: IPProtocolEnum.WB_MON,
79: IPProtocolEnum.WB_EXPAK,
80: IPProtocolEnum.ISO_IP,
81: IPProtocolEnum.VMTP,
82: IPProtocolEnum.SECURE_VMTP,
83: IPProtocolEnum.VINES,
84: IPProtocolEnum.TTP,
85: IPProtocolEnum.NSFNET_IGP,
86: IPProtocolEnum.DGP,
87: IPProtocolEnum.TCF,
88: IPProtocolEnum.EIGRP,
89: IPProtocolEnum.OSPF,
90: IPProtocolEnum.SPRITE_RPC,
91: IPProtocolEnum.LARP,
92: IPProtocolEnum.MTP,
93: IPProtocolEnum.AX25,
94: IPProtocolEnum.OS,
95: IPProtocolEnum.MICP,
96: IPProtocolEnum.SCC_SP,
97: IPProtocolEnum.ETHERIP,
98: IPProtocolEnum.ENCAP,
100: IPProtocolEnum.GMTP,
101: IPProtocolEnum.IFMP,
102: IPProtocolEnum.PNNI,
103: IPProtocolEnum.PIM,
104: IPProtocolEnum.ARIS,
105: IPProtocolEnum.SCPS,
106: IPProtocolEnum.QNX,
107: IPProtocolEnum.AN,
108: IPProtocolEnum.IPCOMP,
109: IPProtocolEnum.SNP,
110: IPProtocolEnum.COMPAQ_PEER,
111: IPProtocolEnum.IPX_IN_IP,
112: IPProtocolEnum.VRRP,
113: IPProtocolEnum.PGM,
115: IPProtocolEnum.L2TP,
116: IPProtocolEnum.DDX,
117: IPProtocolEnum.IATP,
118: IPProtocolEnum.STP,
119: IPProtocolEnum.SRP,
120: IPProtocolEnum.UTI,
121: IPProtocolEnum.SMP,
122: IPProtocolEnum.SM,
123: IPProtocolEnum.PTP,
124: IPProtocolEnum.ISIS,
125: IPProtocolEnum.FIRE,
126: IPProtocolEnum.CRTP,
127: IPProtocolEnum.CRUDP,
128: IPProtocolEnum.SSCOPMCE,
129: IPProtocolEnum.IPLT,
130: IPProtocolEnum.SPS,
131: IPProtocolEnum.PIPE,
132: IPProtocolEnum.SCTP,
133: IPProtocolEnum.FC,
134: IPProtocolEnum.RSVP_E2E_IGNORE,
135: IPProtocolEnum.MOBILITY_HEADER,
136: IPProtocolEnum.UDPLITE,
137: IPProtocolEnum.MPLS_IN_IP,
138: IPProtocolEnum.MANET,
139: IPProtocolEnum.HIP,
140: IPProtocolEnum.SHIM6,
141: IPProtocolEnum.WESP,
142: IPProtocolEnum.ROHC,
143: IPProtocolEnum.SRV6,
144: IPProtocolEnum.AGGFRAG,
145: IPProtocolEnum.NSH,
146: IPProtocolEnum.HOMA,
147: IPProtocolEnum.BIT_EMU,
253: IPProtocolEnum.EXPERIMENTAL_253,
254: IPProtocolEnum.EXPERIMENTAL_254,
255: IPProtocolEnum.RESERVED,
}
def protocol_from_number(n: int) -> IPProtocolEnum:
return IP_PROTOCOL_MAP.get(n, IPProtocolEnum.UNKNOWN)

View File

@@ -4,7 +4,6 @@ import threading
import os import os
import time import time
from typing import List, Dict, Optional from typing import List, Dict, Optional
import asyncpg import asyncpg
from scapy.all import ( from scapy.all import (
Ether, Ether,
@@ -18,13 +17,15 @@ from scapy.all import (
Dot1Q, Dot1Q,
Raw, Raw,
) )
# ---- New imports for AF_PACKET optimized reader ----------------------
import socket import socket
import selectors import selectors
import errno import errno
import struct import struct
from src.Models.etherType import EtherTypeEnum, ethertype_from_int
from src.Models.ip_protocol import IPProtocolEnum, protocol_from_number
# ---- Logging ---------------------------------------------------------- # ---- Logging ----------------------------------------------------------
logging.basicConfig(level=logging.INFO) logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("af_packet_sniffer") logger = logging.getLogger("af_packet_sniffer")
@@ -170,7 +171,7 @@ async def db_insert_packet(pkt_info: dict, bridge: str) -> None:
pkt_info.get("vlan_id"), pkt_info.get("vlan_id"),
pkt_info.get("src_ip"), pkt_info.get("src_ip"),
pkt_info.get("dst_ip"), pkt_info.get("dst_ip"),
pkt_info.get("protocol_name"), pkt_info.get("protocol"),
pkt_info.get("src_port"), pkt_info.get("src_port"),
pkt_info.get("dst_port"), pkt_info.get("dst_port"),
pkt_info["length"], pkt_info["length"],
@@ -192,13 +193,15 @@ def parse_packet(pkt, bridge: str) -> None:
Parse a scapy packet object and collect a normalized dict of metadata Parse a scapy packet object and collect a normalized dict of metadata
which is then scheduled to be written to the database asynchronously. which is then scheduled to be written to the database asynchronously.
The function expects that 'pkt' is a Scapy Packet and that we set Enhancements:
'pkt.sniffed_on' before calling this function. - Uses EtherType and IP Protocol enums (human-readable) for API documentation.
- Records both raw numeric values and enum descriptions.
- Proper VLAN handling (Dot1Q inner ethertype).
- Keeps `protocol_name` (string) for backward compatibility.
""" """
pkt_iface = getattr(pkt, "sniffed_on", None) pkt_iface = getattr(pkt, "sniffed_on", None)
if not pkt_iface: if not pkt_iface:
# If sniffed_on is missing we cannot determine the interface context; # If sniffed_on is missing we cannot determine the interface context; skip this packet.
# skip this packet.
return return
logger.debug("Packet captured on %s, bridge %s", pkt_iface, bridge) logger.debug("Packet captured on %s, bridge %s", pkt_iface, bridge)
@@ -210,78 +213,163 @@ def parse_packet(pkt, bridge: str) -> None:
"raw": bytes(pkt), "raw": bytes(pkt),
"src_mac": None, "src_mac": None,
"dst_mac": None, "dst_mac": None,
"eth_type": None, # eth types: both raw numeric and enum/description
"eth_type_raw": None,
"eth_type": EtherTypeEnum.UNKNOWN, # enum / human description
"vlan_id": None, "vlan_id": None,
# IP protocol: raw numeric and enum/description
"protocol_raw": None,
"protocol": IPProtocolEnum.UNKNOWN,
# backward-compatible string label (older code)
"protocol_name": None,
# L3/L4 fields
"src_ip": None, "src_ip": None,
"dst_ip": None, "dst_ip": None,
"protocol_name": None,
"src_port": None, "src_port": None,
"dst_port": None, "dst_port": None,
} }
# --- Layer extraction --- # --- Layer extraction ---
# Ethernet layer # Ethernet layer + EtherType
if Ether in pkt: if Ether in pkt:
pkt_info["src_mac"] = pkt[Ether].src try:
pkt_info["dst_mac"] = pkt[Ether].dst pkt_info["src_mac"] = pkt[Ether].src
pkt_info["eth_type"] = hex(pkt[Ether].type) except Exception:
pkt_info["src_mac"] = None
try:
pkt_info["dst_mac"] = pkt[Ether].dst
except Exception:
pkt_info["dst_mac"] = None
# VLAN (802.1Q) # Base ethertype (may be 0x8100 for VLAN)
if Dot1Q in pkt: eth_type_raw: Optional[int] = None
pkt_info["vlan_id"] = pkt[Dot1Q].vlan try:
eth_type_raw = int(pkt[Ether].type)
except Exception:
eth_type_raw = None
# ARP # VLAN (Dot1Q) may contain the inner ethertype
if Dot1Q in pkt:
try:
# Dot1Q.type is the encapsulated ethertype
inner = int(pkt[Dot1Q].type)
if inner:
eth_type_raw = inner
except Exception:
# ignore and keep whatever eth_type_raw was
pass
# capture vlan id if present
try:
pkt_info["vlan_id"] = int(pkt[Dot1Q].vlan)
except Exception:
pkt_info["vlan_id"] = None
# Fill eth_type fields (raw + enum)
if eth_type_raw is not None:
pkt_info["eth_type_raw"] = eth_type_raw
try:
pkt_info["eth_type"] = ethertype_from_int(eth_type_raw)
except Exception:
pkt_info["eth_type"] = EtherTypeEnum.UNKNOWN
else:
# Unknown / missing ethertype
pkt_info["eth_type_raw"] = None
pkt_info["eth_type"] = EtherTypeEnum.UNKNOWN
# ARP (layer 2/3)
if ARP in pkt: if ARP in pkt:
pkt_info["protocol_name"] = "ARP" pkt_info["protocol_name"] = "ARP"
pkt_info["src_ip"] = pkt[ARP].psrc pkt_info["src_ip"] = getattr(pkt[ARP], "psrc", None)
pkt_info["dst_ip"] = pkt[ARP].pdst pkt_info["dst_ip"] = getattr(pkt[ARP], "pdst", None)
pkt_info["src_port"] = None pkt_info["src_port"] = None
pkt_info["dst_port"] = None pkt_info["dst_port"] = None
# ARP is a L2 protocol — leave protocol_raw/protocol as UNKNOWN (or set to a sentinel if desired)
# IPv4 # IPv4
if IP in pkt: if IP in pkt:
pkt_info["src_ip"] = pkt[IP].src try:
pkt_info["dst_ip"] = pkt[IP].dst pkt_info["src_ip"] = pkt[IP].src
proto = pkt[IP].proto except Exception:
if proto == 6 and TCP in pkt: pkt_info["src_ip"] = None
try:
pkt_info["dst_ip"] = pkt[IP].dst
except Exception:
pkt_info["dst_ip"] = None
# protocol number (IPv4 'protocol' field)
try:
proto_num = int(pkt[IP].proto)
except Exception:
proto_num = None
if proto_num is not None:
pkt_info["protocol_raw"] = proto_num
try:
pkt_info["protocol"] = protocol_from_number(proto_num)
except Exception:
pkt_info["protocol"] = IPProtocolEnum.UNKNOWN
# Common transports
if proto_num == 6 and TCP in pkt:
pkt_info["protocol_name"] = "TCP" pkt_info["protocol_name"] = "TCP"
pkt_info["src_port"] = pkt[TCP].sport pkt_info["src_port"] = getattr(pkt[TCP], "sport", None)
pkt_info["dst_port"] = pkt[TCP].dport pkt_info["dst_port"] = getattr(pkt[TCP], "dport", None)
elif proto == 17 and UDP in pkt: elif proto_num == 17 and UDP in pkt:
pkt_info["protocol_name"] = "UDP" pkt_info["protocol_name"] = "UDP"
pkt_info["src_port"] = pkt[UDP].sport pkt_info["src_port"] = getattr(pkt[UDP], "sport", None)
pkt_info["dst_port"] = pkt[UDP].dport pkt_info["dst_port"] = getattr(pkt[UDP], "dport", None)
elif proto == 1 and ICMP in pkt: elif proto_num == 1 and ICMP in pkt:
pkt_info["protocol_name"] = "ICMP" pkt_info["protocol_name"] = "ICMP"
else: else:
pkt_info["protocol_name"] = f"IP_PROTO_{proto}" # leave protocol_name as numeric fallback if not matched
if pkt_info["protocol_name"] is None:
pkt_info["protocol_name"] = f"IP_PROTO_{proto_num}" if proto_num is not None else None
# IPv6 # IPv6
if IPv6 in pkt: if IPv6 in pkt:
pkt_info["src_ip"] = pkt[IPv6].src try:
pkt_info["dst_ip"] = pkt[IPv6].dst pkt_info["src_ip"] = pkt[IPv6].src
nh = pkt[IPv6].nh except Exception:
pkt_info["src_ip"] = None
try:
pkt_info["dst_ip"] = pkt[IPv6].dst
except Exception:
pkt_info["dst_ip"] = None
# next header / nh value
try:
nh = int(pkt[IPv6].nh)
except Exception:
nh = None
if nh is not None:
pkt_info["protocol_raw"] = nh
try:
pkt_info["protocol"] = protocol_from_number(nh)
except Exception:
pkt_info["protocol"] = IPProtocolEnum.UNKNOWN
if nh == 6 and TCP in pkt: if nh == 6 and TCP in pkt:
pkt_info["protocol_name"] = "TCP" pkt_info["protocol_name"] = "TCP"
pkt_info["src_port"] = pkt[TCP].sport pkt_info["src_port"] = getattr(pkt[TCP], "sport", None)
pkt_info["dst_port"] = pkt[TCP].dport pkt_info["dst_port"] = getattr(pkt[TCP], "dport", None)
elif nh == 17 and UDP in pkt: elif nh == 17 and UDP in pkt:
pkt_info["protocol_name"] = "UDP" pkt_info["protocol_name"] = "UDP"
pkt_info["src_port"] = pkt[UDP].sport pkt_info["src_port"] = getattr(pkt[UDP], "sport", None)
pkt_info["dst_port"] = pkt[UDP].dport pkt_info["dst_port"] = getattr(pkt[UDP], "dport", None)
elif ICMPv6Unknown in pkt: elif ICMPv6Unknown in pkt:
pkt_info["protocol_name"] = "ICMPv6" pkt_info["protocol_name"] = "ICMPv6"
else: else:
pkt_info["protocol_name"] = f"IPV6_PROTO_{nh}" if pkt_info["protocol_name"] is None:
pkt_info["protocol_name"] = f"IPV6_PROTO_{nh}" if nh is not None else None
# Raw payload / fallback protocol label # Raw payload / fallback protocol label
if Raw in pkt and not pkt_info["protocol_name"]: if Raw in pkt and not pkt_info["protocol_name"]:
pkt_info["protocol_name"] = "RAW" pkt_info["protocol_name"] = "RAW"
# Submit DB insert to background asyncio loop from this thread. # Submit DB insert to background asyncio loop from this thread
asyncio.run_coroutine_threadsafe(db_insert_packet(pkt_info, bridge), async_loop) asyncio.run_coroutine_threadsafe(db_insert_packet(pkt_info, bridge), async_loop)
# ------------------------- # -------------------------
# AF_PACKET optimized reader # AF_PACKET optimized reader
# ------------------------- # -------------------------