在Python中读取原始以太网数据包的VLAN字段

时间:2019-06-18 16:00:40

标签: python sockets packet-sniffers vlan raw-ethernet

我使用以太网数据包(2层,没有UDP / IP或TCP / IP)在两个节点之间进行了低级通信。这些数据包的内部都有VLAN字段,我的接口配置为混杂模式,由于可以在Ubuntu系统的Wireshark中看到VLAN标签,因此可以完全读取它们。

使用python,我能够读取VLAN字段以外的整个数据包。该字段消失,并且在源MAC字段之后,以太网类型就位。

import socket

sock = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(0x0003))

msg = sock.recvmsg(4096)

是否可以使用套接字python模块来执行此操作?我的配置中缺少什么吗?还是网卡问题?

预先感谢

2 个答案:

答案 0 :(得分:1)

晚了聚会,有关详细信息,请参见https://stackoverflow.com/a/59760058/5459467

我建议使用已实现此代码的scapy's socketsconf.L2socketsniff)。否则,请使用以下代码段:

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

(来自https://github.com/secdev/scapy/pull/2091

但是首先,在启动套接字时,使用

sock.setsockopt(SOL_PACKET, PACKET_AUXDATA, 1)

答案 1 :(得分:0)

需要配置NIC驱动程序以保留802.1Q标签。并非所有的NIC都可以做到这一点,而且我不认为有标准的方法可以做到这一点。