1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "net/dns/dns_config_service.h" 6 7 #include "base/logging.h" 8 #include "base/metrics/histogram.h" 9 #include "base/values.h" 10 #include "net/base/ip_endpoint.h" 11 #include "net/base/ip_pattern.h" 12 13 namespace net { 14 15 NameServerClassifier::NameServerClassifier() { 16 // Google Public DNS addresses from: 17 // https://developers.google.com/speed/public-dns/docs/using 18 AddRule("8.8.8.8", NAME_SERVERS_TYPE_GOOGLE_PUBLIC_DNS); 19 AddRule("8.8.4.4", NAME_SERVERS_TYPE_GOOGLE_PUBLIC_DNS); 20 AddRule("2001:4860:4860:0:0:0:0:8888", NAME_SERVERS_TYPE_GOOGLE_PUBLIC_DNS), 21 AddRule("2001:4860:4860:0:0:0:0:8844", NAME_SERVERS_TYPE_GOOGLE_PUBLIC_DNS), 22 23 // Count localhost as private, since we don't know what upstream it uses: 24 AddRule("127.*.*.*", NAME_SERVERS_TYPE_PRIVATE); 25 AddRule("0:0:0:0:0:0:0:1", NAME_SERVERS_TYPE_PRIVATE); 26 27 // RFC 1918 private addresses: 28 AddRule("10.*.*.*", NAME_SERVERS_TYPE_PRIVATE); 29 AddRule("172.[16-31].*.*", NAME_SERVERS_TYPE_PRIVATE); 30 AddRule("192.168.*.*", NAME_SERVERS_TYPE_PRIVATE); 31 32 // IPv4 link-local addresses: 33 AddRule("169.254.*.*", NAME_SERVERS_TYPE_PRIVATE); 34 35 // IPv6 link-local addresses: 36 AddRule("fe80:*:*:*:*:*:*:*", NAME_SERVERS_TYPE_PRIVATE); 37 38 // Anything else counts as public: 39 AddRule("*.*.*.*", NAME_SERVERS_TYPE_PUBLIC); 40 AddRule("*:*:*:*:*:*:*:*", NAME_SERVERS_TYPE_PUBLIC); 41 } 42 43 NameServerClassifier::~NameServerClassifier() {} 44 45 NameServerClassifier::NameServersType NameServerClassifier::GetNameServersType( 46 const std::vector<IPEndPoint>& nameservers) const { 47 NameServersType type = NAME_SERVERS_TYPE_NONE; 48 for (std::vector<IPEndPoint>::const_iterator it = nameservers.begin(); 49 it != nameservers.end(); 50 ++it) { 51 type = MergeNameServersTypes(type, GetNameServerType(it->address())); 52 } 53 return type; 54 } 55 56 struct NameServerClassifier::NameServerTypeRule { 57 NameServerTypeRule(const char* pattern_string, NameServersType type) 58 : type(type) { 59 bool parsed = pattern.ParsePattern(pattern_string); 60 DCHECK(parsed); 61 } 62 63 IPPattern pattern; 64 NameServersType type; 65 }; 66 67 void NameServerClassifier::AddRule(const char* pattern_string, 68 NameServersType address_type) { 69 rules_.push_back(new NameServerTypeRule(pattern_string, address_type)); 70 } 71 72 NameServerClassifier::NameServersType NameServerClassifier::GetNameServerType( 73 const IPAddressNumber& address) const { 74 for (ScopedVector<NameServerTypeRule>::const_iterator it = rules_.begin(); 75 it != rules_.end(); 76 ++it) { 77 if ((*it)->pattern.Match(address)) 78 return (*it)->type; 79 } 80 NOTREACHED(); 81 return NAME_SERVERS_TYPE_NONE; 82 } 83 84 NameServerClassifier::NameServersType 85 NameServerClassifier::MergeNameServersTypes(NameServersType a, 86 NameServersType b) { 87 if (a == NAME_SERVERS_TYPE_NONE) 88 return b; 89 if (b == NAME_SERVERS_TYPE_NONE) 90 return a; 91 if (a == b) 92 return a; 93 return NAME_SERVERS_TYPE_MIXED; 94 } 95 96 // Default values are taken from glibc resolv.h except timeout which is set to 97 // |kDnsTimeoutSeconds|. 98 DnsConfig::DnsConfig() 99 : unhandled_options(false), 100 append_to_multi_label_name(true), 101 randomize_ports(false), 102 ndots(1), 103 timeout(base::TimeDelta::FromSeconds(kDnsTimeoutSeconds)), 104 attempts(2), 105 rotate(false), 106 edns0(false), 107 use_local_ipv6(false) {} 108 109 DnsConfig::~DnsConfig() {} 110 111 bool DnsConfig::Equals(const DnsConfig& d) const { 112 return EqualsIgnoreHosts(d) && (hosts == d.hosts); 113 } 114 115 bool DnsConfig::EqualsIgnoreHosts(const DnsConfig& d) const { 116 return (nameservers == d.nameservers) && 117 (search == d.search) && 118 (unhandled_options == d.unhandled_options) && 119 (append_to_multi_label_name == d.append_to_multi_label_name) && 120 (ndots == d.ndots) && 121 (timeout == d.timeout) && 122 (attempts == d.attempts) && 123 (rotate == d.rotate) && 124 (edns0 == d.edns0) && 125 (use_local_ipv6 == d.use_local_ipv6); 126 } 127 128 void DnsConfig::CopyIgnoreHosts(const DnsConfig& d) { 129 nameservers = d.nameservers; 130 search = d.search; 131 unhandled_options = d.unhandled_options; 132 append_to_multi_label_name = d.append_to_multi_label_name; 133 ndots = d.ndots; 134 timeout = d.timeout; 135 attempts = d.attempts; 136 rotate = d.rotate; 137 edns0 = d.edns0; 138 use_local_ipv6 = d.use_local_ipv6; 139 } 140 141 base::Value* DnsConfig::ToValue() const { 142 base::DictionaryValue* dict = new base::DictionaryValue(); 143 144 base::ListValue* list = new base::ListValue(); 145 for (size_t i = 0; i < nameservers.size(); ++i) 146 list->Append(new base::StringValue(nameservers[i].ToString())); 147 dict->Set("nameservers", list); 148 149 list = new base::ListValue(); 150 for (size_t i = 0; i < search.size(); ++i) 151 list->Append(new base::StringValue(search[i])); 152 dict->Set("search", list); 153 154 dict->SetBoolean("unhandled_options", unhandled_options); 155 dict->SetBoolean("append_to_multi_label_name", append_to_multi_label_name); 156 dict->SetInteger("ndots", ndots); 157 dict->SetDouble("timeout", timeout.InSecondsF()); 158 dict->SetInteger("attempts", attempts); 159 dict->SetBoolean("rotate", rotate); 160 dict->SetBoolean("edns0", edns0); 161 dict->SetBoolean("use_local_ipv6", use_local_ipv6); 162 dict->SetInteger("num_hosts", hosts.size()); 163 164 return dict; 165 } 166 167 168 DnsConfigService::DnsConfigService() 169 : watch_failed_(false), 170 have_config_(false), 171 have_hosts_(false), 172 need_update_(false), 173 last_sent_empty_(true) {} 174 175 DnsConfigService::~DnsConfigService() { 176 } 177 178 void DnsConfigService::ReadConfig(const CallbackType& callback) { 179 DCHECK(CalledOnValidThread()); 180 DCHECK(!callback.is_null()); 181 DCHECK(callback_.is_null()); 182 callback_ = callback; 183 ReadNow(); 184 } 185 186 void DnsConfigService::WatchConfig(const CallbackType& callback) { 187 DCHECK(CalledOnValidThread()); 188 DCHECK(!callback.is_null()); 189 DCHECK(callback_.is_null()); 190 callback_ = callback; 191 watch_failed_ = !StartWatching(); 192 ReadNow(); 193 } 194 195 void DnsConfigService::InvalidateConfig() { 196 DCHECK(CalledOnValidThread()); 197 base::TimeTicks now = base::TimeTicks::Now(); 198 if (!last_invalidate_config_time_.is_null()) { 199 UMA_HISTOGRAM_LONG_TIMES("AsyncDNS.ConfigNotifyInterval", 200 now - last_invalidate_config_time_); 201 } 202 last_invalidate_config_time_ = now; 203 if (!have_config_) 204 return; 205 have_config_ = false; 206 StartTimer(); 207 } 208 209 void DnsConfigService::InvalidateHosts() { 210 DCHECK(CalledOnValidThread()); 211 base::TimeTicks now = base::TimeTicks::Now(); 212 if (!last_invalidate_hosts_time_.is_null()) { 213 UMA_HISTOGRAM_LONG_TIMES("AsyncDNS.HostsNotifyInterval", 214 now - last_invalidate_hosts_time_); 215 } 216 last_invalidate_hosts_time_ = now; 217 if (!have_hosts_) 218 return; 219 have_hosts_ = false; 220 StartTimer(); 221 } 222 223 void DnsConfigService::OnConfigRead(const DnsConfig& config) { 224 DCHECK(CalledOnValidThread()); 225 DCHECK(config.IsValid()); 226 227 bool changed = false; 228 if (!config.EqualsIgnoreHosts(dns_config_)) { 229 dns_config_.CopyIgnoreHosts(config); 230 need_update_ = true; 231 changed = true; 232 } 233 if (!changed && !last_sent_empty_time_.is_null()) { 234 UMA_HISTOGRAM_LONG_TIMES("AsyncDNS.UnchangedConfigInterval", 235 base::TimeTicks::Now() - last_sent_empty_time_); 236 } 237 UMA_HISTOGRAM_BOOLEAN("AsyncDNS.ConfigChange", changed); 238 UMA_HISTOGRAM_ENUMERATION( 239 "AsyncDNS.NameServersType", 240 classifier_.GetNameServersType(dns_config_.nameservers), 241 NameServerClassifier::NAME_SERVERS_TYPE_MAX_VALUE); 242 243 have_config_ = true; 244 if (have_hosts_ || watch_failed_) 245 OnCompleteConfig(); 246 } 247 248 void DnsConfigService::OnHostsRead(const DnsHosts& hosts) { 249 DCHECK(CalledOnValidThread()); 250 251 bool changed = false; 252 if (hosts != dns_config_.hosts) { 253 dns_config_.hosts = hosts; 254 need_update_ = true; 255 changed = true; 256 } 257 if (!changed && !last_sent_empty_time_.is_null()) { 258 UMA_HISTOGRAM_LONG_TIMES("AsyncDNS.UnchangedHostsInterval", 259 base::TimeTicks::Now() - last_sent_empty_time_); 260 } 261 UMA_HISTOGRAM_BOOLEAN("AsyncDNS.HostsChange", changed); 262 263 have_hosts_ = true; 264 if (have_config_ || watch_failed_) 265 OnCompleteConfig(); 266 } 267 268 void DnsConfigService::StartTimer() { 269 DCHECK(CalledOnValidThread()); 270 if (last_sent_empty_) { 271 DCHECK(!timer_.IsRunning()); 272 return; // No need to withdraw again. 273 } 274 timer_.Stop(); 275 276 // Give it a short timeout to come up with a valid config. Otherwise withdraw 277 // the config from the receiver. The goal is to avoid perceivable network 278 // outage (when using the wrong config) but at the same time avoid 279 // unnecessary Job aborts in HostResolverImpl. The signals come from multiple 280 // sources so it might receive multiple events during a config change. 281 282 // DHCP and user-induced changes are on the order of seconds, so 150ms should 283 // not add perceivable delay. On the other hand, config readers should finish 284 // within 150ms with the rare exception of I/O block or extra large HOSTS. 285 const base::TimeDelta kTimeout = base::TimeDelta::FromMilliseconds(150); 286 287 timer_.Start(FROM_HERE, 288 kTimeout, 289 this, 290 &DnsConfigService::OnTimeout); 291 } 292 293 void DnsConfigService::OnTimeout() { 294 DCHECK(CalledOnValidThread()); 295 DCHECK(!last_sent_empty_); 296 // Indicate that even if there is no change in On*Read, we will need to 297 // update the receiver when the config becomes complete. 298 need_update_ = true; 299 // Empty config is considered invalid. 300 last_sent_empty_ = true; 301 last_sent_empty_time_ = base::TimeTicks::Now(); 302 callback_.Run(DnsConfig()); 303 } 304 305 void DnsConfigService::OnCompleteConfig() { 306 timer_.Stop(); 307 if (!need_update_) 308 return; 309 need_update_ = false; 310 last_sent_empty_ = false; 311 if (watch_failed_) { 312 // If a watch failed, the config may not be accurate, so report empty. 313 callback_.Run(DnsConfig()); 314 } else { 315 callback_.Run(dns_config_); 316 } 317 } 318 319 } // namespace net 320 321