在 Python 中读取原始以太网数据包的 VLAN 字段
Reading VLAN field of a raw ethernet packet in Python
我使用以太网数据包在两个节点之间进行低级通信(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 问题?
提前致谢,
NIC 驱动程序需要配置为保留 802.1Q 标签。并非所有 NIC 都可以做到这一点,而且我认为没有标准的方法可以做到这一点。
派对迟到了,请参阅 了解完整详情。
我建议使用已实现此代码的 scapy's sockets(conf.L2socket
或 sniff
)。否则使用下面的代码片段:
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 层,没有 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 问题?
提前致谢,
NIC 驱动程序需要配置为保留 802.1Q 标签。并非所有 NIC 都可以做到这一点,而且我认为没有标准的方法可以做到这一点。
派对迟到了,请参阅 了解完整详情。
我建议使用已实现此代码的 scapy's sockets(conf.L2socket
或 sniff
)。否则使用下面的代码片段:
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)