diff --git a/Build/build-cloudmounter-rules.ts b/Build/build-cloudmounter-rules.ts index e741c4c2..ce2ebea3 100644 --- a/Build/build-cloudmounter-rules.ts +++ b/Build/build-cloudmounter-rules.ts @@ -19,7 +19,7 @@ export const buildCloudMounterRules = task(require.main === module, __filename)( '127.0.0.0/8', '172.16.0.0/12', '192.168.0.0/16' - ].map(cidr => `AND,((${domain}),(SRC-IP-CIDR,${cidr}))`) + ].map(cidr => `AND,((${domain}),(SRC-IP,${cidr}))`) ]); }); diff --git a/Build/lib/clash.ts b/Build/lib/clash.ts index 72e16757..e86d609a 100644 --- a/Build/lib/clash.ts +++ b/Build/lib/clash.ts @@ -1,5 +1,6 @@ import picocolors from 'picocolors'; import { domainWildCardToRegex } from './misc'; +import { isProbablyIpv4, isProbablyIpv6 } from './is-fast-ip'; const identity = (x: T): T => x; const unsupported = Symbol('unsupported'); @@ -14,6 +15,18 @@ const PROCESSOR: Record s 'IP-CIDR': identity, 'IP-CIDR6': identity, 'IP-ASN': identity, + 'SRC-IP': (_raw, _type, value) => { + if (value.includes('/')) { + return `SRC-IP-CIDR,${value}`; + } + if (isProbablyIpv4(value)) { + return `SRC-IP-CIDR,${value}/32`; + } + if (isProbablyIpv6(value)) { + return `SRC-IP-CIDR6,${value}/128`; + } + return ''; + }, 'SRC-IP-CIDR': identity, 'SRC-PORT': identity, 'DST-PORT': identity, diff --git a/Build/lib/singbox.ts b/Build/lib/singbox.ts index fcd5dc30..52551421 100644 --- a/Build/lib/singbox.ts +++ b/Build/lib/singbox.ts @@ -1,10 +1,11 @@ import picocolors from 'picocolors'; import { domainWildCardToRegex } from './misc'; +import { isProbablyIpv4, isProbablyIpv6 } from './is-fast-ip'; const unsupported = Symbol('unsupported'); // https://sing-box.sagernet.org/configuration/rule-set/source-format/ -const PROCESSOR: Record [key: keyof SingboxHeadlessRule, value: string]) | typeof unsupported> = { +const PROCESSOR: Record [key: keyof SingboxHeadlessRule, value: string] | null) | typeof unsupported> = { DOMAIN: (_1, _2, value) => ['domain', value], 'DOMAIN-SUFFIX': (_1, _2, value) => ['domain_suffix', value], 'DOMAIN-KEYWORD': (_1, _2, value) => ['domain_keyword', value], @@ -13,6 +14,18 @@ const PROCESSOR: Record [ 'IP-CIDR': (_1, _2, value) => ['ip_cidr', value.endsWith(',no-resolve') ? value.slice(0, -11) : value], 'IP-CIDR6': (_1, _2, value) => ['ip_cidr', value.endsWith(',no-resolve') ? value.slice(0, -11) : value], 'IP-ASN': unsupported, + 'SRC-IP': (_1, _2, value) => { + if (value.includes('/')) { + return ['source_ip_cidr', value]; + } + if (isProbablyIpv4(value)) { + return ['source_ip_cidr', value + '/32']; + } + if (isProbablyIpv6(value)) { + return ['source_ip_cidr', value + '/128']; + } + return null; + }, 'SRC-IP-CIDR': (_1, _2, value) => ['source_ip_cidr', value.endsWith(',no-resolve') ? value.slice(0, -11) : value], 'SRC-PORT': (_1, _2, value) => ['source_port', value], 'DST-PORT': (_1, _2, value) => ['port', value], @@ -63,9 +76,12 @@ export const surgeRulesetToSingbox = (rules: string[] | Set): SingboxSou if (type in PROCESSOR) { const proc = PROCESSOR[type]; if (proc !== unsupported) { - const [k, v] = proc(cur, type, value); - acc[k] ||= []; - acc[k].push(v); + const r = proc(cur, type, value); + if (r) { + const [k, v] = r; + acc[k] ||= []; + acc[k].push(v); + } } } else { console.log(picocolors.yellow(`[sing-box] unknown rule type: ${type}`), cur);