// Copyright (c) 2011 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/base/mock_host_resolver.h" #include "base/memory/ref_counted.h" #include "base/string_split.h" #include "base/string_util.h" #include "base/threading/platform_thread.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_list| which should be a // comma-separated list of IPv4 or IPv6 literal(s) 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 CreateIPAddressList(const std::string& host_list, const std::string& canonical_name, AddressList* addrlist) { *addrlist = AddressList(); std::vector<std::string> addresses; base::SplitString(host_list, ',', &addresses); for (size_t index = 0; index < addresses.size(); ++index) { IPAddressNumber ip_number; if (!ParseIPLiteralToNumber(addresses[index], &ip_number)) { LOG(WARNING) << "Not a supported IP literal: " << addresses[index]; return ERR_UNEXPECTED; } AddressList result(ip_number, -1, false); struct addrinfo* ai = const_cast<struct addrinfo*>(result.head()); if (index == 0) ai->ai_canonname = do_strdup(canonical_name.c_str()); if (!addrlist->head()) addrlist->Copy(result.head(), false); else addrlist->Append(result.head()); } return OK; } } // namespace MockHostResolverBase::~MockHostResolverBase() {} void MockHostResolverBase::Reset(HostResolverProc* interceptor) { synchronous_mode_ = false; // At the root of the chain, map everything to localhost. scoped_refptr<RuleBasedHostResolverProc> catchall( new RuleBasedHostResolverProc(NULL)); catchall->AddRule("*", "127.0.0.1"); // Next add a rules-based layer the use controls. rules_ = new RuleBasedHostResolverProc(catchall); HostResolverProc* proc = rules_; // Lastly add the provided interceptor to the front of the chain. if (interceptor) { interceptor->SetPreviousProc(proc); proc = interceptor; } HostCache* cache = NULL; if (use_caching_) { cache = new HostCache( 100, // max entries. base::TimeDelta::FromMinutes(1), base::TimeDelta::FromSeconds(0)); } impl_.reset(new HostResolverImpl(proc, cache, 50u, NULL)); } int MockHostResolverBase::Resolve(const RequestInfo& info, AddressList* addresses, CompletionCallback* callback, RequestHandle* out_req, const BoundNetLog& net_log) { if (synchronous_mode_) { callback = NULL; out_req = NULL; } return impl_->Resolve(info, addresses, callback, out_req, net_log); } void MockHostResolverBase::CancelRequest(RequestHandle req) { impl_->CancelRequest(req); } void MockHostResolverBase::AddObserver(Observer* observer) { impl_->AddObserver(observer); } void MockHostResolverBase::RemoveObserver(Observer* observer) { impl_->RemoveObserver(observer); } MockHostResolverBase::MockHostResolverBase(bool use_caching) : use_caching_(use_caching) { Reset(NULL); } //----------------------------------------------------------------------------- struct RuleBasedHostResolverProc::Rule { enum ResolverType { kResolverTypeFail, kResolverTypeSystem, kResolverTypeIPLiteral, }; 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) {} }; RuleBasedHostResolverProc::RuleBasedHostResolverProc(HostResolverProc* previous) : HostResolverProc(previous) { } void RuleBasedHostResolverProc::AddRule(const std::string& host_pattern, const std::string& replacement) { AddRuleForAddressFamily(host_pattern, ADDRESS_FAMILY_UNSPECIFIED, replacement); } void RuleBasedHostResolverProc::AddRuleForAddressFamily( const std::string& host_pattern, AddressFamily address_family, const std::string& replacement) { DCHECK(!replacement.empty()); HostResolverFlags flags = HOST_RESOLVER_LOOPBACK_ONLY | HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6; Rule rule(Rule::kResolverTypeSystem, host_pattern, address_family, flags, replacement, "", 0); rules_.push_back(rule); } 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)); HostResolverFlags flags = HOST_RESOLVER_LOOPBACK_ONLY | HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6; if (!canonical_name.empty()) flags |= HOST_RESOLVER_CANONNAME; Rule rule(Rule::kResolverTypeIPLiteral, host_pattern, ADDRESS_FAMILY_UNSPECIFIED, flags, ip_literal, canonical_name, 0); rules_.push_back(rule); } void RuleBasedHostResolverProc::AddRuleWithLatency( const std::string& host_pattern, const std::string& replacement, int latency_ms) { DCHECK(!replacement.empty()); HostResolverFlags flags = HOST_RESOLVER_LOOPBACK_ONLY | HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6; Rule rule(Rule::kResolverTypeSystem, host_pattern, ADDRESS_FAMILY_UNSPECIFIED, flags, replacement, "", latency_ms); rules_.push_back(rule); } void RuleBasedHostResolverProc::AllowDirectLookup( const std::string& host_pattern) { HostResolverFlags flags = HOST_RESOLVER_LOOPBACK_ONLY | HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6; Rule rule(Rule::kResolverTypeSystem, host_pattern, ADDRESS_FAMILY_UNSPECIFIED, flags, "", "", 0); rules_.push_back(rule); } void RuleBasedHostResolverProc::AddSimulatedFailure( const std::string& host_pattern) { HostResolverFlags flags = HOST_RESOLVER_LOOPBACK_ONLY | HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6; Rule rule(Rule::kResolverTypeFail, host_pattern, ADDRESS_FAMILY_UNSPECIFIED, flags, "", "", 0); rules_.push_back(rule); } int RuleBasedHostResolverProc::Resolve(const std::string& host, AddressFamily address_family, HostResolverFlags host_resolver_flags, AddressList* addrlist, int* os_error) { RuleList::iterator r; for (r = rules_.begin(); r != rules_.end(); ++r) { bool matches_address_family = r->address_family == ADDRESS_FAMILY_UNSPECIFIED || r->address_family == address_family; // 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 && MatchPattern(host, r->host_pattern)) { if (r->latency_ms != 0) base::PlatformThread::Sleep(r->latency_ms); // Remap to a new host. const std::string& effective_host = r->replacement.empty() ? host : r->replacement; // Apply the resolving function to the remapped hostname. switch (r->resolver_type) { case Rule::kResolverTypeFail: return ERR_NAME_NOT_RESOLVED; case Rule::kResolverTypeSystem: return SystemHostResolverProc(effective_host, address_family, host_resolver_flags, addrlist, os_error); case Rule::kResolverTypeIPLiteral: return CreateIPAddressList(effective_host, r->canonical_name, addrlist); default: NOTREACHED(); return ERR_UNEXPECTED; } } } return ResolveUsingPrevious(host, address_family, host_resolver_flags, addrlist, os_error); } RuleBasedHostResolverProc::~RuleBasedHostResolverProc() { } //----------------------------------------------------------------------------- WaitingHostResolverProc::WaitingHostResolverProc(HostResolverProc* previous) : HostResolverProc(previous), event_(false, false) {} void WaitingHostResolverProc::Signal() { event_.Signal(); } int WaitingHostResolverProc::Resolve(const std::string& host, AddressFamily address_family, HostResolverFlags host_resolver_flags, AddressList* addrlist, int* os_error) { event_.Wait(); return ResolveUsingPrevious(host, address_family, host_resolver_flags, addrlist, os_error); } WaitingHostResolverProc::~WaitingHostResolverProc() {} //----------------------------------------------------------------------------- ScopedDefaultHostResolverProc::ScopedDefaultHostResolverProc() {} ScopedDefaultHostResolverProc::ScopedDefaultHostResolverProc( HostResolverProc* proc) { Init(proc); } ScopedDefaultHostResolverProc::~ScopedDefaultHostResolverProc() { HostResolverProc* old_proc = HostResolverProc::SetDefault(previous_proc_); // The lifetimes of multiple instances must be nested. CHECK_EQ(old_proc, current_proc_); } void ScopedDefaultHostResolverProc::Init(HostResolverProc* proc) { current_proc_ = proc; previous_proc_ = HostResolverProc::SetDefault(current_proc_); current_proc_->SetLastProc(previous_proc_); } } // namespace net