简体   繁体   中英

Reading VLAN field of a raw ethernet packet in Python

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)

The NIC driver needs to be configured to leave the 802.1Q tag in place. Not all NICs can do that and I don't believe there's a standard way to do it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM