Python AF_PACKET原始套接字无法捕获ICMP包,参数0x0003是否覆盖所有包?
问题描述
我尝试捕获网卡接口上接收的所有数据包,使用了以下代码:
import socket import sys try: s = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.ntohs(0x0003)) s.bind((interface, 0)) except socket.error as msg: print('Socket could not be created to read the traffic on %s. Error Code : %s ' %(interface, str(msg))) sys.exit() # receive a packet while True: packet = s.recvfrom(65565) print(packet)
目前该代码可以捕获ARP、DHCP数据包,但无法捕获ICMP数据包。我原本以为socket.ntohs(0x0003)会包含所有数据包,请问我是否遗漏了什么配置?
解决方法
你用的0x0003对应ETH_P_ALL,理论上确实会捕获所有以太网二层帧,但抓不到ICMP通常是以下几个原因:
1. 未开启网卡混杂模式
默认状态下,网卡只会接收目标MAC为自身、广播或多播的数据包。如果要捕获经过网卡的所有数据包(包括发给其他主机的ICMP),必须手动开启混杂模式——AF_PACKET套接字不会自动启用该模式:
方法一:用PACKET_ADD_MEMBERSHIP配置
import struct # 开启混杂模式 membership = struct.pack("IHH8s", socket.PACKET_MR_PROMISC, 0, 0, interface.encode()) s.setsockopt(socket.SOL_PACKET, socket.PACKET_ADD_MEMBERSHIP, membership)
方法二:用fcntl操作网卡标志(Linux专属)
import fcntl SIOCGIFFLAGS = 0x8913 SIOCSIFFLAGS = 0x8914 # 获取当前网卡标志 ifreq = struct.pack('16sH', interface.encode(), 0) flags = fcntl.ioctl(s, SIOCGIFFLAGS, ifreq) flags = struct.unpack('16sH', flags)[1] # 设置混杂模式标志(0x100对应IFF_PROMISC) fcntl.ioctl(s, SIOCSIFFLAGS, struct.pack('16sH', interface.encode(), flags | 0x100))
2. 检查系统防火墙规则
iptables/ebtables等防火墙可能过滤了ICMP数据包,导致原始套接字无法捕获。可以临时关闭防火墙测试,或者添加允许ICMP的规则:
# 临时清空iptables规则(Linux) sudo iptables -F sudo iptables -X sudo iptables -P INPUT ACCEPT sudo iptables -P OUTPUT ACCEPT
3. 确认捕获接口是否正确
如果测试的是ping 127.0.0.1这类回环ICMP,数据包只会经过lo接口,不会走物理网卡。此时需要将代码中的interface改为lo,才能捕获回环的ICMP包。
内容的提问来源于stack exchange,提问作者user19416874
相关产品推荐
相关产品推荐

