Skip to content

Commit

Permalink
Feat: sukka_local_dns_mapping.sgmodule now uses new rule-set syntax
Browse files Browse the repository at this point in the history
  • Loading branch information
SukkaW committed Jan 17, 2025
1 parent 8d5da97 commit 6858cd6
Show file tree
Hide file tree
Showing 6 changed files with 119 additions and 52 deletions.
76 changes: 58 additions & 18 deletions Build/build-domestic-direct-lan-ruleset-dns-mapping-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { SHARED_DESCRIPTION } from './constants/description';
import { createMemoizedPromise } from './lib/memo-promise';
import * as yaml from 'yaml';
import { appendArrayInPlace } from './lib/append-array-in-place';
import { OUTPUT_INTERNAL_DIR, OUTPUT_MODULES_DIR, SOURCE_DIR } from './constants/dir';
import { OUTPUT_INTERNAL_DIR, OUTPUT_MODULES_DIR, OUTPUT_MODULES_RULES_DIR, SOURCE_DIR } from './constants/dir';
import { RulesetOutput } from './lib/create-file';

export function createGetDnsMappingRule(allowWildcard: boolean) {
Expand Down Expand Up @@ -78,7 +78,7 @@ export const getDomesticAndDirectDomainsRulesetPromise = createMemoizedPromise(a
export const buildDomesticRuleset = task(require.main === module, __filename)(async (span) => {
const [domestics, directs, lans] = await getDomesticAndDirectDomainsRulesetPromise();

const dataset: DNSMapping[] = ([DOH_BOOTSTRAP, DOMESTICS, DIRECTS] as const).flatMap(Object.values);
const dataset: Array<[name: string, DNSMapping]> = ([DOH_BOOTSTRAP, DOMESTICS, DIRECTS, LAN] as const).flatMap(Object.entries);

return Promise.all([
new RulesetOutput(span, 'domestic', 'non_ip')
Expand Down Expand Up @@ -108,6 +108,41 @@ export const buildDomesticRuleset = task(require.main === module, __filename)(as
])
.addFromRuleset(lans)
.write(),

...dataset.map(([name, { ruleset, domains }]) => {
if (!ruleset) {
return;
}

const output = new RulesetOutput(span, name.toLowerCase(), 'sukka_local_dns_mapping').withTitle(`Sukka's Ruleset - Local DNS Mapping (${name})`).withDescription([
...SHARED_DESCRIPTION,
'',
'This is an internal rule that is only referenced by sukka_local_dns_mapping.sgmodule',
'Do not use this file in your Rule section, all rules are included in non_ip/domestic.conf already.'
]);

domains.forEach((domain) => {
switch (domain[0]) {
case '$':
output.addDomain(domain.slice(1));
break;
case '+':
output.addDomainSuffix(domain.slice(1));
break;
default:
output.addDomainSuffix(domain);
break;
}
});

return output.write({
surge: true,
clash: false,
singbox: false,
surgeDir: OUTPUT_MODULES_RULES_DIR
});
}),

compareAndWriteFile(
span,
[
Expand All @@ -119,26 +154,31 @@ export const buildDomesticRuleset = task(require.main === module, __filename)(as
// I use an object to deduplicate the domains
// Otherwise I could just construct an array directly
dataset.reduce<Record<string, string>>((acc, cur) => {
const { domains, dns, hosts } = cur;
const ruleset_name = cur[0].toLowerCase();
const { domains, dns, hosts, ruleset } = cur[1];

Object.entries(hosts).forEach(([dns, ips]) => {
acc[dns] ||= ips.join(', ');
});

domains.forEach((domain) => {
switch (domain[0]) {
case '$':
acc[domain.slice(1)] ||= `server:${dns}`;
break;
case '+':
acc[`*.${domain.slice(1)}`] ||= `server:${dns}`;
break;
default:
acc[domain] ||= `server:${dns}`;
acc[`*.${domain}`] ||= `server:${dns}`;
break;
}
});
if (ruleset) {
acc[`RULE-SET:https://ruleset.skk.moe/Modules/Rules/sukka_local_dns_mapping/${ruleset_name}.conf`] ||= `server:${dns}`;
} else {
domains.forEach((domain) => {
switch (domain[0]) {
case '$':
acc[domain.slice(1)] ||= `server:${dns}`;
break;
case '+':
acc[`*.${domain.slice(1)}`] ||= `server:${dns}`;
break;
default:
acc[domain] ||= `server:${dns}`;
acc[`*.${domain}`] ||= `server:${dns}`;
break;
}
});
}

return acc;
}, {})
Expand All @@ -153,7 +193,7 @@ export const buildDomesticRuleset = task(require.main === module, __filename)(as
dns: { 'nameserver-policy': Record<string, string | string[]> },
hosts: Record<string, string>
}>((acc, cur) => {
const { domains, dns, ...rest } = cur;
const { domains, dns, ...rest } = cur[1];
domains.forEach((domain) => {
let domainWildcard = domain;
if (domain[0] === '$') {
Expand Down
1 change: 1 addition & 0 deletions Build/constants/dir.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@ export const OUTPUT_SURGE_DIR = path.join(PUBLIC_DIR, 'List');
export const OUTPUT_CLASH_DIR = path.resolve(PUBLIC_DIR, 'Clash');
export const OUTPUT_SINGBOX_DIR = path.resolve(PUBLIC_DIR, 'sing-box');
export const OUTPUT_MODULES_DIR = path.resolve(PUBLIC_DIR, 'Modules');
export const OUTPUT_MODULES_RULES_DIR = path.resolve(OUTPUT_MODULES_DIR, 'Rules');
export const OUTPUT_INTERNAL_DIR = path.resolve(PUBLIC_DIR, 'Internal');
export const OUTPUT_MOCK_DIR = path.resolve(PUBLIC_DIR, 'Mock');
46 changes: 33 additions & 13 deletions Build/lib/rules/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export abstract class RuleOutput<TPreprocessed = unknown> {
protected destPort = new Set<string>();

protected otherRules: string[] = [];
protected abstract type: 'domainset' | 'non_ip' | 'ip';
protected abstract type: 'domainset' | 'non_ip' | 'ip' | (string & {});

private pendingPromise: Promise<any> | null = null;

Expand Down Expand Up @@ -295,38 +295,58 @@ export abstract class RuleOutput<TPreprocessed = unknown> {
);
}

write(): Promise<void> {
write({
surge = true,
clash = true,
singbox = true,
surgeDir = OUTPUT_SURGE_DIR,
clashDir = OUTPUT_CLASH_DIR,
singboxDir = OUTPUT_SINGBOX_DIR
}: {
surge?: boolean,
clash?: boolean,
singbox?: boolean,
surgeDir?: string,
clashDir?: string,
singboxDir?: string
} = {}): Promise<void> {
return this.done().then(() => this.span.traceChildAsync('write all', async () => {
invariant(this.title, 'Missing title');
invariant(this.description, 'Missing description');

const promises = [
compareAndWriteFile(
const promises: Array<Promise<void>> = [];

if (surge) {
promises.push(compareAndWriteFile(
this.span,
withBannerArray(
this.title,
this.description,
this.date,
this.surge()
),
path.join(OUTPUT_SURGE_DIR, this.type, this.id + '.conf')
),
compareAndWriteFile(
path.join(surgeDir, this.type, this.id + '.conf')
));
}
if (clash) {
promises.push(compareAndWriteFile(
this.span,
withBannerArray(
this.title,
this.description,
this.date,
this.clash()
),
path.join(OUTPUT_CLASH_DIR, this.type, this.id + '.txt')
),
compareAndWriteFile(
path.join(clashDir, this.type, this.id + '.txt')
));
}
if (singbox) {
promises.push(compareAndWriteFile(
this.span,
this.singbox(),
path.join(OUTPUT_SINGBOX_DIR, this.type, this.id + '.json')
)
];
path.join(singboxDir, this.type, this.id + '.json')
));
}

if (this.mitmSgmodule) {
const sgmodule = this.mitmSgmodule();
Expand Down
2 changes: 1 addition & 1 deletion Build/lib/rules/ruleset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { isProbablyIpv4, isProbablyIpv6 } from 'foxts/is-probably-ip';
type Preprocessed = [domain: string[], domainSuffix: string[], sortedDomainRules: string[]];

export class RulesetOutput extends RuleOutput<Preprocessed> {
constructor(span: Span, id: string, protected type: 'non_ip' | 'ip') {
constructor(span: Span, id: string, protected type: 'non_ip' | 'ip' | (string & {})) {
super(span, id);
}

Expand Down
6 changes: 6 additions & 0 deletions Source/non_ip/direct.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ export interface DNSMapping {
},
/** which also disallows wildcard */
realip: boolean,
/** should convert to ruleset */
ruleset: boolean,
dns: string,
/**
* domain[0]
Expand All @@ -20,6 +22,7 @@ export const DIRECTS = {
dns: 'system',
hosts: {},
realip: false,
ruleset: false,
domains: [
'securelogin.com.cn',
'$captive.apple.com',
Expand All @@ -30,6 +33,7 @@ export const DIRECTS = {
dns: 'system',
hosts: {},
realip: true,
ruleset: false,
domains: [
'+m2m',
// '+ts.net', // TailScale Magic DNS
Expand All @@ -47,6 +51,7 @@ export const LAN = {
dns: 'system',
hosts: {},
realip: false,
ruleset: true,
domains: [
'+home',
// 'zte.home', // ZTE CPE
Expand Down Expand Up @@ -106,6 +111,7 @@ export const LAN = {
localhost: ['127.0.0.1']
},
realip: true,
ruleset: true,
domains: [
'+lan',
// 'amplifi.lan',
Expand Down
40 changes: 20 additions & 20 deletions Source/non_ip/domestic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export const DOMESTICS: Record<string, DNSMapping> = {
hosts: {},
dns: 'quic://dns.alidns.com:853',
realip: false,
ruleset: true,
domains: [
'uc.cn',
// 'ucweb.com', // UC International
Expand Down Expand Up @@ -82,13 +83,18 @@ export const DOMESTICS: Record<string, DNSMapping> = {
'tanx.com',
'hellobike.com',
'+hichina.com',
'+yunos.com'
'+yunos.com',

// Bilibili Aliyun CDN
'$upos-sz-mirrorali.bilivideo.com',
'$upos-sz-estgoss.bilivideo.com'
]
},
TENCENT: {
hosts: {},
dns: 'https://doh.pub/dns-query',
realip: false,
ruleset: true,
domains: [
// 'dns.pub',
// 'doh.pub',
Expand Down Expand Up @@ -144,28 +150,11 @@ export const DOMESTICS: Record<string, DNSMapping> = {
'+codehub.cn'
]
},
BILIBILI_ALI: {
dns: 'quic://dns.alidns.com:853',
hosts: {},
realip: false,
domains: [
'$upos-sz-mirrorali.bilivideo.com',
'$upos-sz-estgoss.bilivideo.com'
]
},
BILIBILI_BD: {
dns: '180.76.76.76',
hosts: {},
realip: false,
domains: [
'$upos-sz-mirrorbd.bilivideo.com',
'$upos-sz-mirrorbos.bilivideo.com'
]
},
BILIBILI: {
dns: 'https://doh.pub/dns-query',
hosts: {},
realip: false,
ruleset: true,
domains: [
// '$upos-sz-mirrorcoso1.bilivideo.com', // already included in bilivideo.com
// '$upos-sz-estgcos.bilivideo.com', // already included in bilivideo.com, tencent cloud cdn
Expand Down Expand Up @@ -196,6 +185,7 @@ export const DOMESTICS: Record<string, DNSMapping> = {
dns: 'https://doh.pub/dns-query',
hosts: {},
realip: false,
ruleset: true,
domains: [
'mi.com',
'duokan.com',
Expand All @@ -218,6 +208,7 @@ export const DOMESTICS: Record<string, DNSMapping> = {
dns: '180.184.2.2',
hosts: {},
realip: false,
ruleset: true,
domains: [
'bytedance.com',
'+bytecdn.cn',
Expand Down Expand Up @@ -271,6 +262,7 @@ export const DOMESTICS: Record<string, DNSMapping> = {
dns: '180.76.76.76',
hosts: {},
realip: false,
ruleset: true,
domains: [
'91.com',
'hao123.com',
Expand All @@ -295,13 +287,18 @@ export const DOMESTICS: Record<string, DNSMapping> = {
'+bdydns.com',
'+jomoxc.com', // Baidu PCDN, of sort
'+duapp.com',
'+antpcdn.com' // Baidu PCDN
'+antpcdn.com', // Baidu PCDN

// Bilibili Baidu CDN
'$upos-sz-mirrorbd.bilivideo.com',
'$upos-sz-mirrorbos.bilivideo.com'
]
},
QIHOO360: {
hosts: {},
dns: 'https://doh.360.cn/dns-query',
realip: false,
ruleset: true,
domains: [
'+qhimg.com',
'+qhimgs.com',
Expand Down Expand Up @@ -350,6 +347,7 @@ export const DOH_BOOTSTRAP: Record<string, DNSMapping> = {
'dns.alidns.com': ['223.5.5.5', '223.6.6.6', '2400:3200:baba::1', '2400:3200::1']
},
realip: false,
ruleset: false,
dns: 'quic://223.5.5.5:853',
domains: [
'$dns.alidns.com'
Expand All @@ -362,6 +360,7 @@ export const DOH_BOOTSTRAP: Record<string, DNSMapping> = {
// 'dns.pub': ['120.53.53.53', '1.12.12.12']
},
realip: false,
ruleset: false,
dns: 'https://1.12.12.12/dns-query',
domains: [
// '$dot.pub',
Expand All @@ -382,6 +381,7 @@ export const DOH_BOOTSTRAP: Record<string, DNSMapping> = {
// dot.360.net CNAME dns.360.net
},
realip: false,
ruleset: false,
// Surge only supports UDP 53 or Hosts as the bootstrap server of domain DoH
dns: '101.198.198.198', // 'https://101.198.198.198/dns-query', // https://101.198.199.200/dns-query
domains: [
Expand Down

0 comments on commit 6858cd6

Please sign in to comment.