Bug 1361099 - provide a way to map all dns to constant r?valentin draft
authorPatrick McManus <mcmanus@ducksong.com>
Mon, 01 May 2017 13:51:55 -0400
changeset 571415 e2778938ecc43136ac225c7a573b994aca1707cf
parent 571414 bfc7b187005cabbc828ed9f5b61daf139c3cfd90
child 626755 76c2deaafdba7b44397f2bd742664995a0add895
push id56782
push userbmo:mcmanus@ducksong.com
push dateTue, 02 May 2017 15:42:35 +0000
reviewersvalentin
bugs1361099
milestone55.0a1
Bug 1361099 - provide a way to map all dns to constant r?valentin // When non empty all non-localhost DNS queries (including IP addresses) // resolve to this value. The value can be a name or an IP address. // domains mapped to localhost with localDomains stay localhost. pref("network.dns.forceResolve", ""); Testing is the primary use case here - replay captive data on a 'fake server' by directing all traffic to it at the DNS level. Chrome has something similar. MozReview-Commit-ID: 7AOgQZpZKec
modules/libpref/init/all.js
netwerk/dns/nsDNSService2.cpp
netwerk/dns/nsDNSService2.h
netwerk/test/unit/test_dns_localredirect.js
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -1913,16 +1913,21 @@ pref("network.dns.disablePrefetch", fals
 
 // This preference controls whether .onion hostnames are
 // rejected before being given to DNS. RFC 7686
 pref("network.dns.blockDotOnion", true);
 
 // These domains are treated as localhost equivalent
 pref("network.dns.localDomains", "");
 
+// When non empty all non-localhost DNS queries (including IP addresses)
+// resolve to this value. The value can be a name or an IP address.
+// domains mapped to localhost with localDomains stay localhost.
+pref("network.dns.forceResolve", "");
+
 // Contols whether or not "localhost" should resolve when offline
 pref("network.dns.offline-localhost", true);
 
 // The maximum allowed length for a URL - 1MB default
 pref("network.standard-url.max-length", 1048576);
 
 // The preference controls if the rust URL parser is run in parallel with the
 // C++ implementation. Requires restart for changes to take effect.
--- a/netwerk/dns/nsDNSService2.cpp
+++ b/netwerk/dns/nsDNSService2.cpp
@@ -45,16 +45,17 @@ using namespace mozilla::net;
 static const char kPrefDnsCacheEntries[]     = "network.dnsCacheEntries";
 static const char kPrefDnsCacheExpiration[]  = "network.dnsCacheExpiration";
 static const char kPrefDnsCacheGrace[]       = "network.dnsCacheExpirationGracePeriod";
 static const char kPrefIPv4OnlyDomains[]     = "network.dns.ipv4OnlyDomains";
 static const char kPrefDisableIPv6[]         = "network.dns.disableIPv6";
 static const char kPrefDisablePrefetch[]     = "network.dns.disablePrefetch";
 static const char kPrefBlockDotOnion[]       = "network.dns.blockDotOnion";
 static const char kPrefDnsLocalDomains[]     = "network.dns.localDomains";
+static const char kPrefDnsForceResolve[]     = "network.dns.forceResolve";
 static const char kPrefDnsOfflineLocalhost[] = "network.dns.offline-localhost";
 static const char kPrefDnsNotifyResolution[] = "network.dns.notifyResolution";
 
 //-----------------------------------------------------------------------------
 
 class nsDNSRecord : public nsIDNSRecord
 {
 public:
@@ -477,16 +478,17 @@ private:
 
 nsDNSService::nsDNSService()
     : mLock("nsDNSServer.mLock")
     , mDisableIPv6(false)
     , mDisablePrefetch(false)
     , mFirstTime(true)
     , mNotifyResolution(false)
     , mOfflineLocalhost(false)
+    , mForceResolveOn(false)
 {
 }
 
 nsDNSService::~nsDNSService() = default;
 
 NS_IMPL_ISUPPORTS(nsDNSService, nsIDNSService, nsPIDNSService, nsIObserver,
                   nsIMemoryReporter)
 
@@ -541,32 +543,34 @@ nsDNSService::Init()
     bool     offlineLocalhost = true;
     bool     disablePrefetch  = false;
     bool     blockDotOnion    = true;
     int      proxyType        = nsIProtocolProxyService::PROXYCONFIG_DIRECT;
     bool     notifyResolution = false;
 
     nsAdoptingCString ipv4OnlyDomains;
     nsAdoptingCString localDomains;
+    nsAdoptingCString forceResolve;
 
     // read prefs
     nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
     if (prefs) {
         int32_t val;
         if (NS_SUCCEEDED(prefs->GetIntPref(kPrefDnsCacheEntries, &val)))
             maxCacheEntries = (uint32_t) val;
         if (NS_SUCCEEDED(prefs->GetIntPref(kPrefDnsCacheExpiration, &val)))
             defaultCacheLifetime = val;
         if (NS_SUCCEEDED(prefs->GetIntPref(kPrefDnsCacheGrace, &val)))
             defaultGracePeriod = val;
 
         // ASSUMPTION: pref branch does not modify out params on failure
         prefs->GetBoolPref(kPrefDisableIPv6, &disableIPv6);
         prefs->GetCharPref(kPrefIPv4OnlyDomains, getter_Copies(ipv4OnlyDomains));
         prefs->GetCharPref(kPrefDnsLocalDomains, getter_Copies(localDomains));
+        prefs->GetCharPref(kPrefDnsForceResolve, getter_Copies(forceResolve));
         prefs->GetBoolPref(kPrefDnsOfflineLocalhost, &offlineLocalhost);
         prefs->GetBoolPref(kPrefDisablePrefetch, &disablePrefetch);
         prefs->GetBoolPref(kPrefBlockDotOnion, &blockDotOnion);
 
         // If a manual proxy is in use, disable prefetch implicitly
         prefs->GetIntPref("network.proxy.type", &proxyType);
         prefs->GetBoolPref(kPrefDnsNotifyResolution, &notifyResolution);
 
@@ -574,16 +578,17 @@ nsDNSService::Init()
             mFirstTime = false;
 
             // register as prefs observer
             prefs->AddObserver(kPrefDnsCacheEntries, this, false);
             prefs->AddObserver(kPrefDnsCacheExpiration, this, false);
             prefs->AddObserver(kPrefDnsCacheGrace, this, false);
             prefs->AddObserver(kPrefIPv4OnlyDomains, this, false);
             prefs->AddObserver(kPrefDnsLocalDomains, this, false);
+            prefs->AddObserver(kPrefDnsForceResolve, this, false);
             prefs->AddObserver(kPrefDisableIPv6, this, false);
             prefs->AddObserver(kPrefDnsOfflineLocalhost, this, false);
             prefs->AddObserver(kPrefDisablePrefetch, this, false);
             prefs->AddObserver(kPrefBlockDotOnion, this, false);
             prefs->AddObserver(kPrefDnsNotifyResolution, this, false);
 
             // Monitor these to see if there is a change in proxy configuration
             // If a manual proxy is in use, disable prefetch implicitly
@@ -611,16 +616,18 @@ nsDNSService::Init()
         // now, set all of our member variables while holding the lock
         MutexAutoLock lock(mLock);
         mResolver = res;
         mIDN = idn;
         mIPv4OnlyDomains = ipv4OnlyDomains; // exchanges buffer ownership
         mOfflineLocalhost = offlineLocalhost;
         mDisableIPv6 = disableIPv6;
         mBlockDotOnion = blockDotOnion;
+        mForceResolve = forceResolve;
+        mForceResolveOn = !mForceResolve.IsEmpty();
 
         // Disable prefetching either by explicit preference or if a manual proxy is configured 
         mDisablePrefetch = disablePrefetch || (proxyType == nsIProtocolProxyService::PROXYCONFIG_MANUAL);
 
         mLocalDomains.Clear();
         if (localDomains) {
             nsCCharSeparatedTokenizer tokenizer(localDomains, ',',
                                                 nsCCharSeparatedTokenizer::SEPARATOR_OPTIONAL);
@@ -701,16 +708,25 @@ nsDNSService::PreprocessHostname(bool   
         return NS_ERROR_UNKNOWN_HOST;
     }
 
     if (aLocalDomain) {
         aACE.AssignLiteral("localhost");
         return NS_OK;
     }
 
+    if (mForceResolveOn) {
+        MutexAutoLock lock(mLock);
+        if (!aInput.LowerCaseEqualsASCII("localhost") &&
+            !aInput.LowerCaseEqualsASCII("127.0.0.1")) {
+            aACE.Assign(mForceResolve);
+            return NS_OK;
+        }
+    }
+
     if (!aIDN || IsASCII(aInput)) {
         aACE = aInput;
         return NS_OK;
     }
 
     if (!(IsUTF8(aInput) && NS_SUCCEEDED(aIDN->ConvertUTF8toACE(aInput, aACE)))) {
         return NS_ERROR_FAILURE;
     }
--- a/netwerk/dns/nsDNSService2.h
+++ b/netwerk/dns/nsDNSService2.h
@@ -55,18 +55,20 @@ private:
 
     // mLock protects access to mResolver and mIPv4OnlyDomains
     mozilla::Mutex            mLock;
 
     // mIPv4OnlyDomains is a comma-separated list of domains for which only
     // IPv4 DNS lookups are performed. This allows the user to disable IPv6 on
     // a per-domain basis and work around broken DNS servers. See bug 68796.
     nsAdoptingCString                         mIPv4OnlyDomains;
+    nsAdoptingCString                         mForceResolve;
     bool                                      mDisableIPv6;
     bool                                      mDisablePrefetch;
     bool                                      mBlockDotOnion;
     bool                                      mFirstTime;
     bool                                      mNotifyResolution;
     bool                                      mOfflineLocalhost;
+    bool                                      mForceResolveOn;
     nsTHashtable<nsCStringHashKey>            mLocalDomains;
 };
 
 #endif //nsDNSService2_h__
--- a/netwerk/test/unit/test_dns_localredirect.js
+++ b/netwerk/test/unit/test_dns_localredirect.js
@@ -1,18 +1,19 @@
 var dns = Cc["@mozilla.org/network/dns-service;1"].getService(Ci.nsIDNSService);
 var prefs = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
 
+var nextTest;
+
 var listener = {
   onLookupComplete: function(inRequest, inRecord, inStatus) {
     var answer = inRecord.getNextAddrAsString();
     do_check_true(answer == "127.0.0.1" || answer == "::1");
 
-    prefs.clearUserPref("network.dns.localDomains");
-
+    nextTest();
     do_test_finished();
   },
   QueryInterface: function(aIID) {
     if (aIID.equals(Ci.nsIDNSListener) ||
         aIID.equals(Ci.nsISupports)) {
       return this;
     }
     throw Cr.NS_ERROR_NO_INTERFACE;
@@ -21,14 +22,30 @@ var listener = {
 
 const defaultOriginAttributes = {};
 
 function run_test() {
   prefs.setCharPref("network.dns.localDomains", "local.vingtetun.org");
 
   var threadManager = Cc["@mozilla.org/thread-manager;1"].getService(Ci.nsIThreadManager);
   var mainThread = threadManager.currentThread;
+  nextTest = do_test_2;
   dns.asyncResolve("local.vingtetun.org", 0, listener,
                    mainThread, defaultOriginAttributes);
 
   do_test_pending();
 }
 
+function do_test_2() {
+  var threadManager = Cc["@mozilla.org/thread-manager;1"].getService(Ci.nsIThreadManager);
+  var mainThread = threadManager.currentThread;
+  nextTest = testsDone;
+  prefs.setCharPref("network.dns.forceResolve", "localhost");
+  dns.asyncResolve("www.example.com", 0, listener, mainThread, defaultOriginAttributes);
+
+  do_test_pending();
+}
+
+function testsDone() {
+  prefs.clearUserPref("network.dns.localDomains");
+  prefs.clearUserPref("network.dns.forceResolve");
+}
+