From 71ac3c2c5eddc0b9665e27d6dc964b9c545d7d5f Mon Sep 17 00:00:00 2001 From: Steve Workman Date: Sat, 26 Oct 2013 13:27:23 -0700 Subject: [PATCH] Bug 853423 - Block speculative connections for local IP addresses r=mcmanus --- CLOBBER | 2 +- netwerk/base/public/nsISocketTransport.idl | 6 +++++ netwerk/base/src/nsSocketTransport2.cpp | 22 ++++++++++++++++ netwerk/dns/DNS.cpp | 26 +++++++++++++++++++ netwerk/dns/DNS.h | 2 ++ .../protocol/http/nsHttpConnectionInfo.cpp | 20 ++++++++++++++ netwerk/protocol/http/nsHttpConnectionInfo.h | 3 +++ netwerk/protocol/http/nsHttpConnectionMgr.cpp | 16 ++++++++++-- 8 files changed, 94 insertions(+), 3 deletions(-) diff --git a/CLOBBER b/CLOBBER index ae60a813d69..f710260345c 100644 --- a/CLOBBER +++ b/CLOBBER @@ -18,4 +18,4 @@ # Modifying this file will now automatically clobber the buildbot machines \o/ # -Bug 914270 needs a clobber since moving variables to moz.build always requires a clobber (bug 852814) +Bug 853423 - New code (inc. new function IsIPAddrLocal) is not being included in incremental builds. diff --git a/netwerk/base/public/nsISocketTransport.idl b/netwerk/base/public/nsISocketTransport.idl index 50173d338d6..f225f4e27d7 100644 --- a/netwerk/base/public/nsISocketTransport.idl +++ b/netwerk/base/public/nsISocketTransport.idl @@ -176,6 +176,12 @@ interface nsISocketTransport : nsITransport */ const unsigned long DISABLE_IPV4 = (1 << 4); + /** + * If set, indicates that the socket should not connect if the hostname + * resolves to an RFC1918 address or IPv6 equivalent. + */ + const unsigned long DISABLE_RFC1918 = (1 << 5); + /** * Socket QoS/ToS markings. Valid values are IPTOS_DSCP_AFxx or * IPTOS_CLASS_CSx (or IPTOS_DSCP_EF, but currently no supported diff --git a/netwerk/base/src/nsSocketTransport2.cpp b/netwerk/base/src/nsSocketTransport2.cpp index d09b46f2ed1..7e37bbbd726 100644 --- a/netwerk/base/src/nsSocketTransport2.cpp +++ b/netwerk/base/src/nsSocketTransport2.cpp @@ -1161,6 +1161,28 @@ nsSocketTransport::InitiateSocket() return NS_ERROR_OFFLINE; } + // Hosts/Proxy Hosts that are Local IP Literals should not be speculatively + // connected - Bug 853423. + if (mConnectionFlags & nsISocketTransport::DISABLE_RFC1918 && + IsIPAddrLocal(&mNetAddr)) { +#ifdef PR_LOGGING + if (SOCKET_LOG_ENABLED()) { + nsAutoCString netAddrCString; + netAddrCString.SetCapacity(kIPv6CStrBufSize); + if (!NetAddrToString(&mNetAddr, + netAddrCString.BeginWriting(), + kIPv6CStrBufSize)) + netAddrCString = NS_LITERAL_CSTRING(""); + SOCKET_LOG(("nsSocketTransport::InitiateSocket skipping " + "speculative connection for host [%s:%d] proxy " + "[%s:%d] with Local IP address [%s]", + mHost.get(), mPort, mProxyHost.get(), mProxyPort, + netAddrCString.get())); + } +#endif + return NS_ERROR_CONNECTION_REFUSED; + } + // // find out if it is going to be ok to attach another socket to the STS. // if not then we have to wait for the STS to tell us that it is ok. diff --git a/netwerk/dns/DNS.cpp b/netwerk/dns/DNS.cpp index cf1a284f506..f953e457dd6 100644 --- a/netwerk/dns/DNS.cpp +++ b/netwerk/dns/DNS.cpp @@ -177,6 +177,32 @@ bool IsIPAddrV4Mapped(const NetAddr *addr) return false; } +bool IsIPAddrLocal(const NetAddr *addr) +{ + MOZ_ASSERT(addr); + + // IPv4 RFC1918 and Link Local Addresses. + if (addr->raw.family == AF_INET) { + uint32_t addr32 = ntohl(addr->inet.ip); + if (addr32 >> 24 == 0x0A || // 10/8 prefix (RFC 1918). + addr32 >> 20 == 0xAC1 || // 172.16/12 prefix (RFC 1918). + addr32 >> 16 == 0xC0A8 || // 192.168/16 prefix (RFC 1918). + addr32 >> 16 == 0xA9FE) { // 169.254/16 prefix (Link Local). + return true; + } + } + // IPv6 Unique and Link Local Addresses. + if (addr->raw.family == AF_INET6) { + uint16_t addr16 = ntohs(addr->inet6.ip.u16[0]); + if (addr16 >> 9 == 0xfc >> 1 || // fc00::/7 Unique Local Address. + addr16 >> 6 == 0xfe80 >> 6) { // fe80::/10 Link Local Address. + return true; + } + } + // Not an IPv4/6 local address. + return false; +} + NetAddrElement::NetAddrElement(const PRNetAddr *prNetAddr) { PRNetAddrToNetAddr(prNetAddr, &mAddress); diff --git a/netwerk/dns/DNS.h b/netwerk/dns/DNS.h index 4fe64bafb84..e4f0b956b40 100644 --- a/netwerk/dns/DNS.h +++ b/netwerk/dns/DNS.h @@ -160,6 +160,8 @@ bool IsIPAddrAny(const NetAddr *addr); bool IsIPAddrV4Mapped(const NetAddr *addr); +bool IsIPAddrLocal(const NetAddr *addr); + } // namespace net } // namespace mozilla diff --git a/netwerk/protocol/http/nsHttpConnectionInfo.cpp b/netwerk/protocol/http/nsHttpConnectionInfo.cpp index 01c58ada531..42d1a793469 100644 --- a/netwerk/protocol/http/nsHttpConnectionInfo.cpp +++ b/netwerk/protocol/http/nsHttpConnectionInfo.cpp @@ -8,6 +8,10 @@ #include "HttpLog.h" #include "nsHttpConnectionInfo.h" +#include "mozilla/net/DNS.h" +#include "prnetdb.h" + +using namespace mozilla::net; nsHttpConnectionInfo::nsHttpConnectionInfo(const nsACString &host, int32_t port, nsProxyInfo* proxyInfo, @@ -113,3 +117,19 @@ nsHttpConnectionInfo::UsingProxy() return !mProxyInfo->IsDirect(); } +bool +nsHttpConnectionInfo::HostIsLocalIPLiteral() const +{ + PRNetAddr prAddr; + // If the host/proxy host is not an IP address literal, return false. + if (ProxyHost()) { + if (PR_StringToNetAddr(ProxyHost(), &prAddr) != PR_SUCCESS) { + return false; + } + } else if (PR_StringToNetAddr(Host(), &prAddr) != PR_SUCCESS) { + return false; + } + NetAddr netAddr; + PRNetAddrToNetAddr(&prAddr, &netAddr); + return IsIPAddrLocal(&netAddr); +} diff --git a/netwerk/protocol/http/nsHttpConnectionInfo.h b/netwerk/protocol/http/nsHttpConnectionInfo.h index 08584fb220c..128f94b2911 100644 --- a/netwerk/protocol/http/nsHttpConnectionInfo.h +++ b/netwerk/protocol/http/nsHttpConnectionInfo.h @@ -92,6 +92,9 @@ public: // Returns true for any kind of proxy (http, socks, etc..) bool UsingProxy(); + // Returns true when mHost is an RFC1918 literal. + bool HostIsLocalIPLiteral() const; + private: mozilla::ThreadSafeAutoRefCnt mRef; nsCString mHashKey; diff --git a/netwerk/protocol/http/nsHttpConnectionMgr.cpp b/netwerk/protocol/http/nsHttpConnectionMgr.cpp index 7e0ba535040..aab574b8d78 100644 --- a/netwerk/protocol/http/nsHttpConnectionMgr.cpp +++ b/netwerk/protocol/http/nsHttpConnectionMgr.cpp @@ -357,6 +357,14 @@ nsHttpConnectionMgr::SpeculativeConnect(nsHttpConnectionInfo *ci, LOG(("nsHttpConnectionMgr::SpeculativeConnect [ci=%s]\n", ci->HashKey().get())); + // Hosts that are Local IP Literals should not be speculatively + // connected - Bug 853423. + if (ci && ci->HostIsLocalIPLiteral()) { + LOG(("nsHttpConnectionMgr::SpeculativeConnect skipping RFC1918 " + "address [%s]", ci->Host())); + return NS_OK; + } + nsRefPtr args = new SpeculativeConnectArgs(); // Wrap up the callbacks and the target to ensure they're released on the target @@ -1984,13 +1992,13 @@ nsHttpConnectionMgr::CreateTransport(nsConnectionEntry *ent, MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread); nsRefPtr sock = new nsHalfOpenSocket(ent, trans, caps); + if (speculative) + sock->SetSpeculative(true); nsresult rv = sock->SetupPrimaryStreams(); NS_ENSURE_SUCCESS(rv, rv); ent->mHalfOpens.AppendElement(sock); mNumHalfOpenConns++; - if (speculative) - sock->SetSpeculative(true); return NS_OK; } @@ -2711,6 +2719,10 @@ nsHalfOpenSocket::SetupStreams(nsISocketTransport **transport, tmpFlags |= nsISocketTransport::DISABLE_IPV6; } + if (IsSpeculative()) { + tmpFlags |= nsISocketTransport::DISABLE_RFC1918; + } + socketTransport->SetConnectionFlags(tmpFlags); socketTransport->SetQoSBits(gHttpHandler->GetQoSBits());