diff --git a/docs/configurable-proxy-prototype.html b/docs/configurable-proxy-prototype.html new file mode 100644 index 0000000..a8b24e7 --- /dev/null +++ b/docs/configurable-proxy-prototype.html @@ -0,0 +1,225 @@ + + +
+ + +Task 3 设计稿 · 让用户像 Shadowrocket 那样自定义"哪些流量直连 / 走隧道 / 拒绝"。以下是移动端三块核心界面的视觉原型(mockup,非真实数据)。配套规则模型与实现见 配置说明文档 →
+ +{ "domain_suffix": ["git.51yanmei.com"],
+ "outbound": "direct" }# 一行一条:类型,值,动作 +DOMAIN-SUFFIX,git.51yanmei.com,DIRECT +DOMAIN-SUFFIX,aliyun.com,DIRECT +DOMAIN-SUFFIX,tencent.com,DIRECT +DOMAIN-SUFFIX,flutter-io.cn,DIRECT +DOMAIN-SUFFIX,github.com,PROXY +GEOSITE,category-ads,REJECT +GEOIP,CN,DIRECT +FINAL,PROXY
代理模式三选一(全局代理 / 智能分流 / 全部直连),对应 Shadowrocket 的 Global/Rule/Direct。
+内置规则是系统/服务端强制层:LAN 直连恒开(🔒),私有服务走隧道由服务端下发(🔒),国内直连可开关。
+我的规则是用户自定义、可拖动排序的有序表,首命中生效。FINAL 是兜底动作。
+选类型(域名/后缀/关键字/IP-CIDR/GeoIP/GeoSite)→ 填值 → 选动作(直连/走隧道/拒绝)。
+实时预览该规则会被翻译成的 sing-box 路由片段,让高级用户看得懂、放心。
+粘贴 类型,值,动作 一行一条,兼容 Shadowrocket/Clash 直觉。批量建规则、迁移旧配置。
解析给出有效/跳过统计,非法行不静默吞。
+| 动作 | 含义 | sing-box outbound |
|---|---|---|
| 直连 | 不走隧道,本机物理网卡直接出网(国内站、CI 源、私网) | direct |
| 走隧道 | 经 pangolin 节点出网(需科学上网的站) | auto(REALITY/Hy2 择优) |
| 拒绝 | 直接阻断(广告/追踪/恶意域) | block |
| 类型 | 值示例 | 匹配 |
|---|---|---|
| 域名 | example.com | 精确 |
| 域名后缀 | aliyun.com | 含子域(*.aliyun.com) |
| 关键字 | google | 域名含该串 |
| IP-CIDR | 35.190.0.0/16 | IP 段(v4/v6) |
| GeoIP 国家 | CN | 该国 IP 段(自托管规则集) |
| GeoSite 类别 | category-ads / netflix | 预置域名集 |
需要你确认:①这套 UI/模型对不对路?②要不要「从文本导入」这一块(可后置)?③规则粒度够不够(要不要 per-app 分应用代理,shadowrocket 有,较重、建议后置)?确认后我出实现计划开发。设计取舍与实现细节见 配置说明文档 →
+Task 3 设计 · 让用户像 Shadowrocket 那样自定义路由规则(哪些直连 / 走隧道 / 拒绝)。
+配套视觉原型:交互原型 → · 状态:设计待确认(未开发)
+ +当前 pangolin 客户端的分流是服务端固定渲染的:LAN 直连、DNS 劫持、可选国内分流(geoip/geosite-cn)、私有域名走隧道,用户无法自定义。实际需求(如 CI 编译源、公司内网、某些国内站要直连;某些站要强制走隧道;广告要拒绝)无处配置——这次暴露的「CI 流量被灌进隧道拖垮小节点」就是典型。
+本设计给用户一套可配置路由规则,心智模型对齐 Shadowrocket 的 [Rule] 段:有序规则表,首命中生效,动作三选一(直连 / 走隧道 / 拒绝)。
ARCHITECTURE.md §3.1:Dart/Flutter 客户端不得自行拼装或修改 sing-box 配置——配置一律服务端渲染、原样下发。所以"客户端可配置"不能变成"客户端本地改 config"。解法:用户在 App 编规则 → 存为服务端 per-user「路由档案(routing profile)」→ connect 时服务端把档案翻译进渲染的配置。客户端只负责编辑 UI + 存/取档案,永不碰 sing-box JSON。
+App 规则编辑器 ──PUT /v1/routing-profile──▶ 服务端存 per-user 档案(DB)
+ │
+App 点连接 ──POST /v1/nodes/{id}/connect──▶ BuildClientConfig(读档案→翻译成 route.rules)
+ │
+App ◀────────── 完整 sing-box 配置(含用户规则)─────┘ 原样喂内核
+
+ 一条规则 = { type, value, action, note?, enabled }。整个档案:
{
+ "mode": "rule", // global | rule | direct(对齐 shadowrocket 三模式)
+ "builtin": {
+ "china_direct": true, // 国内分流(geoip-cn/geosite-cn → 直连)开关
+ "lan_direct": true, // LAN/私网直连(强制,不可关)
+ "private_via_tunnel": true // 私有服务域名走隧道(服务端下发,不可关)
+ },
+ "rules": [ // 用户自定义,有序,首命中生效
+ { "type": "domain_suffix", "value": "git.51yanmei.com", "action": "direct", "note": "CI 源", "enabled": true },
+ { "type": "geosite", "value": "category-ads", "action": "reject" },
+ { "type": "ip_cidr", "value": "35.190.0.0/16", "action": "proxy" }
+ ],
+ "final": "proxy" // 兜底:未命中任何规则的动作
+}
+
+ | type | 值示例 | sing-box 字段 |
|---|---|---|
domain | example.com | domain(精确) |
domain_suffix | aliyun.com | domain_suffix(含子域) |
domain_keyword | domain_keyword | |
ip_cidr | 35.190.0.0/16 · ::/0 | ip_cidr(v4/v6) |
geoip | CN · US | rule_set(自托管 geoip-*.srs) |
geosite | cn · netflix · category-ads | rule_set(自托管 geosite-*.srs) |
| action | outbound | 说明 |
|---|---|---|
| direct | direct | 物理网卡直连(配合 route_exclude/reverse_mapping 真直连) |
| proxy | auto | 经节点(REALITY/Hy2 urltest 择优) |
| reject | block | 阻断 |
服务端把规则按固定层级拼进 route.rules,自上而下首命中:
PANGOLIN_PRIVATE_SPLIT_DOMAINS)· 服务端rules[] 顺序展开)← 新增china_direct 开时)final:proxy / direct)direct outbound 让 sing-box 从物理网卡直接出连接。但 TUN strict_route 会把包重新捕回隧道——已有两个机制解决,用户规则复用:
route_exclude_address(在 auto_route 层排除,已用于 LAN)。用户加的 ip_cidr → direct 需同步进 route_exclude,否则被 strict_route 抓回。dns.reverse_mapping(记 IP↔域名,按 IP 连接时补回域名元数据让 domain 规则命中)+ local DNS(223.5.5.5,国内解析)。已用于私有域名分流,机制现成。| 端点 | 作用 |
|---|---|
GET /v1/routing-profile | 拉当前用户档案(App 编辑器初始化;无则返回内置默认) |
PUT /v1/routing-profile | 保存档案(服务端校验:CIDR 合法、type 合法、条数上限、去重) |
POST …/connect(现有) | 渲染时读该用户档案,翻译进 route.rules |
档案存 DB(routing_profiles 表:user_id · profile_json · updated_at),不走 connect body(与现有 split_cn 走 query 的约束一致——大规则集不塞 query/body)。客户端本地也缓存一份(离线可看/编,连接时以服务端为准)。
ip_cidr 可解析、type 在白名单、geosite/geoip 值在自托管规则集清单内、总条数 ≤ 上限(如 200)。非法整体拒绝(4xx + 逐条错误),不半保存。| 现有 | 本设计如何吸收 |
|---|---|
| SplitCN(geoip/geosite-cn 直连,#5) | 降为档案里的 builtin.china_direct 开关(层级 5) |
| PrivateSplitDomains(走隧道) | 保留为系统层 3(服务端 env,用户不可动) |
| route_exclude_address(LAN) | 保留 + 扩展:用户 ip_cidr→direct 规则动态并入 |
| reverse_mapping / local DNS | 复用:域名直连规则靠它命中 |
换句话说,本设计是把三个散落的分流机制统一收进一个用户可见、可配的规则模型,底层复用已验证的 sing-box 手法。
+ +确认这份设计后,我用 writing-plans 出 Phase 1 的实现计划(TDD、多端、服务端翻译逐条测),再开发。