面向已能正常连接代理、想优化域名解析质量的用户。读完能独立写出带境内境外分流的 dns 段,理解 expectIPs 的校验语义,并对应到 v2rayN 的参数设置项。
DNS 分流要解决的两个问题
国内网络环境下直接查询境外域名,应答经常被污染:返回的 IP 不属于目标站点,连接表现为超时或落到错误页面。加密远程解析把查询包进 TLS 通道,污染源无法篡改应答内容,这是 DoH 在分流中的核心作用。
境内域名则相反。走远程解析虽然也能拿到结果,但查询链路多一跳代理,且部分国内 CDN 会按解析来源返回不同节点,远程解析容易拿到跨区节点。境内域名交给本地 DNS,就近解析,CDN 调度更准。
| 对比维度 | 本地 DNS | 远程 DoH |
|---|---|---|
| 查询链路 | 直连运营商或公共 DNS | 经代理出站加密查询 |
| 适用域名 | geosite:cn 境内域名 | geosite:geolocation-!cn 境外域名 |
| 防污染能力 | 弱,明文查询 | 强,TLS 内不可篡改 |
| 延迟表现 | 低,就近解析 | 较高,多一跳代理 |
分流的目标不是把查询机械拆开,而是让两类域名各走各的解析通道,同时保证 routing 规则与 dns 段使用同一套域名集合。
dns 段的基础结构与分流写法
Xray 的 dns 段是一个 servers 数组,按顺序匹配:域名命中某条目的 domains 列表就使用该条目;不带 domains 的条目匹配所有域名,放在最后做兜底。把下面这段放到配置根节点即可。
"dns": {
"servers": [
{
"address": "https://1.1.1.1/dns-query",
"domains": ["geosite:geolocation-!cn"],
"tag": "proxy"
},
{
"address": "223.5.5.5",
"domains": ["geosite:cn"],
"expectIPs": ["geoip:cn"]
},
"223.5.5.5"
]
}
第一条管境外,查询经代理出站发出;第二条管境内,用 expectIPs 校验应答归属;第三条是裸地址兜底,覆盖 geosite 数据未收录的域名。v2rayN 生成的配置中,代理出站 tag 为 proxy,直连为 direct,引用时保持一致。代理服务器地址建议直接填 IP,减少引导解析环节。
本地 DNS
- 地址
- 223.5.5.5 或 119.29.29.29
- 匹配
- geosite:cn
- 校验
- expectIPs: geoip:cn
- 出站
- direct
境内域名就近解析,CDN 调度准确。
远程 DoH
- 地址
- https://1.1.1.1/dns-query
- 匹配
- geosite:geolocation-!cn
- 出站
- tag: proxy
- 校验
- 可选 geoip:!cn
查询经代理发出,应答不可被污染。
有固定解析需求的域名可以写进 dns.hosts,它的优先级高于 servers 数组,查询不会外发。内网主机名、自建服务域名适合放在这里。
routing 规则与 domainStrategy 的配合
dns 段决定域名由谁解析,routing 决定连接走哪条出站。只配 dns 段不配 routing,流量仍可能全走代理;只配 routing 不配 dns,境内域名也会被远程解析污染。两者必须成对出现。
"routing": {
"domainStrategy": "IPIfNonMatch",
"rules": [
{
"type": "field",
"domain": ["geosite:cn"],
"outboundTag": "direct"
},
{
"type": "field",
"domain": ["geosite:geolocation-!cn"],
"outboundTag": "proxy"
}
]
}
domainStrategy 三种取值的适用场景
- AsIs:只用域名字符串匹配规则,不主动解析,适合规则全部按域名书写、不依赖 IP 规则的场景。
- IPIfNonMatch:域名规则未命中时再解析域名并尝试 IP 规则,是分流场景的常用值。
- IPOnDemand:只要规则里出现 IP 条件就解析,DNS 请求更频繁,一般不需要。
结论:让 dns 段与 routing 共用同一套域名集合
geosite:cn 在两侧同时出现,境外侧用 geosite:geolocation-!cn 取补集,中间不留空白,否则会出现解析走 DoH、连接走直连的错位。
expectIPs 的防污染语义与验证方法
expectIPs 不是路由规则,它只校验解析结果:结果不在给定 geoip 列表内就丢弃,并按顺序尝试下一个服务器。境内条目最常用的写法是 expectIPs: ["geoip:cn"],确保本地 DNS 只接受境内 IP。
{
"address": "223.5.5.5",
"domains": ["geosite:cn"],
"expectIPs": ["geoip:cn", "geoip:private"]
}
expectIPs 支持取反写法,境外条目可以加 geoip:!cn,拒绝解析到国内 CDN 节点的结果。若希望校验失败直接报错而不是回退,可在条目上加 skipFallback: true。geoip:private 放行内网地址段,避免内网域名被误判丢弃。
验证分流是否生效
- 设置 → 参数设置 → 基础设置,把日志级别调到 debug,重新连接节点。
- 访问一个境外站点,在日志里确认该域名由第一条 DoH 解析,查询经代理发出。
- 访问一个境内站点,确认查询落到 223.5.5.5,且应答通过 geoip:cn 校验。
- 命令行执行
nslookup www.qq.com 223.5.5.5,确认本地 DNS 本身可用。
结论:expectIPs 是校验器,不是路由器
它只丢弃不合格的解析结果,不改变流量走向;流量走哪条出站由 routing 规则决定,不要指望 expectIPs 替你做分流。
常见问题与排查
配置分流后遇到问题,按下面四条顺序排查。
先看日志
v2rayN 的日志窗口会打印每条 DNS 查询的服务器 tag 与结果,把日志级别调到 debug 后,访问一个境外站点,观察查询是否落在远程 DoH 条目上;再访问一个境内站点,观察查询是否落在本地解析条目上。如果两个方向都落在同一条目,说明 dns 段的 domains 匹配顺序有问题,把更具体的域名集合放在数组前面。
更新 geosite 与 geoip 数据文件
Xray 内核启动时会加载本地的 geosite.dat 与 geoip.dat,这两个文件需要定期更新,否则新注册的域名不在 geosite:cn 里,会被当成境外域名走远程解析,表现为国内网站变慢。v2rayN 在「设置」→「路由设置」里提供更新按钮,更新后重启客户端再验证。
确认出站标签与 dns 段一致
dns 段里写的是 outboundTag: proxy,routing 里就必须存在一个 tag 为 proxy 的出站;如果出站标签写错,查询会回退到默认解析,表现为 DoH 条目从未被命中。检查 config.json 时先数一遍出站列表里的 tag,再对照 dns 段逐一核对。
留意系统 DNS 缓存
Windows 的 DNS 客户端会缓存解析结果,修改配置后立即测试可能命中旧缓存。执行 ipconfig /flushdns 清空缓存,再重新连接节点验证。macOS 与 Linux 也有各自的缓存清理命令,清缓存后仍异常再考虑重启客户端。
开启分流后国内网站反而变慢?
先看日志确认查询命中了哪台服务器。常见原因是 geosite:cn 数据过旧,新域名没被收录,走了远程 DoH。更新 geosite 与 geoip 数据文件,或把该域名写进 dns.hosts 固定走本地解析。
远程 DoH 一直超时?
确认 DoH 条目的 tag 指向代理出站,v2rayN 里对应勾选「远程DNS走代理」。1.1.1.1 直连不可达时,把地址换成 https://dns.google/dns-query 或 https://8.8.8.8/dns-query。
境外域名解析到的 IP 仍是污染地址?
该域名很可能不在 geosite:geolocation-!cn 覆盖范围内。检查 dns 段第一条的 domains 与 routing 的境外规则是否使用同一域名集合,再把日志级别调到 debug,确认查询确实落在 DoH 条目上。
手改 config.json 后一选节点就失效?
v2rayN 切换服务器时会按内置模板重新生成配置,手改的 dns 段会被覆盖。分流设置请在「设置」→「参数设置」→「DNS设置」里完成,不要直接编辑生成的配置文件。