catproxy
Version:
a node proxy or host change tools
175 lines (158 loc) • 5.86 kB
JavaScript
const tls = require('tls');
const fs = require('fs');
const path = require('path');
const https = require('https');
const net = require('net');
const url = require('url');
const options = {
// // These are necessary only if using the client certificate authentication
// key: fs.readFileSync('/Users/jxcao/Downloads/2.key'),
// cert: fs.readFileSync('/Users/jxcao/Downloads/2.crt'),
// // This is necessary only if the server uses the self-signed certificate
ca: [ fs.readFileSync('/Users/jxcao/Downloads/cert.crt') ],
host: "www.baidu.com",
port: 443,
path: "", // cdn/desktop/index/main.0cf10bc449.js
rejectUnauthorized: true,
headers: {
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36",
"cookie": "_ntes_nnid=5f3062f82d960111e41f1f71737ec0be,1479703849476; cid=315803048; P_INFO=jianxcao@126.com|1480318745|1|lmlc|11&19|bej&1480310183&mail_client#bej&null#10#0#0|185051&0|caipiao&kaola&yiyuangou&mail126&blog|jianxcao@126.com;NTES_PASSPORT=bIi5T6IjZ75EbMr.zSmJ8oJpWqZygTaZxPENt00hvuS.8ptA.y5u3P5wLo2O4BseKmewVeM3dQy7S12fhB9.Dvty.YTyO9ArJVqBn411Lw6V9inPMH03sGaPd; _ntes_nuid=e93426bc5f42b96ffb17c509ce4c350c; JSESSIONID0=af9ee4adf26fa50df03fbc7fe5166e47; sid=315803048_1482217522151; _gat=1; _ga=GA1.2.1764537290.1479703850; JSESSIONID=936ECC04A4AD9A2695619FC0F5BDD33B",
"if-modified-since": "Thu, 15 Dec 2016 16:46:57 GMT",
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
"host": "www.baidu.com",
"cache-control": "max-age=0",
"accept-encoding": "gzip, deflate, sdch, br",
"accept-language": "zh-CN,zh;q=0.8,en;q=0.6",
"connection": "keep-alive"
}
};
options.checkServerIdentity = checkServerIdentity;
function checkServerIdentity(host, cert) {
// return new Error("Unknown");
// Create regexp to much hostnames
function regexpify(host, wildcards) {
// Add trailing dot (make hostnames uniform)
if (!host || !host.endsWith('.')) host += '.';
// The same applies to hostname with more than one wildcard,
// if hostname has wildcard when wildcards are not allowed,
// or if there are less than two dots after wildcard (i.e. *.com or *d.com)
//
// also
//
// "The client SHOULD NOT attempt to match a presented identifier in
// which the wildcard character comprises a label other than the
// left-most label (e.g., do not match bar.*.example.net)."
// RFC6125
if (!wildcards && /\*/.test(host) || /[\.\*].*\*/.test(host) ||
/\*/.test(host) && !/\*.*\..+\..+/.test(host)) {
return /$./;
}
// Replace wildcard chars with regexp's wildcard and
// escape all characters that have special meaning in regexps
// (i.e. '.', '[', '{', '*', and others)
var re = host.replace(
/\*([a-z0-9\\-_\.])|[\.,\-\\\^\$+?*\[\]\(\):!\|{}]/g,
function(all, sub) {
if (sub) return '[a-z0-9\\-_]*' + (sub === '-' ? '\\-' : sub);
return '\\' + all;
});
return new RegExp('^' + re + '$', 'i');
}
var dnsNames = [];
var uriNames = [];
const ips = [];
var matchCN = true;
var valid = false;
var reason = 'Unknown reason';
// There're several names to perform check against:
// CN and altnames in certificate extension
// (DNS names, IP addresses, and URIs)
//
// Walk through altnames and generate lists of those names
if (cert.subjectaltname) {
cert.subjectaltname.split(/, /g).forEach(function(altname) {
var option = altname.match(/^(DNS|IP Address|URI):(.*)$/);
if (!option)
return;
if (option[1] === 'DNS') {
dnsNames.push(option[2]);
} else if (option[1] === 'IP Address') {
ips.push(option[2]);
} else if (option[1] === 'URI') {
var uri = url.parse(option[2]);
if (uri) uriNames.push(uri.hostname);
}
});
}
// If hostname is an IP address, it should be present in the list of IP
// addresses.
if (net.isIP(host)) {
valid = ips.some(function(ip) {
return ip === host;
});
if (!valid) {
reason = `IP: ${host} is not in the cert's list: ${ips.join(', ')}`;
}
} else if (cert.subject) {
// Transform hostname to canonical form
if (!host || !host.endsWith('.')) host += '.';
// Otherwise check all DNS/URI records from certificate
// (with allowed wildcards)
dnsNames = dnsNames.map(function(name) {
return regexpify(name, true);
});
// Wildcards ain't allowed in URI names
uriNames = uriNames.map(function(name) {
return regexpify(name, false);
});
dnsNames = dnsNames.concat(uriNames);
if (dnsNames.length > 0) matchCN = false;
// Match against Common Name (CN) only if no supported identifiers are
// present.
//
// "As noted, a client MUST NOT seek a match for a reference identifier
// of CN-ID if the presented identifiers include a DNS-ID, SRV-ID,
// URI-ID, or any application-specific identifier types supported by the
// client."
// RFC6125
if (matchCN) {
var commonNames = cert.subject.CN;
if (Array.isArray(commonNames)) {
for (var i = 0, k = commonNames.length; i < k; ++i) {
dnsNames.push(regexpify(commonNames[i], true));
}
} else {
dnsNames.push(regexpify(commonNames, true));
}
}
valid = dnsNames.some(function(re) {
return re.test(host);
});
if (!valid) {
if (cert.subjectaltname) {
reason =
`Host: ${host} is not in the cert's altnames: ` +
`${cert.subjectaltname}`;
} else {
reason = `Host: ${host} is not cert's CN: ${cert.subject.CN}`;
}
}
} else {
reason = 'Cert is empty';
}
if (!valid) {
var err = new Error(
`Hostname/IP doesn't match certificate's altnames: "${reason}"`);
err.reason = reason;
err.host = host;
err.cert = cert;
return err;
}
};
var req = https.request(options, function(res) {
console.log(res.headers);
res.on('data', function(chunk) {
console.log(chunk);
});
});
req.end();