From 5cd60f6ba214fdb08b6aa4c876ddeb3546d8bfda Mon Sep 17 00:00:00 2001 From: avwo Date: Sat, 2 Jun 2018 13:13:48 +0800 Subject: [PATCH] feat: use SNI instead of create random server --- lib/https/ca.js | 6 +++--- lib/https/index.js | 5 ++--- lib/https/util.js | 41 ++++++++++++++++++++++++++++++++++++++--- 3 files changed, 43 insertions(+), 9 deletions(-) diff --git a/lib/https/ca.js b/lib/https/ca.js index 2149717bc..b7da41bc1 100644 --- a/lib/https/ca.js +++ b/lib/https/ca.js @@ -124,10 +124,10 @@ function createCertificate(hostname) { }] } ]); cert.sign(ROOT_KEY, forge.md.sha256.create()); - cert = { + cert = createSecureContext({ key: pki.privateKeyToPem(ROOT_KEY), cert: pki.certificateToPem(cert) - }; + }); cachePairs.set(hostname, cert); return cert; } @@ -168,7 +168,7 @@ function loadCustomCerts() { var altNames = getAltNames(cert); altNames.forEach(function(item) { if (item.type === 2 && !customPairs[item.value]) { - customPairs[item.value] = cert; + customPairs[item.value] = createSecureContext(cert); } }); } catch (e) {} diff --git a/lib/https/index.js b/lib/https/index.js index 21f072e97..cd0394aeb 100644 --- a/lib/https/index.js +++ b/lib/https/index.js @@ -12,8 +12,7 @@ var rules = require('../rules'); var pluginMgr = require('../plugins'); var socketMgr = require('../socket-mgr'); var httpsUtil = require('./util'); -var getDomain = httpsUtil.getDomain; -var serverAgent = httpsUtil.serverAgent; +var getSNIServer = httpsUtil.getSNIServer; var parseReq = require('hparser').parse; var RULE_KEY = 'x-whistle-rule-value'; @@ -602,7 +601,7 @@ module.exports = function(socket, hostname, callback) { abortIfUnavailable(reqSocket); callback(reqSocket); } else { - serverAgent.createServer(getDomain(hostname), handleTlsSocket, function(port) { + getSNIServer(handleTlsSocket, function(port) { reqSocket = net.connect(port, LOCALHOST, function() { tunnelTmplData[reqSocket.localPort] = { clientIp: socket.clientIp, diff --git a/lib/https/util.js b/lib/https/util.js index d809ab013..8d3cf92c5 100644 --- a/lib/https/util.js +++ b/lib/https/util.js @@ -1,8 +1,43 @@ -var serverAgent = require('hagent').serverAgent; +var hagent = require('hagent'); +var tls = require('tls'); var ca = require('./ca'); -serverAgent.createCertificate = ca.createCertificate; -exports.serverAgent = serverAgent; +var createTLSServer = function(options, listener) { + return tls.createServer(options, listener); +}; +var getTLSServer = hagent.create(createTLSServer, 41500); +var callbacks = []; +var TIMEOUT = 3000; +var sniPort; + +var SNICallback = function(serverName, cb) { + serverName = ca.getDomain(serverName); + cb(null, ca.createCertificate(serverName)); +}; + +exports.getSNIServer = function(listener, callback) { + if (sniPort) { + return callback(sniPort); + } + getTLSServer({ SNICallback: SNICallback }, listener, function(server, port) { + var removeServer = function() { + sniPort = null; + try { + server.close(); + } catch(e) {} //重复关闭会导致异常 + }; + server.on('error', removeServer); + var timeout = setTimeout(removeServer, TIMEOUT); + server.once('secureConnection', function() { + clearTimeout(timeout); + }); + sniPort = port; + callbacks.forEach(function(cb) { + cb(sniPort); + }); + }); +}; + exports.getDomain = ca.getDomain; exports.existsCustomCert = ca.existsCustomCert; exports.getRootCAFile = ca.getRootCAFile;