【问题标题】:Reading VLAN field of a raw ethernet packet in Python在 Python 中读取原始以太网数据包的 VLAN 字段
【发布时间】:2019-11-01 07:53:45
【问题描述】:

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

使用 python,我可以读取除 VLAN 字段之外的整个数据包。该字段消失了,在源 MAC 字段之后,Ethertype 就位。

import socket

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

msg = sock.recvmsg(4096)

可以用socket python模块做到这一点吗?是我的配置遗漏了什么还是 NIC 问题?

提前致谢,

【问题讨论】:

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


    【解决方案1】:

    聚会迟到了,详情请见https://stackoverflow.com/a/59760058/5459467

    我建议使用已实现此代码的scapy's socketsconf.L2socketsniff)。否则使用下面的sn-p:

    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)
    

    【讨论】:

      【解决方案2】:

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

      【讨论】:

      • 那么,为什么 Wireshark 可以读取数据包而我的 python 脚本却不能呢?我不明白...
      • 原始套接字可能不够用。很可能,您需要直接从驱动程序中捕获数据包。
      猜你喜欢
      • 2015-05-20
      • 2017-12-26
      • 2011-12-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-02-16
      • 1970-01-01
      • 2012-08-27
      相关资源
      最近更新 更多