openwrt配置肥猫云科学上网

背景

肥猫云在四月份以后改用了独立的客户端,取代了订阅模式,导致家里的每个设备都要安装客户端,太麻烦了。

官方推出了openwrt的版本,经过分析后,是一个netflow+mihomo的套壳项目。

概述

肥猫云 Lite 原包 luci-app-fcclient_3.0.7-202605210720_all.ipk 是一个 OpenWrt 路由器上的套壳代理方案,由三个组件叠加而成:

LuCI 管理界面 (Lua)
    ↕
netflow 后端 (Go binary)  ← 套壳层
    ↕
mihomo (Go binary)        ← 代理核心

组件拆解

1. 代理核心:mihomo

版本: Mihomo Meta v1.19.27 (linux arm64, go1.26.4)

负责实际的代理功能。以子进程方式运行,由 netflow 后端启动和管理。

运行参数:

mihomo -d /etc/netflow/mihomo -f <临时配置文件>
  • -d /etc/netflow/mihomo — 工作目录(geoip/geosite 等数据库所在目录)
  • -f <临时文件> — 配置文件由 netflow 动态生成,存放在 /tmp/.nf_*

关键特性:

  • 使用 geodata 模式(geoip.dat + geosite.dat
  • 支持 VLESS Reality、Shadowsocks、Trojan 等多种协议
  • 自带 RESTful API(外部控制端口 9091)
  • TUN 模式支持(但默认关闭)

2. 套壳层:netflow 后端

位置: /usr/bin/netflow → 符号链接到 netflow_aarch64(Go binary,UPX 压缩) 端口: 127.0.0.1:9190 技术: Go 语言,编译为静态链接二进制,UPX 压缩减少体积

职责

功能 实现方式
管理 mihomo 作为父进程启动/停止 mihomo,监控其运行状态
订阅更新 调用 v2board 面板 API 获取节点列表
配置生成 解密订阅数据 → 生成 mihomo 配置文件 → 写入临时文件
数据加密 使用 /etc/netflow/.dev_salt 做 AES 加密
iptables 管理 理论上负责设置透明代理规则,但实际未生效

配置存储

UCI 配置 (/etc/config/netflow)
  ├── netflow.config      # 基本设置(端口、模式等)
  └── netflow.v2board     # 订阅登录信息(加密存储)

文件存储
  ├── /etc/netflow/config.yaml     # mihomo 配置文件(或临时文件)
  ├── /etc/netflow/mihomo/         # mihomo 工作目录
  │   ├── mihomo                   # mihomo 二进制
  │   ├── geoip.dat                # IP 地理数据库
  │   ├── geosite.dat              # 域名分类数据库
  │   └── config.yaml              # 启动后的配置文件
  ├── /etc/netflow/v2board/
  │   └── subscribe.enc            # 加密的订阅数据
  └── /etc/netflow/.dev_salt       # 设备专属加密盐

加密机制

安装时生成 .dev_salt(32 字节随机数 → 64 位 hex)
    ↓
UCI 中存储的密码/api_url → ENC:base64(AES(salt, 明文))
    ↓
订阅数据 → subscribe.enc → AES(salt, 节点JSON)

3. 管理界面:LuCI

位置:

  • 控制器: /usr/lib/lua/luci/controller/netflow.lua
  • 视图: /usr/lib/lua/luci/view/netflow/main.htm
  • 权限: /usr/share/rpcd/acl.d/luci-app-fcclient.json

负责在 OpenWrt 的 Web 管理界面提供操作面板,功能包括:

  • 输入/修改订阅账号
  • 查看连接状态
  • 切换代理模式
  • 触发订阅更新

RPC 权限文件定义了后端 API 的访问控制。

数据流

订阅更新流程

用户点击"更新订阅"
    ↓
LuCI → RPC → netflow 后端 (127.0.0.1:9190)
    ↓
netflow 解密 UCI 中的 api_url / token
    ↓
调用 v2board 面板 API → 获取节点列表
    ↓
AES 加密 → 写入 subscribe.enc
    ↓
解密 subscribe.enc → 生成 mihomo config.yaml
    ↓
重启 mihomo 进程

代理数据流

局域网设备
    ↓ (iptables REDIRECT / TPROXY / 手动设代理)
mihomo (7890 mixed / 7892 redir)
    ↓ (规则匹配: GEOIP / GEOSITE / DOMAIN-SUFFIX)
代理策略组 (手动 / url-test / fallback)
    ↓ (VLESS Reality 加密隧道)
节点服务器 (35.78.84.79)
    ↓
目标网站

v2board API 对接

netflow 后端实现了 v2board 面板的客户端协议:

  • api/v1/passport/auth/login — 登录获取 token
  • api/v1/user/getSubscribe — 获取订阅元信息
  • api/v1/client/subscribe — 获取实际节点配置

关键设计缺陷

1. iptables 规则未正确配置

prerm 脚本中有 iptables 清理命令,证明 netflow 应该管理透明代理:

iptables -t nat -D PREROUTING -j NETFLOW
iptables -t nat -D PREROUTING -p dport 53 -j REDIRECT --to-ports 7874

但实际运行时 nat 表是空的。可能是:

  • netflow 二进制的 UPX 压缩导致这段代码被省略了
  • 或者此功能在当前版本已移除

2. 订阅加密导致配置不透明

subscribe.enc 使用设备专属 salt 加密,导致:

  • 无法直接查看/修改节点配置
  • 无法将订阅数据迁移到另一台设备
  • mihomo 的配置文件必须由 netflow 生成,无法直接编辑

3. 节点域名依赖特殊 DNS

节点使用的域名(如 a002-lite01.llguangli25n.com)在公共 DNS 中不存在,只有通过 fcclient App 的 TUN/fake-ip 系统才能解析。路由器上的 mihomo 无法直接解析这些域名。

关键发现

订阅系统分析

  • Mac App 使用新 API: fcapi.apiv2.a047.com/api/v1/passport/auth/login
  • 路由器 使用旧 v2board API,返回过期节点
  • 订阅元数据 API: user/getSubscribe?auth_data=JWT 返回套餐/UUID/订阅地址
  • 实际节点配置服务器: fcsblka.fcsubcn.cc:2096(定制 TLS,无法从外部连接)

找到真实节点 IP

  • 通过 Mac 的 netstat 观察到所有节点都连接到 35.78.84.79
  • 路由器 ping 该 IP 可达 (~41ms)

获取jwt token

完整的过程在这里:

# ============================================
# 第1步:登录获取 JWT令牌
# ============================================
curl -X POST "https://fcapi.apiv2.a047.com/api/v1/passport/auth/login" \
  -H "User-Agent: fcclient/3.0.7" \
  -H "Content-Type: application/json" \
  -d '{"email":"xxxxxxxxx@gmail.com","password":"xxxxxxx"}'

# 返回结果:
{
  "status": "success",
  "data": {
    "token": "dW4h1Z87kQQ9vDHrMxxxxxxxxxxxx",
    "auth_data": "eyJ0eXAiOiJKV1QiLCJhxxxxxxxxx.eyJpZCI6MTkyOTg3LCJxxxxxxxxxzdmMGVkMGVhM2VkOWZmYWM0ZWU0NjgyZWFiOTI0NjYifQ.7WpSShJZjn2a3IvVxxxxxxxxiC79LMqLnO1xZw"
  }
}

# ============================================
# 第2步:获取订阅元信息(套餐/UUID/流量/订阅地址)
# ============================================
# 用上一步返回的 auth_data 作为 query 参数
curl "https://fcapi.apiv2.a047.com/api/v1/user/getSubscribe?auth_data=eyJ0eXAiOiJKV1QixxxxxxxJ9.eyJpZCI6MTkyOTg3LCJzZXNzxxxxxxxxGVkMGVhM2VkOWZmYWM0ZWU0xxxxxx0NjYifQ.7WpSShJZjn2a3IvVxxxxxxxxC79LMqLnO1xZw" \
  -H "User-Agent: fcclient/3.0.7"

# 返回结果:
{
  "status": "success",
  "data": {
    "plan_id": 5,
    "token": "dW4h1Z87kQQ9vDHrMgzrmDBlGrDIo3Gm",
    "expired_at": 1825999987,
    "u": 394537826,
    "d": 7870981628,
    "transfer_enable": 64424509440,
    "email": "xxxxxxxxx@gmail.com",
    "uuid": "5xxxxx7-cxxx2-4xxe-89xxx7-67dbbxxxx2",
    "plan": { "name": "肥猫小包", "id": 5, "transfer_enable": 60 },
    "subscribe_url": "https://fcsblka.fcsubcn.cc:2096/api/v1/client/subscribe?token=dW4h1Z87kQQ9vDHrMgzrmDBlGrDIo3Gm",
    "reset_day": 24
  }
}

最终方案

架构

去掉netflow,直接使用mihomo作为透明代理

局域网设备 → 路由器 (iptables 透明代理) → mihomo → 35.78.84.79 (VLESS Reality 节点) → 外网

配置要点

  • 60 个 VLESS Reality 节点 (HK20/TW10/SG10/JP10/US10),全部指向 35.78.84.79
  • 策略组: 🚀 节点选择(手动) / 自动选择(url-test) / 故障转移(fallback)
  • 规则: .cn/GEOIP 直连,google/github/youtube 走代理,其余兜底代理
  • Web 面板: http://192.168.1.1/yacd/ (Yacd-meta),API 密钥 netflow_secret

部署的文件

文件 说明
/etc/netflow/mihomo/config.yaml mihomo 主配置 (60 节点 + 策略 + 规则)
/etc/init.d/mihomo procd 服务管理脚本 (开机自启 + 崩溃重启)
/root/tproxy.sh iptables 透明代理启停脚本 (start/stop/status)
/root/watchdog.sh 看门狗 (cron 每分钟执行,挂了自动重启,重启失败则关 iptables)
/etc/rc.local 开机启动 mihomo + 透明代理
/www/yacd/ Yacd-meta Web 面板 (可通过 http://192.168.1.1/yacd/ 访问)

命令速查

# mihomo 服务管理
/etc/init.d/mihomo start|stop|restart|status
/etc/init.d/mihomo enable|disable  # 开机自启

# 透明代理
/root/tproxy.sh start|stop|status|restart

# 查看日志
logread -e mihomo
cat /tmp/netflow_mihomo.log

# Web 面板
http://192.168.1.1/yacd/   # 连接 192.168.1.1:9091 密钥 netflow_secret

# 添加规则 (sed 免 vi)
sed -i '/DOMAIN-SUFFIX,google.com/i\  - DOMAIN-SUFFIX,baidu.com,DIRECT' /etc/netflow/mihomo/config.yaml
/etc/init.d/mihomo restart

容错机制

场景 结果
mihomo 崩溃 procd 自动重启 + 看门狗兜底
mihomo 重启失败 看门狗自动关闭 iptables,网络恢复
DNS 失效 dnsmasq 直接响应,不依赖 mihomo DNS

待办/风险

  • 35.78.84.79 可能是动态 IP,失效后需重新获取
  • 订阅数据无法直接获取,依赖 Mac 抓包找 IP
  • dnsmasq 上游配置 127.0.0.1#7874 如需调整

对比:我们最终的路由器方案

方面 肥猫云原版 我们的方案
mihomo 管理 netflow 后端生成临时配置 直接编辑固定配置文件
透明代理 依赖 netflow 设置 iptables 独立 tproxy.sh 脚本管理 TPROXY
规则管理 通过订阅数据固定生成 rule-provider / GEOSITE 自动更新
设备白名单 无内置支持 TPROXY 按源 IP 限制
日志管理 无独立配置 procd init 脚本托管
看门狗 cron 脚本监控+自动恢复
容错 mihomo 挂了 iptables 还劫持 看门狗自动关闭 TPROXY
DNS 无独立防污染 sniffer + force-dns-mapping
Web 面板 LuCI 界面 Yacd + external-controller

评论

评论功能即将上线,敬请期待。