Feat: support wildcard from adguard filter

This commit is contained in:
SukkaW 2025-06-20 17:28:09 +08:00
parent 515f262042
commit 6da1069147
11 changed files with 230 additions and 77 deletions

View File

@ -50,11 +50,11 @@ export const buildRejectDomainSet = task(require.main === module, __filename)(as
...ADGUARD_FILTERS.map(filter => ` - ${Array.isArray(filter) ? filter[0] : filter}`)
];
const rejectOutput = new DomainsetOutput(span, 'reject')
const rejectDomainsetOutput = new DomainsetOutput(span, 'reject')
.withTitle('Sukka\'s Ruleset - Reject Base')
.withDescription(rejectBaseDescription);
const rejectExtraOutput = new DomainsetOutput(span, 'reject_extra')
const rejectExtraDomainsetOutput = new DomainsetOutput(span, 'reject_extra')
.withTitle('Sukka\'s Ruleset - Reject Extra')
.withDescription([
...SHARED_DESCRIPTION,
@ -67,7 +67,7 @@ export const buildRejectDomainSet = task(require.main === module, __filename)(as
...ADGUARD_FILTERS_EXTRA.map(filter => ` - ${filter[0]}`)
]);
const rejectPhisingOutput = new DomainsetOutput(span, 'reject_phishing')
const rejectPhisingDomainsetOutput = new DomainsetOutput(span, 'reject_phishing')
.withTitle('Sukka\'s Ruleset - Reject Phishing')
.withDescription([
...SHARED_DESCRIPTION,
@ -79,6 +79,16 @@ export const buildRejectDomainSet = task(require.main === module, __filename)(as
...PHISHING_DOMAIN_LISTS_EXTRA.map(domainList => ` - ${domainList[0]}`)
]);
const rejectNonIpRulesetOutput = new RulesetOutput(span, 'reject', 'non_ip')
.withTitle('Sukka\'s Ruleset - Reject Non-IP')
.withDescription([
...SHARED_DESCRIPTION,
'',
'The ruleset supports AD blocking, tracking protection, privacy protection, anti-phishing, anti-mining',
'',
'The file contains wildcard domains from data source mentioned in /domainset/reject file'
]);
const rejectIPOutput = new RulesetOutput(span, 'reject', 'ip')
.withTitle('Sukka\'s Ruleset - Anti Bogus Domain')
.withDescription([
@ -98,22 +108,25 @@ export const buildRejectDomainSet = task(require.main === module, __filename)(as
// Collect DOMAIN, DOMAIN-SUFFIX, and DOMAIN-KEYWORD from non_ip/reject.conf for deduplication
// DOMAIN-WILDCARD is not really useful for deduplication, it is only included in AdGuardHome output
// It is faster to add base than add others first then whitelist
rejectOutput.addFromRuleset(readLocalRejectRulesetPromise);
rejectExtraOutput.addFromRuleset(readLocalRejectRulesetPromise);
rejectDomainsetOutput.addFromRuleset(readLocalRejectRulesetPromise);
rejectExtraDomainsetOutput.addFromRuleset(readLocalRejectRulesetPromise);
rejectOutput.addFromDomainset(readLocalRejectDomainsetPromise);
rejectExtraOutput.addFromDomainset(readLocalRejectDomainsetPromise);
rejectPhisingOutput.addFromDomainset(readLocalRejectDomainsetPromise);
rejectNonIpRulesetOutput.addFromRuleset(readLocalRejectRulesetPromise);
rejectExtraOutput.addFromDomainset(readLocalRejectExtraDomainsetPromise);
rejectDomainsetOutput.addFromDomainset(readLocalRejectDomainsetPromise);
rejectExtraDomainsetOutput.addFromDomainset(readLocalRejectDomainsetPromise);
rejectPhisingDomainsetOutput.addFromDomainset(readLocalRejectDomainsetPromise);
rejectExtraDomainsetOutput.addFromDomainset(readLocalRejectExtraDomainsetPromise);
rejectIPOutput.addFromRuleset(readLocalRejectIpListPromise);
const appendArrayToRejectOutput = (source: MaybePromise<AsyncIterable<string> | Iterable<string> | string[]>) => rejectOutput.addFromDomainset(source);
const appendArrayToRejectExtraOutput = (source: MaybePromise<AsyncIterable<string> | Iterable<string> | string[]>) => rejectExtraOutput.addFromDomainset(source);
const appendArrayToRejectOutput = (source: MaybePromise<AsyncIterable<string> | Iterable<string> | string[]>) => rejectDomainsetOutput.addFromDomainset(source);
const appendArrayToRejectExtraOutput = (source: MaybePromise<AsyncIterable<string> | Iterable<string> | string[]>) => rejectExtraDomainsetOutput.addFromDomainset(source);
/** Whitelists */
const filterRuleWhitelistDomainSets = new Set(PREDEFINED_WHITELIST);
const filterRuleWhiteKeywords = new Set<string>();
// Parse from AdGuard Filters
await span
@ -127,34 +140,49 @@ export const buildRejectDomainSet = task(require.main === module, __filename)(as
domainListsDownloads.map(task => task(childSpan).then(appendArrayToRejectOutput)),
domainListsExtraDownloads.map(task => task(childSpan).then(appendArrayToRejectExtraOutput)),
rejectPhisingOutput.addFromDomainset(getPhishingDomains(childSpan)),
rejectPhisingDomainsetOutput.addFromDomainset(getPhishingDomains(childSpan)),
adguardFiltersDownloads.map(
task => task(childSpan).then(({ whiteDomains, whiteDomainSuffixes, blackDomains, blackDomainSuffixes, blackIPs }) => {
task => task(childSpan).then(({ whiteDomains, whiteDomainSuffixes, blackDomains, blackDomainSuffixes, blackIPs, blackWildcard, whiteKeyword, blackKeyword }) => {
addArrayElementsToSet(filterRuleWhitelistDomainSets, whiteDomains);
addArrayElementsToSet(filterRuleWhitelistDomainSets, whiteDomainSuffixes, suffix => '.' + suffix);
rejectOutput.bulkAddDomain(blackDomains);
rejectOutput.bulkAddDomainSuffix(blackDomainSuffixes);
addArrayElementsToSet(filterRuleWhiteKeywords, whiteKeyword);
rejectDomainsetOutput.bulkAddDomain(blackDomains);
rejectDomainsetOutput.bulkAddDomainSuffix(blackDomainSuffixes);
rejectDomainsetOutput.bulkAddDomainKeyword(blackKeyword);
rejectNonIpRulesetOutput.bulkAddDomainWildcard(blackWildcard);
rejectIPOutput.bulkAddAnyCIDR(blackIPs, false);
})
),
adguardFiltersExtraDownloads.map(
task => task(childSpan).then(({ whiteDomains, whiteDomainSuffixes, blackDomains, blackDomainSuffixes, blackIPs }) => {
task => task(childSpan).then(({ whiteDomains, whiteDomainSuffixes, blackDomains, blackDomainSuffixes, blackIPs, blackWildcard, whiteKeyword, blackKeyword }) => {
addArrayElementsToSet(filterRuleWhitelistDomainSets, whiteDomains);
addArrayElementsToSet(filterRuleWhitelistDomainSets, whiteDomainSuffixes, suffix => '.' + suffix);
addArrayElementsToSet(filterRuleWhiteKeywords, whiteKeyword);
rejectExtraDomainsetOutput.bulkAddDomain(blackDomains);
rejectExtraDomainsetOutput.bulkAddDomainSuffix(blackDomainSuffixes);
rejectExtraDomainsetOutput.bulkAddDomainKeyword(blackKeyword);
rejectExtraOutput.bulkAddDomain(blackDomains);
rejectExtraOutput.bulkAddDomainSuffix(blackDomainSuffixes);
rejectIPOutput.bulkAddAnyCIDR(blackIPs, false);
rejectNonIpRulesetOutput.bulkAddDomainWildcard(blackWildcard);
})
),
adguardFiltersWhitelistsDownloads.map(
task => task(childSpan).then(({ whiteDomains, whiteDomainSuffixes, blackDomains, blackDomainSuffixes }) => {
task => task(childSpan).then(({ whiteDomains, whiteDomainSuffixes, blackDomains, blackDomainSuffixes, whiteKeyword, blackKeyword }) => {
addArrayElementsToSet(filterRuleWhitelistDomainSets, whiteDomains);
addArrayElementsToSet(filterRuleWhitelistDomainSets, whiteDomainSuffixes, suffix => '.' + suffix);
addArrayElementsToSet(filterRuleWhitelistDomainSets, blackDomains);
addArrayElementsToSet(filterRuleWhitelistDomainSets, blackDomainSuffixes, suffix => '.' + suffix);
addArrayElementsToSet(filterRuleWhiteKeywords, whiteKeyword);
addArrayElementsToSet(filterRuleWhiteKeywords, blackKeyword);
})
),
@ -185,29 +213,45 @@ export const buildRejectDomainSet = task(require.main === module, __filename)(as
}
await Promise.all([
rejectOutput.done(),
rejectExtraOutput.done(),
rejectPhisingOutput.done(),
rejectIPOutput.done()
rejectDomainsetOutput.done(),
rejectExtraDomainsetOutput.done(),
rejectPhisingDomainsetOutput.done(),
rejectIPOutput.done(),
rejectNonIpRulesetOutput.done()
]);
// whitelist
span.traceChildSync('whitelist', () => {
for (const domain of filterRuleWhitelistDomainSets) {
rejectOutput.whitelistDomain(domain);
rejectExtraOutput.whitelistDomain(domain);
rejectPhisingOutput.whitelistDomain(domain);
rejectDomainsetOutput.whitelistDomain(domain);
rejectExtraDomainsetOutput.whitelistDomain(domain);
rejectPhisingDomainsetOutput.whitelistDomain(domain);
rejectNonIpRulesetOutput.whitelistDomain(domain);
}
rejectOutput.domainTrie.dump(arg => rejectExtraOutput.whitelistDomain(arg));
rejectOutput.domainTrie.dump(arg => rejectPhisingOutput.whitelistDomain(arg));
// we use "whitelistKeyword" method, this will be used to create kwfilter internally
for (const keyword of filterRuleWhiteKeywords) {
rejectDomainsetOutput.whitelistKeyword(keyword);
rejectExtraDomainsetOutput.whitelistKeyword(keyword);
rejectPhisingDomainsetOutput.whitelistKeyword(keyword);
rejectNonIpRulesetOutput.whitelistKeyword(keyword);
}
rejectDomainsetOutput.domainTrie.dump(arg => {
rejectExtraDomainsetOutput.whitelistDomain(arg);
rejectPhisingDomainsetOutput.whitelistDomain(arg);
// e.g. .data.microsort.com can strip waston*.event.data.microsort.com
rejectNonIpRulesetOutput.wildcardTrie.whitelist(arg);
});
});
await Promise.all([
rejectOutput.write(),
rejectExtraOutput.write(),
rejectPhisingOutput.write(),
rejectIPOutput.write()
rejectDomainsetOutput.write(),
rejectExtraDomainsetOutput.write(),
rejectPhisingDomainsetOutput.write(),
rejectIPOutput.write(),
rejectNonIpRulesetOutput.write()
]);
// we are going to re-use rejectOutput's domainTrie and mutate it
@ -218,7 +262,7 @@ export const buildRejectDomainSet = task(require.main === module, __filename)(as
'The AdGuardHome ruleset supports AD blocking, tracking protection, privacy protection, anti-mining'
]);
rejectOutputAdGuardHome.domainTrie = rejectOutput.domainTrie;
rejectOutputAdGuardHome.domainTrie = rejectDomainsetOutput.domainTrie;
await rejectOutputAdGuardHome
// .addFromRuleset(readLocalMyRejectRulesetPromise)

View File

@ -15,6 +15,9 @@ const enum ParseType {
BlackIncludeSubdomain = 2,
ErrorMessage = 10,
BlackIP = 20,
BlackWildcard = 30,
BlackKeyword = 40,
WhiteKeyword = 50,
Null = 1000,
NotParsed = 2000
}
@ -28,7 +31,19 @@ export function processFilterRulesWithPreload(
) {
const downloadPromise = fetchAssets(filterRulesUrl, fallbackUrls);
return (span: Span) => span.traceChildAsync<Record<'whiteDomains' | 'whiteDomainSuffixes' | 'blackDomains' | 'blackDomainSuffixes' | 'blackIPs', string[]>>(`process filter rules: ${filterRulesUrl}`, async (span) => {
return (span: Span) => span.traceChildAsync<
Record<
'whiteDomains'
| 'whiteDomainSuffixes'
| 'blackDomains'
| 'blackDomainSuffixes'
| 'blackIPs'
| 'blackWildcard'
| 'whiteKeyword'
| 'blackKeyword',
string[]
>
>(`process filter rules: ${filterRulesUrl}`, async (span) => {
const filterRules = await span.traceChildPromise('download', downloadPromise);
const whiteDomains = new Set<string>();
@ -40,6 +55,10 @@ export function processFilterRulesWithPreload(
const warningMessages: string[] = [];
const blackIPs: string[] = [];
const blackWildcard = new Set<string>();
const whiteKeyword = new Set<string>();
const blackKeyword = new Set<string>();
const MUTABLE_PARSE_LINE_RESULT: [string, ParseType] = ['', ParseType.NotParsed];
/**
@ -83,6 +102,15 @@ export function processFilterRulesWithPreload(
case ParseType.BlackIP:
blackIPs.push(hostname);
break;
case ParseType.BlackWildcard:
blackWildcard.add(hostname);
break;
case ParseType.BlackKeyword:
blackKeyword.add(hostname);
break;
case ParseType.WhiteKeyword:
whiteKeyword.add(hostname);
break;
default:
break;
}
@ -113,7 +141,10 @@ export function processFilterRulesWithPreload(
whiteDomainSuffixes: Array.from(whiteDomainSuffixes),
blackDomains: Array.from(blackDomains),
blackDomainSuffixes: Array.from(blackDomainSuffixes),
blackIPs
blackIPs,
blackWildcard: Array.from(blackWildcard),
whiteKeyword: Array.from(whiteKeyword),
blackKeyword: Array.from(blackKeyword)
};
});
}
@ -482,6 +513,7 @@ export function parse($line: string, result: [string, ParseType], includeThirdPa
}
const parsed = tldts.parse(sliced, looseTldtsOpt);
const hostname = parsed.hostname;
/**
* We can exclude wildcard in TLD
@ -495,15 +527,21 @@ export function parse($line: string, result: [string, ParseType], includeThirdPa
*
* This also exclude non standard TLD like `.tor`, `.onion`, `.dn42`, etc.
*/
if (!parsed.publicSuffix || !parsed.isIcann || !parsed.hostname || !parsed.domain) {
if (!parsed.publicSuffix || !parsed.isIcann || !hostname || !parsed.domain) {
result[1] = ParseType.Null;
return result;
}
// no wildcard, we can safely normalize it˝
if (!parsed.hostname.includes('*')) {
if (!hostname.includes('*')) {
if (hostname.charCodeAt(0) === 45) { // 45 `-`
result[0] = hostname;
result[1] = white ? ParseType.WhiteKeyword : ParseType.BlackKeyword;
return result;
}
if (white) {
result[0] = parsed.hostname;
result[0] = hostname;
result[1] = includeAllSubDomain ? ParseType.WhiteIncludeSubdomain : ParseType.WhiteAbsolute;
return result;
}
@ -522,14 +560,46 @@ export function parse($line: string, result: [string, ParseType], includeThirdPa
}
}
result[0] = parsed.hostname;
result[0] = hostname;
result[1] = includeAllSubDomain ? ParseType.BlackIncludeSubdomain : ParseType.BlackAbsolute;
return result;
}
result[0] = `[parse-filter E0010] (${white ? 'white' : 'black'}) invalid domain: ${JSON.stringify({
line, sliced, sliceStart, sliceEnd, parsed
})}`;
result[1] = ParseType.ErrorMessage;
// now we only have wildcard domain left
if (white) {
// we don't support wildcard in whitelist
// result[1] = ParseType.Null;
// return result;
result[0] = `[parse-filter E0021] wildcard whitelist not supported: ${JSON.stringify({
line, sliced, sliceStart, sliceEnd, parsed
})}`;
result[1] = ParseType.ErrorMessage;
return result;
}
for (let i = 0, len = hostname.length; i < len; i++) {
const char = hostname.charCodeAt(i);
if (
(char >= 97 && char <= 122) // 97-122 `a-z`
|| char === 46 // 46 `.`
|| char === 45 // 45 `-`
|| (char >= 48 && char <= 57) // 48-57 `0-9`
|| char === 42 // 42 `*`
|| char === 95 // 95 `_`
// || (char >= 65 && char <= 90) // 65-90 `A-Z`
) {
continue;
}
result[0] = `[parse-filter E0020] (black) invalid wildcard domain: ${JSON.stringify({
line, sliced, sliceStart, sliceEnd, parsed
})}`;
result[1] = ParseType.ErrorMessage;
return result;
}
result[0] = hostname;
result[1] = ParseType.BlackWildcard;
return result;
}

View File

@ -17,8 +17,12 @@ export class FileOutput {
protected strategies: BaseWriteStrategy[] = [];
public domainTrie = new HostnameSmolTrie(null);
public wildcardTrie: HostnameSmolTrie = new HostnameSmolTrie(null);
protected domainKeywords = new Set<string>();
protected domainWildcard = new Set<string>();
private whitelistKeywords = new Set<string>();
protected userAgent = new Set<string>();
protected processName = new Set<string>();
protected processPath = new Set<string>();
@ -43,6 +47,12 @@ export class FileOutput {
whitelistDomain = (domain: string) => {
this.domainTrie.whitelist(domain);
this.wildcardTrie.whitelist(domain);
return this;
};
whitelistKeyword = (keyword: string) => {
this.whitelistKeywords.add(keyword);
return this;
};
@ -112,6 +122,20 @@ export class FileOutput {
return this;
}
bulkAddDomainKeyword(keywords: string[]) {
for (let i = 0, len = keywords.length; i < len; i++) {
this.domainKeywords.add(keywords[i]);
}
return this;
}
bulkAddDomainWildcard(domains: string[]) {
for (let i = 0, len = domains.length; i < len; i++) {
this.wildcardTrie.add(domains[i]);
}
return this;
}
addIPASN(asn: string) {
this.ipasn.add(asn);
return this;
@ -161,7 +185,7 @@ export class FileOutput {
this.addDomainKeyword(value);
break;
case 'DOMAIN-WILDCARD':
this.domainWildcard.add(value);
this.wildcardTrie.add(value);
break;
case 'USER-AGENT':
this.userAgent.add(value);
@ -318,7 +342,11 @@ export class FileOutput {
this.strategiesWritten = true;
const kwfilter = createKeywordFilter(Array.from(this.domainKeywords));
// We use both DOMAIN-KEYWORD and whitelisted keyword to whitelist DOMAIN and DOMAIN-SUFFIX
const kwfilter = createKeywordFilter(
Array.from(this.domainKeywords)
.concat(Array.from(this.whitelistKeywords))
);
if (this.strategies.filter(not(false)).length === 0) {
throw new Error('No strategies to write ' + this.id);
@ -330,6 +358,8 @@ export class FileOutput {
return;
}
this.wildcardTrie.whitelist(domain, includeAllSubdomain);
for (let i = 0; i < strategiesLen; i++) {
const strategy = this.strategies[i];
if (includeAllSubdomain) {
@ -340,14 +370,27 @@ export class FileOutput {
}
}, true);
for (let i = 0, len = this.strategies.length; i < len; i++) {
// Now, we whitelisted out DOMAIN-KEYWORD
const whiteKwfilter = createKeywordFilter(Array.from(this.whitelistKeywords));
const whitelistedKeywords = Array.from(this.domainKeywords).filter(kw => !whiteKwfilter(kw));
this.wildcardTrie.dumpWithoutDot((wildcard) => {
if (kwfilter(wildcard)) {
return;
}
for (let i = 0; i < strategiesLen; i++) {
const strategy = this.strategies[i];
strategy.writeDomainWildcard(wildcard);
}
});
for (let i = 0; i < strategiesLen; i++) {
const strategy = this.strategies[i];
if (this.domainKeywords.size) {
if (whitelistedKeywords.length) {
strategy.writeDomainKeywords(this.domainKeywords);
}
if (this.domainWildcard.size) {
strategy.writeDomainWildcards(this.domainWildcard);
}
if (this.protocol.size) {
strategy.writeProtocols(this.protocol);
}

View File

@ -52,14 +52,12 @@ export class AdGuardHome extends BaseWriteStrategy {
}
}
writeDomainWildcards(wildcards: Set<string>): void {
for (const wildcard of wildcards) {
const processed = wildcard.replaceAll('?', '*');
if (processed.startsWith('*.')) {
this.result.push(`||${processed.slice(2)}^`);
} else {
this.result.push(`|${processed}^`);
}
writeDomainWildcard(wildcard: string): void {
const processed = wildcard.replaceAll('?', '*');
if (processed.startsWith('*.')) {
this.result.push(`||${processed.slice(2)}^`);
} else {
this.result.push(`|${processed}^`);
}
}

View File

@ -30,7 +30,7 @@ export abstract class BaseWriteStrategy {
abstract writeDomain(domain: string): void;
abstract writeDomainSuffix(domain: string): void;
abstract writeDomainKeywords(keyword: Set<string>): void;
abstract writeDomainWildcards(wildcard: Set<string>): void;
abstract writeDomainWildcard(wildcard: string): void;
abstract writeUserAgents(userAgent: Set<string>): void;
abstract writeProcessNames(processName: Set<string>): void;
abstract writeProcessPaths(processPath: Set<string>): void;

View File

@ -30,7 +30,7 @@ export class ClashDomainSet extends BaseWriteStrategy {
}
writeDomainKeywords = noop;
writeDomainWildcards = noop;
writeDomainWildcard = noop;
writeUserAgents = noop;
writeProcessNames = noop;
writeProcessPaths = noop;
@ -64,7 +64,7 @@ export class ClashIPSet extends BaseWriteStrategy {
writeDomain = notSupported('writeDomain');
writeDomainSuffix = notSupported('writeDomainSuffix');
writeDomainKeywords = notSupported('writeDomainKeywords');
writeDomainWildcards = notSupported('writeDomainWildcards');
writeDomainWildcard = notSupported('writeDomainWildcards');
writeUserAgents = notSupported('writeUserAgents');
writeProcessNames = notSupported('writeProcessNames');
writeProcessPaths = notSupported('writeProcessPaths');
@ -111,8 +111,8 @@ export class ClashClassicRuleSet extends BaseWriteStrategy {
appendSetElementsToArray(this.result, keyword, i => `DOMAIN-KEYWORD,${i}`);
}
writeDomainWildcards(wildcard: Set<string>): void {
appendSetElementsToArray(this.result, wildcard, i => `DOMAIN-REGEX,${ClashClassicRuleSet.domainWildCardToRegex(i)}`);
writeDomainWildcard(wildcard: string): void {
this.result.push(`DOMAIN-REGEX,${ClashClassicRuleSet.domainWildCardToRegex(wildcard)}`);
}
writeUserAgents = noop;

View File

@ -14,6 +14,6 @@ export class LegacyClashPremiumClassicRuleSet extends ClashClassicRuleSet {
super(type, outputDir);
}
override writeDomainWildcards = noop;
override writeDomainWildcard = noop;
override writeIpAsns = noop;
}

View File

@ -71,11 +71,9 @@ export class SingboxSource extends BaseWriteStrategy {
);
}
writeDomainWildcards(wildcard: Set<string>): void {
appendArrayInPlace(
this.singbox.domain_regex ??= [],
Array.from(wildcard, SingboxSource.domainWildCardToRegex)
);
writeDomainWildcard(wildcard: string): void {
this.singbox.domain_regex ??= [];
this.singbox.domain_regex.push(SingboxSource.domainWildCardToRegex(wildcard));
}
writeUserAgents = noop;

View File

@ -12,7 +12,7 @@ export class SurfboardRuleSet extends SurgeRuleSet {
super(type, outputDir);
}
override writeDomainWildcards = noop;
override writeDomainWildcard = noop;
override writeUserAgents = noop;
override writeUrlRegexes = noop;
override writeIpAsns = noop;

View File

@ -33,7 +33,7 @@ export class SurgeDomainSet extends BaseWriteStrategy {
}
writeDomainKeywords = noop;
writeDomainWildcards = noop;
writeDomainWildcard = noop;
writeUserAgents = noop;
writeProcessNames = noop;
writeProcessPaths = noop;
@ -78,8 +78,8 @@ export class SurgeRuleSet extends BaseWriteStrategy {
appendSetElementsToArray(this.result, keyword, i => `DOMAIN-KEYWORD,${i}`);
}
writeDomainWildcards(wildcard: Set<string>): void {
appendSetElementsToArray(this.result, wildcard, i => `DOMAIN-WILDCARD,${i}`);
writeDomainWildcard(wildcard: string): void {
this.result.push(`DOMAIN-WILDCARD,${wildcard}`);
}
writeUserAgents(userAgent: Set<string>): void {
@ -176,7 +176,7 @@ export class SurgeMitmSgmodule extends BaseWriteStrategy {
writeDomainSuffix = noop;
writeDomainKeywords = noop;
writeDomainWildcards = noop;
writeDomainWildcard = noop;
writeUserAgents = noop;
writeProcessNames = noop;
writeProcessPaths = noop;

View File

@ -1,5 +1,5 @@
# $ meta_title Sukka's Ruleset - Reject Domains
# $ meta_description The ruleset supports AD blocking, tracking protection, privacy protection, anti-phishing, anti-mining
# Sukka's Ruleset - Reject Domains
# $ custom_build_script
# $ skip_dedupe_src enforce some blocking to reduce file size
DOMAIN,this_rule_set_is_made_by_sukkaw.skk.moe