You need to enable JavaScript to run this app. Scapy嗅探修改后的UDP数据包无法发送至目标主机问题排查
优惠活动
大模型
产品
解决方案
定价
更多

Scapy嗅探修改后的UDP数据包无法发送至目标主机问题排查

核心问题根因

排查所有现象后,问题本质来自两个Scapy使用的常见误区,和网络防火墙、路由配置本身无关:

  • 嗅探捕获的RTP UDP包自带完整的链路层FCS、IP头校验和、UDP头校验和,这些值是基于原包的IP、端口计算的。修改完IP地址、端口号后,这些校验和完全失效。Scapy 2.2.0版本的默认行为是:如果数据包已经存在某字段的赋值,无论值是否正确,都不会自动重新计算。带错误校验和的包提交给FreeBSD内核协议栈后,会被直接校验丢弃,根本不会从vr0接口发出,这就是你在接口抓包看不到修改后数据包的原因。
  • 手动修改以太网层源目MAC时,跨网段目标的二层目的MAC应该是默认网关(192.168.12.1)的MAC,而非远端目标主机的MAC。硬填远端MAC会导致二层帧无法被网关转发,哪怕校验和正确也无法送达。

分场景问题说明

同网段场景下修改后包无法发送的原因

同网段转发目标192.168.12.112的场景下,你测试从零构造的新UDP包可以正常送达,是因为新构造的包没有旧的残留字段,Scapy会自动计算正确的IP、UDP校验和,内核可以正常接收转发。而修改嗅探包的场景因为携带了失效的旧校验和,被内核直接丢弃。
修复方式为修改完所有字段后,强制删除旧的校验和字段,让Scapy在发包时自动重算正确值:

# 删除IP层旧校验和
del pkt[IP].chksum
# 删除UDP层旧校验和
del pkt[UDP].chksum
# 删除捕获包中残留的以太网层FCS校验
if pkt.haslayer(Ether):
    del pkt[Ether].fcs

跨网段场景下新构造包无法送达的原因

这部分问题和校验和无关,属于发包机制和路由逻辑的问题:

  • Scapy的send()是三层发包函数,本身不会手动构造以太网头,会自动读取系统路由表,查询目标对应的下一跳地址,通过ARP解析下一跳的MAC后再提交给内核发包。你测试的send(IP(dst='192.168.20.111')/UDP(dport=10000))本身的发包逻辑没有问题,数据包确实会从vr0接口发出。
  • 跨网段收不到包的常见排查点:
    • 确认默认网关192.168.12.1的ARP表中是否存在本机192.168.12.111的MAC条目,FreeBSD9.2系统下arp服务异常时,网关会因为没有本机MAC地址,丢弃回程路由的数据包。
    • 确认网关的路由配置中,存在回程到192.168.12.0/24网段的路由,否则网关收到发往192.168.20.111的包后,不知道如何把回包发回给你。
    • 如果之前测试时手动给包添加了以太网层,硬填了远端主机的MAC作为目的MAC,会导致二层帧无法被网关接收,自然无法送达跨网段的目标。

优化后的可运行实现

避免直接修改完整嗅探包的残留字段,从零构造干净的三层数据包,手动强制重算所有校验和,让Scapy自动处理二层转发逻辑:

from scapy.all import *

def forward_packet(original_pkt, target_ip, target_port):
    # 提取原RTP包的负载,不继承原包的旧IP/UDP字段
    payload = original_pkt[UDP].payload
    # 构造干净的三层转发包
    fwd_pkt = IP(
        dst=target_ip,
        src="192.168.12.111",
        ttl=64 # 设置合理TTL,避免原包TTL残留在转发途中被丢弃
    ) / UDP(
        dport=target_port,
        sport=original_pkt[UDP].sport
    ) / payload
    
    # 强制清除残留校验和,让Scapy自动计算正确值
    del fwd_pkt[IP].chksum
    del fwd_pkt[UDP].chksum
    
    # 指定出网接口发包
    send(fwd_pkt, iface="vr0")

if __name__ == "__main__":
    # 嗅探本地50000端口的UDP包,转发到远端10000端口
    sniff(
        filter="udp and port 50000",
        prn=lambda p: forward_packet(p, "192.168.20.111", 10000)
    )

注意事项

  • 不建议手动修改嗅探包的以太网层字段,尤其是跨网段场景,手动填MAC很容易出现二层地址错误,直接使用三层发包函数让系统自动解析下一跳MAC更可靠。
  • 你使用的Scapy 2.2.0是非常老旧的版本,对FreeBSD系统的原生发包支持存在已知bug,如果上述代码依旧无法正常发包,可以尝试换用sendp()二层发包函数,手动指定正确的出网接口、源MAC、默认网关的目的MAC测试。

内容的提问来源于stack exchange,提问作者Maryam

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.11.11 16:45:01