Files
gfw-pac/pac-template

163 lines
4.4 KiB
Plaintext

var proxy = __PROXY__;
var direct = 'DIRECT';
var directDomains = __DIRECT_DOMAINS__;
var domainsUsingProxy = __DOMAINS__;
var localTlds = __LOCAL_TLDS__;
var cnips = __CN_IPS__;
var hasOwnProperty = Object.hasOwnProperty;
var ipRegExp = new RegExp(/^(([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])$/);
function isIPv6(ip) {
// Split the IP address into groups of hexadecimal digits
const groups = ip.split(':');
// An IPv6 address must have at least one group and at most 8 groups
if (groups.length < 1 || groups.length > 8) {
return false;
}
// Check that each group is a valid hexadecimal number
for (const group of groups) {
// Check that the group is not null, undefined, or an empty string before calling parseInt()
if (group === null || group === undefined || group === '') {
continue;
}
// Use parseInt() to check if the group is a valid hexadecimal number
const value = parseInt(group, 16);
if (isNaN(value) || value < 0 || value > 0xFFFF) {
return false;
}
}
// If the address contains a double colon, ensure that it appears only once
if (ip.includes('::')) {
if (ip.indexOf('::') !== ip.lastIndexOf('::')) {
return false;
}
}
// The address is valid if it passes all the checks
return true;
}
function convertAddress(ipchars) {
var bytes = ipchars.split('.');
var result = ((bytes[0] & 0xff) << 24) |
((bytes[1] & 0xff) << 16) |
((bytes[2] & 0xff) << 8) |
(bytes[3] & 0xff);
return result;
}
function match(ip) {
var left = 0, right = cnips.length;
do {
var mid = Math.floor((left + right) / 2),
ipf = (ip & cnips[mid][1]) >>> 0,
m = (cnips[mid][0] & cnips[mid][1]) >>> 0;
if (ipf == m) {
return true;
} else if (ipf > m) {
left = mid + 1;
} else {
right = mid;
}
} while (left + 1 <= right)
return false;
}
function isInDirectDomain(host) {
if (hasOwnProperty.call(directDomains, host)) {
return true;
}
for (var domain in directDomains) {
if (host.endsWith('.' + domain)) {
return true;
}
}
return false;
}
function isInProxyDomain(host) {
if (hasOwnProperty.call(domainsUsingProxy, host)) {
return true;
}
for (var domain in domainsUsingProxy) {
if (host.endsWith('.' + domain)) {
return true;
}
}
return false;
}
function isLocalTestDomain(domain) {
// Chrome uses .test as testing gTLD.
var tld = domain.substring(domain.lastIndexOf('.'));
if (tld === domain) {
return false;
}
return Object.hasOwnProperty.call(localTlds, tld);
}
/* https://github.com/frenchbread/private-ip */
function isPrivateIp(ip) {
return /^(::f{4}:)?10\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$/i.test(ip) ||
/^(::f{4}:)?192\.168\.([0-9]{1,3})\.([0-9]{1,3})$/i.test(ip) ||
/^(::f{4}:)?172\.(1[6-9]|2\d|30|31)\.([0-9]{1,3})\.([0-9]{1,3})$/i.test(ip) ||
/^(::f{4}:)?127\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$/i.test(ip) ||
/^(::f{4}:)?169\.254\.([0-9]{1,3})\.([0-9]{1,3})$/i.test(ip) ||
/^f[cd][0-9a-f]{2}:/i.test(ip) ||
/^fe80:/i.test(ip) ||
/^::1$/.test(ip) ||
/^::$/.test(ip);
}
function FindProxyForURL(url, host) {
if (isPlainHostName(host)
|| isPrivateIp(host)
|| isLocalTestDomain(host)
|| host === 'localhost') {
alert(`${host} MATCHES LOCAL, USING DIRECT`)
return direct;
}
if (shExpMatch(url, "http:*")) {
alert(`${host} IS USING HTTP, USING DIRECT`)
return direct;
}
if (!ipRegExp.test(host)) {
if (isInProxyDomain(host)) {
alert(`${host} MATCHES PROXY DOMAIN`)
return proxy;
}
if (isInDirectDomain(host)) {
alert(`${host} MATCHES DIRECT DOMAIN`)
return direct
}
strIp = dnsResolve(host);
} else {
strIp = host
}
if (!strIp) {
return proxy;
}
intIp = convertAddress(strIp);
if (match(intIp)) {
alert(`${host} MATCHES CNIP`)
return direct;
}
alert(`${host} NO RULES WARE MATCHED, USING PROXY`)
return proxy;
}