Phantun: 一款突破运营商 QoS 封锁的高性能 UDP 流量伪装工具,支持 WireGuard 协议...

公众号关注 「奇妙的 Linux 世界」

设为「星标」,每天带你玩转 Linux !

e29ee7e673c6ab9a4b6aaf0d839f85e0.jpeg

原文链接🔗:https://icloudnative.io/posts/wireguard-over-tcp-using-phantun/

👉WireGuard 作为一个更先进、更现代的 VPN 协议,比起传统的 IPSec、OpenVPN 等实现,效率更高,配置更简单,并且已经合并入 Linux 内核,使用起来更加方便,简直就是 VPN 中的战斗机。越来越多的高人利用 WireGuard 实现很多奇奇怪怪的需求。例如国内与国外机器通过 WireGuard 打通隧道,变成伪 IPLC 专线;或者打通本地与 Kubernetes 集群的网络。

但是 WireGuard 在国内网络环境下会遇到一个致命的问题:UDP 封锁/限速。虽然通过 WireGuard 可以在隧道内传输任何基于 IP 的协议(TCP、UDP、ICMP、SCTP、IPIP、GRE 等),但 WireGuard 隧道本身是通过 UDP 协议进行通信的,而国内运营商根本没有能力和精力根据 TCP 和 UDP 的不同去深度定制不同的 QoS 策略,几乎全部采取一刀切的手段:对 UDP 进行限速甚至封锁

鲁迅先生说过:羊毛出在羊身上!突破口还是在运营商身上:虽然对 UDP 不友好,但却无力深度检测 TCP 连接的真实性

这就好办了,既然你对 TCP 连接睁一只眼闭一只眼,那我将 UDP 连接伪装成 TCP 连接不就蒙混过关了。目前支持将 UDP 流量伪装成 TCP 流量的主流工具是 udp2raw[1],相信很多小伙伴对这个工具都轻车熟路了,但是很遗憾,今天的主角不是它,而是另一款比它更强大的新工具:Phantun[2]

2b438ee43f3cff6ce3ce6134d1264c7f.jpeg

Phantun 介绍

Phantun 整个项目完全使用 Rust 实现,性能吊打 udp2raw。它的初衷和 udp2raw 类似,都是为了实现一种简单的用户态 TCP 状态机来对 UDP 流量做伪装。主要的目的是希望能让 UDP 流量看起来像是 TCP,又不希望受到 TCP retransmission 或者 congestion control 的影响。

需要申明的是,Phantun 的目标不是为了替代 udp2raw,从一开始 Phantun 就希望设计足够的简单高效,所以 udp2raw 支持的 ICMP 隧道,加密,防止重放等等功能 Phantun 都选择不实现。

Phantun 假设 UDP 协议本身已经解决了这些问题,所以整个转发过程就是简单的明文换头加上一些必要的 TCP  状态控制信息。对于我日常使用的 WireGuard 来说,Phantun 这种设计是足够安全的,因为 WireGuard  的协议已经更好的实现了这些安全功能。

Phantun 使用 TUN 接口来收发 3 层数据包,udp2raw 使用 Raw Socket + BFP 过滤器。个人感觉基于 TUN 的实现要稍微的优雅一点,而且跨平台移植也要更容易。

Phantun 的 TCP 连接是按需创建的,只启动 Client 不会主动去连接服务器,需要第一个数据包到达了后才会按需创建。每个 UDP  流都有自己独立的 TCP 连接。这一点跟 udp2raw 很不一样,udp2raw 所有的 UDP 连接共用一个 TCP 连接。这样做的坏处就是 udp2raw 需要额外的头部信息来区分连接,更加增加了头部的开销。跟纯 UDP 比较,Phantun 每个数据包的额外头部开销是 12  byte,udp2raw 根据我的测试达到了 44 bytes 。

下面是 Phantun 与 udp2raw 的详细对比:


Phantunudp2raw
UDP over FakeTCP 混淆
UDP over ICMP 混淆
UDP over UDP 混淆
多线程
吞吐量BetterGood
三层转发模式TUN interfaceRaw sockets + BPF
隧道 MTU 开销12 bytes44 bytes
每个 UDP  流都有自己独立的 TCP 连接Client/ServerServer only
防止重放,加密
IPv6

Phantun 工作原理

9151d4c186881016c23956eb3aea7aff.jpeg

Phantun 分为服务端和客户端,服务端会监听一个端口,比如 4567(通过 --local 参数指定),并将 UDP 数据包转发到 UDP 服务(这里指的就是服务端 WireGuard 的监听端口和地址,通过 --remote 参数指定)。

客户端也会监听一个端口,比如 127.0.0.1:4567(通过 --local 参数指定),并且通过 --remote 参数与服务端(比如 10.0.0.1:4567)建立连接。

客户端与服务端都会创建一个 TUN 网卡,客户端 TUN 网卡默认分配的 IPv4/IPv6 地址分别是 192.168.200.2 和 fcc8::2,服务端 TUN 网卡默认分配的 IPv4/IPv6 地址分别是 192.168.201.2 和 fcc9::2

客户端与服务端都需要开启 IP forwarding,并且需要创建相应的 NAT 规则。客户端在流量离开物理网卡之前,需要对 IP 192.168.200.2 进行 SNAT;服务端在流量进入网卡之前,需要将 IP DNAT 为 192.168.201.2

Phantun 配置步骤

接下来我会通过一个示例来演示如何使用 Phantun 将 WireGuard 的 UDP 流量伪装成 TCP。我们需要在服务端和客户端分别安装 phantun,可以到 release 页面[3]下载,推荐下载静态编译版本 phantun_x86_64-unknown-linux-musl.zip

服务端

假设服务端的公网 IP 地址是 121.36.134.95,WireGuard 监听端口是 51822。首先修改配置文件 /etc/wireguard/wg0.conf,在 [Interface] 中添加以下配置:

MTU = 1300
PreUp = iptables -t nat -A PREROUTING -p tcp -i eth0 --dport 4567 -j DNAT --to-destination 192.168.201.2
PreUp = RUST_LOG=info phantun_server --local 4567 --remote 127.0.0.1:51822 &> /var/log/phantun_server.log &
PostDown = iptables -t nat -D PREROUTING -p tcp -i eth0 --dport 4567 -j DNAT --to-destination 192.168.201.2
PostDown = killall phantun_server || true

你需要将 eth0 替换为你服务端的物理网卡名。MTU 值先不管,后面再告诉大家调试方法。

PreUp = iptables -t nat -A PREROUTING -p tcp -i eth0 --dport 4567 -j DNAT --to-destination 192.168.201.2

这条 iptables 规则表示将 4567 端口的入站流量 DNAT 为 TUN 网卡的 IP 地址。

PreUp = RUST_LOG=info phantun_server --local 4567 --remote 127.0.0.1:51822 &> /var/log/phantun_server.log &

这里会启动 phantun_server,监听在 4567 端口,并将 UDP 数据包转发到 WireGuard。

服务端完整的 WireGuard 配置:

# local settings for Endpoint B
[Interface]
PrivateKey = QH1BJzIZcGo89ZTykxls4i2DKgvByUkHIBy3BES2gX8= 
Address = 10.0.0.2/32
ListenPort = 51822
MTU = 1300
PreUp = iptables -t nat -A PREROUTING -p tcp -i eth0 --dport 4567 -j DNAT --to-destination 192.168.201.2
PreUp = RUST_LOG=info phantun_server --local 4567 --remote 127.0.0.1:51822 &> /var/log/phantun_server.log &
PostDown = iptables -t nat -D PREROUTING -p tcp -i eth0 --dport 4567 -j DNAT --to-destination 192.168.201.2
PostDown = killall phantun_server || true

# remote settings for Endpoint A
[Peer]
PublicKey = wXtD/VrRo92JHc66q4Ypmnd4JpMk7b1Sb0AcT+pJfwY= 
AllowedIPs = 10.0.0.1/32

最后重启 WireGuard 即可:

$ systemctl restart wg-quick@wg0

客户端

假设客户端的 WireGuard 监听端口是 51821。首先修改配置文件 /etc/wireguard/wg0.conf,在 [Interface] 中添加以下配置:

MTU = 1300
PreUp = iptables -t nat -A POSTROUTING -o eth0 -s 192.168.200.2 -j MASQUERADE
PreUp = RUST_LOG=info phantun_client --local 127.0.0.1:4567 --remote 121.36.134.95:4567 &> /var/log/phantun_client.log &
PostDown = iptables -t nat -D POSTROUTING -o eth0 -s 192.168.200.2 -j MASQUERADE
PostDown = killall phantun_client || true

你需要将 eth0 替换为你服务端的物理网卡名。

PreUp = iptables -t nat -A POSTROUTING -o eth0 -s 192.168.200.2 -j MASQUERADE

这条 iptables 规则表示对来自 192.168.200.2(TUN 网卡) 的出站流量进行 MASQUERADE。

PreUp = RUST_LOG=info phantun_client --local 127.0.0.1:4567 --remote 121.36.134.95:4567 &> /var/log/phantun_client.log &

这里会启动 phantun_client,监听在 4567 端口,并与服务端建立连接,将伪装的 TCP 数据包传送给服务端。

除此之外还需要修改 WireGuard peer 的 Endpoint,将其修改为 127.0.0.1:4567。

Endpoint = 127.0.0.1:4567

客户端完整的 WireGuard 配置:

# local settings for Endpoint A
[Interface]
PrivateKey = 0Pyz3cIg2gRt+KxZ0Vm1PvSIU+0FGufPIzv92jTyGWk=
Address = 10.0.0.1/32
ListenPort = 51821
MTU = 1300
PreUp = iptables -t nat -A POSTROUTING -o eth0 -s 192.168.200.2 -j MASQUERADE
PreUp = RUST_LOG=info phantun_client --local 127.0.0.1:4567 --remote 121.36.134.95:4567 &> /var/log/phantun_client.log &
PostDown = iptables -t nat -D POSTROUTING -o eth0 -s 192.168.200.2 -j MASQUERADE
PostDown = killall phantun_client || true

# remote settings for Endpoint B
[Peer]
PublicKey = m40NDb5Cqtb78b1DVwY1+kxbG2yEcRhxlrLm/DlPpz8=
Endpoint = 127.0.0.1:4567
AllowedIPs = 10.0.0.2/32
PersistentKeepalive = 25

最后重启 WireGuard 即可:

$ systemctl restart wg-quick@wg0

查看 phantun_client 的日志:

$ tail -f /var/log/phantun_client.log
 INFO  client > Remote address is: 121.36.134.95:4567
 INFO  client > 1 cores available
 INFO  client > Created TUN device tun0
 INFO  client > New UDP client from 127.0.0.1:51821
 INFO  fake_tcp > Sent SYN to server
 INFO  fake_tcp > Connection to 121.36.134.95:4567 established

查看 wg0 接口:

$ wg show wg0
interface: wg0
  public key: wXtD/VrRo92JHc66q4Ypmnd4JpMk7b1Sb0AcT+pJfwY=
  private key: (hidden)
  listening port: 51821

peer: m40NDb5Cqtb78b1DVwY1+kxbG2yEcRhxlrLm/DlPpz8=
  endpoint: 127.0.0.1:4567
  allowed ips: 10.0.0.2/32
  latest handshake: 1 minute, 57 seconds ago
  transfer: 184 B received, 648 B sent
  persistent keepalive: every 25 seconds

测试连通性:

$ ping 10.0.0.2 -c 3
PING 10.0.0.2 (10.0.0.2) 56(84) bytes of data.
64 bytes from 10.0.0.2: icmp_seq=1 ttl=64 time=13.7 ms
64 bytes from 10.0.0.2: icmp_seq=2 ttl=64 time=14.4 ms
64 bytes from 10.0.0.2: icmp_seq=3 ttl=64 time=15.0 ms

--- 10.0.0.2 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2005ms
rtt min/avg/max/mdev = 13.718/14.373/15.047/0.542 ms

客户端(多服务端)

如果客户端想和多个服务端建立连接,则新增的服务端配置如下:

PreUp = RUST_LOG=info phantun_client --local 127.0.0.1:4568 --remote xxxx:4567 --tun-local=192.168.202.1 --tun-peer=192.168.202.2 &> /var/log/phantun_client.log &
PostDown = iptables -t nat -D POSTROUTING -o eth0 -s 192.168.202.2 -j MASQUERADE

本地监听端口需要选择一个与之前不同的端口,同理,TUN 网卡的地址也需要修改。最终的配置如下:

# local settings for Endpoint A
[Interface]
PrivateKey = 0Pyz3cIg2gRt+KxZ0Vm1PvSIU+0FGufPIzv92jTyGWk=
Address = 10.0.0.1/32
ListenPort = 51821
MTU = 1300
PreUp = iptables -t nat -A POSTROUTING -o eth0 -s 192.168.200.2 -j MASQUERADE
PreUp = RUST_LOG=info phantun_client --local 127.0.0.1:4567 --remote 121.36.134.95:4567 &> /var/log/phantun_client.log &
PreUp = RUST_LOG=info phantun_client --local 127.0.0.1:4568 --remote xxxx:4567 --tun-local=192.168.202.1 --tun-peer=192.168.202.2 &> /var/log/phantun_client.log &
PostDown = iptables -t nat -D POSTROUTING -o eth0 -s 192.168.200.2 -j MASQUERADE
PostDown = iptables -t nat -D POSTROUTING -o eth0 -s 192.168.202.2 -j MASQUERADE
PostDown = killall phantun_client || true

# remote settings for Endpoint B
[Peer]
PublicKey = m40NDb5Cqtb78b1DVwY1+kxbG2yEcRhxlrLm/DlPpz8=
Endpoint = 127.0.0.1:4567
AllowedIPs = 10.0.0.2/32
PersistentKeepalive = 25

MTU 调优

如果你使用 ping 或者 dig 等工具(小数据包)测试 WireGuard 隧道能够正常工作,但浏览器或者远程桌面(大数据包)却无法正常访问,很有可能是 MTU 的问题,你需要将 MTU 的值调小一点。

Phantun 官方建议将 MTU 的值设为 1428(假设物理网卡的 MTU 是 1500),但经我测试是有问题的。建议直接将 MTU 设置为最低值 1280,然后渐渐增加,直到无法正常工作为止,此时你的 MTU 就是最佳值。

你学废了吗?

参考资料

  • Phantun - Rust 写的轻量级 UDP -> TCP 混淆器[4]

  • Phantun GitHub Repo[5]

引用链接

[1]

udp2raw: https://github.com/wangyu-/udp2raw-tunnel

[2]

Phantun: https://github.com/dndx/phantun

[3]

release 页面: https://github.com/dndx/phantun/releases

[4]

Phantun - Rust 写的轻量级 UDP -> TCP 混淆器: https://www.v2ex.com/t/802949

[5]

Phantun GitHub Repo: https://github.com/dndx/phantun

本文转载自:「云原生实验室 」,原文:https://url.hi-linux.com/L6lzw,版权归原作者所有。欢迎投稿,投稿邮箱: editor@hi-linux.com。

f48111cb2c9887d664b761d8c36a61b3.gif

最近,我们建立了一个技术交流微信群。目前群里已加入了不少行业内的大神,有兴趣的同学可以加入和我们一起交流技术,在 「奇妙的 Linux 世界」 公众号直接回复 「加群」 邀请你入群。

d6721e772cc7f320b29473125eaf9ccd.png

你可能还喜欢

点击下方图片即可阅读

58ed8ae5ce52f044db98e42c591ba50a.png

如何通过终端快速访问 Kubernetes 节点 Shell 的 Root 环境 (无需 SSH 权限 )

e9f618152478f37818fd397ccde7e43e.png
点击上方图片,『美团|饿了么』外卖红包天天免费领

d0ae0a7ca2d3cb208da9265cb31a680a.png

更多有趣的互联网新鲜事,关注「奇妙的互联网」视频号全了解!

Caused by: java.lang.ClassNotFoundException: ch.qos.logback.core.joran.spi.JoranException 是一个常见的错误,它表示在运行时找不到 ch.qos.logback.core.joran.spi.JoranException 这个类。这个错误通常是由于缺少相关的依赖或者依赖冲突导致的。 解决这个问题的方法有以下几种: 1. 确保你的项目中包含了 ch.qos.logback.core.joran.spi.JoranException 这个类所在的依赖。你可以通过在你的项目的构建文件(如 pom.xml 或 build.gradle)中添加正确的依赖来解决这个问题。可以参考中提到的使用 Maven Helper 插件来搜索并确认你的项目中是否存在该依赖。 2. 检查你的项目中是否存在依赖冲突。有时候不同的库或模块可能会引入相同的类,但版本不同,导致冲突。你可以通过 Maven Helper 插件或其他依赖分析工具来检查你的项目中是否存在依赖冲突,并解决这个问题。可以参考中提到的使用 Maven Helper 插件来进行依赖分析。 3. 确保你的项目的类加载器能够找到 ch.qos.logback.core.joran.spi.JoranException 这个类。有时候,类加载器可能无法正确地加载所需的类。你可以尝试重新构建你的项目,并确保你的类加载器能够正确加载所有的类。 总结一下,解决 Caused by: java.lang.ClassNotFoundException: ch.qos.logback.core.joran.spi.JoranException 的方法包括添加相关的依赖、解决依赖冲突以及确保类加载器能够正确加载所需的类。希望这些方法对你有帮助。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值