Skip to content

Commit 0632832

Browse files
committed
Merge pull request #62 from joeferner/sni
add `forceSNI` option to listen method
2 parents a48c3e4 + 843f93c commit 0632832

File tree

2 files changed

+72
-24
lines changed

2 files changed

+72
-24
lines changed

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,9 @@ __Arguments__
115115
* sslCaDir - Path to the certificates cache directory (default: process.cwd() + '/.http-mitm-proxy')
116116
* silent - if set to true, nothing will be written to console (default: false)
117117
* timeout - The number of milliseconds of inactivity before a socket is presumed to have timed out. Defaults to no timeout.
118-
* httpAgent - The [http.Agent](https://nodejs.org/api/http.html#http_class_http_agent) to use when making http requests. Useful for chaining proxys. Defaults to an internal Agent.
119-
* httpsAgent - The [https.Agent](https://nodejs.org/api/https.html#https_class_https_agent) to use when making https requests. Useful for chaining proxys. Defaults to an internal Agent.
118+
* httpAgent - The [http.Agent](https://nodejs.org/api/http.html#http_class_http_agent) to use when making http requests. Useful for chaining proxys. (default: internal Agent)
119+
* httpsAgent - The [https.Agent](https://nodejs.org/api/https.html#https_class_https_agent) to use when making https requests. Useful for chaining proxys. (default: internal Agent)
120+
* forceSNI - force use of [SNI](https://en.wikipedia.org/wiki/Server_Name_Indication) by the client. Allow node-http-mitm-proxy to handle all HTTPS requests with a single internal server.
120121

121122
__Example__
122123

lib/proxy.js

Lines changed: 69 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ Proxy.prototype.listen = function(options) {
4747
this.timeout = options.timeout || 0;
4848
this.httpAgent = options.httpAgent || new http.Agent();
4949
this.httpsAgent = options.httpsAgent || new https.Agent();
50+
this.forceSNI = !!options.forceSNI;
51+
if (this.forceSNI && !this.silent) {
52+
console.log('SNI enabled. Clients not supporting SNI may fail');
53+
}
5054
this.sslCaDir = options.sslCaDir || path.resolve(process.cwd(), '.http-mitm-proxy');
5155
this.ca = new ca(this.sslCaDir);
5256
this.sslServers = {};
@@ -243,7 +247,7 @@ Proxy.prototype._onHttpServerConnect = function(req, socket, head) {
243247
if (sslServer) {
244248
return makeConnection(sslServer.port);
245249
} else {
246-
return openHttpsServer(hostname, function(err, port) {
250+
return getHttpsServer(hostname, function(err, port) {
247251
if (err) {
248252
return self._onError('OPEN_HTTPS_SERVER_ERROR', null, err);
249253
}
@@ -266,7 +270,7 @@ Proxy.prototype._onHttpServerConnect = function(req, socket, head) {
266270
conn.on('error', self._onError.bind(self, 'PROXY_TO_PROXY_SOCKET_ERROR', null));
267271
}
268272

269-
function openHttpsServer(hostname, callback) {
273+
function getHttpsServer(hostname, callback) {
270274
self.onCertificateRequired(hostname, function (err, files) {
271275
async.auto({
272276
'keyFileExists': function(callback) {
@@ -320,33 +324,76 @@ Proxy.prototype._onHttpServerConnect = function(req, socket, head) {
320324
if (err) {
321325
return callback(err);
322326
}
323-
if (!self.silent) {
324-
console.log('starting server for ' + hostname);
325-
}
326-
var httpsServer = https.createServer(results.httpsOptions);
327-
httpsServer.timeout = self.timeout;
328-
httpsServer.on('error', self._onError.bind(self, 'HTTPS_SERVER_ERROR', null));
329-
httpsServer.on('clientError', self._onError.bind(self, 'HTTPS_CLIENT_ERROR', null));
330-
httpsServer.on('connect', self._onHttpServerConnect.bind(self));
331-
httpsServer.on('request', self._onHttpServerRequest.bind(self, true));
332-
self.wssServer = new WebSocket.Server({ server: httpsServer });
333-
self.wssServer.on('connection', self._onWebSocketServerConnect.bind(self, true));
334-
httpsServer.listen(function() {
335-
results.openPort = httpsServer.address().port;
327+
if (self.forceSNI) {
328+
if (self.httpsServer) {
329+
results.openPort = self.httpsPort;
330+
if (!self.silent) {
331+
console.log('creating SNI context for ' + hostname);
332+
}
333+
self.httpsServer.addContext(hostname, results.httpsOptions);
334+
self.sslServers[hostname] = {
335+
port: results.openPort
336+
};
337+
return callback(null, results.openPort);
338+
} else {
339+
if (!self.silent) {
340+
console.log('starting HTTPS server');
341+
}
342+
self.httpsServer = createHttpsServer({}, function(httpsServer, wssServer) {
343+
results.openPort = httpsServer.address().port;
344+
if (!self.silent) {
345+
console.log('HTTPS server started on port %d', results.openPort);
346+
}
347+
self.httpsServer = httpsServer;
348+
self.wssServer = wssServer;
349+
self.httpsPort = results.openPort;
350+
if (!self.silent) {
351+
console.log('creating SNI context for ' + hostname);
352+
}
353+
self.httpsServer.addContext(hostname, results.httpsOptions);
354+
self.sslServers[hostname] = {
355+
port: results.openPort
356+
};
357+
return callback(null, results.openPort);
358+
});
359+
}
360+
} else {
336361
if (!self.silent) {
337-
console.log('server started for %s on port %d', hostname, results.openPort);
362+
console.log('starting server for ' + hostname);
338363
}
339-
self.sslServers[hostname] = {
340-
port: results.openPort,
341-
server: httpsServer
342-
};
343-
callback(null, results.openPort);
344-
});
364+
createHttpsServer(results.httpsOptions, function(httpsServer, wssServer) {
365+
results.openPort = httpsServer.address().port;
366+
if (!self.silent) {
367+
console.log('server started for %s on port %d', hostname, results.openPort);
368+
}
369+
self.sslServers[hostname] = {
370+
port: results.openPort,
371+
server: httpsServer,
372+
wsServer: wssServer
373+
};
374+
return callback(null, results.openPort);
375+
});
376+
}
345377
});
346378
});
347379
}
380+
381+
function createHttpsServer(options, callback) {
382+
var httpsServer = https.createServer(options);
383+
httpsServer.timeout = self.timeout;
384+
httpsServer.on('error', self._onError.bind(self, 'HTTPS_SERVER_ERROR', null));
385+
httpsServer.on('clientError', self._onError.bind(self, 'HTTPS_CLIENT_ERROR', null));
386+
httpsServer.on('connect', self._onHttpServerConnect.bind(self));
387+
httpsServer.on('request', self._onHttpServerRequest.bind(self, true));
388+
var wssServer = new WebSocket.Server({ server: httpsServer });
389+
wssServer.on('connection', self._onWebSocketServerConnect.bind(self, true));
390+
httpsServer.listen(function() {
391+
callback(httpsServer, wssServer);
392+
});
393+
}
348394
};
349395

396+
350397
Proxy.prototype.onCertificateRequired = function (hostname, callback) {
351398
var self = this;
352399
return callback(null, {

0 commit comments

Comments
 (0)