This commit is contained in:
@@ -20,7 +20,7 @@ vpn-rules/
|
|||||||
## 为什么需要它
|
## 为什么需要它
|
||||||
|
|
||||||
- 香港代理节点有流量配额(如 BygCloud 100GiB 用满),国内站点/内网流量被隧道进代理会白白烧配额。
|
- 香港代理节点有流量配额(如 BygCloud 100GiB 用满),国内站点/内网流量被隧道进代理会白白烧配额。
|
||||||
- 必须直连的对象:FRP 控制面(mTLS)、B 站全系、DeepSeek/MiniMax 等国内 LLM API、
|
- 必须直连的对象:Windows OneDrive 客户端、FRP 控制面(mTLS)、B 站全系、DeepSeek/MiniMax 等国内 LLM API、
|
||||||
内网/私有 IP 段、国区 iCloud、UGREEN 绿联 NAS 云。
|
内网/私有 IP 段、国区 iCloud、UGREEN 绿联 NAS 云。
|
||||||
- **踩坑**:Clash Verge 全局 `Merge.yaml` 的 `prepend-rules` 会被内核忽略(不生效),
|
- **踩坑**:Clash Verge 全局 `Merge.yaml` 的 `prepend-rules` 会被内核忽略(不生效),
|
||||||
全局直连规则的唯一正确机制是 `profiles/Script.js`(`main(config)` 把规则 prepend 进 `config.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`;
|
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`。
|
macOS 默认写入 `~/Library/Application Support/io.github.clash-verge-rev.clash-verge-rev/profiles/Script.js`。
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,9 @@
|
|||||||
# 路由器端则等 rule-provider 的 interval 到期或手动 reload。
|
# 路由器端则等 rule-provider 的 interval 到期或手动 reload。
|
||||||
|
|
||||||
payload:
|
payload:
|
||||||
|
# Windows OneDrive 客户端始终直连,避免被供应商 Microsoft 规则送入代理
|
||||||
|
- PROCESS-NAME,OneDrive.exe
|
||||||
|
|
||||||
# FRP 控制面(mTLS)保持直连
|
# FRP 控制面(mTLS)保持直连
|
||||||
- DOMAIN,frp.puyuanfh.cn
|
- DOMAIN,frp.puyuanfh.cn
|
||||||
- IP-CIDR,8.133.177.3/32,no-resolve
|
- IP-CIDR,8.133.177.3/32,no-resolve
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
PROCESS-NAME,OneDrive.exe
|
||||||
DOMAIN,frp.puyuanfh.cn
|
DOMAIN,frp.puyuanfh.cn
|
||||||
IP-CIDR,8.133.177.3/32,no-resolve
|
IP-CIDR,8.133.177.3/32,no-resolve
|
||||||
DOMAIN-SUFFIX,bilibili.com
|
DOMAIN-SUFFIX,bilibili.com
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
# 内网源:http://192.168.50.2:3000/ageorge156/vpn-rules/raw/branch/main/direct.yaml
|
# 内网源:http://192.168.50.2:3000/ageorge156/vpn-rules/raw/branch/main/direct.yaml
|
||||||
|
|
||||||
rules:
|
rules:
|
||||||
|
- PROCESS-NAME,OneDrive.exe,DIRECT
|
||||||
- DOMAIN,frp.puyuanfh.cn,DIRECT
|
- DOMAIN,frp.puyuanfh.cn,DIRECT
|
||||||
- IP-CIDR,8.133.177.3/32,DIRECT,no-resolve
|
- IP-CIDR,8.133.177.3/32,DIRECT,no-resolve
|
||||||
- DOMAIN-SUFFIX,bilibili.com,DIRECT
|
- DOMAIN-SUFFIX,bilibili.com,DIRECT
|
||||||
|
|||||||
@@ -62,19 +62,37 @@ def render_script(payload: list[str]) -> str:
|
|||||||
rules = [f" {to_rule(e)!r}," for e in payload]
|
rules = [f" {to_rule(e)!r}," for e in payload]
|
||||||
lines = "\n".join(rules)
|
lines = "\n".join(rules)
|
||||||
return f"""// 由 vpn-rules/direct.yaml 生成 — 勿手改,改真源后重跑 gen_clash_verge_script.py。
|
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 = [
|
const prependRules = [
|
||||||
{lines}
|
{lines}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// 国内可达的 DoH 同时作为 fallback,确保 OneDrive 等境外域名在 DIRECT 出站前可解析。
|
||||||
|
const directDnsFallbacks = [
|
||||||
|
'https://dns.alidns.com/dns-query',
|
||||||
|
'https://doh.pub/dns-query',
|
||||||
|
];
|
||||||
|
|
||||||
function main(config, profileName) {{
|
function main(config, profileName) {{
|
||||||
const existingRules = Array.isArray(config.rules) ? config.rules : [];
|
const existingRules = Array.isArray(config.rules) ? config.rules : [];
|
||||||
const existingRuleSet = new Set(existingRules);
|
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 = [
|
config.rules = [
|
||||||
...prependRules.filter((rule) => !existingRuleSet.has(rule)),
|
...prependRules.filter((rule) => !existingRuleSet.has(rule)),
|
||||||
...existingRules,
|
...existingRules,
|
||||||
];
|
];
|
||||||
|
dns.fallback = [
|
||||||
|
...directDnsFallbacks.filter((server) => !existingFallbackSet.has(server)),
|
||||||
|
...existingFallbacks,
|
||||||
|
];
|
||||||
|
config.dns = dns;
|
||||||
|
|
||||||
return config;
|
return config;
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ sys.path.insert(0, str(ROOT / "scripts"))
|
|||||||
from gen_clash_verge_script import ( # noqa: E402
|
from gen_clash_verge_script import ( # noqa: E402
|
||||||
default_output_path,
|
default_output_path,
|
||||||
load_payload,
|
load_payload,
|
||||||
|
render_script,
|
||||||
to_rule,
|
to_rule,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -193,6 +194,23 @@ class ModuleSpecTests(unittest.TestCase):
|
|||||||
)
|
)
|
||||||
self.assertTrue(all(",DIRECT" not in entry for entry in payload))
|
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__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|||||||
Reference in New Issue
Block a user