puzed/wrapguard
GitHub: puzed/wrapguard
WrapGuard 是一个无需特权或内核模块的纯用户空间 WireGuard 代理,通过动态库注入为指定进程提供透明网络隧道。
Stars: 166 | Forks: 8
# WrapGuard - 用户空间 WireGuard 代理
WrapGuard 允许应用程序从用户空间通过网络通过 WireGuard VPN 路由网络流量,无需容器权限或内核模块。
Linux 是目前主要的生产目标。macOS 的构建、打包和回归检查在 CI 中运行,并且 macOS 运行时路径已证明支持 CLI 目标的直接启动 TCP 路由,但仍处于实验阶段,仅限于可以接受注入的目标。
## 功能
- **纯用户空间**:无需创建 TUN 接口,不需要 NET_ADMIN 权限
- **透明拦截**:在支持的宿主机上使用特定平台的动态库注入
- **双向支持**:在支持的 Linux 构建版本上,传入和传出连接均可工作
- **标准配置**:使用标准 WireGuard 配置文件
## 安装
### 预编译二进制文件
从 [发布页面](https://github.com/puzed/wrapguard/releases) 下载 Linux 和 macOS 的预编译二进制文件。
Linux 版本以生产环境为目标。macOS 归档文件已打包并验证了布局一致性以及发布归档冒烟检查,但在运行时启动器工作完成之前,macOS 支持仍应被视为实验性的。
**无需额外依赖** - WrapGuard 是一个单一二进制文件,包含创建 WireGuard 连接所需的一切。您不需要在主机上安装 WireGuard、内核模块或任何其他 VPN 软件。
### 从源代码构建
```
make build
```
这将创建:
- `wrapguard` - 主可执行文件
- Linux 上的 `libwrapguard.so` 或 macOS 上的 `libwrapguard.dylib` - 位于二进制文件旁边的注入库
## 支持矩阵
- Linux `amd64` 和 `arm64`:支持生产使用。
- `amd64` 和 `arm64` 架构上的 macOS 14 Sonoma 和 macOS 15 Sequoia:针对可作为可执行路径启动的目标,提供实验性的直接启动支持。
- 如果您正在尝试简单的 `.app` 包,当 `Contents/MacOS` 包含单个明确候选者时,WrapGuard 可以解析内部可执行文件;尚不支持 `open -a`。
- 通过非 SIP shell 二进制文件进行的直接 CLI 启动受到支持,其实验性质与其他直接 macOS CLI 目标相同。
- `open -a` 以及依赖 Apple 管理的应用启动器的启动目标:不支持。
- Sequoia 之后的 macOS 新版本可能可以工作,但尚未成为文档化 QA 矩阵的一部分。
- 位于 `/usr/bin`、`/bin`、`/System`、`/sbin` 和 `/usr/libexec` 等位置的 macOS SIP 保护二进制文件:启动前被拒绝,不支持。
- 第三方签名的 GUI 应用、强化运行时应用、沙盒助手和浏览器风格的多进程应用可能仍会启动,但不支持,并且在注入下可能不稳定。
- 路由出站 TCP 是目前 macOS 上文档化和测试过的路径。macOS 上 UDP 不被隧道化,WrapGuard 可能会故意抑制可能的 QUIC `UDP/443` 连接尝试,以便浏览器回退到 TCP 路径,而不是通过 UDP 泄露。
- IPv6 在 macOS 上仍不在生产支持声明范围内。
- Windows:不支持。
## 用法
```
# 通过 WireGuard 路由传入连接
wrapguard --config=~/wg0.conf -- node -e 'http.createServer((_, res) => res.end("hello")).listen(8080)'
# 通过 WireGuard 路由传出连接
wrapguard --config=~/wg1.conf -- curl http://10.0.0.3:8080
# 使用 exit node(通过特定 peer 路由所有流量)
wrapguard --config=~/wg0.conf --exit-node=10.150.0.3 -- curl https://icanhazip.com
# 通过不同的 peer 路由特定子网
wrapguard --config=~/wg0.conf \
--route=192.168.0.0/16:10.150.0.3 \
--route=172.16.0.0/12:10.150.0.4 \
-- curl https://internal.corp.com
# 带 debug 日志输出到控制台
wrapguard --config=~/wg0.conf --log-level=debug -- curl https://icanhazip.com
# 带日志记录到文件
wrapguard --config=~/wg0.conf --log-level=info --log-file=/tmp/wrapguard.log -- curl https://icanhazip.com
```
## macOS 指南
- 使用 WrapGuard 直接启动目标可执行文件。
- 对于 `Contents/MacOS` 中包含单个明确可执行文件的简单 `.app` 包,您也可以传递包路径,WrapGuard 将为您解析内部可执行文件。
- 如果包在 `Contents/MacOS` 中包含多个可执行候选者,WrapGuard 将拒绝启动并要求您显式启动内部可执行文件。
- 如果您想要在 macOS 上使用 WrapGuard 下的 shell 会话,请使用由 WrapGuard 直接启动的非 SIP shell 二进制文件。`/bin` 中受 Apple 保护的 shell 不是受支持的注入目标。
- `open -a AppName` 不等同于直接启动内部可执行文件,也不是受支持的封装路径。
- 位于 `/usr/bin`、`/bin`、`/System`、`/sbin` 和 `/usr/libexec` 等 Apple 受保护位置的二进制文件受 SIP 阻止,不予支持。
- 即使 TCP 拦截有效,Firefox/LibreWolf 类等多进程浏览器等浏览器风格 GUI 应用仍处于实验阶段。Helper、GPU、合成器和沙盒子进程在 DYLD 注入下可能会变得不稳定。
- 对于可重复的实验性浏览器检查,请使用 [docs/macos-browser-validation.md](docs/macos-browser-validation.md) 中的文档化工具,而不是临时启动命令。
- 如果浏览器风格的应用在软刷新与硬刷新时显示不同的结果,请将其视为应用可能正在使用缓存、service worker 或替代传输路径的迹象,而不是假设隧道路径本身已损坏。
- 路由出站 TCP 是目前 macOS 上文档化和测试过的路径。封装 UDP 和封装 IPv6 流量在 macOS 上尚未达到生产就绪状态,更广泛的非阻塞/浏览器套接字兼容性仍在积极验证中。
- DNS 查找仍由主机网络栈解析。WrapGuard 目前通过隧道路由解析后的 IP 字面量 TCP 目标,但不拦截解析器 API 或隧道化 DNS 本身。
- Localhost 和环回流量被有意保留在主机栈上,不通过注入的 SOCKS 路径路由。
### 实验性 GUI 行为
macOS 实验性 GUI 启动的当前预期行为:
- 通过 WrapGuard 直接启动真实可执行文件路径
- 对于 `.app` 包,仅当存在单个明确可执行候选者时,WrapGuard 才可能自动解析 `Contents/MacOS/...`
- 如果浏览器或 GUI 应用需要已运行的应用实例、`open -a`、应用启动器服务或切换到另一个未封装的会话,则该路径不在受支持模型范围内
- 最可靠的验证流程是全新配置文件加上直接内部可执行文件启动
- 如果应用保持在直接启动的进程树中并接受 DYLD 注入,则路由出站 TCP 可以工作
macOS 上当前不受支持或有风险的应用类别:
- Apple 保护或 SIP 保护的二进制文件
- 拒绝注入库的强化运行时应用
- 立即切换到另一个已运行进程或守护进程的应用启动器
- 其关键助手进程无法容忍 DYLD 注入的应用
- 网络或合成器助手在插入下崩溃的沙盒 GUI 应用
### 当前浏览器传输决策
macOS 上当前的实验性浏览器立场是:
- 路由 TCP 是受支持的浏览器传输路径
- macOS 上目前不支持 UDP 和原生 QUIC 隧道
- WrapGuard 可能会抑制可能的浏览器 QUIC / `HTTP/3` `UDP/443` 流量,以便浏览器回退到经过验证的 TCP 路径
- 因此,浏览器支持应被视为实验性的直接启动 TCP 支持,而不是完整的浏览器传输等效性
### macOS 故障排除
- 运行 `wrapguard --doctor [target]` 以在尝试真正启动之前检查本地运行时布局、选定的注入模式和 macOS 预检限制。
- 如果传递目标,`--doctor` 还会在 WrapGuard 启动隧道栈之前验证该启动目标。如果省略目标,它仅检查本地运行时产物。
- `--doctor` 接受可解析的 `.app` 包,打印它选择的内部可执行文件,并在启动前拒绝 macOS 上受 SIP 保护的启动路径。
- 运行 `wrapguard --config= --self-test` 以验证 WrapGuard 能否启动其 IPC/SOCKS 栈、注入库并观察被拦截的出站 `connect()`。
- 如果子进程启动但 WrapGuard 报告拦截器从未宣布就绪,请确认目标不受 SIP 保护,并且 `libwrapguard.dylib` 位于 `wrapguard` 旁边。
- 如果流量未更改,请使用 `--log-level=debug` 重新运行,并检查显示 `DYLD_INSERT_LIBRARIES`、解析的 dylib 路径和拦截器加载消息的启动行。
- 如果基于主机名的连接仍通过主机而不是 VPN 解析,这在目前是预期的。WrapGuard 仅通过 SOCKS 和 WireGuard 用户空间 netstack 路由生成的 IP 字面量 TCP 目标。
- 如果您看到拦截器加载并且出站 `connect()` 调用被拦截,但请求仍以主机 IP 退出,请将其视为隧道路径故障。路由出站 TCP 现在会通过 WireGuard 用户空间 netstack 失败,而不是静默回退到直接主机连接,因此这指向对等可达性、出口节点路由或上游 WireGuard 配置问题,而不是 dylib 注入问题。
- 如果您正在验证类浏览器应用,并且它在软刷新后仍报告主机 IP,请将其与硬刷新和直接 CLI 探测(如 `curl`)进行比较;浏览器缓存、service worker、QUIC/HTTP3 或助手进程不稳定性都可能改变观察到的路径。
- 如果代码签名或强化运行时阻止注入,请暂时使用未签名或开发者控制的二进制文件。公证和强化运行时兼容性不在当前实验性支持声明范围内。
- 如果浏览器或 GUI 应用加载、拦截了一些流量,然后崩溃,请将其视为助手进程兼容性问题,而不是隧道路径损坏的证明。
## 路由
WrapGuard 支持基于策略的路由,以通过特定的 WireGuard 对等节点引导流量。
### 出口节点
使用 `--exit-node` 选项通过特定对等节点路由所有流量(如传统 VPN):
```
wrapguard --config=~/wg0.conf --exit-node=10.150.0.3 -- curl https://example.com
```
### 基于策略的路由
使用 `--route` 选项通过不同对等节点路由特定子网:
```
# 通过一个 peer 路由企业流量,通过另一个 peer 路由互联网
wrapguard --config=~/wg0.conf \
--route=192.168.0.0/16:10.150.0.3 \
--route=0.0.0.0/0:10.150.0.4 \
-- ssh internal.corp.com
```
### 配置文件路由
您还可以在 WireGuard 配置文件中定义路由:
```
[Peer]
PublicKey = ...
AllowedIPs = 10.150.0.0/24
# 通过此 peer 路由所有流量
Route = 0.0.0.0/0
# 或者路由特定子网
Route = 192.168.0.0/16
Route = 172.16.0.0/12:tcp:443
```
## 日志
WrapGuard 提供具有可配置级别和输出目标的结构化 JSON 日志。
### 日志选项
- `--log-level=` - 设置日志级别。默认值:info
- `--log-file=` - 将日志写入文件而不是终端
### 日志级别
- `error` - 仅严重错误
- `warn` - 警告和错误
- `info` - 一般信息、警告和错误(默认)
- `debug` - 详细调试信息
### 日志格式
所有日志都以带时间戳的结构化 JSON 格式输出:
```
{"timestamp":"2025-05-26T10:00:00Z","level":"info","message":"WrapGuard v1.0.0-dev initialized"}
{"timestamp":"2025-05-26T10:00:00Z","level":"info","message":"Config: example-wg0.conf"}
{"timestamp":"2025-05-26T10:00:00Z","level":"info","message":"Interface: 10.2.0.2/32"}
{"timestamp":"2025-05-26T10:00:00Z","level":"info","message":"Peer endpoint: 192.168.1.8:51820"}
{"timestamp":"2025-05-26T10:00:00Z","level":"info","message":"Launching: curl https://icanhazip.com"}
```
指定 `--log-file` 时,所有日志将写入文件,终端中不会显示任何内容。
## 配置
WrapGuard 使用标准 WireGuard 配置文件:
```
[Interface]
PrivateKey =
Address = 10.0.0.2/24
[Peer]
PublicKey =
Endpoint = server.example.com:51820
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 25
```
## 工作原理
1. **主进程**:解析配置,初始化 WireGuard 用户空间实现
2. **注入库**:使用宿主机特定的动态加载路径拦截网络系统调用
3. **虚拟网络栈**:在被拦截的连接和 WireGuard 隧道之间路由数据包
4. **用户空间 TUN/Netstack**:无需内核接口,数据包完全由 WireGuard 用户空间 netstack 在内存中处理
## 限制
- 仅限 Linux 和 macOS(不支持 Windows)
- macOS 运行时支持是实验性的,不应假设适用于 SIP 保护二进制文件、强化运行时应用、`open -a` 启动器路径或无法接受注入库的启动目标
- 路由 TCP 是目前主要的文档化路径
- 封装 UDP 和封装 IPv6 在 macOS 上尚未作为受支持项记录在案
- 由于用户空间数据包处理而产生的性能开销
## 开发
### 运行测试
WrapGuard 包含针对所有核心功能的全面单元测试:
```
# 运行所有测试
go test -v ./...
# 运行测试并生成覆盖率
go test -cover ./...
```
### 构建
```
# 构建主要 binary
make build
# 端到端验证本地 macOS package 布局
make smoke-macos
# 使用全新 profile 启动实验性 macOS browser target
make smoke-macos-browser \
WG_CONFIG=../NL-US-PA-16.conf \
BROWSER_APP="/Applications/LibreWolf.app/Contents/MacOS/librewolf"
# 带 debug 信息构建
make debug
# 清理 build artifacts
make clean
```
## 演示
WrapGuard 包含一个全面的基于 Docker 的演示,展示了 Node.js 应用程序通过 WireGuard 隧道通信,无需 root 权限或内核模块。
演示包括:
- 一个 WireGuard 服务器容器
- 两个使用 WrapGuard 封装的 Node.js HTTP 服务器
- 通过 WireGuard 隧道的跨服务器通信
### 运行演示
```
cd demo
./setup.sh
docker compose up --build
```
## 测试
```
# 测试传出连接
wrapguard --config=example-wg0.conf -- curl https://example.com
# 测试传入连接
wrapguard --config=example-wg0.conf -- python3 -m http.server 8080
```
标签:EVTX分析, Go, IP 地址批量处理, Ruby工具, SOCKS, VPN, Web截图, WireGuard, 代理工具, 动态库注入, 基础设施, 容器安全, 无特权运行, 日志审计, 流量劫持, 用户态网络, 系统编程, 网络安全, 网络拦截, 网络隧道, 透明代理, 隐私保护