添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
🍥

SSpiritsの秘密基地

わたし、気になります!

Featured image of post 巧用 DNS 实现国内外域名 ip 分流上网

巧用 DNS 实现国内外域名 ip 分流上网

这篇文章记录了对几种分流上网方案(iptables、OSPF、DNS 等)的尝试与优劣比较,文中会详细介绍博主目前使用的基于 DNS 的分流方案的原理

visitors

这篇文章记录了对几种分流上网方案(iptables、OSPF、DNS 等)的尝试与优劣比较,文中会详细介绍博主目前使用的基于 DNS 的分流方案的原理与配置教程

前言

本文适合使用软路由做透明代理的同学阅读,并且需要有一定的网络基础知识。如果你是一个小白那么直接跳到 极简配置 部分照着操作即可

博主尝试过如下几种思路实现策略路由(PBR, Policy Based Routing

  1. iptables 给链接打标
  2. OSPF 等路由协议
  3. Clash、V2ray 等代理工具
  4. DNS 分流

前两者的思路类似,都是使用中国 ip 白名单来将国外 ip 转发到旁路由等透明代理设备上。但是无论是 iptables 还是 OSPF 配置都非常复杂,特别是 OSPF 等路由协议科班出身的人都不一定玩得转。我们配置家庭网络追求的是简单好用,使用这样复杂的方案前期调试以及后期更新 ip 列表都很不方便

使用代理工具的分流功能做策略路由简单实用,Clash、V2ray 等客户端都会有开箱即用的配置提供。但是缺点也很明显:所有的流量都会经过代理程序,无法做到分设备代理,对于有有 BT、PCDN 等需求只想部分设备走代理的同学不太适用

使用 DNS 分流方案拥有 iptables 和 OSPF 做策略路由的丰富功能,并且兼具使用代理工具分流配置简单的优点

  1. 丰富的分流策略:可以按国内外 ip 分流也可以按域名分流
  2. 配置简单:最简单的使用方法只需修改 Clash 的配置即可
  3. 去广告:可以阻断广告域名的 DNS 解析来禁止广告加载
  4. 分设备代理:对需要代理的设备使用分流 DNS 转发到代理服务器,其他设备使用上游公共 DNS 直连出公网

但是这个方案也有缺点,对于直接使用 ip 的软件就无能为力了。当然这种情况非常罕见(目前博主只发现 Telegram),而且只需额外添加一条静态路由即可解决

什么?你问我 DNS 是啥玩意?那我建议你 关掉本文 ,或者阅读这篇文章: 详解 DNS 与 CoreDNS 的实现原理

网络架构

需要两个额外组件(极简配置下这两个组件合二为一):

  1. 做透明代理的软路由,可以是主路由也可以是旁路由
  2. 分流 DNS

原理其实很简单:分流 DNS 劫持 DNS 请求,需要走代理的域名返回透明代理 ip,无需走代理的域名直接返回真实 ip

flowchart BT DNS[(分流 DNS)] -->|国内直连| UpDNS DNS -->|国外走代理| Proxy --> 代理服务器 UpDNS[上游公共 DNS] -->|直接出公网| Internet Internet[互联网] Proxy[(透明代理)] Desktop(电脑) -->|分流| DNS Phone(手机) -->|分流| DNS BT(BT 下载机) -->|全局直连| UpDNS IOT(智能家居设备) -->|全局直连| UpDNS

DNS 分流配置

极简配置

使用 fake-ip 模式的 Clash 既作为透明代理又作为 DNS Server,这种方式配置非常简单,只需要一个能运行 Clash 的设备即可

首先你需要部署好 Clash(请自行寻找教程,作为主路由、旁路由都可以,使用虚拟机、docker、lxc 没限制) 然后修改如下配置:

dns:
  enable: true
  // 开启 fake-ip 模式
  enhanced-mode: fake-ip
  // 选择保留 ip 段,一般保持默认即可
  fake-ip-range: 198.18.0.1/16
  // 指定 Clash DNS 监听地址
  listen: 0.0.0.0:53
  // 指定上游公共 DNS
  nameserver:
  - 223.5.5.5:53
  // 添加需要直连的国内域名
  fake-ip-filter:
  - baidu.com
  - ...
tun:
  enable: true
  stack: system
  // 自动为 fake-ip-range 中的 ip 段添加路由
  auto-route: true

这个配置做了三件事

  1. 开启 dns 服务并指定为 fake-ip 模式,监听 53 端口
  2. 对于 fake-ip-filter 中的国内域名直接返回真实 ip,这些域名的流量不再经过代理
  3. 开启 tun 模式并自动添加路由,将发往 fake-ip 的请求交给 clash 处理

最关键的是需要将常见国内域名加入到 fake-ip-filter 中,这里推荐一个每日更新国内域名的项目: felixonmars/dnsmasq-china-list

你可以自行下载 accelerated-domains.china.conf 文件并为其中的域名加上 +. 前缀然后添加到 fake-ip-filter 中。如果你恰好使用 openclash 可以用博主的脚本,可以自动下载国内域名列表并写入 openclash 的配置文件中

rm -f accelerated-domains.china.conf
wget https://raw.githubusercontent.com/felixonmars/dnsmasq-china-list/master/accelerated-domains.china.conf -O /root/accelerated-domains.china.conf
echo '
*.lan
*.localdomain
*.example
*.invalid
*.localhost
*.test
*.local
*.home.arpa
#放行NTP服务
time.*.com
time.*.gov
time.*.edu.cn
time.*.apple.com
ntp.*.com
*.time.edu.cn
*.ntp.org.cn
+.pool.ntp.org
time1.cloud.tencent.com
' > /etc/openclash/custom/openclash_custom_fake_filter.list
awk -F / '{print "+."$2}' /root/accelerated-domains.china.conf >> /etc/openclash/custom/openclash_custom_fake_filter.list
echo fake-ip-filter: > /tmp/openclash_fake_filter.list
awk '{print "  - '\''"$1"'\''"}' /etc/openclash/custom/openclash_custom_fake_filter.list >> /tmp/openclash_fake_filter.list

看到这里恭喜你全部配置已经完成,是不是很简单?接下来将需要走代理的设备 DNS 改为 Clash DNS 的地址即可享受分流上网

如果你的 clash 运行在旁路由上,还需要在主路由的路由表中添加一项,将 fake-ip 指向旁路由

# 198.18.0.1/16 是 fake-ip-range 配置的 ip 段
# 192.168.2.254 是旁路由 ip
route add -net 198.18.0.1/16 gw 192.168.2.254

除非你熟悉 linux 网络配置,否则尽量使用原生 clash 而不是 openclash 之类的周边项目,它们往往会添加 iptables 规则将经过本机的连接都转发到 clash

在运行 clash 的服务器上使用 mtr 或 traceroute 来验证分流策略是否生效:如果 mtr 的结果显示无需代理的域名不止一跳并且没有经过 fake-ip-range 的 ip 段则分流配置正确;也可以观察 Clash 控制台,看看是否有无需走代理域名连上来

# 配置有误
root@OpenWrt:~# mtr -r --tcp www.baidu.com
Start: 2022-06-09T21:37:36+0800
HOST: OpenWrt                              Loss%   Snt   Last   Avg  Best  Wrst StDev
  1.|-- 198.18.0.19(fake-ip)                0.0%    10    0.2   0.1   0.1   0.2   0.0
# 配置正确
root@OpenWrt:~# mtr -r --tcp ntp.aliyun.com
Start: 2022-06-09T21:40:51+0800
HOST: OpenWrt                     Loss%   Snt   Last   Avg  Best  Wrst StDev
  1.|-- <主路由 ip>                 0.0%    10    0.1   0.1   0.1   0.2   0.0
  2.|-- <公网出口 ip>              10.0%    10    6.0   5.2   3.1   9.5   1.9
  3.|-- 117.49.47.202              0.0%    10    4.1   5.0   4.0   6.5   1.0
  4.|-- 116.251.94.198             0.0%    10   10.0  11.0  10.0  13.0   1.0
  5.|-- ???                       100.0    10    0.0   0.0   0.0   0.0   0.0
  6.|-- ???                       100.0    10    0.0   0.0   0.0   0.0   0.0
  7.|-- ???                       100.0    10    0.0   0.0   0.0   0.0   0.0
  8.|-- 203.107.6.88               0.0%    10   24.7  24.7  24.4  26.2   0.5

精准分流配置

使用 Clash DNS 的方案虽然配置非常简单,但是毕竟不可能将所有国内域名都统计出来,还需要根据 ip 进行更精准的分流

flowchart BT DNS[分流 DNS] -->|国内 ip| UpDNS DNS -->|国内域名| UpDNS DNS -->|国外 ip| ClashDNS DNS -->|GFW 黑名单域名| ClashDNS ClashDNS[Clash DNS] --> UpDNS UpDNS[上游公共 DNS]

多数系统不支持指定 DNS 端口,所以分流 DNS 和 Clash DNS 最好分配不同的 ip(可以在单网卡上分配多个内网 ip)

博主选用 IrineSistiana/mosdns-cn 作为分流 DNS,这里引用 mosdns-cn 官方文档上介绍的分流规则

分流模式
mosdns-cn 会根据用户提供的数据采用以下分流模式。

配置了 –local-ip 本地 IP

  1. 如果请求的域名匹配到 –local-domain 本地域名。则直接使用 –local-upstream 本地上游。结束。
  2. 如果请求的域名匹配到 –remote-domain 远程域名。则直接使用–remote-upstream 远程上游。结束。
  3. 非 A/AAAA 类型的请求将直接使用 –local-upstream 本地上游。结束。
  4. 同时转发至本地和远程上游获取应答。
  5. 如果本地上游的应答包含 –local-ip 本地 IP。则直接采用本地上游的结果。结束。
  6. 否则采用远程上游的结果。结束。

只配置了 –local-domain 本地域名

  1. 如果请求的域名匹配到 –local-domain 本地域名。则直接使用 –local-upstream 本地上游。结束。
  2. 其他所有请求会使用 –remote-upstream 远程上游。结束。

只配置了 –remote-domain 远程域名

  1. 如果请求的域名匹配到 –remote-domain 远程域名。则直接使用–remote-upstream 远程上游。结束。
  2. 其他所有请求会使用 –local-upstream 本地上游。结束。

Github 上有详细使用教程,这里给出博主使用的启动脚本,每次启动时拉取最新的国内外域名/ip 数据

RELEASE_URL=$(curl -s https://api.github.com/repos/Loyalsoldier/v2ray-rules-dat/releases/latest | grep browser_download_url)
GEOSITE_URL=$(echo "$RELEASE_URL" | grep geosite.dat\" | cut -d'"' -f4)
GEOIP_URL=$(echo "$RELEASE_URL" | grep geoip.dat\" | cut -d'"' -f4)
if [ -z $GEOSITE_URL ];
  echo "GEOSITE_URL required!"
  exit 1
if [ -z $GEOIP_URL ];
  echo "GEOIP_URL required!"
  exit 1
echo $GEOSITE_URL
echo $GEOIP_URL
wget $GEOSITE_URL -O geosite.dat
wget $GEOIP_URL -O geoip.dat
mosdns-cn -s :53 --blacklist-domain "geosite.dat:category-ads-all" --local-upstream 223.5.5.5:53 --local-domain "geosite.dat:cn" --local-ip "geoip.dat:cn" --remote-upstream https://8.8.8.8/dns-query --remote-domain "geosite.dat:geolocation-!cn"

去广告/DNS 解析统计配置

mos-dns 支持配置黑名单域名直接给出空响应,可以使用这一机制阻断广告域名的访问: mosdns-cn --blacklist-domain "geosite.dat:category-ads-all"

但是目前少有大佬分享适配 mosdns-cn 的去广告规则,这种专业的事情还是交给 Adguard Home 来做:

flowchart BT DNS[分流 DNS] -->|国内 ip| AdguardHome DNS -->|国内域名| AdguardHome DNS -->|国外 ip| ClashDNS DNS -->|GFW 黑名单域名| ClashDNS ClashDNS[Clash DNS] --> AdguardHome AdguardHome[Adguard Home] --> UpDNS UpDNS[上游公共 DNS]

将 Adguard Home 放在 mosdns-cn 和 Clash DNS 的上游还有其他好处,可以借助它的仪表盘和日志分析出整个网络访问的网站

Adguard Home 的部署教程网上有很多,能看到这里的人肯定也不用我赘述了。这里推荐一个博主自用的过滤规则,有了它就不需要其他规则了: BlueSkyXN/AdGuardHomeRules

其他配置

自动设置设备的 DNS 服务器

极简配置 中博主提到 将需要走代理的设备 DNS 改为分流 DNS ,这一步可以手动改也可以借助 DHCP 自动配置:DHCP Option 6 的作用就是指定客户端使用的 DNS,在 Openwrt LAN 接口的高级设置中即可找到该设置

为直接使用 IP 的 APP 设置路由

直接使用 ip 的软件没有经过 DNS 自然就无法获取到 Clash 的 fake-ip,对于这种情况需要在主路由上添加静态路由将这些软件使用的 ip 的下一跳路由改为 Clash 的 fake-ip

目前我只发现 Telegram 存在这种情况,需要添加的路由如下:

# 192.18.1.254 是 fake-ip,可以从 fake-ip-range 中随便选择一个
route add -net 91.108.4.0/22 gw 192.18.1.254
route add -net 91.108.8.0/22 gw 192.18.1.254
route add -net 91.108.12.0/22 gw 192.18.1.254
route add -net 91.108.16.0/22 gw 192.18.1.254
route add -net 91.108.56.0/22 gw 192.18.1.254
route add -net 149.154.160.0/20 gw 192.18.1.254
Clash
MosDNS
策略路由
Licensed under CC BY-NC-SA 4.0 转载或引用本文时请遵守许可协议,知会作者并注明出处不得用于商业用途!
Last updated on Sep 02, 2022 02:13