summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/base/address_list.cc50
-rw-r--r--net/base/address_list.h15
-rw-r--r--net/base/mock_host_resolver.cc80
-rw-r--r--net/base/mock_host_resolver.h24
-rw-r--r--net/http/http_auth_handler_negotiate.h8
-rw-r--r--net/http/http_auth_handler_negotiate_unittest.cc96
-rw-r--r--net/net.gyp1
-rw-r--r--net/socket/socks_client_socket_unittest.cc2
8 files changed, 242 insertions, 34 deletions
diff --git a/net/base/address_list.cc b/net/base/address_list.cc
index cf7f0d5..1736a19 100644
--- a/net/base/address_list.cc
+++ b/net/base/address_list.cc
@@ -13,6 +13,14 @@ namespace net {
namespace {
+char* do_strdup(const char* src) {
+#if defined(OS_WIN)
+ return _strdup(src);
+#else
+ return strdup(src);
+#endif
+}
+
// Make a copy of |info| (the dynamically-allocated parts are copied as well).
// If |recursive| is true, chained entries via ai_next are copied too.
// Copy returned by this function should be deleted using
@@ -27,11 +35,7 @@ struct addrinfo* CreateCopyOfAddrinfo(const struct addrinfo* info,
// ai_canonname is a NULL-terminated string.
if (info->ai_canonname) {
-#ifdef OS_WIN
- copy->ai_canonname = _strdup(info->ai_canonname);
-#else
- copy->ai_canonname = strdup(info->ai_canonname);
-#endif
+ copy->ai_canonname = do_strdup(info->ai_canonname);
}
// ai_addr is a buffer of length ai_addrlen.
@@ -162,21 +166,45 @@ void AddressList::Reset() {
}
// static
-AddressList AddressList::CreateIPv6Address(unsigned char data[16]) {
+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;
- ai->ai_addrlen = sizeof(struct sockaddr_in6);
+ 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[ai->ai_addrlen]);
- memset(addr6, 0, sizeof(struct sockaddr_in6));
-
- ai->ai_addr = reinterpret_cast<struct sockaddr*>(addr6);
+ 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*/));
}
diff --git a/net/base/address_list.h b/net/base/address_list.h
index e8ecb63..ce17645 100644
--- a/net/base/address_list.h
+++ b/net/base/address_list.h
@@ -59,8 +59,19 @@ class AddressList {
// empty state as when first constructed.
void Reset();
- // Used by unit-tests to manually set the TCP socket address.
- static AddressList CreateIPv6Address(unsigned char data[16]);
+ // 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/mock_host_resolver.cc b/net/base/mock_host_resolver.cc
index d99b24e..573d57e 100644
--- a/net/base/mock_host_resolver.cc
+++ b/net/base/mock_host_resolver.cc
@@ -13,10 +13,14 @@
namespace net {
namespace {
-// Fills |addrlist| with a socket address for |host| which should be an
-// IPv6 literal. Returns OK on success.
-int ResolveIPV6LiteralUsingGURL(const std::string& host,
- AddressList* addrlist) {
+
+// Fills |*addrlist| with a socket address for |host| which should be an
+// 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 success,
+// ERR_UNEXPECTED otherwise.
+int CreateIPv6Address(const std::string& host,
+ const std::string& canonical_name,
+ AddressList* addrlist) {
// GURL expects the hostname to be surrounded with brackets.
std::string host_brackets = "[" + host + "]";
url_parse::Component host_comp(0, host_brackets.size());
@@ -31,7 +35,26 @@ int ResolveIPV6LiteralUsingGURL(const std::string& host,
return ERR_UNEXPECTED;
}
- *addrlist = AddressList::CreateIPv6Address(ipv6_addr);
+ *addrlist = AddressList::CreateIPv6Address(ipv6_addr, canonical_name);
+ return OK;
+}
+
+// Fills |*addrlist| with a socket address for |host| which should be an
+// IPv4 literal. If |canonical_name| is non-empty it is used as the DNS
+// canonical name for the host. Returns OK on success, ERR_UNEXPECTED otherwise.
+int CreateIPv4Address(const std::string& host,
+ const std::string& canonical_name,
+ AddressList* addrlist) {
+ unsigned char ipv4_addr[4];
+ url_parse::Component host_comp(0, host.size());
+ int num_components;
+ url_canon::CanonHostInfo::Family family = url_canon::IPv4AddressToNumber(
+ host.data(), host_comp, ipv4_addr, &num_components);
+ if (family != url_canon::CanonHostInfo::IPV4) {
+ LOG(WARNING) << "Not an IPv4 literal: " << host;
+ return ERR_UNEXPECTED;
+ }
+ *addrlist = AddressList::CreateIPv4Address(ipv4_addr, canonical_name);
return OK;
}
@@ -104,23 +127,30 @@ struct RuleBasedHostResolverProc::Rule {
kResolverTypeFail,
kResolverTypeSystem,
kResolverTypeIPV6Literal,
+ kResolverTypeIPV4Literal,
};
ResolverType resolver_type;
std::string host_pattern;
AddressFamily address_family;
+ HostResolverFlags host_resolver_flags;
std::string replacement;
+ std::string canonical_name;
int latency_ms; // In milliseconds.
Rule(ResolverType resolver_type,
const std::string& host_pattern,
AddressFamily address_family,
+ HostResolverFlags host_resolver_flags,
const std::string& replacement,
+ const std::string& canonical_name,
int latency_ms)
: resolver_type(resolver_type),
host_pattern(host_pattern),
address_family(address_family),
+ host_resolver_flags(host_resolver_flags),
replacement(replacement),
+ canonical_name(canonical_name),
latency_ms(latency_ms) {}
};
@@ -143,16 +173,32 @@ void RuleBasedHostResolverProc::AddRuleForAddressFamily(
const std::string& replacement) {
DCHECK(!replacement.empty());
Rule rule(Rule::kResolverTypeSystem, host_pattern,
- address_family, replacement, 0);
+ address_family, 0, replacement, "", 0);
+ rules_.push_back(rule);
+}
+
+void RuleBasedHostResolverProc::AddIPv4Rule(const std::string& host_pattern,
+ const std::string& ipv4_literal,
+ const std::string& canonical_name) {
+ Rule rule(Rule::kResolverTypeIPV4Literal,
+ host_pattern,
+ ADDRESS_FAMILY_UNSPECIFIED,
+ canonical_name.empty() ? 0 : HOST_RESOLVER_CANONNAME,
+ ipv4_literal,
+ canonical_name,
+ 0);
rules_.push_back(rule);
}
void RuleBasedHostResolverProc::AddIPv6Rule(const std::string& host_pattern,
- const std::string& ipv6_literal) {
+ const std::string& ipv6_literal,
+ const std::string& canonical_name) {
Rule rule(Rule::kResolverTypeIPV6Literal,
host_pattern,
ADDRESS_FAMILY_UNSPECIFIED,
+ canonical_name.empty() ? 0 : HOST_RESOLVER_CANONNAME,
ipv6_literal,
+ canonical_name,
0);
rules_.push_back(rule);
}
@@ -163,21 +209,21 @@ void RuleBasedHostResolverProc::AddRuleWithLatency(
int latency_ms) {
DCHECK(!replacement.empty());
Rule rule(Rule::kResolverTypeSystem, host_pattern,
- ADDRESS_FAMILY_UNSPECIFIED, replacement, latency_ms);
+ ADDRESS_FAMILY_UNSPECIFIED, 0, replacement, "", latency_ms);
rules_.push_back(rule);
}
void RuleBasedHostResolverProc::AllowDirectLookup(
const std::string& host_pattern) {
Rule rule(Rule::kResolverTypeSystem, host_pattern,
- ADDRESS_FAMILY_UNSPECIFIED, "", 0);
+ ADDRESS_FAMILY_UNSPECIFIED, 0, "", "", 0);
rules_.push_back(rule);
}
void RuleBasedHostResolverProc::AddSimulatedFailure(
const std::string& host_pattern) {
Rule rule(Rule::kResolverTypeFail, host_pattern,
- ADDRESS_FAMILY_UNSPECIFIED, "", 0);
+ ADDRESS_FAMILY_UNSPECIFIED, 0, "", "", 0);
rules_.push_back(rule);
}
@@ -190,8 +236,14 @@ int RuleBasedHostResolverProc::Resolve(const std::string& host,
bool matches_address_family =
r->address_family == ADDRESS_FAMILY_UNSPECIFIED ||
r->address_family == address_family;
-
- if (matches_address_family && MatchPatternASCII(host, r->host_pattern)) {
+ // Flags match if all of the bitflags in host_resolver_flags are enabled
+ // in the rule's host_resolver_flags. However, the rule may have additional
+ // flags specified, in which case the flags should still be considered a
+ // match.
+ bool matches_flags = (r->host_resolver_flags & host_resolver_flags) ==
+ host_resolver_flags;
+ if (matches_flags && matches_address_family &&
+ MatchPatternASCII(host, r->host_pattern)) {
if (r->latency_ms != 0)
PlatformThread::Sleep(r->latency_ms);
@@ -209,7 +261,9 @@ int RuleBasedHostResolverProc::Resolve(const std::string& host,
host_resolver_flags,
addrlist);
case Rule::kResolverTypeIPV6Literal:
- return ResolveIPV6LiteralUsingGURL(effective_host, addrlist);
+ return CreateIPv6Address(effective_host, r->canonical_name, addrlist);
+ case Rule::kResolverTypeIPV4Literal:
+ return CreateIPv4Address(effective_host, r->canonical_name, addrlist);
default:
NOTREACHED();
return ERR_UNEXPECTED;
diff --git a/net/base/mock_host_resolver.h b/net/base/mock_host_resolver.h
index 5a1df7f..ad89a48 100644
--- a/net/base/mock_host_resolver.h
+++ b/net/base/mock_host_resolver.h
@@ -107,12 +107,26 @@ class RuleBasedHostResolverProc : public HostResolverProc {
AddressFamily address_family,
const std::string& replacement);
- // Same as AddRule(), but the replacement is expected to be an IPV6 literal.
- // You should use this in place of AddRule(), since the system's host resolver
- // may not support IPv6 literals on all systems. Whereas this variant
- // constructs the socket address directly so it will always work.
+ // Same as AddRule(), but the replacement is expected to be an IPV4 literal.
+ // This can be used in place of AddRule() to bypass the system's host
+ // resolver. |ipv4_literal| must be an IPv4 literal, typically taking the form
+ // of "[0-255].[0-255].[0-255].[0-255]".
+ // If |canonical-name| is non-empty, it is copied to the resulting AddressList
+ // but does not impact DNS resolution.
+ void AddIPv4Rule(const std::string& host_pattern,
+ const std::string& ipv4_literal,
+ const std::string& canonical_name);
+
+ // Same as AddRule(), but |ipv6_literal| is expected to be an IPV6 literal,
+ // without enclosing brackets. You should use this in place of AddRule(),
+ // since the system's host resolver may not support IPv6 literals on all
+ // systems. This variant constructs the socket address directly so it will
+ // always work.
+ // If |canonical-name| is non-empty, it is copied to the resulting AddressList
+ // but does not impact DNS resolution.
void AddIPv6Rule(const std::string& host_pattern,
- const std::string& ipv6_literal);
+ const std::string& ipv6_literal,
+ const std::string& canonical_name);
void AddRuleWithLatency(const std::string& host_pattern,
const std::string& replacement,
diff --git a/net/http/http_auth_handler_negotiate.h b/net/http/http_auth_handler_negotiate.h
index 7bb9426..77add14 100644
--- a/net/http/http_auth_handler_negotiate.h
+++ b/net/http/http_auth_handler_negotiate.h
@@ -108,6 +108,12 @@ class HttpAuthHandlerNegotiate : public HttpAuthHandler {
CompletionCallback* callback,
const BoundNetLog& net_log);
+#if defined(OS_WIN)
+ // These are public for unit tests
+ std::wstring CreateSPN(const AddressList& address_list, const GURL& orign);
+ const std::wstring& spn() const { return spn_; }
+#endif // defined(OS_WIN)
+
protected:
virtual bool Init(HttpAuth::ChallengeTokenizer* challenge);
@@ -116,8 +122,6 @@ class HttpAuthHandlerNegotiate : public HttpAuthHandler {
#if defined(OS_WIN)
void OnResolveCanonicalName(int result);
- std::wstring CreateSPN(const AddressList& address_list, const GURL& orign);
-
HttpAuthSSPI auth_sspi_;
AddressList address_list_;
scoped_ptr<SingleRequestHostResolver> single_resolve_;
diff --git a/net/http/http_auth_handler_negotiate_unittest.cc b/net/http/http_auth_handler_negotiate_unittest.cc
new file mode 100644
index 0000000..6ed882f
--- /dev/null
+++ b/net/http/http_auth_handler_negotiate_unittest.cc
@@ -0,0 +1,96 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/http/http_auth_handler_negotiate.h"
+
+#include "net/base/mock_host_resolver.h"
+#include "net/base/net_errors.h"
+#include "net/base/test_completion_callback.h"
+#if defined(OS_WIN)
+#include "net/http/mock_sspi_library_win.h"
+#endif
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+
+// TODO(cbentzel): Remove the OS_WIN condition once Negotiate is supported
+// on all platforms.
+#if defined(OS_WIN)
+namespace {
+
+void CreateHandler(bool disable_cname_lookup, bool include_port,
+ const std::string& url_string,
+ SSPILibrary* sspi_library,
+ scoped_refptr<HttpAuthHandlerNegotiate>* handler) {
+ *handler = new HttpAuthHandlerNegotiate(sspi_library, 50, NULL,
+ disable_cname_lookup,
+ include_port);
+ std::string challenge = "Negotiate";
+ HttpAuth::ChallengeTokenizer props(challenge.begin(), challenge.end());
+ GURL gurl(url_string);
+ (*handler)->InitFromChallenge(&props, HttpAuth::AUTH_SERVER, gurl);
+}
+
+} // namespace
+
+TEST(HttpAuthHandlerNegotiateTest, DisableCname) {
+ MockSSPILibrary mock_library;
+ scoped_refptr<HttpAuthHandlerNegotiate> auth_handler;
+ CreateHandler(true, false, "http://alias:500", &mock_library, &auth_handler);
+ EXPECT_FALSE(auth_handler->NeedsCanonicalName());
+ EXPECT_EQ(L"HTTP/alias", auth_handler->spn());
+}
+
+TEST(HttpAuthHandlerNegotiateTest, DisableCnameStandardPort) {
+ MockSSPILibrary mock_library;
+ scoped_refptr<HttpAuthHandlerNegotiate> auth_handler;
+ CreateHandler(true, true, "http://alias:80", &mock_library, &auth_handler);
+ EXPECT_FALSE(auth_handler->NeedsCanonicalName());
+ EXPECT_EQ(L"HTTP/alias", auth_handler->spn());
+}
+
+TEST(HttpAuthHandlerNegotiateTest, DisableCnameNonstandardPort) {
+ MockSSPILibrary mock_library;
+ scoped_refptr<HttpAuthHandlerNegotiate> auth_handler;
+ CreateHandler(true, true, "http://alias:500", &mock_library, &auth_handler);
+ EXPECT_FALSE(auth_handler->NeedsCanonicalName());
+ EXPECT_EQ(L"HTTP/alias:500", auth_handler->spn());
+}
+
+TEST(HttpAuthHandlerNegotiateTest, CnameSync) {
+ MockSSPILibrary mock_library;
+ scoped_refptr<HttpAuthHandlerNegotiate> auth_handler;
+ CreateHandler(false, false, "http://alias:500", &mock_library, &auth_handler);
+ EXPECT_TRUE(auth_handler->NeedsCanonicalName());
+ MockHostResolver* mock_resolver = new MockHostResolver();
+ scoped_refptr<HostResolver> scoped_resolver(mock_resolver);
+ mock_resolver->set_synchronous_mode(true);
+ mock_resolver->rules()->AddIPv4Rule("alias", "10.0.0.2",
+ "canonical.example.com");
+ TestCompletionCallback callback;
+ EXPECT_EQ(OK, auth_handler->ResolveCanonicalName(mock_resolver, &callback,
+ NULL));
+ EXPECT_EQ(L"HTTP/canonical.example.com", auth_handler->spn());
+}
+
+TEST(HttpAuthHandlerNegotiateTest, CnameAsync) {
+ MockSSPILibrary mock_library;
+ scoped_refptr<HttpAuthHandlerNegotiate> auth_handler;
+ CreateHandler(false, false, "http://alias:500", &mock_library, &auth_handler);
+ EXPECT_TRUE(auth_handler->NeedsCanonicalName());
+ MockHostResolver* mock_resolver = new MockHostResolver();
+ scoped_refptr<HostResolver> scoped_resolver(mock_resolver);
+ mock_resolver->set_synchronous_mode(false);
+ mock_resolver->rules()->AddIPv4Rule("alias", "10.0.0.2",
+ "canonical.example.com");
+ TestCompletionCallback callback;
+ EXPECT_EQ(ERR_IO_PENDING, auth_handler->ResolveCanonicalName(mock_resolver,
+ &callback,
+ NULL));
+ EXPECT_EQ(OK, callback.WaitForResult());
+ EXPECT_EQ(L"HTTP/canonical.example.com", auth_handler->spn());
+}
+#endif // defined(OS_WIN)
+
+} // namespace net
diff --git a/net/net.gyp b/net/net.gyp
index 7ef7bf2..a7f3095 100644
--- a/net/net.gyp
+++ b/net/net.gyp
@@ -674,6 +674,7 @@
'http/http_auth_handler_basic_unittest.cc',
'http/http_auth_handler_digest_unittest.cc',
'http/http_auth_handler_factory_unittest.cc',
+ 'http/http_auth_handler_negotiate_unittest.cc',
'http/http_auth_sspi_win_unittest.cc',
'http/http_auth_unittest.cc',
'http/http_byte_range_unittest.cc',
diff --git a/net/socket/socks_client_socket_unittest.cc b/net/socket/socks_client_socket_unittest.cc
index eb2ab6a..f05a7db 100644
--- a/net/socket/socks_client_socket_unittest.cc
+++ b/net/socket/socks_client_socket_unittest.cc
@@ -341,7 +341,7 @@ TEST_F(SOCKSClientSocketTest, SOCKS4AFailedDNS) {
TEST_F(SOCKSClientSocketTest, SOCKS4AIfDomainInIPv6) {
const char hostname[] = "an.ipv6.address";
- host_resolver_->rules()->AddIPv6Rule(hostname, "2001:db8:8714:3a90::12");
+ host_resolver_->rules()->AddIPv6Rule(hostname, "2001:db8:8714:3a90::12", "");
std::string request(kSOCKS4aInitialRequest,
arraysize(kSOCKS4aInitialRequest));