You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 20:18:20