avatar🌌
seewhyseewhy的小木屋

宠辱不惊,看庭前花开花落。 去留无意,望天空云卷云舒。

在 FlClash Android 中使用 Tailscale

背景

最近在整理手机上的代理配置,碰到一个比较具体的问题:Android 上想同时使用代理和 Tailscale。

我平时手机上会开 Clash 类客户端,主要用来走代理规则。同时又希望手机能通过 Tailscale 访问家里的 Mac mini,比如用 CC Pocket 连 Mac 上的 bridge。桌面端还好,Tailscale 和 Clash Verge 可以同时跑,通过路由排除就能共存。但 Android 上麻烦一点,因为官方 Tailscale App 和代理 App 都要占用系统 VPN。

后来发现 FlClash 使用的 mihomo 内核已经支持 type: tailscale 出站,于是就尝试把 Tailscale 放进 FlClash 配置里,让它作为一个特殊节点使用。

这篇记录一下配置和排查过程。主要是为了以后自己再换手机时别踩同样的坑。

大概思路

最终思路是:

  • FlClash 继续作为 Android 上唯一的 VPN。
  • 普通外网流量按原来的代理规则走。
  • 100.64.0.0/10 这段 Tailscale 地址走 mihomo 内置的 Tailscale 出站。
  • 局域网地址,比如 192.168.0.0/16,继续直连。

也就是把 Tailscale 当成一个代理节点来用,而不是再单独开官方 Tailscale App。

我这里用的是 FlClash,内核是 mihomo。测试时版本大概是:

  • FlClash:0.8.93

版本以后肯定会变,这里只是记录一下当时的环境。

Tailscale 出站配置

核心配置是一个 type: tailscale 的 proxy:

yaml
proxies:
  - name: TAILSCALE
    type: tailscale
    hostname: flclash-android
    auth-key: tskey-auth-xxxx
    control-url: https://controlplane.tailscale.com
    state-dir: ./tailscale
    ephemeral: false
    udp: true
    accept-routes: true
    ip-version: ipv4-prefer

这里有几个字段比较关键:

  • hostname:这个设备在 Tailscale 里显示的名字。
  • auth-key:Tailscale 的授权 key,这个不要公开。
  • state-dir:Tailscale 本地状态目录,后面踩坑主要就在这里。
  • accept-routes:是否接受 Tailscale 路由,我这里先开着。

我一开始还试过给 TAILSCALEdialer-proxy,想让它通过代理去连 Tailscale 控制面。结果在 Android 上遇到过类似这样的错误:

text
magicsock: Rebind IPv4 failed: failed to bind any ports

最后还是去掉了 dialer-proxy,让它直接走当前网络。至少我这里这样更稳定。

规则配置

然后需要在规则里把 Tailscale 网段放到前面:

yaml
proxy-groups:
  - name: Tailscale
    type: select
    proxies:
      - TAILSCALE
      - DIRECT

rules:
  - IP-CIDR,100.64.0.0/10,Tailscale,no-resolve
  - IP-CIDR,100.100.100.100/32,Tailscale,no-resolve
  - DOMAIN-SUFFIX,ts.net,Tailscale
  - IP-CIDR,192.168.0.0/16,DIRECT,no-resolve
  - IP-CIDR,10.0.0.0/8,DIRECT,no-resolve
  - IP-CIDR,172.16.0.0/12,DIRECT,no-resolve
  - IP-CIDR,169.254.0.0/16,DIRECT,no-resolve
  # 其他代理规则
  - MATCH,节点选择

这里 100.64.0.0/10 是 Tailscale 使用的 CGNAT 网段,100.100.100.100 是 Tailscale DNS。规则要尽量靠前,不然可能先被其他规则截走。

局域网地址我还是直接放行。比如手机在家里访问 192.168.x.x,就没必要绕 Tailscale。

FlClash 的应用白名单

我手机上 FlClash 用的是白名单模式,也就是只有选中的 App 才进入 VPN。

这个地方也容易误判。如果某个 App 没有被选中,它根本不会进入 FlClash,也就不会走内置 Tailscale。

比如我要用 CC Pocket 访问 Mac mini,就要确认 CC Pocket 在 FlClash 的白名单里。否则它访问 100.x.x.x 时,既不会走代理,也不会走 FlClash 里的 Tailscale 出站。

这个可以通过 adb 看一下 VPN 里包含哪些 UID:

bash
adb shell 'dumpsys connectivity | grep -A6 "VPN CONNECTED" | grep "Uids"'
adb shell 'dumpsys package com.k9i.ccpocket | grep appId | head -1'

如果 CC Pocket 的 appId 不在 VPN 的 Uids 范围里,那就是白名单没勾上。

怎么验证

调试时我主要用了 mihomo 的本地 API。FlClash 默认会开一个本地控制端口,我这里是 127.0.0.1:9090

先看 Tailscale 出站有没有被加载:

bash
adb shell 'curl -s http://127.0.0.1:9090/proxies/TAILSCALE'

如果能看到类似 type: Tailscale 的信息,说明配置至少被 mihomo 识别了。

然后访问一个 Tailscale IP。因为 adb shell 本身不一定在 FlClash 的 VPN 白名单里,所以不能直接用普通 curl 判断。更稳的方法是显式走 mihomo 的 HTTP 代理口:

bash
adb shell 'curl -v -x http://127.0.0.1:7890 --connect-timeout 8 http://100.x.x.x:8765/health'

如果命中规则,日志里应该能看到类似:

text
match IPCIDR(100.64.0.0/10) using Tailscale[TAILSCALE]

也可以抓实时日志:

bash
adb shell 'curl -s "http://127.0.0.1:9090/logs?level=debug" | grep -iE "tailscale|tsnet|magicsock|100\\."'

另外在 Mac 上也可以看 Tailscale 状态:

bash
/Applications/Tailscale.app/Contents/MacOS/Tailscale status

如果成功,应该能看到 flclash-android 这个节点变成 active。

CC Pocket 的 404

后面还有一个小插曲。

我用 CC Pocket 连 Mac mini,局域网地址 192.168.x.x:8765 正常,但 Tailscale 地址 100.x.x.x:8765 一直看起来不对。一开始怀疑是 Android 版 CC Pocket 或官方 Tailscale App 有问题。

后来才发现是 Mac 上有一个之前测试时留下的 Python HTTP 服务,刚好绑定在 Tailscale IP 的 8765 端口。结果访问 100.x.x.x:8765 时命中的是这个测试服务,而不是 CC Pocket bridge;访问 192.168.x.x:8765 时才命中真正的 bridge。

可以用这个命令查:

bash
lsof -nP -iTCP:8765 -sTCP:LISTEN

停掉那个 Python 服务后,两个地址都打到了同一个 bridge。

另一个容易误会的点是,不要只根据浏览器打开 / 的结果判断服务是否正常。我们当时看到过 404,但真正的问题不是 URL 协议写错,而是请求打到了另一个占用端口的测试服务。

所以这类问题最好先确认端口背后到底是谁在监听,再看应用自己的健康检查接口:

bash
curl http://100.x.x.x:8765/health

最后

目前这套方案已经能满足我的需求:Android 上只开 FlClash,一个 VPN 同时处理代理和 Tailscale 访问。

整体感觉可用,但排查时要记住几件事:

  • Android 上官方 Tailscale App 和 FlClash 不能同时作为系统 VPN。
  • type: tailscale 是否真的登录成功,要看日志和 tailnet 状态。
  • 白名单模式下,目标 App 必须进 FlClash VPN。
  • state-dir 不要随便改。
  • 看到 HTTP 404 时先确认访问的是不是正确协议和正确服务。

这次折腾下来,感觉最有用的还是日志。规则看起来都对的时候,不要继续猜,直接看 mihomo logs 里 Tailscale 有没有真的登录成功。

we-mp-rss 的自动化扫码登录方案
Valaxy v0.28.11 驱动|主题-Yunv0.28.11