From 37b01ff016ebb688ddcc9c2a038fc67fa60f4446 Mon Sep 17 00:00:00 2001 From: SukkaW Date: Thu, 7 Dec 2023 20:39:52 +0800 Subject: [PATCH] Chore: improve reject hosts robustness --- Build/lib/cached-tld-parse.ts | 4 ++++ Build/lib/is-fast-ip.ts | 33 +++++++++++++++++++++++++++++++++ Build/lib/parse-filter.ts | 29 ++++++++++++----------------- 3 files changed, 49 insertions(+), 17 deletions(-) create mode 100644 Build/lib/is-fast-ip.ts diff --git a/Build/lib/cached-tld-parse.ts b/Build/lib/cached-tld-parse.ts index 356b2888..b5ced6de 100644 --- a/Build/lib/cached-tld-parse.ts +++ b/Build/lib/cached-tld-parse.ts @@ -5,8 +5,12 @@ import type { PublicSuffixList } from 'gorhill-publicsuffixlist'; const cache = createCache('cached-tld-parse', true); const sharedConfig = { allowPrivateDomains: true }; +const sharedConfig2 = { allowPrivateDomains: true, detectIp: false }; +/** { allowPrivateDomains: true } */ export const parse = (domain: string) => cache.sync(domain, () => tldts.parse(domain, sharedConfig)); +/** { allowPrivateDomains: true, detectIp: false } */ +export const parse2 = (domain: string) => cache.sync(domain, () => tldts.parse(domain, sharedConfig2)); let gothillGetDomainCache: ReturnType | null = null; export const createCachedGorhillGetDomain = (gorhill: PublicSuffixList) => { diff --git a/Build/lib/is-fast-ip.ts b/Build/lib/is-fast-ip.ts new file mode 100644 index 00000000..8b15aba1 --- /dev/null +++ b/Build/lib/is-fast-ip.ts @@ -0,0 +1,33 @@ +/** + * Check if a hostname is an IP. You should be aware that this only works + * because `hostname` is already garanteed to be a valid hostname! + */ +export function isProbablyIpv4(hostname: string): boolean { + // Cannot be shorted than 1.1.1.1 + if (hostname.length < 7) { + return false; + } + + // Cannot be longer than: 255.255.255.255 + if (hostname.length > 15) { + return false; + } + + let numberOfDots = 0; + + for (let i = 0; i < hostname.length; i += 1) { + const code = hostname.charCodeAt(i); + + if (code === 46 /* '.' */) { + numberOfDots += 1; + } else if (code < 48 /* '0' */ || code > 57 /* '9' */) { + return false; + } + } + + return ( + numberOfDots === 3 + && hostname.charCodeAt(0) !== 46 + && /* '.' */ hostname.charCodeAt(hostname.length - 1) !== 46 /* '.' */ + ); +} diff --git a/Build/lib/parse-filter.ts b/Build/lib/parse-filter.ts index 2de56b2d..20da8cef 100644 --- a/Build/lib/parse-filter.ts +++ b/Build/lib/parse-filter.ts @@ -6,6 +6,7 @@ import { NetworkFilter } from '@cliqz/adblocker'; import { processLine } from './process-line'; import { getGorhillPublicSuffixPromise } from './get-gorhill-publicsuffix'; import type { PublicSuffixList } from 'gorhill-publicsuffixlist'; +import { isProbablyIpv4 } from './is-fast-ip'; const DEBUG_DOMAIN_TO_FIND: string | null = null; // example.com | null let foundDebugDomain = false; @@ -22,19 +23,16 @@ const warnOnce = (url: string, isWhite: boolean, ...message: any[]) => { const normalizeDomain = (domain: string) => { if (!domain) return null; + if (isProbablyIpv4(domain)) return null; - const parsed = tldts.parse(domain); + const parsed = tldts.parse2(domain); if (parsed.isIp) return null; + if (!parsed.isIcann && !parsed.isPrivate) return null; - if (parsed.isIcann || parsed.isPrivate) { - const h = parsed.hostname; + const h = parsed.hostname; + if (!h) return null; - if (h === null) return null; - - return h[0] === '.' ? h.slice(1) : h; - } - - return null; + return h[0] === '.' ? h.slice(1) : h; }; export async function processDomainLists(domainListsUrl: string | URL, includeAllSubDomain = false) { @@ -89,6 +87,7 @@ export async function processHosts(hostsUrl: string | URL, includeAllSubDomain = } const domain = skipDomainCheck ? _domain : normalizeDomain(_domain); + if (domain) { if (includeAllSubDomain) { domainSets.add(`.${domain}`); @@ -301,19 +300,15 @@ function parse($line: string, gorhill: PublicSuffixList): null | [hostname: stri // && (!filter.isRegex()) // isPlain() === !isRegex() && (!filter.isFullRegex()) ) { - if (!gorhill.getDomain(filter.hostname)) { - return null; - } const hostname = normalizeDomain(filter.hostname); if (!hostname) { + console.log(' * [parse-filter E0000] invalid domain:', filter.hostname); return null; } - // console.log({ - // '||': filter.isHostnameAnchor(), - // '|': filter.isLeftAnchor(), - // '|https://': !filter.isHostnameAnchor() && (filter.fromHttps() || filter.fromHttp()) - // }); + // |: filter.isHostnameAnchor(), + // |: filter.isLeftAnchor(), + // |https://: !filter.isHostnameAnchor() && (filter.fromHttps() || filter.fromHttp()) const isIncludeAllSubDomain = filter.isHostnameAnchor(); if (filter.isException() || filter.isBadFilter()) {