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
NameServerClassifier()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
~NameServerClassifier()43 NameServerClassifier::~NameServerClassifier() {}
44
GetNameServersType(const std::vector<IPEndPoint> & nameservers) const45 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 {
NameServerTypeRulenet::NameServerClassifier::NameServerTypeRule57 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
AddRule(const char * pattern_string,NameServersType address_type)67 void NameServerClassifier::AddRule(const char* pattern_string,
68 NameServersType address_type) {
69 rules_.push_back(new NameServerTypeRule(pattern_string, address_type));
70 }
71
GetNameServerType(const IPAddressNumber & address) const72 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
MergeNameServersTypes(NameServersType a,NameServersType b)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|.
DnsConfig()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
~DnsConfig()109 DnsConfig::~DnsConfig() {}
110
Equals(const DnsConfig & d) const111 bool DnsConfig::Equals(const DnsConfig& d) const {
112 return EqualsIgnoreHosts(d) && (hosts == d.hosts);
113 }
114
EqualsIgnoreHosts(const DnsConfig & d) const115 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
CopyIgnoreHosts(const DnsConfig & d)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
ToValue() const141 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
DnsConfigService()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
~DnsConfigService()175 DnsConfigService::~DnsConfigService() {
176 }
177
ReadConfig(const CallbackType & callback)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
WatchConfig(const CallbackType & callback)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
InvalidateConfig()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
InvalidateHosts()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
OnConfigRead(const DnsConfig & config)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
OnHostsRead(const DnsHosts & hosts)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
StartTimer()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
OnTimeout()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
OnCompleteConfig()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