From 1f8ef93d7d33758a11ee7bb360fe0d86f6062ad2 Mon Sep 17 00:00:00 2001 From: Nihanth Subramanya Date: Wed, 8 Sep 2021 14:35:57 +0000 Subject: [PATCH] Bug 1634246 - Add option to disallow connections to localhost while in offline mode. r=necko-reviewers,valentin Differential Revision: https://phabricator.services.mozilla.com/D116466 --- modules/libpref/init/StaticPrefList.yaml | 6 +++ netwerk/base/nsSocketTransport2.cpp | 4 +- netwerk/base/nsUDPSocket.cpp | 5 +- netwerk/test/unit/test_localhost_offline.js | 59 +++++++++++++++++++++ netwerk/test/unit/test_udpsocket_offline.js | 36 +++++++++++++ netwerk/test/unit/xpcshell.ini | 1 + 6 files changed, 109 insertions(+), 2 deletions(-) create mode 100644 netwerk/test/unit/test_localhost_offline.js diff --git a/modules/libpref/init/StaticPrefList.yaml b/modules/libpref/init/StaticPrefList.yaml index 9a792daca6e0..da3c1743ef2d 100644 --- a/modules/libpref/init/StaticPrefList.yaml +++ b/modules/libpref/init/StaticPrefList.yaml @@ -9363,6 +9363,12 @@ value: false mirror: always +# If set to true, disallow localhost connections when offline. +- name: network.disable-localhost-when-offline + type: RelaxedAtomicBool + value: false + mirror: always + # Enables the predictive service. - name: network.predictor.enabled type: bool diff --git a/netwerk/base/nsSocketTransport2.cpp b/netwerk/base/nsSocketTransport2.cpp index 44ffc35b26af..bec3da66c86f 100644 --- a/netwerk/base/nsSocketTransport2.cpp +++ b/netwerk/base/nsSocketTransport2.cpp @@ -1204,7 +1204,9 @@ nsresult nsSocketTransport::InitiateSocket() { return NS_ERROR_ABORT; } if (gIOService->IsOffline()) { - if (!isLocal) return NS_ERROR_OFFLINE; + if (StaticPrefs::network_disable_localhost_when_offline() || !isLocal) { + return NS_ERROR_OFFLINE; + } } else if (!isLocal) { #ifdef DEBUG // all IP networking has to be done from the parent diff --git a/netwerk/base/nsUDPSocket.cpp b/netwerk/base/nsUDPSocket.cpp index dcd1a8b34025..817b2d42f28e 100644 --- a/netwerk/base/nsUDPSocket.cpp +++ b/netwerk/base/nsUDPSocket.cpp @@ -31,6 +31,7 @@ #include "nsICancelable.h" #include "nsWrapperCacheInlines.h" #include "HttpConnectionUDP.h" +#include "mozilla/StaticPrefs_network.h" namespace mozilla { namespace net { @@ -72,7 +73,9 @@ static nsresult CheckIOStatus(const NetAddr* aAddr) { return NS_ERROR_FAILURE; } - if (gIOService->IsOffline() && !aAddr->IsLoopbackAddr()) { + if (gIOService->IsOffline() && + (StaticPrefs::network_disable_localhost_when_offline() || + !aAddr->IsLoopbackAddr())) { return NS_ERROR_OFFLINE; } diff --git a/netwerk/test/unit/test_localhost_offline.js b/netwerk/test/unit/test_localhost_offline.js new file mode 100644 index 000000000000..6ae09836b5a1 --- /dev/null +++ b/netwerk/test/unit/test_localhost_offline.js @@ -0,0 +1,59 @@ +"use strict"; + +const { HttpServer } = ChromeUtils.import("resource://testing-common/httpd.js"); +var httpServer = null; + +function makeChan(url) { + let chan = NetUtil.newChannel({ + uri: url, + loadUsingSystemPrincipal: true, + }).QueryInterface(Ci.nsIHttpChannel); + chan.loadFlags |= Ci.nsIRequest.LOAD_BYPASS_CACHE; + chan.loadFlags |= Ci.nsIRequest.INHIBIT_CACHING; + return chan; +} + +function makeURL(host) { + return `http://${host}:${httpServer.identity.primaryPort}/`; +} + +add_task(async function test_localhost_offline() { + Services.io.offline = true; + Services.prefs.setBoolPref("network.disable-localhost-when-offline", false); + let chan = makeChan(makeURL("127.0.0.1")); + await new Promise(resolve => { + chan.asyncOpen(new ChannelListener(resolve)); + }); + + chan = makeChan(makeURL("localhost")); + await new Promise(resolve => { + chan.asyncOpen(new ChannelListener(resolve)); + }); + + Services.prefs.setBoolPref("network.disable-localhost-when-offline", true); + + chan = makeChan(makeURL("127.0.0.1")); + await new Promise(resolve => { + chan.asyncOpen(new ChannelListener(resolve, null, CL_EXPECT_FAILURE)); + }); + chan = makeChan(makeURL("localhost")); + await new Promise(resolve => { + chan.asyncOpen(new ChannelListener(resolve, null, CL_EXPECT_FAILURE)); + }); + + Services.prefs.clearUserPref("network.disable-localhost-when-offline"); + Services.io.offline = false; +}); + +function run_test() { + httpServer = new HttpServer(); + httpServer.registerPathHandler("/", response => { + response.seizePower(); + response.write("HTTP/1.1 200 OK\r\n"); + response.write("\r\n"); + response.write("Hello, world!"); + response.finish(); + }); + httpServer.start(-1); + run_next_test(); +} diff --git a/netwerk/test/unit/test_udpsocket_offline.js b/netwerk/test/unit/test_udpsocket_offline.js index 8f6e351f7ee8..080f54281ddc 100644 --- a/netwerk/test/unit/test_udpsocket_offline.js +++ b/netwerk/test/unit/test_udpsocket_offline.js @@ -76,6 +76,23 @@ add_test(function test_ipv4_loopback() { Assert.ok(false, "unexpected exception: " + e); } + // Now with localhost connections disabled in offline mode. + Services.prefs.setBoolPref("network.disable-localhost-when-offline", true); + socket = Cc["@mozilla.org/network/udp-socket;1"].createInstance( + Ci.nsIUDPSocket + ); + + Assert.throws(() => { + socket.init2( + "127.0.0.1", + -1, + Services.scriptSecurityManager.getSystemPrincipal(), + true + ); + }, /NS_ERROR_OFFLINE/); + + Services.prefs.setBoolPref("network.disable-localhost-when-offline", false); + run_next_test(); }); @@ -95,14 +112,33 @@ add_test(function test_ipv6_loopback() { Assert.ok(false, "unexpected exception: " + e); } + // Now with localhost connections disabled in offline mode. + Services.prefs.setBoolPref("network.disable-localhost-when-offline", true); + socket = Cc["@mozilla.org/network/udp-socket;1"].createInstance( + Ci.nsIUDPSocket + ); + + Assert.throws(() => { + socket.init2( + "::1", + -1, + Services.scriptSecurityManager.getSystemPrincipal(), + true + ); + }, /NS_ERROR_OFFLINE/); + + Services.prefs.setBoolPref("network.disable-localhost-when-offline", false); + run_next_test(); }); function run_test() { // jshint ignore:line Services.io.offline = true; + Services.prefs.setBoolPref("network.disable-localhost-when-offline", false); registerCleanupFunction(() => { Services.io.offline = false; + Services.prefs.clearUserPref("network.disable-localhost-when-offline"); }); run_next_test(); } diff --git a/netwerk/test/unit/xpcshell.ini b/netwerk/test/unit/xpcshell.ini index b0a791817466..4b75891b4023 100644 --- a/netwerk/test/unit/xpcshell.ini +++ b/netwerk/test/unit/xpcshell.ini @@ -243,6 +243,7 @@ skip-if = (toolkit != 'gtk') [test_idna2008.js] [test_immutable.js] run-sequentially = node server exceptions dont replay well +[test_localhost_offline.js] [test_localstreams.js] [test_large_port.js] [test_mismatch_last-modified.js]