I have a low level comunication between two nodes using Ethernet packets (2-layer, no UDP/IP nor TCP/IP). These packets has the VLAN field inside, my interface is configured in promiscuous mode and it is able to read them completely due to I can see the VLAN tag in Wireshark in my Ubuntu system.
Using python, I'm able to read the entire packet except the VLAN field. The field is vanished and after the source MAC field the Ethertype comes in place.
import socket
sock = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(0x0003))
msg = sock.recvmsg(4096)
It is possible to do this with socket python module? Am I missing something in my configuration or it is a NIC issue?
Thanks in advance,
Late to the party, see https://stackoverflow.com/a/59760058/5459467 for full details.
I advise to use scapy's sockets (conf.L2socket
or sniff
) that have this code implemented. Otherwise use the snippet below:
import ctypes, socket
# From bits/socket.h
SOL_PACKET = 263
# From asm/socket.h
SO_ATTACH_FILTER = 26
ETH_P_8021Q = 0x8100
PACKET_AUXDATA = 8
TP_STATUS_VLAN_VALID = 1 << 4
class tpacket_auxdata(ctypes.Structure):
_fields_ = [
("tp_status", ctypes.c_uint),
("tp_len", ctypes.c_uint),
("tp_snaplen", ctypes.c_uint),
("tp_mac", ctypes.c_ushort),
("tp_net", ctypes.c_ushort),
("tp_vlan_tci", ctypes.c_ushort),
("tp_padding", ctypes.c_ushort),
]
def _recv_raw(sock, x=65535):
"""Internal function to receive a Packet,
and process ancillary data.
"""
flags_len = socket.CMSG_LEN(4096)
pkt, ancdata, flags, sa_ll = sock.recvmsg(x, flags_len)
if not pkt:
return pkt, sa_ll
for cmsg_lvl, cmsg_type, cmsg_data in ancdata:
# Check available ancillary data
if (cmsg_lvl == SOL_PACKET and cmsg_type == PACKET_AUXDATA):
# Parse AUXDATA
auxdata = tpacket_auxdata.from_buffer_copy(cmsg_data)
if auxdata.tp_vlan_tci != 0 or \
auxdata.tp_status & TP_STATUS_VLAN_VALID:
# Insert VLAN tag
tag = struct.pack(
"!HH",
ETH_P_8021Q,
auxdata.tp_vlan_tci
)
pkt = pkt[:12] + tag + pkt[12:]
return pkt
(From https://github.com/secdev/scapy/pull/2091)
But first, while starting your socket, use
sock.setsockopt(SOL_PACKET, PACKET_AUXDATA, 1)