diff options
author | vandebo@chromium.org <vandebo@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-08-18 23:26:51 +0000 |
---|---|---|
committer | vandebo@chromium.org <vandebo@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-08-18 23:26:51 +0000 |
commit | de114d6a8a223904bc5988c36c22518dd59e1b3a (patch) | |
tree | c5f21c96501172b8dd9dc3a7871ae89fa16cacdc /net | |
parent | 4067f4a5f0c7ace27a9631cfbf261e42e1ecc8e6 (diff) | |
download | chromium_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.cc | 91 | ||||
-rw-r--r-- | net/base/address_list.h | 20 | ||||
-rw-r--r-- | net/base/address_list_unittest.cc | 63 | ||||
-rw-r--r-- | net/base/host_resolver_impl.cc | 19 | ||||
-rw-r--r-- | net/base/host_resolver_impl_unittest.cc | 5 | ||||
-rw-r--r-- | net/base/mock_host_resolver.cc | 26 |
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, |