8 个版本
0.3.7 | 2023 年 12 月 24 日 |
---|---|
0.3.6 | 2023 年 12 月 21 日 |
0.3.5 | 2023 年 10 月 2 日 |
0.3.4 | 2022 年 9 月 25 日 |
0.3.0 | 2022 年 2 月 15 日 |
#336 在 网络编程
每月 49 次下载
165KB
2K SLoC

onetun
一个跨平台的用户空间 WireGuard 端口转发器,无需 root 权限或系统网络配置。
使用场景
从未安装 WireGuard 的设备访问您 WireGuard 网络上运行的 TCP 或 UDP 服务。
例如,
- 无法安装 WireGuard(root)的个人或共享计算机
- 物联网和移动设备
- 无 root 容器
下载
您可以从 crates.io 安装 onetun,要求 Rust ≥1.70.0
cargo install onetun
您还可以从 发布页面 下载 Windows、macOS(Intel)和 Linux(amd64)的二进制文件。
您还可以使用 Docker 运行 onetun
docker run --rm --name onetun --user 1000 -p 8080:8080 aramperes/onetun \
0.0.0.0:8080:192.168.4.2:8080 [...options...]
您还可以使用 Rust ≥1.70.0 在本地构建 onetun
git clone https://github.com/aramperes/onetun && cd onetun
cargo build --release
./target/release/onetun
用法
onetun 在您的本地系统上打开一个 TCP 或 UDP 端口,并将流量转发到 WireGuard 网络中某个对等方的端口。它不需要更改操作系统网络接口:您不需要有 root
权限,或在本地上安装任何 WireGuard 工具即可工作。
唯一的前提是在远程 WireGuard 端点注册对等 IP 和公钥;这对于 WireGuard 端点信任 onetun 对等方以及数据包路由是必要的。
onetun [src_host:]<src_port>:<dst_host>:<dst_port>[:TCP,UDP,...] [...] \
--endpoint-addr <public WireGuard endpoint address> \
--endpoint-public-key <the public key of the peer on the endpoint> \
--private-key <private key assigned to onetun> \
--source-peer-ip <IP assigned to onetun> \
--keep-alive <optional persistent keep-alive in seconds> \
--log <optional log level, defaults to "info">
注意:您可以使用环境变量来设置所有这些标志。使用
onetun --help
获取详细信息。
示例
假设您的 WireGuard 端点具有以下配置,并且可以从 140.30.3.182:51820
访问
# /etc/wireguard/wg0.conf
[Interface]
PrivateKey = ********************************************
ListenPort = 51820
Address = 192.168.4.1
# A friendly peer that hosts the TCP service we want to reach
[Peer]
PublicKey = AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AllowedIPs = 192.168.4.2/32
# Peer assigned to onetun
[Peer]
PublicKey = BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
AllowedIPs = 192.168.4.3/32
我们希望访问友好的对等方(192.168.4.2
)上的 Web 服务器,端口号为 8080
。我们可以使用 onetun 打开一个本地端口,例如 127.0.0.1:8080
,这样就可以通过 WireGuard 隧道到达对等方的 Web 服务器
onetun 127.0.0.1:8080:192.168.4.2:8080 \
--endpoint-addr 140.30.3.182:51820 \
--endpoint-public-key 'PUB_****************************************' \
--private-key 'PRIV_BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB' \
--source-peer-ip 192.168.4.3 \
--keep-alive 10
然后你会看到这个日志
INFO onetun > Tunneling TCP [127.0.0.1:8080]->[192.168.4.2:8080] (via [140.30.3.182:51820] as peer 192.168.4.3)
这意味着你现在可以本地访问该端口了!
curl 127.0.0.1:8080
Hello world!
并行多个隧道
onetun 支持并行运行多个隧道。例如
onetun 127.0.0.1:8080:192.168.4.2:8080 127.0.0.1:8081:192.168.4.4:8081
INFO onetun::tunnel > Tunneling TCP [127.0.0.1:8080]->[192.168.4.2:8080] (via [140.30.3.182:51820] as peer 192.168.4.3)
INFO onetun::tunnel > Tunneling TCP [127.0.0.1:8081]->[192.168.4.4:8081] (via [140.30.3.182:51820] as peer 192.168.4.3)
... 将在本地打开 TCP 端口 8080 和 8081,并将它们转发到不同对等方的相应端口。
UDP 支持
onetun 支持UDP转发。你可以在端口转发配置的末尾添加 :UDP
,或者添加 UDP,TCP
以支持同一端口的两种协议(注意,这会在同一端口上打开 2 个独立的隧道)
onetun 127.0.0.1:8080:192.168.4.2:8080:UDP
INFO onetun::tunnel > Tunneling UDP [127.0.0.1:8080]->[192.168.4.2:8080] (via [140.30.3.182:51820] as peer 192.168.4.3)
onetun 127.0.0.1:8080:192.168.4.2:8080:UDP,TCP
INFO onetun::tunnel > Tunneling UDP [127.0.0.1:8080]->[192.168.4.2:8080] (via [140.30.3.182:51820] as peer 192.168.4.3)
INFO onetun::tunnel > Tunneling TCP [127.0.0.1:8080]->[192.168.4.2:8080] (via [140.30.3.182:51820] as peer 192.168.4.3)
注意:UDP 支持完全是实验性的。在使用任何生产环境之前,你应该阅读 架构 部分的 UDP 部分。
IPv6 支持
onetun 支持IPv4和IPv6。实际上,你可以使用 onetun 将某些IP版本转发到另一个,例如 6-to-4
onetun [::1]:8080:192.168.4.2:8080
INFO onetun::tunnel > Tunneling TCP [[::1]:8080]->[192.168.4.2:8080] (via [140.30.3.182:51820] as peer 192.168.4.3)
注意,每个隧道只能支持一个“源”IP版本和一个“目标”IP版本。如果你想在同一端口上支持IPv4和IPv6,你应该创建第二个端口转发
onetun [::1]:8080:192.168.4.2:8080 127.0.0.1:8080:192.168.4.2:8080
INFO onetun::tunnel > Tunneling TCP [[::1]:8080]->[192.168.4.2:8080] (via [140.30.3.182:51820] as peer 192.168.4.3)
INFO onetun::tunnel > Tunneling TCP [127.0.0.1:8080]->[192.168.4.2:8080] (via [140.30.3.182:51820] as peer 192.168.4.3)
数据包捕获
出于调试目的,你可以启用 onetun 与 WireGuard 对等方之间发送的 IP 数据包的捕获。输出是 libpcap 捕获文件,可以用 Wireshark 查看。
onetun --pcap wg.pcap 127.0.0.1:8080:192.168.4.2:8080
INFO onetun::pcap > Capturing WireGuard IP packets to wg.pcap
INFO onetun::tunnel > Tunneling TCP [127.0.0.1:8080]->[192.168.4.2:8080] (via [140.30.3.182:51820] as peer 192.168.4.3)
要捕获发送到和从 onetun 本地端口的数据包,你必须使用像 tcpdump
这样的外部工具,并且需要有 root 权限
sudo tcpdump -i lo -w local.pcap 'dst 127.0.0.1 && port 8080'
WireGuard 选项
默认情况下,onetun 将在所有接口和动态端口(即 IPv4 端点的 0.0.0.0:0)上创建 UDP 套接字,用于与 WireGuard 端点通信。你可以使用
--endpoint-bind-addr
绑定到静态地址。
onetun --endpoint-bind-addr 0.0.0.0:51820 --endpoint-addr 140.30.3.182:51820 [...]
通过使用 预共享密钥 (PSK),可以进一步增强 WireGuard 连接的安全性。你可以使用 wg genpsk
命令生成此类密钥,并使用 --preshared-key
提供。对等方还必须使用 PresharedKey
选项配置此密钥。
onetun --preshared-key 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' [...]
架构
简而言之: onetun 使用 smoltcp的 TCP/IP 和 UDP 堆栈,使用其状态机(“虚拟接口”)生成 IP 数据包。生成的 IP 数据包被 boringtun 加密并发送到 WireGuard 端点。从 WireGuard 端点接收到的加密 IP 数据包使用 boringtun 解密,并通过 smoltcp 虚拟接口状态机发送。onetun 在虚拟接口中创建“虚拟套接字”,以转发从入站连接发送的数据,以及从虚拟接口接收数据以转发回本地客户端。
onetun 使用异步运行时 tokio 来监听指定端口的新的 TCP 连接。
当客户端连接到 onetun 的 TCP 端口时,在 smoltcp 的“虚拟”TCP/IP 接口中创建一个“虚拟客户端”,它完全运行在 onetun 进程内部。为“虚拟客户端”分配一个临时的“虚拟端口”,它映射回本地客户端。
当真实客户端打开连接时,虚拟客户端套接字打开一个到虚拟服务器(绑定到远程主机/端口的虚拟套接字)的 TCP 连接。虚拟接口接着构造 SYN
段,并将其封装在 IP 数据包中。由于虚拟客户端和服务器是如何配置的,IP 数据包使用配置的 source-peer-ip
(例如上述示例中的 192.168.4.3
)作为源地址,并且目的地址与端口映射配置的目的地址相匹配(192.168.4.2
)。
通过这种方式,我们让 smoltcp 处理 IP 数据包的构造和客户端 TCP 状态的处理。实际上,我们不将那些数据包发送到虚拟服务器,而是在虚拟接口中拦截它们,使用 boringtun 加密数据包,并将它们发送到 WireGuard 端点的 UDP 端口。
一旦 WireGuard 端点收到加密的 IP 数据包,它使用其私钥对其进行解密并读取 IP 数据包。它读取目的地址,使用匹配的对等方的公钥重新加密 IP 数据包,并将其发送到对等方的 UDP 端点。
对等方接收到加密的 IP 数据包并对其进行解密。然后它可以读取内部有效负载(TCP 段),将其转发到服务器的端口,服务器处理 TCP 段。TCP 服务器响应 SYN-ACK
,它通过对等方的本地 WireGuard 接口返回,加密后转发到 WireGuard 端点,最后返回到 onetun 的 UDP 端口。
当 onetun 从 WireGuard 端点收到加密的数据包时,它使用 boringtun 进行解密。生成的 IP 数据包被分配给 onetun 内运行的相应虚拟接口;IP 数据包随后被读取和处理,虚拟客户端的 TCP 状态得到更新。
每当真实客户端发送数据时,它由虚拟客户端“发送”,这再次启动整个 IP 封装和 WireGuard 加密。当真实服务器发送数据时,它通过虚拟接口路由,允许虚拟客户端读取它。当虚拟客户端读取数据时,它将数据简单地推回给真实客户端。
这项工作全部得益于 smoltcp 和 boringtun,因此特别感谢这些库的开发者。
UDP
UDP支持是实验性的。由于UDP消息是无状态的,onetun没有完美的方式知道何时将分配的虚拟端口释放回池中供新对等方使用。这会导致随着时间的推移出现问题,因为虚拟端口的耗尽意味着新的数据报将被丢弃。为了减轻这个问题,onetun将限制一个对等IP地址使用的端口数量;如果来自不同端口的另一个数据报与相同的IP一起到来,则将释放最久未使用的虚拟端口并将其分配给新的对等端口。在此之后,任何目的地为重用虚拟端口的报文将路由到新的对等方,而任何由旧对等方接收的报文将被丢弃。
此外,在许多IP同时耗尽UDP虚拟端口池的情况下,如果一个新的对等IP发送数据,onetun必须从任何对等IP中选择最久未使用的虚拟端口并重新使用它。但是,这只有在最久未使用的端口未被使用一段时间的情况下才允许。如果所有虚拟端口都真正“活跃”(在该时间限制内有至少一次传输),由于耗尽,新的数据报将因耗尽而被丢弃。
总的来说,我不建议在公共服务中使用UDP转发,因为它很可能容易受到简单的DoS或DDoS攻击。
HTTP/SOCKS代理
onetun是一个传输层代理(也称为端口转发);它不提供HTTP/SOCKS代理服务器。但是,您可以将onetun与远程服务器上的代理服务器链式连接,该远程服务器锁定到您的WireGuard网络。
例如,您可以在对等方上运行dante-server(例如,192.168.4.2
)以下配置
# /etc/danted.conf
logoutput: syslog
user.privileged: root
user.unprivileged: nobody
internal: 192.168.4.2 port=1080
external: eth0
socksmethod: none
clientmethod: none
# Locks down proxy use to WireGuard peers (192.168.4.x)
client pass {
from: 192.168.4.0/24 to: 0.0.0.0/0
}
socks pass {
from: 192.168.4.0/24 to: 0.0.0.0/0
}
然后使用onetun在本地上暴露SOCKS5代理
onetun 127.0.0.1:1080:192.168.4.2:1080
INFO onetun::tunnel > Tunneling TCP [127.0.0.1:1080]->[192.168.4.2:1080] (via [140.30.3.182:51820] as peer 192.168.4.3)
使用curl
测试(或配置您的浏览器)
curl -x socks5://127.0.0.1:1080 https://ifconfig.me
贡献和维护
我非常乐意接受对onetun的贡献,并留出时间来审查所有pull请求。如果您不确定您的贡献是否在项目范围内,请考虑在GitHub上打开一个问题。
免责声明:我没有足够的时间积极维护onetun,除了开源贡献之外。
许可证
MIT许可证。有关详细信息,请参阅LICENSE
。版权©2023 Aram Peres。
依赖关系
~9–26MB
~360K SLoC