Commit 1c7cf3f8 authored by mmenke@chromium.org's avatar mmenke@chromium.org

Fix crash when trying to connect to an IPv6 IP via a SOCKS4 proxy.

The socks client socket correctly requests the HostResolver only
give it IPv4 addresses, but the HostResolver ignored that flag when
passed IPs directly.  This fixes that behavior.

BUG=379031

Review URL: https://codereview.chromium.org/435603008

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@288143 0039d316-1c4b-4281-b951-d872f2087c98
parent f687e794
......@@ -35,6 +35,7 @@
#include "net/base/dns_reloader.h"
#include "net/base/dns_util.h"
#include "net/base/host_port_pair.h"
#include "net/base/ip_endpoint.h"
#include "net/base/net_errors.h"
#include "net/base/net_log.h"
#include "net/base/net_util.h"
......@@ -182,7 +183,7 @@ bool IsGloballyReachable(const IPAddressNumber& dest,
rv = socket->GetLocalAddress(&endpoint);
if (rv != OK)
return false;
DCHECK(endpoint.GetFamily() == ADDRESS_FAMILY_IPV6);
DCHECK_EQ(ADDRESS_FAMILY_IPV6, endpoint.GetFamily());
const IPAddressNumber& address = endpoint.address();
bool is_link_local = (address[0] == 0xFE) && ((address[1] & 0xC0) == 0x80);
if (is_link_local)
......@@ -2032,10 +2033,18 @@ bool HostResolverImpl::ResolveAsIP(const Key& key,
~(HOST_RESOLVER_CANONNAME | HOST_RESOLVER_LOOPBACK_ONLY |
HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6),
0) << " Unhandled flag";
bool ipv6_disabled = (default_address_family_ == ADDRESS_FAMILY_IPV4) &&
!probe_ipv6_support_;
*net_error = OK;
if ((ip_number.size() == kIPv6AddressSize) && ipv6_disabled) {
AddressFamily family = GetAddressFamily(ip_number);
if (family == ADDRESS_FAMILY_IPV6 &&
!probe_ipv6_support_ &&
default_address_family_ == ADDRESS_FAMILY_IPV4) {
// Don't return IPv6 addresses if default address family is set to IPv4,
// and probes are disabled.
*net_error = ERR_NAME_NOT_RESOLVED;
} else if (key.address_family != ADDRESS_FAMILY_UNSPECIFIED &&
key.address_family != family) {
// Don't return IPv6 addresses for IPv4 queries, and vice versa.
*net_error = ERR_NAME_NOT_RESOLVED;
} else {
*addresses = AddressList::CreateFromIPAddress(ip_number, info.port());
......
......@@ -1236,6 +1236,33 @@ TEST_F(HostResolverImplTest, SetDefaultAddressFamily_IPv6) {
EXPECT_TRUE(requests_[2]->HasOneAddress("1.0.0.1", 80));
}
// Make sure that the address family parameter is respected when raw IPs are
// passed in.
TEST_F(HostResolverImplTest, AddressFamilyWithRawIPs) {
Request* request =
CreateRequest("127.0.0.1", 80, MEDIUM, ADDRESS_FAMILY_IPV4);
EXPECT_EQ(OK, request->Resolve());
EXPECT_TRUE(request->HasOneAddress("127.0.0.1", 80));
request = CreateRequest("127.0.0.1", 80, MEDIUM, ADDRESS_FAMILY_IPV6);
EXPECT_EQ(ERR_NAME_NOT_RESOLVED, request->Resolve());
request = CreateRequest("127.0.0.1", 80, MEDIUM, ADDRESS_FAMILY_UNSPECIFIED);
EXPECT_EQ(OK, request->Resolve());
EXPECT_TRUE(request->HasOneAddress("127.0.0.1", 80));
request = CreateRequest("::1", 80, MEDIUM, ADDRESS_FAMILY_IPV4);
EXPECT_EQ(ERR_NAME_NOT_RESOLVED, request->Resolve());
request = CreateRequest("::1", 80, MEDIUM, ADDRESS_FAMILY_IPV6);
EXPECT_EQ(OK, request->Resolve());
EXPECT_TRUE(request->HasOneAddress("::1", 80));
request = CreateRequest("::1", 80, MEDIUM, ADDRESS_FAMILY_UNSPECIFIED);
EXPECT_EQ(OK, request->Resolve());
EXPECT_TRUE(request->HasOneAddress("::1", 80));
}
TEST_F(HostResolverImplTest, ResolveFromCache) {
proc_->AddRuleForAllFamilies("just.testing", "192.168.1.42");
proc_->SignalMultiple(1u); // Need only one.
......
......@@ -14,6 +14,7 @@
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/threading/platform_thread.h"
#include "net/base/ip_endpoint.h"
#include "net/base/net_errors.h"
#include "net/base/net_util.h"
#include "net/base/test_completion_callback.h"
......@@ -154,6 +155,12 @@ int MockHostResolverBase::ResolveFromIPLiteralOrCache(const RequestInfo& info,
AddressList* addresses) {
IPAddressNumber ip;
if (ParseIPLiteralToNumber(info.hostname(), &ip)) {
// This matches the behavior HostResolverImpl.
if (info.address_family() != ADDRESS_FAMILY_UNSPECIFIED &&
info.address_family() != GetAddressFamily(ip)) {
return ERR_NAME_NOT_RESOLVED;
}
*addresses = AddressList::CreateFromIPAddress(ip, info.port());
if (info.host_resolver_flags() & HOST_RESOLVER_CANONNAME)
addresses->SetDefaultCanonicalName();
......
......@@ -10,6 +10,7 @@
#include "net/base/net_log_unittest.h"
#include "net/base/test_completion_callback.h"
#include "net/base/winsock_init.h"
#include "net/dns/host_resolver.h"
#include "net/dns/mock_host_resolver.h"
#include "net/socket/client_socket_factory.h"
#include "net/socket/socket_test_util.h"
......@@ -414,4 +415,36 @@ TEST_F(SOCKSClientSocketTest, DisconnectWhileHostResolveInProgress) {
EXPECT_FALSE(user_sock_->IsConnectedAndIdle());
}
// Tries to connect to an IPv6 IP. Should fail, as SOCKS4 does not support
// IPv6.
TEST_F(SOCKSClientSocketTest, NoIPv6) {
const char kHostName[] = "::1";
user_sock_ = BuildMockSocket(NULL, 0,
NULL, 0,
host_resolver_.get(),
kHostName, 80,
NULL);
EXPECT_EQ(ERR_NAME_NOT_RESOLVED,
callback_.GetResult(user_sock_->Connect(callback_.callback())));
}
// Same as above, but with a real resolver, to protect against regressions.
TEST_F(SOCKSClientSocketTest, NoIPv6RealResolver) {
const char kHostName[] = "::1";
scoped_ptr<HostResolver> host_resolver(
HostResolver::CreateSystemResolver(HostResolver::Options(), NULL));
user_sock_ = BuildMockSocket(NULL, 0,
NULL, 0,
host_resolver.get(),
kHostName, 80,
NULL);
EXPECT_EQ(ERR_NAME_NOT_RESOLVED,
callback_.GetResult(user_sock_->Connect(callback_.callback())));
}
} // namespace net
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment