mirror of
https://github.com/iBug/pac.git
synced 2025-07-14 21:32:15 +08:00
185 lines
5.5 KiB
Python
Executable File
185 lines
5.5 KiB
Python
Executable File
#!/usr/bin/python3
|
|
|
|
import os
|
|
from datetime import datetime
|
|
import ipaddress
|
|
import requests
|
|
from requests.exceptions import RequestException, HTTPError
|
|
|
|
import gfwlist
|
|
|
|
SOURCES_4 = {
|
|
'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',
|
|
}
|
|
SOURCES_6 = {
|
|
'gaoyifan': 'https://gaoyifan.github.io/china-operator-ip/china6.txt',
|
|
}
|
|
SOURCES_46 = {
|
|
'maxmind': 'https://github.com/v2fly/geoip/raw/release/text/cn.txt',
|
|
}
|
|
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)
|
|
response.raise_for_status()
|
|
template = "var CHINA = [\n{}\n];\n"
|
|
lines = []
|
|
for iprange in response.text.strip().split("\n"):
|
|
if iprange.find(":") != -1:
|
|
break
|
|
ipnet = ipaddress.IPv4Network(iprange)
|
|
netaddr = int(ipnet.network_address)
|
|
netmask = int(ipnet.netmask)
|
|
s = f" [0x{netaddr:08X}, 0x{netmask:08X}], // {iprange}"
|
|
lines.append(s)
|
|
lines.append(" [0xFFFFFFFF, 0xFFFFFFFF] // 255.255.255.255/32") # use broadcast as a placeholder
|
|
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"):
|
|
if iprange.find(":") == -1:
|
|
continue
|
|
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 write_pac(filename, code, data, data_6, tail):
|
|
with open(os.path.join(OUT_DIR, filename), "w") as f:
|
|
f.write(code)
|
|
f.write(data)
|
|
f.write("\n")
|
|
f.write(data_6)
|
|
f.write("\n")
|
|
f.write(tail)
|
|
|
|
|
|
def main():
|
|
now = datetime.utcnow()
|
|
date = now.strftime("%Y%m%d")
|
|
with open("code.js", "r") as f:
|
|
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_4:
|
|
key_6 = list(SOURCES_6)[0]
|
|
print(f"Generating PAC script from source {key}(IPv4) & {key_6}(IPv6)")
|
|
try:
|
|
data = fetch_and_convert(SOURCES_4[key])
|
|
data_6 = fetch_and_convert_ip6(SOURCES_6[key_6])
|
|
except RequestException:
|
|
continue
|
|
except HTTPError:
|
|
continue
|
|
|
|
filename = f"pac-IPv4_{key}--IPv6_{key_6}.txt"
|
|
filename_gfwlist = f"pac-gfwlist-IPv4_{key}--IPv6_{key_6}.txt"
|
|
write_pac(filename, code, data, data_6, gfwlist_stub)
|
|
write_pac(filename_gfwlist, code, data, data_6, gfwlist_part)
|
|
|
|
for key in SOURCES_46:
|
|
print(f"Generating PAC script from source {key}(IPv4v6)")
|
|
try:
|
|
data = fetch_and_convert(SOURCES_46[key])
|
|
data_6 = fetch_and_convert_ip6(SOURCES_46[key])
|
|
except RequestException:
|
|
continue
|
|
except HTTPError:
|
|
continue
|
|
|
|
filename = f"pac-IPv4v6_{key}.txt"
|
|
filename_gfwlist = f"pac-gfwlist-IPv4v6_{key}.txt"
|
|
write_pac(filename, code, data, data_6, gfwlist_stub)
|
|
write_pac(filename_gfwlist, code, data, data_6, gfwlist_part)
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|