适用场景

本文适用于以下组合:

  • 系统为 Arch Linux;
  • 使用 NetworkManager 创建 Wi-Fi 热点;
  • 使用 Clash Verge Rev,其内核为 Mihomo;
  • 已启用 TUN 模式;
  • 热点客户端可以连接、可以获取 IP 地址,但无法打开网站;
  • 关闭 TUN 后,热点客户端立即恢复联网。

以下名称仅为示例,实际环境必须替换为本机名称:

项目 示例值
热点连接名称 test4096
热点无线接口 wlp2s0
上网接口 enp3s0
热点网段 10.42.0.0/24
热点网关与 DNS 10.42.0.1

本文的修复目标是:保持主机的 TUN 模式,同时让热点客户端通过物理上网接口正常访问互联网。 热点客户端不会因此自动使用主机的 Clash 代理,相关限制见文末。

现象与结论

典型现象如下:

  1. 主机本身可以正常访问互联网。
  2. 热点客户端能够关联 Wi-Fi,并通过 DHCP 获取 10.42.0.x 地址。
  3. 关闭 Clash Verge 的 TUN 模式后,客户端可以访问互联网。
  4. 启用 TUN 模式后,客户端无法访问域名或网页。

此问题通常不是热点的 NAT 或防火墙规则缺失,而是以下两项设置组合后的 DNS 路径不一致:

  1. exclude-interface: wlp2s0 让热点客户端的数据不进入 TUN;
  2. 热点使用的 dnsmasq 仍然进入 TUN,获得了 Mihomo 的 Fake-IP DNS 回答。

客户端得到 198.18.x.x 形式的 Fake-IP 后,会尝试经物理上网接口直接连接这个地址。Fake-IP 仅能由 Mihomo TUN 解释和转发;客户端流量已经绕过 TUN,因此连接失败。

相关概念

TUN

TUN 是一个虚拟网络接口。Mihomo 可以通过它接收主机发出的网络连接,再按代理规则转发。启用 auto-route 后,Mihomo 会添加路由规则,使符合条件的流量进入该接口。

NetworkManager 共享模式

NetworkManager 的热点共享模式会完成三项工作:

  1. 为热点接口分配私有网段地址,例如 10.42.0.1
  2. 启动 dnsmasq,为客户端分配 IP 地址并提供 DNS;
  3. 添加 NAT 和转发规则,使 10.42.0.0/24 的客户端能够经主机的上网接口访问外部网络。

NAT 是“网络地址转换”。它会把客户端的私有地址转换成主机的上网地址,使外部网络的返回数据能够回到正确的客户端。

Fake-IP

Fake-IP 是 Mihomo 常用的 DNS 工作方式。DNS 查询会得到一个保留地址,例如 198.18.0.119,而不是网站的真实公网地址。之后,进入 TUN 的连接由 Mihomo 根据这个地址还原网站域名并转发。

因此,Fake-IP 不是可以直接通过路由器访问的公网地址。发送给 Fake-IP 的连接必须经过 Mihomo。

UID

UID 是 Linux 用于标识用户和进程的数字。一个服务进程以哪个用户运行,就拥有对应的 UID。Mihomo 的 exclude-uid 可以让指定 UID 发出的本机流量不进入 TUN。

在常见的 Arch Linux NetworkManager 配置中,热点 dnsmasqnobody 用户运行,其 UID 通常为 65534。该值必须在本机确认,不能仅凭经验固定填写。

故障路径

仅排除热点接口时

为热点接口加入排除规则后,普通客户端数据会走物理上网接口:

1
2
3
4
5
热点客户端
-> wlp2s0
-> NetworkManager 转发与 NAT
-> enp3s0
-> 路由器与互联网

这条路径是正确的。但 DNS 的路径不同:

1
2
3
4
5
热点客户端
-> 10.42.0.1:53
-> dnsmasq(主机本地进程)
-> Mihomo TUN
-> Fake-IP 回答,例如 198.18.0.119

exclude-interface 只匹配从 wlp2s0 接收的数据包。dnsmasq 向上游 DNS 发起的查询是主机本地生成的数据包,没有 wlp2s0 这个入站接口,因此仍可能被 TUN 接管。

加入 dnsmasq UID 排除后

1
2
3
4
5
6
热点客户端
-> 10.42.0.1:53
-> dnsmasq(UID 65534)
-> 物理上网接口
-> 上游 DNS
-> 真实公网 IP

此时,客户端获得真实公网 IP;客户端的普通流量也经物理上网接口发送,DNS 结果与数据路径一致,网站可以正常访问。

排查步骤

1. 确认热点接口和上网接口

1
2
nmcli device status
ip -br addr

确认热点使用的无线接口,例如 wlp2s0,以及主机实际连接互联网的接口,例如 enp3s0。接口名称因设备而异,不应直接套用示例名称。

2. 检查热点客户端的出站路由

10.42.0.209 替换为一个已连接客户端的实际地址:

1
ip route get 1.1.1.1 from 10.42.0.209 iif wlp2s0

在本例中,正确结果应类似:

1
1.1.1.1 from 10.42.0.209 via 192.168.1.1 dev enp3s0

其中 dev enp3s0 表示客户端流量会从物理上网接口离开主机。若结果显示 dev Mihomo,说明热点接口排除未生效,或编辑的不是当前生效的 Merge 配置。

3. 检查 NetworkManager 的 NAT 与转发规则

1
sudo nft -a list ruleset

共享热点正常时,应存在类似以下规则:

1
2
3
4
5
6
7
8
9
10
11
12
table ip nm-shared-wlp2s0 {
chain nat_postrouting {
type nat hook postrouting priority srcnat; policy accept;
ip saddr 10.42.0.0/24 ip daddr != 10.42.0.0/24 masquerade
}

chain filter_forward {
type filter hook forward priority filter; policy accept;
ip saddr 10.42.0.0/24 iifname "wlp2s0" accept
ip daddr 10.42.0.0/24 oifname "wlp2s0" ct state { established, related } accept
}
}

masquerade 表示 NAT 已启用;从 wlp2s0 进入的流量和返回 wlp2s0 的已建立连接均被允许。若这些规则存在,且第 2 步的路由结果指向物理上网接口,问题通常不在 NAT 或转发规则。

4. 确认 dnsmasq 的 UID

1
2
ps -eo user,uid,pid,args | rg '[d]nsmasq|nm-dnsmasq'
id -u nobody

常见输出形式如下:

1
2
nobody  65534  1234  /usr/sbin/dnsmasq ...
65534

第一列是运行用户,第二列是 UID。若 dnsmasq 的 UID 不是 65534,后续配置必须使用实际输出的数字。

5. 直接查询热点 DNS

安装 bind 后可使用 dig

1
2
sudo pacman -S bind
dig @10.42.0.1 example.com A +short

在出现该问题的配置中,可能得到 198.18.x.x。该网段是常见的 Fake-IP 地址范围,不是 example.com 应直接访问的公网地址。修复后,结果应为正常公网地址,且不应位于 198.18.0.0/15

修复方法

1. 编辑当前订阅的 Merge 配置

在 Clash Verge Rev 的配置界面中,打开当前正在使用的订阅,编辑其 Merge 配置。不同版本的界面可能将该入口显示为 MergeMixin 或“合并配置”。

不要直接编辑以下运行时文件:

1
~/.local/share/io.github.clash-verge-rev.clash-verge-rev/clash-verge.yaml

该文件由 Clash Verge Rev 生成,重启内核或切换配置后可能被覆盖。它适合用于检查最终配置,不适合作为持久化修改位置。

在已有的 tun: 配置块中加入以下内容。不要在同一个 YAML 文件中重复创建第二个 tun: 块。

1
2
3
4
5
tun:
exclude-interface:
- wlp2s0
exclude-uid:
- 65534

说明:

  • wlp2s0 必须替换为热点实际使用的无线接口;
  • 65534 必须替换为第 4 步查到的 dnsmasq UID;
  • 保留原有的 enableauto-routedns-hijackstack 等 TUN 设置;这里只是向原有 tun: 块补充两项排除规则。

exclude-interface 处理热点客户端转发的流量,exclude-uid 处理 dnsmasq 进程主动发出的 DNS 查询。两项规则需要同时存在。

2. 重载内核并重新连接客户端

保存 Merge 配置后,在 Clash Verge Rev 中重启 Mihomo 内核。随后让热点客户端断开 Wi-Fi 再重新连接,以清除客户端可能缓存的旧 DNS 结果。

可以检查生成后的运行时配置是否包含这两项设置:

1
2
rg -n -C 3 'exclude-interface|exclude-uid' \
~/.local/share/io.github.clash-verge-rev.clash-verge-rev/clash-verge.yaml

该检查仅适用于通过常规 Arch Linux 软件包安装的 Clash Verge Rev。若使用 Flatpak 或其他安装方式,应从应用界面确认最终生效的配置。

验证结果

按以下顺序验证,可以区分网络转发问题和 DNS 问题:

  1. 在热点客户端上访问 1.1.1.1,或执行 ping -c 3 1.1.1.1。成功说明 IPv4 转发和 NAT 基本正常。
  2. 在主机上执行 dig @10.42.0.1 example.com A +short。结果不应为 198.18.x.x
  3. 在客户端浏览器中访问普通域名,例如 https://example.com
  4. 再次执行第 2 节中的 ip route get 命令,确认客户端流量仍经物理上网接口离开主机。

常见异常

现象 可能原因 处理方式
路由结果显示 dev Mihomo 热点接口名称错误,或 Merge 配置未生效 检查 ip -br addr、当前订阅和内核重载状态
DNS 仍返回 198.18.x.x dnsmasq UID 不是 65534,或 UID 排除未生效 重新执行 ps -eo user,uid,pid,args,使用实际 UID
可以访问 IP,不能访问域名 DNS 路径仍被 TUN 生成 Fake-IP 检查 exclude-uid 与热点 DNS 地址
IP 地址也无法访问 不是本问题的 DNS 情况 检查 nft 规则、上网接口、每个接口的 IPv4 转发状态
客户端偶发无法访问部分网站 热点启用了 IPv6,但上游没有可共享的 IPv6 前缀 单独检查 IPv6,必要时关闭热点连接的 IPv6 共享

若没有 IPv6 上游网络,并且确认问题来自 IPv6,可关闭该热点连接的 IPv6:

1
2
3
nmcli connection modify test4096 ipv6.method disabled
nmcli connection down test4096
nmcli connection up test4096

这不是 Fake-IP 问题的主要修复,只用于处理没有 IPv6 上游时客户端优先使用 IPv6 所产生的额外现象。

exclude-uid 的影响范围

exclude-uid: 65534 不只匹配 DNS 端口,它会让所有以 UID 65534 运行的本机进程绕过 TUN。通常该 UID 只有 dnsmasq 等低权限服务使用,但应先检查实际范围:

1
ps -eo user=,uid=,comm= | awk '$2 == 65534'

若有其他需要强制经过代理的服务也使用该 UID,应重新评估该方案。对于 NetworkManager 热点使用的独立 dnsmasq 进程,此排除通常足够小,且能避免 DNS 得到与客户端数据路径不匹配的 Fake-IP。

为什么 Windows 中可能没有此问题

Windows 的 Internet Connection Sharing、DNS 服务和 TUN 驱动与 Arch Linux 中的 NetworkManager、dnsmasq、Mihomo 路由规则不是同一套实现。Windows 中热点 DNS 服务可能没有进入 TUN,或 TUN 驱动对共享流量有不同处理,因此相同操作不一定复现问题。

应根据实际数据路径判断,而不是假设两个系统的热点共享行为一致。

适用边界

本文配置让热点客户端绕过 TUN 并直接通过主机的物理上网接口访问互联网。它解决的是“开启主机 TUN 后,热点客户端无法上网”的问题。

若目标是让热点客户端的全部流量也经过 Clash 代理,则需要单独设计透明代理、路由标记和 DNS 规则,不能仅删除 exclude-interface。否则容易再次出现循环路由、Fake-IP 无法访问或客户端流量被错误丢弃的问题。

参考资料