From 97b3893a5710229a4efaf009d1b1b80d9a3918f0 Mon Sep 17 00:00:00 2001 From: Mike Perry Date: Tue, 10 Sep 2013 17:00:27 -0700 Subject: [PATCH] Bug #5741: Prevent WebSocket DNS leak. This is due to an improper implementation of the WebSocket spec by Mozilla. "There MUST be no more than one connection in a CONNECTING state. If multiple connections to the same IP address are attempted simultaneously, the client MUST serialize them so that there is no more than one connection at a time running through the following steps. If the client cannot determine the IP address of the remote host (for example, because all communication is being done through a proxy server that performs DNS queries itself), then the client MUST assume for the purposes of this step that each host name refers to a distinct remote host," https://tools.ietf.org/html/rfc6455#page-15 They implmented the first paragraph, but not the second... While we're at it, we also prevent the DNS service from being used to look up anything other than IP addresses if socks_remote_dns is set to true, so this bug can't turn up in other components or due to 3rd party addons. --- netwerk/dns/nsDNSService2.cpp | 26 +++++++++++++++++++++++++- netwerk/dns/nsDNSService2.h | 1 + 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/netwerk/dns/nsDNSService2.cpp b/netwerk/dns/nsDNSService2.cpp index 665726360cd17..7cda3d0a5f6f4 100644 --- a/netwerk/dns/nsDNSService2.cpp +++ b/netwerk/dns/nsDNSService2.cpp @@ -53,12 +53,14 @@ static const char kPrefDnsCacheGrace[] = static const char kPrefIPv4OnlyDomains[] = "network.dns.ipv4OnlyDomains"; static const char kPrefDisableIPv6[] = "network.dns.disableIPv6"; static const char kPrefDisablePrefetch[] = "network.dns.disablePrefetch"; +static const char kPrefDisableDNS[] = "network.proxy.socks_remote_dns"; 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"; static const char kPrefNetworkProxyType[] = "network.proxy.type"; +static const char kPrefNetworkProxyPrefix[] = "network.proxy."; //----------------------------------------------------------------------------- @@ -501,6 +503,7 @@ nsDNSService::nsDNSService() mDisableIPv6(false), mDisablePrefetch(false), mBlockDotOnion(false), + mDisableDNS(false), mNotifyResolution(false), mOfflineLocalhost(false), mForceResolveOn(false), @@ -609,6 +612,11 @@ nsresult nsDNSService::ReadPrefs(const char* name) { mProxyType = tmpint; } } + if (!name || !strcmp(name, kPrefDisableDNS)) { + if (NS_SUCCEEDED(Preferences::GetBool(kPrefDisableDNS, &tmpbool))) { + mDisableDNS = tmpbool; + } + } if (!name || !strcmp(name, kPrefIPv4OnlyDomains)) { Preferences::GetCString(kPrefIPv4OnlyDomains, mIPv4OnlyDomains); } @@ -679,7 +687,7 @@ nsDNSService::Init() { // Monitor these to see if there is a change in proxy configuration // If a manual proxy is in use, disable prefetch implicitly - prefs->AddObserver("network.proxy.type", this, false); + prefs->AddObserver(kPrefNetworkProxyPrefix, this, false); } nsDNSPrefetch::Initialize(this); @@ -809,6 +817,14 @@ nsresult nsDNSService::AsyncResolveInternal( NS_DispatchToMainThread(new NotifyDNSResolution(aHostname)); } + PRNetAddr tempAddr; + if (mDisableDNS) { + // Allow IP lookups through, but nothing else. + if (PR_StringToNetAddr(aHostname.BeginReading(), &tempAddr) != PR_SUCCESS) { + return NS_ERROR_UNKNOWN_PROXY_HOST; // XXX: NS_ERROR_NOT_IMPLEMENTED? + } + } + if (!res) return NS_ERROR_OFFLINE; if ((type != RESOLVE_TYPE_DEFAULT) && (type != RESOLVE_TYPE_TXT)) { @@ -1058,6 +1074,14 @@ nsresult nsDNSService::ResolveInternal( flags |= RESOLVE_OFFLINE; } + PRNetAddr tempAddr; + if (mDisableDNS) { + // Allow IP lookups through, but nothing else. + if (PR_StringToNetAddr(aHostname.BeginReading(), &tempAddr) != PR_SUCCESS) { + return NS_ERROR_UNKNOWN_PROXY_HOST; // XXX: NS_ERROR_NOT_IMPLEMENTED? + } + } + // // sync resolve: since the host resolver only works asynchronously, we need // to use a mutex and a condvar to wait for the result. however, since the diff --git a/netwerk/dns/nsDNSService2.h b/netwerk/dns/nsDNSService2.h index e68337681315f..7325a20572654 100644 --- a/netwerk/dns/nsDNSService2.h +++ b/netwerk/dns/nsDNSService2.h @@ -88,6 +88,7 @@ class nsDNSService final : public nsPIDNSService, bool mDisableIPv6; bool mDisablePrefetch; bool mBlockDotOnion; + bool mDisableDNS; bool mNotifyResolution; bool mOfflineLocalhost; bool mForceResolveOn; -- GitLab