← 返回

使用 trans_proxy 搭建透明代理网关

使用 trans_proxy 搭建透明代理网关 封面图

什么是透明代理

传统代理需要在每台设备上手动配置代理地址,透明代理则工作在网关这一层:局域网设备只要把默认网关和 DNS 指向代理机器,所有 TCP 流量就会被自动拦截并转发到上游代理,设备本身不用做任何代理配置。

这对不方便设置代理的设备(智能电视、IoT 设备、游戏主机等)尤其有用。

trans_proxy 的工作原理

trans_proxy 是一个用 Rust 写的透明代理工具,支持 macOS 和 Linux,基于 tokio 异步运行时。它的整体架构如下:

trans_proxy 架构示意图

获取原始目的地址

透明代理要解决的第一个问题是:流量被 NAT 重定向到 trans_proxy 的监听端口后,怎么知道客户端原本想访问的地址?

trans_proxy 在两个平台上用了不同的办法:

  • macOS (pf):通过 DIOCNATLOOK ioctl 查询 pf 的 NAT 状态表,拿到连接被重定向前的原始目的地址
  • Linux (nftables):在 accept 出来的 socket 上通过 SO_ORIGINAL_DST getsockopt 读取原始目的地址

解析出 hostname

拿到原始 IP 和端口后,还要把 IP 还原成域名,因为上游 HTTP CONNECT 代理需要 CONNECT hostname:port 格式的请求。trans_proxy 按下面的优先级确定 hostname:

  1. SNI 提取:对 TLS 连接(端口 443),解析 ClientHello 里的 SNI 扩展字段,直接拿到客户端要访问的域名,不需要解密 TLS 流量
  2. DNS 反查:如果启用了内置 DNS 转发器,trans_proxy 会记录 DNS 查询结果,可以从里面反查 IP 对应的域名
  3. IP fallback:两种办法都拿不到域名时,就直接用 IP

内置 DNS 转发器

trans_proxy 内置了一个 DNS 转发器,监听网关接口的 53 端口,功能包括:

  • DNS-over-HTTPS (DoH):把 DNS 查询通过 HTTPS 发给上游 DNS 服务器(默认 Cloudflare),避免 DNS 污染
  • HTTP/2 连接池:复用 HTTP/2 连接,降低 DoH 查询延迟
  • TTL 缓存:按 DNS 记录的 TTL 缓存查询结果
  • 查询合并(coalescing):合并对同一域名的并发查询,避免重复请求

除了提供 DNS 服务,它记录的查询结果也给上面的 hostname 解析提供了 IP 到域名的反查依据。

防火墙集成

trans_proxy 通过脚本管理防火墙规则:

  • macOS:用 pf 的 anchor 机制,把 NAT 重定向规则挂在独立的 anchor 下,不影响系统已有的 pf 规则
  • Linux:创建独立的 nftables table,同样不干扰现有的防火墙配置

安装与编译

Bash
# 克隆仓库
git clone https://github.com/madeye/trans_proxy.git
cd trans_proxy

# 编译(需要 Rust 1.70+)
cargo build --release

# 编译产物在 target/release/trans_proxy

使用方法

macOS

假设网关机器的网络接口是 en0,上游 HTTP CONNECT 代理跑在本地 127.0.0.1:1082

Bash
# 启动 trans_proxy(启用 DNS 转发器)
sudo ./trans_proxy --upstream-proxy 127.0.0.1:1082 --dns

# 设置 pf NAT 重定向规则
sudo scripts/pf_setup.sh en0 8443

Linux

假设网关接口是 eth0,上游代理在 127.0.0.1:7890

Bash
# 启动 trans_proxy
sudo ./trans_proxy --upstream-proxy 127.0.0.1:7890 --dns --interface eth0

# 设置 nftables 规则
sudo scripts/nftables_setup.sh eth0 8443

主要参数

参数默认值说明
--listen-addr0.0.0.0:8443trans_proxy 监听地址
--upstream-proxy(必填)上游 HTTP CONNECT 代理地址
--dns关闭启用内置 DNS 转发器
--interfaceen0 / eth0网关网络接口
--dns-upstreamCloudflare DoH上游 DNS 服务器(支持 UDP 或 DoH)
--log-levelinfo日志级别(trace/debug/info/warn/error)
-d / --daemon关闭以 daemon 方式运行

客户端配置

局域网内的设备只需要两步:

  1. 默认网关设为运行 trans_proxy 的机器 IP
  2. DNS 服务器设为同一 IP(如果启用了 --dns

macOS、iOS、Windows、Linux、Android 等主流平台都支持,设备端不用装任何软件。

安装为系统服务

trans_proxy 支持一键安装为系统服务:

Bash
sudo ./trans_proxy --upstream-proxy 127.0.0.1:1082 --dns --install
  • macOS:创建 LaunchDaemon,开机自启
  • Linux:创建 systemd unit,并通过 ExecStartPre / ExecStopPost 自动管理 nftables 规则的加载和清除

卸载服务:

Bash
sudo ./trans_proxy --uninstall

排查问题

遇到问题时,先把日志级别调高观察:

Bash
sudo ./trans_proxy --upstream-proxy 127.0.0.1:1082 --dns --log-level debug

常见问题:

  • /dev/pf 权限错误(macOS):确认以 root 权限运行
  • NAT 查询失败:检查防火墙规则是否正确加载(macOS 用 pfctl -sa,Linux 用 nft list ruleset
  • 连接超时:确认上游代理运行正常,检查网关机器是否开启了 IP 转发(Linux 需要 sysctl net.ipv4.ip_forward=1
  • DNS 解析失败:确认 53 端口没有被其他进程占用(lsof -i :53

与 Caddy 正向代理配合

trans_proxy 需要一个上游 HTTP CONNECT 代理。没有现成的话,可以参考之前的文章用 Caddy 搭一个。典型的组合是:

TEXT
局域网设备 → trans_proxy(网关) → Caddy HTTPS 正向代理(远程服务器) → 目标网站

这样局域网设备不用任何配置,所有流量自动通过加密隧道转发。

小结

trans_proxy 解决的核心问题是:让局域网内所有设备不做任何配置就能走代理上网。它的好处在于:

  1. 零配置客户端:设备只需改网关和 DNS,不用装软件也不用配代理
  2. 跨平台:同时支持 macOS (pf) 和 Linux (nftables) 作为网关
  3. DNS 防污染:内置 DoH 转发器,从源头解决 DNS 污染
  4. 不侵入现有防火墙:anchor / 独立 table 机制不干扰已有规则
  5. 异步高性能:基于 tokio,每个连接独立调度,适合网关的高并发场景