Windows系统中伪造UDP数据包被拦截的原因排查
你遇到的两个核心问题——伪造源IP的UDP数据包无法传出本机、IPv4校验和被篡改——本质上是系统网络安全机制和代码中IP_HDRINCL选项设置时机错误共同导致的,下面逐一拆解并给出修复方案:
一、为什么伪造源IP的数据包会被丢弃?
1. 反向路径过滤(Reverse Path Filtering)
绝大多数现代操作系统(包括Windows、Linux)都默认开启了反向路径过滤机制,它的作用是验证数据包的源IP是否符合当前主机的路由路径:如果系统判断从伪造的源IP无法反向回传到本机,就会直接丢弃该数据包,即使你关闭了防火墙也没用。
比如你伪造源IP为192.168.110.x,但你的本机IP是192.168.110.79,系统会检查“从这个伪造IP发过来的数据包,是否能通过当前路由回到本机”,显然不符合,所以直接丢弃。
2. IP_HDRINCL选项设置时机错误
你的代码里把socket.setOption(IP_HDRINCL)放在了send的回调函数里,这完全晚了——当你调用socket.send的时候,系统已经按照默认逻辑处理IP头了(包括自动填充源IP、计算校验和),回调里再设置选项根本起不到作用。
二、为什么IPv4校验和被修改?
当IP_HDRINCL没有正确开启时,系统会自动接管IP头的生成:它会忽略你手动设置的源IP、校验和等字段,用本机真实IP覆盖源IP,并重新计算校验和,这就是为什么你设置的0xFFFF会被替换的原因。
三、修复步骤与代码调整
1. 先正确开启IP_HDRINCL选项
创建socket后立刻设置IP_HDRINCL,告诉系统“我自己负责构造完整的IP头,不要自动修改”:
const raw = require("raw-socket"); const UDPPacket = require("../generic/UDPPacket"); const IPV4Packet = require("../generic/IPV4Packet"); // 创建socket后立即设置IP_HDRINCL var socket = raw.createSocket({ protocol: raw.Protocol.UDP }); socket.setOption( raw.SocketLevel.IPPROTO_IP, raw.SocketOption.IP_HDRINCL, Buffer.from([0x01, 0x00, 0x00, 0x00]), 4 ); // 后续的message监听、数据包构造逻辑不变 socket.on("message", function (buffer, source) { console.log("received " + buffer.length + " bytes from " + source); });
2. 关闭反向路径过滤
对于Linux系统:
执行以下命令临时关闭(重启后失效,要永久修改需编辑/etc/sysctl.conf):
sudo sysctl -w net.ipv4.conf.all.rp_filter=0 sudo sysctl -w net.ipv4.conf.default.rp_filter=0 sudo sysctl -w net.ipv4.conf.eth0.rp_filter=0 # eth0替换成你的网卡名称
对于Windows系统:
- 打开注册表编辑器,定位到
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces - 找到对应网卡的子项,添加
DWORD类型的EnableReversePathFiltering,值设为0 - 重启网络服务或电脑生效
3. 确保校验和计算正确
当IP_HDRINCL开启后,系统不会帮你计算IPv4头和UDP的校验和,你需要确保IPV4Packet和UDPPacket类中的校验和计算逻辑是正确的:
- IPv4头校验和是对IP头(不含选项)的16位补码和的补码
- UDP校验和需要包含伪IP头(源IP、目标IP、协议号、UDP长度)+ UDP头+数据的16位补码和的补码
如果校验和计算错误,即使数据包发出去,目标主机也会丢弃它。
4. 测试建议
先测试本机到本机的伪造数据包:把dstAddr设为127.0.0.1或本机真实IP,用Wireshark抓包验证是否能收到,确认没问题后再测试局域网内的其他机器。
额外注意事项
- 有些杀毒软件或主机入侵防御系统(HIPS)可能会拦截raw socket发送的伪造数据包,如果关闭防火墙后还是不行,可以暂时禁用这类软件试试。
- 在局域网中伪造IP时,尽量选择当前网段内的未被使用的IP,避免和其他设备冲突导致数据包丢失。
内容的提问来源于stack exchange,提问作者Tomáš Zato

