Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[routing] Add custom blocking & bypass sites routing rules #445

Open
wants to merge 2 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 77 additions & 20 deletions _worker.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

105 changes: 84 additions & 21 deletions src/worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -1227,6 +1227,8 @@ async function updateDataset (env, newSettings, resetSettings) {
customCdnHost: validateField('customCdnHost')?.trim() ?? currentSettings?.customCdnHost ?? '',
customCdnSni: validateField('customCdnSni')?.trim() ?? currentSettings?.customCdnSni ?? '',
bestVLESSTrojanInterval: validateField('bestVLESSTrojanInterval') ?? currentSettings?.bestVLESSTrojanInterval ?? '30',
customRuleBlockSites: validateField("customRuleBlockSites")?.trim() ?? currentSettings?.customRuleBlockSites ?? "",
customRuleBypassSites: validateField("customRuleBypassSites")?.trim() ?? currentSettings?.customRuleBypassSites ?? "",
vlessConfigs: validateField('vlessConfigs') ?? currentSettings?.vlessConfigs ?? true,
trojanConfigs: validateField('trojanConfigs') ?? currentSettings?.trojanConfigs ?? false,
ports: validateField('ports')?.split(',') ?? currentSettings?.ports ?? ['443'],
Expand Down Expand Up @@ -1373,6 +1375,8 @@ function renderHomePage (request, proxySettings, hostName, isPassSet) {
customCdnHost,
customCdnSni,
bestVLESSTrojanInterval,
customRuleBlockSites,
customRuleBypassSites,
vlessConfigs,
trojanConfigs,
ports,
Expand Down Expand Up @@ -1791,6 +1795,14 @@ function renderHomePage (request, proxySettings, hostName, isPassSet) {
<label for="bestVLESSTrojanInterval">🔄 Best Interval</label>
<input type="number" id="bestVLESSTrojanInterval" name="bestVLESSTrojanInterval" min="10" max="90" value="${bestVLESSTrojanInterval}">
</div>
<div class="form-control">
<label for="customRuleBlockSites">🟠 Custom Rules: Block Sites</label>
<input type="text" id="customRuleBlockSites" name="customRuleBlockSites" value="${customRuleBlockSites}">
</div>
<div class="form-control">
<label for="customRuleBypassSites">🟢 Custom Rules: Bypass Sites</label>
<input type="text" id="customRuleBypassSites" name="customRuleBypassSites" value="${customRuleBypassSites}">
</div>
<div class="form-control" style="padding-top: 10px;">
<label for="vlessConfigs">⚙️ Protocols</label>
<div style="width: 100%; display: grid; grid-template-columns: 1fr 1fr; align-items: baseline; margin-top: 10px;">
Expand Down Expand Up @@ -2694,6 +2706,8 @@ function renderHomePage (request, proxySettings, hostName, isPassSet) {
const customCdnHost = document.getElementById('customCdnHost').value;
const customCdnSni = document.getElementById('customCdnSni').value;
const isCustomCdn = customCdnAddrs.length > 0 || customCdnHost !== '' || customCdnSni !== '';
const customRuleBlockSites = document.getElementById('customRuleBlockSites').value?.split(',').filter(addr => addr !== '');
const customRuleBypassSites = document.getElementById('customRuleBypassSites').value?.split(',').filter(addr => addr !== '');
const warpEndpoints = document.getElementById('warpEndpoints').value?.replaceAll(' ', '').split(',');
const noiseCountMin = getValue('noiseCountMin');
const noiseCountMax = getValue('noiseCountMax');
Expand Down Expand Up @@ -3290,7 +3304,9 @@ function buildXrayRoutingRules (proxySettings, outboundAddrs, isChain, isBalance
bypassRussia,
blockAds,
blockPorn,
blockUDP443
blockUDP443,
customRuleBlockSites,
customRuleBypassSites
} = proxySettings;

const isBlock = blockAds || blockPorn;
Expand Down Expand Up @@ -3331,33 +3347,51 @@ function buildXrayRoutingRules (proxySettings, outboundAddrs, isChain, isBalance
type: "field"
});

if (isBypass || isBlock) {
if (isBypass || isBlock || customRuleBlockSites || customRuleBypassSites) {
const createRule = (type, outbound) => ({
[type]: [],
outboundTag: outbound,
type: "field"
});

let geositeDirectRule, geoipDirectRule;
if (!isWorkerLess) {
geositeDirectRule = createRule("domain", "direct");
geoipDirectRule = createRule("ip", "direct");
if (customRuleBlockSites) {
let customSiteBlockRule = createRule("domain", "block");
customRuleBlockSites.split(",").forEach(
domainName => customSiteBlockRule.domain.push(domainName.trim())
);
rules.push(customSiteBlockRule);
}

let geositeBlockRule = createRule("domain", "block");
geoRules.forEach(({ rule, type, domain, ip }) => {
if (rule) {
if (type === 'direct') {
geositeDirectRule?.domain.push(domain);
geoipDirectRule?.ip?.push(ip);
} else {
geositeBlockRule.domain.push(domain);
}
if (customRuleBypassSites) {
let customSiteBypassRule = createRule("domain", "direct");
customRuleBypassSites.split(",").forEach(
domainName => customSiteBypassRule.domain.push(domainName.trim())
);
rules.push(customSiteBypassRule);
}

if (isBypass || isBlock) {
let geositeDirectRule, geoipDirectRule;
if (!isWorkerLess) {
geositeDirectRule = createRule("domain", "direct");
geoipDirectRule = createRule("ip", "direct");
}
});

!isWorkerLess && isBypass && rules.push(geositeDirectRule, geoipDirectRule);
isBlock && rules.push(geositeBlockRule);

let geositeBlockRule = createRule("domain", "block");
geoRules.forEach(({ rule, type, domain, ip }) => {
if (rule) {
if (type === 'direct') {
geositeDirectRule?.domain.push(domain);
geoipDirectRule?.ip?.push(ip);
} else {
geositeBlockRule.domain.push(domain);
}
}
});

!isWorkerLess && isBypass && rules.push(geositeDirectRule, geoipDirectRule);
isBlock && rules.push(geositeBlockRule);
}
}

blockUDP443 && rules.push({
Expand Down Expand Up @@ -4007,11 +4041,26 @@ function buildClashRoutingRules (proxySettings) {
bypassRussia,
blockAds,
blockPorn,
blockUDP443
blockUDP443,
customRuleBlockSites,
customRuleBypassSites
} = proxySettings;

const isBypass = bypassIran || bypassChina || bypassLAN || bypassRussia;
const isBlock = blockAds || blockPorn;

let customSiteBlockRules = [], customSiteBypassRules = [];
if (customRuleBlockSites) {
customRuleBlockSites.split(",").forEach(
domainName => customSiteBlockRules.push(`DOMAIN-SUFFIX,${domainName},REJECT`)
);
}
if (customRuleBypassSites) {
customRuleBypassSites.split(",").forEach(
domainName => customSiteBypassRules.push(`DOMAIN-SUFFIX,${domainName},DIRECT`)
);
}

let geositeDirectRules = [], geoipDirectRules = [], geositeBlockRules = [];
const geoRules = [
{ rule: bypassLAN, type: 'direct', geosite: "private", geoip: "private" },
Expand All @@ -4038,6 +4087,8 @@ function buildClashRoutingRules (proxySettings) {

let rules = [
`AND,((IP-CIDR,${localDNS}/32),(DST-PORT,53)),DIRECT`,
...customSiteBlockRules,
...customSiteBypassRules,
...geositeDirectRules,
...geoipDirectRules,
...geositeBlockRules
Expand Down Expand Up @@ -4478,7 +4529,9 @@ function buildSingBoxRoutingRules (proxySettings) {
bypassRussia,
blockAds,
blockPorn,
blockUDP443
blockUDP443,
customRuleBlockSites,
customRuleBypassSites
} = proxySettings;

const isBypass = bypassIran || bypassChina || bypassRussia;
Expand Down Expand Up @@ -4588,6 +4641,16 @@ function buildSingBoxRoutingRules (proxySettings) {
outbound: "direct"
});

customRuleBlockSites && rules.push({
domain_suffix: customRuleBlockSites.split(',').map(item => item.trim()),
outbound: "block"
});

customRuleBypassSites && rules.push({
domain_suffix: customRuleBypassSites.split(',').map(item => item.trim()),
outbound: "direct"
});

const createRule = (outbound) => ({
rule_set: [],
outbound
Expand Down