Files
cellular-proxy/README.md
T
Hermes 88f2ff44aa fix(detect): never bind USB gadget iface as proxy egress
设备把自己当 USB 网卡挂给上游主机时会出现 usb0(驱动 configfs-gadget.g1,
IP 192.168.68.1)。该链路只通向 PC,被当成出口后所有出站都 context
deadline exceeded,客户端看到 socks connect failed rep=0x01。

误选原因:score_iface_as_cellular 给 usb0 与真出口 wwan0 都打 175 分。
usb0 靠名称命中 patterns 里的 usb(+80)与非默认路由(+40);wwan0 的
bam-dmux 驱动不在白名单里,白丢 +100。detect_cellular_iface 用 -gt 比较,
list_ifaces 按名排序让 usb0 先入选,平分下无法被顶替。

改动:
- lib.sh 新增 iface_is_usb_gadget(),按驱动名与 gadget 总线路径识别,
  并并入 is_virtual_or_skip_iface(usb0 评分 175 -> 0)
- 驱动白名单补 bam-dmux/bam_dmux/qcom-ipa/ipa_wan;名称权重 80 -> 40,
  确保驱动证据始终压过名称猜测
- 新增 detect_cellular_iface_via_mm(),把 ModemManager bearer 的
  interface: 作为第 0 步权威来源
- detect_cellular_iface / resolve_cellular 全链路拒绝 gadget 网卡,
  取不到真出口时按 REQUIRE_CELLULAR_IFACE 直接失败而不是绑错
- generate/install/upgrade/watch/detect/verify 各入口独立设闸,
  verify.sh 发现出口是 gadget 时直接 exit 4 并给出修复命令
- 默认 CELLULAR_IFACE_PATTERNS 去掉 usb/enx;upgrade.sh 与根 install.sh
  就地迁移已有 settings.conf,旧机器升级即修复
- 新增 tests/detect-gadget.sh:18 条离线断言,无需真机
2026-08-23 18:39:34 +08:00

164 lines
6.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# cellular-proxy
轻量 **「走代理 = 走数据流量」**(无 frp,512MB 友好)。
## 语义
| 流量 | 出口 |
|------|------|
| **不走** 本代理 | 系统默认(通常 WiFi) |
| **走** 本代理 | **一律数据网卡**(自动探测并 bind |
## ★ 一条命令(安装 / 升级通用)
```bash
curl -fsSL 'https://gitea.chickliu.fun/Hermes/cellular-proxy/raw/branch/main/install.sh' | sudo bash
```
| 机器状态 | 行为 |
|----------|------|
| **未安装** | 全量安装:探测网卡 → 下 sing-box → 启动 → 验证 |
| **已安装** | 增量升级:保留密钥/网卡/账密,更新 UI/scripts,默认不重下二进制 |
不需要记 `--upgrade` / `--install`**同一条命令反复执行即可**。
可选覆盖(首次安装常用):
```bash
curl -fsSL 'https://gitea.chickliu.fun/Hermes/cellular-proxy/raw/branch/main/install.sh' | sudo bash -s -- \
--iface wwan0 \
--secret '面板密钥' \
--user proxy \
--pass '代理密码'
```
| 选项 | 说明 |
|------|------|
| (无参数) | **自动**:未装→安装,已装→升级 |
| `--force-install` | 已装也强制全量安装 |
| `--force-binary` | 升级时强制重下 sing-box |
| `--ui-only` | 只更新 9090 面板 |
| `--rebind` | 升级时重新探测数据网卡 |
| `--verify` | 升级后做出口验证(升级默认跳过) |
| `--iface` | 强制指定数据网卡 |
| `--secret` | 面板密钥(默认随机;升级不改已有) |
| `--user` / `--pass` | 代理鉴权 |
| `--port` / `--panel-port` | 默认 7890 / 9090 |
| `--memory` | MemoryMax MB,默认 96 |
| `--skip-start` / `--skip-verify` | 跳过启动或验证 |
## 已装后的快捷方式
装过一次后也可用:
```bash
sudo cpxy upgrade # 等同再跑上面那条 curl(增量)
sudo cpxy upgrade --ui-only
sudo cpxy upgrade --force-binary
sudo cpxy upgrade --verify
```
| 保留 | 默认跳过 | 会更新 |
|------|----------|--------|
| `settings.conf` / `PANEL_SECRET` / 代理账密 | 重下 sing-box(已存在则复用) | UI 面板 |
| `CELLULAR_IFACE` 绑定 | 重新探测网卡 | scripts / `cpxy` / systemd |
| 端口与 MemoryMax | 出口公网验证 | 重生 `config.json` 并 restart |
常用运维:
```bash
cpxy verify
cpxy rebind
cpxy status | logs
cpxy auth --user u --pass p
cpxy auth --show | --clear
cpxy watch status # WWAN 自动监控
cpxy watch once # 手动跑一轮检查
```
### 重拨 / `rep=0x01` 自愈
| 层级 | 做法 |
|------|------|
| **绑定(推荐)** | 默认 `BIND_SOURCE_IP=false`:只 `bind_interface=wwanX`**不 pin 私网源 IP**,重拨换地址通常不用 regenerate |
| **监控** | `cellular-proxy-watch``ip monitor` + **ModemManager 重拨/重注册日志** + 60s 轮询;网卡改名/掉线/stale pin 或 MM 抖动后自动等数据面再 `generate` |
| **MM 标准(省流量)** | 默认 `WATCH_MM_EVENTS=true`:只读本机 `journalctl -u ModemManager`**不做公网探针**;命中 `registration/packet service` 等状态变化后 settle→等 IPv4→restart |
| **兜底 timer** | 每 2 分钟 oneshot 再检查一次 |
| **手动** | `cpxy rebind && cpxy verify` |
关监控:`ENABLE_CELLULAR_WATCH=false``cpxy upgrade`,或 `cpxy watch stop`
若必须 pin 源 IP`BIND_SOURCE_IP=true`(依赖 watch 同步,否则会再次 stale)。
- 代理:`LAN-IP:7890`HTTP + SOCKS5
- 面板:`http://LAN-IP:9090/ui/`(密钥在安装结束输出 / `settings.conf`
- **UI 可直接配置代理账号密码**(管理 API 默认 `9091`,与面板 secret 相同)
## 自动探测逻辑(摘要)
顺序如下,前一步命中即返回:
0. **ModemManager bearer**`mmcli -b` 报的 `interface:`)—— 最权威,优先采用
1. 驱动像蜂窝/USB 拨号:`qmi_wwan``cdc_mbim``cdc_ether``rndis_host``bam-dmux``rmnet*` 等(+100
2. 名称含 `wwan` / `wwp` / `ppp` / `rmnet` / `ccmni` …(+40,弱启发式)
3. **不是** 系统默认路由网卡(默认通常是 WiFi)
4. 多默认路由时取次要默认口
5. 回退:任意非默认且有 IPv4 的物理网卡
探测失败会直接报错并提示用 `--iface`
### 绝不绑定 USB gadget 网卡
设备把自己当 USB 网卡挂给上游主机时会出现 `usb0` / `rndis0`(驱动 `configfs-gadget`
`g_ether` 等)。那是「本机 → PC」的下行链路,一旦被当成代理出口,所有出站都会
`context deadline exceeded`SOCKS5 客户端看到的就是 `socks connect failed rep=0x01`
因此:
- `iface_is_usb_gadget()` 按驱动名与 gadget 总线路径识别这类接口,打分阶段直接跳过;
- 默认探测关键词不再包含 `usb` / `enx`,升级时会自动从已有 `settings.conf` 里剔除;
- 即使手工把 `CELLULAR_IFACE=usb0` 写进配置或用 `--iface usb0``detect` / `generate` /
`install` / `upgrade` / `watch` 都会拒绝并改用 ModemManager 的结果;
- 真正的 USB 上行模组(`rndis_host``cdc_*``qmi_wwan`)是 host 侧驱动,不受影响。
回归测试(不需要真机,纯离线,覆盖 18 条断言):
```bash
bash tests/detect-gadget.sh
```
## 手动安装
```bash
git clone https://gitea.chickliu.fun/Hermes/cellular-proxy.git
cd cellular-proxy
sudo ./scripts/install.sh # 同样会自动探测并绑定
```
## 资源
- 单进程 sing-box
- 中文静态面板(animal-island-ui 视觉 token,单文件无 React
- 默认 `MemoryMax=96MB`
## 二进制从哪里下?
**优先 Gitea Release 预置包**(一键安装默认走 Gitea,无需访问 GitHub):
```text
https://gitea.chickliu.fun/Hermes/cellular-proxy/releases/download/bin-v1.11.7/sing-box-1.11.7-linux-amd64.tar.gz
https://gitea.chickliu.fun/Hermes/cellular-proxy/releases/download/bin-v1.11.7/sing-box-1.11.7-linux-arm64.tar.gz
https://gitea.chickliu.fun/Hermes/cellular-proxy/releases/download/bin-v1.11.7/sing-box-1.11.7-linux-armv7.tar.gz
```
下载顺序:`Gitea 整包``Gitea 分片合并(兜底)``GitHub 代理(https://git.86482425.xyz)``直连 GitHub`
## 代理账号密码
| 方式 | 命令 / 入口 |
|------|-------------|
| **UI** | `http://LAN-IP:9090/ui/` → 面板 secret → 代理账号密码 |
| **CLI** | `sudo cpxy auth --user u --pass p` |
| 安装时 | `--user` / `--pass` |
管理 API`POST http://LAN-IP:9091/proxy-auth`Header `Authorization: Bearer $PANEL_SECRET`