Skip to content

Commit

Permalink
CIDR只保留构建树所需的前缀位,减少最终文件体积约100k;树底层使用map替代object提高大约7倍查询效率(实际单次查询差距绝对值…
Browse files Browse the repository at this point in the history
…在0.002ms以下,无意义的优化)
  • Loading branch information
zhiyi7 committed Dec 4, 2024
1 parent 509f516 commit 74e6d0a
Showing 5 changed files with 60 additions and 86 deletions.
1 change: 1 addition & 0 deletions .github/workflows/auto-generate-pac.yml
Original file line number Diff line number Diff line change
@@ -11,6 +11,7 @@ on:
- 'direct-domains.txt'
- 'proxy-domains.txt'
- 'cidrs-cn.txt'
- '!gfw.pac'
workflow_dispatch:

jobs:
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -43,3 +43,5 @@ $RECYCLE.BIN/

# Windows shortcuts
*.lnk

test.js
9 changes: 2 additions & 7 deletions gfw-pac.py
Original file line number Diff line number Diff line change
@@ -27,16 +27,11 @@ def parse_args():
def convert_cidr(cidr):
if '/' in cidr:
network = ipaddress.ip_network(cidr.strip(), strict=False)
network_address = network.network_address
prefixlen = network.prefixlen
network_address = int(network.network_address) >> (network.max_prefixlen - network.prefixlen)
else:
network = ipaddress.ip_address(cidr.strip())
network_address = network
prefixlen = network.max_prefixlen
if network.version == 4:
return hex(int(network_address))[2:] + '/' + str(prefixlen)
else:
return network.compressed
return hex(int(network_address))[2:]

def generate_cnip_cidrs():
""" 从文件中读取CIDR地址 """
68 changes: 28 additions & 40 deletions gfw.pac

Large diffs are not rendered by default.

66 changes: 27 additions & 39 deletions pac-template
Original file line number Diff line number Diff line change
@@ -10,35 +10,45 @@ var localTlds = __LOCAL_TLDS__;

var cidrs = __CIDRS__;

var hasOwnProperty = Object.hasOwnProperty;

function isIpAddress(ip) {
return /^\d{1,3}(\.\d{1,3}){3}$/.test(ip) || /^([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{0,4}$/.test(ip);
}

function RadixTree() {
this.root = {};
this.root = new Map();
}

RadixTree.prototype.insert = function(string) {
var node = this.root;
for (var i = 0; i < string.length; i++) {
var char = string[i];
if (!node[char]) {
node[char] = {};
if (!node.has(char)) {
node.set(char, new Map());
}
node = node[char];
node = node.get(char);
}
};

RadixTree.prototype.to_list = function() {
return this.root;
};
RadixTree.prototype.search = function(string) {
var currentNode = this.root;
var isLastNode = false;
for (var i=0; i < string.length; i++) {
var char = string[i];
if (currentNode.has(char)) {
currentNode = currentNode.get(char);
isLastNode = currentNode.size === 0;
} else {
break;
}
}
return isLastNode;
}

function ipToBinary(ip) {
var bin = ''
// Check if it's IPv4
if (/^\d{1,3}(\.\d{1,3}){3}$/.test(ip)) {
return ip.split('.').map(function(num) {
bin = ip.split('.').map(function(num) {
return ("00000000" + parseInt(num, 10).toString(2)).slice(-8);
}).join('');
} else if (/^([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{0,4}$/.test(ip)) {
@@ -54,25 +64,11 @@ function ipToBinary(ip) {
var fullAddress = left.concat(Array(zeroGroups + 1).join('0').split('')).concat(right);

// Convert each group to binary and pad to 16 bits
return fullAddress.map(function(group) {
bin = fullAddress.map(function(group) {
return ("0000000000000000" + parseInt(group || '0', 16).toString(2)).slice(-16);
}).join('');
}
}

function searchRadixTree(bits) {
var currentNode = radixTree;
var isLastNode = false;
for (var i=0; i<bits.length; i++) {
var char = bits[i];
if (currentNode[char]) {
currentNode = currentNode[char];
isLastNode = Object.keys(currentNode).length === 0;
} else {
break;
}
}
return isLastNode;
return bin.replace(/^0+/, '');
}

function isInDirectDomain(host) {
@@ -142,7 +138,7 @@ function FindProxyForURL(url, host) {
} else if (isPrivateIp(ip)) {
debug('域名解析后命中私有 IP 地址', host, ip);
return direct;
} else if (searchRadixTree(ipToBinary(ip))) {
} else if (radixTree.search(ipToBinary(ip))) {
debug('匹配到直连IP', host, ip);
return direct;
}
@@ -152,7 +148,7 @@ function FindProxyForURL(url, host) {
}

var allowAlert = true
function debug(msg, host, ip) {
function debug(msg, host='', ip='') {
if (!allowAlert) {
return
}
@@ -166,19 +162,11 @@ function debug(msg, host, ip) {
var radixTree = new RadixTree();

(function () {
var startTime = new Date().getMilliseconds();
debug('开始生成 Radix Tree', 'PAC文件载入开始', startTime.toString());
debug('开始生成 Radix Tree', 'PAC文件载入开始');
for (let i=0; i<cidrs.length; i++) {
var cidr = cidrs[i];
var [ip, prefixLen] = cidr.split('/');
if (!cidr.includes(':')) {
var ip = ip.match(/.{1,2}/g).map(function(byte) {
return parseInt(byte, 16);
}).join('.');
}
var bits = ipToBinary(ip).slice(0, prefixLen);
var prefix = cidrs[i];
var bits = (parseInt(prefix, 16)).toString(2);
radixTree.insert(bits);
}
radixTree = radixTree.to_list();
debug('Radix Tree 已生成', 'PAC文件载入完毕', cidrs.length.toString()+'个CIDR条目');
})();

0 comments on commit 74e6d0a

Please sign in to comment.