From 7cfdc0fbcc65ef30c272ab5f6d75782dcd56d9b5 Mon Sep 17 00:00:00 2001 From: ageorge156 Date: Sun, 30 Aug 2026 16:00:41 +0800 Subject: [PATCH] fix: keep OneDrive on direct routing --- README.md | 4 +++- direct.yaml | 3 +++ router/direct-plain.txt | 1 + router/direct-rules.yaml | 1 + scripts/gen_clash_verge_script.py | 20 +++++++++++++++++++- tests/test_module_spec.py | 18 ++++++++++++++++++ 6 files changed, 45 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7a844b6..a13a3f9 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ vpn-rules/ ## 为什么需要它 - 香港代理节点有流量配额(如 BygCloud 100GiB 用满),国内站点/内网流量被隧道进代理会白白烧配额。 -- 必须直连的对象:FRP 控制面(mTLS)、B 站全系、DeepSeek/MiniMax 等国内 LLM API、 +- 必须直连的对象:Windows OneDrive 客户端、FRP 控制面(mTLS)、B 站全系、DeepSeek/MiniMax 等国内 LLM API、 内网/私有 IP 段、国区 iCloud、UGREEN 绿联 NAS 云。 - **踩坑**:Clash Verge 全局 `Merge.yaml` 的 `prepend-rules` 会被内核忽略(不生效), 全局直连规则的唯一正确机制是 `profiles/Script.js`(`main(config)` 把规则 prepend 进 `config.rules`)。 @@ -36,6 +36,8 @@ python3 scripts/gen_clash_verge_script.py ``` 对当前及以后新增/切换的所有订阅生效;订阅更新不会覆盖它。 +脚本还会把国内可达的阿里 DNS 和腾讯 DNS DoH 端点补入 `dns.fallback`,避免境外域名 +命中 `DIRECT` 后因供应商的境外 DNS fallback 不可达而解析失败。 Windows 默认写入 `%APPDATA%\io.github.clash-verge-rev.clash-verge-rev\profiles\Script.js`; macOS 默认写入 `~/Library/Application Support/io.github.clash-verge-rev.clash-verge-rev/profiles/Script.js`。 diff --git a/direct.yaml b/direct.yaml index 52ecf5b..b4e8c7b 100644 --- a/direct.yaml +++ b/direct.yaml @@ -20,6 +20,9 @@ # 路由器端则等 rule-provider 的 interval 到期或手动 reload。 payload: + # Windows OneDrive 客户端始终直连,避免被供应商 Microsoft 规则送入代理 + - PROCESS-NAME,OneDrive.exe + # FRP 控制面(mTLS)保持直连 - DOMAIN,frp.puyuanfh.cn - IP-CIDR,8.133.177.3/32,no-resolve diff --git a/router/direct-plain.txt b/router/direct-plain.txt index e4005a6..a1a0a2e 100644 --- a/router/direct-plain.txt +++ b/router/direct-plain.txt @@ -1,3 +1,4 @@ +PROCESS-NAME,OneDrive.exe DOMAIN,frp.puyuanfh.cn IP-CIDR,8.133.177.3/32,no-resolve DOMAIN-SUFFIX,bilibili.com diff --git a/router/direct-rules.yaml b/router/direct-rules.yaml index 4f20ea7..8b6c273 100644 --- a/router/direct-rules.yaml +++ b/router/direct-rules.yaml @@ -11,6 +11,7 @@ # 内网源:http://192.168.50.2:3000/ageorge156/vpn-rules/raw/branch/main/direct.yaml rules: + - PROCESS-NAME,OneDrive.exe,DIRECT - DOMAIN,frp.puyuanfh.cn,DIRECT - IP-CIDR,8.133.177.3/32,DIRECT,no-resolve - DOMAIN-SUFFIX,bilibili.com,DIRECT diff --git a/scripts/gen_clash_verge_script.py b/scripts/gen_clash_verge_script.py index 99f28fa..dd1f4d4 100644 --- a/scripts/gen_clash_verge_script.py +++ b/scripts/gen_clash_verge_script.py @@ -62,19 +62,37 @@ def render_script(payload: list[str]) -> str: rules = [f" {to_rule(e)!r}," for e in payload] lines = "\n".join(rules) return f"""// 由 vpn-rules/direct.yaml 生成 — 勿手改,改真源后重跑 gen_clash_verge_script.py。 -// 全局直连规则:FRP 控制面、B站、国内 LLM、内网段、国区 iCloud、UGREEN 一律 DIRECT。 +// 全局直连规则:OneDrive、FRP 控制面、B站、国内 LLM、内网段、国区 iCloud、UGREEN 一律 DIRECT。 const prependRules = [ {lines} ]; +// 国内可达的 DoH 同时作为 fallback,确保 OneDrive 等境外域名在 DIRECT 出站前可解析。 +const directDnsFallbacks = [ + 'https://dns.alidns.com/dns-query', + 'https://doh.pub/dns-query', +]; + function main(config, profileName) {{ const existingRules = Array.isArray(config.rules) ? config.rules : []; const existingRuleSet = new Set(existingRules); + const dns = config.dns && typeof config.dns === 'object' && !Array.isArray(config.dns) + ? config.dns + : {{}}; + const existingFallbacks = Array.isArray(dns.fallback) + ? dns.fallback + : (typeof dns.fallback === 'string' ? [dns.fallback] : []); + const existingFallbackSet = new Set(existingFallbacks); config.rules = [ ...prependRules.filter((rule) => !existingRuleSet.has(rule)), ...existingRules, ]; + dns.fallback = [ + ...directDnsFallbacks.filter((server) => !existingFallbackSet.has(server)), + ...existingFallbacks, + ]; + config.dns = dns; return config; }} diff --git a/tests/test_module_spec.py b/tests/test_module_spec.py index 2c5fe3b..270278d 100644 --- a/tests/test_module_spec.py +++ b/tests/test_module_spec.py @@ -16,6 +16,7 @@ sys.path.insert(0, str(ROOT / "scripts")) from gen_clash_verge_script import ( # noqa: E402 default_output_path, load_payload, + render_script, to_rule, ) @@ -193,6 +194,23 @@ class ModuleSpecTests(unittest.TestCase): ) self.assertTrue(all(",DIRECT" not in entry for entry in payload)) + def test_onedrive_process_is_forced_to_use_direct_routing(self) -> None: + payload = load_payload(ROOT / "direct.yaml") + + self.assertIn("PROCESS-NAME,OneDrive.exe", payload) + self.assertEqual( + to_rule("PROCESS-NAME,OneDrive.exe"), + "PROCESS-NAME,OneDrive.exe,DIRECT", + ) + + def test_clash_verge_script_adds_reachable_direct_dns_fallbacks(self) -> None: + script = render_script(["PROCESS-NAME,OneDrive.exe"]) + + self.assertIn("const directDnsFallbacks", script) + self.assertIn("https://dns.alidns.com/dns-query", script) + self.assertIn("https://doh.pub/dns-query", script) + self.assertIn("config.dns = dns", script) + if __name__ == "__main__": unittest.main()