Linux桥接环境下NetfilterQueue set_payload保留原payload问题求解
问题根因及解决方案
核心根因1:桥接二层报文默认不经过iptables过滤链
Linux 桥接默认仅处理二层转发,桥接流量不会经过IP层的netfilter钩子,你配置的iptables -A FORWARD规则无法匹配到桥接转发的报文,NFQueue实际没有收到目标流量,自然不会生效。
核心根因2:Python3 NetfilterQueue API适配问题
绝大多数Python3版本的NetfilterQueue依赖包,不支持set_payload()后调用pkt.accept()的修改逻辑,修改后的报文不会被提交到内核,最终转发的还是原始报文。
核心根因3:报文修改后未补全必要字段
你仅删除了IP和TCP的校验和,未更新IP头的总长度字段,如果替换前后payload长度不一致,修改后的报文会被判定为无效报文,触发对端重传,你抓到的还是原始重传报文。
drop+send方案失效原因
Scapy默认send()走三层路由栈发包,不会从桥接接口直接发送二层帧,且未指定出口接口,所以桥接口抓不到对应报文。
修复步骤
1. 开启桥接流量过iptables的内核开关
执行以下命令:
sysctl -w net.bridge.bridge-nf-call-iptables=1 # 如需永久生效,执行以下命令写入配置文件 echo "net.bridge.bridge-nf-call-iptables=1" >> /etc/sysctl.conf sysctl -p
执行后通过iptables -L FORWARD -v查看规则计数,确认桥接流量已经匹配到FORWARD链规则。
2. 修改Python3处理代码
直接使用set_verdict_modified接口提交修改后的报文,同时补全报文字段更新逻辑,示例代码如下:
import scapy.all as scapy from netfilterqueue import NetfilterQueue def print_and_accept(pkt): http_packet = scapy.IP(pkt.get_payload()) if http_packet.haslayer(scapy.Raw) and http_packet.haslayer(scapy.TCP): if http_packet[scapy.TCP].dport == 80 or http_packet[scapy.TCP].sport == 80: try: # 兼容非UTF-8编码的payload raw_content = http_packet[scapy.Raw].load.decode('utf-8', errors='ignore') modified_content = raw_content.replace("text", "txet").encode('utf-8') http_packet[scapy.Raw].load = modified_content # 自动重新计算IP头长度、IP校验和、TCP校验和 del http_packet[scapy.IP].len del http_packet[scapy.IP].chksum del http_packet[scapy.TCP].chksum # 直接提交修改后的报文 pkt.set_verdict_modified(NetfilterQueue.NF_ACCEPT, bytes(http_packet), len(http_packet)) print('>> Payload Changed') return except: pass # 无需修改的报文直接放行 pkt.accept() nfqueue = NetfilterQueue() nfqueue.bind(0, print_and_accept) try: nfqueue.run() except KeyboardInterrupt: print('exiting') nfqueue.unbind()
3. drop+send方案修复方法
首先关闭桥接网卡的TX offload功能,避免网卡覆盖Scapy计算的校验和:
ethtool -K 你的桥接接口名称 tx off
修改代码中的报文提交逻辑,使用二层发送接口指定桥接接口发包:
# 丢弃原始报文 pkt.drop() # br0替换为你的桥接接口名称 scapy.sendp(http_packet, iface="br0", verbose=0)
注意事项
- 该方案仅对HTTP明文流量生效,HTTPS加密流量修改后会直接断开连接
- 如果你修改了HTTP响应的内容长度,需要同步修改
Content-Length头的值,否则会出现页面加载异常、截断等问题 - 需提前关闭系统的rp_filter反向路径校验,避免修改后的报文被内核丢弃
内容的提问来源于stack exchange,提问作者Fares Meg
相关产品推荐
相关产品推荐

