Files
rule-providers/Clash/Android_clash.js
T
2026-08-24 00:27:44 +08:00

1498 lines
26 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* ============================================================
* 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;
}