summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorvandebo@chromium.org <vandebo@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-08-18 23:26:51 +0000
committervandebo@chromium.org <vandebo@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-08-18 23:26:51 +0000
commitde114d6a8a223904bc5988c36c22518dd59e1b3a (patch)
treec5f21c96501172b8dd9dc3a7871ae89fa16cacdc /net
parent4067f4a5f0c7ace27a9631cfbf261e42e1ecc8e6 (diff)
downloadchromium_src-de114d6a8a223904bc5988c36c22518dd59e1b3a.zip
chromium_src-de114d6a8a223904bc5988c36c22518dd59e1b3a.tar.gz
chromium_src-de114d6a8a223904bc5988c36c22518dd59e1b3a.tar.bz2
Don't resolve IP literals.
For each resolution request this checks to see if this 'host' is a literal ip address. If so, it synthesises a struct addrinfo and returns it without adding it to the cache. BUG=39830 TEST=unit tests, new and old Committed: http://src.chromium.org/viewvc/chrome?view=rev&revision=56384 Review URL: http://codereview.chromium.org/3023048 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@56615 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
-rw-r--r--net/base/address_list.cc91
-rw-r--r--net/base/address_list.h20
-rw-r--r--net/base/address_list_unittest.cc63
-rw-r--r--net/base/host_resolver_impl.cc19
-rw-r--r--net/base/host_resolver_impl_unittest.cc5
-rw-r--r--net/base/mock_host_resolver.cc26
6 files changed, 139 insertions, 85 deletions
diff --git a/net/base/address_list.cc b/net/base/address_list.cc
index 1c97311..75c30b8 100644
--- a/net/base/address_list.cc
+++ b/net/base/address_list.cc
@@ -85,6 +85,53 @@ void SetPortRecursive(struct addrinfo* info, int port) {
} // namespace
+AddressList::AddressList(const IPAddressNumber& address, int port,
+ bool canonicalize_name) {
+ struct addrinfo* ai = new addrinfo;
+ memset(ai, 0, sizeof(addrinfo));
+ ai->ai_socktype = SOCK_STREAM;
+
+ switch (address.size()) {
+ case 4: {
+ ai->ai_family = AF_INET;
+ const size_t sockaddr_in_size = sizeof(struct sockaddr_in);
+ ai->ai_addrlen = sockaddr_in_size;
+
+ struct sockaddr_in* addr = reinterpret_cast<struct sockaddr_in*>(
+ new char[sockaddr_in_size]);
+ memset(addr, 0, sockaddr_in_size);
+ addr->sin_family = AF_INET;
+ memcpy(&addr->sin_addr, &address[0], 4);
+ ai->ai_addr = reinterpret_cast<struct sockaddr*>(addr);
+ break;
+ }
+ case 16: {
+ ai->ai_family = AF_INET6;
+ const size_t sockaddr_in6_size = sizeof(struct sockaddr_in6);
+ ai->ai_addrlen = sockaddr_in6_size;
+
+ struct sockaddr_in6* addr6 = reinterpret_cast<struct sockaddr_in6*>(
+ new char[sockaddr_in6_size]);
+ memset(addr6, 0, sockaddr_in6_size);
+ addr6->sin6_family = AF_INET6;
+ memcpy(&addr6->sin6_addr, &address[0], 16);
+ ai->ai_addr = reinterpret_cast<struct sockaddr*>(addr6);
+ break;
+ }
+ default: {
+ NOTREACHED() << "Bad IP address";
+ break;
+ }
+ }
+
+ if (canonicalize_name) {
+ std::string name = NetAddressToString(ai);
+ ai->ai_canonname = do_strdup(name.c_str());
+ }
+ data_ = new Data(ai, false /*is_system_created*/);
+ SetPort(port);
+}
+
void AddressList::Adopt(struct addrinfo* head) {
data_ = new Data(head, true /*is_system_created*/);
}
@@ -143,50 +190,6 @@ void AddressList::Reset() {
data_ = NULL;
}
-// static
-AddressList AddressList::CreateIPv4Address(unsigned char data[4],
- const std::string& canonical_name) {
- struct addrinfo* ai = new addrinfo;
- memset(ai, 0, sizeof(addrinfo));
- ai->ai_family = AF_INET;
- ai->ai_socktype = SOCK_STREAM;
- const size_t sockaddr_in_size = sizeof(struct sockaddr_in);
- ai->ai_addrlen = sockaddr_in_size;
- if (!canonical_name.empty())
- ai->ai_canonname = do_strdup(canonical_name.c_str());
-
- struct sockaddr_in* addr = reinterpret_cast<struct sockaddr_in*>(
- new char[sockaddr_in_size]);
- memset(addr, 0, sockaddr_in_size);
- addr->sin_family = AF_INET;
- memcpy(&addr->sin_addr, data, 4);
- ai->ai_addr = reinterpret_cast<struct sockaddr*>(addr);
-
- return AddressList(new Data(ai, false /*is_system_created*/));
-}
-
-// static
-AddressList AddressList::CreateIPv6Address(unsigned char data[16],
- const std::string& canonical_name) {
- struct addrinfo* ai = new addrinfo;
- memset(ai, 0, sizeof(addrinfo));
- ai->ai_family = AF_INET6;
- ai->ai_socktype = SOCK_STREAM;
- const size_t sockaddr_in6_size = sizeof(struct sockaddr_in6);
- ai->ai_addrlen = sockaddr_in6_size;
- if (!canonical_name.empty())
- ai->ai_canonname = do_strdup(canonical_name.c_str());
-
- struct sockaddr_in6* addr6 = reinterpret_cast<struct sockaddr_in6*>(
- new char[sockaddr_in6_size]);
- memset(addr6, 0, sockaddr_in6_size);
- addr6->sin6_family = AF_INET6;
- memcpy(&addr6->sin6_addr, data, 16);
- ai->ai_addr = reinterpret_cast<struct sockaddr*>(addr6);
-
- return AddressList(new Data(ai, false /*is_system_created*/));
-}
-
AddressList::Data::Data(struct addrinfo* ai, bool is_system_created)
: head(ai), is_system_created(is_system_created) {
DCHECK(head);
diff --git a/net/base/address_list.h b/net/base/address_list.h
index 996d871..1ca86a1 100644
--- a/net/base/address_list.h
+++ b/net/base/address_list.h
@@ -9,6 +9,7 @@
#include <string>
#include "base/ref_counted.h"
+#include "net/base/net_util.h"
struct addrinfo;
@@ -21,6 +22,11 @@ class AddressList {
// Constructs an empty address list.
AddressList() {}
+ // Constructs an address list for a single IP literal. If
+ // |canonicalize_name| is true, fill the ai_canonname field with the
+ // canonicalized IP address.
+ AddressList(const IPAddressNumber& address, int port, bool canonicalize_name);
+
// Adopt the given addrinfo list in place of the existing one if any. This
// hands over responsibility for freeing the addrinfo list to the AddressList
// object.
@@ -60,20 +66,6 @@ class AddressList {
// empty state as when first constructed.
void Reset();
- // Used by unit-tests to manually create an IPv4 AddressList. |data| should
- // be an IPv4 address in network order (big endian).
- // If |canonical_name| is non-empty, it will be duplicated in the
- // ai_canonname field of the addrinfo struct.
- static AddressList CreateIPv4Address(unsigned char data[4],
- const std::string& canonical_name);
-
- // Used by unit-tests to manually create an IPv6 AddressList. |data| should
- // be an IPv6 address in network order (big endian).
- // If |canonical_name| is non-empty, it will be duplicated in the
- // ai_canonname field of the addrinfo struct.
- static AddressList CreateIPv6Address(unsigned char data[16],
- const std::string& canonical_name);
-
// Get access to the head of the addrinfo list.
const struct addrinfo* head() const { return data_->head; }
diff --git a/net/base/address_list_unittest.cc b/net/base/address_list_unittest.cc
index 6e38c7d..65d0f5c 100644
--- a/net/base/address_list_unittest.cc
+++ b/net/base/address_list_unittest.cc
@@ -16,9 +16,8 @@
namespace {
// Use getaddrinfo() to allocate an addrinfo structure.
-void CreateAddressList(const std::string& hostname,
- int port,
- net::AddressList* addrlist) {
+int CreateAddressList(const std::string& hostname, int port,
+ net::AddressList* addrlist) {
#if defined(OS_WIN)
net::EnsureWinsockInit();
#endif
@@ -26,20 +25,21 @@ void CreateAddressList(const std::string& hostname,
net::ADDRESS_FAMILY_UNSPECIFIED,
0,
addrlist, NULL);
- EXPECT_EQ(0, rv);
- addrlist->SetPort(port);
+ if (rv == 0)
+ addrlist->SetPort(port);
+ return rv;
}
void CreateLongAddressList(net::AddressList* addrlist, int port) {
- CreateAddressList("192.168.1.1", port, addrlist);
+ EXPECT_EQ(0, CreateAddressList("192.168.1.1", port, addrlist));
net::AddressList second_list;
- CreateAddressList("192.168.1.2", port, &second_list);
+ EXPECT_EQ(0, CreateAddressList("192.168.1.2", port, &second_list));
addrlist->Append(second_list.head());
}
TEST(AddressListTest, GetPort) {
net::AddressList addrlist;
- CreateAddressList("192.168.1.1", 81, &addrlist);
+ EXPECT_EQ(0, CreateAddressList("192.168.1.1", 81, &addrlist));
EXPECT_EQ(81, addrlist.GetPort());
addrlist.SetPort(83);
@@ -48,7 +48,7 @@ TEST(AddressListTest, GetPort) {
TEST(AddressListTest, Assignment) {
net::AddressList addrlist1;
- CreateAddressList("192.168.1.1", 85, &addrlist1);
+ EXPECT_EQ(0, CreateAddressList("192.168.1.1", 85, &addrlist1));
EXPECT_EQ(85, addrlist1.GetPort());
// Should reference the same data as addrlist1 -- so when we change addrlist1
@@ -107,10 +107,10 @@ TEST(AddressListTest, CopyNonRecursive) {
TEST(AddressListTest, Append) {
net::AddressList addrlist1;
- CreateAddressList("192.168.1.1", 11, &addrlist1);
+ EXPECT_EQ(0, CreateAddressList("192.168.1.1", 11, &addrlist1));
EXPECT_EQ(11, addrlist1.GetPort());
net::AddressList addrlist2;
- CreateAddressList("192.168.1.2", 12, &addrlist2);
+ EXPECT_EQ(0, CreateAddressList("192.168.1.2", 12, &addrlist2));
EXPECT_EQ(12, addrlist2.GetPort());
ASSERT_TRUE(addrlist1.head()->ai_next == NULL);
@@ -172,4 +172,45 @@ TEST(AddressListTest, Canonical) {
EXPECT_EQ("blah", canon_name3);
}
+TEST(AddressListTest, IPLiteralConstructor) {
+ struct TestData {
+ std::string ip_address;
+ std::string canonical_ip_address;
+ bool is_ipv6;
+ } tests[] = {
+ { "127.0.00.1", "127.0.0.1", false },
+ { "192.168.1.1", "192.168.1.1", false },
+ { "::1", "::1", true },
+ { "2001:db8:0::42", "2001:db8::42", true },
+ };
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); i++) {
+ net::AddressList expected_list;
+ int rv = CreateAddressList(tests[i].canonical_ip_address, 80,
+ &expected_list);
+ if (tests[i].is_ipv6 && rv != 0) {
+ LOG(WARNING) << "Unable to resolve ip literal '" << tests[i].ip_address
+ << "' test skipped.";
+ continue;
+ }
+ ASSERT_EQ(0, rv);
+ const struct addrinfo* good_ai = expected_list.head();
+
+ net::IPAddressNumber ip_number;
+ net::ParseIPLiteralToNumber(tests[i].ip_address, &ip_number);
+ net::AddressList test_list(ip_number, 80, true);
+ const struct addrinfo* test_ai = test_list.head();
+
+ EXPECT_EQ(good_ai->ai_family, test_ai->ai_family);
+ EXPECT_EQ(good_ai->ai_socktype, test_ai->ai_socktype);
+ EXPECT_EQ(good_ai->ai_addrlen, test_ai->ai_addrlen);
+ size_t sockaddr_size =
+ good_ai->ai_socktype == AF_INET ? sizeof(struct sockaddr_in) :
+ good_ai->ai_socktype == AF_INET6 ? sizeof(struct sockaddr_in6) : 0;
+ EXPECT_EQ(memcmp(good_ai->ai_addr, test_ai->ai_addr, sockaddr_size), 0);
+ EXPECT_EQ(good_ai->ai_next, test_ai->ai_next);
+ EXPECT_EQ(strcmp(tests[i].canonical_ip_address.c_str(),
+ test_ai->ai_canonname), 0);
+ }
+}
+
} // namespace
diff --git a/net/base/host_resolver_impl.cc b/net/base/host_resolver_impl.cc
index aa1ed9c..11d9306 100644
--- a/net/base/host_resolver_impl.cc
+++ b/net/base/host_resolver_impl.cc
@@ -754,8 +754,6 @@ HostResolverImpl::~HostResolverImpl() {
delete job_pools_[i];
}
-// TODO(eroman): Don't create cache entries for hostnames which are simply IP
-// address literals.
int HostResolverImpl::Resolve(const RequestInfo& info,
AddressList* addresses,
CompletionCallback* callback,
@@ -772,6 +770,23 @@ int HostResolverImpl::Resolve(const RequestInfo& info,
// Update the net log and notify registered observers.
OnStartRequest(net_log, request_id, info);
+ // Check for IP literal.
+ IPAddressNumber ip_number;
+ if (ParseIPLiteralToNumber(info.hostname(), &ip_number)) {
+ DCHECK_EQ((info.host_resolver_flags() &
+ ~(HOST_RESOLVER_CANONNAME | HOST_RESOLVER_LOOPBACK_ONLY)), 0)
+ << " Unhandled flag";
+ AddressList result(ip_number, info.port(),
+ (info.host_resolver_flags() & HOST_RESOLVER_CANONNAME));
+
+ *addresses = result;
+ // Update the net log and notify registered observers.
+ OnFinishRequest(net_log, request_id, info, OK,
+ 0, /* os_error (unknown since from cache) */
+ false /* was_from_cache */);
+ return OK;
+ }
+
// Build a key that identifies the request in the cache and in the
// outstanding jobs map.
Key key = GetEffectiveKeyForRequest(info);
diff --git a/net/base/host_resolver_impl_unittest.cc b/net/base/host_resolver_impl_unittest.cc
index be0e2cb..a3b863d 100644
--- a/net/base/host_resolver_impl_unittest.cc
+++ b/net/base/host_resolver_impl_unittest.cc
@@ -399,11 +399,6 @@ TEST_F(HostResolverImplTest, NumericIPv6Address) {
const int kPortnum = 5555;
HostResolver::RequestInfo info("2001:db8::1", kPortnum);
int err = host_resolver->Resolve(info, &adrlist, NULL, NULL, BoundNetLog());
- // On computers without IPv6 support, getaddrinfo cannot convert IPv6
- // address literals to addresses (getaddrinfo returns EAI_NONAME). So this
- // test has to allow host_resolver->Resolve to fail.
- if (err == ERR_NAME_NOT_RESOLVED)
- return;
EXPECT_EQ(OK, err);
const struct addrinfo* ainfo = adrlist.head();
diff --git a/net/base/mock_host_resolver.cc b/net/base/mock_host_resolver.cc
index 8d1fd89..a9fc754 100644
--- a/net/base/mock_host_resolver.cc
+++ b/net/base/mock_host_resolver.cc
@@ -9,11 +9,20 @@
#include "base/ref_counted.h"
#include "net/base/net_errors.h"
#include "net/base/net_util.h"
+#include "net/base/sys_addrinfo.h"
namespace net {
namespace {
+char* do_strdup(const char* src) {
+#if defined(OS_WIN)
+ return _strdup(src);
+#else
+ return strdup(src);
+#endif
+}
+
// Fills |*addrlist| with a socket address for |host| which should be an
// IPv4 or IPv6 literal without enclosing brackets. If |canonical_name| is
// non-empty it is used as the DNS canonical name for the host. Returns OK on
@@ -27,15 +36,10 @@ int CreateIPAddress(const std::string& host,
return ERR_UNEXPECTED;
}
- if (ip_number.size() == 4) {
- *addrlist = AddressList::CreateIPv4Address(&ip_number[0], canonical_name);
- } else if (ip_number.size() == 16) {
- *addrlist = AddressList::CreateIPv6Address(&ip_number[0], canonical_name);
- } else {
- NOTREACHED();
- return ERR_UNEXPECTED;
- }
-
+ AddressList result(ip_number, -1, false);
+ struct addrinfo* ai = const_cast<struct addrinfo*>(result.head());
+ ai->ai_canonname = do_strdup(canonical_name.c_str());
+ *addrlist = result;
return OK;
}
@@ -161,6 +165,10 @@ void RuleBasedHostResolverProc::AddIPLiteralRule(
const std::string& host_pattern,
const std::string& ip_literal,
const std::string& canonical_name) {
+ // Literals are always resolved to themselves by HostResolverImpl,
+ // consequently we do not support remapping them.
+ IPAddressNumber ip_number;
+ DCHECK(!ParseIPLiteralToNumber(host_pattern, &ip_number));
Rule rule(Rule::kResolverTypeIPLiteral,
host_pattern,
ADDRESS_FAMILY_UNSPECIFIED,