From cf08e0d8407b12b05568c8e3378cc832d9976e81 Mon Sep 17 00:00:00 2001 From: iBug Date: Mon, 27 Jul 2020 03:00:37 +0800 Subject: [PATCH] Add domain checking and pattern matching --- build.py | 17 +++++++++++++++++ code.js | 52 +++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 66 insertions(+), 3 deletions(-) diff --git a/build.py b/build.py index 5092b82..82f3fc8 100755 --- a/build.py +++ b/build.py @@ -6,6 +6,8 @@ import ipaddress import requests from requests.exceptions import RequestException, HTTPError +import gfwlist + SOURCES = { 'ipdeny.com': 'http://www.ipdeny.com/ipblocks/data/aggregated/cn-aggregated.zone', @@ -13,6 +15,9 @@ SOURCES = { } OUT_DIR = "dist" +# Stub content to disable GFWList check +GFWLIST_STUB = "var DOMAINS = {};\nvar BLACKPAT = [];\nvar WHITEPAT = [];\n" + def fetch_and_convert(src): response = requests.get(src) @@ -36,6 +41,9 @@ def main(): code = f.read() code = code.replace("@@TIME@@", now.isoformat()[:-7]) + gfwlist_part = gfwlist.generate_pac_partial() + gfwlist_stub = GFWLIST_STUB + os.makedirs(OUT_DIR, mode=0o755, exist_ok=True) for key in SOURCES: print(f"Generating PAC script from source {key}") @@ -45,10 +53,19 @@ def main(): continue except HTTPError: continue + filename = f"pac-{key}.txt" + filename_gfwlist = f"pac-gfwlist-{key}.txt" with open(os.path.join(OUT_DIR, filename), "w") as f: f.write(code) f.write(data) + f.write("\n") + f.write(gfwlist_stub) + with open(os.path.join(OUT_DIR, filename), "w") as f: + f.write(code) + f.write(data) + f.write("\n") + f.write(gfwlist_part) if __name__ == '__main__': diff --git a/code.js b/code.js index 00bd6a1..36c4a62 100644 --- a/code.js +++ b/code.js @@ -1,6 +1,9 @@ // Author: iBug // Time: @@TIME@@ +var proxy = __PROXY__; +var direct = "DIRECT"; + function belongsToSubnet(host, list) { var ip = host.split(".").map(Number); ip = 0x1000000 * ip[0] + 0x10000 * ip[1] + 0x100 * ip[2] + ip[3]; @@ -23,6 +26,38 @@ function belongsToSubnet(host, list) { return (masked ^ list[x][0]) == 0; } +function hasMatchedPattern(text, patterns) { + for (var i = 0; i < patterns.length; i++) { + if (shExpMatch(text, patterns[i]) + return true; + } + return false; +} + +function checkDomainType(host) { + // Check if a domain is blacklisted or whitelisted + var segments = host.split(".").reverse(); + var ptr = DOMAINS; + var type = DOMAINS["@"]; + for (var i = 0; i < segments.length; i++) { + var segment = segments[i]; + ptr = ptr[segment]; + if (ptr === undefined) + break; + if (ptr["@"] !== undefined) + type = ptr["@"]; + } + return type; +} + +function hasWhitelistedPattern(url) { + return hasMatchedPattern(url, WHITEPAT); +} + +function hasBlacklistedPattern(url) { + return hasMatchedPattern(url, BLACKPAT); +} + function isChina(host) { return belongsToSubnet(host, CHINA); } @@ -31,10 +66,21 @@ function isLan(host) { return belongsToSubnet(host, LAN); } -var proxy = "__PROXY__"; -var direct = "DIRECT"; - function FindProxyForURL(url, host) { + if (hasWhitelistedPattern(url)) { + return direct; + } + if (hasBlacklistedPattern(url)) { + return proxy; + } + var domainType = checkDomainType(host); + if (domainType === 0) { + return proxy; + } else if (domainType === 1) { + return direct; + } + + // Fallback to IP whitelist var remote = dnsResolve(host); if (!remote || remote.indexOf(":") !== -1) { // resolution failed or is IPv6 addr