15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/dns/dns_config_service.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/metrics/histogram.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/values.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/ip_endpoint.h"
11a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "net/base/ip_pattern.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace net {
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)NameServerClassifier::NameServerClassifier() {
16a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Google Public DNS addresses from:
17a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // https://developers.google.com/speed/public-dns/docs/using
18a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  AddRule("8.8.8.8", NAME_SERVERS_TYPE_GOOGLE_PUBLIC_DNS);
19a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  AddRule("8.8.4.4", NAME_SERVERS_TYPE_GOOGLE_PUBLIC_DNS);
20a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  AddRule("2001:4860:4860:0:0:0:0:8888", NAME_SERVERS_TYPE_GOOGLE_PUBLIC_DNS),
21a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  AddRule("2001:4860:4860:0:0:0:0:8844", NAME_SERVERS_TYPE_GOOGLE_PUBLIC_DNS),
22a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
23a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Count localhost as private, since we don't know what upstream it uses:
24a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  AddRule("127.*.*.*", NAME_SERVERS_TYPE_PRIVATE);
25a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  AddRule("0:0:0:0:0:0:0:1", NAME_SERVERS_TYPE_PRIVATE);
26a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
27a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // RFC 1918 private addresses:
28a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  AddRule("10.*.*.*", NAME_SERVERS_TYPE_PRIVATE);
29a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  AddRule("172.[16-31].*.*", NAME_SERVERS_TYPE_PRIVATE);
30a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  AddRule("192.168.*.*", NAME_SERVERS_TYPE_PRIVATE);
31a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
32a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // IPv4 link-local addresses:
33a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  AddRule("169.254.*.*", NAME_SERVERS_TYPE_PRIVATE);
34a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
35a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // IPv6 link-local addresses:
36a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  AddRule("fe80:*:*:*:*:*:*:*", NAME_SERVERS_TYPE_PRIVATE);
37a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
38a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Anything else counts as public:
39a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  AddRule("*.*.*.*", NAME_SERVERS_TYPE_PUBLIC);
40a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  AddRule("*:*:*:*:*:*:*:*", NAME_SERVERS_TYPE_PUBLIC);
41a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
42a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
43a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)NameServerClassifier::~NameServerClassifier() {}
44a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
45a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)NameServerClassifier::NameServersType NameServerClassifier::GetNameServersType(
46a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const std::vector<IPEndPoint>& nameservers) const {
47a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  NameServersType type = NAME_SERVERS_TYPE_NONE;
48a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  for (std::vector<IPEndPoint>::const_iterator it = nameservers.begin();
49a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)       it != nameservers.end();
50a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)       ++it) {
51a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    type = MergeNameServersTypes(type, GetNameServerType(it->address()));
52a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
53a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return type;
54a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
55a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
56a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)struct NameServerClassifier::NameServerTypeRule {
57a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  NameServerTypeRule(const char* pattern_string, NameServersType type)
58a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      : type(type) {
59a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    bool parsed = pattern.ParsePattern(pattern_string);
60a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    DCHECK(parsed);
61a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
62a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
63a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  IPPattern pattern;
64a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  NameServersType type;
65a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)};
66a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
67a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void NameServerClassifier::AddRule(const char* pattern_string,
68a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                   NameServersType address_type) {
69a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  rules_.push_back(new NameServerTypeRule(pattern_string, address_type));
70a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
71a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
72a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)NameServerClassifier::NameServersType NameServerClassifier::GetNameServerType(
73a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const IPAddressNumber& address) const {
74a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  for (ScopedVector<NameServerTypeRule>::const_iterator it = rules_.begin();
75a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)       it != rules_.end();
76a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)       ++it) {
77a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if ((*it)->pattern.Match(address))
78a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      return (*it)->type;
79a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
80a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  NOTREACHED();
81a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return NAME_SERVERS_TYPE_NONE;
82a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
83a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
84a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)NameServerClassifier::NameServersType
85a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)NameServerClassifier::MergeNameServersTypes(NameServersType a,
86a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                            NameServersType b) {
87a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (a == NAME_SERVERS_TYPE_NONE)
88a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return b;
89a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (b == NAME_SERVERS_TYPE_NONE)
90a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return a;
91a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (a == b)
92a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return a;
93a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return NAME_SERVERS_TYPE_MIXED;
94a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
95a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Default values are taken from glibc resolv.h except timeout which is set to
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// |kDnsTimeoutSeconds|.
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DnsConfig::DnsConfig()
993551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    : unhandled_options(false),
1003551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      append_to_multi_label_name(true),
101c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      randomize_ports(false),
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ndots(1),
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      timeout(base::TimeDelta::FromSeconds(kDnsTimeoutSeconds)),
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      attempts(2),
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      rotate(false),
106d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      edns0(false),
107d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      use_local_ipv6(false) {}
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DnsConfig::~DnsConfig() {}
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DnsConfig::Equals(const DnsConfig& d) const {
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return EqualsIgnoreHosts(d) && (hosts == d.hosts);
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DnsConfig::EqualsIgnoreHosts(const DnsConfig& d) const {
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (nameservers == d.nameservers) &&
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         (search == d.search) &&
1183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)         (unhandled_options == d.unhandled_options) &&
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         (append_to_multi_label_name == d.append_to_multi_label_name) &&
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         (ndots == d.ndots) &&
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         (timeout == d.timeout) &&
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         (attempts == d.attempts) &&
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         (rotate == d.rotate) &&
124d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)         (edns0 == d.edns0) &&
125d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)         (use_local_ipv6 == d.use_local_ipv6);
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DnsConfig::CopyIgnoreHosts(const DnsConfig& d) {
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  nameservers = d.nameservers;
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  search = d.search;
1313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  unhandled_options = d.unhandled_options;
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  append_to_multi_label_name = d.append_to_multi_label_name;
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ndots = d.ndots;
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  timeout = d.timeout;
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  attempts = d.attempts;
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  rotate = d.rotate;
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  edns0 = d.edns0;
138d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  use_local_ipv6 = d.use_local_ipv6;
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)base::Value* DnsConfig::ToValue() const {
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::DictionaryValue* dict = new base::DictionaryValue();
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::ListValue* list = new base::ListValue();
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < nameservers.size(); ++i)
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    list->Append(new base::StringValue(nameservers[i].ToString()));
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->Set("nameservers", list);
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  list = new base::ListValue();
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < search.size(); ++i)
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    list->Append(new base::StringValue(search[i]));
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->Set("search", list);
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  dict->SetBoolean("unhandled_options", unhandled_options);
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetBoolean("append_to_multi_label_name", append_to_multi_label_name);
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetInteger("ndots", ndots);
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetDouble("timeout", timeout.InSecondsF());
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetInteger("attempts", attempts);
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetBoolean("rotate", rotate);
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetBoolean("edns0", edns0);
161d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  dict->SetBoolean("use_local_ipv6", use_local_ipv6);
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dict->SetInteger("num_hosts", hosts.size());
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return dict;
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DnsConfigService::DnsConfigService()
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : watch_failed_(false),
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      have_config_(false),
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      have_hosts_(false),
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      need_update_(false),
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      last_sent_empty_(true) {}
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DnsConfigService::~DnsConfigService() {
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DnsConfigService::ReadConfig(const CallbackType& callback) {
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(CalledOnValidThread());
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!callback.is_null());
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(callback_.is_null());
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  callback_ = callback;
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ReadNow();
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DnsConfigService::WatchConfig(const CallbackType& callback) {
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(CalledOnValidThread());
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!callback.is_null());
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(callback_.is_null());
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  callback_ = callback;
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  watch_failed_ = !StartWatching();
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ReadNow();
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DnsConfigService::InvalidateConfig() {
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(CalledOnValidThread());
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::TimeTicks now = base::TimeTicks::Now();
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!last_invalidate_config_time_.is_null()) {
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UMA_HISTOGRAM_LONG_TIMES("AsyncDNS.ConfigNotifyInterval",
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             now - last_invalidate_config_time_);
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  last_invalidate_config_time_ = now;
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!have_config_)
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  have_config_ = false;
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StartTimer();
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DnsConfigService::InvalidateHosts() {
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(CalledOnValidThread());
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::TimeTicks now = base::TimeTicks::Now();
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!last_invalidate_hosts_time_.is_null()) {
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UMA_HISTOGRAM_LONG_TIMES("AsyncDNS.HostsNotifyInterval",
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             now - last_invalidate_hosts_time_);
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  last_invalidate_hosts_time_ = now;
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!have_hosts_)
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  have_hosts_ = false;
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StartTimer();
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DnsConfigService::OnConfigRead(const DnsConfig& config) {
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(CalledOnValidThread());
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(config.IsValid());
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool changed = false;
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!config.EqualsIgnoreHosts(dns_config_)) {
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    dns_config_.CopyIgnoreHosts(config);
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    need_update_ = true;
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    changed = true;
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!changed && !last_sent_empty_time_.is_null()) {
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UMA_HISTOGRAM_LONG_TIMES("AsyncDNS.UnchangedConfigInterval",
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             base::TimeTicks::Now() - last_sent_empty_time_);
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UMA_HISTOGRAM_BOOLEAN("AsyncDNS.ConfigChange", changed);
238a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  UMA_HISTOGRAM_ENUMERATION(
239a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      "AsyncDNS.NameServersType",
240a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      classifier_.GetNameServersType(dns_config_.nameservers),
241a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      NameServerClassifier::NAME_SERVERS_TYPE_MAX_VALUE);
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  have_config_ = true;
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (have_hosts_ || watch_failed_)
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    OnCompleteConfig();
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DnsConfigService::OnHostsRead(const DnsHosts& hosts) {
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(CalledOnValidThread());
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool changed = false;
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (hosts != dns_config_.hosts) {
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    dns_config_.hosts = hosts;
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    need_update_ = true;
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    changed = true;
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!changed && !last_sent_empty_time_.is_null()) {
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UMA_HISTOGRAM_LONG_TIMES("AsyncDNS.UnchangedHostsInterval",
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             base::TimeTicks::Now() - last_sent_empty_time_);
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UMA_HISTOGRAM_BOOLEAN("AsyncDNS.HostsChange", changed);
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  have_hosts_ = true;
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (have_config_ || watch_failed_)
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    OnCompleteConfig();
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DnsConfigService::StartTimer() {
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(CalledOnValidThread());
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (last_sent_empty_) {
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(!timer_.IsRunning());
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;  // No need to withdraw again.
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  timer_.Stop();
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Give it a short timeout to come up with a valid config. Otherwise withdraw
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the config from the receiver. The goal is to avoid perceivable network
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // outage (when using the wrong config) but at the same time avoid
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // unnecessary Job aborts in HostResolverImpl. The signals come from multiple
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // sources so it might receive multiple events during a config change.
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // DHCP and user-induced changes are on the order of seconds, so 150ms should
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // not add perceivable delay. On the other hand, config readers should finish
2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // within 150ms with the rare exception of I/O block or extra large HOSTS.
2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const base::TimeDelta kTimeout = base::TimeDelta::FromMilliseconds(150);
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  timer_.Start(FROM_HERE,
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               kTimeout,
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               this,
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               &DnsConfigService::OnTimeout);
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DnsConfigService::OnTimeout() {
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(CalledOnValidThread());
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!last_sent_empty_);
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Indicate that even if there is no change in On*Read, we will need to
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // update the receiver when the config becomes complete.
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  need_update_ = true;
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Empty config is considered invalid.
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  last_sent_empty_ = true;
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  last_sent_empty_time_ = base::TimeTicks::Now();
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  callback_.Run(DnsConfig());
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DnsConfigService::OnCompleteConfig() {
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  timer_.Stop();
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!need_update_)
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  need_update_ = false;
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  last_sent_empty_ = false;
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (watch_failed_) {
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If a watch failed, the config may not be accurate, so report empty.
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    callback_.Run(DnsConfig());
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    callback_.Run(dns_config_);
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace net
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
321