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
|
8fd7d9db1b
|
feat(tools): 新增 refresh-cdn-lists.sh,把清单刷新变成一条命令
之前刷清单是我临时写内联 python 干的,没脚本、不可复现。现在补上:
- 四个来源:CF ips-v4/v6、Fastly public-ip-list、Akamai 的
akamai_ip_cidr_blocks.lst(v4 已合并版)+ akamai_ipv6_list.lst(v6 未合并,自己 collapse)
- **交叉校验**:把 Akamai 原始 9462 行自己 collapse 一遍,与仓库给的合并版逐条比对,
不一致就拒绝落盘(说明上游出了问题)。实测两者都是 235 条、集合完全相同。
- **确定性**:排序固定,连跑两次字节级一致(已验证 v4 脚本与 v6 文件 diff 都为空)。
- **幂等**:无差异时直接报"已是最新"退出,不碰文件。
- 默认只报告差异(`<` 当前独有 / `>` 上游独有);`--apply` 才落盘;`--cache DIR` 供离线/测试。
首次运行就抓到上游漂移:Fastly 从 19 条涨到 **21** 条,新增 90.98.0.0/17 与
90.98.128.0/18(相邻不重叠,净增 2 条 / 49,152 个地址)——这两段之前一直没被绕行。
已落盘,v4 269 → 271。
修掉一个自己引入的 bug:v6 文件的注释拼接逻辑写重了,第一次 --apply 把 193 条写成了
385 条(每条重复两次)。现在 v6 改成整文件重新生成(头和正文同源),并验证无重复。
线上已同步:两台主机 + 两个 GCP 项目的 cdn-egress-deny 规则都是 271 条,
两侧集合逐条比对完全一致。
|
2026-11-08 11:31:52 +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
|
bb27fb24dc
|
feat(cdn-list): v4 清单 188 → 402 条,覆盖面上补到 GCP 那份的规模
现网 188 条(CF 15 + Fastly 19 + Akamai/Linode 154)是 2026-09 审计的产物;
GCP 项目里的 egress 拒绝规则用的是更完整的一份(Akamai 368 条)。这次把主机侧
对齐到同一份,两边从此一致——不一致会导致"漏绕(按 CDN 计费)"或"误丢包"。
实测结论(写进 docs/cdn-list-audit.md):
- nft 是"一个集合一次查找",netlink 字节码里只有一条 lookup,不是几百条 cmp;
- 集合 188 条 vs 40 条端到端无差异,扩到 50,188 条仍然测不出差异;
- 所以"精简到几十条"没有任何性能收益,只会把无辜地址丢给上游 Oracle。
顺带证伪了两个之前的口头推测:
- GCP 单条防火墙规则没有 256 个 destinationRanges 上限(实测 3000 个也能建);
- 精确挖掉 Linode 反而使条数从 368 涨到 381(减法切碎片),故不挖。
测试断言从单一区间 [180,200] 换成三层保护:总数 402±10%、Cloudflare 15 条逐条核对、
Fastly 抽样核对——CF/Fastly 是官方权威值,不该漂移;Akamai 是 BGP 派生的浮动值。
两台机器已重跑并验证:CDN 出口走 Oracle,非 CDN 仍走 GCP 自己。
|
2026-11-08 10:38:45 +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 |
|
eli
|
a7f63052a2
|
fix(cdn-bypass): networkd drop-in 防 fwmark 策略路由被清——2026-10-16 gcoregon 静默失效根治
- 安装时写 /etc/systemd/networkd.conf.d/90-cdn-bypass.conf(ManageForeignRoutingPolicyRules=no),
卸载时移除;落盘即对下一次 networkd 重启生效,装时不动 networkd。
- 根因:unattended-upgrade 升级 systemd 触发 networkd 重启,默认 ManageForeignRoutingPolicyRules=yes
会把 route unit 加的 ip rule fwmark 1 当外源规则清掉,oneshot unit 仍 active (exited) 无人察觉。
- 已在 gcoregon 实测:写 drop-in 后重启 networkd,规则存活、CDN 出口恢复为 alius。
- 测试断言同步;顺带消除本脚本链接解析处的 SC2015。
|
2026-10-30 20:38:45 +08:00 |
|
eli
|
9722fa1825
|
docs: cdn-bypass 注释/CLAUDE.md 对齐新架构(客户端流量同样经 nft 筛选;direct 出站带 255 的典型症状;188 官方 CIDR;drop-in 20- 前缀)
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-09-28 13:10:11 +08:00 |
|
eli
|
06d26b252b
|
fix: cdn-bypass drop-in 改名 20- 前缀——官方 xray 安装脚本自带 10-donot_touch_single_conf.conf 会在同前缀 ASCII 序后加载盖掉我们的 -confdir;卸载同时清 10-/20- 两种残留
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-09-28 13:04:50 +08:00 |
|
eli
|
582f12efaa
|
fix: systemd drop-in ExecStart 从新版 {path=...;argv[]=...} 形式正确抽出 argv[]
新版 systemd systemctl show -p ExecStart --value 输出复合形式,
先前直接把整串写进 drop-in ExecStart= 会被 systemd 拒绝
('argv[]=' 不是合法可执行名),xray 用旧 ExecStart 起来没挂 confdir,
dokodemo 永远不起。
drop-in 现在从 argv[]= 提取纯命令行再附加 -confdir。
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-09-28 12:51:23 +08:00 |
|
eli
|
960ca8c3f2
|
refactor: 端口过滤下沉到 nft 层(xray 不再做端口筛选),架构对齐 nft 全筛原则
- nft mangle 打标链加 `th dport { 53, 80, 443 }`:非 web/DNS 端口的 CDN 流量
根本不进 tproxy,直接直连。省 upstream 流量的同时 QuIC(udp/443) 自动覆盖。
- xray routing 删 port 过滤:交给 nft 预筛,不再有重复筛分层。
- 测试断言同步反向:xray 不应再写 "port": "53,80,443"。
设计原则:get/post 只在一个地方 —— nft 决定哪些包进 tproxy;xray 只决定
「进来的包走哪个 upstream」。两套筛选条件不重叠就不会出现「nft 抓了 xray
不认」或反过来。
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-09-28 11:50:01 +08:00 |
|
eli
|
2c13ffc03d
|
fix: cdn-bypass 清单只保留三家公司官方段(401→188,剔除 213 条来源不明的 LE 回源 IP)
2026-09 期间治理 LE 证书续期时,把 LE 验证回源节点的 GCP/Linode IP 误当 CDN 段
加进清单;经 Whois+CF/Fastly/Akamai 官方清单逐条审计后:
- CF 15 条(cloudflare.com/ips-v4)
- Fastly 19 条(api.fastly.com/public-ip-list)
- Akamai/Linode 154 条(AS20940/AS16625/AS63949/AS36183)
共 188 条;剔掉 NTT/Level3/CenturyLink/Verizon/GTT/IBM Cloud/Zayo/AAPT/
CAT Telecom/Softbank/HE/Microsoft/Cologix/PCCW/TPG/IDNIC/Reliance/Telstra/
Telefonica/e-Trade/Fortinet 等 213 条非 CDN 段。
测试断言放宽到 [180,200],防止再次膨胀。
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-09-28 11:34:52 +08:00 |
|
eli
|
09a5f6566a
|
fix: cdn-bypass 与 gcoregon 实战清单合并(287→401) + routing 端口过滤
- CDN CIDR 快照 stale:2026-09 扩到 400 条时没回灌脚本,补入 114 条缺失段
(103.x/122.252/128.241/139.177/157.238/165.254 等 Akamai),只多 1 条 /32
- routing 片段 catch-all → network tcp,udp + port 53,80,443:
nft 已按 CDN 网段预筛,xray 只补 dokodemo 入站的端口层过滤,
非 web/DNS 端口直接直连以省上游流量(上游常为计费/限流节点)
- 头注释更新:说明两层的分工、客户端入站不在本脚本范围
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-09-28 08:00:56 +08:00 |
|
eli
|
826014e3b8
|
feat: 新增 setup_cdn_bypass_tproxy.sh —— CDN 绕行透明代理
面向 GCP 等封锁/计费 CDN(Cloudflare/Fastly/Akamai)出口的 VPS:本机到
287 段 CDN 网段的流量经 nft 打标 → ip rule → lo → xray dokodemo tproxy →
上游不限流节点。粘贴 vless:// 链接即用;xray 配置经 confdir 注入不碰原
config.json;ip rule/route 由 oneshot service 持久化;出站 mark 255 防回环。
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-09-26 12:25:30 +08:00 |
|