tunless 无TUN透明代理。无需伪造IP,无需路由劫持,无需第二个TCP协议栈。

来源: https://github.com/bojieli/tunless/

你已经在运行 mihomo 或 sing-box 了:节点正常工作,规则配置妥当,订阅也能自动更新。但麻烦的是,如何让应用程序真正使用这些配置。

有些程序会读取 HTTPS_PROXY 环境变量,但很多程序根本不看这一项,而是直接绕过代理发出请求,且不给你任何提示。于是你开启了 TUN 模式,因为它能接管所有流量——但这带来了一系列问题:你的 DNS 解析器开始返回 198.18.0.0/15 网段的地址,这些地址除了生成它们的代理程序外,对外界毫无意义;你的路由表被修改了,且修改者无法将其还原;一旦该代理进程崩溃,你就会直接断网。

tunless 提供了第三种选择。它在更高一层——即 Socket 层面——拦截连接,此时数据尚未被封装成网络数据包。在这个层级,内核依然掌握着应用程序请求的主机名以及发起请求的程序信息,因此无需进行任何重构或伪造。它将拦截到的连接以标准 SOCKS5 协议的形式,转发给你现有的代理程序。

为什么在更高一层处理会带来根本性的变化

当数据包被交给 TUN 设备时,你最初输入的域名信息已经丢失,只剩下地址和端口。然而,代理规则通常是基于域名设定的,因此必须设法找回域名信息,而实现这一点的方法只有两种:要么在 DNS 响应中返回一个虚构地址并记录其对应的域名,要么在数据包传输途中读取 TLS 握手信息,寄希望于其中的主机名仍以明文形式存在。

这两种方法在大多数情况下都有效,但也解释了人们实际遇到的故障:一种情况是虚构地址的有效期超过了其背后的映射关系,导致连接虽能建立却无法传输数据;另一种情况是“加密客户端握手”(Encrypted Client Hello)技术的普及,正在悄然让第二种方法失效。

而在 Socket 层,这些问题都不存在,因为此时原始信息尚未丢失。

这正是核心理念,其余的一切都由此衍生:

名称会被解析为真实地址,因此不会有虚假地址泄漏到缓存、日志或执行自身 DNS 检查的应用程序中。
路由表保持原样,无需进行回滚操作,也不会留下指向已不存在设备的残留配置。
数据流始终在内核自身的套接字(socket)上运行;用户空间中不存在重复实现内核既有功能的第二套 TCP/IP 协议栈。
如果 tunless 停止运行,连接将恢复通过常规路径进行。捕获操作由内核掌控,因此终止该进程即可释放资源;我们通过发送 SIGKILL 信号来验证这一点。
你的代理服务不受影响;tunless 仅替代入站处理逻辑,而不改变路由规则。
若需了解更详尽的论证(包括被否决的方案及其原因),请参阅 BLUEPRINT.md。

How it works

应用程序照常调用 connect()。由于捕获点位于操作系统自身的套接字层(Linux 上的 eBPF cgroup 钩子、macOS 上的 Network Extension 或 Windows 上的 WFP),因此数据流到达时仍保留着原始目标地址和发起调用的进程信息。tunless 决定是否拦截该流量:将 53 端口的流量发送至您指定的解析器,其余流量则以标准的 SOCKS5 格式转发。您的代理端看到的将是一个常规的 SOCKS5 客户端。

Platform How it captures Where it stands
Linux eBPF cgroup connect/sendmsg/recvmsg and sockops TCP and UDP over both address families, on the host and inside container namespaces. Unconnected UDP is single-destination on purpose; see the note under migration.
macOS NETransparentProxyProvider system extension Notarized builds pass the recorded live suites. Upstream degradation and Wi-Fi/hotspot changes retain fail-closed capture while transports rebuild. Clean-machine qualification of the exact candidate is still open.
Windows WFP ALE connect-redirect callout Source only. The driver has never been built by a WDK, loaded, or run under Driver Verifier, and it is not signed. Treat it as a design, not a download.

这三个平台在发布时的成熟度各不相同,发布说明中也明确指出了这一点:在 0.3.0 版本中,Linux 版为正式可用(GA)状态,macOS 版为 Beta 状态,而 Windows 版仅提供源码。您可以借此了解发布版本涵盖的内容以及项目的实际进展。

可移植的核心组件负责处理这三个平台共有的 SOCKS5 相关工作,包括:TCP 和 UDP 数据发送,HTTP CONNECT 及 SOCKS5 协议的入站连接处理,流量捕获过滤,用于监控实际 DNS 响应的 DNS 观察器,以及两种将进程身份信息传递给下游的可选机制。

流量捕获带来的开销约为吞吐量的 0.25%。在稳定的链路测试中,捕获模式下的速率为 112.82 MB/s,而直接传输速率为 113.13 MB/s;每转发 1 GB 数据消耗约 1.35 CPU 秒和 10 MB 内存。该仓库中记录的每一项数据——无论是性能测量结果还是发布准入指标——都标明了测试所用的机器环境及测试日期。

个人点评:

强烈建议 R主席 sing-box mihomo 吸收这个项目

曾经上诉项目都有过一些不使用tun 也可代理程序(实现透明代理)的轻方案,倒是现在都只会想到 tun了。

但代理程序这一模块到底应该塞进核心,还是由客户端完成,这是另一个话题了,有时间写进《冲浪小本本儿》里。