简体   繁体   English

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

[英]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).我使用以太网数据包(2 层,无 UDP/IP 或 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.这些数据包内部有 VLAN 字段,我的接口配置为混杂模式,由于我可以在 Ubuntu 系统的 Wireshark 中看到 VLAN 标记,因此它能够完全读取它们。

Using python, I'm able to read the entire packet except the VLAN field.使用 python,我能够读取除 VLAN 字段之外的整个数据包。 The field is vanished and after the source MAC field the Ethertype comes in place.该字段消失,在源 MAC 字段之后,以太网类型就位。

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?可以用 socket python 模块做到这一点吗? Am I missing something in my configuration or it is a NIC issue?我的配置中是否遗漏了某些内容,或者是 NIC 问题?

Thanks in advance,提前致谢,

Late to the party, see https://stackoverflow.com/a/59760058/5459467 for full details.聚会迟到,请参阅https://stackoverflow.com/a/59760058/5459467了解完整详情。

I advise to use scapy's sockets ( conf.L2socket or sniff ) that have this code implemented.我建议使用实现了此代码的scapy 套接字conf.L2socketsniff )。 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 ) (来自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.需要配置 NIC 驱动程序以保留 802.1Q 标记。 Not all NICs can do that and I don't believe there's a standard way to do it.并非所有 NIC 都可以做到这一点,我认为没有标准的方法可以做到这一点。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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