«

使用udp2raw封装WireGuard UDP流量

myluzh 发布于 阅读:56 RouterOS


0x00 前言

本文是上一篇《RouterOS 基于 WireGuard 与动态 DNS 列表的策略分流》的进阶篇。上一篇已经实现 RouterOS 通过 WireGuard 连接 HK VPS,并基于 DNS 解析结果做 address-list 和策略路由分流。

本文不改原来的 DNS 分流逻辑,只在 WireGuard 外层增加 udp2raw 封装。通过 udp2raw,隐藏原始 WireGuard UDP 端口和协议特征,绕过一些简单的 UDP 限速或 UDP 阻断,让公网链路表现为类似 TCP 的流量。

内层 WireGuard 仍然按 UDP 工作,外层 faketcp 只是运输封装。最终链路是:RouterOS CHR -> Debian 旁路节点 udp2raw client -> HK VPS udp2raw server -> VPS 本机 wg0。

0x01 udp2raw 介绍

udp2raw 是什么?

udp2raw 是一个把 UDP 数据包封装进 raw packet 的隧道工具。它常用于把原本的 UDP 应用流量伪装成其他形态,例如:faketcp,udp,icmp。

但要注意:udp2raw faketcp 不是 HTTPS/TLS 伪装,udp2raw faketcp 不等于真实 TCP 应用,强 DPI 仍可能识别它不是正常 TCP 流量。

faketcp 是怎么做到无状态的?

普通 TCP 是由操作系统内核维护状态的,比如 SYN、SYN/ACK、ACK、ESTABLISHED、seq/ack、重传、拥塞控制、连接关闭。

udp2raw faketcp 的思路不一样:程序使用 raw socket 自己构造 IP/TCP 头,不调用内核的 TCP listen/connect/accept。外层包长得像 TCP,但不是内核 TCP 栈建立出来的真实连接。

因为系统内核并不知道这个“TCP 连接”,如果收到对端 faketcp 包,可能会认为这是不存在的连接,然后自动回 RST。所以 udp2raw 使用 -a 自动添加 iptables 规则,把相关包在进入内核 TCP 栈前 DROP 掉。这样 raw socket 能收到包,内核 TCP 栈不会插手回 RST。

这里说的“无状态”不是完全没有状态,而是:不是内核 TCP 状态,不是完整 TCP 连接,只是用户态用 raw packet 模拟出足够像 TCP 的外观。

当前使用的模式

我这里使用的是:--raw-mode faketcp--cipher-mode aes128cfb--auth-mode hmac_sha1

--cipher-mode xor 更省 CPU,但更像简单混淆。虽然内层 WireGuard 本身已经有强加密,但我这边 Debian 旁路节点和 VPS 都是 x86_64,目前没有明显 CPU 瓶颈,所以先保留 aes128cfb + hmac_sha1。如果后面测速发现 CPU 成为瓶颈,再考虑两端同时改成 --cipher-mode xor

注意:udp2raw 两端的 raw-modecipher-modeauth-mode 必须一致。

0x02 当前拓扑

我这里 RouterOS CHR 跑在 PVE 上,另外在 PVE 里起了一台很小的 Debian VM,专门跑 udp2raw client。

当前地址规划:RouterOS WireGuard 地址是 10.252.252.2/30,Debian 旁路节点是 172.17.10.254/24。只要 RouterOS 能访问这台 Debian 即可,具体放在哪个网段按自己的网络规划来。Debian 上 udp2raw client 监听 0.0.0.0:15182/udp,转发到 VPS 的 119.28.68.138:35827/faketcp。VPS 上 udp2raw server 监听 0.0.0.0:35827/faketcp,再转发给本机 127.0.0.1:443/udp

flowchart LR
    LAN["LAN / DNS 分流流量"] --> ROS["RouterOS CHR<br/>WG: 10.252.252.2/30"]
    ROS -->|"WG UDP<br/>172.17.10.254:15182"| DEBIAN["Debian 旁路节点<br/>udp2raw client"]
    DEBIAN -->|"faketcp<br/>119.28.68.138:35827"| VPS_RAW["HK VPS<br/>udp2raw server"]
    VPS_RAW -->|"UDP<br/>127.0.0.1:443"| VPS_WG["wg0<br/>10.252.252.1/30"]
    VPS_WG --> WAN["VPS 出口"]

我的 VPS 上 nginx/docker 占用的是 TCP 443,WireGuard 实际监听的是 UDP 443,两者不冲突。udp2raw 外层单独使用 TCP 35827

0x03 Debian 旁路节点配置

Debian VM 很小就够用,只要 RouterOS 到 Debian 网络可达即可。建议配置:1 core CPU,256MB 或 512MB 内存,4GB 硬盘。

安装依赖:

root@pve-debian:~# apt update
root@pve-debian:~# apt install -y curl tar iptables ca-certificates tcpdump openssl

下载 udp2raw:

root@pve-debian:~# cd /tmp
root@pve-debian:/tmp# curl -fsSL -o udp2raw.tar.gz https://github.com/wangyu-/udp2raw/releases/download/20230206.0/udp2raw_binaries.tar.gz
root@pve-debian:/tmp# mkdir -p /tmp/udp2raw
root@pve-debian:/tmp# tar -xzf udp2raw.tar.gz -C /tmp/udp2raw
root@pve-debian:/tmp# install -m 0755 /tmp/udp2raw/udp2raw_amd64 /usr/local/bin/udp2raw

生成 key:

root@pve-debian:~# mkdir -p /etc/udp2raw
root@pve-debian:~# openssl rand -base64 32 > /etc/udp2raw/key
root@pve-debian:~# chmod 600 /etc/udp2raw/key
root@pve-debian:~# cat /etc/udp2raw/key
<UDP2RAW_KEY>

这个 key 两端必须一致,后面 VPS 也要填同一个。

创建 client 配置:

root@pve-debian:~# vi /etc/udp2raw/client.conf
-c
-l 0.0.0.0:15182
-r 119.28.68.138:35827
-k <UDP2RAW_KEY>
--raw-mode faketcp
--cipher-mode aes128cfb
--auth-mode hmac_sha1
-a

创建 systemd 服务:

root@pve-debian:~# vi /etc/systemd/system/udp2raw-wg-client.service
[Unit]
Description=udp2raw WireGuard wrapper client
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
ExecStart=/usr/local/bin/udp2raw --conf-file /etc/udp2raw/client.conf
Restart=always
RestartSec=3

[Install]
WantedBy=multi-user.target

启动:

root@pve-debian:~# systemctl daemon-reload
root@pve-debian:~# systemctl enable --now udp2raw-wg-client
root@pve-debian:~# systemctl status udp2raw-wg-client

0x04 VPS 配置 udp2raw server

VPS 上先确认 WireGuard 实际监听端口:

root@itho:~# wg show wg0
interface: wg0
  listening port: 443

我这里 wg0 实际监听的是 UDP 443,所以 udp2raw server 要转发到 127.0.0.1:443。如果你的 WireGuard 是 51820,这里就改成 127.0.0.1:51820

安装依赖和 udp2raw:

root@itho:~# apt update
root@itho:~# apt install -y curl tar iptables ca-certificates tcpdump
root@itho:~# cd /tmp
root@itho:/tmp# curl -fsSL -o udp2raw.tar.gz https://github.com/wangyu-/udp2raw/releases/download/20230206.0/udp2raw_binaries.tar.gz
root@itho:/tmp# mkdir -p /tmp/udp2raw
root@itho:/tmp# tar -xzf udp2raw.tar.gz -C /tmp/udp2raw
root@itho:/tmp# install -m 0755 /tmp/udp2raw/udp2raw_amd64 /usr/local/bin/udp2raw

创建 server 配置:

root@itho:~# mkdir -p /etc/udp2raw
root@itho:~# vi /etc/udp2raw/server.conf
-s
-l 0.0.0.0:35827
-r 127.0.0.1:443
-k <UDP2RAW_KEY>
--raw-mode faketcp
--cipher-mode aes128cfb
--auth-mode hmac_sha1
-a

创建 systemd 服务:

root@itho:~# vi /etc/systemd/system/udp2raw-wg-server.service
[Unit]
Description=udp2raw WireGuard wrapper server
After=network-online.target wg-quick@wg0.service
Wants=network-online.target

[Service]
Type=simple
ExecStart=/usr/local/bin/udp2raw --conf-file /etc/udp2raw/server.conf
Restart=always
RestartSec=3

[Install]
WantedBy=multi-user.target

启动:

root@itho:~# systemctl daemon-reload
root@itho:~# systemctl enable --now udp2raw-wg-server
root@itho:~# systemctl status udp2raw-wg-server

安全组需要放行 TCP 35827 入站。

我一开始就卡在这里,VPS 上 tcpdump 抓不到任何 35827 的包。后面放行安全组后,udp2raw 才进入 client_ready / server_ready

VPS 上可以这样看:

root@itho:~# journalctl -u udp2raw-wg-server -f

正常会看到:

received syn,sent syn ack back
changed state to server_ready

0x05 RouterOS 修改 WireGuard Peer

原来的 WireGuard peer 是直接指向 VPS 公网 IP 的,现在改成本地 Debian 旁路节点。我这里 peer 名字是 peer-119

[admin@HOME2-ROS] > /interface/wireguard/peers/set [find name="peer-119"] endpoint-address=172.17.10.254 endpoint-port=15182 persistent-keepalive=5s

注意:RouterOS 填的是 172.17.10.254:15182,不是 VPS 的 119.28.68.138:35827

15182 是 RouterOS 到 Debian 的本地 UDP 端口。
35827 是 Debian 到 VPS 的公网 faketcp 端口。

0x06 MTU 调整

这里是一个重点坑。刚开始隧道已经通了,RouterOS ping VPS 的 WireGuard 地址也正常,但是客户端网页打不开。这个现象很容易误判成 DNS、路由或者 NAT 问题,实际上是 MTU 太大。

WireGuard 外面又套了一层 udp2raw faketcp,有效 MTU 会变小。如果两端 WireGuard 还保持默认较大的 MTU,就可能出现:ping 正常、小包正常,但是网页打不开、HTTPS/TLS 握手卡住,或者视频加载异常。

我这边最终把 WireGuard 两端 MTU 都设置成 1320,稳定了。

RouterOS 端:

[admin@HOME2-ROS] > /interface/wireguard/set wireguard2 mtu=1320

VPS 端运行时设置:

root@itho:~# ip link set mtu 1320 dev wg0

VPS 持久化写入 /etc/wireguard/wg0.conf

[Interface]
Address = 10.252.252.1/30
ListenPort = 443
PrivateKey = ...
MTU = 1320

然后重启 WireGuard:

root@itho:~# systemctl restart wg-quick@wg0

RouterOS 也建议加 MSS clamp:

/ip/firewall/mangle/add chain=forward out-interface=wireguard2 protocol=tcp tcp-flags=syn action=change-mss new-mss=clamp-to-pmtu passthrough=yes comment="clamp MSS for WG over udp2raw"

0x07 测试验证

RouterOS 测试

RouterOS 上 ping VPS 的 WireGuard 地址:

[admin@HOME2-ROS] > /ping 10.252.252.1 src-address=10.252.252.2
    SEQ HOST                                     SIZE TTL TIME       STATUS
      0 10.252.252.1                               56  64 39ms891us
      1 10.252.252.1                               56  64 39ms729us

之前直连 WireGuard 大概 35ms,现在套了一层 udp2raw 后大概 39-40ms,多了约 5ms。

VPS 测试

VPS 上看 wg show

root@itho:~# wg show wg0
interface: wg0
  listening port: 443

peer: XvnO1bNLgGGjBqRaKN9w03U2N9v0okLvKT9Cb1HB6g0=
  endpoint: 127.0.0.1:50473
  latest handshake: 11 seconds ago

这里最关键的是 endpoint: 127.0.0.1:50473。这说明 VPS 的 WireGuard 收到的是本机 udp2raw server 转发进来的包,不再是公网直接 UDP 进 wg0。

抓包验证

Debian 上抓外层 faketcp:

root@pve-debian:~# tcpdump -ni ens18 host 119.28.68.138 and tcp port 35827

可以看到 172.17.10.254.xxxxx > 119.28.68.138.35827119.28.68.138.35827 > 172.17.10.254.xxxxx 这样的双向流量。

到这里,WireGuard over udp2raw 已经完成。

0x08 踩坑记录

1、端口不能写 151820

一开始我把 Debian 本地监听端口写成了 151820,udp2raw 直接报错:

invalid port: 151820

端口最大只能到 65535,所以后面改成了 15182

2、VPS TCP 443 已经被 nginx 占用

我的 VPS 上 nginx/docker 已经占用了 TCP 443,所以 udp2raw 不能再监听 TCP 443

最后选择了 udp2raw faketcp:35827

注意 WireGuard 用的是 UDP 443,nginx 用的是 TCP 443,这两个不冲突。

3、安全组必须放行 TCP 35827

VPS 本机服务已经启动,但安全组没放行时,VPS 上抓不到任何包。放行 TCP 35827 后,udp2raw 立刻握手成功。

root@itho:~# tcpdump -ni eth0 tcp port 35827
0 packets captured

4、MTU 太大导致网页打不开

这是最隐蔽的问题。隧道 ping 通,不代表网页一定能正常打开。套了 udp2raw 后,我这里 WireGuard 两端 MTU 设置为 1320 才稳定。

0x09 总结

这套方案最大的优点是:不破坏原来的 RouterOS DNS 分流结构。RouterOS 还是继续负责 DNS FWD、address-list、mangle、策略路由和 WireGuard。

Debian 旁路节点只负责把 RouterOS 发来的 WireGuard UDP 包封装成 faketcp,再转给 VPS。

最终公网链路从 RouterOS -> VPS WireGuard UDP 变成 RouterOS -> Debian -> udp2raw faketcp -> VPS -> wg0

缺点也很明确:多了一层用户态封装,延迟增加了约 5ms,并且需要处理 MTU 问题。

参考:udp2raw 项目地址 https://github.com/wangyu-/udp2raw 。上一篇是《RouterOS 7 + Ubuntu VPS:基于 WireGuard 与动态 DNS 列表的策略分流》。

routeros ros wireguard udp2raw faaketcp udp debian


正文到此结束
版权声明:若无特殊注明,本文皆为 Myluzh Blog 原创,转载请保留文章出处。
文章内容:https://itho.cn/ros/595.html
文章标题:《使用udp2raw封装WireGuard UDP流量