From 04c6c76b14b30d895d68ad90f624925d0aee07ef Mon Sep 17 00:00:00 2001 From: Martin Schuhfuss Date: Wed, 9 Aug 2017 00:42:28 +0200 Subject: [PATCH] Handle IPv6-addresses correctly in checkHost() Add proper handling of IPv6-addresses to the checkHost()-method. Like IPv4-addresses, IPv6 addresses are always allowed. --- lib/Server.js | 13 +++++++++---- test/Validation.test.js | 21 +++++++++++++++------ 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/lib/Server.js b/lib/Server.js index 0805d8b910..1683ef8a39 100644 --- a/lib/Server.js +++ b/lib/Server.js @@ -11,6 +11,7 @@ const ip = require("ip"); const serveIndex = require("serve-index"); const historyApiFallback = require("connect-history-api-fallback"); const path = require("path"); +const url = require("url"); const selfsigned = require("selfsigned"); const sockjs = require("sockjs"); const spdy = require("spdy"); @@ -439,11 +440,15 @@ Server.prototype.checkHost = function(headers) { // we don't care about port not matching const hostHeader = headers.host; if(!hostHeader) return false; - const idx = hostHeader.indexOf(":"); - const hostname = idx >= 0 ? hostHeader.substr(0, idx) : hostHeader; - // always allow requests with explicit IP-address - if(ip.isV4Format(hostname)) return true; + // use the node url-parser to retrieve the hostname from the host-header. + const hostname = url.parse("//" + hostHeader, false, true).hostname; + + // always allow requests with explicit IPv4 or IPv6-address. + // A note on IPv6 addresses: hostHeader will always contain the brackets denoting + // an IPv6-address in URLs, these are removed from the hostname in url.parse(), + // so we have the pure IPv6-address in hostname. + if(ip.isV4Format(hostname) || ip.isV6Format(hostname)) return true; // always allow localhost host, for convience if(hostname === "localhost") return true; diff --git a/test/Validation.test.js b/test/Validation.test.js index 8da8b29815..6ccc0809fc 100644 --- a/test/Validation.test.js +++ b/test/Validation.test.js @@ -113,13 +113,22 @@ describe("Validation", function() { it("should allow access for every requests using an IP", function() { const options = {}; - const headers = { - host: "192.168.1.123" - }; + const testHosts = [ + "192.168.1.123", + "192.168.1.2:8080", + "[::1]", + "[::1]:8080", + "[ad42::1de2:54c2:c2fa:1234]", + "[ad42::1de2:54c2:c2fa:1234]:8080" + ]; + const server = new Server(compiler, options); - if(!server.checkHost(headers)) { - throw new Error("Validation didn't fail"); - } + testHosts.forEach(function(testHost) { + const headers = { host: testHost }; + if(!server.checkHost(headers)) { + throw new Error("Validation didn't pass"); + } + }); }); it("should not allow hostnames that don't match options.public", function() {