为了实现全屋代理,我选择 R4S 作为我家庭网络中的主路由,Linksys MX5300 作为二级路由,代理方案使用 OpenClash 插件。由于整套环境存在些许问题,所以利用周末的时间,改造下上网环境。
当上网稳定的情况下,我一般是很少再动了。毕竟如果一旦出现问题,会导致家庭网络瘫痪从而使家中所有智能设备全部掉线,如果设备支持自动连接还好,但是不支持自动连接的问题就大了。 另外如果导致软路由断网,那基本上可以宣告 Game Over 了。
既然如此,为什么还要冒着断网的风险去重新配网呢?而且还是在身居外地的情况下,究其原因无非以下几点:
由于存在以上四点主要问题,所以就不得不优化一下网络了。
前两种问题是最好解决的,但是也比较麻烦。之所以好解决,是因为将硬路由的上网模式改为桥接即可。但是桥接可能丧失路由的 Mesh 组网功能,这点需要注意。
前两种问题解决了,但是会迎来另一个棘手的问题。为了保证家庭 wifi 的安全性,我们一般都会进行 MAC 绑定,然后仅允许绑定 MAC 的设备上网。但是桥接之后,这部分功能也丧失了。
软路由能解决吗?当然,而且方案有很多种。可以采用防火墙限制上网设备,但是为了追求简单干脆,我用另外一种也就是 DHCP 分发的手段限制可连接 WIFI 的上网设备。如果 DHCP 不分发 IP,那么 WIFI 自然而然就连不上了。
我们按照下图的步骤,依次打开【网络】->【接口】->【LAN】->【修改】
下划到底部,打开【高级设置】,取消【动态 DHCP】,如图:
取消之后,所有的设备只有进行静态登记之后才能连上 WIFI。我们通过下图:
【网络】->【DHCP/DNS】划到【静态地址分配】,添加 MAC 地址及 IP 即可。
我们知道硬路由有一个功能就是可以实时显示在线设备,而软路由实现此功能需要另外一个插件: 【onliner】
为了避免缺少依赖,一定要下载 all.ipk 版。
目前的代理方案是使用 OpenClash 的 Fake-IP 增强模式,并开启【绕过中国大陆 IP】,这也是我一直以来常用的方式。那这有什么弊端呢? OpenClash 首先要明白的是,该方案存在 DNS 污染吗? 回答这个问题前,我们需要了解 DNS 在 OpenClash 中的应用场景: 解析域名,判断是否命中 IP 类规则 进行直连(DIRECT)时,解析域名与远端连接 作为一个 DNS 调度服务器 通过以上应用分析,要想实现 DNS 污染,需要符合以下几种情况: 域名类规则没有命中 命中 IP 类或 MATCH 规则且直连 例 1 123 Rule: - "GEOIP,US,Proxy" # IP 为美国时走代理 - "MATCH,DIRECT" # 其余请求直连 我们看下以上例子,如果 IP 命中 US,那么走代理,否则走直连。此时如果访问 google.com 由于规则中并没有基于域名的规则,那么就需要进行 DNS 解析,此时就会得到一个经过污染了的保留 IP, 而该保留 IP 并非美国 IP,所以走直连。也就是说以上配置存在 DNS 污染问题。 例 2 123 Rule: - "GEOIP,CN,DIRECT" - "MATCH,Proxy" 以上配置可以避免大部分的污染问题,因为为了保证国内地址的可访问性,一般是很少将国外的域名污染成国内的 IP。但是,如果呢?我们可以在 IP 规则之前加上域名规则: 1234 Rule: - "DOMAIN-SUFFIX,google.com,Proxy" - "GEOIP,CN,DIRECT" - "MATCH,Proxy" 这样一来就可以解决域名污染的问题了。 DNS 解析 OpenClash 提供了 nameserver 及 fallback 来配置 DNS。我们看下具体的流程: 1、从 nameserver 和 fallback 里的 DNS 进行并发请求,并且选取 nameserver 中最先响应的结果作为基准; 2、使用 GEOIP 判断此 IP 的所属区域,如果属于国内(CN)或保留地址则直接响应给客户端; 3、其他情况则把 fallback 中的结果响应给客户端; 我们以例 2 中的规则为例子并以 Fake-IP 模式进行说明: 123 Rule: - "GEOIP,CN,DIRECT" - "MATCH,Proxy" 当客户端发送对 google.com 的请求时,会被 OpenClash 劫持然后返回一个 Fake-IP 并做好与域名的绑定。客户端拿到 Fake-IP 并对其进行请求,该请求再次被 OpenClash 拦截, 并根据绑定关系拿到该 Fake-IP 对应的 google.com。然后根据规则查找,发现没有基于域名的规则,而仅有的 IP 规则并没有 no-resolve 选项。那么就需要对 google.com 进行 DNS 解析。 OpenClash 会对 nameserver 及 fallback 中的 DNS 进行并发请求。由于是对外请求的,那么该 DNS 查询就会被 DNS 服务器主动污染或者运营商劫持。出现这个问题我们一般是更换 DNS 以及 将 fallback 指向 国外 DNS。但是对于运营商提供的 DNS 我们就无能为力了。此时 OpenClash 就会拿到 nameserver、fallback 双方解析出来的 IP。如果该 IP 是国内的,那么就采用该 IP 进行规则判断,如果 该 IP 是国外的,那么就采用 fallback 的结果进行规则判断。如果是直连模式,那么就直接用解析出来的 IP 发送请求;如果是代理模式,就将请求域名发送给代理服务器,由代理 服务器完成 DNS 解析。 通过以上分析,其实我们发现,以上配置其实能够解决绝大部分的污染问题,对于一般的用户也基本够用了。但是如果仔细推敲其实这里是有问题的,Fake-IP 模式下的 OpenClash 对于 DNS 的解析仅仅 用于代理规则判断,如果是直连模式时才会进行实际的请求。那么解析时,由于是 nameserver、fallback 并发请求,如果 nameserver 配置为国内 DNS 时,对于国外域名的请求,国内 DNS 就会有 解析记录,此时就会涉及到隐私安全问题。那么你可能就会想,直接把 nameserver 配置为国外 DNS 不就行了,那么国内域名的解析就有问题了。 另外,对于 Fake-IP,有些客户端就会表现出异样的行为,比如我那台领势路由器就会亮红灯。另一方面,我们希望国内的域名返回真实的 IP,只有需要代理的域名返回 Fake-IP(不要说通过 Fake-IP-Filter 实现)。 对于以上问题,总结一下我们的需求: 1、对于国内的域名走国内 DNS 解析并返回真实 IP。 2、对于国外的域名走国外解析,跳过国内解析过程,避免留下印记。 3、对于国内的请求直接跳过 OpenClash 的处理,一方面加快响应,另一方面避免由于 OpenClash 崩溃导致所有设备断网。 如果你也有以上需求,那么我们可以继续往下看了! MosDNS 为了实现以上目标,我们需要一款 DNS 分流软件,它就是 MosDNS。 我们通过以下命令进行安装,当前版本为 MosDNS v5.1.3: 先升级必要工具: 123 opkg updateopkg install curlopkg update libcur 执行安装脚本: 1 sh -c "$(curl -ksS https://raw.githubusercontent.com/sbwml/luci-app-mosdns/v5/install.sh)" 安装成功之后,你会在【服务】->【MosDNS】找到。然后按照如图所示,关闭转发,打开自定义配置文件: 我们添加以下配置文件: 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217 log: level: info file: "/opt/data/mosdns/mosdns.log" #api: #http: "0.0.0.0:9091"plugins: #--------------------------------------------------------------------# # 缓存 - tag: cache type: cache args: size: 10240 lazy_cache_ttl: 86400 dump_file: /etc/mosdns/cache.dump # 修改 ttl (默认 0 不修改 ttl) - tag: ttl_sequence type: sequence args: - exec: ttl 60-600 - tag: modify_response type: sequence args: - exec: jump ttl_sequence - exec: accept # 有响应终止返回 - tag: has_response type: sequence args: - matches: has_resp exec: goto modify_response #--------------------------------------------------------------------# # 黑名单 加入的域名将屏蔽 DNS 解析 - tag: blocklist type: domain_set args: files: - "/etc/mosdns/rule/blocklist.txt" # PTR 黑名单 加入的域名将阻止 PTR 请求 - tag: local_ptr type: domain_set args: files: - "/etc/mosdns/rule/local-ptr.txt" # 白名单 由本地 DNS 负责解析(如果黑名单命中,则直接拒绝,也就是黑名单具有最高优先级) - tag: whitelist type: domain_set args: files: - "/etc/mosdns/rule/whitelist.txt" # DDNS 名单,加入的域名始终使用 "本地 DNS" 进行解析 - tag: ddnslist type: domain_set args: files: - "/etc/mosdns/rule/ddnslist.txt" # 灰名单 加入的域名将仅使用 "国外DNS服务器" 进行解析 - tag: greylist type: domain_set args: files: - "/etc/mosdns/rule/greylist.txt" #--------------------------------------------------------------------# # 自定义 Hosts 重写 - tag: hosts type: hosts args: files: - "/etc/mosdns/rule/hosts.txt" # 重定向请求的域名 - tag: redirect type: redirect args: files: - "/etc/mosdns/rule/redirect.txt" #--------------------------------------------------------------------# # 国内域名 - tag: geosite_cn type: domain_set args: files: - "/var/mosdns/geosite_cn.txt" # 国外域名 - tag: geosite_no_cn type: domain_set args: files: - "/var/mosdns/geosite_geolocation-!cn.txt" # 国内 IP - tag: geoip_cn type: ip_set args: files: - "/var/mosdns/geoip_cn.txt" #--------------------------------------------------------------------# # 国内 DNS 服务器 - tag: forward_local type: forward args: concurrent: 3 upstreams: - tag: dnsmasq addr: "udp://127.0.0.1" - tag: alidns addr: "https://dns.alidns.com/dns-query" dial_addr: "223.5.5.5" - tag: dnspod addr: "https://doh.pub/dns-query" dial_addr: "1.12.12.12" # 国外 DNS 服务器 - tag: forward_remote type: forward args: concurrent: 1 upstreams: - tag: openClash addr: "udp://127.0.0.1:7874" #--------------------------------------------------------------------# # 本地解析处理 - tag: local_resolve_sequence type: sequence args: - exec: $forward_local - exec: jump has_response # 远程解析处理 - tag: remote_resolve_sequence type: sequence args: - exec: prefer_ipv4 - exec: ecs 159.230.104.0/24 # VPS 网段 - exec: $forward_remote - exec: jump has_response # fallback 用本地服务器 sequence 返回非国内 IP 则 drop_resp - tag: query_is_cn_ip type: sequence args: - exec: $forward_local - exec: jump ttl_sequence - matches: "!resp_ip $geoip_cn" exec: drop_resp # fallback 用远程服务器 sequence - tag: query_is_remote type: sequence args: - exec: jump remote_resolve_sequence - exec: reject 3 # fallback 用远程服务器 sequence - tag: fallback type: fallback args: primary: query_is_cn_ip secondary: query_is_remote threshold: 500 always_standby: false #--------------------------------------------------------------------# - tag: main_sequence type: sequence args: - matches: qname $local_ptr $blocklist exec: reject 3 - matches: qtype 12 exec: reject 3 - matches: qtype 65 exec: reject 3 - exec: $hosts - matches: has_resp exec: accept - exec: $redirect - matches: has_resp exec: accept - matches: qname $whitelist $geosite_cn exec: $cache - matches: has_resp exec: accept - matches: qname $whitelist $ddnslist $geosite_cn exec: jump local_resolve_sequence - matches: qname $greylist $geosite_no_cn exec: jump remote_resolve_sequence - exec: $fallback #--------------------------------------------------------------------# # 启动 udp 服务器。 - tag: udp_server type: udp_server args: entry: main_sequence listen: ":5335" # 启动 tcp 服务器。 - tag: tcp_server type: tcp_server args: entry: main_sequence listen: ":5335" MosDNS 选用的是 V5 的版本,如果你用的是 V4,那么两者配置文件不通用,这个要注意! 这里不会对 MosDNS 本身做详细的介绍,如果你想了解更多关于 MosDNS 的内容,请移步到 【wiki】 ; DNS DNS 部分,我们添加了 forward_local 跟 forward_remote 两个 DNS 插件,如下: 1234567891011121314151617181920212223 # 国内 DNS 服务器- tag: forward_local type: forward args: concurrent: 3 upstreams: - tag: dnsmasq addr: "udp://127.0.0.1" - tag: alidns addr: "https://dns.alidns.com/dns-query" dial_addr: "223.5.5.5" - tag: dnspod addr: "https://doh.pub/dns-query" dial_addr: "1.12.12.12"# 国外 DNS 服务器- tag: forward_remote type: forward args: concurrent: 1 upstreams: - tag: openClash addr: "udp://127.0.0.1:7874" 我们将国内的 DNS 解析转发到 forward_local,将国外的 DNS 解析转移到 forward_remote。forward_local 中,我们配置了 3 个 DNS 地址,分别是本机、阿里、腾讯,为什么添加本机呢?其实本机 DNS 由 dnsmasq 负责解析,而 dnsmasq 会拿到运营商分配的地址,通常对本地 DNS 解析有 buff 加成。3 个 DNS 并发请求,取最快的作为响应。再补充一点,dnsmasq 监听的是 53 端口,MosDNS 监听的是 5335,所以 MosDNS 并不会影响 dnsmasq。那么你可能会有疑问,DNS 解析是如何被劫持到非标准端口 5335 的 MosDNS 的,不急,我们继续往下看。 forward_remote 负责国外 DNS 的解析,这里我们将它全权交由 OpenClash 处理。也就是说由 OpenClash 解析的请求都是要经过代理转发的。问题来了,经过国内 DNS 解析的请求还会被 OpenClash 转发吗?会! 其实对于请求劫持,OpenClash 做的还远不止这些,不过这是 OpenClash 专题要讲的事情。 执行序列 对于 local_ptr、blocklist 两个列表、qtype 12(PTR)、qtype 65(针对于 iOS 14)类型的解析会以 reject 3 也就是 NXDOMAIN 响应。对于 whitelist 白名单、geosite_cn 国内域名的请求先查询缓存,如果缓存不存在再进行国内 DNS 的解析(成功解析之后自动加入缓存)。这里我们并没有对 DDNS 及代理的解析做缓存,DDNS 由于会时常变更,并且它的访问频率比较低,所以也没有太大的必要加入缓存。而代理域名的解析由于 OpenClash 会直接返回 Fake-IP,OpenClash 自身就会做 Fake-IP 的持久化,所以就没有必要再做一次缓存了。毕竟,如果 Fake-IP 过期或者清理之后,缓存还生效,那么上网就会出现问题,并且 Fake-IP 并 不慢。 如果一个域名未匹配灰名单、国内规则,也未匹配 geosite_no_cn 属于三无域名,那么就要执行 fallback。首先会进行国内 DNS 解析拿到 IP,然后对该 IP 进行判断,如果符合国内则进行响应,否则丢弃交由国外 DNS 解析。 名单 整个配置文件已经把模板定好,我们可以直接通过面板来灵活定制我们的规则: 白名单中的域名会走国内 DNS 解析。 用于屏蔽某个域名的解析。 需要走国外 DNS 解析的域名。 DDNS 域名: 如果存在 DDNS 域名,可以添加进来,由国内 DNS 解析。 最后一项就是需要打开数据库的定期更新: AdGuard Home 上文中,我们提到过 MosDNS 运行在 5335 端口,那么负责劫持 DNS 到 MosDNS 的就是 AdGuard Home 了。 AdGuard Home AdGuard Home 将流量挟持到自己的 553 端口,我们可以通过配置 AdGuard Home 的【客户端配置】来指定接入的设备是否需要代理。 通过【设置】->【DNS 设置】指定它的上游 DNS 服务器为: 127.0.0.1:5335 ,也就是 MosDNS 的监听端口。 通过【服务】->【AdGuard Home】,重定向 53 端口到 AdGuardHome 来劫持流量到自身。如下图: AdGuard Home 基本设置就完成了,你也可以设置广告规则、敏感内容过滤等,本文就不对其展开了。 OpenClash 基础配置 OpenClash 就是我们目标的最后一环节,我们需要按照如下步骤做好基础配置: 1、取消【绕过中国大陆 IP】 2、本地 DNS 劫持停用 3、勾选【自定义上游 DNS 服务器】,取消【追加上游 DN】、【追加默认 DNS】勾选,如下图: 4、移除 FallBack、default-NameServer 下的内容,并为 NameServer 添加国外 DNS 解析: 之所以要取消【追加上游 DNS】、【追加默认 DNS】是避免 OpenClash 将运营商分配的 DNS 添加进来,因为进入到 OpenClash 的流量一定是要走代理的,这些域名就不能被运营商的 DNS 解析。当你设置好之后一定要先【保存】,再【应用】。 否则配置不会生效,在应用之后,一定要去你的配置文件里看看最终生成的 DNS 是不是你指定的。 对于 Rule 部分,你可以配置成以下内容: 123 - "GEOIP,LAN,🇨🇳 China"- "GEOIP,CN,🇨🇳 China"- "MATCH,Proxy" 如果命中大陆或者本地的 IP 那么走直连,其余走代理。 请求劫持 到目前为止,好像该配的都配完了,国内的域名由 MosDNS 处理,国外的域名解析由 OpenClash 转发给 8.8.8.8 完成解析。此时其实只是完成了客户端到软路由的 DNS 解析,客户端拿到 DNS 解析记录之后会发送请求,如果只是以上的简单配置,那么流量会再次被 OpenClash 劫持。以下防火墙规则验证这一点: 我们看到源地址是 0.0.0.0/0 目标地址是 198.18.0.0/16、0.0.0.0/0 的流量都会转发到 7892 端口,也就是 OpenClash 代理端口。目标 198.18.0.0/16 为 Fake-IP 地址段,当客户端发起对该段的请求时,说明是需要代理的,所以这条规则没问题,但是下面一条规则就有问题了,我们需要将它移除: 1 iptables -t nat -D openclash -p tcp -s 0.0.0.0/0 -d 0.0.0.0/0 -j REDIRECT --to-ports 7892 这样对于目标非 Fake-IP 的流量就不会流经 OpenClash 内核了。但是这会引发另外一个问题,我们知道有些 App 会直接发起对 IP 的请求,比如:Telegram,Netflix 等。该防火墙规则会导致这些流量直接走直连从而影响使用。怎么解决这个问题呢? 方法有二,我们可以根据它们的 CIDR 来选择流量劫持,但是不靠谱,因为还需要定期维护,一但对方更换,那么又会出现问题,比较被动。这里我们选择另外一个方案解决——利用 china ipset: 1 iptables -t nat -A openclash -p tcp -m set ! --match-set china_ip_route dst -j REDIRECT --to-ports 7892 我们将目标地址非 China 的流量也转发到 OpenClash,就可以解决以上问题。还会有问题吗?答案是肯定的,除了客户端的请求外,宿主机也会产生请求,所以我们不得对这部分流量加以控制: 1、避免宿主机自身的出口流量全部走代理 1 iptables -t nat -D openclash_output -p tcp -m owner ! --uid-owner 65534 -j REDIRECT --to-ports 7892 2、对于宿主机自身的 TCP 流量除了 Fake IP 外,对于非中国 IP 的流量且非 OpenClash 的出口流量也重定向到代理 1 iptables -t nat -A openclash_output -p tcp -m set ! --match-set china_ip_route dst -m owner ! --uid-owner 65534 -j REDIRECT --to-ports 7892 3、避免来自中国的 UDP 流量经过代理 1 iptables -t mangle -D openclash -p udp -j TPROXY --tproxy-mark 0x162/0xffffffff --on-port 7895 4、重定向非中国的 UDP 流量到代理 1 iptables -t mangle -A openclash -p udp -m set ! --match-set china_ip_route dst -j TPROXY --tproxy-mark 0x162/0xffffffff --on-port 7895 以上关键的地方在于 china_ip_route ,它包含了中国的 IP 段,所有根据 IP 的规则都要经过它来判断,那么如何生成 china_ip_route 便成了一个问题。其实 OpenClash 有自动更新 GEO 数据库及中国大陆白名单的定时任务,也就是说它会生成我们需要的 ipset 文件。 所以我们要做的就是添加以下命令,用于将 china_ip_route 文件转换成对应的 ipset: 12 ipset -! flush china_ip_routeipset -! restore </etc/openclash/china_ip_route.ipset 2>/dev/null 最终我们将以下内容添加到【开发者选项】中: 123456789101112131415161718192021222324 #!/bin/sh. /usr/share/openclash/log.sh. /lib/functions.sh# This script is called by /etc/init.d/openclash# Add your custom firewall rules here, they will be added after the end of the OpenClash iptables rulesipset -! flush china_ip_routeipset -! restore </etc/openclash/china_ip_route.ipset 2>/dev/null# 避免来自中国的流量经过代理,需要走代理的都保留了 Fake IPiptables -t nat -D openclash -p tcp -s 0.0.0.0/0 -d 0.0.0.0/0 -j REDIRECT --to-ports 7892# 避免宿主机自身的出口流量全部走代理iptables -t nat -D openclash_output -p tcp -m owner ! --uid-owner 65534 -j REDIRECT --to-ports 7892# 避免来自中国的 UDP 流量经过代理iptables -t mangle -D openclash -p udp -j TPROXY --tproxy-mark 0x162/0xffffffff --on-port 7895# 除 Fake IP 外,非中国 IP 的流量也重定向到代理iptables -t nat -A openclash -p tcp -m set ! --match-set china_ip_route dst -j REDIRECT --to-ports 7892# 重定向非中国的 UDP 流量到代理iptables -t mangle -A openclash -p udp -m set ! --match-set china_ip_route dst -j TPROXY --tproxy-mark 0x162/0xffffffff --on-port 7895# 对于宿主机自身的 TCP 流量除了 Fake IP 外,对于非中国 IP 的流量且非 OpenClash 的出口流量也重定向到代理iptables -t nat -A openclash_output -p tcp -m set ! --match-set china_ip_route dst -m owner ! --uid-owner 65534 -j REDIRECT --to-ports 7892exit 0 保存、应用! 尾声 以上就是本次家庭网络改造的流程,最终可以实现,家中所有接入设备的实时管控。可以清楚的了解到每台设备的上网信息并对其加以限制。同时对于国内网的网站访问也可以做到精确分流,提升响应速度。当然这套方案也并不完美,由于国内域名跳过了 OpenClash 也就意味着失去了对它们的限制。不过可以从 DNS 维度对它们进行屏蔽。如果是基于 IP 的,那就只能通过防火墙加以限制了。 缺失模块。 1、请确保node版本大于6.2 2、在博客根目录(注意不是yilia-plus根目录)执行以下命令: npm i hexo-generator-json-content --save 3、在根目录_config.yml里添加配置: jsonContent: meta: false pages: false posts: title: true date: true path: true text: false raw: false content: false slug: false updated: false comments: false link: false permalink: false excerpt: false categories: false tags: true
目前的代理方案是使用 OpenClash 的 Fake-IP 增强模式,并开启【绕过中国大陆 IP】,这也是我一直以来常用的方式。那这有什么弊端呢?
回答这个问题前,我们需要了解 DNS 在 OpenClash 中的应用场景:
通过以上应用分析,要想实现 DNS 污染,需要符合以下几种情况:
123
Rule: - "GEOIP,US,Proxy" # IP 为美国时走代理 - "MATCH,DIRECT" # 其余请求直连
我们看下以上例子,如果 IP 命中 US,那么走代理,否则走直连。此时如果访问 google.com 由于规则中并没有基于域名的规则,那么就需要进行 DNS 解析,此时就会得到一个经过污染了的保留 IP, 而该保留 IP 并非美国 IP,所以走直连。也就是说以上配置存在 DNS 污染问题。
Rule: - "GEOIP,CN,DIRECT" - "MATCH,Proxy"
以上配置可以避免大部分的污染问题,因为为了保证国内地址的可访问性,一般是很少将国外的域名污染成国内的 IP。但是,如果呢?我们可以在 IP 规则之前加上域名规则:
1234
Rule: - "DOMAIN-SUFFIX,google.com,Proxy" - "GEOIP,CN,DIRECT" - "MATCH,Proxy"
这样一来就可以解决域名污染的问题了。
OpenClash 提供了 nameserver 及 fallback 来配置 DNS。我们看下具体的流程:
1、从 nameserver 和 fallback 里的 DNS 进行并发请求,并且选取 nameserver 中最先响应的结果作为基准; 2、使用 GEOIP 判断此 IP 的所属区域,如果属于国内(CN)或保留地址则直接响应给客户端; 3、其他情况则把 fallback 中的结果响应给客户端;
我们以例 2 中的规则为例子并以 Fake-IP 模式进行说明:
当客户端发送对 google.com 的请求时,会被 OpenClash 劫持然后返回一个 Fake-IP 并做好与域名的绑定。客户端拿到 Fake-IP 并对其进行请求,该请求再次被 OpenClash 拦截, 并根据绑定关系拿到该 Fake-IP 对应的 google.com。然后根据规则查找,发现没有基于域名的规则,而仅有的 IP 规则并没有 no-resolve 选项。那么就需要对 google.com 进行 DNS 解析。 OpenClash 会对 nameserver 及 fallback 中的 DNS 进行并发请求。由于是对外请求的,那么该 DNS 查询就会被 DNS 服务器主动污染或者运营商劫持。出现这个问题我们一般是更换 DNS 以及 将 fallback 指向 国外 DNS。但是对于运营商提供的 DNS 我们就无能为力了。此时 OpenClash 就会拿到 nameserver、fallback 双方解析出来的 IP。如果该 IP 是国内的,那么就采用该 IP 进行规则判断,如果 该 IP 是国外的,那么就采用 fallback 的结果进行规则判断。如果是直连模式,那么就直接用解析出来的 IP 发送请求;如果是代理模式,就将请求域名发送给代理服务器,由代理 服务器完成 DNS 解析。
通过以上分析,其实我们发现,以上配置其实能够解决绝大部分的污染问题,对于一般的用户也基本够用了。但是如果仔细推敲其实这里是有问题的,Fake-IP 模式下的 OpenClash 对于 DNS 的解析仅仅 用于代理规则判断,如果是直连模式时才会进行实际的请求。那么解析时,由于是 nameserver、fallback 并发请求,如果 nameserver 配置为国内 DNS 时,对于国外域名的请求,国内 DNS 就会有 解析记录,此时就会涉及到隐私安全问题。那么你可能就会想,直接把 nameserver 配置为国外 DNS 不就行了,那么国内域名的解析就有问题了。
另外,对于 Fake-IP,有些客户端就会表现出异样的行为,比如我那台领势路由器就会亮红灯。另一方面,我们希望国内的域名返回真实的 IP,只有需要代理的域名返回 Fake-IP(不要说通过 Fake-IP-Filter 实现)。
对于以上问题,总结一下我们的需求: 1、对于国内的域名走国内 DNS 解析并返回真实 IP。 2、对于国外的域名走国外解析,跳过国内解析过程,避免留下印记。 3、对于国内的请求直接跳过 OpenClash 的处理,一方面加快响应,另一方面避免由于 OpenClash 崩溃导致所有设备断网。
如果你也有以上需求,那么我们可以继续往下看了!
为了实现以上目标,我们需要一款 DNS 分流软件,它就是 MosDNS。 我们通过以下命令进行安装,当前版本为 MosDNS v5.1.3: 先升级必要工具: 123 opkg updateopkg install curlopkg update libcur 执行安装脚本: 1 sh -c "$(curl -ksS https://raw.githubusercontent.com/sbwml/luci-app-mosdns/v5/install.sh)" 安装成功之后,你会在【服务】->【MosDNS】找到。然后按照如图所示,关闭转发,打开自定义配置文件: 我们添加以下配置文件: 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217 log: level: info file: "/opt/data/mosdns/mosdns.log" #api: #http: "0.0.0.0:9091"plugins: #--------------------------------------------------------------------# # 缓存 - tag: cache type: cache args: size: 10240 lazy_cache_ttl: 86400 dump_file: /etc/mosdns/cache.dump # 修改 ttl (默认 0 不修改 ttl) - tag: ttl_sequence type: sequence args: - exec: ttl 60-600 - tag: modify_response type: sequence args: - exec: jump ttl_sequence - exec: accept # 有响应终止返回 - tag: has_response type: sequence args: - matches: has_resp exec: goto modify_response #--------------------------------------------------------------------# # 黑名单 加入的域名将屏蔽 DNS 解析 - tag: blocklist type: domain_set args: files: - "/etc/mosdns/rule/blocklist.txt" # PTR 黑名单 加入的域名将阻止 PTR 请求 - tag: local_ptr type: domain_set args: files: - "/etc/mosdns/rule/local-ptr.txt" # 白名单 由本地 DNS 负责解析(如果黑名单命中,则直接拒绝,也就是黑名单具有最高优先级) - tag: whitelist type: domain_set args: files: - "/etc/mosdns/rule/whitelist.txt" # DDNS 名单,加入的域名始终使用 "本地 DNS" 进行解析 - tag: ddnslist type: domain_set args: files: - "/etc/mosdns/rule/ddnslist.txt" # 灰名单 加入的域名将仅使用 "国外DNS服务器" 进行解析 - tag: greylist type: domain_set args: files: - "/etc/mosdns/rule/greylist.txt" #--------------------------------------------------------------------# # 自定义 Hosts 重写 - tag: hosts type: hosts args: files: - "/etc/mosdns/rule/hosts.txt" # 重定向请求的域名 - tag: redirect type: redirect args: files: - "/etc/mosdns/rule/redirect.txt" #--------------------------------------------------------------------# # 国内域名 - tag: geosite_cn type: domain_set args: files: - "/var/mosdns/geosite_cn.txt" # 国外域名 - tag: geosite_no_cn type: domain_set args: files: - "/var/mosdns/geosite_geolocation-!cn.txt" # 国内 IP - tag: geoip_cn type: ip_set args: files: - "/var/mosdns/geoip_cn.txt" #--------------------------------------------------------------------# # 国内 DNS 服务器 - tag: forward_local type: forward args: concurrent: 3 upstreams: - tag: dnsmasq addr: "udp://127.0.0.1" - tag: alidns addr: "https://dns.alidns.com/dns-query" dial_addr: "223.5.5.5" - tag: dnspod addr: "https://doh.pub/dns-query" dial_addr: "1.12.12.12" # 国外 DNS 服务器 - tag: forward_remote type: forward args: concurrent: 1 upstreams: - tag: openClash addr: "udp://127.0.0.1:7874" #--------------------------------------------------------------------# # 本地解析处理 - tag: local_resolve_sequence type: sequence args: - exec: $forward_local - exec: jump has_response # 远程解析处理 - tag: remote_resolve_sequence type: sequence args: - exec: prefer_ipv4 - exec: ecs 159.230.104.0/24 # VPS 网段 - exec: $forward_remote - exec: jump has_response # fallback 用本地服务器 sequence 返回非国内 IP 则 drop_resp - tag: query_is_cn_ip type: sequence args: - exec: $forward_local - exec: jump ttl_sequence - matches: "!resp_ip $geoip_cn" exec: drop_resp # fallback 用远程服务器 sequence - tag: query_is_remote type: sequence args: - exec: jump remote_resolve_sequence - exec: reject 3 # fallback 用远程服务器 sequence - tag: fallback type: fallback args: primary: query_is_cn_ip secondary: query_is_remote threshold: 500 always_standby: false #--------------------------------------------------------------------# - tag: main_sequence type: sequence args: - matches: qname $local_ptr $blocklist exec: reject 3 - matches: qtype 12 exec: reject 3 - matches: qtype 65 exec: reject 3 - exec: $hosts - matches: has_resp exec: accept - exec: $redirect - matches: has_resp exec: accept - matches: qname $whitelist $geosite_cn exec: $cache - matches: has_resp exec: accept - matches: qname $whitelist $ddnslist $geosite_cn exec: jump local_resolve_sequence - matches: qname $greylist $geosite_no_cn exec: jump remote_resolve_sequence - exec: $fallback #--------------------------------------------------------------------# # 启动 udp 服务器。 - tag: udp_server type: udp_server args: entry: main_sequence listen: ":5335" # 启动 tcp 服务器。 - tag: tcp_server type: tcp_server args: entry: main_sequence listen: ":5335" MosDNS 选用的是 V5 的版本,如果你用的是 V4,那么两者配置文件不通用,这个要注意! 这里不会对 MosDNS 本身做详细的介绍,如果你想了解更多关于 MosDNS 的内容,请移步到 【wiki】 ; DNS DNS 部分,我们添加了 forward_local 跟 forward_remote 两个 DNS 插件,如下: 1234567891011121314151617181920212223 # 国内 DNS 服务器- tag: forward_local type: forward args: concurrent: 3 upstreams: - tag: dnsmasq addr: "udp://127.0.0.1" - tag: alidns addr: "https://dns.alidns.com/dns-query" dial_addr: "223.5.5.5" - tag: dnspod addr: "https://doh.pub/dns-query" dial_addr: "1.12.12.12"# 国外 DNS 服务器- tag: forward_remote type: forward args: concurrent: 1 upstreams: - tag: openClash addr: "udp://127.0.0.1:7874" 我们将国内的 DNS 解析转发到 forward_local,将国外的 DNS 解析转移到 forward_remote。forward_local 中,我们配置了 3 个 DNS 地址,分别是本机、阿里、腾讯,为什么添加本机呢?其实本机 DNS 由 dnsmasq 负责解析,而 dnsmasq 会拿到运营商分配的地址,通常对本地 DNS 解析有 buff 加成。3 个 DNS 并发请求,取最快的作为响应。再补充一点,dnsmasq 监听的是 53 端口,MosDNS 监听的是 5335,所以 MosDNS 并不会影响 dnsmasq。那么你可能会有疑问,DNS 解析是如何被劫持到非标准端口 5335 的 MosDNS 的,不急,我们继续往下看。 forward_remote 负责国外 DNS 的解析,这里我们将它全权交由 OpenClash 处理。也就是说由 OpenClash 解析的请求都是要经过代理转发的。问题来了,经过国内 DNS 解析的请求还会被 OpenClash 转发吗?会! 其实对于请求劫持,OpenClash 做的还远不止这些,不过这是 OpenClash 专题要讲的事情。 执行序列 对于 local_ptr、blocklist 两个列表、qtype 12(PTR)、qtype 65(针对于 iOS 14)类型的解析会以 reject 3 也就是 NXDOMAIN 响应。对于 whitelist 白名单、geosite_cn 国内域名的请求先查询缓存,如果缓存不存在再进行国内 DNS 的解析(成功解析之后自动加入缓存)。这里我们并没有对 DDNS 及代理的解析做缓存,DDNS 由于会时常变更,并且它的访问频率比较低,所以也没有太大的必要加入缓存。而代理域名的解析由于 OpenClash 会直接返回 Fake-IP,OpenClash 自身就会做 Fake-IP 的持久化,所以就没有必要再做一次缓存了。毕竟,如果 Fake-IP 过期或者清理之后,缓存还生效,那么上网就会出现问题,并且 Fake-IP 并 不慢。 如果一个域名未匹配灰名单、国内规则,也未匹配 geosite_no_cn 属于三无域名,那么就要执行 fallback。首先会进行国内 DNS 解析拿到 IP,然后对该 IP 进行判断,如果符合国内则进行响应,否则丢弃交由国外 DNS 解析。 名单 整个配置文件已经把模板定好,我们可以直接通过面板来灵活定制我们的规则: 白名单中的域名会走国内 DNS 解析。 用于屏蔽某个域名的解析。 需要走国外 DNS 解析的域名。 DDNS 域名: 如果存在 DDNS 域名,可以添加进来,由国内 DNS 解析。 最后一项就是需要打开数据库的定期更新: AdGuard Home 上文中,我们提到过 MosDNS 运行在 5335 端口,那么负责劫持 DNS 到 MosDNS 的就是 AdGuard Home 了。 AdGuard Home AdGuard Home 将流量挟持到自己的 553 端口,我们可以通过配置 AdGuard Home 的【客户端配置】来指定接入的设备是否需要代理。 通过【设置】->【DNS 设置】指定它的上游 DNS 服务器为: 127.0.0.1:5335 ,也就是 MosDNS 的监听端口。 通过【服务】->【AdGuard Home】,重定向 53 端口到 AdGuardHome 来劫持流量到自身。如下图: AdGuard Home 基本设置就完成了,你也可以设置广告规则、敏感内容过滤等,本文就不对其展开了。 OpenClash 基础配置 OpenClash 就是我们目标的最后一环节,我们需要按照如下步骤做好基础配置: 1、取消【绕过中国大陆 IP】 2、本地 DNS 劫持停用 3、勾选【自定义上游 DNS 服务器】,取消【追加上游 DN】、【追加默认 DNS】勾选,如下图: 4、移除 FallBack、default-NameServer 下的内容,并为 NameServer 添加国外 DNS 解析: 之所以要取消【追加上游 DNS】、【追加默认 DNS】是避免 OpenClash 将运营商分配的 DNS 添加进来,因为进入到 OpenClash 的流量一定是要走代理的,这些域名就不能被运营商的 DNS 解析。当你设置好之后一定要先【保存】,再【应用】。 否则配置不会生效,在应用之后,一定要去你的配置文件里看看最终生成的 DNS 是不是你指定的。 对于 Rule 部分,你可以配置成以下内容: 123 - "GEOIP,LAN,🇨🇳 China"- "GEOIP,CN,🇨🇳 China"- "MATCH,Proxy" 如果命中大陆或者本地的 IP 那么走直连,其余走代理。 请求劫持 到目前为止,好像该配的都配完了,国内的域名由 MosDNS 处理,国外的域名解析由 OpenClash 转发给 8.8.8.8 完成解析。此时其实只是完成了客户端到软路由的 DNS 解析,客户端拿到 DNS 解析记录之后会发送请求,如果只是以上的简单配置,那么流量会再次被 OpenClash 劫持。以下防火墙规则验证这一点: 我们看到源地址是 0.0.0.0/0 目标地址是 198.18.0.0/16、0.0.0.0/0 的流量都会转发到 7892 端口,也就是 OpenClash 代理端口。目标 198.18.0.0/16 为 Fake-IP 地址段,当客户端发起对该段的请求时,说明是需要代理的,所以这条规则没问题,但是下面一条规则就有问题了,我们需要将它移除: 1 iptables -t nat -D openclash -p tcp -s 0.0.0.0/0 -d 0.0.0.0/0 -j REDIRECT --to-ports 7892 这样对于目标非 Fake-IP 的流量就不会流经 OpenClash 内核了。但是这会引发另外一个问题,我们知道有些 App 会直接发起对 IP 的请求,比如:Telegram,Netflix 等。该防火墙规则会导致这些流量直接走直连从而影响使用。怎么解决这个问题呢? 方法有二,我们可以根据它们的 CIDR 来选择流量劫持,但是不靠谱,因为还需要定期维护,一但对方更换,那么又会出现问题,比较被动。这里我们选择另外一个方案解决——利用 china ipset: 1 iptables -t nat -A openclash -p tcp -m set ! --match-set china_ip_route dst -j REDIRECT --to-ports 7892 我们将目标地址非 China 的流量也转发到 OpenClash,就可以解决以上问题。还会有问题吗?答案是肯定的,除了客户端的请求外,宿主机也会产生请求,所以我们不得对这部分流量加以控制: 1、避免宿主机自身的出口流量全部走代理 1 iptables -t nat -D openclash_output -p tcp -m owner ! --uid-owner 65534 -j REDIRECT --to-ports 7892 2、对于宿主机自身的 TCP 流量除了 Fake IP 外,对于非中国 IP 的流量且非 OpenClash 的出口流量也重定向到代理 1 iptables -t nat -A openclash_output -p tcp -m set ! --match-set china_ip_route dst -m owner ! --uid-owner 65534 -j REDIRECT --to-ports 7892 3、避免来自中国的 UDP 流量经过代理 1 iptables -t mangle -D openclash -p udp -j TPROXY --tproxy-mark 0x162/0xffffffff --on-port 7895 4、重定向非中国的 UDP 流量到代理 1 iptables -t mangle -A openclash -p udp -m set ! --match-set china_ip_route dst -j TPROXY --tproxy-mark 0x162/0xffffffff --on-port 7895 以上关键的地方在于 china_ip_route ,它包含了中国的 IP 段,所有根据 IP 的规则都要经过它来判断,那么如何生成 china_ip_route 便成了一个问题。其实 OpenClash 有自动更新 GEO 数据库及中国大陆白名单的定时任务,也就是说它会生成我们需要的 ipset 文件。 所以我们要做的就是添加以下命令,用于将 china_ip_route 文件转换成对应的 ipset: 12 ipset -! flush china_ip_routeipset -! restore </etc/openclash/china_ip_route.ipset 2>/dev/null 最终我们将以下内容添加到【开发者选项】中: 123456789101112131415161718192021222324 #!/bin/sh. /usr/share/openclash/log.sh. /lib/functions.sh# This script is called by /etc/init.d/openclash# Add your custom firewall rules here, they will be added after the end of the OpenClash iptables rulesipset -! flush china_ip_routeipset -! restore </etc/openclash/china_ip_route.ipset 2>/dev/null# 避免来自中国的流量经过代理,需要走代理的都保留了 Fake IPiptables -t nat -D openclash -p tcp -s 0.0.0.0/0 -d 0.0.0.0/0 -j REDIRECT --to-ports 7892# 避免宿主机自身的出口流量全部走代理iptables -t nat -D openclash_output -p tcp -m owner ! --uid-owner 65534 -j REDIRECT --to-ports 7892# 避免来自中国的 UDP 流量经过代理iptables -t mangle -D openclash -p udp -j TPROXY --tproxy-mark 0x162/0xffffffff --on-port 7895# 除 Fake IP 外,非中国 IP 的流量也重定向到代理iptables -t nat -A openclash -p tcp -m set ! --match-set china_ip_route dst -j REDIRECT --to-ports 7892# 重定向非中国的 UDP 流量到代理iptables -t mangle -A openclash -p udp -m set ! --match-set china_ip_route dst -j TPROXY --tproxy-mark 0x162/0xffffffff --on-port 7895# 对于宿主机自身的 TCP 流量除了 Fake IP 外,对于非中国 IP 的流量且非 OpenClash 的出口流量也重定向到代理iptables -t nat -A openclash_output -p tcp -m set ! --match-set china_ip_route dst -m owner ! --uid-owner 65534 -j REDIRECT --to-ports 7892exit 0 保存、应用! 尾声 以上就是本次家庭网络改造的流程,最终可以实现,家中所有接入设备的实时管控。可以清楚的了解到每台设备的上网信息并对其加以限制。同时对于国内网的网站访问也可以做到精确分流,提升响应速度。当然这套方案也并不完美,由于国内域名跳过了 OpenClash 也就意味着失去了对它们的限制。不过可以从 DNS 维度对它们进行屏蔽。如果是基于 IP 的,那就只能通过防火墙加以限制了。 缺失模块。 1、请确保node版本大于6.2 2、在博客根目录(注意不是yilia-plus根目录)执行以下命令: npm i hexo-generator-json-content --save 3、在根目录_config.yml里添加配置: jsonContent: meta: false pages: false posts: title: true date: true path: true text: false raw: false content: false slug: false updated: false comments: false link: false permalink: false excerpt: false categories: false tags: true
为了实现以上目标,我们需要一款 DNS 分流软件,它就是 MosDNS。
我们通过以下命令进行安装,当前版本为 MosDNS v5.1.3:
opkg updateopkg install curlopkg update libcur
1
sh -c "$(curl -ksS https://raw.githubusercontent.com/sbwml/luci-app-mosdns/v5/install.sh)"
安装成功之后,你会在【服务】->【MosDNS】找到。然后按照如图所示,关闭转发,打开自定义配置文件:
我们添加以下配置文件:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
log: level: info file: "/opt/data/mosdns/mosdns.log" #api: #http: "0.0.0.0:9091"plugins: #--------------------------------------------------------------------# # 缓存 - tag: cache type: cache args: size: 10240 lazy_cache_ttl: 86400 dump_file: /etc/mosdns/cache.dump # 修改 ttl (默认 0 不修改 ttl) - tag: ttl_sequence type: sequence args: - exec: ttl 60-600 - tag: modify_response type: sequence args: - exec: jump ttl_sequence - exec: accept # 有响应终止返回 - tag: has_response type: sequence args: - matches: has_resp exec: goto modify_response #--------------------------------------------------------------------# # 黑名单 加入的域名将屏蔽 DNS 解析 - tag: blocklist type: domain_set args: files: - "/etc/mosdns/rule/blocklist.txt" # PTR 黑名单 加入的域名将阻止 PTR 请求 - tag: local_ptr type: domain_set args: files: - "/etc/mosdns/rule/local-ptr.txt" # 白名单 由本地 DNS 负责解析(如果黑名单命中,则直接拒绝,也就是黑名单具有最高优先级) - tag: whitelist type: domain_set args: files: - "/etc/mosdns/rule/whitelist.txt" # DDNS 名单,加入的域名始终使用 "本地 DNS" 进行解析 - tag: ddnslist type: domain_set args: files: - "/etc/mosdns/rule/ddnslist.txt" # 灰名单 加入的域名将仅使用 "国外DNS服务器" 进行解析 - tag: greylist type: domain_set args: files: - "/etc/mosdns/rule/greylist.txt" #--------------------------------------------------------------------# # 自定义 Hosts 重写 - tag: hosts type: hosts args: files: - "/etc/mosdns/rule/hosts.txt" # 重定向请求的域名 - tag: redirect type: redirect args: files: - "/etc/mosdns/rule/redirect.txt" #--------------------------------------------------------------------# # 国内域名 - tag: geosite_cn type: domain_set args: files: - "/var/mosdns/geosite_cn.txt" # 国外域名 - tag: geosite_no_cn type: domain_set args: files: - "/var/mosdns/geosite_geolocation-!cn.txt" # 国内 IP - tag: geoip_cn type: ip_set args: files: - "/var/mosdns/geoip_cn.txt" #--------------------------------------------------------------------# # 国内 DNS 服务器 - tag: forward_local type: forward args: concurrent: 3 upstreams: - tag: dnsmasq addr: "udp://127.0.0.1" - tag: alidns addr: "https://dns.alidns.com/dns-query" dial_addr: "223.5.5.5" - tag: dnspod addr: "https://doh.pub/dns-query" dial_addr: "1.12.12.12" # 国外 DNS 服务器 - tag: forward_remote type: forward args: concurrent: 1 upstreams: - tag: openClash addr: "udp://127.0.0.1:7874" #--------------------------------------------------------------------# # 本地解析处理 - tag: local_resolve_sequence type: sequence args: - exec: $forward_local - exec: jump has_response # 远程解析处理 - tag: remote_resolve_sequence type: sequence args: - exec: prefer_ipv4 - exec: ecs 159.230.104.0/24 # VPS 网段 - exec: $forward_remote - exec: jump has_response # fallback 用本地服务器 sequence 返回非国内 IP 则 drop_resp - tag: query_is_cn_ip type: sequence args: - exec: $forward_local - exec: jump ttl_sequence - matches: "!resp_ip $geoip_cn" exec: drop_resp # fallback 用远程服务器 sequence - tag: query_is_remote type: sequence args: - exec: jump remote_resolve_sequence - exec: reject 3 # fallback 用远程服务器 sequence - tag: fallback type: fallback args: primary: query_is_cn_ip secondary: query_is_remote threshold: 500 always_standby: false #--------------------------------------------------------------------# - tag: main_sequence type: sequence args: - matches: qname $local_ptr $blocklist exec: reject 3 - matches: qtype 12 exec: reject 3 - matches: qtype 65 exec: reject 3 - exec: $hosts - matches: has_resp exec: accept - exec: $redirect - matches: has_resp exec: accept - matches: qname $whitelist $geosite_cn exec: $cache - matches: has_resp exec: accept - matches: qname $whitelist $ddnslist $geosite_cn exec: jump local_resolve_sequence - matches: qname $greylist $geosite_no_cn exec: jump remote_resolve_sequence - exec: $fallback #--------------------------------------------------------------------# # 启动 udp 服务器。 - tag: udp_server type: udp_server args: entry: main_sequence listen: ":5335" # 启动 tcp 服务器。 - tag: tcp_server type: tcp_server args: entry: main_sequence listen: ":5335"
MosDNS 选用的是 V5 的版本,如果你用的是 V4,那么两者配置文件不通用,这个要注意!
这里不会对 MosDNS 本身做详细的介绍,如果你想了解更多关于 MosDNS 的内容,请移步到 【wiki】 ;
DNS 部分,我们添加了 forward_local 跟 forward_remote 两个 DNS 插件,如下:
1234567891011121314151617181920212223
# 国内 DNS 服务器- tag: forward_local type: forward args: concurrent: 3 upstreams: - tag: dnsmasq addr: "udp://127.0.0.1" - tag: alidns addr: "https://dns.alidns.com/dns-query" dial_addr: "223.5.5.5" - tag: dnspod addr: "https://doh.pub/dns-query" dial_addr: "1.12.12.12"# 国外 DNS 服务器- tag: forward_remote type: forward args: concurrent: 1 upstreams: - tag: openClash addr: "udp://127.0.0.1:7874"
我们将国内的 DNS 解析转发到 forward_local,将国外的 DNS 解析转移到 forward_remote。forward_local 中,我们配置了 3 个 DNS 地址,分别是本机、阿里、腾讯,为什么添加本机呢?其实本机 DNS 由 dnsmasq 负责解析,而 dnsmasq 会拿到运营商分配的地址,通常对本地 DNS 解析有 buff 加成。3 个 DNS 并发请求,取最快的作为响应。再补充一点,dnsmasq 监听的是 53 端口,MosDNS 监听的是 5335,所以 MosDNS 并不会影响 dnsmasq。那么你可能会有疑问,DNS 解析是如何被劫持到非标准端口 5335 的 MosDNS 的,不急,我们继续往下看。
forward_remote 负责国外 DNS 的解析,这里我们将它全权交由 OpenClash 处理。也就是说由 OpenClash 解析的请求都是要经过代理转发的。问题来了,经过国内 DNS 解析的请求还会被 OpenClash 转发吗?会! 其实对于请求劫持,OpenClash 做的还远不止这些,不过这是 OpenClash 专题要讲的事情。
对于 local_ptr、blocklist 两个列表、qtype 12(PTR)、qtype 65(针对于 iOS 14)类型的解析会以 reject 3 也就是 NXDOMAIN 响应。对于 whitelist 白名单、geosite_cn 国内域名的请求先查询缓存,如果缓存不存在再进行国内 DNS 的解析(成功解析之后自动加入缓存)。这里我们并没有对 DDNS 及代理的解析做缓存,DDNS 由于会时常变更,并且它的访问频率比较低,所以也没有太大的必要加入缓存。而代理域名的解析由于 OpenClash 会直接返回 Fake-IP,OpenClash 自身就会做 Fake-IP 的持久化,所以就没有必要再做一次缓存了。毕竟,如果 Fake-IP 过期或者清理之后,缓存还生效,那么上网就会出现问题,并且 Fake-IP 并 不慢。
如果一个域名未匹配灰名单、国内规则,也未匹配 geosite_no_cn 属于三无域名,那么就要执行 fallback。首先会进行国内 DNS 解析拿到 IP,然后对该 IP 进行判断,如果符合国内则进行响应,否则丢弃交由国外 DNS 解析。
整个配置文件已经把模板定好,我们可以直接通过面板来灵活定制我们的规则:
白名单中的域名会走国内 DNS 解析。
用于屏蔽某个域名的解析。
需要走国外 DNS 解析的域名。
DDNS 域名:
如果存在 DDNS 域名,可以添加进来,由国内 DNS 解析。
最后一项就是需要打开数据库的定期更新:
上文中,我们提到过 MosDNS 运行在 5335 端口,那么负责劫持 DNS 到 MosDNS 的就是 AdGuard Home 了。
AdGuard Home 将流量挟持到自己的 553 端口,我们可以通过配置 AdGuard Home 的【客户端配置】来指定接入的设备是否需要代理。
通过【设置】->【DNS 设置】指定它的上游 DNS 服务器为: 127.0.0.1:5335 ,也就是 MosDNS 的监听端口。
127.0.0.1:5335
通过【服务】->【AdGuard Home】,重定向 53 端口到 AdGuardHome 来劫持流量到自身。如下图:
AdGuard Home 基本设置就完成了,你也可以设置广告规则、敏感内容过滤等,本文就不对其展开了。
OpenClash 就是我们目标的最后一环节,我们需要按照如下步骤做好基础配置:
1、取消【绕过中国大陆 IP】
2、本地 DNS 劫持停用
3、勾选【自定义上游 DNS 服务器】,取消【追加上游 DN】、【追加默认 DNS】勾选,如下图:
4、移除 FallBack、default-NameServer 下的内容,并为 NameServer 添加国外 DNS 解析:
之所以要取消【追加上游 DNS】、【追加默认 DNS】是避免 OpenClash 将运营商分配的 DNS 添加进来,因为进入到 OpenClash 的流量一定是要走代理的,这些域名就不能被运营商的 DNS 解析。当你设置好之后一定要先【保存】,再【应用】。 否则配置不会生效,在应用之后,一定要去你的配置文件里看看最终生成的 DNS 是不是你指定的。
对于 Rule 部分,你可以配置成以下内容:
- "GEOIP,LAN,🇨🇳 China"- "GEOIP,CN,🇨🇳 China"- "MATCH,Proxy"
如果命中大陆或者本地的 IP 那么走直连,其余走代理。
到目前为止,好像该配的都配完了,国内的域名由 MosDNS 处理,国外的域名解析由 OpenClash 转发给 8.8.8.8 完成解析。此时其实只是完成了客户端到软路由的 DNS 解析,客户端拿到 DNS 解析记录之后会发送请求,如果只是以上的简单配置,那么流量会再次被 OpenClash 劫持。以下防火墙规则验证这一点:
我们看到源地址是 0.0.0.0/0 目标地址是 198.18.0.0/16、0.0.0.0/0 的流量都会转发到 7892 端口,也就是 OpenClash 代理端口。目标 198.18.0.0/16 为 Fake-IP 地址段,当客户端发起对该段的请求时,说明是需要代理的,所以这条规则没问题,但是下面一条规则就有问题了,我们需要将它移除:
iptables -t nat -D openclash -p tcp -s 0.0.0.0/0 -d 0.0.0.0/0 -j REDIRECT --to-ports 7892
这样对于目标非 Fake-IP 的流量就不会流经 OpenClash 内核了。但是这会引发另外一个问题,我们知道有些 App 会直接发起对 IP 的请求,比如:Telegram,Netflix 等。该防火墙规则会导致这些流量直接走直连从而影响使用。怎么解决这个问题呢? 方法有二,我们可以根据它们的 CIDR 来选择流量劫持,但是不靠谱,因为还需要定期维护,一但对方更换,那么又会出现问题,比较被动。这里我们选择另外一个方案解决——利用 china ipset:
iptables -t nat -A openclash -p tcp -m set ! --match-set china_ip_route dst -j REDIRECT --to-ports 7892
我们将目标地址非 China 的流量也转发到 OpenClash,就可以解决以上问题。还会有问题吗?答案是肯定的,除了客户端的请求外,宿主机也会产生请求,所以我们不得对这部分流量加以控制:
1、避免宿主机自身的出口流量全部走代理
iptables -t nat -D openclash_output -p tcp -m owner ! --uid-owner 65534 -j REDIRECT --to-ports 7892
2、对于宿主机自身的 TCP 流量除了 Fake IP 外,对于非中国 IP 的流量且非 OpenClash 的出口流量也重定向到代理
iptables -t nat -A openclash_output -p tcp -m set ! --match-set china_ip_route dst -m owner ! --uid-owner 65534 -j REDIRECT --to-ports 7892
3、避免来自中国的 UDP 流量经过代理
iptables -t mangle -D openclash -p udp -j TPROXY --tproxy-mark 0x162/0xffffffff --on-port 7895
4、重定向非中国的 UDP 流量到代理
iptables -t mangle -A openclash -p udp -m set ! --match-set china_ip_route dst -j TPROXY --tproxy-mark 0x162/0xffffffff --on-port 7895
以上关键的地方在于 china_ip_route ,它包含了中国的 IP 段,所有根据 IP 的规则都要经过它来判断,那么如何生成 china_ip_route 便成了一个问题。其实 OpenClash 有自动更新 GEO 数据库及中国大陆白名单的定时任务,也就是说它会生成我们需要的 ipset 文件。 所以我们要做的就是添加以下命令,用于将 china_ip_route 文件转换成对应的 ipset:
china_ip_route
12
ipset -! flush china_ip_routeipset -! restore </etc/openclash/china_ip_route.ipset 2>/dev/null
最终我们将以下内容添加到【开发者选项】中:
123456789101112131415161718192021222324
#!/bin/sh. /usr/share/openclash/log.sh. /lib/functions.sh# This script is called by /etc/init.d/openclash# Add your custom firewall rules here, they will be added after the end of the OpenClash iptables rulesipset -! flush china_ip_routeipset -! restore </etc/openclash/china_ip_route.ipset 2>/dev/null# 避免来自中国的流量经过代理,需要走代理的都保留了 Fake IPiptables -t nat -D openclash -p tcp -s 0.0.0.0/0 -d 0.0.0.0/0 -j REDIRECT --to-ports 7892# 避免宿主机自身的出口流量全部走代理iptables -t nat -D openclash_output -p tcp -m owner ! --uid-owner 65534 -j REDIRECT --to-ports 7892# 避免来自中国的 UDP 流量经过代理iptables -t mangle -D openclash -p udp -j TPROXY --tproxy-mark 0x162/0xffffffff --on-port 7895# 除 Fake IP 外,非中国 IP 的流量也重定向到代理iptables -t nat -A openclash -p tcp -m set ! --match-set china_ip_route dst -j REDIRECT --to-ports 7892# 重定向非中国的 UDP 流量到代理iptables -t mangle -A openclash -p udp -m set ! --match-set china_ip_route dst -j TPROXY --tproxy-mark 0x162/0xffffffff --on-port 7895# 对于宿主机自身的 TCP 流量除了 Fake IP 外,对于非中国 IP 的流量且非 OpenClash 的出口流量也重定向到代理iptables -t nat -A openclash_output -p tcp -m set ! --match-set china_ip_route dst -m owner ! --uid-owner 65534 -j REDIRECT --to-ports 7892exit 0
保存、应用!
以上就是本次家庭网络改造的流程,最终可以实现,家中所有接入设备的实时管控。可以清楚的了解到每台设备的上网信息并对其加以限制。同时对于国内网的网站访问也可以做到精确分流,提升响应速度。当然这套方案也并不完美,由于国内域名跳过了 OpenClash 也就意味着失去了对它们的限制。不过可以从 DNS 维度对它们进行屏蔽。如果是基于 IP 的,那就只能通过防火墙加以限制了。