I\'m trying to create software that sniffes DHCP-offers from diffrent VLAN\'s and my problem is that the packets recv\'ed by me contains no VLAN-tags. I\'m using raw sockets, an
If I understand the Linux code correctly, VLAN tags are stripped from packets' payload early and stored in a field that is not accessible through the raw sockets API. Instead, try to do what wireshark does, i.e., use the pcap API.
This is old, but this still hasn't been solved:
When VLAN offload is enabled on the NIC Linux will not deliver the VLAN tag in the data returned by recv. Instead, it delivers the VLAN TCI in a control message.
To get the control fields, you need to use PACKET_AUXDATA
, which will add the following to ancillary data:
struct tpacket_auxdata {
__u32 tp_status;
__u32 tp_len; /* packet length */
__u32 tp_snaplen; /* captured length */
__u16 tp_mac;
__u16 tp_net;
__u16 tp_vlan_tci;
__u16 tp_padding;
};
For instance
sock.setsockopt(SOL_PACKET, PACKET_AUXDATA, 1)
Once that is done, use recvmsg()
and iterate through the ancillary data looking for PACKET_AUXDATA
. Get tp_vlan_tci out of it, and inject this back into the packet data.
Examples of code
https://github.com/the-tcpdump-group/libpcap/blob/3a7962215f4f3b13ac792ad0e0487a53c0f1178e/pcap-linux.c#L1756
import ctypes, socket
# From bits/socket.h
SOL_PACKET = 263
# From asm/socket.h
SO_ATTACH_FILTER = 26
ETH_P_8021Q = 0x8100
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)