/* ============================================================ * 1. 基础配置 * ============================================================ */ const generalConfig = { "mode": "rule", /* * 关闭 IPv6。 * * 移动网络环境下优先保证稳定性。 */ "ipv6": false, "log-level": "silent", "allow-lan": true, /* * 统一延迟计算。 */ "unified-delay": true, /* * TCP 并发连接。 */ "tcp-concurrent": true, /* * 严格进程匹配。 */ "find-process-mode": "strict", /* * Chrome TLS 指纹。 */ "global-client-fingerprint": "chrome", "profile": { "store-selected": true, "store-fake-ip": true } }; /* ============================================================ * 2. Sniffer * ============================================================ */ const snifferConfig = { "enable": true, "parse-pure-ip": true, "sniff": { "HTTP": { "ports": [ 80, "8080-8880" ], "override-destination": true }, "TLS": { "ports": [ 443, 8443 ] }, "QUIC": { "ports": [ 443, 8443 ] } }, "skip-domain": [ "Mijia Cloud" ] }; /* ============================================================ * 3. TUN * ============================================================ */ const tunConfig = { "enable": true, "stack": "system", "dns-hijack": [ "any:53" ], "auto-route": true, "auto-detect-interface": true, "strict-route": true }; /* ============================================================ * 4. DNS * ============================================================ */ const dnsConfig = { "enable": true, "ipv6": false, /* * 移动网络环境下优先稳定性。 */ "prefer-h3": false, "listen": "0.0.0.0:53", "fake-ip-range": "198.18.0.1/16", "enhanced-mode": "fake-ip", /* * 主 DNS。 */ "nameserver": [ "https://dns.alidns.com/dns-query", "https://doh.pub/dns-query" ], /* * DNS 备用。 */ "fallback": [ "223.5.5.5", "119.29.29.29" ], /* * 启动阶段 DNS。 */ "default-nameserver": [ "223.5.5.5", "114.114.114.114" ], /* * DNS 回退过滤。 */ "fallback-filter": { "geoip": true, "geoip-code": "CN", "geosite": [ "gfw" ], "ipcidr": [ "240.0.0.0/4", "0.0.0.0/32", "127.0.0.1/32" ] }, /* * Fake-IP 排除列表。 */ "fake-ip-filter": [ "*.lan", "*.localdomain", "*.example", "*.invalid", "*.localhost", "*.test", "*.local", "*.home.arpa", "*.woozooo.com", "*.kiid.top", "43.142.112.88", "time.*.com", "time.*.gov", "time.*.edu.cn", "time.*.apple.com", "time-ios.apple.com", "time1.*.com", "time2.*.com", "time3.*.com", "time4.*.com", "time5.*.com", "time6.*.com", "time7.*.com", "ntp.*.com", "ntp1.*.com", "ntp2.*.com", "ntp3.*.com", "ntp4.*.com", "ntp5.*.com", "ntp6.*.com", "ntp7.*.com", "*.time.edu.cn", "*.ntp.org.cn", "+.pool.ntp.org", "time1.cloud.tencent.com", "music.163.com", "*.music.163.com", "*.126.net", "musicapi.taihe.com", "music.taihe.com", "songsearch.kugou.com", "trackercdn.kugou.com", "*.kuwo.cn", "api-jooxtt.sanook.com", "api.joox.com", "joox.com", "y.qq.com", "*.y.qq.com", "streamoc.music.tc.qq.com", "mobileoc.music.tc.qq.com", "isure.stream.qqmusic.qq.com", "dl.stream.qq.com", "aqqmusic.tc.qq.com", "amobile.music.tc.qq.com", "*.xiami.com", "*.music.migu.cn", "music.migu.cn", "+.msftconnecttest.com", "+.msftncsi.com", "localhost.ptlogin2.qq.com", "localhost.sec.qq.com", "+.qq.com", "+.tencent.com", "+.srv.nintendo.net", "*.n.n.srv.nintendo.net", "+.stun.playstation.net", "xbox.*.*.microsoft.com", "*.*.xboxlive.com", "xbox.*.microsoft.com", "xnotify.xboxlive.com", "+.battlenet.com.cn", "+.wotgame.cn", "+.wggames.cn", "+.wowsgame.cn", "+.wargaming.net", "proxy.golang.org", "stun.*.*", "stun.*.*.*", "+.stun.*.*", "+.stun.*.*.*", "+.stun.*.*.*.*", "+.stun.*.*.*.*.*", "heartbeat.belkin.com", "*.linksys.com", "*.linksyssmartwifi.com", "*.router.asus.com", "mesu.apple.com", "swscan.apple.com", "swquery.apple.com", "swdownload.apple.com", "swdist.apple.com", "lens.l.google.com", "stun.l.google.com", "na.b.g-tun.com", "+.nflxvideo.net", "*.square-enix.com", "*.finalfantasyxiv.com", "*.ffxiv.com", "*.ff14.sdo.com", "ff.dorado.sdo.com", "*.mcdn.bilivideo.cn", "+.media.dssott.com", "shark007.net", "Mijia Cloud", "+.cmbchina.com", "+.cmbimg.com", "adguardteam.github.io", "adrules.top", "anti-ad.net", "local.adguard.org", "static.adtidy.org", "+.sandai.net", "+.n0808.com", "+.3gppnetwork.org" ] }; /* ============================================================ * 5. 节点名称过滤 * ============================================================ */ /* * 排除: * * - 回国 * - 校园 * - 游戏 * - 通知 * - 流量 * - 到期 * - 官网 * - 客服 * - 机场 * - 邀请 * - 返利 * - 循环 * - 备用 * - 过期 * - 已用 * - 联系 * - 邮箱 * - 工单 * - 贩卖 * - 倒卖 * - 防止 * - 国内 * - 地址 * - 频道 * - 无法 * - 说明 * - 使用 * - 提示 * - 特别 * - 访问 * - 支持 * - 教程 * - 关注 * - 更新 * - 作者 * - 加入 * - 超时 * - 收藏 * - 福利 * - 失联 * 等非实际代理节点。 */ const nodeNameExcludeReg = /回国|校园|游戏|通知|流量|到期|官网|客服|机场|邀请|返利|循环|备用|过期|已用|联系|邮箱|工单|贩卖|倒卖|防止|国内|地址|频道|无法|说明|使用|提示|特别|访问|支持|教程|关注|更新|作者|加入|超时|收藏|福利|失联|\b(USE|USED|TOTAL|EXPIRE|EMAIL|PANEL|CHANNEL|AUTHOR|TRAFFIC)\b|compatible/i; /* ============================================================ * 6. 地区定义 * ============================================================ */ /* * 地区匹配优先级: * * 1. 香港 * 2. 台湾 * 3. 日本 * 4. 新加坡 * 5. 美国 * 6. 韩国 * 7. 其他 * * 其他没有 pattern, * 只负责接收没有匹配任何已知地区的节点。 */ const regionDefinitions = [ { key: "hongKong", groupName: "🇭🇰 香港节点", pattern: /🇭🇰|香港|\b(HK|HKG|Hong Kong)\b/i }, { key: "taiwan", groupName: "🇹🇼 台湾节点", pattern: /🇹🇼|台湾|\b(TW|TWN|Taiwan)\b/i }, { key: "japan", groupName: "🇯🇵 日本节点", pattern: /🇯🇵|日本|\b(JP|JPN|Japan)\b/i }, { key: "singapore", groupName: "🇸🇬 新加坡节点", pattern: /🇸🇬|新加坡|狮城|\b(SG|SGP|Singapore)\b/i }, { key: "usa", groupName: "🇺🇸 美国节点", pattern: /🇺🇸|美国|\b(US|USA|United States)\b/i }, { key: "korea", groupName: "🇰🇷 韩国节点", pattern: /🇰🇷|韩国|首尔|\b(KR|KOR|Korea)\b/i }, { key: "other", groupName: "🇨🇳 其他节点", pattern: null } ]; /* ============================================================ * 7. AI 地区 * ============================================================ */ /* * 香港明确排除。 * * AI 可以使用: * * 台湾 * 日本 * 新加坡 * 美国 * 韩国 * 其他 */ const aiRegionKeys = [ "taiwan", "japan", "singapore", "usa", "korea", "other" ]; /* ============================================================ * 8. 测速配置 * ============================================================ */ const speedTestUrl = "https://www.gstatic.com/generate_204"; /* * 所有 URL-Test 统一使用此参数。 */ const urlTestDefaults = { "interval": 600, "timeout": 3000, "url": speedTestUrl, "lazy": true, "max-failed-times": 3, "tolerance": 80 }; /* ============================================================ * 9. Rule Provider * ============================================================ */ const mirrorBaseUrl = "https://ghproxy.net/"; const ruleProviders = { "ads": { "type": "http", "behavior": "domain", "format": "text", "path": "./rules/adss.list", "url": mirrorBaseUrl + "https://raw.githubusercontent.com/DustinWin/ruleset_geodata/clash-ruleset/ads.list", "interval": 86400 }, "applications": { "type": "http", "behavior": "classical", "format": "text", "path": "./rules/applicationss.list", "url": mirrorBaseUrl + "https://raw.githubusercontent.com/DustinWin/ruleset_geodata/clash-ruleset/applications.list", "interval": 86400 }, "private": { "type": "http", "behavior": "domain", "format": "text", "path": "./rules/privates.list", "url": mirrorBaseUrl + "https://raw.githubusercontent.com/DustinWin/ruleset_geodata/clash-ruleset/private.list", "filter": "^((?!openai).)*$", "interval": 86400 }, "microsoft-cn": { "type": "http", "behavior": "domain", "format": "text", "path": "./rules/microsoft-cns.list", "url": mirrorBaseUrl + "https://raw.githubusercontent.com/DustinWin/ruleset_geodata/clash-ruleset/microsoft-cn.list", "interval": 86400 }, "openai": { "type": "http", "behavior": "domain", "format": "text", "path": "./rules/openais.list", "url": mirrorBaseUrl + "https://raw.githubusercontent.com/DustinWin/ruleset_geodata/mihomo-ruleset/ai.list", "interval": 86400 }, "apple-cn": { "type": "http", "behavior": "domain", "format": "text", "path": "./rules/apple-cns.list", "url": mirrorBaseUrl + "https://raw.githubusercontent.com/DustinWin/ruleset_geodata/clash-ruleset/apple-cn.list", "interval": 86400 }, "google-cn": { "type": "http", "behavior": "domain", "format": "text", "path": "./rules/google-cns.list", "url": mirrorBaseUrl + "https://raw.githubusercontent.com/DustinWin/ruleset_geodata/clash-ruleset/google-cn.list", "interval": 86400 }, "games-cn": { "type": "http", "behavior": "domain", "format": "text", "path": "./rules/games-cns.list", "url": mirrorBaseUrl + "https://raw.githubusercontent.com/DustinWin/ruleset_geodata/clash-ruleset/games-cn.list", "interval": 86400 }, "networktest": { "type": "http", "behavior": "classical", "format": "text", "path": "./rules/networktests.list", "url": mirrorBaseUrl + "https://raw.githubusercontent.com/DustinWin/ruleset_geodata/clash-ruleset/networktest.list", "interval": 86400 }, "proxy": { "type": "http", "behavior": "domain", "format": "text", "path": "./rules/proxys.list", "url": mirrorBaseUrl + "https://raw.githubusercontent.com/y7478729/ruleset_geodata/clash-ruleset/proxy.list", "interval": 86400 }, "cn": { "type": "http", "behavior": "domain", "format": "text", "path": "./rules/cns.list", "url": mirrorBaseUrl + "https://raw.githubusercontent.com/DustinWin/ruleset_geodata/clash-ruleset/cn.list", "interval": 86400 }, "telegramip": { "type": "http", "behavior": "ipcidr", "format": "text", "path": "./rules/telegramips.list", "url": mirrorBaseUrl + "https://raw.githubusercontent.com/DustinWin/ruleset_geodata/clash-ruleset/telegramip.list", "interval": 86400 }, "privateip": { "type": "http", "behavior": "ipcidr", "format": "text", "path": "./rules/privateips.list", "url": mirrorBaseUrl + "https://raw.githubusercontent.com/DustinWin/ruleset_geodata/clash-ruleset/privateip.list", "interval": 86400 }, "cnip": { "type": "http", "behavior": "ipcidr", "format": "text", "path": "./rules/cnips.list", "url": mirrorBaseUrl + "https://raw.githubusercontent.com/DustinWin/ruleset_geodata/clash-ruleset/cnip.list", "interval": 86400 } }; /* ============================================================ * 10. 分流规则 * ============================================================ */ const rules = [ /* * AI */ "RULE-SET,openai,🤖 人工智能", /* * 广告 */ "RULE-SET,ads,🆎 广告拦截", /* * 本地应用 */ "RULE-SET,applications,🎯 全球直连", /* * 私有网络 */ "RULE-SET,private,🎯 全球直连", /* * 微软 */ "RULE-SET,microsoft-cn,🎯 全球直连", /* * Apple */ "RULE-SET,apple-cn,🎯 全球直连", /* * Google */ "RULE-SET,google-cn,🌐 海外服务", /* * 游戏 */ "RULE-SET,games-cn,🎯 全球直连", /* * 网络测试 */ "RULE-SET,networktest,📈 网络测试", /* * 已知代理域名 */ "RULE-SET,proxy,🪜 代理域名", /* * 中国域名 */ "RULE-SET,cn,🎯 全球直连", /* * Telegram IP */ "RULE-SET,telegramip,🌐 海外服务,no-resolve", /* * 私有 IP */ "RULE-SET,privateip,🎯 全球直连,no-resolve", /* * 中国 IP */ "RULE-SET,cnip,🎯 全球直连,no-resolve", /* * 最终兜底 */ "MATCH,🛟 兜底策略" ]; /* ============================================================ * 11. 通用工具函数 * ============================================================ */ /* * 数组去重,同时保持原始顺序。 */ function unique(items) { return [ ...new Set( items.filter(Boolean) ) ]; } /* * 安全读取节点名称。 */ function getProxyName(proxy) { if ( !proxy || typeof proxy.name !== "string" ) { return ""; } return proxy.name.trim(); } /* * 判断是否为有效节点。 */ function isValidProxy(proxy) { const name = getProxyName(proxy); if (!name) { return false; } return !nodeNameExcludeReg.test( name ); } /* ============================================================ * 12. 获取原始节点 * ============================================================ */ function getRawProxies(config) { /* * 优先使用 Sub-Store 传入的 config.proxies。 */ if ( config && Array.isArray(config.proxies) ) { return config.proxies; } /* * 兼容 Sub-Store $proxies。 */ if ( typeof $proxies !== "undefined" && Array.isArray($proxies) ) { return $proxies; } return []; } /* ============================================================ * 13. 过滤有效节点 * ============================================================ */ function filterValidProxies(proxies) { return unique( proxies .filter(isValidProxy) .map(proxy => ({ ...proxy, name: getProxyName(proxy) })) ); } /* ============================================================ * 14. 节点地区分类 * ============================================================ */ /* * 与旧版本不同: * * 不再: * * 地区 1 → 遍历全部节点 * 地区 2 → 遍历全部节点 * 地区 3 → 遍历全部节点 * * 而是: * * 节点 1 → 找到所属地区 * 节点 2 → 找到所属地区 * 节点 3 → 找到所属地区 * * 每个节点只分类一次。 */ function classifyProxies( proxies ) { const regionProxyMap = {}; /* * 初始化所有地区。 */ regionDefinitions.forEach( region => { regionProxyMap[ region.key ] = []; } ); /* * 每个节点只处理一次。 */ proxies.forEach(proxy => { const name = getProxyName(proxy); /* * 从前往后寻找第一个匹配地区。 * * other 没有 pattern, * 因此最终自然成为兜底。 */ const matchedRegion = regionDefinitions.find( region => { if (!region.pattern) { return true; } return region.pattern.test( name ); } ); /* * 理论上不会出现, * 因为 other 永远存在。 */ if (!matchedRegion) { return; } regionProxyMap[ matchedRegion.key ].push(name); }); /* * 最终统一去重。 */ Object.keys( regionProxyMap ).forEach(key => { regionProxyMap[key] = unique( regionProxyMap[key] ); }); return regionProxyMap; } /* ============================================================ * 15. 创建地区测速组 * ============================================================ */ function createRegionUrlTestGroup( region, proxyNames ) { return { ...urlTestDefaults, "name": region.groupName, "type": "url-test", "proxies": unique( proxyNames ), /* * 地区组只允许真实代理节点。 */ "exclude-type": "direct" }; } /* ============================================================ * 16. 创建 Select 组 * ============================================================ */ function createSelectGroup( name, proxies, options = {} ) { return { "name": name, "type": "select", "proxies": unique( proxies ), ...options }; } /* ============================================================ * 17. 获取地区组名称 * ============================================================ */ function getActiveRegionNames( regionDefinitions, regionProxyMap ) { return regionDefinitions .filter(region => { const nodes = regionProxyMap[ region.key ]; return ( Array.isArray(nodes) && nodes.length > 0 ); }) .map(region => region.groupName ); } /* ============================================================ * 18. 获取 AI 候选地区 * ============================================================ */ function getAiCandidates( regionDefinitions, regionProxyMap ) { const candidates = []; aiRegionKeys.forEach( regionKey => { const region = regionDefinitions.find( item => item.key === regionKey ); if (!region) { return; } const nodes = regionProxyMap[ regionKey ]; if ( !Array.isArray(nodes) || nodes.length === 0 ) { return; } candidates.push( region.groupName ); } ); /* * 非香港地区全部不存在时: * * 不允许回退到自动选择, * 因为自动选择可能包含香港。 * * 使用 DIRECT 保证: * * 1. 策略组始终存在 * 2. 配置始终合法 * 3. 香港永远不会进入 AI */ return candidates.length > 0 ? unique(candidates) : ["DIRECT"]; } /* ============================================================ * 19. 创建自动选择 * ============================================================ */ function createAutoSelectGroup( candidates ) { return { ...urlTestDefaults, "name": "♻️ 自动选择", "type": "url-test", "proxies": unique( candidates ) }; } /* ============================================================ * 20. 创建故障转移 * ============================================================ */ function createFallbackGroup( candidates ) { return { "name": "🔯 故障转移", "type": "fallback", "proxies": unique( candidates ), "url": speedTestUrl, "interval": 600, "timeout": 3000, "lazy": true }; } /* ============================================================ * 21. 主函数 * ============================================================ */ function main(config = {}) { /* ---------------------------------------------------------- * 21.1 获取原始节点 * ---------------------------------------------------------- */ const rawProxies = getRawProxies(config); /* ---------------------------------------------------------- * 21.2 过滤有效节点 * ---------------------------------------------------------- */ const filteredProxies = filterValidProxies( rawProxies ); /* * 保留过滤后的节点。 */ config.proxies = filteredProxies; /* ---------------------------------------------------------- * 21.3 地区分类 * ---------------------------------------------------------- */ const regionProxyMap = classifyProxies( filteredProxies ); /* ---------------------------------------------------------- * 21.4 获取实际存在的地区 * ---------------------------------------------------------- */ const activeRegions = getActiveRegionNames( regionDefinitions, regionProxyMap ); /* ---------------------------------------------------------- * 21.5 创建地区测速组 * ---------------------------------------------------------- */ const regionUrlTestGroups = []; regionDefinitions.forEach( region => { const proxyNames = regionProxyMap[ region.key ]; /* * 没有节点则隐藏。 */ if ( !Array.isArray(proxyNames) || proxyNames.length === 0 ) { return; } regionUrlTestGroups.push( createRegionUrlTestGroup( region, proxyNames ) ); } ); /* ---------------------------------------------------------- * 21.6 自动选择候选 * ---------------------------------------------------------- */ const autoSelectCandidates = activeRegions.length > 0 ? activeRegions : ["DIRECT"]; const autoSelectGroup = createAutoSelectGroup( autoSelectCandidates ); /* ---------------------------------------------------------- * 21.7 故障转移 * ---------------------------------------------------------- */ const fallbackGroup = createFallbackGroup( autoSelectCandidates ); /* ---------------------------------------------------------- * 21.8 AI * ---------------------------------------------------------- */ const aiCandidates = getAiCandidates( regionDefinitions, regionProxyMap ); const aiGroup = { "name": "🤖 人工智能", "type": "url-test", "proxies": aiCandidates, "url": speedTestUrl, "interval": 600, "timeout": 3000, "lazy": true, "tolerance": 80, "max-failed-times": 3 }; /* ---------------------------------------------------------- * 21.9 主节点选择 * ---------------------------------------------------------- */ const nodeSelectCandidates = unique([ "♻️ 自动选择", "🔯 故障转移", ...activeRegions ]); /* ---------------------------------------------------------- * 21.10 构建策略组 * ---------------------------------------------------------- */ const proxyGroups = [ /* * ======================================================== * 核心策略组 * ======================================================== * * 按重要程度放在最顶部。 */ createSelectGroup( "🚀 节点选择", nodeSelectCandidates ), autoSelectGroup, fallbackGroup, /* * ======================================================== * 地区自动测速 * ======================================================== */ ...regionUrlTestGroups, /* * ======================================================== * 人工智能 * ======================================================== */ aiGroup, /* * ======================================================== * 海外服务 * ======================================================== */ createSelectGroup( "🌐 海外服务", [ "🚀 节点选择", "♻️ 自动选择", "🔯 故障转移", ...activeRegions ] ), /* * ======================================================== * 代理域名 * ======================================================== */ createSelectGroup( "🪜 代理域名", [ "🚀 节点选择", "🎯 全球直连" ] ), /* * ======================================================== * 网络测试 * ======================================================== */ createSelectGroup( "📈 网络测试", [ "🎯 全球直连", "🚀 节点选择", "♻️ 自动选择", "🔯 故障转移" ] ), /* * ======================================================== * 广告拦截 * ======================================================== */ createSelectGroup( "🆎 广告拦截", [ "REJECT" ] ), /* * ======================================================== * 最终兜底 * ======================================================== */ createSelectGroup( "🛟 兜底策略", [ "🚀 节点选择", "🎯 全球直连" ] ), /* * ======================================================== * 全球直连 * ======================================================== */ createSelectGroup( "🎯 全球直连", [ "DIRECT" ] ) ]; /* ========================================================== * 22. 写入最终配置 * ========================================================== */ Object.assign( config, generalConfig ); config["sniffer"] = snifferConfig; config["tun"] = tunConfig; config["dns"] = dnsConfig; config["proxy-groups"] = proxyGroups; config["rule-providers"] = ruleProviders; config["rules"] = rules; /* ========================================================== * 23. 返回 * ========================================================== */ return config; }