• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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