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

向TUN设备写入构造的UDP数据包后服务器无法接收的问题排查

问题分析与解决方案

你的代码核心问题是对TUN设备的读写方向理解错误,另外还有几个配置/构造层面的细节需要修正,下面逐一拆解说明:

1. TUN设备读写逻辑搞反了

TUN作为三层虚拟网卡,它的文件描述符读写逻辑和你预期的完全相反:

  • 当你从tun.fd读取时,是获取内核准备通过TUN设备发送到外部隧道的数据包;
  • 当你往tun.fd写入时,是把外部隧道收到的数据包注入内核,内核会将其当作从TUN网卡接收的包来处理(比如转发到本地或其他物理网卡)。

你现在想把数据包通过tun0发送到目标服务器,但os.write(tun.fd, raw(pkt))的操作是把包“塞给内核”,而不是从tun0发出去。这也是为什么Scapy的send(pkt)(默认走物理网卡)和nc(遵循系统默认路由)能正常工作,但直接写TUN fd不行的核心原因。

2. 数据包源地址未指定(可选但关键)

你构造IP包时没设置src参数,Scapy会自动填充系统默认网卡的IP地址。但如果要通过tun0发送数据包,源地址应该显式设置为tun0的192.168.2.1——否则服务器的回复包可能找不到正确的返回路径,或者被路由规则拦截。

3. 缺少路由规则配置(若需强制流量走tun0)

如果你的目标是让发往x.x.x.x的流量必须通过tun0发送,需要先添加路由规则告诉系统这一点:

ip route add x.x.x.x/32 dev tun0

修正后的代码示例

如果你只是想通过tun0发送测试数据包,不需要手动操作TUN fd,直接让Scapy绑定tun0网卡发送即可:

from scapy.all import *

# 显式指定tun0的源地址构造数据包
pkt = IP(src="192.168.2.1", dst="x.x.x.x")/UDP(dport=7777)/"Hello tunnel"
# Scapy默认会自动计算校验和,不需要手动转raw再重新构造IP包
pkt.show()

# 绑定tun0网卡发送数据包
send(pkt, iface="tun0")

如果你的场景是要手动实现VPN类的隧道收发逻辑,正确的流程应该是:

  1. 开启内核IP转发:echo 1 > /proc/sys/net/ipv4/ip_forward
  2. 配置路由让目标流量指向tun0
  3. 从tun.fd读取内核待发送的包,通过你的隧道传输到远端
  4. 接收远端发来的包,写入tun.fd让内核处理分发

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 11:04:10