标签: R4S

  • Q3000 + R4S 分流进阶:方案 B 的 Mihomo 全权 DNS 实战

    Q3000 + R4S 分流进阶:方案 B 的 Mihomo 全权 DNS 实战

    本文是《Q3000 + R4S 分流终极指南:同一套大陆 IP 分流下的两种 DNS 方案》的续篇。上一篇文章对比了方案 A 与方案 B;本文只讲后来正式投入使用的方案 B:客户端网关仍为 Q3000,DNS 仍指向 R4S,但所有 DNS 查询统一交给 Mihomo 分类。本文记录最终结构、完整请求路径、关键 YAML、境外 DNS 通道、切换步骤、验收方法、故障边界和重装恢复。

    一、为什么单独写这篇续篇

    上一篇文章完成时,方案 A 已经稳定运行,方案 B 还只是经过配置验证、尚未正式切换。因此上一篇文章给出的阶段性建议是“生产继续使用方案 A”。

    后续实际测试发生了变化:

    方案 B 已正式切换并持续运行
    淘宝、微信等国内应用正常
    Google、YouTube、TikTok 等国外服务正常
    ssh.cloud.google.com 长连接正常
    Google Play 可以正常下载并完成安装
    services.googleapis.cn 特例已由 YAML 统一处理
    境外 DNS 已增加跨地区专用通道
    旧的四千多条 dnsmasq 代理域名和自定义插件已移除
    

    所以这篇文章不是推翻上一篇,而是把上一篇中的“候选方案 B”补全为一套已经落地、可以备份和重装恢复的正式方案。

    二、先给出最终结论

    当前网络的固定结构如下:

    客户端地址:192.168.10.100-192.168.10.200
    客户端默认网关:192.168.10.1(Q3000)
    客户端 DNS:192.168.10.3(R4S dnsmasq)
    
    Q3000:
    大陆目标 IP → WAN1 直接出网
    其他目标 IP / Fake-IP → 下一跳 192.168.10.3
    
    R4S:
    dnsmasq 的唯一上游 → 127.0.0.1#1053
    
    Mihomo:
    国内域名 → 国内 DNS → 返回真实 IP
    国外域名 → 境外 DNS → 返回 Fake-IP
    特殊域名 → 按 YAML 明确指定 Fake-IP 或真实 IP
    未知域名 → 返回真实 IP,再由 Q3000 按 IP 归属兜底
    

    这套结构可以用一句话概括:

    Mihomo 负责给域名分类和发放地址,Q3000 负责根据最终目标 IP 选择道路,R4S/Nikki/Mihomo 只承载真正需要代理的业务流量。

    方案 B 并不是把国内业务流量全部交给 R4S。国内域名的 DNS 查询经过 Mihomo,但拿到大陆真实 IP 后,真正的淘宝、微信、银行 App 等业务连接仍由 Q3000 直接从 WAN1 出口。

    三、五个组件分别负责什么

    Q3000(主路由)
    ├─ WAN 拨号、NAT、DHCP、VLAN、Wi-Fi 和客户端管理
    ├─ 保存大陆 IPv4 地址库 CN4-A01~CN4-A08
    ├─ 命中大陆 IP:WAN1 直连
    └─ 未命中大陆 IP:下一跳交给 R4S
    
    R4S(硬件设备)
    └─ ImmortalWrt / OpenWrt(操作系统)
       ├─ dnsmasq(监听 192.168.10.3:53,接收全网 DNS 查询)
       ├─ Tailscale(独立的远程组网服务)
       └─ Nikki(管理和启动代理配置的插件)
          └─ Mihomo(实际执行 DNS、Fake-IP、规则和代理连接的内核)
    

    再用最通俗的比喻说明:

    • dnsmasq 是对外营业的 DNS 前台,客户端只认识它。
    • Mihomo DNS 是后台判断员,决定返回真实 IP 还是 Fake-IP。
    • Q3000 是总路口,看到最终目标 IP 后决定走 WAN1 还是 R4S。
    • Nikki 是 Mihomo 的管理系统,不负责亲自转发每一个数据包。
    • Zashboard 是观察和选择策略的控制面板,也不是转发内核。

    四、方案 B 与旧方案 A 到底差在哪里

    方案 A:dnsmasq 先用四千多个域名分类

    客户端 DNS 查询
      ↓
    R4S dnsmasq
      ├─ 命中约四千多个代理域名 → Mihomo DNS
      ├─ 命中自定义插件域名 → Mihomo DNS
      └─ 其余域名 → 国内普通 DNS
    

    这种方式的优点是普通国内 DNS 不依赖 Mihomo;缺点是分类逻辑分散在自动域名表、更新脚本、自定义插件和 YAML 多处。

    方案 B:dnsmasq 不再分类,全部交给 Mihomo

    客户端 DNS 查询
      ↓
    R4S dnsmasq
      ↓ 所有域名
    127.0.0.1:1053
      ↓
    Mihomo DNS 按 YAML 统一分类
    

    因此方案 B 中已经不再需要:

    /etc/dnsmasq.d/gwf-gfwlist.conf
    /etc/dnsmasq.d/gwf-ui.conf
    /usr/local/sbin/update-gfw-dnsmasq
    每天更新代理域名的 cron 任务
    “域名分流”LuCI 插件
    

    这些组件必须先备份、验证方案 B 后再移除,不能一上来直接删除。

    五、Q3000 的 IP 分流仍然是核心

    方案 B 只替换 DNS 分类方法,Q3000 的两条核心规则没有改变。

    规则 1:大陆 IP 直接出网

    名称:CodexCNDirect
    来源:192.168.10.100-192.168.10.200
    目标:CN4-A01~CN4-A08
    出口:WAN1
    优先级:高于下一条兜底规则
    

    规则 2:其他地址交给 R4S

    名称:CodexR4S
    来源:192.168.10.100-192.168.10.200
    目标:任意
    下一跳:192.168.10.3
    优先级:低于 CodexCNDirect
    

    八个 CN4 分组只是大陆 IPv4 数据库。真正触发分流的是 CodexCNDirect 对这些分组的引用,而不是导入 IP 数据后自动发生魔法。

    “被引用次数 1”表示有一条规则正在使用该分组,不表示访问次数。访问淘宝一万次,它仍然是 1。

    这里还有两个不能省略的前提:

    1. Q3000 的 DHCP 固定地址和动态地址池必须落在这两条规则声明的来源范围内;超出 192.168.10.100-192.168.10.200 的客户端不会自动套用这套分流,需要同步扩大来源范围或增加规则。
    2. R4S 自身地址 192.168.10.3 不能包含在 CodexR4S 的来源范围内。Mihomo 建立到代理节点的连接时,来源是 R4S;排除它以后,Q3000 才会把该连接直接从 WAN1 发出,而不会再次送回 R4S 形成循环。

    六、方案 B 的核心 DNS 配置

    下面是当前实测配置中与方案 B 有关的部分。节点、订阅、控制密钥等私密内容不在本文展示。

    dns:
      enable: true
      cache-algorithm: arc
      listen: 0.0.0.0:1053
      ipv6: false
      respect-rules: true
      enhanced-mode: fake-ip
      fake-ip-range: 198.18.0.1/16
      fake-ip-filter-mode: rule
    
      default-nameserver:
        - 223.5.5.5
        - 119.29.29.29
    
      proxy-server-nameserver:
        - https://dns.alidns.com/dns-query
        - https://doh.pub/dns-query
    
      direct-nameserver:
        - https://dns.alidns.com/dns-query
        - https://doh.pub/dns-query
    
      direct-nameserver-follow-policy: true
    
      nameserver-policy:
        "rule-set:cn_domain":
          - https://dns.alidns.com/dns-query
          - https://doh.pub/dns-query
        "rule-set:geolocation-!cn":
          - https://8.8.8.8/dns-query#境外DNS通道
          - https://1.1.1.1/dns-query#境外DNS通道
    
      nameserver:
        - https://8.8.8.8/dns-query#境外DNS通道
        - https://1.1.1.1/dns-query#境外DNS通道
    
      fake-ip-filter:
        - DOMAIN,services.googleapis.cn,fake-ip
        - RULE-SET,fakeipfilter_domain,real-ip
        - RULE-SET,cn_domain,real-ip
        - RULE-SET,geolocation-!cn,fake-ip
        - MATCH,real-ip
    

    注意:#境外DNS通道 不是 YAML 注释。它是 Mihomo 在 DNS 上游地址后使用的策略组标记,表示访问这个 DoH 上游时必须经过名为“境外DNS通道”的代理组。

    七、五类 DNS 配置是什么关系

    这些名称容易让人误以为存在简单的上下级关系。实际上,它们是 Mihomo 在不同场景调用的不同 DNS 角色。

    1. default-nameserver

    default-nameserver:
      - 223.5.5.5
      - 119.29.29.29
    

    它负责最基础的启动解析,例如先解析其他 DoH 服务器自身的域名。这里使用可在大陆直连的纯 IP DNS,避免 Mihomo 刚启动时需要“先解析 DNS 服务器,才能使用 DNS 服务器”的循环。

    2. proxy-server-nameserver

    proxy-server-nameserver:
      - https://dns.alidns.com/dns-query
      - https://doh.pub/dns-query
    

    它专门解析代理节点服务器的域名。

    假设订阅中的节点地址是:

    sg-node.example.com
    

    Mihomo 必须先知道这个节点域名对应的真实 IP,才能连上节点。这里使用阿里和腾讯的国内 DoH,即使全部代理节点当前都不可用,Mihomo 仍然可以查到各节点服务器的 IP,并在节点恢复后重新连接。

    3. direct-nameserver

    它用于直连流量需要重新解析域名时的国内 DNS。国内服务不需要绕到 Google DNS 或 Cloudflare DNS 查询。

    4. nameserver-policy

    它按域名规则集选择上游:

    命中 cn_domain → 阿里 / 腾讯 DNS
    命中 geolocation-!cn → Google / Cloudflare DNS,并经过境外DNS通道
    

    5. nameserver

    它是没有被更具体策略选中的默认业务 DNS。在本方案中使用 Google 和 Cloudflare DoH,并明确绑定“境外DNS通道”。

    所以它们不是“一个覆盖另一个”的单一优先级列表,而是:

    启动解析 → default-nameserver
    代理节点域名 → proxy-server-nameserver
    直连重解析 → direct-nameserver
    已知域名分类 → nameserver-policy
    其余普通查询 → nameserver
    

    八、fake-ip-filter-mode: rule 为什么关键

    旧配置常见的是:

    fake-ip-filter-mode: blacklist
    

    在 blacklist 模式下,fake-ip-filter 更像“不使用 Fake-IP 的例外名单”。这不适合本方案,因为我们需要明确表达四种结果:国内真实 IP、国外 Fake-IP、兼容性域名真实 IP、特殊国外服务强制 Fake-IP。

    规则模式会从上到下判断,第一条命中即停止:

    - DOMAIN,services.googleapis.cn,fake-ip
    

    Google Play 特例优先返回 Fake-IP。

    - RULE-SET,fakeipfilter_domain,real-ip
    

    局域网发现、时间同步和部分不兼容 Fake-IP 的域名返回真实 IP。

    - RULE-SET,cn_domain,real-ip
    

    已知国内域名返回真实 IP,让 Q3000 可以命中大陆 IP 库。

    - RULE-SET,geolocation-!cn,fake-ip
    

    已知国外域名返回 Fake-IP,使 Q3000 稳定地把后续业务连接交给 R4S。

    - MATCH,real-ip
    

    无法确定的新域名保守地返回真实 IP,最后由 Q3000 的大陆 IP 库判断走 WAN1 还是 R4S。

    必须再次强调:

    fake-ip-filter 只决定 DNS 回答是真实 IP 还是 Fake-IP,不直接等于 DIRECT 或 PROXY。真正的业务连接到达 R4S 后,还要由 YAML 的正式 rules: 再判断一次。

    九、国内服务的完整闭环

    下面以手机打开淘宝为例,把 DNS 阶段和真实流量阶段完整分开。

    第一阶段:查询淘宝的 IP

    淘宝 App(准备访问 taobao.com)
      ↓
    手机系统 DNS 缓存(检查是否已有未过期答案)
      ↓ 缓存没有可用答案
    手机网络系统(生成查询 taobao.com 的 DNS 数据包)
      ↓
    手机 Wi-Fi 网卡(把 DNS 数据包发给 192.168.10.3)
      ↓
    无线 AP / K2P(只负责局域网二层转发)
      ↓
    R4S 网卡(收到目标端口为 53 的 DNS 查询)
      ↓
    R4S Linux 网络系统(把 53 端口数据交给 dnsmasq)
      ↓
    dnsmasq(检查本地缓存;没有答案时把查询全部转发到 127.0.0.1:1053)
      ↓
    Mihomo DNS(检查自己的 DNS 缓存和 fake-ip-filter 规则)
      ↓
    RULE-SET,cn_domain,real-ip(确认 taobao.com 属于国内域名)
      ↓
    nameserver-policy(选择阿里 DNS 或腾讯 DNS)
      ↓
    国内上游 DNS(返回 taobao.com 的真实大陆 IP)
      ↓
    Mihomo DNS(按 real-ip 要求保留真实 IP,并缓存结果)
      ↓
    dnsmasq(缓存答案并返回手机)
      ↓
    无线 AP / K2P(把 DNS 回应转交手机)
      ↓
    手机系统 DNS 缓存(保存淘宝真实 IP)
      ↓
    淘宝 App(取得真实大陆 IP)
    

    第二阶段:真正访问淘宝

    淘宝 App(向刚取得的大陆真实 IP 发起 HTTPS / QUIC 连接)
      ↓
    手机 Wi-Fi 网卡(把业务数据交给默认网关 192.168.10.1)
      ↓
    无线 AP / K2P(把数据转交 Q3000)
      ↓
    Q3000(读取来源 IP 和目标 IP)
      ↓
    CodexCNDirect(目标 IP 命中 CN4-A01~CN4-A08)
      ↓
    Q3000 WAN1 与 NAT(把客户端私网地址转换为宽带出口地址)
      ↓
    淘宝服务器(接收请求并返回内容)
      ↓
    Q3000 连接跟踪与 NAT 还原(确认回应属于原手机连接)
      ↓
    无线 AP / K2P(把回应转交手机)
      ↓
    淘宝 App(收到页面、图片和视频数据)
    

    结论:Mihomo 参加了淘宝的 DNS 判断,但淘宝真正的大流量没有经过代理节点。

    十、国外服务的完整闭环

    下面以手机访问 YouTube 为例。

    第一阶段:查询 YouTube 的 IP

    YouTube App(准备访问 youtube.com)
      ↓
    手机系统 DNS 缓存(没有可用答案)
      ↓
    手机网络系统(把 DNS 查询发给 192.168.10.3)
      ↓
    无线 AP / K2P(转交 R4S)
      ↓
    R4S dnsmasq(把查询转给 127.0.0.1:1053)
      ↓
    Mihomo DNS(检查 fake-ip-filter)
      ↓
    RULE-SET,geolocation-!cn,fake-ip(确认是非国内域名)
      ↓
    Mihomo Fake-IP 映射表(分配并记录 198.18.x.x = youtube.com)
      ↓
    Mihomo DNS(把 Fake-IP 返回 dnsmasq)
      ↓
    dnsmasq(把 Fake-IP 返回手机)
      ↓
    手机系统 DNS 缓存(保存 198.18.x.x)
      ↓
    YouTube App(取得 Fake-IP)
    

    这里返回 Fake-IP 时,Mihomo 不需要先把 YouTube 的真实 IP 交给手机。它记录了 Fake-IP 与域名的映射,稍后再根据域名规则建立代理连接。

    第二阶段:真正播放 YouTube

    YouTube App(向 198.18.x.x 的 443 端口发起 HTTPS / QUIC 连接)
      ↓
    手机 Wi-Fi 网卡(把业务数据交给默认网关 192.168.10.1)
      ↓
    Q3000(发现 Fake-IP 不属于大陆 IPv4 库)
      ↓
    CodexR4S(把连接下一跳交给 192.168.10.3)
      ↓
    R4S Linux 防火墙 / Nikki 透明代理规则(截获应该由 Mihomo 处理的连接)
      ↓
    Mihomo 内核(从 Fake-IP 映射表还原 youtube.com)
      ↓
    Mihomo rules(匹配 youtube_domain)
      ↓
    YouTube 策略组(选择当前节点或地区组)
      ↓
    Mihomo(通过代理节点建立到 YouTube / googlevideo CDN 的真实连接)
      ↓
    R4S 默认路由(把代理节点连接发给 Q3000)
      ↓
    Q3000(来源是 R4S,不再折返给 R4S,直接从 WAN1 出网)
      ↓
    代理节点 → YouTube / googlevideo CDN
      ↓
    视频数据沿代理隧道返回 Mihomo
      ↓
    Mihomo → R4S 局域网接口 → Q3000 / K2P 交换路径 → 手机
      ↓
    YouTube App(解码并播放视频)
    

    十一、Google Play 为什么需要单独一条规则

    services.googleapis.cn 虽然以 .cn 结尾,但它属于 Google Play 的服务链。若按普通国内域名处理,它可能返回大陆真实 IP,Q3000 随即让它直连;而账号、控制接口和其他下载 CDN 又可能走代理,最终造成同一次下载出口不一致,表现为一直等待、卡在 1% 或完全无法下载。

    因此它必须放在 cn_domain 之前:

    fake-ip-filter:
      - DOMAIN,services.googleapis.cn,fake-ip
      - RULE-SET,fakeipfilter_domain,real-ip
      - RULE-SET,cn_domain,real-ip
    

    完整闭环如下:

    Google Play(查询 services.googleapis.cn)
      ↓
    dnsmasq → Mihomo DNS
      ↓
    第一条精确规则强制返回 Fake-IP
      ↓
    手机向 Fake-IP 建立连接
      ↓
    Q3000 不命中大陆 IP 库 → CodexR4S
      ↓
    R4S / Nikki / Mihomo 还原域名
      ↓
    正式 rules 命中 Google 策略组
      ↓
    Google Play 控制连接和下载连接保持一致的代理出口
      ↓
    下载进度超过 1% 并完成安装
    

    这也是方案 B 移除旧“域名分流”插件后,仍能正常使用 Google Play 的关键。

    十二、为什么增加“境外DNS通道”

    国外域名会使用:

    https://8.8.8.8/dns-query
    https://1.1.1.1/dns-query
    

    在大陆网络中,不能假设它们始终可以稳定直连。若它们跟随普通“默认代理”,DNS 能否工作就会依赖默认策略当时选中的单一地区或节点。

    因此单独建立一个只服务于境外 DNS 的跨地区组:

    proxy-groups:
      - name: 境外DNS通道
        type: fallback
        url: https://www.gstatic.com/generate_204
        interval: 60
        lazy: false
        proxies:
          - 新加坡-故转
          - 香港-故转
          - 日本-故转
          - 台湾-故转
          - 美国-故转
    

    然后把境外 DoH 明确绑定到它:

    - https://8.8.8.8/dns-query#境外DNS通道
    - https://1.1.1.1/dns-query#境外DNS通道
    

    它的运行逻辑是:

    每 60 秒主动检测候选通道
      ↓
    优先使用列表中第一个健康地区
      ↓
    当前地区失效
      ↓
    自动切换到下一个健康地区
    

    健康检查使用 Google 的 generate_204,因为这个组的任务就是访问境外 DNS。国内连通性测试只能证明节点“能联网”,不能充分证明它可以稳定访问 Google 或 Cloudflare DNS。

    这个组不放 DIRECT 作为最后候选。原因是大陆直连 8.8.8.8 或 1.1.1.1 并不是可靠兜底,反而会让故障表现变得随机。

    但也要理解它的边界:

    • 一个地区故障:自动换其他地区。
    • 一个节点故障:对应地区组可以继续选择其他健康节点。
    • 所有代理地区全部故障:境外 DNS 仍会失败。
    • Mihomo 进程停止:国内外 DNS 都会失败,因为 dnsmasq 的唯一上游就是 Mihomo。

    “境外DNS通道”提高的是代理节点局部故障时的可用性,不是让完全不可用的节点恢复工作。

    十三、为什么不会形成 DNS 死循环

    常见担心是:

    访问 Google DNS 需要代理
    代理节点域名又需要 DNS
    DNS 还没工作,节点就无法连接
    

    本方案用不同 DNS 角色拆开了这个循环:

    default-nameserver(国内纯 IP DNS)
      ↓ 先解析阿里、腾讯等 DoH 服务器自身域名
    proxy-server-nameserver(国内可直连 DoH)
      ↓ 解析各代理节点服务器域名
    代理节点取得真实 IP并建立连接
      ↓
    境外DNS通道变为可用
      ↓
    8.8.8.8 / 1.1.1.1 DoH 开始解析国外业务域名
    

    即使所有代理节点暂时故障,阿里和腾讯 DNS 仍可以继续解析节点服务器域名。节点一旦恢复,Mihomo 知道应该连接哪个真实 IP,不会因为境外 DNS 不通而永远无法恢复。

    十四、实际切换步骤

    以下步骤适用于已经运行方案 A、准备切换方案 B 的环境。全新安装可以跳过“清理方案 A 组件”,但仍应先备份。

    1. 完整备份

    至少保存:

    /etc/config/dhcp
    /etc/config/nikki
    /etc/nikki/profiles/当前配置.yaml
    /etc/nikki/run/config.yaml
    /etc/crontabs/root
    /etc/dnsmasq.d/gwf-gfwlist.conf
    /etc/dnsmasq.d/gwf-ui.conf
    /usr/local/sbin/update-gfw-dnsmasq
    域名分流插件文件
    Q3000 的 DHCP、IP 分组和两条分流规则
    

    备份必须放到 R4S 之外再保存一份,否则重刷存储卡时设备内备份也会一起消失。

    2. 修改持久 YAML

    应修改 Nikki 的持久配置,例如:

    /etc/nikki/profiles/nikki_optimized_config.yaml
    

    不要只修改:

    /etc/nikki/run/config.yaml
    

    运行配置由 Nikki 生成,重启或重新应用后可能被覆盖。

    把本文第六节的 DNS 片段合并到现有唯一的 dns: 段中。不能在文件底部再增加第二个 dns:。

    同时确保规则集存在:

    rule-providers:
      fakeipfilter_domain:
        type: http
        behavior: domain
        format: mrs
        interval: 86400
        url: "你的可信规则源/fakeip-filter.mrs"
    
      cn_domain:
        type: http
        behavior: domain
        format: mrs
        interval: 86400
        url: "你的可信规则源/cn.mrs"
    
      geolocation-!cn:
        type: http
        behavior: domain
        format: mrs
        interval: 86400
        url: "你的可信规则源/geolocation-!cn.mrs"
    

    3. 先做内核语法校验

    不要直接重启碰运气。使用设备当前 Mihomo 内核检查候选文件:

    /usr/bin/mihomo -t -d /etc/nikki/run -f /tmp/scheme-b-candidate.yaml
    

    看到类似下面的结果才可以继续:

    configuration file ... test is successful
    

    4. 应用 YAML 并重启 Nikki

    建议先准备 5~10 分钟自动回滚,再原子替换持久 YAML,最后只重启 Nikki。

    确认:

    /etc/init.d/nikki status
    

    应返回:

    running
    

    5. 让 dnsmasq 全部转给 Mihomo

    LuCI 路径:

    网络 → DHCP/DNS → 转发 → DNS 转发
    

    只保留:

    127.0.0.1#1053
    

    对应的 UCI 操作为:

    uci -q delete dhcp.@dnsmasq[0].server
    uci add_list dhcp.@dnsmasq[0].server='127.0.0.1#1053'
    uci set dhcp.@dnsmasq[0].noresolv='1'
    uci commit dhcp
    /etc/init.d/dnsmasq restart
    

    截图中看到 127.0.0.1#1053,就表示客户端查询先到 dnsmasq,再统一转给 Mihomo 的 1053 端口。

    6. 验证后再移除方案 A 组件

    先确认淘宝、Google、Google Play 等全部正常,再删除旧四千域名文件、更新脚本、定时任务和自定义插件。删除前必须保留可恢复副本。

    十五、完整验收方法

    1. DNS 返回类型

    在 R4S 上执行:

    nslookup taobao.com 127.0.0.1
    nslookup google.com 127.0.0.1
    nslookup services.googleapis.cn 127.0.0.1
    

    预期结果:

    taobao.com → 真实大陆 IP
    google.com → 198.18.x.x
    services.googleapis.cn → 198.18.x.x
    

    建议再测试:

    baidu.com → 真实大陆 IP
    youtube.com → 198.18.x.x
    

    2. 境外 DNS 通道

    在 Zashboard 的“代理”页面检查:

    境外DNS通道
    类型:Fallback
    状态:Alive
    当前:某个健康地区组
    

    在“连接”页面检查 8.8.8.8 和 1.1.1.1,代理链应包含:

    当前节点 → 地区手动/自动组 → 地区故转组 → 境外DNS通道
    

    3. 应用验收

    □ 淘宝首页、搜索、图片和视频正常
    □ 微信消息、朋友圈图片和小程序正常
    □ 国内银行及生活服务 App 正常
    □ Google 搜索正常
    □ YouTube 首页、缩略图和视频播放正常
    □ TikTok 正常
    □ ssh.cloud.google.com 能完成长连接
    □ Google Play 下载超过 1% 并完成安装
    □ Tailscale 子网访问和出口节点正常
    

    Google Play 不能只测试打开商店首页,必须实际下载并完成一个应用。

    十六、常见现象与排查

    1. Zashboard 中来源为什么都是 192.168.10.1

    Q3000 与 R4S 当前位于同一 LAN。Q3000 把非大陆流量折返给同网段 R4S 时会做连接转换,因此 Mihomo 看到的来源通常是 Q3000,而不是真实手机或电脑 IP。

    这不影响分流和速度,只影响按客户端观察。若一定要保留真实来源,需要为 Q3000 与 R4S 建立独立传输网段,使用第二根网线或 VLAN;那是另一项架构改造,不是方案 B 本身的问题。

    2. 电脑访问 YouTube,为什么 R4S 看不到 YouTube 代理链

    先检查电脑是否开启了 Clash Verge 等本机代理。

    浏览器 → PC Clash → 代理节点
    

    这种情况下,YouTube 已被电脑本机接管,没有把原始 YouTube 连接交给 R4S。R4S 面板只能看到 PC Clash 连接其节点的加密连接,不会显示 YouTube → 节点。

    3. 手机与安卓模拟器表现为什么可能不同

    它们可能具有不同 DNS 缓存、QUIC 连接、Google 服务框架状态和既有长连接。修改 DNS 后应关闭并重新打开目标 App;必要时断开 Wi-Fi 后重新连接。不要把一次旧连接的结果当成新配置的最终判断。

    4. 为什么页面出现 iosapps.itunes.apple.com

    这是 Apple App Store 或系统内容下载域名,不是 YouTube 视频域名。判断大流量属于谁,必须同时看主机名、规则、代理链和实际设备状态,不能只凭下载速度猜测。

    5. 专用应用策略为什么偶尔显示“默认代理”

    Mihomo 的正式 rules: 从上到下匹配,第一条命中就停止。如果一个宽泛规则集排在 YouTube、Apple、Google 等专用规则之前,它可能提前接走连接。

    需要专用策略组严格生效时,应把更具体的规则放在更宽泛的规则之前,并在修改后重新运行 Mihomo 语法校验和应用测试。

    十七、方案 B 的故障边界

    Mihomo 正常,某个代理节点故障

    国内 DNS → 阿里 / 腾讯 DNS → 正常
    国内真实流量 → Q3000 WAN1 → 正常
    境外 DNS → 境外DNS通道自动切换地区
    

    全部代理节点故障,但 Mihomo 仍在运行

    国内 DNS → 仍可由国内上游解析
    国内真实流量 → 仍可由 Q3000 WAN1 直连
    境外 DNS / 国外代理访问 → 失败
    代理节点域名 → 仍可由 proxy-server-nameserver 解析
    

    Mihomo 进程停止

    dnsmasq 仍监听 192.168.10.3:53
    但唯一上游 127.0.0.1:1053 不可用
    国内外新域名都无法解析
    已有缓存和既有长连接可能暂时继续工作
    

    R4S 断电或网线断开

    客户端 DNS 固定为 192.168.10.3,所以新域名都无法解析。这个物理故障不属于 DNS 规则能够解决的范围。

    因此方案 B 的真实取舍是:

    配置集中、覆盖完整、重装简单,但 Mihomo 成为全网 DNS 的关键服务。

    十八、备份、回退与重装恢复

    方案 B 的最小恢复清单

    1. 安装 ImmortalWrt / OpenWrt 与 Nikki
    2. 导入已经验证过的 Mihomo YAML
    3. 确认 Mihomo DNS 监听 0.0.0.0:1053
    4. dnsmasq 唯一上游设置为 127.0.0.1#1053
    5. 确认 fake-ip-filter-mode 为 rule
    6. 确认 services.googleapis.cn 位于 cn_domain 之前
    7. 恢复境外DNS通道
    8. 确认 Q3000 八个 CN4 分组与两条分流规则仍存在
    9. 完成 DNS、国内应用、国外应用和 Google Play 验收
    

    回退到方案 A 时需要恢复

    旧 Nikki YAML
    旧 /etc/config/dhcp
    四千多条 dnsmasq 代理域名文件
    自定义域名例外文件
    自动更新脚本与 cron 任务
    域名分流 LuCI 插件
    

    最可靠的做法不是现场凭记忆重建,而是提前准备一键备份、一键应用和一键回退脚本,并在执行网络修改前设置定时自动回滚。

    十九、日常维护建议

    每月检查

    □ Nikki 与 Mihomo 正常运行
    □ 127.0.0.1:1053 正常监听
    □ 境外DNS通道状态为 Alive
    □ taobao.com 返回真实 IP
    □ google.com 返回 Fake-IP
    □ services.googleapis.cn 返回 Fake-IP
    □ Google Play 实际下载正常
    □ Q3000 的 CN4 分组仍被 CodexCNDirect 引用
    

    更新 YAML 或订阅后检查

    □ 节点域名仍能被 proxy-server-nameserver 解析
    □ 地区组名称没有改变
    □ 境外DNS通道引用的五个地区组仍存在
    □ 应用专用规则没有被更宽泛规则提前截获
    □ Nikki 混入设置没有覆盖 YAML 中的 DNS 配置
    

    大陆 IPv4 库

    当前八个 CN4 分组是保存在 Q3000 内部的地址数据,访问时不依赖外部脚本。但一次性导入的快照不会自动跟随地址分配变化,长期使用应增加定期同步、差异检查和自动备份。

    二十、可直接交给 Codex 的提示词

    1. 切换方案 B

    请先完整备份 Q3000 与 R4S 当前配置,并准备定时自动回滚。保持客户端网关 192.168.10.1、DNS 192.168.10.3,以及 Q3000 的 CodexCNDirect/CodexR4S 规则不变。把 R4S dnsmasq 的唯一上游改为 127.0.0.1#1053,并在现有 Nikki YAML 的唯一 dns: 段中启用 fake-ip-filter-mode: rule。国内域名返回 real-ip,非中国域名返回 fake-ip,services.googleapis.cn 必须在 cn_domain 前强制 fake-ip。增加跨地区“境外DNS通道”,让 8.8.8.8 和 1.1.1.1 DoH 明确经过该组。先用当前 Mihomo 内核校验候选配置,应用后验证淘宝、Google、Google Play 和实际代理链;全部通过后再移除旧四千域名、更新任务和域名分流插件。
    

    2. 诊断国内应用变慢

    请保持现有 Q3000 + R4S 方案 B 不变,分别检查 DNS 阶段和真实业务流量阶段。确认目标国内域名是否命中 cn_domain 并返回真实大陆 IP,Q3000 是否命中 CodexCNDirect,真实流量是否从 WAN1 直出。不要只根据 Zashboard 是否出现连接判断,也不要未经验证修改节点或全局 DNS。
    

    3. 诊断国外服务打不开

    请检查该服务实际使用的主域名、子域名、CNAME 和 CDN 域名;确认 DNS 返回 Fake-IP 还是实际 IP,Q3000 是否把连接送到 R4S,Mihomo 的正式 rules 命中了哪个规则集和策略组,境外DNS通道是否健康。对比 PC Clash 与 R4S 使用同一节点时的 DNS、QUIC、IPv6、MTU 和代理链,不要先假设是节点问题。
    

    4. 重装后恢复

    请在全新 R4S 上恢复方案 B:安装 Nikki,导入已验证 YAML,确认 Mihomo DNS 监听 1053,把 dnsmasq 唯一上游设置为 127.0.0.1#1053,验证 domestic real-ip、foreign fake-ip、services.googleapis.cn fake-ip 和境外DNS通道。保持 Q3000 的大陆 IP 分流规则不变。所有敏感密钥、订阅和节点凭据从备份恢复,不要输出到日志或文章。
    

    二十一、最终总结

    方案 B 最容易被误解为“所有流量都经过 Mihomo”。准确说法是:

    所有 DNS 查询都经过 Mihomo 分类
    但不是所有真实业务流量都经过 Mihomo
    

    国内服务:

    DNS → R4S dnsmasq → Mihomo → 国内 DNS → 真实大陆 IP
    业务流量 → Q3000 → CodexCNDirect → WAN1
    

    国外服务:

    DNS → R4S dnsmasq → Mihomo → Fake-IP
    业务流量 → Q3000 → CodexR4S → R4S/Nikki/Mihomo → 代理节点
    

    特殊服务:

    services.googleapis.cn → YAML 第一条规则强制 Fake-IP → Google 策略组
    

    境外 DNS:

    8.8.8.8 / 1.1.1.1 DoH → 境外DNS通道 → 跨地区自动切换
    

    整套方案真正稳定的原因,不是某一份域名名单足够长,而是每层职责都很清楚:

    • Mihomo 负责 DNS 分类、Fake-IP 映射和代理规则。
    • Q3000 负责根据大陆 IP 数据库选择真实道路。
    • dnsmasq 负责为全网客户端提供统一 DNS 入口。
    • Nikki 负责持久配置和 Mihomo 生命周期。
    • 境外DNS通道负责降低单一地区或节点故障对国外解析的影响。

    理解这五层之后,遇到问题就可以准确判断它发生在“域名解析、IP 选路、透明接管、代理规则还是节点连接”,不再把所有故障都笼统归结为“网络慢”或“节点不行”。

  • Q3000 + R4S 分流终极指南:同一套大陆 IP 分流下的两种 DNS 方案

    Q3000 + R4S 分流终极指南:同一套大陆 IP 分流下的两种 DNS 方案

    客户端默认网关使用 Q3000 192.168.10.1,DNS 使用 R4S 192.168.10.3。Q3000 根据大陆 IPv4 库决定国内流量直接走 WAN,其余流量交给 R4S/Nikki/Mihomo。本文完整比较两种 DNS 子方案:已经验证运行的“dnsmasq 选择性转发”,以及配置更集中的“Mihomo 全权解析”。

    一、先给出结论

    本文讨论的不是两套完全不同的网络,而是同一个大方案下的两种 DNS 实现。

    大方案始终不变:

    客户端 IP:192.168.10.100-192.168.10.200
    默认网关:192.168.10.1(Q3000)
    DNS:192.168.10.3(R4S dnsmasq)
    
    Q3000 判断目标 IP:
    大陆 IP → WAN1 直接出网
    其他 IP → 下一跳 192.168.10.3 → R4S/Nikki/Mihomo
    

    两种 DNS 子方案如下:

    子方案 DNS 的第一判断者 国内 DNS 是否依赖 Mihomo 手工维护内容 当前状态
    A:dnsmasq 选择性转发 dnsmasq 否 services.googleapis.cn 一条例外 已验证,正在使用
    B:Mihomo 全权解析 Mihomo 是 Nikki YAML 可行,但尚未切换

    当前更推荐方案 A。它已经解决淘宝、微信、Google、YouTube、Google SSH、Muse、Google Play 等实际问题,而且 Nikki/Mihomo 单独停止时,普通国内 DNS 仍可工作。

    方案 B 的优点是配置集中、重装项目更少;代价是 Mihomo 会成为全网 DNS 的单点。它适合愿意为配置统一性接受这一故障范围的人。

    二、先分清 Q3000、R4S、Nikki、Mihomo 和 dnsmasq

    Q3000(主路由)
    ├─ 负责 WAN 拨号和 NAT
    ├─ 负责 DHCP、Wi-Fi、VLAN 和客户端管理
    ├─ 保存大陆 IPv4 分组
    └─ 根据目标 IP 决定 WAN1 直连或下一跳 R4S
    
    R4S(硬件设备)
    └─ ImmortalWrt/OpenWrt(操作系统)
       ├─ dnsmasq(监听 192.168.10.3:53,接收客户端 DNS 查询)
       ├─ Tailscale(独立的组网服务)
       └─ Nikki(代理管理插件)
          └─ Mihomo(真正执行 DNS、Fake-IP、规则匹配和代理连接的核心)
    

    用通俗的话说:

    • Q3000 是总路口,负责决定真实业务流量往哪里走。
    • dnsmasq 是 DNS 前台,负责接收客户端“这个域名对应什么 IP”的问题。
    • Nikki 是管理 Mihomo 的控制系统,不是代理内核本身。
    • Mihomo 才是代理内核,也可以提供 DNS 和 Fake-IP 服务。
    • Zashboard 只是 Mihomo 的控制面板,不负责实际转发。

    “数据包到达 R4S”不等于“已经使用代理节点”。数据包还要被 Nikki 的透明代理规则接管,再由 Mihomo 根据 YAML 规则决定使用代理或 DIRECT。

    三、Q3000 的大陆 IP 分流如何触发

    1. 大陆 IP 数据放在哪里

    Q3000 中保存了约 6200 条大陆 IPv4 网段。为了适应设备的对象容量,它们被拆成八个 IP 分组:

    CN4-A01
    CN4-A02
    CN4-A03
    CN4-A04
    CN4-A05
    CN4-A06
    CN4-A07
    CN4-A08
    

    这些分组只是“地址资料库”,本身不会主动改变流量方向。

    2. 真正引用 IP 库的是两条规则

    Q3000 当前的核心规则是:

    优先级 0:CodexCNDirect
    来源地址:192.168.10.100-192.168.10.200
    目标地址:CN4-A01~CN4-A08
    动作:WAN1 直接出网
    
    优先级 1:CodexR4S
    来源地址:192.168.10.100-192.168.10.200
    目标地址:任意
    动作:下一跳 192.168.10.3
    

    客户端每建立一个连接,Q3000 都会用数据包中的“来源 IP”和“目标 IP”匹配规则:

    先检查 CodexCNDirect
      ↓
    目标 IP 属于大陆 IPv4 库
      → WAN1 直接出网
    
    目标 IP 不属于大陆 IPv4 库
      ↓
    继续检查 CodexR4S
      → 下一跳交给 R4S
    

    匹配工作由 Q3000 自己的路由引擎实时完成,不需要电脑脚本持续运行。此前的脚本只负责下载 IP 库、创建八个对象并建立两条引用规则。

    3. “被引用次数 1”不是访问次数

    IP 分组中的“被引用次数”表示有多少条配置规则正在使用这个分组:

    CN4-A01 被 CodexCNDirect 引用
    → 被引用次数为 1
    

    访问淘宝一万次仍然是 1。只有再创建一条规则并引用 CN4-A01,它才会变成 2。真正的流量和连接数量应在 Q3000 的终端监控、连接监控或流量统计中查看。

    四、一次上网请求其实分为两个阶段

    很多误解来自把 DNS 查询和网页流量混成一件事。实际上每次访问通常包含两个阶段。

    第一阶段是查询地址:

    “taobao.com 对应哪个 IP?”
    

    第二阶段才是真正访问:

    “向刚才得到的 IP 建立 TCP、TLS、QUIC 或其他连接。”
    

    DNS 服务器只负责回答地址,不承担网页、视频和下载数据。默认网关只处理真正的数据连接,不负责替客户端理解域名。

    下面分别展开两种 DNS 子方案。

    五、方案 A:dnsmasq 选择性转发

    这是当前已经验证、正在使用的方案。

    1. 核心结构

    所有客户端都向 192.168.10.3:53 查询 DNS,但 dnsmasq 会先分类:

    客户端 DNS 查询
      ↓
    R4S dnsmasq
      ├─ 命中自动代理域名表
      │    → 127.0.0.1:1053 → Mihomo DNS
      │
      ├─ 命中自定义插件例外
      │    → 127.0.0.1:1053 → Mihomo DNS
      │
      └─ 没有命中
           → 223.5.5.5 / 223.6.6.6
           → 返回真实 IP
    

    自动代理域名表来自 Loyalsoldier 的 gfw.txt,当前约 4393 条,通过以下程序每天更新:

    更新程序:/usr/local/sbin/update-gfw-dnsmasq
    定时任务:每天 04:17
    生成文件:/etc/dnsmasq.d/gwf-gfwlist.conf
    

    更新程序会拒绝安装少于 3000 条的不完整列表。因此这四千多条不需要人工逐条维护。

    自定义插件只维护自动列表没有收录的特殊例外:

    服务 → 域名分流
    当前只保留:services.googleapis.cn
    数据文件:/etc/dnsmasq.d/gwf-ui.conf
    

    2. 国内请求:第一阶段,DNS 查询

    以手机打开淘宝为例:

    淘宝 App(准备访问 taobao.com)
      ↓
    手机系统 DNS 缓存(检查是否已有未过期答案)
      ↓ 缓存没有可用答案
    手机网络系统(生成查询 taobao.com 的 DNS 数据包)
      ↓
    手机 Wi-Fi 网卡(把 DNS 数据包发送给 DNS 服务器 192.168.10.3)
      ↓
    无线 AP / K2P(只负责交换和转发局域网数据)
      ↓
    R4S 网卡(收到目标端口为 53 的 DNS 查询)
      ↓
    R4S Linux 网络系统(把本机 53 端口查询交给 dnsmasq)
      ↓
    dnsmasq(检查本地缓存、Hosts、自动代理域名表和插件例外)
      ↓ taobao.com 没有命中代理域名表
    dnsmasq(把查询发给默认上游 223.5.5.5 或 223.6.6.6)
      ↓
    R4S 默认路由(把上游 DNS 查询交给 Q3000 192.168.10.1)
      ↓
    Q3000 WAN(将查询发送到互联网中的国内 DNS)
      ↓
    国内上游 DNS(返回 taobao.com 的真实 IP)
      ↓
    Q3000(收到 DNS 回应并转回 R4S)
      ↓
    R4S dnsmasq(缓存答案,并生成发往手机的 DNS 回应)
      ↓
    无线 AP / K2P(把局域网回应转交手机)
      ↓
    手机系统 DNS 缓存(保存 taobao.com 的真实 IP)
      ↓
    淘宝 App(取得真实大陆 IP)
    

    这一阶段 R4S 参与了 DNS,但 Mihomo 没有参与。

    3. 国内请求:第二阶段,真实业务流量

    淘宝 App(向刚才得到的真实大陆 IP 发起 HTTPS/QUIC 连接)
      ↓
    手机网络系统(发现目标不在本地网段,需要交给默认网关)
      ↓
    手机 Wi-Fi 网卡(把真实业务数据发给默认网关 192.168.10.1)
      ↓
    无线 AP / K2P(把数据转交 Q3000)
      ↓
    Q3000(读取来源 IP 和目标 IP)
      ↓
    CodexCNDirect(发现目标 IP 位于 CN4-A01~CN4-A08)
      ↓
    Q3000 WAN1 与 NAT(把客户端私网地址转换成宽带出口地址)
      ↓
    运营商网络(把连接送到淘宝服务器)
      ↓
    淘宝服务器(返回网页、图片、视频或接口数据)
      ↓
    Q3000 连接跟踪与 NAT 还原(确认回应属于原客户端)
      ↓
    无线 AP / K2P(把回应转交手机)
      ↓
    淘宝 App(收到真实业务数据)
    

    真正的淘宝流量没有进入 R4S、Nikki 或 Mihomo。

    4. 国外请求:第一阶段,DNS 查询

    以手机打开 Google 为例:

    浏览器或 Google App(准备访问 google.com)
      ↓
    手机系统 DNS 缓存(没有可用答案)
      ↓
    手机网络系统(生成查询 google.com 的 DNS 数据包)
      ↓
    手机 Wi-Fi 网卡(发送给 DNS 服务器 192.168.10.3)
      ↓
    无线 AP / K2P(转交 R4S)
      ↓
    R4S 网卡与 Linux 网络系统(把 53 端口查询交给 dnsmasq)
      ↓
    dnsmasq(发现 google.com 命中自动代理域名表)
      ↓
    dnsmasq(把查询转交本机 127.0.0.1:1053)
      ↓
    Mihomo DNS(检查 DNS 缓存、nameserver-policy 和 Fake-IP 规则)
      ↓
    Mihomo Fake-IP 映射表(为 google.com 分配并记录 198.18.x.x)
      ↓
    Mihomo DNS(把 198.18.x.x 返回给 dnsmasq)
      ↓
    dnsmasq(把 Fake-IP 回答发送给手机)
      ↓
    手机系统 DNS 缓存(记录 google.com = 198.18.x.x)
      ↓
    浏览器或 Google App(取得 Fake-IP)
    

    Fake-IP 不是 Google 的真实服务器地址,而是 Mihomo 给该域名发放的内部号码牌。

    5. 国外请求:第二阶段,真实业务流量

    浏览器或 Google App(向 198.18.x.x:443 发起 HTTPS/QUIC 连接)
      ↓
    手机网络系统(把连接交给默认网关 192.168.10.1)
      ↓
    无线 AP / K2P(转交 Q3000)
      ↓
    Q3000(检查目标 IP)
      ↓
    CodexCNDirect(198.18.x.x 不属于大陆 IP 库,因此不匹配)
      ↓
    CodexR4S(兜底匹配,将连接的下一跳设为 192.168.10.3)
      ↓
    R4S 网卡(收到 Q3000 转来的业务连接)
      ↓
    Nikki 防火墙与透明代理规则(把连接交给 Mihomo)
      ↓
    Mihomo Fake-IP 映射表(查出 198.18.x.x 对应 google.com)
      ↓
    Mihomo 规则引擎(命中 Google 规则和对应策略组)
      ↓
    Mihomo 代理节点(建立加密代理连接)
      ↓
    R4S 默认路由(把代理节点连接交给 Q3000)
      ↓
    Q3000(发现来源是 R4S,不再送回 R4S,直接从 WAN1 出网)
      ↓
    代理节点(代表家庭网络访问 Google 真实服务器)
      ↓
    返回数据沿代理隧道回到 R4S/Mihomo
      ↓
    Mihomo(解密并交还原始客户端连接)
      ↓
    Q3000 / 局域网交换路径(把回应送回手机)
      ↓
    浏览器或 Google App(收到 Google 内容)
    

    6. Google Play 特例的完整流程

    services.googleapis.cn 是国外服务使用中国域名和大陆地址的特殊情况。若按普通国内域名处理,它会返回类似 211.95.34.139 的大陆真实 IP,Q3000 随即直接走 WAN,导致 Google Play 的控制连接和下载连接使用不同出口,下载卡在 1%。

    插件中加入该域名后:

    Google Play(查询 services.googleapis.cn)
      ↓
    R4S dnsmasq(命中插件自定义规则)
      ↓
    Mihomo DNS 1053(返回 198.18.x.x Fake-IP)
      ↓
    手机(向 Fake-IP 发起 Play 下载连接)
      ↓
    Q3000(Fake-IP 不属于大陆 IP,交给 R4S)
      ↓
    Nikki/Mihomo(还原 services.googleapis.cn 并使用 Google 代理策略)
      ↓
    Google Play(正常高速下载)
    

    这一条已经经过多次实际测试:删除就无法下载,恢复后立即正常。

    7. 方案 A 的故障边界

    Mihomo停止,但 R4S 和 dnsmasq 正常
    → 普通国内 DNS 仍可通过 223.5.5.5/223.6.6.6 解析
    → 国内真实流量仍由 Q3000 直接出网
    → 自动代理名单和插件例外无法正常使用
    
    整个 R4S断电或 dnsmasq停止
    → 客户端配置的 DNS 192.168.10.3 不可用
    → 国内外新域名都无法正常解析
    

    因此方案 A 只能隔离“Mihomo 进程故障”,不能抵抗“R4S 整机故障”。

    六、方案 B:所有 DNS 全权交给 Mihomo

    这是一套可行但尚未正式切换的替代方案。它不是让所有真实流量都经过 R4S,而是让所有 DNS 查询都先经过 Mihomo。

    1. 核心结构

    客户端所有 DNS 查询
      ↓
    R4S dnsmasq 192.168.10.3:53
      ↓ 无条件转发
    Mihomo DNS 127.0.0.1:1053
      ↓
    Mihomo 根据规则返回真实 IP 或 Fake-IP
      ↓
    Q3000 根据最终 IP 决定 WAN1 或 R4S
    

    Mihomo不是权威 DNS 数据库。它仍然需要向上游 DNS 查询,只是由它选择上游并决定最终向客户端返回真实 IP 还是 Fake-IP:

    cn_domain → 阿里 DNS / 腾讯 DNS 等国内上游
    geolocation-!cn → Google / Cloudflare 等国外 DoH 上游
    

    2. 为什么不能直接把所有 DNS 转给当前 Mihomo

    当前配置使用:

    fake-ip-filter-mode: blacklist
    

    在 blacklist 模式下,fake-ip-filter 是“不返回 Fake-IP”的例外名单。命中列表返回真实 IP,其他域名默认返回 Fake-IP。

    如果不修改 YAML 就把所有 DNS 都转给 Mihomo,很多没有进入例外名单的国内域名也会获得 Fake-IP,随后被 Q3000 交给 R4S,国内直连优势会被削弱。

    因此需要改成 Mihomo 支持的规则模式:

    dns:
      fake-ip-filter-mode: rule
      fake-ip-filter:
        - DOMAIN,services.googleapis.cn,fake-ip
        - RULE-SET,fakeipfilter_domain,real-ip
        - RULE-SET,cn_domain,real-ip
        - RULE-SET,geolocation-!cn,fake-ip
        - MATCH,real-ip
    

    注意:这段内容应替换现有 dns: 中的 fake-ip-filter-mode 和 fake-ip-filter,不能再增加第二个 dns:。

    持久配置应修改:

    /etc/nikki/profiles/nikki_optimized_config.yaml
    

    不要只修改:

    /etc/nikki/run/config.yaml
    

    后者是 Nikki 生成的运行配置,重启或重新应用配置后可能被覆盖。

    3. 每条规则是什么意思

    - DOMAIN,services.googleapis.cn,fake-ip
    

    精确匹配 Google Play 特例,并在国内域名规则之前强制返回 Fake-IP。

    - RULE-SET,fakeipfilter_domain,real-ip
    

    局域网、设备发现、时间同步等不适合 Fake-IP 的域名返回真实 IP。

    - RULE-SET,cn_domain,real-ip
    

    已知国内域名返回真实 IP,让 Q3000 有机会命中大陆 IP 库并直接出 WAN。

    - RULE-SET,geolocation-!cn,fake-ip
    

    已知非中国域名返回 Fake-IP,确保 Q3000 把连接交给 R4S。

    - MATCH,real-ip
    

    无法按域名判断的新域名返回真实 IP,最后由 Q3000 的大陆 IP 库判断走向。

    当前 Mihomo 为 v1.19.27,支持 fake-ip-filter-mode: rule;现有 fakeipfilter_domain、cn_domain 和 geolocation-!cn 也都是可用于 DNS 规则的 domain 类型规则集。

    这里必须分清两层规则:fake-ip-filter 只决定 DNS 阶段向客户端返回 Fake-IP 还是真实 IP,并不直接等于 PROXY 或 DIRECT。真实业务连接到达 R4S 后,仍由 YAML 中正式的 rules: 从上到下匹配,并由对应策略组决定使用代理节点还是直连。本文让国外域名优先取得 Fake-IP,是为了让 Q3000 稳定地把连接送到 R4S,同时让 Mihomo 能从 Fake-IP 映射表还原域名;最终代理动作仍属于第二阶段。

    4. 国内请求:第一阶段,DNS 查询

    淘宝 App(准备访问 taobao.com)
      ↓
    手机系统 DNS 缓存(没有可用答案)
      ↓
    手机网络系统(向 192.168.10.3 发送 DNS 查询)
      ↓
    无线 AP / K2P(转交 R4S)
      ↓
    R4S dnsmasq(不再检查四千域名,所有查询都转给 127.0.0.1:1053)
      ↓
    Mihomo DNS(从上到下检查 fake-ip-filter 规则)
      ↓
    RULE-SET,cn_domain,real-ip(确认 taobao.com 属于国内域名)
      ↓
    nameserver-policy(选择阿里 DNS 或腾讯 DNS 等国内上游)
      ↓
    国内上游 DNS(返回淘宝真实大陆 IP)
      ↓
    Mihomo DNS(因为规则要求 real-ip,所以把真实 IP 返回给 dnsmasq)
      ↓
    dnsmasq(把真实 IP 返回手机)
      ↓
    手机系统 DNS 缓存(保存淘宝真实 IP)
      ↓
    淘宝 App(取得真实大陆 IP)
    

    这里国内 DNS 也依赖 Mihomo,但真实业务流量仍然可以绕过 R4S。

    5. 国内请求:第二阶段,真实业务流量

    淘宝 App(向真实大陆 IP 发起连接)
      ↓
    手机默认网关 192.168.10.1
      ↓
    Q3000(目标 IP 命中 CN4-A01~CN4-A08)
      ↓
    CodexCNDirect
      ↓
    WAN1 与 NAT
      ↓
    淘宝服务器
      ↓
    Q3000 连接跟踪与 NAT 还原
      ↓
    手机淘宝 App
    

    Mihomo只参加了 DNS,没有承载淘宝业务流量。

    6. 国外请求:第一阶段,DNS 查询

    浏览器或 Google App(查询 google.com)
      ↓
    手机 DNS → R4S dnsmasq
      ↓
    dnsmasq(全部转给 Mihomo DNS 1053)
      ↓
    Mihomo DNS(检查规则)
      ↓
    RULE-SET,geolocation-!cn,fake-ip(确认属于非中国域名)
      ↓
    Mihomo Fake-IP 映射表(生成并记录 198.18.x.x = google.com)
      ↓
    Mihomo DNS → dnsmasq → 手机
      ↓
    手机系统 DNS 缓存(保存 Fake-IP)
    

    7. 国外请求:第二阶段,真实业务流量

    浏览器或 Google App(向 198.18.x.x 发起连接)
      ↓
    手机默认网关 192.168.10.1
      ↓
    Q3000(Fake-IP 不属于大陆 IP 库)
      ↓
    CodexR4S(下一跳 192.168.10.3)
      ↓
    R4S Nikki 透明代理
      ↓
    Mihomo(通过 Fake-IP 映射还原 google.com)
      ↓
    Mihomo规则引擎(选择 Google 策略组和代理节点)
      ↓
    Q3000 WAN1 → 代理节点 → Google
      ↓
    回应经代理隧道返回 Mihomo
      ↓
    Mihomo → 局域网 → 手机
    

    8. Google Play 特例:两个阶段

    第一阶段:

    Google Play(查询 services.googleapis.cn)
      ↓
    dnsmasq(全部转给 Mihomo)
      ↓
    Mihomo首先命中 DOMAIN,services.googleapis.cn,fake-ip
      ↓
    因为该规则位于 cn_domain 之前,所以强制返回 Fake-IP
      ↓
    手机取得 198.18.x.x
    

    第二阶段:

    Google Play(向 Fake-IP 建立下载连接)
      ↓
    Q3000(不命中大陆 IP 库)
      ↓
    CodexR4S → R4S/Nikki/Mihomo
      ↓
    Mihomo还原 services.googleapis.cn 并使用 Google 代理策略
      ↓
    Google Play 正常下载
    

    因此方案 B 不再需要域名分流插件维护这一条规则。

    9. 未识别域名:两个阶段

    第一阶段:

    客户端查询一个新域名
      ↓
    Mihomo没有命中 cn_domain 或 geolocation-!cn
      ↓
    MATCH,real-ip
      ↓
    Mihomo通过默认安全上游取得真实 IP
      ↓
    把真实 IP 返回客户端
    

    第二阶段:

    客户端向真实 IP 发起连接
      ↓
    Q3000检查大陆 IPv4 库
      ├─ 属于大陆 → WAN1
      └─ 不属于大陆 → R4S/Nikki/Mihomo
    

    这让 Q3000 的 IP 数据库成为域名规则没有覆盖时的最后保险。

    10. 方案 B 的故障边界

    Mihomo停止
    → dnsmasq虽然仍监听 192.168.10.3:53
    → 但唯一上游 127.0.0.1:1053 不可用
    → 国内外新域名都无法正常解析
    
    整个 R4S断电
    → 客户端 DNS 192.168.10.3 不可用
    → 国内外新域名都无法正常解析
    

    可以另做健康检查,在 Mihomo停止时临时把 dnsmasq 切回国内 DNS,从而保住国内访问;但这会增加新的自动化与回滚逻辑,不能把普通国内 DNS 与 Mihomo DNS 同时无条件配置成竞争上游,否则可能造成国外域名泄漏或解析不一致。

    七、两种 DNS 方案的本质区别

    方案 A

    dnsmasq先按域名名单决定:
    代理名单/插件例外 → Mihomo
    其他域名 → 国内普通 DNS
    
    Q3000再按最终 IP 决定:
    大陆 IP → WAN1
    其他 IP/Fake-IP → R4S
    

    方案 B

    dnsmasq把全部查询交给 Mihomo
    
    Mihomo按 YAML 决定:
    国内域名 → 真实 IP
    国外域名 → Fake-IP
    特殊域名 → 明确指定 fake-ip 或 real-ip
    未知域名 → 真实 IP
    
    Q3000再按最终 IP决定:
    大陆 IP → WAN1
    其他 IP/Fake-IP → R4S
    

    对比表

    对比项 方案 A:选择性转发 方案 B:Mihomo 全权解析
    国内 DNS dnsmasq 直接访问国内上游 Mihomo选择国内上游
    国外 DNS 自动名单命中后进入 Mihomo 全部进入 Mihomo并按规则分类
    Google Play 特例 LuCI 插件维护 YAML 第一条规则维护
    四千域名文件 需要,但自动更新 不需要
    自定义插件 需要,当前仅一条 不需要
    配置集中度 中等 高
    Mihomo停止后国内 DNS 大部分仍可用 不可用
    域名规则漏收 依赖 Q3000 非大陆 IP 兜底,但可能受普通 DNS 结果影响 MATCH real-ip 后由 Q3000 兜底
    当前实测状态 已完整验证 尚未正式切换
    推荐对象 稳定优先 配置统一优先

    八、为什么方案 A 当前更值得保留

    方案 A 看起来多了四千域名文件、更新脚本和一个插件,但实际人工维护量并不大:

    四千多条域名 → 每天自动更新
    插件 → 只维护 services.googleapis.cn 一条
    

    它最大的价值不是“域名更多”,而是把普通国内 DNS 与 Mihomo 的运行状态分开。Nikki/Mihomo 单独重启、崩溃或更新时,国内 DNS 和 Q3000 国内直连仍有机会继续工作。

    方案 B 的设计更加整洁,但整洁不等于故障范围更小。在家庭网络中,DNS 是所有应用的入口,一旦 Mihomo成为唯一 DNS 上游,它的停止会表现成“整个网络都打不开”。

    因此当前建议是:

    生产使用:继续方案 A
    研究或后续简化:先以可回滚方式测试方案 B
    

    九、重装 R4S 时分别恢复什么

    方案 A 的恢复项目

    1. 安装 Nikki 和 Mihomo 内核
    2. 导入并验证 nikki_optimized_config.yaml
    3. 恢复 dnsmasq 默认上游 223.5.5.5、223.6.6.6
    4. 安装 update-gfw-dnsmasq
    5. 恢复每天 04:17 的更新任务
    6. 生成 gwf-gfwlist.conf
    7. 安装 LuCI 域名分流插件
    8. 添加 services.googleapis.cn
    9. 检查 google.com 返回 Fake-IP
    10. 检查 services.googleapis.cn 返回 Fake-IP
    11. 检查 taobao.com 返回大陆真实 IP
    

    这些步骤适合封装成一个一键恢复脚本,不应依靠记忆手工重建。

    方案 B 的恢复项目

    1. 安装 Nikki 和 Mihomo 内核
    2. 导入包含 rule 模式 DNS 配置的 nikki_optimized_config.yaml
    3. 让 dnsmasq 的唯一上游指向 127.0.0.1#1053
    4. 检查 google.com 返回 Fake-IP
    5. 检查 services.googleapis.cn 返回 Fake-IP
    6. 检查 taobao.com 返回大陆真实 IP
    7. 确认 Q3000 的两条分流规则仍然存在
    

    方案 B 不需要四千域名更新程序和插件,但必须保证 Nikki 启动顺序、Mihomo DNS 监听和规则集下载全部正常。

    十、完整验收清单

    无论选择哪种 DNS 子方案,都应按以下顺序验收:

    DNS 层
    □ taobao.com 返回真实大陆 IP
    □ baidu.com 返回真实大陆 IP
    □ google.com 返回 198.18.x.x
    □ youtube.com 返回 198.18.x.x
    □ services.googleapis.cn 返回 198.18.x.x
    
    Q3000 分流层
    □ CodexCNDirect 已启用并引用八个 CN4 分组
    □ CodexR4S 已启用,下一跳为 192.168.10.3
    □ 客户端范围为 192.168.10.100-192.168.10.200
    
    应用层
    □ 淘宝和微信正常
    □ 国内网页打开速度正常
    □ Google 搜索正常
    □ YouTube 首页、缩略图和视频正常
    □ ssh.cloud.google.com 能建立长连接
    □ Google Play 可以下载并完成安装
    □ Muse 等曾经异常的网站正常
    □ Tailscale 子网访问和出口节点正常
    

    测试 Google Play 时,不要只看到商店首页就判断成功。应实际选择一个应用,确认下载进度超过 1% 并完成安装。

    十一、常见问题

    1. 所有流量是否第一时间经过 Nikki

    不是。客户端默认网关是 Q3000:

    大陆真实 IP → Q3000直接 WAN1
    非大陆真实 IP/Fake-IP → Q3000交给 R4S → Nikki/Mihomo
    

    两种 DNS 方案改变的是“如何得到目标 IP”,不是把国内业务流量重新强制送进 R4S。

    2. 为什么 Zashboard 中来源都是 192.168.10.1

    当前 Q3000 和 R4S 位于同一 LAN。Q3000 把连接折返给 LAN 内下一跳时会隐藏原始客户端地址,因此 Mihomo看到的来源是 Q3000。这个问题不影响分流和速度,但 Zashboard 无法按真实客户端统计。

    要保留真实来源 IP,需要为 Q3000 与 R4S 建立独立传输网段,可通过第二根网线或 VLAN 实现;这属于另一项网络架构改造,与两种 DNS 子方案无关。

    3. 客户端手动设置 8.8.8.8 会怎样

    客户端访问 8.8.8.8:53 时,目标 IP 不属于大陆地址库,Q3000 会把查询交给 R4S。若 Nikki 的透明代理 DNS 劫持正常,查询仍可能进入 Mihomo;但不应依赖客户端随意设置 DNS,标准配置仍是 192.168.10.3。

    4. 为什么 services.googleapis.cn 不能直接按 .cn 直连

    域名后缀只表示命名空间,不代表该服务在当前网络下可以完整直连。Google Play 同时使用控制域名、下载 CDN 和账号连接;如果其中一部分直连、一部分代理,同一个下载任务会产生出口不一致并卡住。

    5. Q3000 大陆 IP 库是否自动更新

    当前八个 CN4 分组是一次性导入的快照,数据保存在 Q3000 中,访问时无需外部脚本;但它不会自行跟随互联网地址分配变化。长期使用应增加定期同步与备份工具,并在更新后检查八个对象和两条规则的引用关系。

    十二、最终选择建议

    稳定性优先时:

    选择方案 A
    dnsmasq 维护自动代理域名表
    插件只保留 services.googleapis.cn
    国内 DNS 不依赖 Mihomo进程
    

    配置集中优先时:

    选择方案 B
    所有 DNS 交给 Mihomo
    YAML 使用 fake-ip-filter-mode: rule
    services.googleapis.cn 写入第一条强制 Fake-IP 规则
    接受 Mihomo成为全网 DNS 单点
    

    无论选择哪一种,真正决定国内业务流量是否绕过 R4S 的核心都不是域名列表,而是 Q3000 中的两条规则:

    大陆 IP → CodexCNDirect → WAN1
    其他 IP → CodexR4S → R4S/Nikki/Mihomo
    

    DNS 负责发放“目的地址”,Q3000 负责选择“实际道路”,R4S/Nikki/Mihomo 负责处理“需要代理的那部分连接”。把这三层职责分开理解,整套网络就不再神秘。

  • Q3000 + R4S + Nikki:国内直连、国外按需代理的分流教程(已弃用)

    Q3000 + R4S + Nikki:国内直连、国外按需代理的分流教程(已弃用)

    一套不依赖爱快付费“IP 归属地”的家庭网络方案。国内和普通境外服务由 Q3000 直接访问;只有命中代理域名表的请求才交给 R4S 上的 Nikki/Mihomo。本文既讲配置,也解释每一步为什么这样做。

    本文记录的是一套已经实际运行并解决淘宝、微信等国内应用卡顿问题的配置。它适合以下场景:

    • Q3000(爱快系统)作为主路由,负责拨号、DHCP、VLAN、Wi-Fi 和 NAT。
    • R4S 刷入 ImmortalWrt/OpenWrt,并安装 Nikki。
    • 希望国内流量尽量不进入 R4S,国外受限服务自动代理。
    • 希望保留 Tailscale 子网路由、出口节点等功能。
    • 不购买爱快“IP 归属地”功能。

    文中的地址是实际示例。照做前,请先把它们换成自己的网段。本文默认读者已经能登录 Q3000 和 R4S,不再讲网线连接、SSH 登录和 LuCI 登录。

    一、最终效果

    配置完成后,普通客户端会获得:

    项目 示例值 由谁提供
    客户端 IP 192.168.10.100 Q3000 DHCP
    默认网关 192.168.10.1 Q3000
    DNS 服务器 192.168.10.3 R4S 上的 dnsmasq
    Q3000 地址 192.168.10.1 主路由
    R4S 地址 192.168.10.3 DNS 分类器、代理入口、Tailscale 节点
    Mihomo Fake-IP 段 198.18.0.0/16 Mihomo

    最重要的一句话是:

    网关走 Q3000,DNS 问 R4S;只有 DNS 返回 198.18.x.x 的目标,Q3000 才把后续连接送到 R4S。

    因此:

    • 淘宝、微信、银行、视频网站等国内服务,通常从 Q3000 直接出 WAN。
    • 能在国内直连的普通境外网站,也从 Q3000 直接出 WAN。
    • Google、TikTok 等命中代理域名表的服务,自动交给 R4S/Nikki/Mihomo。
    • R4S 不再是所有设备的默认网关,也不再处理绝大多数国内连接。

    二、先弄懂四个组件的关系

    很多配置混乱,源头不是某个选项,而是把 R4S、Nikki、Mihomo 当成了同一个东西。它们的关系如下:

    Q3000(独立主路由)
    ├─ WAN 拨号与 NAT
    ├─ LAN/VLAN/Wi-Fi
    ├─ DHCP
    └─ 静态路由:198.18.0.0/16 → R4S
    
    R4S(硬件设备)
    └─ ImmortalWrt/OpenWrt(操作系统)
       ├─ dnsmasq:本方案的前置 DNS 分类器
       ├─ Tailscale:独立的组网服务
       └─ Nikki:OpenWrt 上的代理管理插件
          ├─ 管理配置文件和防火墙规则
          └─ 启动、停止并管理 Mihomo
             ├─ 真正执行 Fake-IP、代理规则和节点连接
             └─ 向 Zashboard 提供控制 API
    

    用通俗的话说:

    • R4S 是一台小电脑。
    • ImmortalWrt/OpenWrt 是它的操作系统。
    • Nikki 是系统里的管理工具,负责准备运行环境并叫醒 Mihomo。
    • Mihomo 才是真正执行代理和规则匹配的核心程序。
    • Zashboard 只是查看和操作 Mihomo 的网页控制台,不负责转发流量。
    • Tailscale 与 Nikki 是平级服务,不包含在 Nikki 里面。

    所以,“流量经过 R4S”并不等于“流量经过 Mihomo”;只有被 Nikki 防火墙规则接管的连接,才会进入 Mihomo。

    三、旧方案为什么会让国内 App 卡顿

    旧方案把客户端的默认网关和 DNS 都设置为 192.168.10.3:

    手机/电脑 → R4S → Nikki/Mihomo 判断 → DIRECT 或代理
    

    Mihomo 会根据 YAML 中的域名规则、IP 规则、GeoIP、规则集和最终 MATCH 判断走向。例如:

    - RULE-SET,cn_domain,DIRECT
    - RULE-SET,cn_ip,DIRECT,no-resolve
    - MATCH,PROXY
    

    这里的 DIRECT 只表示“不走代理节点”,不表示“绕开 R4S”。国内连接仍然先进入 R4S,再从 R4S 的同一个 LAN 网口送回 Q3000 出网,返回包也要经过相应路径。这种单臂旁路由折返会同时受到以下因素影响:

    • Nikki 的透明代理和 nftables 规则;
    • Fake-IP 与真实 IP 的映射;
    • DNS 劫持和 dnsmasq;
    • UDP/TCP 的不同接管方式;
    • 同一个物理接口上的来回转发;
    • 应用自身的多域名、多 IP、HTTP/3 和长连接。

    这不代表传统旁路由一定不能用,但在这套设备、固件和配置组合中,曾出现淘宝卡住、微信打不开、手机提示网络异常,而国外代理流量反而正常的现象。问题的关键是:即使最终判定为 DIRECT,国内数据包仍然已经进入 R4S 的复杂转发路径。

    四、新方案的核心原理

    新方案把“是否需要送进 R4S”的判断提前到 DNS 阶段。

    R4S 的 dnsmasq 中放入约四千多条代理域名规则。每条规则类似:

    server=/google.com/127.0.0.1#1053
    

    含义是:

    • 如果查询的域名命中列表,把 DNS 查询交给 Mihomo 的 1053 端口;
    • 如果没有命中,交给阿里公共 DNS,返回真实 IP。

    1. 国内或普通直连域名

    手机查询 taobao.com
    → R4S dnsmasq 没有命中代理域名表
    → 阿里 DNS 返回真实 IP
    → 手机连接真实 IP
    → 默认网关是 Q3000
    → Q3000 直接从 WAN 出网
    

    这个过程中,R4S 只回答了一次 DNS。真正的业务流量没有进入 R4S、Nikki 或 Mihomo。

    2. 需要代理的域名

    手机查询 google.com
    → R4S dnsmasq 命中代理域名表
    → 查询转交 Mihomo:1053
    → Mihomo 返回 198.18.x.x Fake-IP
    → 手机连接这个 Fake-IP
    → 默认网关先到 Q3000
    → Q3000 静态路由把 198.18.0.0/16 送给 R4S
    → Nikki 防火墙接管连接
    → Mihomo 恢复原域名并选择代理节点
    

    因此,并不是所有流量第一时间经过 Nikki。进入 Nikki 的主要是被标记成 Fake-IP 的连接。

    3. 能直连的境外服务

    一个域名只要没有命中代理列表,就会获得真实 IP,并由 Q3000 直接访问。它是不是“中国 IP”并不重要,所以不需要爱快付费的“IP 归属地”功能。

    这也回答了一个常见问题:国外服务不等于都要代理。可直连的境外网站不会因为 R4S 停机而失去转发路径,但如果客户端 DNS 仍指向已经停机的 R4S,新域名仍会因为无法解析而打不开。后文会用备用 Wi-Fi 解决这个故障场景。

    4. 这四千多条域名够不够

    这份表不是“全世界所有国外域名”,而是社区维护的、通常需要代理的域名集合。它的覆盖面比旧方案的完整 YAML 规则窄:

    • 旧方案:所有连接先进入 Mihomo,再由完整规则体系决定 DIRECT 或代理。
    • 新方案:只有前置域名表命中的连接进入 Mihomo,其余连接直接走 Q3000。

    优点是国内路径简单、稳定、延迟低;代价是新出现或未收录的受限域名可能被当作直连而失败。遇到漏网域名时,把它加入自定义代理域名表即可。

    五、准备工作与地址规划

    开始前至少准备:

    • Q3000 已能正常拨号上网;
    • R4S 已安装 ImmortalWrt/OpenWrt、Nikki 和 Mihomo 内核;
    • Nikki 已导入一份本身可用的订阅/YAML;
    • R4S 能使用 curl 下载文件;
    • 手边有一个完全直连的 Wi-Fi,方便配置失误时继续管理设备;
    • 已导出 Q3000 配置,并备份 R4S 的 /etc/config。

    本文地址规划:

    设备/网段 地址
    Q3000 LAN1 192.168.10.1/24
    R4S LAN 192.168.10.3/24
    Q3000 DHCP 池 192.168.10.100-192.168.10.200
    客户端网关 192.168.10.1
    客户端 DNS 192.168.10.3
    Mihomo Fake-IP 198.18.0.0/16

    **安全提醒:**修改网关、DHCP、静态路由和防火墙可能导致暂时失联。先备份,再改一项、验证一项。不要把订阅链接、节点信息、SSH 密码、API 令牌或 Mihomo 控制密钥粘贴到公开文章和公开对话中。

    六、配置 R4S 的基础网络

    R4S 使用固定地址:

    IP:192.168.10.3
    掩码:255.255.255.0
    网关:192.168.10.1
    DNS:可先用 192.168.10.1 或可靠的国内 DNS
    

    在 LuCI 中通常位于:

    网络 → 接口 → LAN → 编辑 → 常规设置
    

    R4S 不再负责给家庭主网分配地址,因此关闭 LAN 接口上的 DHCP 服务,但不要关闭 dnsmasq 服务本身。本方案仍需要 dnsmasq 在 192.168.10.3:53 回答 DNS。

    通常路径:

    网络 → 接口 → LAN → 编辑 → DHCP 服务器 → 忽略此接口
    

    确认 R4S 自身可以访问互联网:

    ping -c 3 223.5.5.5
    nslookup github.com 223.5.5.5
    

    七、配置 Nikki 与 Mihomo

    1. 先让原始 YAML 正常运行

    先在 Nikki 中导入自己的订阅或 YAML,确认节点本身可以连接。本文不提供任何订阅、节点或密钥。

    建议基础状态:

    项目 建议值
    TCP 代理方式 Redirect
    UDP 代理方式 TUN
    LAN 代理 开启
    路由器自身代理 按需开启
    Fake-IP 开启
    Fake-IP 范围 198.18.0.1/16
    Mihomo DNS 监听 127.0.0.1:1053 或配置实际使用的 1053 监听
    大陆 IP 提前绕过 关闭
    Nikki IPv4 DNS 劫持 关闭
    Nikki IPv6 DNS 劫持 关闭
    Nikki 代理配置中 TCP、UDP、DNS 劫持与 IPv4/IPv6 代理选项
    R4S 上的 Nikki 代理配置:TCP 使用 Redirect、UDP 使用 TUN,IPv4/IPv6 DNS 劫持关闭。

    “大陆 IP 提前绕过”不是绝对不可用,而是不作为本文方案的核心。本文依靠“DNS 分类 + Fake-IP 静态路由”决定哪些连接进入 R4S;再叠加一套大陆 IP 提前绕过,会增加判断层级和排错难度。

    2. 为什么要关闭 Nikki 的 DNS 劫持

    我们要让 dnsmasq 成为第一层分类器:普通域名走国内 DNS,命中列表的域名才去 Mihomo。如果开启 Nikki 的全局 DNS 劫持,所有查询可能先被重定向到 Mihomo,前置分类就失去意义。

    命令行等价设置为:

    uci set nikki.proxy.ipv4_dns_hijack='0'
    uci set nikki.proxy.ipv6_dns_hijack='0'
    uci commit nikki
    /etc/init.d/nikki restart
    

    3. OpenWrt 的“DNS 重定向”要不要关

    LuCI 中:

    网络 → DHCP/DNS → 常规 → DNS 重定向
    
    R4S 的 DHCP/DNS 常规设置中 DNS 重定向处于开启状态
    这里的 DNS 重定向属于 dnsmasq/OpenWrt,和 Nikki 的 DNS 劫持不是同一个开关。

    这个选项把经过 R4S 的客户端 DNS 查询强制拉回 R4S 的 dnsmasq,和 Nikki 的 DNS 劫持不是同一个开关。本方案中,普通客户端已经明确使用 192.168.10.3 作为 DNS,而默认网关又是 Q3000,因此该选项不是核心。可以保留开启;关键是关闭 Nikki 的 IPv4/IPv6 DNS 劫持。

    补充说明:它究竟在什么情况下生效

    192.168.10.3 就是 R4S。客户端使用 192.168.10.3 作为 DNS,确实就是主动向 R4S 上的 dnsmasq 查询。这种正常查询不需要“DNS 重定向”帮忙,因为目的地址本来就是 R4S。

    “DNS 重定向”处理的是另一种情况:客户端没有使用 DHCP 下发的 DNS,而是自行查询其他 DNS。例如在旧方案中,客户端默认网关也是 R4S:

    客户端默认网关:192.168.10.3
    客户端手动 DNS:8.8.8.8
    
    客户端 → 准备访问 8.8.8.8:53
           → DNS 请求先经过 R4S
           → R4S 的 DNS 重定向规则将它拦截
           → 改送给 R4S 自己的 dnsmasq
    

    此时,即使客户端手动填写 8.8.8.8,传统的 UDP/TCP 53 端口查询仍可能被 R4S 拉回本机,因此这个开关在“所有请求都经过 R4S”的旧方案中很有作用。

    当前方案的路径不同:

    客户端默认网关:192.168.10.1(Q3000)
    客户端手动 DNS:8.8.8.8
    
    客户端 → Q3000 → 8.8.8.8
    

    这个查询根本没有经过 R4S,所以 R4S 上的 DNS 重定向看不到、也拦不住它。结果是:

    • DNS 分类被绕过;
    • 需要代理的域名不会获得 198.18.x.x Fake-IP;
    • Q3000 的 Fake-IP 静态路由不会被触发;
    • Google 等服务会被当成普通直连,通常无法访问;
    • 在国内直接使用 8.8.8.8 还可能遇到超时、污染或不稳定。

    浏览器 DoH、Android 私人 DNS、iCloud 专用代理一类加密 DNS 也可能绕过传统的 53 端口重定向。因此,当前方案依赖客户端使用 Q3000 DHCP 下发的 192.168.10.3。从当前拓扑的实际作用看,R4S 的“DNS 重定向”关闭即可;即使保留开启,也不能阻止以 Q3000 为网关的客户端绕过 R4S DNS。

    4. YAML 和 Nikki UI 谁优先

    Nikki 启动时可能把“混入配置”合并到原始 YAML,再生成真正交给 Mihomo 的运行配置。因此:

    • 原始 YAML 是基础;
    • Nikki UI 和混入配置可能覆盖或补充它;
    • 最终运行结果要看 Nikki 生成的配置、UCI 设置以及防火墙状态;
    • 不要直接修改 /etc/nikki/run/config.yaml,它可能在重启后重新生成。

    例如,YAML 写了 Fake-IP,但 Nikki UI 又把 DNS 模式改掉,最后应以运行配置为准。排查时可查看:

    uci show nikki
    grep -nE 'enhanced-mode|fake-ip-range|listen' /etc/nikki/run/config.yaml
    nft list ruleset | grep -i nikki
    

    八、在 R4S 安装“分流 DNS”

    本文附带三份脚本:

    scripts/update-gfw-dnsmasq.sh
    scripts/install-split-dns.sh
    scripts/rollback-split-dns.sh
    

    它们不会包含你的订阅、密码或节点。安装脚本会先备份 /etc/config/dhcp、/etc/config/nikki、dnsmasq 附加目录和 root 定时任务。

    1. 上传脚本

    把下面两份文件上传到 R4S 的 /tmp:

    update-gfw-dnsmasq.sh
    install-split-dns.sh
    

    执行:

    chmod +x /tmp/update-gfw-dnsmasq.sh /tmp/install-split-dns.sh
    /tmp/install-split-dns.sh
    

    脚本完成以下工作:

    1. 创建带时间戳的备份目录,并把路径写入 /root/last-split-dns-backup。
    2. 让 dnsmasq 读取 /etc/dnsmasq.d。
    3. 把普通域名上游设为 223.5.5.5 和 223.6.6.6。
    4. 关闭 DNS Rebind 保护,使 dnsmasq 接受 Mihomo 返回的 198.18.x.x Fake-IP。
    5. 允许经过路由的局域网客户端使用该 DNS。
    6. 关闭 Nikki 的 IPv4/IPv6 DNS 劫持。
    7. 下载代理域名表,生成指向 127.0.0.1#1053 的规则。
    8. 每天 04:17 自动更新域名表。
    9. 重启 cron、Nikki 和 dnsmasq。

    关闭 Rebind 保护是为了接受 Fake-IP,会降低 dnsmasq 对“公网域名返回私有/保留地址”的防护。本方案的 R4S 位于 Q3000 内网,DNS 端口不得暴露到 WAN;防火墙应只允许可信 LAN/Tailscale 使用。

    2. 检查结果

    wc -l /etc/dnsmasq.d/gwf-gfwlist.conf
    grep -c '^server=/' /etc/dnsmasq.d/gwf-gfwlist.conf
    dnsmasq --test
    grep update-gfw-dnsmasq /etc/crontabs/root
    uci get nikki.proxy.ipv4_dns_hijack
    uci get nikki.proxy.ipv6_dns_hijack
    

    期望看到:

    • 域名规则数量大于 3000,实际数量会随上游更新变化;
    • dnsmasq --test 返回语法正确;
    • 两个 Nikki DNS 劫持值都是 0;
    • root 定时任务中存在更新命令。

    3. 检查 DNS 分类

    在 R4S 上执行:

    nslookup taobao.com 127.0.0.1
    nslookup google.com 127.0.0.1
    

    预期:

    • 淘宝返回真实公网 IP;
    • Google 返回 198.18.x.x 一类 Fake-IP。

    4. 手动补充漏网域名

    如果某个确定需要代理的域名没有命中,可新建:

    cat >/etc/dnsmasq.d/gwf-custom.conf <<'EOF'
    server=/example.com/127.0.0.1#1053
    server=/example.net/127.0.0.1#1053
    EOF
    
    dnsmasq --test && /etc/init.d/dnsmasq restart
    

    一条 server=/example.com/... 通常也匹配其子域名。添加前应先确认它确实需要代理;把国内 CDN 域名误加进去,可能重新引入国内 App 变慢的问题。

    九、配置 Q3000

    不同爱快版本的文字可能略有差异,但功能位置基本一致。

    1. LAN1 与 DHCP

    进入:

    网络设置 → DHCP 设置 → DHCP 服务端
    

    主网配置为:

    接口:LAN1
    地址池:192.168.10.100 - 192.168.10.200
    网关:192.168.10.1
    首选 DNS:192.168.10.3
    备用 DNS:留空
    租期:120 分钟(可按需调整)
    
    Q3000 主网 DHCP 服务端的地址池、网关与 DNS 设置
    Q3000 主网 DHCP:默认网关为 192.168.10.1,首选 DNS 为 R4S 的 192.168.10.3,备用 DNS 留空。

    备用 DNS 留空是有意的。若填入公共 DNS,部分手机和电脑会自行选择备用 DNS,绕过 R4S 的域名分类,表现为同一网站时好时坏。

    2. 检查静态 DHCP 绑定

    这是本次实际遇到的重要问题:DHCP 服务端已经把网关改为 .1,但 PC 反复禁用、启用网卡后,网关仍然是 .3。原因是该 PC 有一条静态 DHCP 绑定,里面单独写了旧网关。

    逐条检查静态分配/终端绑定:

    IP:按原计划保留
    网关:192.168.10.1
    DNS1:192.168.10.3
    DNS2:留空
    

    不要只检查全局 DHCP;终端专属设置通常优先于全局值。

    3. 添加 Fake-IP 静态路由

    进入:

    网络设置 → 静态路由
    

    添加:

    项目 值
    名称 NikkiFakeIP
    目标网段 198.18.0.0/16
    下一跳 192.168.10.3
    出口接口 LAN1/自动选择正确 LAN
    状态 启用
    Q3000 中指向 R4S 的 Fake-IP 与 Tailscale 静态路由
    Q3000 当前静态路由:Fake-IP 网段以及 Tailscale/远端 LAN 的回程路由都指向 R4S。

    这条路由就是整套方案的“搬运工”:Q3000 看到目标是 198.18.x.x,便知道这个地址不是从 WAN 直接访问,而应交给 R4S 解释。

    4. 不需要配置的项目

    本方案不需要:

    • 爱快付费“IP 归属地”;
    • 用五元组规则判断所有国外 IP;
    • 把默认路由或全网网关改成 R4S;
    • 按国家建立大量 IP 路由;
    • 为 GWF-5G 单独创建“全部下一跳 R4S”的策略路由。

    5. Q3000 能否单独封禁或限制某台客户端

    旧方案中,所有客户端先把流量交给 R4S,R4S 再转发或代理。若 R4S 对这些连接做了源地址转换,Q3000 看到的来源就可能全部是 192.168.10.3,从而无法在主路由上准确区分手机、电脑和电视。

    当前方案中,每台客户端的默认网关都是 Q3000。对于国内和普通境外直连流量,路径为:

    192.168.10.100(PC)   → Q3000 → WAN
    192.168.10.101(手机) → Q3000 → WAN
    192.168.10.102(电视) → Q3000 → WAN
    

    Q3000 可以直接看到每台设备原来的 IP 和 MAC,因此可以分别查看在线状态、禁止上网、设置上网时段、进行访问控制或配置固定地址。

    访问 Google 等代理服务时,第一段仍然经过 Q3000:

    客户端 → Q3000 → 198.18.x.x → R4S/Mihomo
    

    因此,如果 Q3000 使用客户端 IP/MAC,在流量进入转发路径时执行“终端禁止上网”或同类整机封禁,通常会在连接抵达 R4S 之前将其拦截。整机封禁不仅对国内和可直连服务有效,对 Google 等代理流量通常也同样有效。

    但 Mihomo 接管连接后,会以 R4S 的身份重新连接代理节点:

    R4S/Mihomo → 代理节点 → 目标网站
    

    这个真正从 WAN 发出的外层代理连接,在 Q3000 看来通常来自 192.168.10.3。因此,“能否封禁设备”和“能否精确统计代理流量”是两件不同的事:

    Q3000 上的操作 国内/直连流量 Google 等代理流量
    按 IP/MAC 禁止整台设备上网 有效 通常同样有效,因为第一段先经过 Q3000
    按 IP/MAC 设置上网时间 有效 只要规则作用于客户端转发入口,通常有效
    查看每台设备的直连连接和流量 可以准确区分 代理出口部分可能统计到 R4S
    对单台设备精确限制代理出口带宽 可以直接限制直连部分 是否准确取决于 Q3000 限速规则的作用阶段,需要实测
    按最终网站域名进行封禁 可使用 Q3000 的相关能力 可能受 Fake-IP 和代理封装影响,宜在 Mihomo 规则中处理

    为了让设备控制长期稳定,建议在 Q3000 中按 MAC 给需要管理的设备分配固定 IP,再使用 Q3000 的终端控制或 ACL。配置后应同时测试一个国内网站和一个代理网站,并查看规则命中情况;不同爱快版本中的“终端限速”“流控分流”和“访问控制”可能工作在不同阶段,不能仅凭界面上已经保存规则就判断代理流量一定被准确计量。

    十、让客户端重新获取网络参数

    完成 Q3000 配置后,让手机断开并重新连接 Wi-Fi;Windows 可执行:

    ipconfig /release
    ipconfig /renew
    ipconfig /flushdns
    ipconfig /all
    

    正确结果是:

    IPv4:192.168.10.x
    默认网关:192.168.10.1
    DNS:192.168.10.3
    

    这组结果看起来“不对称”,其实正是设计目标:

    • 网关 .1 决定业务流量默认从 Q3000 出去;
    • DNS .3 只负责给域名分类和返回地址。

    DNS 服务器不是默认网关,它们完全可以是两台不同设备。

    十一、从一次请求看完整运行过程

    场景 A:打开淘宝

    1. 手机向 192.168.10.3 查询淘宝相关域名。
    2. dnsmasq 未在代理域名表中命中。
    3. dnsmasq 向阿里 DNS 查询,返回真实 IP。
    4. 手机把业务包发给默认网关 192.168.10.1。
    5. Q3000 直接 NAT 到 WAN。
    6. R4S、Nikki 和 Mihomo不参与业务转发。

    场景 B:打开 Google

    1. 手机向 R4S 查询域名。
    2. dnsmasq 命中代理域名表,把查询送到 Mihomo 1053。
    3. Mihomo 返回 198.18.x.x。
    4. 手机把连接交给 Q3000。
    5. Q3000 命中 198.18.0.0/16 → 192.168.10.3 静态路由。
    6. R4S 上的 Nikki 防火墙捕获连接。
    7. Mihomo 根据 Fake-IP 映射还原域名,并按 YAML 选择代理组和节点。
    8. 返回数据沿连接状态回到手机。

    场景 C:访问可直连的境外网站

    1. 域名未命中代理表。
    2. 客户端得到真实 IP。
    3. Q3000 直接访问该境外 IP。
    4. R4S 不参与业务流量。

    场景 D:应用直接写死 IP

    如果应用完全不做 DNS 查询,而是直接连接某个真实 IP,就没有域名可供前置分类。这种连接默认由 Q3000 直连。若它必须代理,需要额外的 IP 路由、策略规则,或让该设备改用旧式“全量进入 Mihomo”的网络。不要为了极少数情况把整个主网重新改成全量旁路由。

    十二、Zashboard 为什么看不到国内连接

    旧方案中,所有流量都进入 Mihomo,因此 Zashboard 能看到淘宝、微信等国内连接,并显示最终走 DIRECT。

    新方案中,国内业务包从 Q3000 直接出 WAN,不进入 Mihomo,所以 Zashboard 通常只能看到代理域名产生的连接。它不是丢包,也不是监控坏了,而是说明分流发生在 Mihomo 之前。

    查看全网连接应使用 Q3000 的终端/连接监控;查看代理连接和节点选择才使用 Zashboard。

    十三、备用直连 Wi-Fi 有没有必要

    建议保留三个用途不同的网络:

    Wi-Fi 用途 网关/DNS思路
    GWF-5G 日常自动分流 网关 Q3000,DNS R4S
    WRT-5G 故障应急、完全直连 独立 VLAN,由 Q3000 提供网关和公共/运营商 DNS
    Guest-5G 访客隔离 独立访客 VLAN

    主网虽然不是把默认网关设成 R4S,但 DNS 依赖 R4S。R4S 停机后,已经建立的国内 IP 连接可能暂时继续,新的域名查询却会失败。备用 Wi-Fi 的价值就是完全不依赖 R4S:

    • 使用独立 VLAN;
    • 网关指向该 VLAN 的 Q3000 地址;
    • DNS 使用 Q3000、运营商 DNS 或可信公共 DNS;
    • 不添加“下一跳 R4S”的策略路由;
    • Fake-IP 静态路由即使是全局路由,也不会产生 Fake-IP,因为该 VLAN 不使用 R4S DNS。

    所以备用 Wi-Fi 不是为了日常分流,而是为了 R4S 重启、升级、配置失败时还能访问国内网络和管理设备。

    十四、Tailscale 的兼容配置

    Tailscale 和 Nikki 是 R4S 上两个独立服务:Tailscale 建立虚拟专网,Nikki 管理 Mihomo 代理。当前分流方案不会自动删除 Tailscale 设置,但回程路由必须正确。

    1. Q3000 添加 Tailscale 回程路由

    如果 R4S 关闭 Tailscale SNAT(NoSNAT=true),Q3000 必须知道怎样回到 Tailscale 地址和远端 LAN。

    添加:

    名称 目标网段 下一跳
    TailscaleCGNAT 100.64.0.0/10 192.168.10.3
    R2SRemoteLAN 192.168.110.0/24 192.168.10.3

    第一条让家庭 LAN 设备能把响应送回 Tailscale 客户端;第二条让本地设备知道公司/远端 LAN 位于 R4S 的 Tailscale 通道后面。

    2. Tailscale 出口节点能否继续使用代理

    可以,但需要 Nikki 接管来自 Tailscale 接口的流量。检查 Nikki 入站接口中是否包含 tailscale,并确认防火墙允许 Tailscale 与 LAN/WAN 互通。

    逻辑是:

    远端设备 → Tailscale 隧道 → R4S tailscale 接口
    → Nikki 透明代理规则(若包含该接口)
    → Mihomo 按 YAML 判断 DIRECT 或代理
    

    如果不希望出口节点流量经过代理,就不要让 Nikki 接管 Tailscale 入站,或添加明确的绕过规则。这里没有“一律正确”的开关,取决于出口节点的用途。

    3. 为什么远程桌面可能真的变流畅

    这不一定是错觉。旧方案把本地大量国内流量也送进 R4S/Nikki,增加 R4S 的连接跟踪、DNS、透明代理和单臂折返负担。新方案让绝大多数国内连接由 Q3000 直接处理,R4S 更空闲,Tailscale 的 CPU、队列和连接跟踪竞争都可能减少。

    不过远程桌面还受到宽带上行、运营商互联、Wi-Fi、Tailscale 是 direct 还是 DERP 等影响。要验证是否真实提速,可在相同时间段对比:

    tailscale ping 对端Tailscale地址
    tailscale status
    

    direct 表示两端直接打洞,通常更快;relay/DERP 表示经中继,延迟一般更高。

    4. 手机访问远端 LAN 慢,是否一定与本方案有关

    不一定。若 R4S 到远端 R2S 和远端 LAN 都很快,而手机到远端慢,应继续检查:

    • 手机到 R4S 是 direct 还是 DERP;
    • 手机移动网络是否限制 UDP;
    • 远端 R2S 是否正确发布 192.168.110.0/24;
    • Tailscale 管理后台是否批准子网路由;
    • 远端设备的默认网关和回程路由;
    • 公司侧曾做过的端口映射或防火墙规则。

    手机自身运行 Tailscale 时,访问 192.168.110.0/24 通常由手机 Tailscale 客户端直接送入隧道,不一定经过家庭 Q3000 的分流路径。因此不能仅凭“手机慢”认定是当前 DNS 分流造成的。

    十五、完整验收清单

    按顺序验证,不要只测试一个网站:

    检查项 正确结果
    客户端默认网关 192.168.10.1
    客户端 DNS 192.168.10.3
    淘宝/微信/银行 App 正常且无明显卡顿
    普通国内网站 正常
    Google/TikTok 可通过代理访问
    国内域名解析 返回真实公网 IP
    代理域名解析 返回 198.18.x.x
    Q3000 Fake-IP 路由 198.18.0.0/16 → 192.168.10.3
    Nikki DNS 劫持 IPv4、IPv6 均关闭
    Zashboard 主要看到代理连接,看不到多数国内连接
    WRT-5G R4S 停机时仍可直连国内网络
    Tailscale 需要时显示 direct,远端子网可达

    建议重启一次 R4S,再让客户端重新联网,确认配置不会只在当前运行状态下生效。

    十六、常见故障与排查

    1. 淘宝、微信卡住,Google 却正常

    优先检查:

    客户端网关是不是还在指向 192.168.10.3?
    静态 DHCP 绑定里是不是保留了旧网关?
    国内域名是不是错误返回了 198.18.x.x?
    Nikki DNS 劫持是不是又被打开?
    

    不要一上来反复修改 YAML 节点规则。先确认国内业务流量有没有真的绕开 R4S。

    2. PC 更新租约后网关仍是 .3

    检查 Q3000 中该 PC 的静态 DHCP/终端绑定。专属绑定中的网关会覆盖 DHCP 服务端的全局网关。修改后再执行 ipconfig /release 和 ipconfig /renew。

    3. 手机 DNS 仍是 192.168.10.3

    这是正确状态,不是残留配置。R4S 在本方案中仍是 DNS 分类器,只是不再是默认网关。

    4. 国内正常,某个受限网站打不开

    执行:

    nslookup 目标域名 192.168.10.3
    grep -F '目标域名' /etc/dnsmasq.d/gwf-gfwlist.conf
    

    若返回真实 IP 且列表没有该域名,将正确的主域名加入 gwf-custom.conf。若已经返回 Fake-IP,再去检查 Q3000 静态路由、Nikki 防火墙、Mihomo 规则和节点。

    5. 所有域名都打不开,但直接访问 IP 可能正常

    检查 R4S 是否在线、dnsmasq 是否监听 53 端口、Q3000 DHCP 是否仍只发布 R4S DNS:

    /etc/init.d/dnsmasq status
    netstat -lnup | grep ':53 '
    dnsmasq --test
    logread -e dnsmasq
    

    然后临时连接 WRT-5G 直连网络,不要急着给主网增加公共 DNS2,否则会破坏稳定分类。

    6. Zashboard 没有国内连接

    这是设计结果。国内业务没有进入 Mihomo,去 Q3000 查看全网连接。

    7. 重启 Nikki 后行为变化

    Nikki 的混入配置可能重新生成运行配置。比较:

    uci show nikki
    grep -nE 'dns:|enhanced-mode|fake-ip-range|listen:' /etc/nikki/run/config.yaml
    

    不要直接编辑运行目录中的 YAML。应修改原始配置或 Nikki UI/混入配置中的对应项目。

    8. mmstat.com 这类国内域名怎么判断

    本方案不是让 Mihomo 猜它是不是国内域名。dnsmasq 只问一个更直接的问题:“它是否在需要代理的域名表里?”不在列表就返回真实 IP,让 Q3000 直连。这样不需要维护千千万万个国内域名,也不依赖 GeoIP 先查归属地。

    9. RULE-SET,cn_ip,DIRECT,no-resolve 还要不要改

    它仍可保留在 Mihomo YAML 中,作为已经进入 Mihomo 后的保护规则。no-resolve 表示这条 IP 规则不为了匹配而额外触发 DNS 解析。新方案的关键不在于删改这一条,而是多数国内连接根本不再进入 Mihomo。

    十七、回滚方法

    1. 回滚 R4S

    把 rollback-split-dns.sh 上传到 R4S 的 /tmp,执行:

    chmod +x /tmp/rollback-split-dns.sh
    /tmp/rollback-split-dns.sh
    

    脚本读取 /root/last-split-dns-backup,恢复安装前的 DHCP/DNS 与 Nikki 配置,并删除自动更新任务和生成的域名表。

    2. 回滚 Q3000 为完全直连

    为了最快恢复基本上网:

    1. 保持客户端网关为 Q3000,例如 192.168.10.1。
    2. 把 DHCP DNS 临时改为 Q3000、运营商 DNS 或可靠公共 DNS。
    3. 禁用或删除 198.18.0.0/16 → 192.168.10.3 静态路由。
    4. 客户端重新获取 DHCP 并清除 DNS 缓存。

    这会失去自动代理,但能先恢复稳定直连。确认网络正常后,再逐层恢复分流,不要同时改动 Q3000、dnsmasq、Nikki 和 YAML。

    十八、让 Codex 协助配置的提示词

    下面的提示词可以直接改地址后使用。不要在提示词中写明文密码、订阅链接和 API 密钥;需要登录时单独安全提供,并在完成后更换临时凭据。

    1. 只读审计现状

    请只读检查我的 Q3000 与 R4S 当前网络配置,不要修改任何设置。目标方案是:Q3000 做默认网关和 DHCP,R4S 的 dnsmasq 做前置 DNS 分类;未命中代理域名表的请求由 Q3000 直连,命中的域名由 Mihomo 返回 198.18.0.0/16 Fake-IP,再由 Q3000 静态路由送往 R4S。请检查 DHCP、静态 DHCP、静态路由、Nikki DNS 劫持、dnsmasq 上游、Fake-IP 范围、Mihomo 1053 DNS 监听、Tailscale 回程路由,并先给出风险和回滚点。不要显示或记录任何密钥。
    

    2. 实施前备份并分阶段修改

    请按“先备份、一次只改一层、每层验证、失败自动回滚”的方式实施 Q3000 + R4S 分流。我的主网是 192.168.10.0/24,Q3000 是 192.168.10.1,R4S 是 192.168.10.3,Mihomo Fake-IP 是 198.18.0.0/16。先备份 Q3000 和 R4S 配置;先改 R4S DNS 分类并验证,再改 Q3000 DHCP 与 Fake-IP 静态路由。修改主网网关前提醒我切到备用 Wi-Fi。完成后列出每个 UI 路径、旧值、新值、验证结果和回滚命令。
    

    3. 排查国内 App 卡顿

    当前表现是国外代理正常,但淘宝、微信或其他国内 App 卡顿。请不要先改节点或重写 YAML。先只读确认客户端实际网关和 DNS、Q3000 静态 DHCP 是否覆盖全局 DHCP、国内域名是否返回真实 IP、Nikki IPv4/IPv6 DNS 劫持是否关闭、国内业务包是否仍进入 Mihomo。请用证据定位是哪一层出错,再提出最小修改,并准备回滚。
    

    4. 排查单个网站未代理

    某个域名在当前“dnsmasq 域名分类 + Mihomo Fake-IP”方案下无法访问。请检查它及实际使用的子域名/CNAME 是否命中 /etc/dnsmasq.d/gwf-gfwlist.conf,解析结果是实际 IP 还是 198.18.x.x,Q3000 的 198.18.0.0/16 静态路由是否命中,以及连接是否出现在 Zashboard。只有确认是列表漏收后,才把最小必要主域名加入 gwf-custom.conf,并测试 dnsmasq 语法和访问结果。
    

    5. 检查 Tailscale,不动代理主方案

    请单独诊断 R4S 上的 Tailscale,不修改现有 Nikki/Mihomo 分流。检查 peer 是 direct 还是 DERP、R4S 与远端子网路由器的延迟、子网路由发布/批准状态、NoSNAT 设置,以及 Q3000 是否有 100.64.0.0/10 和远端 LAN 经 192.168.10.3 的回程路由。请区分“家庭分流问题”和“手机运营商/Tailscale 打洞问题”。
    

    6. 生成重装后的复原报告

    请根据实际运行状态生成一份可复原报告,内容包括 Q3000 的 LAN、DHCP、静态 DHCP、VLAN/Wi-Fi、静态路由;R4S 的网络、dnsmasq、Nikki UCI、Mihomo Fake-IP/DNS 监听、Tailscale 与防火墙;并隐去密码、令牌、订阅地址和节点信息。报告中同时给出验证命令和完整回滚顺序。
    

    十九、重装时只记住这四个核心改动

    如果以后重新刷机,整套方案最核心的是:

    1. Q3000 做主网默认网关和 DHCP:客户端网关是 Q3000,不是 R4S。
    2. R4S dnsmasq 做域名分类:普通域名走国内 DNS,代理域名转给 Mihomo 1053。
    3. Q3000 添加 Fake-IP 静态路由:198.18.0.0/16 → R4S。
    4. Nikki 只接管送到 R4S 的连接:关闭 Nikki 全局 DNS 劫持,保留 Mihomo Fake-IP 与代理规则。

    YAML、UI 混入、Tailscale 和备用 Wi-Fi 都是在这四个核心之上的功能层。理解这四点,就不容易在重装时又退回“所有流量先过 R4S”的旧结构。

    二十、附录:完整脚本

    以下脚本与本文附件一致。复制时请保留 Unix 换行符;若从 Windows 编辑器上传,建议先执行 sed -i 's/\r$//' 文件名 清除可能的 CRLF。

    1. update-gfw-dnsmasq.sh

    #!/bin/sh
    
    set -eu
    
    TARGET_DIR="/etc/dnsmasq.d"
    TARGET_FILE="$TARGET_DIR/gwf-gfwlist.conf"
    TMP_LIST="/tmp/gwf-gfwlist.$$.txt"
    TMP_CONF="/tmp/gwf-gfwlist.$$.conf"
    URL_PRIMARY="https://cdn.jsdelivr.net/gh/Loyalsoldier/v2ray-rules-dat@release/gfw.txt"
    URL_FALLBACK="https://raw.githubusercontent.com/Loyalsoldier/v2ray-rules-dat/release/gfw.txt"
    
    cleanup() {
        rm -f "$TMP_LIST" "$TMP_CONF"
    }
    trap cleanup EXIT INT TERM
    
    mkdir -p "$TARGET_DIR"
    
    if ! curl -fsSL --connect-timeout 15 --max-time 120 "$URL_PRIMARY" -o "$TMP_LIST"; then
        curl -fsSL --connect-timeout 15 --max-time 120 "$URL_FALLBACK" -o "$TMP_LIST"
    fi
    
    awk '
        BEGIN {
            print "# Generated from Loyalsoldier/v2ray-rules-dat gfw.txt"
            print "# Matching domains are resolved by Mihomo fake-IP DNS."
        }
        {
            gsub(/\r/, "")
            domain = tolower($0)
            if (domain ~ /^[a-z0-9][a-z0-9._-]*[a-z0-9]$/ && domain ~ /\./) {
                print "server=/" domain "/127.0.0.1#1053"
            }
        }
    ' "$TMP_LIST" | sort -u > "$TMP_CONF"
    
    rule_count="$(grep -c '^server=/' "$TMP_CONF" || true)"
    if [ "$rule_count" -lt 3000 ]; then
        echo "Refusing to install incomplete GFW list: $rule_count rules" >&2
        exit 1
    fi
    
    if ! dnsmasq --test --conf-file="$TMP_CONF" 2>&1 | grep -q 'syntax check OK'; then
        echo "dnsmasq rejected the downloaded configuration" >&2
        exit 1
    fi
    
    if [ -f "$TARGET_FILE" ] && cmp -s "$TMP_CONF" "$TARGET_FILE"; then
        echo "GFW DNS list is already current: $rule_count rules"
        exit 0
    fi
    
    PREVIOUS_FILE=""
    if [ -f "$TARGET_FILE" ]; then
        PREVIOUS_FILE="$TARGET_FILE.previous"
        cp "$TARGET_FILE" "$PREVIOUS_FILE"
    fi
    
    cp "$TMP_CONF" "$TARGET_FILE.new"
    mv "$TARGET_FILE.new" "$TARGET_FILE"
    
    if ! dnsmasq --test 2>&1 | grep -q 'syntax check OK'; then
        if [ -n "$PREVIOUS_FILE" ] && [ -f "$PREVIOUS_FILE" ]; then
            mv "$PREVIOUS_FILE" "$TARGET_FILE"
        else
            rm -f "$TARGET_FILE"
        fi
        echo "dnsmasq rejected the generated configuration" >&2
        exit 1
    fi
    
    if [ -n "$PREVIOUS_FILE" ]; then
        rm -f "$PREVIOUS_FILE"
    fi
    
    /etc/init.d/dnsmasq restart
    echo "Installed $rule_count GFW DNS rules"
    

    2. install-split-dns.sh

    #!/bin/sh
    
    set -eu
    
    if [ ! -f /tmp/update-gfw-dnsmasq.sh ]; then
        echo "Upload update-gfw-dnsmasq.sh to /tmp first" >&2
        exit 1
    fi
    
    BACKUP_DIR="/root/before-split-dns-$(date +%Y%m%d-%H%M%S)"
    mkdir -p "$BACKUP_DIR"
    cp -a /etc/config/dhcp /etc/config/nikki "$BACKUP_DIR/"
    cp -a /etc/crontabs/root "$BACKUP_DIR/crontab-root" 2>/dev/null || true
    cp -a /etc/dnsmasq.d "$BACKUP_DIR/dnsmasq.d" 2>/dev/null || true
    cp -a /usr/local/sbin/update-gfw-dnsmasq "$BACKUP_DIR/update-gfw-dnsmasq" 2>/dev/null || true
    echo "$BACKUP_DIR" > /root/last-split-dns-backup
    
    mkdir -p /etc/dnsmasq.d /usr/local/sbin
    
    uci set dhcp.@dnsmasq[0].confdir='/etc/dnsmasq.d'
    uci set dhcp.@dnsmasq[0].noresolv='1'
    uci set dhcp.@dnsmasq[0].rebind_protection='0'
    uci set dhcp.@dnsmasq[0].localservice='0'
    uci -q delete dhcp.@dnsmasq[0].server || true
    uci add_list dhcp.@dnsmasq[0].server='223.5.5.5'
    uci add_list dhcp.@dnsmasq[0].server='223.6.6.6'
    uci commit dhcp
    
    uci set nikki.proxy.ipv4_dns_hijack='0'
    uci set nikki.proxy.ipv6_dns_hijack='0'
    uci commit nikki
    
    cp /tmp/update-gfw-dnsmasq.sh /usr/local/sbin/update-gfw-dnsmasq
    chmod 0755 /usr/local/sbin/update-gfw-dnsmasq
    /usr/local/sbin/update-gfw-dnsmasq
    
    cron_line='17 4 * * * /usr/local/sbin/update-gfw-dnsmasq >/tmp/update-gfw-dnsmasq.log 2>&1'
    touch /etc/crontabs/root
    if ! grep -Fqx "$cron_line" /etc/crontabs/root; then
        printf '%s\n' "$cron_line" >> /etc/crontabs/root
    fi
    
    /etc/init.d/cron restart
    /etc/init.d/nikki restart
    /etc/init.d/dnsmasq restart
    
    echo "Backup: $BACKUP_DIR"
    echo "Split DNS installed"
    

    3. rollback-split-dns.sh

    #!/bin/sh
    
    set -eu
    
    POINTER="/root/last-split-dns-backup"
    if [ ! -s "$POINTER" ]; then
        echo "Backup pointer not found: $POINTER" >&2
        exit 1
    fi
    
    BACKUP_DIR="$(cat "$POINTER")"
    if [ ! -d "$BACKUP_DIR" ]; then
        echo "Backup directory not found: $BACKUP_DIR" >&2
        exit 1
    fi
    
    cp "$BACKUP_DIR/dhcp" /etc/config/dhcp
    cp "$BACKUP_DIR/nikki" /etc/config/nikki
    
    if [ -f "$BACKUP_DIR/crontab-root" ]; then
        cp "$BACKUP_DIR/crontab-root" /etc/crontabs/root
    else
        sed -i '\|/usr/local/sbin/update-gfw-dnsmasq|d' /etc/crontabs/root 2>/dev/null || true
    fi
    
    if [ -f "$BACKUP_DIR/update-gfw-dnsmasq" ]; then
        cp "$BACKUP_DIR/update-gfw-dnsmasq" /usr/local/sbin/update-gfw-dnsmasq
        chmod 0755 /usr/local/sbin/update-gfw-dnsmasq
    else
        rm -f /usr/local/sbin/update-gfw-dnsmasq
    fi
    
    if [ -f "$BACKUP_DIR/dnsmasq.d/gwf-gfwlist.conf" ]; then
        cp "$BACKUP_DIR/dnsmasq.d/gwf-gfwlist.conf" /etc/dnsmasq.d/gwf-gfwlist.conf
    else
        rm -f /etc/dnsmasq.d/gwf-gfwlist.conf
    fi
    
    /etc/init.d/cron restart
    /etc/init.d/nikki restart
    /etc/init.d/dnsmasq restart
    
    echo "R4S split DNS rolled back from $BACKUP_DIR"
    

    二十一、参考资料


    **最后提醒:**这套方案的目标不是让规则数量最多,而是把国内直连路径变得简单,把复杂代理判断限制在真正需要代理的连接上。修改后必须以客户端实际拿到的网关/DNS、DNS 返回结果、Q3000 路由命中和 Mihomo 连接记录为准,不能只看 UI 中某个开关。