From b221d2cf88ec4cb7ce8bf371b4bbb266c0506bf8 Mon Sep 17 00:00:00 2001 From: Sing Yu Chan Date: 2025年4月18日 14:17:28 +0800 Subject: [PATCH 01/16] fix build --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 596745ce7..3b9d3927a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,7 +20,7 @@ env: jobs: build: - runs-on: ubuntu-20.04 + runs-on: ubuntu-24.04 steps: - name: Checkout uses: actions/checkout@v2 From c3b0d1b6a1029bb7c93143b27a89ea5fa156cd67 Mon Sep 17 00:00:00 2001 From: pexcn Date: 2025年4月18日 14:27:46 +0800 Subject: [PATCH 02/16] fix netaggregate build failed --- scripts/_pre_/50-tools.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/_pre_/50-tools.sh b/scripts/_pre_/50-tools.sh index e4edd2787..1c6efb952 100755 --- a/scripts/_pre_/50-tools.sh +++ b/scripts/_pre_/50-tools.sh @@ -7,5 +7,6 @@ cd ../.. # https://github.com/afpd/netaggregate/pull/1 cd tools/netaggregate +sed -i '/#include /a #include ' netaggregate.hpp make --silent cd ../.. From ff2f33dd2e836b4ffefe8791844bd476e0abf8d5 Mon Sep 17 00:00:00 2001 From: pexcn Date: 2025年11月17日 21:55:21 +0800 Subject: [PATCH 03/16] chinalist: remove google domains I usually use this list in conjunction with the `add_tagchn_ip` option of chinadns-ng, but some domains in google.china.conf resolve to blocked ips. --- scripts/chinalist/chinalist.sh | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/scripts/chinalist/chinalist.sh b/scripts/chinalist/chinalist.sh index ef9e87d1a..a2195759a 100755 --- a/scripts/chinalist/chinalist.sh +++ b/scripts/chinalist/chinalist.sh @@ -5,7 +5,6 @@ CUR_DIR=$(pwd) TMP_DIR=$(mktemp -d /tmp/chinalist.XXXXXX) SRC_URL_1="https://raw.githubusercontent.com/felixonmars/dnsmasq-china-list/master/apple.china.conf" -SRC_URL_2="https://raw.githubusercontent.com/felixonmars/dnsmasq-china-list/master/google.china.conf" SRC_URL_3="https://raw.githubusercontent.com/felixonmars/dnsmasq-china-list/master/accelerated-domains.china.conf" SRC_URL_4="https://raw.githubusercontent.com/pexcn/daily-extras/master/chinalist-extras.txt" SRC_FILE="$CUR_DIR/dist/toplist/toplist.txt" @@ -15,7 +14,6 @@ fetch_src() { cd $TMP_DIR curl -sSL $SRC_URL_1 -o apple.conf - curl -sSL $SRC_URL_2 -o google.conf curl -sSL $SRC_URL_3 -o china.conf curl -sSL $SRC_URL_4 -o chinalist-extras.txt cp $SRC_FILE . @@ -26,7 +24,7 @@ fetch_src() { gen_list() { cd $TMP_DIR - cat apple.conf google.conf china.conf | + cat apple.conf china.conf | # remove empty lines sed '/^[[:space:]]*$/d' | # remove comment lines From 0ee150bf31474ab815e1df1f0a1b247789261046 Mon Sep 17 00:00:00 2001 From: pexcn Date: 2025年11月18日 15:29:08 +0800 Subject: [PATCH 04/16] toplist: redesign --- generate.sh | 4 ++++ scripts/_pre_/01-toplist.sh | 34 ---------------------------------- scripts/toplist.sh | 10 ++++++++++ 3 files changed, 14 insertions(+), 34 deletions(-) delete mode 100755 scripts/_pre_/01-toplist.sh create mode 100755 scripts/toplist.sh diff --git a/generate.sh b/generate.sh index 8b6449a26..8fa89a9a0 100755 --- a/generate.sh +++ b/generate.sh @@ -23,6 +23,10 @@ post() { } main() { + # toplist + mkdir -p dist/toplist/ + scripts/toplist.sh> dist/toplist/toplist.txt + # ad domain list scripts/adlist/adlist.sh diff --git a/scripts/_pre_/01-toplist.sh b/scripts/_pre_/01-toplist.sh deleted file mode 100755 index 71c28b46d..000000000 --- a/scripts/_pre_/01-toplist.sh +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/bash -e -set -o pipefail - -CUR_DIR=$(pwd) -TMP_DIR=$(mktemp -d /tmp/toplist.XXXXXX) - -SRC_URL="https://s3-us-west-1.amazonaws.com/umbrella-static/top-1m.csv.zip" -DEST_FILE="dist/toplist/toplist.txt" - -gen_list() { - cd $TMP_DIR - - curl -sSL $SRC_URL | - # unzip - gunzip | - # extract domain - awk -F ',' '{print 2ドル}' | - # convert to unix format - sed $'s/\r$//'> toplist.txt - - cd $CUR_DIR -} - -copy_dest() { - install -D -m 644 $TMP_DIR/toplist.txt $DEST_FILE -} - -clean_up() { - rm -r $TMP_DIR -} - -gen_list -copy_dest -clean_up diff --git a/scripts/toplist.sh b/scripts/toplist.sh new file mode 100755 index 000000000..5f23464db --- /dev/null +++ b/scripts/toplist.sh @@ -0,0 +1,10 @@ +#!/bin/sh + +TOPLIST_URL="https://s3-us-west-1.amazonaws.com/umbrella-static/top-1m.csv.zip" + +curl -L $TOPLIST_URL | + gunzip | + # extract domain + cut -d',' -f2 | + # convert to unix format + sed 's/\r$//' From 397e19c14ad73ee7ab8d35e7854cfb0e7093de0d Mon Sep 17 00:00:00 2001 From: pexcn Date: 2026年1月31日 21:46:11 +0800 Subject: [PATCH 05/16] README: Powered by DartNode --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 7fd53987f..0e6530ce1 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,8 @@ This script can be automatically generate something what you needed every day. [![Flag Counter](https://s04.flagcounter.com/countxl/jtlp/bg_FFFFFF/txt_000000/border_CCCCCC/columns_2/maxflags_10/viewers_3/labels_1/pageviews_1/flags_0/percent_0/)](https://info.flagcounter.com/jtlp) +[![Powered by DartNode](https://dartnode.com/branding/DN-Open-Source-sm.png)](https://dartnode.com "Powered by DartNode - Free VPS for Open Source") + ## 🍭 Lists - [`adlist/adlist.txt`](https://raw.githubusercontent.com/pexcn/daily/gh-pages/adlist/adlist.txt) From 5129543544cf2c61cd70bb295d1024bc04e3ad64 Mon Sep 17 00:00:00 2001 From: Sing Yu Chan Date: 2026年1月31日 21:52:25 +0800 Subject: [PATCH 06/16] fix dartnode image url --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0e6530ce1..3d4cddb51 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ This script can be automatically generate something what you needed every day. [![Flag Counter](https://s04.flagcounter.com/countxl/jtlp/bg_FFFFFF/txt_000000/border_CCCCCC/columns_2/maxflags_10/viewers_3/labels_1/pageviews_1/flags_0/percent_0/)](https://info.flagcounter.com/jtlp) -[![Powered by DartNode](https://dartnode.com/branding/DN-Open-Source-sm.png)](https://dartnode.com "Powered by DartNode - Free VPS for Open Source") +[![Powered by DartNode](https://github.com/bin456789/reinstall/assets/7548515/435d6740-bcdd-4f3a-a196-2f60ae397f17)](https://dartnode.com "Powered by DartNode - Free VPS for Open Source") ## 🍭 Lists From 83b89b4480648a5d748311df28255deee9044d72 Mon Sep 17 00:00:00 2001 From: pexcn Date: 2026年1月31日 22:01:46 +0800 Subject: [PATCH 07/16] for verify only --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 3d4cddb51..aa32395a9 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,7 @@ This script can be automatically generate something what you needed every day. [![Flag Counter](https://s04.flagcounter.com/countxl/jtlp/bg_FFFFFF/txt_000000/border_CCCCCC/columns_2/maxflags_10/viewers_3/labels_1/pageviews_1/flags_0/percent_0/)](https://info.flagcounter.com/jtlp) [![Powered by DartNode](https://github.com/bin456789/reinstall/assets/7548515/435d6740-bcdd-4f3a-a196-2f60ae397f17)](https://dartnode.com "Powered by DartNode - Free VPS for Open Source") +[![Powered by DartNode](https://dartnode.com/branding/DN-Open-Source-sm.png)](https://dartnode.com "Powered by DartNode - Free VPS for Open Source") ## 🍭 Lists From fb830c6cf414ec6bc2a9493b004eec7d3aa388a4 Mon Sep 17 00:00:00 2001 From: pexcn Date: Wed, 4 Mar 2026 20:19:16 +0800 Subject: [PATCH 08/16] pac: rewrite whitelist template --- template/pac/whitelist.template | 207 ++++++++++++++++++++++---------- 1 file changed, 145 insertions(+), 62 deletions(-) diff --git a/template/pac/whitelist.template b/template/pac/whitelist.template index c3afb0e23..12fbc7d9f 100644 --- a/template/pac/whitelist.template +++ b/template/pac/whitelist.template @@ -1,104 +1,187 @@ const proxy = "SOCKS5 127.0.0.1:1080;"; const direct = "DIRECT;"; -const hasOwnProperty = Object.hasOwnProperty; +const hasOwn = Object.hasOwn || function (obj, prop) { + return Object.prototype.hasOwnProperty.call(obj, prop); +}; const china_domains = { ___CHINALIST_PLACEHOLDER___ }; -const subnet_ips = [ - 0, 16777216, // 0.0.0.0 -> 0.255.255.255 - 167772160, 184549376, // 10.0.0.0/8 -> 10.255.255.255 - 1681915904, 1686110208, // 100.64.0.0/10 -> 100.127.255.255 - 2130706432, 2147483648, // 127.0.0.0/8 -> 127.255.255.255 - -1442971648, -1442906112, // 169.254.0.0/16 -> 169.254.255.255 - -1408237568, -1407188992, // 172.16.0.0/12 -> 172.31.255.255 - -1073741824, -1073741568, // 192.0.0.0/24 -> 192.0.0.255 - -1073741312, -1073741056, // 192.0.2.0/24 -> 192.0.2.255 - -1071660032, -1071659776, // 192.31.196.0/24 -> 192.31.196.255 - -1070284544, -1070284288, // 192.52.193.0/24 -> 192.52.193.255 - -1067949312, -1067949056, // 192.88.99.0/24 -> 192.88.99.255 - -1062731776, -1062666240, // 192.168.0.0/16 -> 192.168.255.255 - -1062260736, -1062260480, // 192.175.48.0/24 -> 192.175.48.255 - -971898880, -971767808, // 198.18.0.0/15 -> 198.19.255.255 - -969710592, -969710336, // 198.51.100.0/24 -> 198.51.100.255 - -889163520, -889163264, // 203.0.113.0/24 -> 203.0.113.255 - -536870912, 0 // 224.0.0.0/3 -> 255.255.255.255 +const subnet_ranges = [ + 0, 16777216, 167772160, 184549376, + 1681915904, 1686110208, 2130706432, 2147483648, + 2851995648, 2852061184, 2886729728, 2887778304, + 3221225472, 3221225728, 3221225984, 3221226240, + 3223306240, 3223306496, 3224681472, 3224681728, + 3227016704, 3227016960, 3232235520, 3232301056, + 3232706560, 3232706816, 3323068416, 3323199488, + 3325256704, 3325256960, 3405803776, 3405804032, + 3758096384, 4294967296 ]; -function is_ipv4(host) { - const regex = /^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(:([0-9]|[1-9]\d|[1-9]\d{2}|[1-9]\d{3}|[1-5]\d{4}|6[0-4]\d{3}|65[0-4]\d{2}|655[0-2]\d|6553[0-5]))?$/g; - if (regex.test(host)) { - return true; +const _CACHE_LIMIT = 4096; +const _cache = Object.create(null); +const _cache_ring = new Array(_CACHE_LIMIT); +let _cache_pos = 0; +let _cache_size = 0; + +function _cacheGet(host) { + return _cache[host]; +} + +function _cachePut(host, val) { + if (_cache[host] !== undefined) { + _cache[host] = val; + return; } + if (_cache_size < _CACHE_LIMIT) { + _cache_ring[_cache_size++] = host; + } else { + const old = _cache_ring[_cache_pos]; + if (old !== undefined) { + delete _cache[old]; + } + _cache_ring[_cache_pos] = host; + _cache_pos = (_cache_pos + 1) % _CACHE_LIMIT; + } + _cache[host] = val; } -function convert_address(ipchars) { - if (ipchars.indexOf(':') !== -1) { - ipchars = ipchars.split(':')[0]; +function _isCn(host) { + const len = host.length; + let end = len; + // Tolerate a trailing dot (FQDN form), e.g. "example.cn." + if (len> 0 && host.charCodeAt(len - 1) === 46) { // '.' + end = len - 1; } - const bytes = ipchars.split('.'); - const result = ((bytes[0] & 0xff) << 24) | - ((bytes[1] & 0xff) << 16) | - ((bytes[2] & 0xff) << 8) | - (bytes[3] & 0xff); - return result; + return end> 3 + && host.charCodeAt(end - 3) === 46 // '.' + && host.charCodeAt(end - 2) === 99 // 'c' + && host.charCodeAt(end - 1) === 110; // 'n' } -function is_china_domain(domain) { - return !!dnsDomainIs(domain, ".cn"); +function _ipv4ToUint(host) { + const colon = host.indexOf(':'); + if (colon !== -1) { + // If it contains ':' but no '.', assume IPv6 literal -> not IPv4. + if (host.indexOf('.') === -1) return null; + host = host.substring(0, colon); + } + + let acc = 0; + let octet = 0; + let digits = 0; + let parts = 0; + let leadingZero = false; + + for (let i = 0; i < host.length; i++) { + const c = host.charCodeAt(i); + + if (c>= 48 && c <= 57) { + if (digits === 0) { + leadingZero = (c === 48); + } + digits++; + octet = octet * 10 + (c - 48); + if (octet> 255) return null; + continue; + } + + if (c !== 46) return null; // only '.' allowed + if (digits === 0) return null; // empty octet + if (leadingZero && digits> 1) return null; // reject leading zeros like "01" + + acc = acc * 256 + octet; + parts++; + if (parts> 3) return null; + + octet = 0; + digits = 0; + leadingZero = false; + } + + if (digits === 0) return null; + if (leadingZero && digits> 1) return null; + + acc = acc * 256 + octet; + if (parts !== 3) return null; + + return acc; } -function match_domains(domain, domains) { - let suffix; - let pos = domain.lastIndexOf('.'); - pos = domain.lastIndexOf('.', pos - 1); - while (1) { - if (pos <= 0) { - return hasOwnProperty.call(domains, domain); +const _ip_table = new Array(256); +(function _initIpTable() { + for (let i = 0; i < 256; i++) { + _ip_table[i] = []; + } + for (let i = 0; i < subnet_ranges.length; i += 2) { + const start = subnet_ranges[i]; + const end = subnet_ranges[i + 1]; + const pStart = (start>>> 24) & 0xFF; + const pEnd = ((end - 1)>>> 24) & 0xFF; + for (let p = pStart; p <= pEnd; p++) { + _ip_table[p].push(start, end); } - suffix = domain.substring(pos + 1); - if (hasOwnProperty.call(domains, suffix)) { + } +})(); + +function _matchSubnet(ip) { + const ranges = _ip_table[(ip>>> 24) & 0xFF]; + for (let i = 0; i < ranges.length; i += 2) { + if (ranges[i] <= ip && ip < ranges[i + 1]) { return true; } - pos = domain.lastIndexOf('.', pos - 1); } + return false; } -function match_subnet_ips(ip, ips) { - for (let i = 0; i < 28; i += 2) { - if (ips[i] <= ip && ip < ips[i + 1]) { +function _matchDomains(host, domains) { + if (hasOwn(domains, host)) return true; + + // Start from the 2nd-level domain boundary to avoid checking TLD-only keys. + let last = host.lastIndexOf('.'); + if (last <= 0) return false; + + let pos = host.lastIndexOf('.', last - 1); + while (pos> 0) { + if (hasOwn(domains, host.substring(pos + 1))) { return true; } + pos = host.lastIndexOf('.', pos - 1); } + + return false; } -/** - * @return {string} Connect via direct or proxy. - */ function FindProxyForURL(url, host) { if (typeof host === 'undefined' || isPlainHostName(host) === true || host === '127.0.0.1' - || host === 'localhost') { + || host === 'localhost' + || host === '::1') { return direct; } - if (is_china_domain(host) === true) { - return direct; + const cached = _cacheGet(host); + if (cached !== undefined) { + return cached; } - if (match_domains(host, china_domains) === true) { - return direct; - } - - if (is_ipv4(host) === true) { - const ip = convert_address(host); - if (match_subnet_ips(ip, subnet_ips) === true) { - return direct; + let result = proxy; + if (_isCn(host) === true || _matchDomains(host, china_domains) === true) { + result = direct; + } else { + const c0 = host.length> 0 ? host.charCodeAt(0) : 0; + if (c0>= 48 && c0 <= 57) { + const ip = _ipv4ToUint(host); + if (ip !== null && _matchSubnet(ip) === true) { + result = direct; + } } } - return proxy; + _cachePut(host, result); + return result; } From bacb8a197f7b8d0496afbb3c5d5067a014770a77 Mon Sep 17 00:00:00 2001 From: pexcn Date: Thu, 5 Mar 2026 11:16:40 +0800 Subject: [PATCH 09/16] pac: whitelist: camelCase naming --- template/pac/whitelist.template | 77 ++++++++++++++++----------------- 1 file changed, 37 insertions(+), 40 deletions(-) diff --git a/template/pac/whitelist.template b/template/pac/whitelist.template index 12fbc7d9f..a0dee655f 100644 --- a/template/pac/whitelist.template +++ b/template/pac/whitelist.template @@ -5,11 +5,11 @@ const hasOwn = Object.hasOwn || function (obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); }; -const china_domains = { +const chinaDomains = { ___CHINALIST_PLACEHOLDER___ }; -const subnet_ranges = [ +const subnetRanges = [ 0, 16777216, 167772160, 184549376, 1681915904, 1686110208, 2130706432, 2147483648, 2851995648, 2852061184, 2886729728, 2887778304, @@ -21,38 +21,37 @@ const subnet_ranges = [ 3758096384, 4294967296 ]; -const _CACHE_LIMIT = 4096; -const _cache = Object.create(null); -const _cache_ring = new Array(_CACHE_LIMIT); -let _cache_pos = 0; -let _cache_size = 0; +const CACHE_LIMIT = 4096; +const cache = Object.create(null); +const cacheRing = new Array(CACHE_LIMIT); +let cachePos = 0; +let cacheSize = 0; -function _cacheGet(host) { - return _cache[host]; +function cacheGet(host) { + return cache[host]; } -function _cachePut(host, val) { - if (_cache[host] !== undefined) { - _cache[host] = val; +function cachePut(host, val) { + if (cache[host] !== undefined) { + cache[host] = val; return; } - if (_cache_size < _CACHE_LIMIT) { - _cache_ring[_cache_size++] = host; + if (cacheSize < CACHE_LIMIT) { + cacheRing[cacheSize++] = host; } else { - const old = _cache_ring[_cache_pos]; + const old = cacheRing[cachePos]; if (old !== undefined) { - delete _cache[old]; + delete cache[old]; } - _cache_ring[_cache_pos] = host; - _cache_pos = (_cache_pos + 1) % _CACHE_LIMIT; + cacheRing[cachePos] = host; + cachePos = (cachePos + 1) % CACHE_LIMIT; } - _cache[host] = val; + cache[host] = val; } -function _isCn(host) { +function isCn(host) { const len = host.length; let end = len; - // Tolerate a trailing dot (FQDN form), e.g. "example.cn." if (len> 0 && host.charCodeAt(len - 1) === 46) { // '.' end = len - 1; } @@ -62,11 +61,10 @@ function _isCn(host) { && host.charCodeAt(end - 1) === 110; // 'n' } -function _ipv4ToUint(host) { +function ipv4ToUint(host) { const colon = host.indexOf(':'); if (colon !== -1) { - // If it contains ':' but no '.', assume IPv6 literal -> not IPv4. - if (host.indexOf('.') === -1) return null; + if (host.indexOf('.') === -1) return null; // host is ipv6 host = host.substring(0, colon); } @@ -111,24 +109,24 @@ function _ipv4ToUint(host) { return acc; } -const _ip_table = new Array(256); -(function _initIpTable() { +const ipTable = new Array(256); +(function initIpTable() { for (let i = 0; i < 256; i++) { - _ip_table[i] = []; + ipTable[i] = []; } - for (let i = 0; i < subnet_ranges.length; i += 2) { - const start = subnet_ranges[i]; - const end = subnet_ranges[i + 1]; + for (let i = 0; i < subnetRanges.length; i += 2) { + const start = subnetRanges[i]; + const end = subnetRanges[i + 1]; const pStart = (start>>> 24) & 0xFF; const pEnd = ((end - 1)>>> 24) & 0xFF; for (let p = pStart; p <= pEnd; p++) { - _ip_table[p].push(start, end); + ipTable[p].push(start, end); } } })(); -function _matchSubnet(ip) { - const ranges = _ip_table[(ip>>> 24) & 0xFF]; +function matchSubnet(ip) { + const ranges = ipTable[(ip>>> 24) & 0xFF]; for (let i = 0; i < ranges.length; i += 2) { if (ranges[i] <= ip && ip < ranges[i + 1]) { return true; @@ -137,10 +135,9 @@ function _matchSubnet(ip) { return false; } -function _matchDomains(host, domains) { +function matchDomains(host, domains) { if (hasOwn(domains, host)) return true; - // Start from the 2nd-level domain boundary to avoid checking TLD-only keys. let last = host.lastIndexOf('.'); if (last <= 0) return false; @@ -164,24 +161,24 @@ function FindProxyForURL(url, host) { return direct; } - const cached = _cacheGet(host); + const cached = cacheGet(host); if (cached !== undefined) { return cached; } let result = proxy; - if (_isCn(host) === true || _matchDomains(host, china_domains) === true) { + if (isCn(host) === true || matchDomains(host, chinaDomains) === true) { result = direct; } else { const c0 = host.length> 0 ? host.charCodeAt(0) : 0; if (c0>= 48 && c0 <= 57) { - const ip = _ipv4ToUint(host); - if (ip !== null && _matchSubnet(ip) === true) { + const ip = ipv4ToUint(host); + if (ip !== null && matchSubnet(ip) === true) { result = direct; } } } - _cachePut(host, result); + cachePut(host, result); return result; } From 7d1fc862515d056def4a76e06ea7a5f958bcad9c Mon Sep 17 00:00:00 2001 From: pexcn Date: Thu, 5 Mar 2026 11:46:11 +0800 Subject: [PATCH 10/16] pac: whitelist: optimize readability of subnet cidr --- template/pac/whitelist.template | 45 +++++++++++++++++++++++---------- 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/template/pac/whitelist.template b/template/pac/whitelist.template index a0dee655f..4b82077e1 100644 --- a/template/pac/whitelist.template +++ b/template/pac/whitelist.template @@ -9,16 +9,26 @@ const chinaDomains = { ___CHINALIST_PLACEHOLDER___ }; -const subnetRanges = [ - 0, 16777216, 167772160, 184549376, - 1681915904, 1686110208, 2130706432, 2147483648, - 2851995648, 2852061184, 2886729728, 2887778304, - 3221225472, 3221225728, 3221225984, 3221226240, - 3223306240, 3223306496, 3224681472, 3224681728, - 3227016704, 3227016960, 3232235520, 3232301056, - 3232706560, 3232706816, 3323068416, 3323199488, - 3325256704, 3325256960, 3405803776, 3405804032, - 3758096384, 4294967296 +const SUBNET_CIDRS = [ + "0.0.0.0/8", + "10.0.0.0/8", + "100.64.0.0/10", + "127.0.0.0/8", + "169.254.0.0/16", + "172.16.0.0/12", + "192.0.0.0/24", + "192.0.2.0/24", + "192.31.196.0/24", + "192.52.193.0/24", + "192.88.99.0/24", + "192.168.0.0/16", + "192.175.48.0/24", + "198.18.0.0/15", + "198.51.100.0/24", + "203.0.113.0/24", + "224.0.0.0/4", + "240.0.0.0/4", + "255.255.255.255/32", ]; const CACHE_LIMIT = 4096; @@ -114,9 +124,18 @@ const ipTable = new Array(256); for (let i = 0; i < 256; i++) { ipTable[i] = []; } - for (let i = 0; i < subnetRanges.length; i += 2) { - const start = subnetRanges[i]; - const end = subnetRanges[i + 1]; + for (let i = 0; i < SUBNET_CIDRS.length; i++) { + const cidr = SUBNET_CIDRS[i]; + const slash = cidr.indexOf('/'); + if (slash < 0) continue; + const ipStr = cidr.substring(0, slash); + const prefix = parseInt(cidr.substring(slash + 1), 10); + if (!(prefix>= 0 && prefix <= 32)) continue; + const base = ipv4ToUint(ipStr); + if (base === null) continue; + const mask = prefix === 0 ? 0 : ((0xFFFFFFFF << (32 - prefix))>>> 0); + const start = (base & mask)>>> 0; + const end = start + Math.pow(2, 32 - prefix); // [start, end) const pStart = (start>>> 24) & 0xFF; const pEnd = ((end - 1)>>> 24) & 0xFF; for (let p = pStart; p <= pEnd; p++) { From b2063c11d1992cec872e791c810343aa30397b1f Mon Sep 17 00:00:00 2001 From: pexcn Date: Thu, 5 Mar 2026 11:52:00 +0800 Subject: [PATCH 11/16] pac: whitelist: fix pac format --- template/pac/whitelist.template | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/template/pac/whitelist.template b/template/pac/whitelist.template index 4b82077e1..0a0fd6ba9 100644 --- a/template/pac/whitelist.template +++ b/template/pac/whitelist.template @@ -1,5 +1,5 @@ -const proxy = "SOCKS5 127.0.0.1:1080;"; -const direct = "DIRECT;"; +const proxy = "SOCKS5 127.0.0.1:1080"; +const direct = "DIRECT"; const hasOwn = Object.hasOwn || function (obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); From d1ab5b48565db655ef56d3b974087a76693d2105 Mon Sep 17 00:00:00 2001 From: pexcn Date: Thu, 5 Mar 2026 14:48:24 +0800 Subject: [PATCH 12/16] pac: rewrite gfwlist template --- template/pac/gfwlist.template | 91 +++++++++++++++++++++++++---------- 1 file changed, 66 insertions(+), 25 deletions(-) diff --git a/template/pac/gfwlist.template b/template/pac/gfwlist.template index 52a7e473e..ea14f15fb 100644 --- a/template/pac/gfwlist.template +++ b/template/pac/gfwlist.template @@ -1,50 +1,91 @@ -const proxy = "SOCKS5 127.0.0.1:1080;"; -const direct = "DIRECT;"; +const proxy = "SOCKS5 127.0.0.1:1080"; +const direct = "DIRECT"; -const hasOwnProperty = Object.hasOwnProperty; +const hasOwn = Object.hasOwn || function (obj, prop) { + return Object.prototype.hasOwnProperty.call(obj, prop); +}; -const gfwlist_domains = { +const gfwlistDomains = { ___GFWLIST_PLACEHOLDER___ }; -function is_china_domain(domain) { - return !!dnsDomainIs(domain, ".cn"); +const CACHE_LIMIT = 4096; +const cache = Object.create(null); +const cacheRing = new Array(CACHE_LIMIT); +let cachePos = 0; +let cacheSize = 0; + +function cacheGet(host) { + return cache[host]; } -function match_domains(domain, domains) { - let suffix; - let pos = domain.lastIndexOf('.'); - pos = domain.lastIndexOf('.', pos - 1); - while (1) { - if (pos <= 0) { - return hasOwnProperty.call(domains, domain); +function cachePut(host, val) { + if (cache[host] !== undefined) { + cache[host] = val; + return; + } + if (cacheSize < CACHE_LIMIT) { + cacheRing[cacheSize++] = host; + } else { + const old = cacheRing[cachePos]; + if (old !== undefined) { + delete cache[old]; } - suffix = domain.substring(pos + 1); - if (hasOwnProperty.call(domains, suffix)) { + cacheRing[cachePos] = host; + cachePos = (cachePos + 1) % CACHE_LIMIT; + } + cache[host] = val; +} + +function isCn(host) { + const len = host.length; + let end = len; + if (len> 0 && host.charCodeAt(len - 1) === 46) { // '.' + end = len - 1; + } + return end> 3 + && host.charCodeAt(end - 3) === 46 // '.' + && host.charCodeAt(end - 2) === 99 // 'c' + && host.charCodeAt(end - 1) === 110; // 'n' +} + +function matchDomains(host, domains) { + if (hasOwn(domains, host)) return true; + + let last = host.lastIndexOf('.'); + if (last <= 0) return false; + + let pos = host.lastIndexOf('.', last - 1); + while (pos> 0) { + if (hasOwn(domains, host.substring(pos + 1))) { return true; } - pos = domain.lastIndexOf('.', pos - 1); + pos = host.lastIndexOf('.', pos - 1); } + + return false; } -/** - * @return {string} Connect via direct or proxy. - */ function FindProxyForURL(url, host) { if (typeof host === 'undefined' || isPlainHostName(host) === true || host === '127.0.0.1' - || host === 'localhost') { + || host === 'localhost' + || host === '::1') { return direct; } - if (is_china_domain(host) === true) { - return direct; + const cached = cacheGet(host); + if (cached !== undefined) { + return cached; } - if (match_domains(host, gfwlist_domains) === true) { - return proxy; + if (isCn(host) === true) { + cachePut(host, direct); + return direct; } - return direct; + const result = matchDomains(host, gfwlistDomains) === true ? proxy : direct; + cachePut(host, result); + return result; } From 8a5d2c54ff7d3e61127c705214926edc428a9f52 Mon Sep 17 00:00:00 2001 From: pexcn Date: 2026年3月23日 10:17:35 +0800 Subject: [PATCH 13/16] chnroute: update apnic url --- scripts/chnroute/chnroute.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/chnroute/chnroute.sh b/scripts/chnroute/chnroute.sh index 7ca4fbbba..13b1c7e94 100755 --- a/scripts/chnroute/chnroute.sh +++ b/scripts/chnroute/chnroute.sh @@ -4,7 +4,7 @@ set -o pipefail CUR_DIR=$(pwd) TMP_DIR=$(mktemp -d /tmp/chnroute.XXXXXX) -SRC_URL_1="https://ftp.apnic.net/apnic/stats/apnic/delegated-apnic-latest" +SRC_URL_1="https://ftp.apnic.net/stats/apnic/delegated-apnic-latest" SRC_URL_2="https://raw.githubusercontent.com/17mon/china_ip_list/master/china_ip_list.txt" DEST_FILE_1="dist/chnroute/chnroute.txt" DEST_FILE_2="dist/chnroute/chnroute6.txt" From cd50f6a90db37dd58530a68410e8e393ab793022 Mon Sep 17 00:00:00 2001 From: pexcn Date: 2026年3月23日 10:18:33 +0800 Subject: [PATCH 14/16] hkgroute: initial --- generate.sh | 3 ++ scripts/hkgroute/hkgroute.sh | 57 ++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) create mode 100755 scripts/hkgroute/hkgroute.sh diff --git a/generate.sh b/generate.sh index 8fa89a9a0..088026240 100755 --- a/generate.sh +++ b/generate.sh @@ -44,6 +44,9 @@ main() { # chnroute scripts/chnroute/chnroute.sh + # hkgroute + scripts/chnroute/hkgroute.sh + # pac scripts/pac/pac.sh diff --git a/scripts/hkgroute/hkgroute.sh b/scripts/hkgroute/hkgroute.sh new file mode 100755 index 000000000..493ca68b7 --- /dev/null +++ b/scripts/hkgroute/hkgroute.sh @@ -0,0 +1,57 @@ +#!/bin/bash -e +set -o pipefail + +CUR_DIR=$(pwd) +TMP_DIR=$(mktemp -d /tmp/hkgroute.XXXXXX) + +SRC_URL_1="https://ftp.apnic.net/stats/apnic/delegated-apnic-latest" +DEST_FILE_1="dist/hkgroute/hkgroute.txt" +DEST_FILE_2="dist/hkgroute/hkgroute6.txt" + +fetch_src() { + cd $TMP_DIR + + curl -sSL $SRC_URL_1 -o apnic.txt + + cd $CUR_DIR +} + +gen_list_v4() { + cd $TMP_DIR + + # convert to cidr format + cat apnic.txt | grep ipv4 | grep HK | awk -F\| '{ printf("%s/%d\n", 4,ドル 32-log(5ドル)/log(2)) }'> apnic-v4.tmp + + # ipv4 cidr merge + cat apnic-v4.tmp | $CUR_DIR/tools/ip-dedup/obj/ip-dedup -4> hkgroute.txt + + cd $CUR_DIR +} + +gen_list_v6() { + cd $TMP_DIR + + # convert to cidr format + cat apnic.txt | grep ipv6 | grep HK | awk -F\| '{ printf("%s/%d\n", 4,ドル 5ドル) }'> apnic-v6.tmp + + # ipv6 cidr merge + cat apnic-v6.tmp | $CUR_DIR/tools/ip-dedup/obj/ip-dedup -6> hkgroute6.txt + + cd $CUR_DIR +} + +copy_dest() { + install -D -m 644 $TMP_DIR/hkgroute.txt $DEST_FILE_1 + install -D -m 644 $TMP_DIR/hkgroute6.txt $DEST_FILE_2 +} + +clean_up() { + rm -r $TMP_DIR + echo "[$(basename 0ドル .sh)]: done." +} + +fetch_src +gen_list_v4 +gen_list_v6 +copy_dest +clean_up From 637de0f01c24dfa8252d27ba09679c508362585a Mon Sep 17 00:00:00 2001 From: pexcn Date: 2026年3月23日 10:19:50 +0800 Subject: [PATCH 15/16] hkgroute: fix invoke --- generate.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generate.sh b/generate.sh index 088026240..450a6af2c 100755 --- a/generate.sh +++ b/generate.sh @@ -45,7 +45,7 @@ main() { scripts/chnroute/chnroute.sh # hkgroute - scripts/chnroute/hkgroute.sh + scripts/hkgroute/hkgroute.sh # pac scripts/pac/pac.sh From ab48bfd9cb91e264e6cd43da35b4df30d09622b5 Mon Sep 17 00:00:00 2001 From: pexcn Date: 2026年3月23日 10:24:51 +0800 Subject: [PATCH 16/16] hkgroute: update README --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index aa32395a9..1f9d36769 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,8 @@ This script can be automatically generate something what you needed every day. - [`adblock/adblock.conf`](https://raw.githubusercontent.com/pexcn/daily/gh-pages/adblock/adblock.conf) - [`chnroute/chnroute.txt`](https://raw.githubusercontent.com/pexcn/daily/gh-pages/chnroute/chnroute.txt) - [`chnroute/chnroute6.txt`](https://raw.githubusercontent.com/pexcn/daily/gh-pages/chnroute/chnroute6.txt) +- [`hkgroute/hkgroute.txt`](https://raw.githubusercontent.com/pexcn/daily/gh-pages/hkgroute/hkgroute.txt) +- [`hkgroute/hkgroute6.txt`](https://raw.githubusercontent.com/pexcn/daily/gh-pages/hkgroute/hkgroute6.txt) - [`chinalist/chinalist.txt`](https://raw.githubusercontent.com/pexcn/daily/gh-pages/chinalist/chinalist.txt) - [`gfwlist/gfwlist.txt`](https://raw.githubusercontent.com/pexcn/daily/gh-pages/gfwlist/gfwlist.txt) - [`pac/gfwlist.pac`](https://raw.githubusercontent.com/pexcn/daily/gh-pages/pac/gfwlist.pac)

AltStyle によって変換されたページ (->オリジナル) /