From 19a63a0f253cf0fe14f201c0c51a666fe767e9fb Mon Sep 17 00:00:00 2001 From: Zach Bloomquist Date: Fri, 15 Mar 2019 01:01:50 -0400 Subject: [PATCH] Only listen on loopback interfaces (#3666) * https-proxy, server: only listen on loopback for ipv4/v6 * server: use supplied port * https-proxy, server: remove ::1 listener * server: add test that all servers only listen on lo, not other interfaces --- packages/https-proxy/lib/server.coffee | 2 +- packages/server/lib/file_server.coffee | 4 +-- packages/server/lib/server.coffee | 11 +++---- packages/server/test/unit/server_spec.coffee | 32 ++++++++++++++++++++ 4 files changed, 39 insertions(+), 10 deletions(-) diff --git a/packages/https-proxy/lib/server.coffee b/packages/https-proxy/lib/server.coffee index 8d804a5401..2cf8979f7f 100644 --- a/packages/https-proxy/lib/server.coffee +++ b/packages/https-proxy/lib/server.coffee @@ -164,7 +164,7 @@ class Server @_sniServer.on "upgrade", @_onUpgrade.bind(@, options.onUpgrade) @_sniServer.on "request", @_onRequest.bind(@, options.onRequest) - @_sniServer.listen => + @_sniServer.listen 0, '127.0.0.1', => ## store the port of our current sniServer @_sniPort = @_sniServer.address().port diff --git a/packages/server/lib/file_server.coffee b/packages/server/lib/file_server.coffee index 2ab385e298..254dcf1e49 100644 --- a/packages/server/lib/file_server.coffee +++ b/packages/server/lib/file_server.coffee @@ -40,7 +40,7 @@ module.exports = { allowDestroy(srv) - srv.listen -> + srv.listen 0, '127.0.0.1', -> resolve({ port: -> srv.address().port @@ -50,5 +50,5 @@ module.exports = { close: -> srv.destroyAsync() - }) + }) } diff --git a/packages/server/lib/server.coffee b/packages/server/lib/server.coffee index cff31142c9..4899c9ef91 100644 --- a/packages/server/lib/server.coffee +++ b/packages/server/lib/server.coffee @@ -255,20 +255,17 @@ class Server _listen: (port, onError) -> new Promise (resolve) => listener = => - port = @_server.address().port + address = @_server.address() @isListening = true - debug("Server listening on port %s", port) + debug("Server listening on ", address) @_server.removeListener "error", onError - resolve(port) + resolve(address.port) - ## nuke port from our args if its falsy - args = _.compact([port, listener]) - - @_server.listen.apply(@_server, args) + @_server.listen(port || 0, '127.0.0.1', listener) _getRemoteState: -> # { diff --git a/packages/server/test/unit/server_spec.coffee b/packages/server/test/unit/server_spec.coffee index b1fb551ad0..a80f135fea 100644 --- a/packages/server/test/unit/server_spec.coffee +++ b/packages/server/test/unit/server_spec.coffee @@ -1,6 +1,7 @@ require("../spec_helper") _ = require("lodash") +os = require("os") http = require("http") express = require("express") Promise = require("bluebird") @@ -29,6 +30,7 @@ describe "lib/server", -> @config = cfg @server = Server() + @oldFileServer = @server._fileServer @server._fileServer = @fileServer afterEach -> @@ -114,6 +116,36 @@ describe "lib/server", -> .spread (port) => expect(port).to.eq(@port) + it "all servers listen only on localhost and no other interface", -> + fileServer.create.restore() + @server._fileServer = @oldFileServer + + interfaces = _.flatten(_.values(os.networkInterfaces())) + nonLoopback = interfaces.find (iface) => + iface.family == "IPv4" && iface.address != "127.0.0.1" + + ## verify that we can connect to `port` over loopback + ## and not over another configured IPv4 address + tryOnlyLoopbackConnect = (port) => + Promise.all([ + connect.byPortAndAddress(port, "127.0.0.1") + connect.byPortAndAddress(port, nonLoopback) + .then -> + throw new Error("Shouldn't be able to connect on #{nonLoopback.address}:#{port}") + .catch { errno: "ECONNREFUSED" }, -> + ]) + + @server.createServer(@app, {}) + .spread (port) => + Promise.map( + [ + port + @server._fileServer.port() + @server._httpsProxy._sniPort + ], + tryOnlyLoopbackConnect + ) + it "resolves with warning if cannot connect to baseUrl", -> sinon.stub(connect, "ensureUrl").rejects() @server.createServer(@app, {port: @port, baseUrl: "http://localhost:#{@port}"})