Skip to main content
  1. Posts/

开公司 VPN 后 ChatGPT 无法访问:一场 DNS 归属与透明代理的冲突

·1870 words·4 mins
Table of Contents
Note: This article is available in Chinese only. 本文暂无英文版本。 View original

起因
#

最近在家办公,需要连公司 VPN(UniVPN)进内网。但一连上 VPN,浏览器里的 chatgpt.com 就直接打不开了。

看起来很像「VPN 把网络搞坏了」。以前遇到这种情况,可能就忍忍,查资料时关掉,进内网时再打开。但来回切实在太难受了,于是决定查一查到底哪里冲突了。

现象
#

连上 UniVPN 后,访问 chatgpt.com 会跳拦截页面:“Unable to load site / Please try again later…"。页面下方标着一行:[IP: <一台香港 VPS 的 IP> | Ray ID: ...]。 这台香港 VPS 正是我自己的节点。关掉 VPN,刷新页面,又能正常访问了。

这很容易把思路带偏:连着 VPN 测出口,显示的也是香港 VPS 的 IP。说明从本地到代理的链路是通的。 但问题在于,香港机房的 IP 对 ChatGPT 来说是非法的(会被风控)。我原本在路由器的透明代理上配了专门的规则,让 chatgpt.com 走解锁节点,绝不走香港节点。 现在一开 VPN,AI 域名又开始走香港节点了。说明路由器上的分流规则彻底失效,流量漏到了默认节点。

排查
#

既然外网是通的,TLS、TCP 连通性和隧道本身都没问题。公司 DNS 也能正常解析内网域名。

往下看网卡配置:

1Get-NetIPInterface -AddressFamily IPv4 | Select-Object InterfaceAlias, InterfaceMetric
2Get-DnsClientServerAddress -AddressFamily IPv4 | Select-Object InterfaceAlias, ServerAddresses

发现 UniVPN 建了个 TAP 网卡,IPv4 metric 强制设成了 1,绑定的 DNS 是 <公司DNS>。 相比之下,家里 WLAN 的 metric 只有 35,DNS 是路由器 192.168.2.1

metric 越小优先级越高。UniVPN 把自己压到 1,意思是强行接管全局默认路由,所有的 DNS 查询都会往公司 DNS 发。

我一开始想暴力改 metric,把它改到 100。结果 UniVPN 有后台进程盯着,刚改完几秒钟就刷回 1。后来甚至写了个计划任务每 3 分钟强行改一次,但这属于猫鼠游戏,网络会一直抖动。跟企业 VPN 客户端硬刚写死的逻辑是不靠谱的。

根因
#

为什么 DNS 发给公司,会破坏透明代理的分流?

我家的透明代理跑在 192.168.2.1 上,用的是 fake-ip 机制(198.18.0.0/16)。

正常不开 VPN 时:

  1. 电脑解析 chatgpt.com,去问路由器。
  2. 路由器不查公网,直接丢回来一个假 IP(比如 198.18.0.28)。
  3. 电脑向 198.18.0.28 建 TCP 连接。
  4. 路由器收到流量,反查内部映射,知道这是要去 chatgpt.com,于是匹配到 AI 域名解锁规则,转发给专用节点。

开启 VPN 后:

  1. TAP 网卡 metric 为 1。电脑不问路由器了,直接把 chatgpt.com 丢给 <公司DNS> 解析。
  2. 公司 DNS 老老实实去公网查到了真实的 IP(比如 104.18.x.x)并返回。
  3. 电脑直接向这个真实公网 IP 发起连接。
  4. 因为是真实 IP,这股流量没有命中 fake-ip 网段,直接绕过了透明代理的核心分流。
  5. 路由器底层收到未知的 TCP 流量,无法识别域名,只能走 fallback 逻辑,扔进默认的全局代理——也就是那台香港 VPS。
  6. 最后,去 ChatGPT 的流量阴差阳错从香港出去了,被 OpenAI 拦截。

说白了:在基于 fake-ip 的透明代理架构中,DNS 的归属决定了流量走向。一旦 VPN 抢占了 DNS 解析权,依赖 fake-ip 的代理链路就断了。

修复
#

既然不能抢 metric,就在 DNS 解析层面做分流。Windows 下可以用 NRPT (Name Resolution Policy Table)。 它能在不改变网卡优先级的前提下,强制规定某些域名去哪里查 DNS。

思路很简单:内网域名走公司 DNS,其他域名滚回本地路由器。

管理员权限跑 PowerShell:

 1# 1) 内网域名强制走公司 DNS
 2Add-DnsClientNrptRule -Namespace "<公司内网域名>" -NameServers "<公司DNS>" -DisplayName "UniVPN internal"
 3
 4# 2) 其他所有域名走家里路由器(恢复 fake-ip)
 5Add-DnsClientNrptRule -Namespace "." -NameServers "192.168.2.1" -DisplayName "All other DNS via router"
 6
 7# 3) 关掉「智能多网卡名字解析」,防止 Windows 乱发 DNS 请求
 8$p = "HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\DNSClient"
 9New-Item -Path $p -Force | Out-Null
10New-ItemProperty -Path $p -Name DisableSmartNameResolution -PropertyType DWord -Value 1 -Force
11
12# 4) 清缓存
13ipconfig /flushdns

完事后,我把那个每 3 分钟改 metric 的计划任务也删了。

验证
#

开着 VPN,TAP metric 依然是 1。

看下 NRPT 规则:

1Get-DnsClientNrptRule

查外网域名:

1Resolve-DnsName chatgpt.com

返回 198.18.0.28,标准的 fake-ip,说明查询交给了路由器。

查内网:

1Resolve-DnsName <内网主机>

返回 <内网主机IP>,内网也通。

浏览器打开 chatgpt.com,页面秒开。

顺带一提,验证连通性尽量用浏览器。如果用 curl 去测,会因为没有浏览器指纹被 Cloudflare 直接 403 挡掉,容易误判。

注意事项
#

  1. 换网络要删规则:上面的 catch-all 写死了 192.168.2.1。如果你带电脑去了公司,发现没网了,记得先把这条规则删掉:
    1Get-DnsClientNrptRule | Where-Object { ($_.Namespace -join ",") -eq "." } | Remove-DnsClientNrptRule -Force
  2. 公司如果换了内网 DNS 地址,也要记得同步改 <公司内网域名> 的规则。
  3. NRPT 只管 DNS 去哪问,不管路由表和实际流量怎么走。

结论
#

一开始以为是 VPN 把网络搞断了,最后发现只是抢了 DNS 的解析权。

直连和代理冲突时,先查当前域名到底是由谁在解析,往往是最具性价比的排查手段。

碰到强行修改配置的 VPN 客户端,在操作系统的网络栈里用 NRPT 做域名级分流,比写死循环脚本改 metric 靠谱得多。

Related

从进程视角重新理解 Docker

·3840 words·8 mins
起因 # 第一次接触 Docker 是 2017 年,在深圳网警机房驻场做审核项目。机房完全没有外网,模型、依赖、运行环境全靠 U 盘拷贝 docker image 来传输。后来做模型转换系统,再到量化行业负责机器学习平台,和 Docker、K8s 打了不少交道。但距离上一次系统梳理 namespace、cgroup 这些底层机制,已经过去好几年了。

redis学习笔记

·1290 words·3 mins
最近在做一个智能算力的项目,其中需要用到redis维护某个全局的时间窗口