diff --git a/lib/goldilocks.js b/lib/goldilocks.js index 709ade1..e938bfd 100644 --- a/lib/goldilocks.js +++ b/lib/goldilocks.js @@ -80,40 +80,16 @@ module.exports.create = function (deps, config) { } function createTcpForwarder(mod) { - var destination = mod.address.split(':'); - var connected = false; - return function (conn) { - var newConn = deps.net.createConnection({ - port: destination[1] - , host: destination[0] || '127.0.0.1' + var newConnOpts = require('./domain-utils').separatePort(mod.address); - , remoteFamily: conn.remoteFamily - , remoteAddress: conn.remoteAddress - , remotePort: conn.remotePort - }, function () { - connected = true; - - newConn.pipe(conn); - conn.pipe(newConn); - }); - - // Not sure how to effectively report this to the user or client, but we need to listen - // for the event to prevent it from crashing us. - newConn.on('error', function (err) { - if (connected) { - console.error('TCP forward remote error', err); - conn.end(); - } else { - console.log('TCP forward connection error', err); - require('./proxy-err-resp').sendBadGateway(conn, err, config.debug); - } - }); - conn.on('error', function (err) { - console.error('TCP forward client error', err); - newConn.end(); + ['remote', 'local'].forEach(function (end) { + ['Family', 'Address', 'Port'].forEach(function (name) { + newConnOpts[end+name] = conn[end+name]; + }); }); + deps.proxy(conn, newConnOpts); }; } diff --git a/lib/modules/http.js b/lib/modules/http.js index 593e867..9434e03 100644 --- a/lib/modules/http.js +++ b/lib/modules/http.js @@ -275,7 +275,6 @@ module.exports.create = function (deps, conf, greenlockMiddleware) { return false; } - var connected = false; var newConnOpts = separatePort(mod.address); newConnOpts.servername = separatePort(headers.host).host; newConnOpts.data = opts.firstChunk; @@ -284,28 +283,7 @@ module.exports.create = function (deps, conf, greenlockMiddleware) { newConnOpts.remoteAddress = opts.address || conn.remoteAddress; newConnOpts.remotePort = opts.port || conn.remotePort; - var newConn = deps.net.createConnection(newConnOpts, function () { - connected = true; - newConn.write(opts.firstChunk); - newConn.pipe(conn); - conn.pipe(newConn); - }); - - // Not sure how to effectively report this to the user or client, but we need to listen - // for the event to prevent it from crashing us. - newConn.on('error', function (err) { - if (connected) { - console.error('HTTP proxy remote error', err); - conn.end(); - } else { - require('../proxy-err-resp').sendBadGateway(conn, err, conf.debug); - } - }); - conn.on('error', function (err) { - console.error('HTTP proxy client error', err); - newConn.end(); - }); - + deps.proxy(conn, newConnOpts, opts.firstChunk); return true; } diff --git a/lib/modules/tls.js b/lib/modules/tls.js index db642fd..9c00ae1 100644 --- a/lib/modules/tls.js +++ b/lib/modules/tls.js @@ -186,49 +186,24 @@ module.exports.create = function (deps, config, netHandler) { }); function proxy(socket, opts, mod) { - var destination = mod.address.split(':'); - var connected = false; + var newConnOpts = require('../domain-utils').separatePort(mod.address); + newConnOpts.servername = opts.servername; + newConnOpts.data = opts.firstChunk; - var newConn = deps.net.createConnection({ - port: destination[1] - , host: destination[0] || '127.0.0.1' + newConnOpts.remoteFamily = opts.family || extractSocketProp(socket, 'remoteFamily'); + newConnOpts.remoteAddress = opts.address || extractSocketProp(socket, 'remoteAddress'); + newConnOpts.remotePort = opts.port || extractSocketProp(socket, 'remotePort'); - , servername: opts.servername - , data: opts.firstChunk - , remoteFamily: opts.family || extractSocketProp(socket, 'remoteFamily') - , remoteAddress: opts.address || extractSocketProp(socket, 'remoteAddress') - , remotePort: opts.port || extractSocketProp(socket, 'remotePort') - }, function () { - connected = true; - if (!opts.hyperPeek) { - newConn.write(opts.firstChunk); - } - newConn.pipe(socket); - socket.pipe(newConn); - }); - - // Not sure how to effectively report this to the user or client, but we need to listen - // for the event to prevent it from crashing us. - newConn.on('error', function (err) { - if (connected) { - console.error('TLS proxy remote error', err); - socket.end(); + deps.proxy(socket, newConnOpts, opts.firstChunk, function () { + // This function is called in the event of a connection error and should decrypt + // the socket so the proxy module can send a 502 HTTP response. + var tlsOpts = localhostCerts.mergeTlsOptions('localhost.daplie.me', {isServer: true}); + if (opts.hyperPeek) { + return new tls.TLSSocket(socket, tlsOpts); } else { - console.log('TLS proxy connection error', err); - var tlsOpts = localhostCerts.mergeTlsOptions('localhost.daplie.me', {isServer: true}); - var decrypted; - if (opts.hyperPeek) { - decrypted = new tls.TLSSocket(socket, tlsOpts); - } else { - decrypted = new tls.TLSSocket(wrapSocket(socket, opts), tlsOpts); - } - require('../proxy-err-resp').sendBadGateway(decrypted, err, config.debug); + return new tls.TLSSocket(wrapSocket(socket, opts), tlsOpts); } }); - socket.on('error', function (err) { - console.error('TLS proxy client error', err); - newConn.end(); - }); } function terminate(socket, opts) { diff --git a/lib/proxy-conn.js b/lib/proxy-conn.js new file mode 100644 index 0000000..476546c --- /dev/null +++ b/lib/proxy-conn.js @@ -0,0 +1,71 @@ +'use strict'; + +function getRespBody(err, debug) { + if (debug) { + return err.toString(); + } + + if (err.code === 'ECONNREFUSED') { + return 'The connection was refused. Most likely the service being connected to ' + + 'has stopped running or the configuration is wrong.'; + } + + return 'Bad Gateway: ' + err.code; +} + +function sendBadGateway(conn, err, debug) { + var body = getRespBody(err, debug); + + conn.write([ + 'HTTP/1.1 502 Bad Gateway' + , 'Date: ' + (new Date()).toUTCString() + , 'Connection: close' + , 'Content-Type: text/html' + , 'Content-Length: ' + body.length + , '' + , body + ].join('\r\n')); + conn.end(); +} + +module.exports.getRespBody = getRespBody; +module.exports.sendBadGateway = sendBadGateway; + +module.exports.create = function (deps, config) { + return function proxy(conn, newConnOpts, firstChunk, decrypt) { + var connected = false; + var newConn = deps.net.createConnection(newConnOpts, function () { + connected = true; + + if (firstChunk) { + newConn.write(firstChunk); + } + + newConn.pipe(conn); + conn.pipe(newConn); + }); + + newConn.on('error', function (err) { + if (connected) { + // Not sure how to report this to a user or a client. We can assume that some data + // has already been exchanged, so we can't really be sure what we can send in addition + // that wouldn't result in a parse error. + console.log('proxy remote error', err); + conn.end(); + } else { + console.log('proxy connection error', err); + if (decrypt) { + sendBadGateway(decrypt(conn), err, config.debug); + } else { + sendBadGateway(conn, err, config.debug); + } + } + }); + + // Listening for this largely to prevent uncaught exceptions. + conn.on('error', function (err) { + console.log('proxy client error', err); + newConn.end(); + }); + }; +}; diff --git a/lib/proxy-err-resp.js b/lib/proxy-err-resp.js deleted file mode 100644 index c2a35a8..0000000 --- a/lib/proxy-err-resp.js +++ /dev/null @@ -1,32 +0,0 @@ -'use strict'; - -function getRespBody(err, debug) { - if (debug) { - return err.toString(); - } - - if (err.code === 'ECONNREFUSED') { - return 'The connection was refused. Most likely the service being connected to ' - + 'has stopped running or the configuration is wrong.'; - } - - return 'Bad Gateway: ' + err.code; -} - -function sendBadGateway(conn, err, debug) { - var body = getRespBody(err, debug); - - conn.write([ - 'HTTP/1.1 502 Bad Gateway' - , 'Date: ' + (new Date()).toUTCString() - , 'Connection: close' - , 'Content-Type: text/html' - , 'Content-Length: ' + body.length - , '' - , body - ].join('\r\n')); - conn.end(); -} - -module.exports.getRespBody = getRespBody; -module.exports.sendBadGateway = sendBadGateway; diff --git a/lib/worker.js b/lib/worker.js index 79db594..23724cb 100644 --- a/lib/worker.js +++ b/lib/worker.js @@ -9,5 +9,7 @@ process.on('message', function (conf) { // HTTP proxying connection creation is not something we currently control. , net: require('net') }; + deps.proxy = require('./proxy-conn').create(deps, conf); + require('./goldilocks.js').create(deps, conf); });