Windows 与 Linux 的网络代理机制:从 System Proxy 到 TUN、Netfilter
从一次 Microsoft Store 与 Xbox 的故障开始
最近在 Windows 上使用 v2rayN 时,遇到了一个很具体、也很容易让人困惑的问题:浏览器访问网页一切正常,但 Microsoft Store 和 Xbox 却无法联网。更奇怪的是,问题并不是简单地“Windows 没有网络”,因为 Steam 以及其他普通桌面应用仍然可以正常工作。
最初排查的是 Xbox 服务、Microsoft Store、游戏组件和 Windows 网络本身。后来注意到 v2rayN 里有一个看起来不太像普通代理开关的选项:
解除 UWP Loopback 限制
开启这个设置后,Microsoft Store 和 Xbox 的网络行为恢复了。这个结果也带来了更有意思的问题:为什么一个代理客户端需要修改 Windows 的 Loopback 访问权限?Windows 的系统代理到底影响哪些应用?为什么浏览器可以走代理,游戏或系统应用却可能不行?如果换成 Linux,代理又是在什么层面接管流量的?
顺着这个故障继续往下看,才发现“代理”并不是一种单一机制:它可能是应用读取的一项配置,也可能是虚拟网络接口,或者是内核网络栈中的路由与过滤规则。
在 Windows 上使用 v2rayN、Clash 或 sing-box 时,经常会看到几个选项:
System Proxy
TUN
Loopback Exemption
Transparent Proxy
它们都能让程序“通过代理上网”,但工作位置并不相同。浏览器能打开网页,也不代表游戏、终端工具或后台服务一定会走代理;TUN 也只是提供了流量进入用户态程序的路径,并不自动接管所有数据包。
因此,理解这些差异时始终抓住一个问题:
流量是在应用层被应用主动送给代理,还是已经进入操作系统网络栈后,才被路由或拦截到代理?
先看整体:代理流量经过哪些层
“代理”不是一个单独的网络层,而是一组发生在不同位置的机制。先把完整路径放在一起:
Application
│
├─ 应用主动读取代理配置
│ ↓
│ Loopback → 本机代理进程
│
└─ 应用直接创建 socket
↓
操作系统网络栈
↓
路由 / 过滤 / 透明接管
↓
物理网卡或 TUN
↓
代理、VPN 或 Internet
这张图先给出全文的主线:应用可以主动把请求交给 HTTP/SOCKS 代理,也可以完全不知道代理的存在,让内核通过路由、虚拟网卡或过滤规则接管流量。Windows 和 Linux 的名称、API、驱动不同,但都可以放回这条路径理解。

同一个目标可以呈现出两条完全不同的路径:
浏览器:应用 → System Proxy → 127.0.0.1:10809 → 代理进程 → Internet
游戏: 应用 → socket → 内核路由 → TUN → 代理进程 → Internet
接下来分别看应用代理、Loopback、TUN、路由和 Netfilter,最后再把它们放回这张图中。
1. System Proxy:应用主动遵守的约定
假设代理客户端在本机监听一个 HTTP 或 SOCKS 端口:
127.0.0.1:10809
打开 Windows 的系统代理后,配置大致相当于:
HTTP proxy = 127.0.0.1:10809
HTTPS proxy = 127.0.0.1:10809
支持系统代理的应用会先连接本机代理,再由代理代表它访问远端:
Browser
↓ 读取代理配置
127.0.0.1:10809
↓
Local proxy client
↓
Remote proxy
↓
Internet
这里的关键是“读取”。System Proxy 不是内核规则,也不是一个会扫描所有连接的防火墙。它更像应用层 API 或配置约定:应用愿意遵守,流量才会进入代理。
因此,使用原始 socket 的程序可能完全绕过它:
socket.connect(("1.2.3.4", 443))
这段代码只表达了目标地址、端口和协议,并没有表达“请先经过 HTTP Proxy”。游戏、某些命令行工具、数据库客户端以及自带网络引擎的程序,常常有自己的代理配置,或者干脆不支持代理。
Windows 里还要注意 WinINet 与 WinHTTP 的区别。桌面应用常见的浏览器式网络请求通常会受到用户代理设置影响;服务、系统组件和命令行程序可能使用 WinHTTP,读取的是另一套配置。应用还可能通过 PAC 文件,根据目标地址选择 DIRECT 或某个代理。排查“浏览器可以、服务不行”时,不能只看控制面板里的代理开关。
2. Loopback:代理为什么总在 127.0.0.1 上
127.0.0.1、localhost 和 IPv6 的 ::1 都属于 loopback,意思是“本机访问本机”。
Application A
↓ connect(127.0.0.1:10809)
Operating system network stack
↓
Application B: local proxy
数据不会真的从网卡发到路由器,再绕回来。它会在本机协议栈和 loopback 接口中完成传递。Linux 上可以这样查看 loopback 接口:
ip addr show lo
代理监听 loopback 有几个好处:默认不暴露给局域网,应用使用统一的本机地址,代理也不需要占用真实网卡地址。但“只在本机”不等于“任何本机进程都能访问”。Windows 的沙箱模型正好会让这个假设变得复杂。
3. Windows 的 UWP Loopback 限制
部分 UWP / AppContainer 应用运行在受限制的安全边界内。Windows 默认限制它们访问本机 loopback,原因是 localhost 上可能有很多只为本机服务的端口:
127.0.0.1:5432 PostgreSQL
127.0.0.1:6379 Redis
127.0.0.1:3000 开发服务器
127.0.0.1:10809 代理客户端
如果低权限应用可以任意扫描和连接这些服务,其他本地进程就可能成为攻击面。
于是会出现一个看似矛盾的故障:如果某个 Microsoft Store / packaged 应用采用了系统代理,而代理地址又是 127.0.0.1:10809,它在连接本机代理时仍可能被系统的 loopback 限制拒绝。
Xbox
↓ 遵守 System Proxy
127.0.0.1:10809
↓
Loopback access denied
“解除 UWP Loopback 限制”本质上是给指定 packaged 应用增加 loopback 豁免,使它可以访问本机代理端口。它只解决“应用能不能连接本机代理”这一跳,并不会让一个原本不支持系统代理的游戏突然支持代理,也不会替代 TUN。具体应用是否采用系统代理、是否属于受限的 AppContainer,应结合应用类型和 WFP/网络诊断结果确认,不能仅凭“浏览器能上网”断定故障原因。
4. TUN:把代理从应用配置下沉到网络接口
当程序不遵守 System Proxy 时,常见方案是 TUN。TUN 是一个虚拟的三层网络接口,向内核表现得像 eth0、wlan0 一样,但接口另一端不是物理网卡,而是用户态程序。
普通直连路径是:
Application
↓ socket
Kernel TCP/IP stack
↓ routing
Wi-Fi / Ethernet
↓
Physical network
启用 TUN 后,路由可以把目标流量送到虚拟接口:
Application
↓ socket
Kernel TCP/IP stack
↓ routing
tun0
↓ read/write packets
Proxy or VPN process
↓
Encrypted tunnel / Internet
对应用而言,它仍然是在连接目标 IP 和端口;它不必知道代理的存在。变化发生在内核的路由决策和 TUN 驱动层。
Linux 通常通过 /dev/net/tun 创建 TUN 设备。用户态程序打开这个设备后,内核发往该接口的 IP packet 就可以被程序读出;程序也可以把处理后的 packet 写回去。Windows 没有完全相同的设备文件模型,但 Wintun 等虚拟网卡驱动提供了相同的核心能力:为用户态 VPN / 代理程序提供一个虚拟三层接口。Wintun 本身不是拦截任意应用流量的规则引擎,仍需要路由、策略路由或其他过滤机制把流量送入接口。
需要区分 TUN 和 TAP:TUN 处理 IP 层的 packet,TAP 更接近二层以太网 frame。大多数面向 IP 路由的 VPN 和代理透明接管方案使用 TUN;需要模拟网卡二层行为时才会使用 TAP。
5. 路由表决定“送到哪里”,不会自动决定“由谁代理”
TUN 只是接口。要让流量进入 TUN,还需要路由或拦截规则。
Linux 可以用下面的命令查看路由:
ip route
一个典型的 TUN 方案可能增加更具体的路由,或者把默认路由指向 TUN:
目标地址 下一跳 / 接口
10.0.0.0/8 eth0
192.168.1.0/24 wlan0
0.0.0.0/0 tun0
路由最长前缀匹配:更具体的网络优先于默认路由。因此,代理程序通常必须保留一条到代理服务器本身的直连路径,否则会发生“代理连接也被送回 TUN”的递归环路。
Application → tun0 → Proxy → tun0 → Proxy → ...
成熟的 TUN 实现会使用排除路由、策略路由、独立路由表或进程标记来避免这个问题。DNS 也必须单独设计:如果域名解析仍然直连,可能出现 DNS 泄漏;如果代理按域名分流,则需要在连接建立前保留域名信息或使用透明 DNS 方案。
6. Netfilter 与透明代理
路由解决的是“packet 应该走哪块接口”;如果应用根本没有配置代理,系统还需要有一种办法把它的流量交给代理进程。这就引出了一个关键问题:系统级透明代理需要内核支持吗?
答案是需要操作系统网络栈的支持,但通常不需要修改内核源码。所谓“透明”,是指应用不必配置 HTTP 或 SOCKS 代理,系统仍能在 socket 或 packet 经过网络栈时拦截、重定向,或者把它送入虚拟网卡。用户态代理程序本身不能凭空看到其他应用的任意连接,必须依靠内核规则、过滤驱动或 TUN 路径把流量交给它。也存在基于 LD_PRELOAD、Winsock hook 等方式的进程级用户态方案,但它们的覆盖范围和可靠性不同,不能与内核级 packet 接管混为一谈。
Linux 和 Windows 的实现入口不同:Linux 通常使用 Netfilter 配合 iptables / nftables、REDIRECT、TPROXY 和策略路由;Windows 没有 Netfilter,常见方案是 Windows Filtering Platform(WFP)及其过滤驱动,或 WinDivert 等数据包拦截机制。如果采用 TUN 模型,则可以使用 Wintun 提供虚拟三层接口,再通过路由把流量送入其中。
可以把两者的抽象路径画成:
Linux: Application → Linux kernel / Netfilter → Transparent proxy
Windows: Application → Windows network stack / WFP → Transparent proxy
两套系统的目标相同:让应用无须知道代理的存在;但 Linux 更常见的是“Netfilter 规则 + 路由”,Windows 则更依赖“WFP/过滤驱动 + 虚拟网卡或用户态程序”。TUN 也可以参与透明接管,但它是虚拟三层接口,不等同于 Netfilter 或 WFP 的连接重定向。
可以把三者的职责分开记:路由决定从哪里走,过滤规则决定是否拦截、修改或标记,代理进程负责协议转换以及连接远端。它们组合起来,才构成一套透明代理。
Linux 还提供 Netfilter,在 packet 经过内核网络栈的不同阶段时执行规则。iptables 是传统用户态配置工具,nftables 是更新的规则框架;它们都不是代理本身。
简化的接收路径可以画成:
网卡收到 packet
↓
PREROUTING
↓
路由判断
↙ ↘
INPUT FORWARD
↓
POSTROUTING
本机进程产生的流量通常会经过 OUTPUT,再进入路由和 POSTROUTING。透明代理利用这些钩子修改目的地、标记连接,或把连接重定向到代理监听端口:
Application
↓ 原目标 example.com:443
Kernel OUTPUT / PREROUTING
↓ redirect / tproxy / mark
Transparent proxy
↓
Remote destination
透明代理的“透明”是对应用透明,不是对内核透明。内核仍然执行了明确的规则。常见机制有三种:
REDIRECT:把连接改送到本机某个端口,简单但可能丢失原始目的地址信息。TPROXY:保留原始目标地址,并配合策略路由把连接交给代理,适合更精确的透明接管。mark:给 packet 或连接打标记,让后续策略路由选择专门的路由表。
实际配置还要考虑回环流量、代理进程自身流量、局域网网段、IPv6、UDP 和已建立连接。规则写得过于宽泛,最容易造成代理递归、局域网不可达或 DNS 异常。
7. 四种“代理”不要混为一谈
| 机制 | 工作层次 | 谁需要知道代理 | 常见覆盖范围 |
|---|---|---|---|
| HTTP Proxy | 应用层 | HTTP 客户端 | HTTP / HTTPS,以及 CONNECT 隧道 |
| SOCKS5 | 会话层附近 | 支持 SOCKS 的客户端 | TCP;协议支持 UDP,但实现未必支持 |
| Transparent Proxy | 内核规则 + 用户态代理 | 应用通常不需要知道 | 被规则匹配的连接 |
| VPN / TUN | 虚拟三层接口 | 应用不需要知道 | 由路由决定的 IP 流量 |
Transparent Proxy 更像一组接管机制,而不是一种具体协议。它可能在 TCP 建连阶段把流量交给用户态代理,也可能结合特殊的 UDP 处理。VPN / TUN 则从 IP 路由层接住流量,天然更适合覆盖不支持代理的程序,但也需要处理 MTU、路由递归、DNS 和 IPv6 等问题。
HTTP Proxy 与 SOCKS5 的区别
HTTP Proxy 和 SOCKS5 经常同时出现在代理客户端的配置中,但它们承担的职责不同。HTTP Proxy 理解 HTTP 协议;SOCKS5 则只负责建立连接和转发数据,不理解上层协议。
HTTP Proxy 的典型流程是:
Browser
↓ HTTP 请求 / CONNECT
HTTP Proxy
↓
Internet
访问普通 HTTP 网站时,客户端可以直接把 HTTP 请求交给代理;访问 HTTPS 时,客户端通常先发送 CONNECT example.com:443,让代理建立一条到目标服务器的 TCP 隧道,之后代理只转发加密字节。建立隧道后,普通 HTTP Proxy 通常看不到 HTTPS 内部的 URL、header 和 body;只有额外部署受信任证书和 TLS 中间人解密时,代理才可能读取这些内容。
SOCKS5 的流程更接近通用的连接转发:
Application
↓ SOCKS5 握手:目标地址 + 端口
SOCKS5 Proxy
↓ 原样转发 TCP / UDP
Internet
因此,SOCKS5 不关心流量是 HTTP、HTTPS、SSH 还是数据库协议,更适合支持多种 TCP 流量的程序;但应用本身必须支持 SOCKS5,或者由 TUN、透明代理等机制代为接管。SOCKS5 协议定义了 UDP ASSOCIATE,但具体代理软件、客户端和网络环境未必支持 UDP;QUIC/HTTP/3 使用 UDP,因此不能默认认为 SOCKS5 能代理所有 QUIC 流量。HTTP Proxy 本身也不提供加密,SOCKS5 同样不是 VPN;连接的安全性通常来自 HTTPS、SSH 或代理软件建立的额外加密隧道。
两者可以这样对比:
| 对比 | HTTP Proxy | SOCKS5 |
|---|---|---|
| 工作层次 | 应用层 | 会话 / 连接转发层 |
| 是否理解 HTTP | 是 | 否 |
| HTTPS | 通常通过 CONNECT 建立隧道 | 直接转发 TCP |
| 支持范围 | 主要是 HTTP / HTTPS | TCP,也可支持 UDP |
| 常见用途 | 浏览器、包管理器、HTTP 客户端 | 浏览器、游戏、SSH、数据库客户端 |
| 是否自动加密 | 否 | 否 |
DNS 解析位置也可能不同。使用 SOCKS5 时,socks5-hostname 通常表示由代理端解析域名;如果先在本地解析,再把 IP 交给代理,就可能产生 DNS 泄漏。HTTP Proxy 也需要根据客户端和代理的实现,确认域名是在本地解析还是由代理处理。
8. Windows 与 Linux 的对应关系
可以用下面的方式建立一个粗略但实用的对照:
| 目标 | Windows 常见机制 | Linux 常见机制 |
|---|---|---|
| 应用主动使用代理 | WinINet / WinHTTP 代理配置 | 环境变量、应用配置、库自身设置 |
| 本机代理入口 | 127.0.0.1 / localhost | 127.0.0.1 / lo |
| 虚拟三层接口 | Wintun 等虚拟网卡 | /dev/net/tun、tun0 |
| 选择出口 | 路由表、接口 metric、策略路由 | ip route、ip rule、多路由表 |
| 内核级拦截 | WFP 等过滤平台 | Netfilter、nftables、iptables |
| 透明接管 | 驱动或过滤平台配合用户态程序 | REDIRECT、TPROXY、mark |
两套系统的名字和 API 不同,但抽象是相同的:应用创建 socket,内核根据路由和过滤规则处理 packet,最终交给物理接口、虚拟接口或本机监听者。
9. 用正确的问题排查代理故障
遇到“某程序不能联网”时,可以按流量实际经过的层次排查:
- 程序是否支持并启用了 HTTP / SOCKS 代理?不要假设它会读取系统代理。
- 代理是否真的监听在预期地址和端口?检查
127.0.0.1、IPv6::1以及监听范围。 - 如果是 UWP 应用,是否被 Windows Loopback 限制拦截?
- 如果使用 TUN,虚拟接口是否存在,路由是否把目标流量送进去?
- 代理进程访问远端服务器时,是否被再次送回 TUN 或透明代理规则?
- 故障属于 TCP、UDP、DNS、IPv4 还是 IPv6?“网页能打开”只证明了某一种流量成功。
Linux 上常用的观察工具包括:
ss -lntup # 查看监听端口
ip addr # 查看接口和地址
ip route get 1.1.1.1
ip rule # 查看策略路由
tcpdump -ni any # 观察 packet 经过哪些接口
Windows 上可以使用 netstat、PowerShell 的 Get-NetTCPConnection、Get-NetIPConfiguration、route print,以及 Wireshark / pktmon 观察连接和 packet。排障时最好先确定“连接有没有到达代理端口”,再判断“代理能不能连接上游”,最后才检查 TLS、认证和应用协议。
回到整体:一张网络心智模型
现在把前面拆开的概念重新串起来,可以得到开头那条主线的具体版本:
应用是否主动使用代理?
│
┌────┴────┐
│ │
是 否
│ │
System TUN / transparent proxy
Proxy │
│ 内核路由与过滤规则
↓ │
Loopback ↓
│ tun0 / redirect / TPROXY
└────┬────┘
↓
本机代理进程
↓
远端代理 / VPN / 真实网络
最重要的不是记住某个工具的选项,而是分清三个问题:
- 应用是否知道代理? 这是 System Proxy、HTTP Proxy 和 SOCKS 的问题。
- 内核把 packet 送到哪里? 这是接口、路由和策略路由的问题。
- 谁在内核路径上修改或接管了 packet? 这是 Netfilter、WFP、透明代理和 TUN 用户态程序的问题。
浏览器通过系统代理访问网页,说明应用层协作成功;游戏通过 TUN 访问网络,说明内核路径被接管;UWP 应用无法连接本机代理,则可能只是 Loopback 权限问题。看起来都是“代理不能用”,实际上发生在完全不同的层次。
理解这条边界之后,Windows 的 UWP Loopback、Linux 的 tun0、iptables/nftables、VPN、Docker bridge 乃至 Kubernetes 的网络插件,就不再是互不相关的术语,而是同一套网络栈在不同位置提供的能力。
参考资料
- Interprocess communication — UWP applications:Windows packaged application 的 loopback 限制与豁免机制。
- About Windows Filtering Platform:WFP 的网络栈 hook、过滤层和 callout 机制。
- Universal TUN/TAP device driver:Linux TUN/TAP 设备与用户态程序之间的 packet 收发模型。
- RFC 1928 — SOCKS Protocol Version 5:SOCKS5 的连接建立与 UDP ASSOCIATE。
- RFC 9110 — HTTP Semantics:HTTP
CONNECT方法和隧道语义。