Python实现数据包嗅探解析以太网帧时MAC与协议字段取值异常
Python原始套接字解析以太网帧字段异常问题排查
核心错误原因
你当前代码的问题本质是创建的套接字类型无法获取以太网链路层帧头,所有解析逻辑的输入从最开始就错了:
- 你在Windows下创建的是
AF_INET地址族的原始套接字,配合SIO_RCVALL控制选项只能收到IP层及以上的报文,操作系统会在交付数据前剥掉14字节的以太网帧头,recvfrom返回的raw_data第一个字节就是IP报文的起始位置,完全不包含目的MAC、源MAC、以太网协议类型这三个链路层字段。 - 你硬将IP头的前14字节按以太网帧结构解析,得到的结果自然完全不符合预期:
- 解析出的"MAC地址"实际是IP头的版本、服务类型、报文长度、标识等字段拼接出来的值,和真实MAC无关
- 解析出的"以太网协议号"实际是本机源IP地址的前两个字节,这也和你观察到的"连接不同WiFi时该值变化"的现象完全吻合
- 你注释里的Linux平台代码还有一处拼写错误:
socket.SOCKET_RAW应为socket.SOCK_RAW,修正后Linux下可正常获取链路层帧。
修复方案
- 跨平台抓以太网帧(推荐):Windows原生套接字不支持直接获取链路层以太网帧头,需要先安装Npcap抓包驱动,通过pcap接口抓包(可以直接用
scapy、pyshark等封装好的库,不用自己处理平台差异)。 - 仅Linux环境运行:直接使用你注释中的逻辑,修正拼写错误即可:
# Linux平台正确的原始套接字创建代码 conn = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.ntohs(3)) - 无需获取MAC地址,仅解析IP/TCP/UDP层:删除现有以太网帧解析逻辑,直接从IP头开始解析即可。你当前的套接字配置已经开启了
IP_HDRINCL选项,能拿到完整IP头,IP头偏移9位置的1字节就是IP协议号:6对应TCP、17对应UDP。
快速验证方法
你可以在recvfrom拿到raw_data后立刻打印第一个字节的值,正常IPv4报文的IP头第一个字节固定为0x45(4位版本号为4,4位头长度为5*4=20字节),如果打印结果确实是0x45,就能直接证明收到的数据没有以太网帧头。
内容的提问来源于stack exchange,提问作者X0-user-0X
相关产品推荐
相关产品推荐

