Erebus: 一个无根用户态 VPN 代理

Erebus 在受限环境中实现无根 VPN 连接

Erebus 是一个用户态 VPN 代理,允许用户在不需要 root 权限或修改宿主机网络栈的情况下建立 VPN 连接。通过在单个进程中完全实现 OpenVPN 协议和 TCP/IP 协议栈,Erebus 绕过了对内核 tun/tap 接口和路由表修改的需求,使其成为 CI runner、沙箱和非特权容器等无法使用 sudo 权限环境的理想选择。

架构:将 VPN 协议栈移至用户态

Erebus 使用其内部逻辑取代了传统的基于内核的路由和 TCP 处理。该工具唯一需要的系统权限是打开标准网络套接字的能力。

数据流

当发起请求时,数据遵循以下路径:

  1. 本地 HTTP 客户端:客户端应用程序指向本地 Erebus 代理。
  2. HTTP 代理:Erebus 接收并转发请求。
  3. 用户态 TCP/IP 协议栈:该进程通过手动构建和解析 IPv4、TCP 和 ICMP 数据包来实现。
  4. 加密:使用 OpenVPN 静态密钥(wire format v1)协议对数据包进行加密,并应用 HMAC 和数据包 ID。
  5. 传输:加密后的数据作为 UDP 数据报或 TCP 帧发送到 OpenVPN 服务器。

核心功能与能力

无根操作

Erebus 不需要 sudo 权限,不需要设置脚本,也不会触及宿主机的接口、路由或 DNS 设置。它可以作为一个标准的用户进程启动和停止。

可选流量路由

连接是显式的而非系统级的。用户必须将特定应用程序指向本地代理,以通过 VPN 路由流量。

  • 出站:本地 HTTP/1.x 代理将请求转发到 VPN 上的资源。
  • 入站:端口转发可实现本地服务与 VPN 对端之间的双向暴露。

协议支持

  • OpenVPN:支持通过 UDP 或 TCP 使用静态密钥模式(预共享密钥)。它支持 CBC 加密算法(AES, ARIA, Camellia)和各种 HMAC 摘要算法。
  • IPsec:包含一个与 strongSwan 协同工作的 IKEv2 控制平面和 ESP 数据平面。由于无根进程无法发送原始 ESP,所有流量都使用预共享密钥通过 UDP 封装(NAT-T)。

使用与安装

Erebus 使用 Common Lisp (SBCL) 编写,并作为 Debian 软件包分发给 Debian/Ubuntu 衍生版本。

快速开始配置

一个用于出站 UDP 代理的最小配置定义在 INI 文件中:

[erebus]
client-ip = 10.8.0.2

[openvpn-server]
proto  = udp
 host   = vpn.example.com
port   = 1194
secret = /etc/erebus/static.key
cipher = AES-256-CBC
auth   = SHA256

[proxy-out]
address = 127.0.0.1
port    = 11023

要使用该代理,用户可以通过命令行路由流量: http_proxy=http://127.0.0.1:11023 curl http://10.8.0.1/

性能与局限性

Erebus 是一个处于早期阶段的实验性项目,其优先级是正确性和清晰度而非性能。

适用场景

理想场景 不理想场景
在非特权容器中的内部 HTTP 服务 系统级 VPN 路由
需要私有端点的 CI 任务 大规模数据传输
沙箱或多租户宿主机 TLS 模式 OpenVPN (证书)
将单个本地端口暴露给 VPN 对端 HTTPS CONNECT 隧道或 SOCKS

性能权衡

由于实现方式是逐个发送数据块并等待确认后再发送下一个,因此大文件下载速度明显慢于标准代理。这种设计选择确保了代码的简洁性和互操作性。

Sources