mirror of
https://github.com/iBug/pac.git
synced 2025-07-14 21:32:15 +08:00
add ipv6 support
This commit is contained in:
parent
d3db3ab5d3
commit
44848fb670
96
build.py
96
build.py
@ -13,6 +13,9 @@ SOURCES = {
|
|||||||
'ipdeny.com': 'http://www.ipdeny.com/ipblocks/data/aggregated/cn-aggregated.zone',
|
'ipdeny.com': 'http://www.ipdeny.com/ipblocks/data/aggregated/cn-aggregated.zone',
|
||||||
'17mon': 'https://raw.githubusercontent.com/17mon/china_ip_list/master/china_ip_list.txt',
|
'17mon': 'https://raw.githubusercontent.com/17mon/china_ip_list/master/china_ip_list.txt',
|
||||||
}
|
}
|
||||||
|
SOURCES2 = {
|
||||||
|
'gaoyifan': 'https://gaoyifan.github.io/china-operator-ip/china6.txt',
|
||||||
|
}
|
||||||
OUT_DIR = "dist"
|
OUT_DIR = "dist"
|
||||||
|
|
||||||
# Stub content to disable GFWList check
|
# Stub content to disable GFWList check
|
||||||
@ -34,6 +37,89 @@ def fetch_and_convert(src):
|
|||||||
return template.format("\n".join(lines))
|
return template.format("\n".join(lines))
|
||||||
|
|
||||||
|
|
||||||
|
def fetch_and_convert_ip6(src):
|
||||||
|
response = requests.get(src)
|
||||||
|
response.raise_for_status()
|
||||||
|
text = response.text
|
||||||
|
|
||||||
|
template = "var CHINA6_F = [\n{}\n];\n\n"
|
||||||
|
template2 = "var CHINA6_S = [\n{}\n];\n"
|
||||||
|
lines = []
|
||||||
|
lines2 = []
|
||||||
|
lastnum = 0
|
||||||
|
count = 0
|
||||||
|
begins = False
|
||||||
|
ends = False
|
||||||
|
lower = 0
|
||||||
|
upper = 0
|
||||||
|
networkstr_b = ""
|
||||||
|
iprangestr_b = ""
|
||||||
|
fixlen = len(f" [0xFFFFFFFF, -1, 0xFFFFFFFF],")
|
||||||
|
|
||||||
|
for iprange in text.strip().split("\n"):
|
||||||
|
ipnet = ipaddress.IPv6Network(iprange)
|
||||||
|
prefixlen = ipnet.prefixlen
|
||||||
|
fulladdr = str(ipnet.exploded).replace(':', '')
|
||||||
|
num1 = int(fulladdr[0:8], 16)
|
||||||
|
num2 = int(fulladdr[8:16], 16)
|
||||||
|
fullmask = f"{ipnet.netmask:X}"
|
||||||
|
mask1 = fullmask[0:8]
|
||||||
|
mask2 = fullmask[8:16]
|
||||||
|
|
||||||
|
if lastnum != num1 and begins:
|
||||||
|
ends = True
|
||||||
|
|
||||||
|
if ends:
|
||||||
|
begins = False
|
||||||
|
ends = False
|
||||||
|
upper = count - 1
|
||||||
|
s2 = networkstr_b
|
||||||
|
if upper == lower:
|
||||||
|
s2 = iprangestr_b
|
||||||
|
s = f" [0x{lastnum:08X}, {lower}, {upper}],"
|
||||||
|
len1 = len(s)
|
||||||
|
if len1 < fixlen:
|
||||||
|
s = s + " " * (fixlen - len1)
|
||||||
|
s = f"{s} // {s2}"
|
||||||
|
lines.append(s)
|
||||||
|
|
||||||
|
if prefixlen <= 32:
|
||||||
|
if begins:
|
||||||
|
raise NameError(f"Invalid list order: \n{iprange}")
|
||||||
|
s = f" [0x{num1:08X}, -1, 0x{mask1}], // {iprange}"
|
||||||
|
lines.append(s)
|
||||||
|
else:
|
||||||
|
if not begins:
|
||||||
|
begins = True
|
||||||
|
lower = count
|
||||||
|
networkstr_b = str(ipnet.exploded)[0:10]
|
||||||
|
iprangestr_b = iprange
|
||||||
|
|
||||||
|
s = f" [0x{num2:08X}, 0x{mask2}], // {count}, {iprange}"
|
||||||
|
lines2.append(s)
|
||||||
|
count = count + 1
|
||||||
|
lastnum = num1
|
||||||
|
|
||||||
|
if begins:
|
||||||
|
begins = False
|
||||||
|
ends = False
|
||||||
|
upper = count - 1
|
||||||
|
s2 = networkstr_b
|
||||||
|
if upper == lower:
|
||||||
|
s2 = iprangestr_b
|
||||||
|
s = f" [0x{lastnum:08X}, {lower}, {upper}],"
|
||||||
|
len1 = len(s)
|
||||||
|
if len1 < fixlen:
|
||||||
|
s = s + " " * (fixlen - len1)
|
||||||
|
s = f"{s} // {s2}"
|
||||||
|
lines.append(s)
|
||||||
|
|
||||||
|
lines.append(" [0xFFFFFFFF, -1, 0xFFFFFFFF] // ffff:ffff::/32 placeholder")
|
||||||
|
lines2.append(f" [0xFFFFFFFF, 0xFFFFFFFF] // {count}, placeholder, not in use")
|
||||||
|
|
||||||
|
return template.format("\n".join(lines)) + template2.format("\n".join(lines2))
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
now = datetime.utcnow()
|
now = datetime.utcnow()
|
||||||
date = now.strftime("%Y%m%d")
|
date = now.strftime("%Y%m%d")
|
||||||
@ -49,22 +135,28 @@ def main():
|
|||||||
print(f"Generating PAC script from source {key}")
|
print(f"Generating PAC script from source {key}")
|
||||||
try:
|
try:
|
||||||
data = fetch_and_convert(SOURCES[key])
|
data = fetch_and_convert(SOURCES[key])
|
||||||
|
key2 = list(SOURCES2)[0]
|
||||||
|
data2 = fetch_and_convert_ip6(SOURCES2[key2])
|
||||||
except RequestException:
|
except RequestException:
|
||||||
continue
|
continue
|
||||||
except HTTPError:
|
except HTTPError:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
filename = f"pac-{key}.txt"
|
filename = f"pac-{key}-{key2}.txt"
|
||||||
filename_gfwlist = f"pac-gfwlist-{key}.txt"
|
filename_gfwlist = f"pac-gfwlist-{key}-{key2}.txt"
|
||||||
with open(os.path.join(OUT_DIR, filename), "w") as f:
|
with open(os.path.join(OUT_DIR, filename), "w") as f:
|
||||||
f.write(code)
|
f.write(code)
|
||||||
f.write(data)
|
f.write(data)
|
||||||
f.write("\n")
|
f.write("\n")
|
||||||
|
f.write(data2)
|
||||||
|
f.write("\n")
|
||||||
f.write(gfwlist_stub)
|
f.write(gfwlist_stub)
|
||||||
with open(os.path.join(OUT_DIR, filename_gfwlist), "w") as f:
|
with open(os.path.join(OUT_DIR, filename_gfwlist), "w") as f:
|
||||||
f.write(code)
|
f.write(code)
|
||||||
f.write(data)
|
f.write(data)
|
||||||
f.write("\n")
|
f.write("\n")
|
||||||
|
f.write(data2)
|
||||||
|
f.write("\n")
|
||||||
f.write(gfwlist_part)
|
f.write(gfwlist_part)
|
||||||
|
|
||||||
|
|
||||||
|
143
code.js
143
code.js
@ -5,6 +5,102 @@
|
|||||||
var proxy = __PROXY__;
|
var proxy = __PROXY__;
|
||||||
var direct = "DIRECT";
|
var direct = "DIRECT";
|
||||||
|
|
||||||
|
// lower: lower_index
|
||||||
|
// upper: (upper_index + 1) / (array_length if upper_index = last)
|
||||||
|
function binarySearch(list, num, lower, upper) {
|
||||||
|
var x = lower, y = upper, middle;
|
||||||
|
while (y - x > 1) {
|
||||||
|
middle = Math.floor((x + y) / 2);
|
||||||
|
if (list[middle][0] > num)
|
||||||
|
y = middle;
|
||||||
|
else
|
||||||
|
x = middle;
|
||||||
|
}
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
function fixLength(text) {
|
||||||
|
if (text.length == 1) return "000" + text;
|
||||||
|
if (text.length == 2) return "00" + text;
|
||||||
|
if (text.length == 3) return "0" + text;
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
function convertToInt(high, low) {
|
||||||
|
if (low.length != 4)
|
||||||
|
return parseInt(high + fixLength(low), 16);
|
||||||
|
return parseInt(high + low, 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isLan_Internal6(parts) {
|
||||||
|
var num = convertToInt(parts[0], parts[1]);
|
||||||
|
var list = LAN6;
|
||||||
|
var x = binarySearch(list, num, 0, list.length);
|
||||||
|
|
||||||
|
return ((num & list[x][1]) === list[x][0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isInNet6(parts, list, list2) {
|
||||||
|
var num = convertToInt(parts[0], parts[1]);
|
||||||
|
var x = binarySearch(list, num, 0, list.length);
|
||||||
|
|
||||||
|
if (list[x][1] == -1)
|
||||||
|
return ((num & list[x][2]) === list[x][0]);
|
||||||
|
|
||||||
|
// not in net (/33 - /64)
|
||||||
|
if (num !== list[x][0])
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var num2 = convertToInt(parts[2], parts[3]);
|
||||||
|
var x2 = binarySearch(list2, num2, list[x][1], list[x][2] + 1);
|
||||||
|
|
||||||
|
return ((num2 & list2[x2][1]) === list2[x2][0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isLanOrChina6(host) {
|
||||||
|
if (host.indexOf("::") === -1) {
|
||||||
|
var groups = host.split(":");
|
||||||
|
if (groups.length != 8)
|
||||||
|
return false; // invalid ipv6 format
|
||||||
|
return isInNet6(groups, CHINA6_F, CHINA6_S) || isInNet6(groups, LAN6_F, LAN6_S);
|
||||||
|
}
|
||||||
|
|
||||||
|
var halfs = host.split("::");
|
||||||
|
var left = halfs[0];
|
||||||
|
var right = halfs[1];
|
||||||
|
if (left.length < 1) left = "0000";
|
||||||
|
if (right.length < 1) right = "0000";
|
||||||
|
|
||||||
|
var groups1 = left.split(":");
|
||||||
|
if (groups1.length > 3)
|
||||||
|
return isInNet6(groups1, CHINA6_F, CHINA6_S) || isInNet6(groups1, LAN6_F, LAN6_S);
|
||||||
|
|
||||||
|
var groups2 = right.split(":");
|
||||||
|
var zeros = 8 - (groups1.length + groups2.length);
|
||||||
|
if (zeros < 2)
|
||||||
|
return false; // invalid ipv6 format
|
||||||
|
|
||||||
|
var parts = ["0", "0", "0", "0"];
|
||||||
|
parts[0] = groups1[0];
|
||||||
|
var i = 1;
|
||||||
|
for (var j = 1; j < groups1.length; j++) {
|
||||||
|
parts[i] = groups1[j];
|
||||||
|
i = i + 1;
|
||||||
|
if (i == 4) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i < 4) {
|
||||||
|
for (var k = 0; k < zeros; k++) {
|
||||||
|
parts[i] = "0000";
|
||||||
|
i = i + 1;
|
||||||
|
if (i == 4) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (i == 3) parts[3] = groups2[0];
|
||||||
|
|
||||||
|
return isInNet6(parts, CHINA6_F, CHINA6_S) || isInNet6(parts, LAN6_F, LAN6_S);
|
||||||
|
}
|
||||||
|
|
||||||
function belongsToSubnet(host, list) {
|
function belongsToSubnet(host, list) {
|
||||||
var ip = convert_addr(host) >>> 0;
|
var ip = convert_addr(host) >>> 0;
|
||||||
|
|
||||||
@ -83,11 +179,34 @@ function FindProxyForURL(url, host) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Fallback to IP whitelist
|
// Fallback to IP whitelist
|
||||||
var remote = dnsResolve(host);
|
|
||||||
if (!remote || remote.indexOf(":") !== -1) {
|
// if host is IPv6
|
||||||
// resolution failed or is IPv6 addr
|
if (host.indexOf(":") !== -1) {
|
||||||
|
if (isLanOrChina6(host)) {
|
||||||
|
return direct;
|
||||||
|
}
|
||||||
return proxy;
|
return proxy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// default resolve IPv4
|
||||||
|
// var remote = dnsResolve(host);
|
||||||
|
// if (!remote) {
|
||||||
|
// // resolution failed
|
||||||
|
// return proxy;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// method for IPv6
|
||||||
|
var ips = dnsResolveEx(host);
|
||||||
|
if (!ips)
|
||||||
|
return proxy;
|
||||||
|
var remote = ips.split(";")[0];
|
||||||
|
if (remote.indexOf(":") !== -1) {
|
||||||
|
if (isLanOrChina6(remote)) {
|
||||||
|
return direct;
|
||||||
|
}
|
||||||
|
return proxy;
|
||||||
|
}
|
||||||
|
|
||||||
if (isLan(remote) || isChina(remote)) {
|
if (isLan(remote) || isChina(remote)) {
|
||||||
return direct;
|
return direct;
|
||||||
}
|
}
|
||||||
@ -104,3 +223,21 @@ var LAN = [
|
|||||||
[0xC0A80000, 0xFFFF0000] // 192.168.0.0/16
|
[0xC0A80000, 0xFFFF0000] // 192.168.0.0/16
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// not support /65 - /128
|
||||||
|
var LAN6_F = [
|
||||||
|
[0x00000000, 0, 0], // ::/64
|
||||||
|
[0x0064FF9B, 1, 2], // 64:ff9b:
|
||||||
|
[0x01000000, 3, 3], // 100::/64
|
||||||
|
[0x20010000, -1, 0xFFFFFFFF], // 2001::/32 - teredo, may remove
|
||||||
|
[0xFC000000, -1, 0xFE000000], // fc00::/7
|
||||||
|
[0xFE800000, -1, 0xFFC00000], // fe80::/10
|
||||||
|
[0xFF000000, -1, 0xFF000000] // ff00::/8
|
||||||
|
];
|
||||||
|
|
||||||
|
var LAN6_S = [
|
||||||
|
[0x00000000, 0xFFFFFFFF], // 0, ::/64 - catch {::, ::1, ::ffff:0:0/96, ::ffff:0:0:0/96}, may remove
|
||||||
|
[0x00000000, 0xFFFFFFFF], // 1, 64:ff9b::/64 - catch {64:ff9b::/96, NAT64}, may remove
|
||||||
|
[0x00010000, 0xFFFF0000], // 2, 64:ff9b:1::/48 - NAT64, may remove
|
||||||
|
[0x00000000, 0xFFFFFFFF] // 3, 100::/64
|
||||||
|
];
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user