5 Commits

Author SHA1 Message Date
eli dea51c546a chore(cdn-v6): 文件头补上 Akamai 来源仓库地址(测试断言要求写明来源) 2026-11-08 13:13:39 +08:00
eli ca5d8ee84a refactor: CDN 清单生成器移交 gc-toolkit/cdn-list
这份清单存在的唯一原因是 GCP 把 CDN 出站单独计价(Carrier Peering,$0.08/GiB 从
第一字节起算、无 200 GiB 免费额度),而消费它的 VPC 拒绝规则 cdn-egress-deny 本身
也是 GCP 资源。所以生成器归 gc-toolkit 更合理。

- 删掉本仓库的 tools/refresh-cdn-lists.sh(功能已合并进 gc-toolkit,避免两份分叉)
- 脚本头部与 docs/cdn-list-audit.md 改成指路 gc-toolkit
- 清单内容本次无变化:v4 271 条 / v6 193 条,与 gc-toolkit 生成的 canonical 文件一致

迁移后 gc-toolkit 那边多了两件事:生成 canonical 的 cdn-cidrs-v4/v6.txt,
以及 --vpsetup 参数(一次运行同时同步本仓库的内嵌清单与 v6 文件)。
2026-11-08 13:12:01 +08:00
eli 37db75413d fix(cdn-list): 换用上游仓库自带的合并版,并补上一直缺失的 Akamai IPv6
两件事,都是之前搞错的。

一、v4 清单的源头找错了处理方式
实际数据源是 SecOps-Institute/Akamai-ASN-and-IPs-List(按 40 个 ASN 从 RADb 拉 BGP
宣告,每小时更新)。内嵌的那份是拿它的 akamai_ip_list.lst 手工合并、且是一两年前的
快照。复核发现:
  - 该仓库本来就提供合并好的 akamai_ip_cidr_blocks.lst(235 条,与原始 9462 行
    collapse 后完全等价),根本不用自己合;
  - 旧快照已漂移:265 段 / 209,106 地址 Akamai 已不再宣告(白绕),
    49 段 / 13,504 地址是新宣告的(没绕 → 一直在按 $0.08/GiB 计费)。
换成 235 条后,v4 总数 402 → 269。

二、Akamai 的 IPv6 一直是空的
之前写"没有官方来源所以故意不收"——前提就错了:同一个仓库有 akamai_ipv6_list.lst
(3849 行,未合并,需要自己 collapse 成 183 条)。也就是说在此之前所有走 v6 的
Akamai 边缘流量都没被绕行,一直在按 CDN 计费。现已补上:v6 从 10 条 → 193 条
(CF 7 + Fastly 3 + Akamai 183)。

配套改动:
  - 脚本头部写清【怎么更新这份清单】+ CDN_LIST_AUDIT_DATE,超过 180 天打告警;
  - 测试断言从"单一区间"改成三层:总数 269±10%、CF 15 条逐条核对、Fastly 抽样;
    v6 侧补 Akamai 主段与条数下限,防止再次被删空;
  - docs/cdn-list-audit.md 重写,记录依据(GCP 按目的地网络自动判定、Akamai 无官方
    公开清单的穷举证据)、20 万地址漂移、以及 5 万条集合的实测无差异。

线上已同步:两台主机渲染结果 md5 一致(c8f16ac8…);两个 GCP 项目的 egress 拒绝规则
都改成同一份 269 段(原来是 gcoregon 旧 368 段、gcoregon-2 中间版 402 段,两边还不一致)。
真实 Akamai 边缘地址抽验命中:www.akamai.com / www.microsoft.com 的 AAAA 都落在
2600:1400::/24 内。
2026-11-08 11:17:55 +08:00
eli b1ab48afd3 docs(cdn-v6): 把 Akamai 段的空缺从 TODO 改成有依据的结论
上一版留的是"待从官方文档/WHOIS 核对后补入"。调研后发现这个待办本身不成立:
Akamai 根本没有面向公众的单文件网段清单,官方只给客户 Site Shield / Origin IP ACL
(按客户定制),第三方仓库 SecOps-Institute/Akamai-ASN-and-IPs-List 里还混着
Akamai Connected Cloud / Linode(AS63949)的客户虚拟机段,拿来当 CDN 名单会误绕一大片
普通 Linode 站点。

按仓库既有的"CDN 清单只收官方公布的网段"约束,结论是【不收】,并把理由写进文件。
对应测试从"必须含 TODO"改成"必须含留空理由 + 必须含不采用第三方的说明",防止以后
有人顺手补段却不留依据。
2026-11-07 21:05:58 +08:00
eli 15690fd9a6 fix(cdn-bypass): 改为独立实例,修掉 confdir 合并污染主配置
原方案给主 xray 加 -confdir,被 xray 的合并语义坑了两处(真机 -dump 实证):
1) 片段 outbounds 被前插成 outbounds[0],cdn-bypass-out 变成所有未命中流量的默认出站
2) Config.Override 用 c.RouterConfig = o.RouterConfig,片段的 routing 整体替换主配置的
   routing —— 5 条规则与 IPIfNonMatch 全丢(geoip:cn/私网/bittorrent/tg-in 全部失效)

单进程无解:带 routing 就毁主配置,去掉 routing 则 bypass 入站落到 direct 并打环。
改为独立 xray 实例(同一个 /usr/local/bin/xray,不重复安装):
- xray-cdn-bypass.service:User/Group 继承主 unit,CAP_NET_ADMIN 供 tproxy+SO_MARK,
  PartOf 传播 stop/restart,WantedBy 同时挂主服务(PartOf 不传播 start,
  否则看门狗次月恢复后 bypass 仍 dead,而 nft 还在打标 → CDN 流量黑洞)
- 多上游 balancer:oracle-1..N 随机选健康节点(random + observatory;
  fallbackTag 必须非空,否则 strategy 不会注入 observatory)
- 双栈:table ip / table ip6 各一套打标+tproxy,v6 tproxy 目标写死 [::1]
- 卸载顺序:先撤 nft/策略路由再停实例,避免仍在打标+端口已关

已修的真机问题:mktemp 无 .json 后缀导致 xray 拒绝加载配置;
route unit 是 oneshot+RemainAfterExit,只 enable 不会重跑 ExecStart,必须 restart;
运行时 systemctl enable --now nftables 会触发 flush ruleset 清空主机防火墙,改为只 enable。

新增 cdn-cidrs-v6.txt(只收官方段,Akamai v6 待补)与 6 条回归守卫(已做变异测试)。
2026-11-07 20:53:47 +08:00