系统代理只能代理部分流量,TUN 模式接管所有流量。本文从原理到实践,讲清楚两种代理方式的区别,帮你根据场景做出正确选择。
大家好,我是阿明。
很多刚接触 macOS 代理工具的朋友都会遇到一个非常经典,甚至有点让人抓狂的问题:“我明明已经在代理软件里开了‘全局模式’,为什么在终端里执行 curl 或者 git clone 还是慢得要死?为什么我写的代码跑起来还是连不上国外的 API?”
这个问题的根源,其实就在于你对“代理”的理解还停留在表面。在 macOS 上,实现代理的方式有很多种,最常见的两种就是**系统代理(System Proxy)**和 TUN 模式(TUN Mode)。虽然它们看起来都能让你访问原本无法访问的网站,但背后的实现逻辑、接管流量的范围以及适用场景完全不同。
今天这篇文章,我就打算把这两个东西彻底讲透,让你以后不再为“流量走没走代理”这种事纠结。
1. 为什么开了代理,Terminal 还是不走代理?
这是最常见的新手坑。你打开了 Clash 或者 Surge,勾选了“系统代理”,在浏览器里访问 Google 丝般顺滑。于是你满怀信心地打开终端,想克隆一个 GitHub 仓库,结果依然是 Connection timed out。
原因很简单:“系统代理”不是万能钥匙,它更像是一个“自愿参与”的协议。
在 macOS 的“系统设置 - 网络 - 代理”里,你可以配置 HTTP、HTTPS 和 SOCKS 代理服务器地址。当你勾选代理软件的“系统代理”选项时,软件其实只是在系统配置里填上了这些地址。
问题在于,并不是所有软件都会去读取这个配置。
- 浏览器(Chrome/Safari): 它们非常乖,会主动检查系统设置,发现有代理就会按照指示走。
- 终端(Terminal/iTerm2): 它们基本不看系统代理设置。除非你在
.zshrc或者当前会话里手动执行export http_proxy=...,否则它们会直连网络。 - 各类编程语言运行时(Python/Node.js/Go): 大多数情况下它们也不会自动读取系统代理。比如你用 Python 的
requests库发请求,默认它是直连的。 - Docker: 这是一个大坑。Docker 容器里的流量完全独立,它根本不知道宿主机的系统代理是什么。
- 游戏: 绝大多数游戏都是直接通过 Socket 连接服务器,完全无视系统代理设置。
所以,如果你需要接管这些“不听话”的流量,仅仅靠系统代理是不够的。
2. macOS 网络代理的三种主力方式
在深入对比之前,我们先明确一下在 Mac 上常见的几种流量接管手段:
- 系统代理(System Proxy): 最基础的方式,通过环境变量或系统配置引导软件。它工作在应用层(Layer 7)。
- TUN 模式(TUN Mode): 通过创建虚拟网卡,从**网络层(Layer 3)**拦截所有流量。这是目前最主流的“真全局”方案。
- Proxychains 等注入式工具: 通过 Hook 系统调用,强制让某个特定命令走代理。
接下来,我们重点聊聊前两者的区别。
3. 系统代理原理:温文尔雅的引导
系统代理的本质是应用层转发。当你开启系统代理时,代理软件会在本地启动一个监听端口(比如 7890)。然后它修改 macOS 的系统网络设置,告诉系统:“如果有 HTTP 或 HTTPS 的请求,请引导应用发送到 127.0.0.1:7890”。
它的局限性非常明显:
- 协议单一: 系统代理主要针对 HTTP 和 HTTPS。虽然也有 SOCKS 代理设置,但很多软件对 SOCKS 的支持并不好。
- 非强制性: 就像我前面说的,软件可以选择无视。这就是为什么你在终端里需要手动配置环境变量。
- UDP 的缺失: 系统代理基本无法处理 UDP 流量。如果你玩外服游戏或者使用某些基于 UDP 的协议(如 QUIC/HTTP3),系统代理往往起不到作用。
4. TUN 模式原理:霸道总裁式的接管
如果说系统代理是“引导”,那么 TUN 模式就是“拦截”。
TUN(Network TUNnel)是一种内核级别的虚拟网络设备。开启 TUN 模式后,代理软件会向系统申请创建一个虚拟网卡,通常名字叫 utun0、utun1 之类的。你可以通过在终端输入 ifconfig 看到它。
它的工作流程如下:
- 代理软件修改系统的路由表,把默认路由或者特定范围的网络流量都指向这个
utun虚拟网卡。 - 现在,操作系统认为所有的网络请求都应该通过这个虚拟网卡发出去。
- 代理软件在后台实时监听这个虚拟网卡。当数据包到达网卡时,代理软件直接从网络层(IP 层)把数据包抓走。
- 代理软件对数据包进行解包、重新封装,然后通过加密隧道发送到远端服务器。
为什么 TUN 模式能搞定 Terminal?
因为路由表是操作系统的最高指令。无论你是浏览器、终端还是游戏,只要你想发送网络包,就必须经过操作系统的路由决策。既然路由表说流量要去 utun0,那你就得乖乖过去。代理软件在网卡出口等着,直接截获流量。
TUN 模式的优势:
- 真·全局: 接管所有 TCP 和 UDP 流量。
- 应用透明: 应用完全不需要知道代理的存在,也不需要任何特殊配置。
- 解决 DNS 污染: 配合代理软件的 DNS 接管功能,可以彻底解决国内 DNS 劫持问题。
5. DNS 处理:系统代理 vs TUN 模式
这是一个经常被忽略但极其重要的点。
在系统代理模式下,DNS 解析通常是由浏览器自己完成的。浏览器可能会先尝试本地 DNS 解析,然后再把解析出来的 IP 发给代理服务器,或者直接把域名发给代理服务器(由服务器远程解析)。这种方式很容易导致 DNS 泄漏。
在 TUN 模式下,代理软件通常会接管系统的 DNS 设置(修改 /etc/resolv.conf)。它会拦截所有发往 53 端口的 DNS 请求。
- Fake-IP 模式: 代理软件收到 DNS 请求后,直接返回一个假的内部 IP(比如
198.18.0.1)。当应用尝试连接这个假 IP 时,代理软件再根据之前的记录,把请求转发到真实的域名目标。 - Real-IP 模式: 代理软件先在后台帮解析出真实的 IP,再返回给应用。
TUN 模式下的 Fake-IP 方案是目前公认的最佳实践,它能极大地提高首包响应速度。
6. 两者对比大表格
为了方便大家快速查阅,我整理了这个对比表:
| 维度 | 系统代理 (System Proxy) | TUN 模式 (TUN Mode) |
|---|---|---|
| 工作层次 | 应用层 (Layer 7) | 网络层 (Layer 3) |
| 覆盖范围 | 仅支持主动读取设置的应用 | 整个操作系统,包含终端、游戏、后台进程 |
| 协议支持 | 主要是 HTTP/HTTPS/SOCKS | TCP / UDP 全部支持 |
| Terminal 默认走代理 | 否(需手动配置 export) | 是(直接生效) |
| 游戏支持 | 极差 | 极好(支持 UDP 转发) |
| 配置复杂度 | 极简,一键开启 | 略高,需要系统权限和虚拟网卡支持 |
| 性能消耗 | 极低(几乎忽略不计) | 较高(内核态与用户态切换开销) |
| 稳定性 | 极高 | 中等(偶尔会出现网卡挂起) |
| DNS 泄漏风险 | 较高 | 极低(可完全接管 DNS) |
7. 深入探讨:为什么 TUN 模式性能开销更大?
很多朋友会问,既然 TUN 模式这么好,为什么不一直开着?这就涉及到性能损耗了。
系统代理是在应用层处理的。比如 Chrome 要发一个 HTTP 请求,它直接把请求内容塞给代理软件的端口。这中间的转换非常轻量。
TUN 模式则不同。每一个网络包(Packet)都要经历以下过程:
- 应用产生数据包。
- 操作系统根据路由表把包发给虚拟网卡
utun。 - 数据包从内核态(Kernel Space)拷贝到用户态(User Space)的代理软件。
- 代理软件解析包头,重新封装。
- 封装后的包再从用户态拷贝回内核态,通过物理网卡发出。
这种内核态与用户态之间的频繁切换和内存拷贝,在流量非常大(比如下载几百 GB 的文件)或者网速非常快(千兆光纤)的时候,会消耗明显的 CPU 资源。这也是为什么在老款 MacBook Air 上开着 TUN 模式下载东西,风扇会狂转的原因。
8. 什么时候用系统代理就够了?
在以下场景中,系统代理其实是更好的选择:
- 日常网页浏览: 如果你只是上上网、查查资料,看看 YouTube。浏览器对系统代理的支持是最完美的,性能损耗也是最小的。
- 老款 Mac 设备: 为了保护电池和降低发热,系统代理更友好。
- 对稳定性要求极高: 系统代理只是改个配置,基本不会导致断网。而 TUN 模式涉及到修改内核路由表,如果代理软件崩溃,可能会导致你整台电脑彻底断网,需要手动清理路由表或者重启。
- 远程桌面或局域网协作: 开启 TUN 模式有时会干扰本地局域网的发现功能(比如 AirDrop 或打印机连接),如果你遇到这类问题,切换回系统代理通常能解决。
9. 什么时候必须用 TUN 模式?
如果你属于以下人群,TUN 模式几乎是你的唯一选择:
- 开发者(DevOps/后端/全栈):
- 你需要频繁在终端使用
git,docker,npm,brew,go install。 - 你在本地调试代码,代码需要访问国外的云服务或 API(比如 OpenAI API)。
- 你的项目依赖很多包管理工具,它们往往不遵循系统代理。
- 你需要频繁在终端使用
- 外服游戏玩家: 想在 Mac 上玩美服《魔兽世界》或台服《英雄联盟》?没 TUN 模式几乎不可能,因为游戏走的是 UDP 协议。
- 需要使用特定 UDP 软件: 比如某些语音工具、视频会议软件。
- 追求极致隐私: 想让电脑上每一个后台进程都经过代理,不留下任何直连痕迹。
10. 如何检查流量到底走没走代理?
别再只看浏览器能不能打开 Google 了。作为专业用户,你需要这几个命令:
检查系统代理设置:
networksetup -getwebproxy "Wi-Fi"
networksetup -getsocksfirewallproxy "Wi-Fi"
在终端检查连接:
curl -v https://www.google.com
观察输出。如果看到 Connected to 127.0.0.1 (127.0.0.1) port 7890,说明走的是系统代理的环境变量。如果直接连接到了远程 IP,说明没走代理。
检查网卡状态:
ifconfig | grep utun
如果能看到 utun0, utun1 等网卡,说明 TUN 模式已启动。
检查路由表:
netstat -nr | grep utun
看看默认网关(default)是不是指向了虚拟网卡。
11. Proxychains:另一种补充方案
有些朋友觉得开启 TUN 模式太重了,但又想让终端走代理。这时候可以考虑 Proxychains-ng。
它的原理是通过 DYLD_INSERT_LIBRARIES 环境变量,将一个动态库注入到你要运行的进程中,然后 Hook 它的网络连接函数。
用法示例:
proxychains4 brew update
这种方式的优点是“外科手术式”的精准,只对这一个命令生效。缺点是配置稍显繁琐,且在 macOS 上受 SIP(系统完整性保护)的限制,无法直接作用于系统自带的命令(如 /usr/bin/curl),你需要用 Homebrew 安装一个副本才能用。
12. 安全性与隐私:值得警惕的地方
开启 TUN 模式意味着你将整台电脑的网络流量“托付”给了代理软件。
- 流量可见性: 代理软件可以看到每一个包的目的地。
- 根权限: 开启 TUN 模式通常需要授予软件
root权限或安装辅助工具。
所以我个人的建议是:一定要使用信誉良好的客户端。 开源项目(如 Clash Verge Rev, Clash Meta)或者老牌商业软件(如 Surge, Stash)是比较稳妥的选择。千万不要去用那些来路不明、甚至需要你关闭系统 SIP 才能运行的“破解版”软件。
13. 阿明的推荐组合方案
作为一名长期在 macOS 下工作的开发者,我的配置建议是:
- 日常状态: 开启代理软件的“系统代理”。此时浏览器工作正常,不会增加额外功耗。
- 开发状态: 开启 TUN 模式。当我需要运行
npm install或者启动我的后端项目时,我会开启 TUN。 - 进阶配置: 在代理软件里设置“分流规则”。
- 将
localhost,127.0.0.1,192.168.0.0/16等内网地址设置为直连。 - 将国内常用域名(如 百度、知乎)设置为直连。
- 只有真正的海外请求才走代理。 这样既能保证访问国内服务的速度,又能让终端无缝出海。
- 将
14. 常见问题排查 (FAQ)
Q: 开启了 TUN 模式,为什么 AirDrop 用不了了?
A: 这是因为部分代理软件的 TUN 模式接管了太彻底,干扰了局域网的广播包。尝试在设置里将 169.254.0.0/16(本地链路地址)加入排除列表。
Q: 开启 TUN 后,网速变慢了? A: 检查是否开启了 Fake-IP。如果是 Real-IP 模式,解析速度可能会受影响。另外,检查你的 CPU 占用率,如果 CPU 满载,网速自然会上不去。
Q: 终端依然不通,即使开了 TUN?
A: 检查一下你是否在 .zshrc 里还残留着旧的 http_proxy 环境变量。环境变量的优先级有时会干扰 TUN 模式的表现,建议全部删掉。
总结
- 系统代理是“请客吃饭”,应用可以不来,适合轻量级、低功耗的上网。
- TUN 模式是“强制执行”,不管应用愿不愿意,流量都必须经过代理,是开发者和硬核玩家的标配。
- 按需切换才是最高效的使用方式。
理解了这两者的区别,你就能明白为什么有时候需要“全局”,而有时候只需要一个环境变量。希望这篇文章能帮你彻底扫清 macOS 代理的盲区。
我是阿明,专注于分享 macOS 上的效率工具和技术干货。如果你觉得这篇文章对你有帮助,欢迎分享给身边的朋友!