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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 15:57:03