Back out 34169163c4f3:8ca46c86c440 (bug 853423) for leaks

This commit is contained in:
Phil Ringnalda 2013-10-26 15:12:05 -07:00
parent 459cd3adc5
commit db998e8c18
9 changed files with 13 additions and 467 deletions

View File

@ -18,4 +18,4 @@
# Modifying this file will now automatically clobber the buildbot machines \o/
#
Bug 853423 - New code (inc. new function IsIPAddrLocal) is not being included in incremental builds.
Bug 914270 needs a clobber since moving variables to moz.build always requires a clobber (bug 852814)

View File

@ -176,12 +176,6 @@ 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

View File

@ -1161,28 +1161,6 @@ 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("<IP-to-string failed>");
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.

View File

@ -177,32 +177,6 @@ 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);

View File

@ -160,8 +160,6 @@ bool IsIPAddrAny(const NetAddr *addr);
bool IsIPAddrV4Mapped(const NetAddr *addr);
bool IsIPAddrLocal(const NetAddr *addr);
} // namespace net
} // namespace mozilla

View File

@ -8,10 +8,6 @@
#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,
@ -117,19 +113,3 @@ 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);
}

View File

@ -92,9 +92,6 @@ 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;

View File

@ -357,14 +357,6 @@ 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<SpeculativeConnectArgs> args = new SpeculativeConnectArgs();
// Wrap up the callbacks and the target to ensure they're released on the target
@ -1992,13 +1984,13 @@ nsHttpConnectionMgr::CreateTransport(nsConnectionEntry *ent,
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
nsRefPtr<nsHalfOpenSocket> 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;
}
@ -2719,10 +2711,6 @@ nsHalfOpenSocket::SetupStreams(nsISocketTransport **transport,
tmpFlags |= nsISocketTransport::DISABLE_IPV6;
}
if (IsSpeculative()) {
tmpFlags |= nsISocketTransport::DISABLE_RFC1918;
}
socketTransport->SetConnectionFlags(tmpFlags);
socketTransport->SetQoSBits(gHttpHandler->GetQoSBits());

View File

@ -1,89 +1,11 @@
/* -*- Mode: JavaScript; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim: set ts=4 sts=4 et sw=4 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
const CC = Components.Constructor;
const ServerSocket = CC("@mozilla.org/network/server-socket;1",
"nsIServerSocket",
"init");
var serv;
var ios;
/** Example local IP addresses (literal IP address hostname).
*
* Note: for IPv6 Unique Local and Link Local, a wider range of addresses is
* set aside than those most commonly used. Technically, link local addresses
* include those beginning with fe80:: through febf::, although in practise
* only fe80:: is used. Necko code blocks speculative connections for the wider
* range; hence, this test considers that range too.
*/
var localIPv4Literals =
[ // IPv4 RFC1918 \
"10.0.0.1", "10.10.10.10", "10.255.255.255", // 10/8
"172.16.0.1", "172.23.172.12", "172.31.255.255", // 172.16/20
"192.168.0.1", "192.168.192.168", "192.168.255.255", // 192.168/16
// IPv4 Link Local
"169.254.0.1", "169.254.192.154", "169.254.255.255" // 169.254/16
];
var localIPv6Literals =
[ // IPv6 Unique Local fc00::/7
"fc00::1", "fdfe:dcba:9876:abcd:ef01:2345:6789:abcd",
"fdff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
// IPv6 Link Local fe80::/10
"fe80::1", "fe80::abcd:ef01:2345:6789",
"febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff"
];
var localIPLiterals = localIPv4Literals.concat(localIPv6Literals);
/** Example remote IP addresses
*
* Note: The test environment may not have external network access, so
* resolving hostnames may not be possible. Thus, literals are used here, and
* should be directly converted by the stub resolver to IP addresses.
*/
var remoteIPv4Literals =
[ "93.184.216.119", // example.com
"74.125.239.130", // google.com
"63.245.217.105", // mozilla.org
"173.252.110.27" // facebook.com
];
var remoteIPv6Literals =
[ "2607:f8b0:4005:802::1009", // google.com
"2620:101:8008:5::2:1", // mozilla.org
"2a03:2880:2110:df07:face:b00c::1" // facebook.com
];
var remoteIPLiterals = remoteIPv4Literals.concat(remoteIPv6Literals);
/** Test function list and descriptions.
*/
var testList =
[ test_speculative_connect,
test_hostnames_resolving_to_local_addresses,
test_hostnames_resolving_to_remote_addresses,
test_proxies_with_local_addresses,
test_proxies_with_remote_addresses
];
var testDescription =
[ "Expect pass with localhost",
"Expect failure with resolved local IPs",
"Expect success with resolved remote IPs",
"Expect failure for proxies with local IPs",
"Expect success for proxies with remote IPs"
];
var testIdx = 0;
var hostIdx = 0;
/** TestServer
*
* Implements nsIServerSocket for test_speculative_connect.
*/
function TestServer() {
this.listener = ServerSocket(-1, true, -1);
this.listener.asyncListen(this);
@ -94,310 +16,25 @@ TestServer.prototype = {
if (iid.equals(Ci.nsIServerSocket) ||
iid.equals(Ci.nsISupports))
return this;
throw Cr.NS_ERROR_NO_INTERFACE;
throw Components.results.NS_ERROR_NO_INTERFACE;
},
onSocketAccepted: function(socket, trans) {
try { this.listener.close(); } catch(e) {}
do_check_true(true);
next_test();
do_test_finished();
},
onStopListening: function(socket) {}
};
/** TestOutputStreamCallback
*
* Implements nsIOutputStreamCallback for socket layer tests.
*/
function TestOutputStreamCallback(transport, hostname, proxied, expectSuccess, next) {
this.transport = transport;
this.hostname = hostname;
this.proxied = proxied;
this.expectSuccess = expectSuccess;
this.next = next;
this.dummyContent = "Dummy content";
}
TestOutputStreamCallback.prototype = {
QueryInterface: function(iid) {
if (iid.equals(Ci.nsIOutputStreamCallback) ||
iid.equals(Ci.nsISupports))
return this;
throw Cr.NS_ERROR_NO_INTERFACE;
},
onOutputStreamReady: function(stream) {
do_check_neq(typeof(stream), undefined);
try {
stream.write(this.dummyContent, this.dummyContent.length);
} catch (e) {
// Spec Connect FAILED.
do_check_instanceof(e, Ci.nsIException);
if (this.expectSuccess) {
// We may expect success, but the address could be unreachable
// in the test environment, so expect errors.
if (this.proxied) {
do_check_true(e.result == Cr.NS_ERROR_NET_TIMEOUT ||
e.result == Cr.NS_ERROR_PROXY_CONNECTION_REFUSED);
} else {
do_check_true(e.result == Cr.NS_ERROR_NET_TIMEOUT ||
e.result == Cr.NS_ERROR_CONNECTION_REFUSED);
}
} else {
// A refusal to connect speculatively should throw an error.
do_check_eq(e.result, Cr.NS_ERROR_CONNECTION_REFUSED);
}
this.transport.close(Cr.NS_BINDING_ABORTED);
this.next();
return;
}
// Spec Connect SUCCEEDED.
if (this.expectSuccess) {
do_check_true(true, "Success for " + this.hostname);
} else {
do_throw("Speculative Connect should have failed for " +
this.hostname);
}
this.transport.close(Cr.NS_BINDING_ABORTED);
this.next();
}
};
/** test_speculative_connect
*
* Tests a basic positive case using nsIOService.SpeculativeConnect:
* connecting to localhost.
*/
function test_speculative_connect() {
serv = new TestServer();
var URI = ios.newURI("http://localhost:" + serv.listener.port + "/just/a/test", null, null);
ios.QueryInterface(Ci.nsISpeculativeConnect)
.speculativeConnect(URI, null);
}
/* Speculative connections should not be allowed for hosts with local IP
* addresses (Bug 853423). That list includes:
* -- IPv4 RFC1918 and Link Local Addresses.
* -- IPv6 Unique and Link Local Addresses.
*
* Two tests are required:
* 1. Verify IP Literals passed to the SpeculativeConnect API.
* 2. Verify hostnames that need to be resolved at the socket layer.
*/
/** test_hostnames_resolving_to_addresses
*
* Common test function for resolved hostnames. Takes a list of hosts, a
* boolean to determine if the test is expected to succeed or fail, and a
* function to call the next test case.
*/
function test_hostnames_resolving_to_addresses(host, expectSuccess, next) {
do_print(host);
var sts = Cc["@mozilla.org/network/socket-transport-service;1"]
.getService(Ci.nsISocketTransportService);
do_check_neq(typeof(sts), undefined);
var transport = sts.createTransport(null, 0, host, 80, null);
do_check_neq(typeof(transport), undefined);
transport.connectionFlags = Ci.nsISocketTransport.DISABLE_RFC1918;
transport.setTimeout(Ci.nsISocketTransport.TIMEOUT_CONNECT, 1);
transport.setTimeout(Ci.nsISocketTransport.TIMEOUT_READ_WRITE, 1);
do_check_eq(1, transport.getTimeout(Ci.nsISocketTransport.TIMEOUT_CONNECT));
var outStream = transport.openOutputStream(Ci.nsITransport.OPEN_UNBUFFERED,0,0);
do_check_neq(typeof(outStream), undefined);
var callback = new TestOutputStreamCallback(transport, host, false,
expectSuccess,
next);
do_check_neq(typeof(callback), undefined);
// Need to get main thread pointer to ensure nsSocketTransport::AsyncWait
// adds callback to nsOutputStreamReadyEvent on main thread, and doesn't
// addref off the main thread.
var gThreadManager = Cc["@mozilla.org/thread-manager;1"]
.getService(Ci.nsIThreadManager);
var mainThread = gThreadManager.currentThread;
try {
outStream.QueryInterface(Ci.nsIAsyncOutputStream)
.asyncWait(callback, 0, 0, mainThread);
} catch (e) {
do_throw("asyncWait should not fail!");
}
}
/**
* test_hostnames_resolving_to_local_addresses
*
* Creates an nsISocketTransport and simulates a speculative connect request
* for a hostname that resolves to a local IP address.
* Runs asynchronously; on test success (i.e. failure to connect), the callback
* will call this function again until all hostnames in the test list are done.
*
* Note: This test also uses an IP literal for the hostname. This should be ok,
* as the socket layer will ask for the hostname to be resolved anyway, and DNS
* code should return a numerical version of the address internally.
*/
function test_hostnames_resolving_to_local_addresses() {
if (hostIdx >= localIPLiterals.length) {
// No more local IP addresses; move on.
next_test();
return;
}
var host = localIPLiterals[hostIdx++];
// Test another local IP address when the current one is done.
var next = test_hostnames_resolving_to_local_addresses;
test_hostnames_resolving_to_addresses(host, false, next);
}
/**
* test_hostnames_resolving_to_remote_addresses
*
* Creates an nsISocketTransport and simulates a speculative connect request
* for a hostname that resolves to a local IP address.
* Runs asynchronously; on test success (i.e. failure to connect), the callback
* will call this function again until all hostnames in the test list are done.
*
* Note: This test also uses an IP literal for the hostname. This should be ok,
* as the socket layer will ask for the hostname to be resolved anyway, and DNS
* code should return a numerical version of the address internally.
*/
function test_hostnames_resolving_to_remote_addresses() {
if (hostIdx >= remoteIPLiterals.length) {
// No more remote IP addresses; move on.
next_test();
return;
}
var host = remoteIPLiterals[hostIdx++];
// Test another remote IP address when the current one is done.
var next = test_hostnames_resolving_to_remote_addresses;
test_hostnames_resolving_to_addresses(host, true, next);
}
/** test_speculative_connect_with_host_list
*
* Common test function for resolved proxy hosts. Takes a list of hosts, a
* boolean to determine if the test is expected to succeed or fail, and a
* function to call the next test case.
*/
function test_proxies(proxyHost, expectSuccess, next) {
do_print("Proxy: " + proxyHost);
var sts = Cc["@mozilla.org/network/socket-transport-service;1"]
.getService(Ci.nsISocketTransportService);
do_check_neq(typeof(sts), undefined);
var pps = Cc["@mozilla.org/network/protocol-proxy-service;1"]
.getService();
do_check_neq(typeof(pps), undefined);
var proxyInfo = pps.newProxyInfo("http", proxyHost, 8080, 0, 1, null);
do_check_neq(typeof(proxyInfo), undefined);
var transport = sts.createTransport(null, 0, "dummyHost", 80, proxyInfo);
do_check_neq(typeof(transport), undefined);
transport.connectionFlags = Ci.nsISocketTransport.DISABLE_RFC1918;
transport.setTimeout(Ci.nsISocketTransport.TIMEOUT_CONNECT, 1);
do_check_eq(1, transport.getTimeout(Ci.nsISocketTransport.TIMEOUT_CONNECT));
transport.setTimeout(Ci.nsISocketTransport.TIMEOUT_READ_WRITE, 1);
var outStream = transport.openOutputStream(Ci.nsITransport.OPEN_UNBUFFERED,0,0);
do_check_neq(typeof(outStream), undefined);
var callback = new TestOutputStreamCallback(transport, proxyHost, true,
expectSuccess,
next);
do_check_neq(typeof(callback), undefined);
// Need to get main thread pointer to ensure nsSocketTransport::AsyncWait
// adds callback to nsOutputStreamReadyEvent on main thread, and doesn't
// addref off the main thread.
var gThreadManager = Cc["@mozilla.org/thread-manager;1"]
.getService(Ci.nsIThreadManager);
var mainThread = gThreadManager.currentThread;
try {
outStream.QueryInterface(Ci.nsIAsyncOutputStream)
.asyncWait(callback, 0, 0, mainThread);
} catch (e) {
do_throw("asyncWait should not fail!");
}
}
/**
* test_proxies_with_local_addresses
*
* Creates an nsISocketTransport and simulates a speculative connect request
* for a proxy that resolves to a local IP address.
* Runs asynchronously; on test success (i.e. failure to connect), the callback
* will call this function again until all proxies in the test list are done.
*
* Note: This test also uses an IP literal for the proxy. This should be ok,
* as the socket layer will ask for the proxy to be resolved anyway, and DNS
* code should return a numerical version of the address internally.
*/
function test_proxies_with_local_addresses() {
if (hostIdx >= localIPLiterals.length) {
// No more local IP addresses; move on.
next_test();
return;
}
var host = localIPLiterals[hostIdx++];
// Test another local IP address when the current one is done.
var next = test_proxies_with_local_addresses;
test_proxies(host, false, next);
}
/**
* test_proxies_with_remote_addresses
*
* Creates an nsISocketTransport and simulates a speculative connect request
* for a proxy that resolves to a local IP address.
* Runs asynchronously; on test success (i.e. failure to connect), the callback
* will call this function again until all proxies in the test list are done.
*
* Note: This test also uses an IP literal for the proxy. This should be ok,
* as the socket layer will ask for the proxy to be resolved anyway, and DNS
* code should return a numerical version of the address internally.
*/
function test_proxies_with_remote_addresses() {
if (hostIdx >= remoteIPLiterals.length) {
// No more local IP addresses; move on.
next_test();
return;
}
var host = remoteIPLiterals[hostIdx++];
// Test another local IP address when the current one is done.
var next = test_proxies_with_remote_addresses;
test_proxies(host, true, next);
}
/** next_test
*
* Calls the next test in testList. Each test is responsible for calling this
* function when its test cases are complete.
*/
function next_test() {
if (testIdx >= testList.length) {
// No more tests; we're done.
do_test_finished();
return;
}
do_print("SpeculativeConnect: " + testDescription[testIdx]);
hostIdx = 0;
// Start next test in list.
testList[testIdx++]();
}
/** run_test
*
* Main entry function for test execution.
*/
function run_test() {
ios = Cc["@mozilla.org/network/io-service;1"]
.getService(Ci.nsIIOService);
var ios = Cc["@mozilla.org/network/io-service;1"]
.getService(Ci.nsIIOService);
serv = new TestServer();
URI = ios.newURI("http://localhost:" + serv.listener.port + "/just/a/test", null, null);
ios.QueryInterface(Components.interfaces.nsISpeculativeConnect)
.speculativeConnect(URI, null);
do_test_pending();
next_test();
}