Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / net / dns / dns_config_service.cc
blob447f7083c1fa2f73d7cd4afc9be35af610ae5f4e
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.
5 #include "net/dns/dns_config_service.h"
7 #include "base/logging.h"
8 #include "base/metrics/histogram_macros.h"
9 #include "base/values.h"
10 #include "net/base/ip_endpoint.h"
11 #include "net/base/ip_pattern.h"
13 namespace net {
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),
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);
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);
32 // IPv4 link-local addresses:
33 AddRule("169.254.*.*", NAME_SERVERS_TYPE_PRIVATE);
35 // IPv6 link-local addresses:
36 AddRule("fe80:*:*:*:*:*:*:*", NAME_SERVERS_TYPE_PRIVATE);
38 // Anything else counts as public:
39 AddRule("*.*.*.*", NAME_SERVERS_TYPE_PUBLIC);
40 AddRule("*:*:*:*:*:*:*:*", NAME_SERVERS_TYPE_PUBLIC);
43 NameServerClassifier::~NameServerClassifier() {}
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()));
53 return type;
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);
63 IPPattern pattern;
64 NameServersType type;
67 void NameServerClassifier::AddRule(const char* pattern_string,
68 NameServersType address_type) {
69 rules_.push_back(new NameServerTypeRule(pattern_string, address_type));
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;
80 NOTREACHED();
81 return NAME_SERVERS_TYPE_NONE;
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;
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) {}
109 DnsConfig::~DnsConfig() {}
111 bool DnsConfig::Equals(const DnsConfig& d) const {
112 return EqualsIgnoreHosts(d) && (hosts == d.hosts);
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);
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;
141 base::Value* DnsConfig::ToValue() const {
142 scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
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);
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);
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());
164 return dict.release();
167 DnsConfigService::DnsConfigService()
168 : watch_failed_(false),
169 have_config_(false),
170 have_hosts_(false),
171 need_update_(false),
172 last_sent_empty_(true) {}
174 DnsConfigService::~DnsConfigService() {
177 void DnsConfigService::ReadConfig(const CallbackType& callback) {
178 DCHECK(CalledOnValidThread());
179 DCHECK(!callback.is_null());
180 DCHECK(callback_.is_null());
181 callback_ = callback;
182 ReadNow();
185 void DnsConfigService::WatchConfig(const CallbackType& callback) {
186 DCHECK(CalledOnValidThread());
187 DCHECK(!callback.is_null());
188 DCHECK(callback_.is_null());
189 callback_ = callback;
190 watch_failed_ = !StartWatching();
191 ReadNow();
194 void DnsConfigService::InvalidateConfig() {
195 DCHECK(CalledOnValidThread());
196 base::TimeTicks now = base::TimeTicks::Now();
197 if (!last_invalidate_config_time_.is_null()) {
198 UMA_HISTOGRAM_LONG_TIMES("AsyncDNS.ConfigNotifyInterval",
199 now - last_invalidate_config_time_);
201 last_invalidate_config_time_ = now;
202 if (!have_config_)
203 return;
204 have_config_ = false;
205 StartTimer();
208 void DnsConfigService::InvalidateHosts() {
209 DCHECK(CalledOnValidThread());
210 base::TimeTicks now = base::TimeTicks::Now();
211 if (!last_invalidate_hosts_time_.is_null()) {
212 UMA_HISTOGRAM_LONG_TIMES("AsyncDNS.HostsNotifyInterval",
213 now - last_invalidate_hosts_time_);
215 last_invalidate_hosts_time_ = now;
216 if (!have_hosts_)
217 return;
218 have_hosts_ = false;
219 StartTimer();
222 void DnsConfigService::OnConfigRead(const DnsConfig& config) {
223 DCHECK(CalledOnValidThread());
224 DCHECK(config.IsValid());
226 bool changed = false;
227 if (!config.EqualsIgnoreHosts(dns_config_)) {
228 dns_config_.CopyIgnoreHosts(config);
229 need_update_ = true;
230 changed = true;
232 if (!changed && !last_sent_empty_time_.is_null()) {
233 UMA_HISTOGRAM_LONG_TIMES("AsyncDNS.UnchangedConfigInterval",
234 base::TimeTicks::Now() - last_sent_empty_time_);
236 UMA_HISTOGRAM_BOOLEAN("AsyncDNS.ConfigChange", changed);
237 UMA_HISTOGRAM_ENUMERATION(
238 "AsyncDNS.NameServersType",
239 classifier_.GetNameServersType(dns_config_.nameservers),
240 NameServerClassifier::NAME_SERVERS_TYPE_MAX_VALUE);
242 have_config_ = true;
243 if (have_hosts_ || watch_failed_)
244 OnCompleteConfig();
247 void DnsConfigService::OnHostsRead(const DnsHosts& hosts) {
248 DCHECK(CalledOnValidThread());
250 bool changed = false;
251 if (hosts != dns_config_.hosts) {
252 dns_config_.hosts = hosts;
253 need_update_ = true;
254 changed = true;
256 if (!changed && !last_sent_empty_time_.is_null()) {
257 UMA_HISTOGRAM_LONG_TIMES("AsyncDNS.UnchangedHostsInterval",
258 base::TimeTicks::Now() - last_sent_empty_time_);
260 UMA_HISTOGRAM_BOOLEAN("AsyncDNS.HostsChange", changed);
262 have_hosts_ = true;
263 if (have_config_ || watch_failed_)
264 OnCompleteConfig();
267 void DnsConfigService::StartTimer() {
268 DCHECK(CalledOnValidThread());
269 if (last_sent_empty_) {
270 DCHECK(!timer_.IsRunning());
271 return; // No need to withdraw again.
273 timer_.Stop();
275 // Give it a short timeout to come up with a valid config. Otherwise withdraw
276 // the config from the receiver. The goal is to avoid perceivable network
277 // outage (when using the wrong config) but at the same time avoid
278 // unnecessary Job aborts in HostResolverImpl. The signals come from multiple
279 // sources so it might receive multiple events during a config change.
281 // DHCP and user-induced changes are on the order of seconds, so 150ms should
282 // not add perceivable delay. On the other hand, config readers should finish
283 // within 150ms with the rare exception of I/O block or extra large HOSTS.
284 const base::TimeDelta kTimeout = base::TimeDelta::FromMilliseconds(150);
286 timer_.Start(FROM_HERE,
287 kTimeout,
288 this,
289 &DnsConfigService::OnTimeout);
292 void DnsConfigService::OnTimeout() {
293 DCHECK(CalledOnValidThread());
294 DCHECK(!last_sent_empty_);
295 // Indicate that even if there is no change in On*Read, we will need to
296 // update the receiver when the config becomes complete.
297 need_update_ = true;
298 // Empty config is considered invalid.
299 last_sent_empty_ = true;
300 last_sent_empty_time_ = base::TimeTicks::Now();
301 callback_.Run(DnsConfig());
304 void DnsConfigService::OnCompleteConfig() {
305 timer_.Stop();
306 if (!need_update_)
307 return;
308 need_update_ = false;
309 last_sent_empty_ = false;
310 if (watch_failed_) {
311 // If a watch failed, the config may not be accurate, so report empty.
312 callback_.Run(DnsConfig());
313 } else {
314 callback_.Run(dns_config_);
318 } // namespace net