diff --git a/README.md b/README.md index 70b9fbb64..0cd94bbdb 100644 --- a/README.md +++ b/README.md @@ -4,17 +4,17 @@ Sync Rules Pull Request Validation Platforms - License + Repository code license

-面向 Surge、Quantumult X、Egern、sing-box 和 mihomo 的规则构建仓库。`main` 保存稳定源码并触发发布,客户端产物位于对应平台分支。 +本仓库从配置的上游和本地维护源生成 Surge、Quantumult X、Egern、sing-box 与 mihomo 规则。`main` 保存构建源码、配置和工作流;可直接使用的文件位于对应平台分支。 > [!IMPORTANT] -> 客户端不要引用 `main`。第三方规则不因格式转换而自动适用 MIT,来源和许可边界见 [`NOTICE`](NOTICE) 与 [`THIRD_PARTY_NOTICES.md`](THIRD_PARTY_NOTICES.md)。 +> 客户端不要引用 `main`。规则名称和区域分类沿用上游定义,不构成准确性、完整性或适用性保证。第三方内容不因格式转换而自动适用本仓库的 MIT 许可,详见 [`NOTICE`](NOTICE) 与 [`THIRD_PARTY_NOTICES.md`](THIRD_PARTY_NOTICES.md)。 -## 使用规则 +## 获取产物 -稳定 URL 格式: +分支 URL 格式: ```text https://raw.githubusercontent.com/KuGouGo/Rules/{branch}/{type}/{name}.{extension} @@ -38,25 +38,24 @@ https://raw.githubusercontent.com/KuGouGo/Rules/sing-box/domain/cn.srs https://raw.githubusercontent.com/KuGouGo/Rules/mihomo/ip/google.mrs ``` -各平台的接入方式和最小配置示例位于对应产物分支的 `README.md`。分支 URL 始终指向最新产物;需要固定内容时,将分支名替换为具体提交 SHA。 +各平台的接入方式和最小配置示例位于对应产物分支的 `README.md`。分支 URL 会随成功发布变化,不适合作为不可变版本标识;需要固定内容时,应将分支名替换为产物分支的提交 SHA。 -## 常用规则 +## 规则说明 -| 名称 | 类型 | 用途 | +| 名称 | 类型 | 当前生成方式 | | --- | --- | --- | -| `cn` | domain / ip | 中国大陆域名或合并后的中国大陆 CIDR | -| `geolocation-cn` | domain | 上游定义的中国大陆区域域名 | -| `geolocation-!cn` | domain | 上游定义的非中国大陆区域域名 | -| `google` / `telegram` | ip | 对应服务的 CIDR;Telegram 额外合并 ASN 前缀 | -| `emby-cn` | domain | Emby 中国大陆细分规则 | -| `emby` | domain | 通用 Emby 规则 | -| `fakeip-filter` | domain | 本仓库维护的 Fake-IP 排除规则 | +| `cn` | domain | v2fly/domain-list-community 的 `cn` 集合及其派生结果 | +| `cn` | ip | 配置的中国大陆 IP 上游经规范化、去重和 CIDR 合并后的结果 | +| `geolocation-cn` / `geolocation-!cn` | domain | 上游提供的区域集合名称与内容 | +| `google` / `telegram` | ip | 配置的服务地址源;Telegram 结果还合并配置的 ASN 前缀 | +| `emby-cn` / `emby` | domain | 本仓库维护的两个 Emby 规则集合 | +| `fakeip-filter` | domain | 本仓库维护的 Fake-IP 排除集合 | -`emby-cn` 必须放在 `emby` 前面。规则名称来自上游,不同名称即使内容相近也不视为别名;使用前请在目标分支确认文件存在。 +在按首条命中处理的客户端中,如果同时使用 `emby-cn` 和 `emby`,应先加载范围较窄的 `emby-cn`。规则文件会随上游增加、删除或改变;使用前应在目标分支确认文件存在并检查内容。 -## 平台能力 +## 转换行为 -| 平台 | 精确域名 | 后缀 | 关键词 | 正则 | IP CIDR | +| 产物平台 | 精确域名 | 后缀 | 关键词 | 正则 | IP CIDR | | --- | :---: | :---: | :---: | :---: | :---: | | Surge | ✓ | ✓ | ✓ | — | ✓ | | Quantumult X | ✓ | ✓ | ✓ | — | ✓ | @@ -64,17 +63,17 @@ https://raw.githubusercontent.com/KuGouGo/Rules/mihomo/ip/google.mrs | sing-box | ✓ | ✓ | ✓ | ✓ | ✓ | | mihomo | ✓ | ✓ | — | — | ✓ | -`—` 表示当前转换链不保留该类型,不代表客户端本身不支持。列表只包含不受支持的规则类型时,对应平台不会发布空产物。 +`✓` 表示当前转换器会保留并输出该类型,`—` 表示当前转换链会省略该类型;该表不判断客户端自身的全部能力。一个列表在目标平台没有可保留条目时,不发布空文件。 属性与区域名称沿用上游语义: - `name@cn`、`name@!cn`、`name@ads` 是属性派生集合,`@!cn` 不是布尔取反。 - `*-cn`、`*-!cn` 是区域列表名称;明显冗余的属性派生不会发布。 -- `official`、`registry`、`community` 仅表示采集来源分类,不代表质量或许可等级。 +- `official`、`registry`、`community` 是仓库配置中的来源分类,不代表质量、可信度或许可等级。 ## 本地维护 -要求 Bash 5+、GNU Make、Git 和 Python 3。macOS 可使用 Homebrew Bash 完成验证与文本构建;sing-box 和 mihomo 的完整二进制构建仅支持 lock 文件声明的 Linux 平台。 +本地命令要求 Bash 5+、GNU Make、Git 和 Python 3。macOS 可使用 Homebrew Bash 运行检查和文本构建;需要下载 sing-box 或 mihomo 的二进制构建只支持 lock 文件声明的 Linux 平台。 ```bash make check-runtime @@ -84,21 +83,22 @@ make preflight make clean ``` -- `make validate`:运行 Shell、Python、配置、规则质量和测试检查。 +- `make validate`:运行 Shell、Python、配置、自定义规则和测试检查。 - `make build-custom-text`:生成自定义文本产物,不下载二进制工具。 -- `make preflight`:执行完整验证和文本构建,适合提交前检查。 -- `make clean`:删除生成产物和临时文件,保留可信工具缓存。 +- `make preflight`:执行 `make validate` 和自定义文本构建;不执行上游完整同步、二进制构建或发布。 +- `make clean`:删除生成产物和临时文件,保留已校验的工具缓存。 完整环境、构建事务和调试命令见 [开发指南](docs/DEVELOPMENT.md)。 ## 仓库边界 - 长期分支只保留 `main` 与 `surge`、`quanx`、`egern`、`sing-box`、`mihomo` 五个产物分支。 -- 代码、文档和依赖更新通过临时分支向 `main` 提交 Pull Request;验证通过并合并后才构建和发布,临时分支自动删除。 +- 变更通过临时分支向 `main` 提交 Pull Request;PR 运行静态检查和不发布的完整候选构建,临时分支在合并后删除。 +- `main` 在构建相关路径变化、定时任务运行或人工触发时执行发布工作流;产物内容没有变化时不会创建新的产物分支提交。 - Dependabot 每月向 `main` 集中提交一个 GitHub Actions minor/patch 更新 PR;major 与安全告警单独人工评估。 - `fakeip-filter` 是本仓库维护的文本源,不下载第三方预编译文件。 - 构建摘要、manifest 和 CI 通过都不是第三方许可证明。 -- 规则按现状提供,部署前应检查内容并保留回滚方案。 +- 规则按现状提供。使用者需自行判断策略、顺序和更新带来的影响,并保留可回退版本。 ## 文档 diff --git a/scripts/tests/test-custom-build-atomic.sh b/scripts/tests/test-custom-build-atomic.sh index 3694a66e9..b523c113f 100644 --- a/scripts/tests/test-custom-build-atomic.sh +++ b/scripts/tests/test-custom-build-atomic.sh @@ -62,7 +62,7 @@ assert_injected_failure_preserves_output() { # Change a maintained source so staging contains output different from the # restored controlled artifact. A late text failure must still publish nothing. -printf '\nDOMAIN-SUFFIX,atomic-stage.example\n' >> "$REPO/sources/custom/domain/emby.list" +printf '\nDOMAIN-SUFFIX,atomic-stage.example.com\n' >> "$REPO/sources/custom/domain/emby.list" assert_injected_failure_preserves_output late-text RULES_BUILD_CUSTOM_TEXT_ONLY=1 # Avoid network/tool-lock behavior only inside this disposable test copy. The @@ -100,7 +100,7 @@ assert_injected_failure_preserves_output late-binary printf 'restored binary\n' > "$REPO/.output/domain/surge/unrelated.list" RULES_CONFLICT_BASE_SHA="$BASE_SHA" RULES_BUILD_CUSTOM_TEXT_ONLY=1 \ "$REPO/scripts/commands/build-custom.sh" >/dev/null -grep -Fx 'DOMAIN-SUFFIX,atomic-stage.example' "$REPO/.output/domain/surge/emby.list" >/dev/null +grep -Fx 'DOMAIN-SUFFIX,atomic-stage.example.com' "$REPO/.output/domain/surge/emby.list" >/dev/null grep -Fx 'restored upstream' "$REPO/.output/unrelated/upstream.txt" >/dev/null grep -Fx 'restored binary' "$REPO/.output/domain/surge/unrelated.list" >/dev/null diff --git a/scripts/tests/test-custom-rule-quality.sh b/scripts/tests/test-custom-rule-quality.sh index 43a59e566..66244c63b 100755 --- a/scripts/tests/test-custom-rule-quality.sh +++ b/scripts/tests/test-custom-rule-quality.sh @@ -58,6 +58,21 @@ IP-CIDR6,fc00::/7 EOF assert_lint_passes "pass" "$TMP_DIR/pass/domain" "$TMP_DIR/pass/ip" +make_case_dirs "$TMP_DIR/fakeip-single-label" +printf '%s\n' 'DOMAIN-SUFFIX,lan' > "$TMP_DIR/fakeip-single-label/domain/fakeip-filter.list" +assert_lint_passes \ + "fakeip-single-label" \ + "$TMP_DIR/fakeip-single-label/domain" \ + "$TMP_DIR/fakeip-single-label/ip" + +make_case_dirs "$TMP_DIR/non-fakeip-single-label" +printf '%s\n' 'DOMAIN-SUFFIX,lan' > "$TMP_DIR/non-fakeip-single-label/domain/example.list" +assert_lint_fails_with \ + "non-fakeip-single-label" \ + "DOMAIN-SUFFIX value is too broad" \ + "$TMP_DIR/non-fakeip-single-label/domain" \ + "$TMP_DIR/non-fakeip-single-label/ip" + make_case_dirs "$TMP_DIR/domain-coverage" cat > "$TMP_DIR/domain-coverage/domain/example.list" <<'EOF' DOMAIN-SUFFIX,example.com diff --git a/scripts/tests/test-fakeip-migration.sh b/scripts/tests/test-fakeip-migration.sh index c68363588..da2cb2e99 100644 --- a/scripts/tests/test-fakeip-migration.sh +++ b/scripts/tests/test-fakeip-migration.sh @@ -38,12 +38,21 @@ git -C "$RENDER_REPO" commit -m add-fakeip >/dev/null RULES_BUILD_CUSTOM_TEXT_ONLY=1 "$RENDER_REPO/scripts/commands/build-custom.sh" >/dev/null RULES_BUILD_CUSTOM_TEXT_ONLY=1 "$RENDER_REPO/scripts/commands/build-custom.sh" >/dev/null -grep -Fx 'DOMAIN-SUFFIX,in-addr.arpa' "$RENDER_REPO/.output/domain/surge/fakeip-filter.list" >/dev/null -grep -Fx 'DOMAIN,localhost.localdomain' "$RENDER_REPO/.output/domain/surge/fakeip-filter.list" >/dev/null -grep -Fx 'HOST-SUFFIX,in-addr.arpa,fakeip-filter' "$RENDER_REPO/.output/domain/quanx/fakeip-filter.list" >/dev/null -grep -Fx 'HOST,localhost.localdomain,fakeip-filter' "$RENDER_REPO/.output/domain/quanx/fakeip-filter.list" >/dev/null -grep -Fx " - 'in-addr.arpa'" "$RENDER_REPO/.output/domain/egern/fakeip-filter.yaml" >/dev/null -grep -Fx " - 'localhost.localdomain'" "$RENDER_REPO/.output/domain/egern/fakeip-filter.yaml" >/dev/null +if grep -Fx '*' "$ROOT/sources/custom/domain/fakeip-filter.list" >/dev/null; then + echo "test failed: universal Fake-IP bypass must not be published" >&2 + exit 1 +fi +grep -Fx 'DOMAIN-SUFFIX,lan' "$RENDER_REPO/.output/domain/surge/fakeip-filter.list" >/dev/null +grep -Fx 'DOMAIN,proxy.golang.org' "$RENDER_REPO/.output/domain/surge/fakeip-filter.list" >/dev/null +if grep -F 'DOMAIN-REGEX,' "$RENDER_REPO/.output/domain/surge/fakeip-filter.list" >/dev/null; then + echo "test failed: Surge output retained unsupported regex rules" >&2 + exit 1 +fi +grep -Fx 'HOST-SUFFIX,lan,fakeip-filter' "$RENDER_REPO/.output/domain/quanx/fakeip-filter.list" >/dev/null +grep -Fx 'HOST,proxy.golang.org,fakeip-filter' "$RENDER_REPO/.output/domain/quanx/fakeip-filter.list" >/dev/null +grep -Fx " - 'lan'" "$RENDER_REPO/.output/domain/egern/fakeip-filter.yaml" >/dev/null +grep -Fx " - 'proxy.golang.org'" "$RENDER_REPO/.output/domain/egern/fakeip-filter.yaml" >/dev/null +grep -Fx " - '^time\\.[^.]+\\.com$'" "$RENDER_REPO/.output/domain/egern/fakeip-filter.yaml" >/dev/null prepare_collision_repo() { local repo="$1" diff --git a/scripts/tools/lint-custom-rules.py b/scripts/tools/lint-custom-rules.py index 3a6f978ca..c97ffe127 100644 --- a/scripts/tools/lint-custom-rules.py +++ b/scripts/tools/lint-custom-rules.py @@ -73,7 +73,11 @@ def load_domain_rules(directory: Path, reporter: Reporter) -> list[LocatedRule]: result: list[LocatedRule] = [] for path in iter_rule_files(directory): validate_rule_file_name(path, reporter) - rules, errors = parse_classical_domain_file(path, require_canonical=True) + rules, errors = parse_classical_domain_file( + path, + require_canonical=True, + allow_single_label_suffix=path.name == "fakeip-filter.list", + ) reporter.errors.extend(errors) if not rules: reporter.error(f"{path}:0 has no effective rules") diff --git a/sources/custom/domain/fakeip-filter.list b/sources/custom/domain/fakeip-filter.list index ffbf6b049..3c73cf3a1 100644 --- a/sources/custom/domain/fakeip-filter.list +++ b/sources/custom/domain/fakeip-filter.list @@ -1,13 +1,120 @@ -# KuGouGo-maintained conservative Fake-IP exclusions. -# -# Reverse DNS namespaces must retain address semantics instead of receiving a -# synthetic address. See RFC 3172 and RFC 3596. -DOMAIN-SUFFIX,in-addr.arpa -DOMAIN-SUFFIX,ip6.arpa - -# Special-use names used for local resolution and protocol discovery. -# See RFC 6761, RFC 7050, RFC 8375, and RFC 9462. -DOMAIN,localhost.localdomain -DOMAIN-SUFFIX,ipv4only.arpa +# KuGouGo-maintained Fake-IP exclusions. +# A universal wildcard is intentionally omitted because it disables Fake-IP +# for every domain and makes the remaining entries ineffective. + +# LAN and special-use names +DOMAIN-SUFFIX,lan +DOMAIN-SUFFIX,localdomain +DOMAIN-SUFFIX,example +DOMAIN-SUFFIX,invalid +DOMAIN-SUFFIX,localhost +DOMAIN-SUFFIX,test +DOMAIN-SUFFIX,local DOMAIN-SUFFIX,home.arpa -DOMAIN-SUFFIX,resolver.arpa +DOMAIN-SUFFIX,direct + +# NTP services +DOMAIN-REGEX,^time\.[^.]+\.com$ +DOMAIN-REGEX,^time\.[^.]+\.gov$ +DOMAIN-REGEX,^time\.[^.]+\.edu\.cn$ +DOMAIN-REGEX,^time\.[^.]+\.apple\.com$ +DOMAIN,time-ios.apple.com +DOMAIN-REGEX,^time[1-7]\.[^.]+\.com$ +DOMAIN-REGEX,^ntp\.[^.]+\.com$ +DOMAIN-REGEX,^ntp[1-7]\.[^.]+\.com$ +DOMAIN-SUFFIX,time.edu.cn +DOMAIN-SUFFIX,ntp.org.cn +DOMAIN-SUFFIX,pool.ntp.org +DOMAIN,time1.cloud.tencent.com + +# Music services +DOMAIN-SUFFIX,music.163.com +DOMAIN-SUFFIX,126.net +DOMAIN,musicapi.taihe.com +DOMAIN,music.taihe.com +DOMAIN,songsearch.kugou.com +DOMAIN,trackercdn.kugou.com +DOMAIN-SUFFIX,kuwo.cn +DOMAIN,api-jooxtt.sanook.com +DOMAIN,api.joox.com +DOMAIN,joox.com +DOMAIN-SUFFIX,y.qq.com +DOMAIN,streamoc.music.tc.qq.com +DOMAIN,mobileoc.music.tc.qq.com +DOMAIN,isure.stream.qqmusic.qq.com +DOMAIN,dl.stream.qqmusic.qq.com +DOMAIN,aqqmusic.tc.qq.com +DOMAIN,amobile.music.tc.qq.com +DOMAIN-SUFFIX,xiami.com +DOMAIN-SUFFIX,music.migu.cn + +# Connectivity checks and local login endpoints +DOMAIN-SUFFIX,msftconnecttest.com +DOMAIN-SUFFIX,msftncsi.com +DOMAIN,localhost.ptlogin2.qq.com +DOMAIN,localhost.sec.qq.com +DOMAIN-REGEX,^localhost\.[^.]+\.weixin\.qq\.com$ +DOMAIN-SUFFIX,kk-rays.com + +# Games +DOMAIN-SUFFIX,steamcontent.com +DOMAIN-SUFFIX,srv.nintendo.net +DOMAIN-SUFFIX,cdn.nintendo.net +DOMAIN-REGEX,^xbox\.[^.]+\.[^.]+\.microsoft\.com$ +DOMAIN-REGEX,^(?:[^.]+\.){2}xboxlive\.com$ +DOMAIN-REGEX,^xbox\.[^.]+\.microsoft\.com$ +DOMAIN,xnotify.xboxlive.com +DOMAIN-SUFFIX,battle.net +DOMAIN-SUFFIX,battlenet.com.cn +DOMAIN-SUFFIX,wotgame.cn +DOMAIN-SUFFIX,wggames.cn +DOMAIN-SUFFIX,wowsgame.cn +DOMAIN-SUFFIX,wargaming.net + +# Development and STUN +DOMAIN,proxy.golang.org +DOMAIN-REGEX,^(?:.+\.)?stun(?:\.[^.]+){2,5}$ + +# Routers +DOMAIN,heartbeat.belkin.com +DOMAIN-SUFFIX,linksys.com +DOMAIN-SUFFIX,linksyssmartwifi.com +DOMAIN-SUFFIX,router.asus.com + +# Apple software updates +DOMAIN,mesu.apple.com +DOMAIN,swscan.apple.com +DOMAIN,swquery.apple.com +DOMAIN,swdownload.apple.com +DOMAIN,swcdn.apple.com +DOMAIN,swdist.apple.com + +# Services and applications +DOMAIN,lens.l.google.com +DOMAIN,na.b.g-tun.com +DOMAIN-SUFFIX,square-enix.com +DOMAIN-SUFFIX,finalfantasyxiv.com +DOMAIN-SUFFIX,ffxiv.com +DOMAIN-SUFFIX,ff14.sdo.com +DOMAIN,ff.dorado.sdo.com +DOMAIN-SUFFIX,mcdn.bilivideo.cn +DOMAIN-SUFFIX,media.dssott.com +DOMAIN,shark007.net +DOMAIN-SUFFIX,market.xiaomi.com +DOMAIN-SUFFIX,cmbchina.com +DOMAIN-SUFFIX,cmbimg.com +DOMAIN,adguardteam.github.io +DOMAIN,adrules.top +DOMAIN,anti-ad.net +DOMAIN,local.adguard.org +DOMAIN,static.adtidy.org +DOMAIN-SUFFIX,sandai.net +DOMAIN-SUFFIX,n0808.com +DOMAIN-SUFFIX,3gppnetwork.org +DOMAIN-SUFFIX,uu.163.com +DOMAIN,ps.res.netease.com +DOMAIN-SUFFIX,oray.com +DOMAIN-SUFFIX,orayimg.com +DOMAIN-SUFFIX,gcloudcs.com +DOMAIN-SUFFIX,gcloudsdk.com +DOMAIN-SUFFIX,dynv6.net