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_client.h"
6 
7 #include <utility>
8 
9 #include "base/bind.h"
10 #include "base/metrics/histogram_macros.h"
11 #include "base/rand_util.h"
12 #include "base/values.h"
13 #include "net/dns/address_sorter.h"
14 #include "net/dns/dns_session.h"
15 #include "net/dns/dns_socket_pool.h"
16 #include "net/dns/dns_transaction.h"
17 #include "net/dns/dns_util.h"
18 #include "net/dns/resolve_context.h"
19 #include "net/log/net_log.h"
20 #include "net/log/net_log_event_type.h"
21 #include "net/socket/client_socket_factory.h"
22 
23 namespace net {
24 
25 namespace {
26 
27 // Creates NetLog parameters for the DNS_CONFIG_CHANGED event.
NetLogDnsConfigParams(const DnsConfig * config)28 base::Value NetLogDnsConfigParams(const DnsConfig* config) {
29   if (!config)
30     return base::DictionaryValue();
31 
32   return base::Value::FromUniquePtrValue(config->ToValue());
33 }
34 
IsEqual(const base::Optional<DnsConfig> & c1,const DnsConfig * c2)35 bool IsEqual(const base::Optional<DnsConfig>& c1, const DnsConfig* c2) {
36   if (!c1.has_value() && c2 == nullptr)
37     return true;
38 
39   if (!c1.has_value() || c2 == nullptr)
40     return false;
41 
42   return c1.value() == *c2;
43 }
44 
UpdateConfigForDohUpgrade(DnsConfig * config)45 void UpdateConfigForDohUpgrade(DnsConfig* config) {
46   bool has_doh_servers = !config->dns_over_https_servers.empty();
47   // Do not attempt upgrade when there are already DoH servers specified or
48   // when there are aspects of the system DNS config that are unhandled.
49   if (!config->unhandled_options && config->allow_dns_over_https_upgrade &&
50       !has_doh_servers &&
51       config->secure_dns_mode == DnsConfig::SecureDnsMode::AUTOMATIC) {
52     // If we're in strict mode on Android, only attempt to upgrade the
53     // specified DoT hostname.
54     if (!config->dns_over_tls_hostname.empty()) {
55       config->dns_over_https_servers = GetDohUpgradeServersFromDotHostname(
56           config->dns_over_tls_hostname, config->disabled_upgrade_providers);
57       has_doh_servers = !config->dns_over_https_servers.empty();
58       UMA_HISTOGRAM_BOOLEAN("Net.DNS.UpgradeConfig.DotUpgradeSucceeded",
59                             has_doh_servers);
60     } else {
61       bool all_local = true;
62       for (const auto& server : config->nameservers) {
63         if (server.address().IsPubliclyRoutable()) {
64           all_local = false;
65           break;
66         }
67       }
68       UMA_HISTOGRAM_BOOLEAN("Net.DNS.UpgradeConfig.HasPublicInsecureNameserver",
69                             !all_local);
70 
71       config->dns_over_https_servers = GetDohUpgradeServersFromNameservers(
72           config->nameservers, config->disabled_upgrade_providers);
73       has_doh_servers = !config->dns_over_https_servers.empty();
74       UMA_HISTOGRAM_BOOLEAN("Net.DNS.UpgradeConfig.InsecureUpgradeSucceeded",
75                             has_doh_servers);
76     }
77   } else {
78     UMA_HISTOGRAM_BOOLEAN("Net.DNS.UpgradeConfig.Ineligible.DohSpecified",
79                           has_doh_servers);
80     UMA_HISTOGRAM_BOOLEAN("Net.DNS.UpgradeConfig.Ineligible.UnhandledOptions",
81                           config->unhandled_options);
82   }
83 }
84 
85 class DnsClientImpl : public DnsClient {
86  public:
DnsClientImpl(NetLog * net_log,ClientSocketFactory * socket_factory,const RandIntCallback & rand_int_callback)87   DnsClientImpl(NetLog* net_log,
88                 ClientSocketFactory* socket_factory,
89                 const RandIntCallback& rand_int_callback)
90       : net_log_(net_log),
91         socket_factory_(socket_factory),
92         rand_int_callback_(rand_int_callback) {}
93 
94   ~DnsClientImpl() override = default;
95 
CanUseSecureDnsTransactions() const96   bool CanUseSecureDnsTransactions() const override {
97     const DnsConfig* config = GetEffectiveConfig();
98     return config && config->dns_over_https_servers.size() > 0;
99   }
100 
CanUseInsecureDnsTransactions() const101   bool CanUseInsecureDnsTransactions() const override {
102     const DnsConfig* config = GetEffectiveConfig();
103     return config && config->nameservers.size() > 0 && insecure_enabled_ &&
104            !config->unhandled_options && !config->dns_over_tls_active;
105   }
106 
SetInsecureEnabled(bool enabled)107   void SetInsecureEnabled(bool enabled) override {
108     insecure_enabled_ = enabled;
109   }
110 
FallbackFromSecureTransactionPreferred(ResolveContext * context) const111   bool FallbackFromSecureTransactionPreferred(
112       ResolveContext* context) const override {
113     if (!CanUseSecureDnsTransactions())
114       return true;
115 
116     DCHECK(session_);  // Should be true if CanUseSecureDnsTransactions() true.
117     return context->NumAvailableDohServers(session_.get()) == 0;
118   }
119 
FallbackFromInsecureTransactionPreferred() const120   bool FallbackFromInsecureTransactionPreferred() const override {
121     return !CanUseInsecureDnsTransactions() ||
122            insecure_fallback_failures_ >= kMaxInsecureFallbackFailures;
123   }
124 
SetSystemConfig(base::Optional<DnsConfig> system_config)125   bool SetSystemConfig(base::Optional<DnsConfig> system_config) override {
126     if (system_config == system_config_)
127       return false;
128 
129     system_config_ = std::move(system_config);
130 
131     return UpdateDnsConfig();
132   }
133 
SetConfigOverrides(DnsConfigOverrides config_overrides)134   bool SetConfigOverrides(DnsConfigOverrides config_overrides) override {
135     if (config_overrides == config_overrides_)
136       return false;
137 
138     config_overrides_ = std::move(config_overrides);
139 
140     return UpdateDnsConfig();
141   }
142 
ReplaceCurrentSession()143   void ReplaceCurrentSession() override {
144     if (!session_)
145       return;
146 
147     UpdateSession(session_->config());
148   }
149 
GetCurrentSession()150   DnsSession* GetCurrentSession() override { return session_.get(); }
151 
GetEffectiveConfig() const152   const DnsConfig* GetEffectiveConfig() const override {
153     if (!session_)
154       return nullptr;
155 
156     DCHECK(session_->config().IsValid());
157     return &session_->config();
158   }
159 
GetHosts() const160   const DnsHosts* GetHosts() const override {
161     const DnsConfig* config = GetEffectiveConfig();
162     if (!config)
163       return nullptr;
164 
165     return &config->hosts;
166   }
167 
GetTransactionFactory()168   DnsTransactionFactory* GetTransactionFactory() override {
169     return session_.get() ? factory_.get() : nullptr;
170   }
171 
GetAddressSorter()172   AddressSorter* GetAddressSorter() override { return address_sorter_.get(); }
173 
IncrementInsecureFallbackFailures()174   void IncrementInsecureFallbackFailures() override {
175     ++insecure_fallback_failures_;
176   }
177 
ClearInsecureFallbackFailures()178   void ClearInsecureFallbackFailures() override {
179     insecure_fallback_failures_ = 0;
180   }
181 
GetSystemConfigForTesting() const182   base::Optional<DnsConfig> GetSystemConfigForTesting() const override {
183     return system_config_;
184   }
185 
GetConfigOverridesForTesting() const186   DnsConfigOverrides GetConfigOverridesForTesting() const override {
187     return config_overrides_;
188   }
189 
SetTransactionFactoryForTesting(std::unique_ptr<DnsTransactionFactory> factory)190   void SetTransactionFactoryForTesting(
191       std::unique_ptr<DnsTransactionFactory> factory) override {
192     factory_ = std::move(factory);
193   }
194 
195  private:
BuildEffectiveConfig() const196   base::Optional<DnsConfig> BuildEffectiveConfig() const {
197     DnsConfig config;
198     if (config_overrides_.OverridesEverything()) {
199       config = config_overrides_.ApplyOverrides(DnsConfig());
200     } else {
201       if (!system_config_)
202         return base::nullopt;
203 
204       config = config_overrides_.ApplyOverrides(system_config_.value());
205     }
206 
207     UpdateConfigForDohUpgrade(&config);
208 
209     // TODO(ericorth): Consider keeping a separate DnsConfig for pure Chrome-
210     // produced configs to allow respecting all fields like |unhandled_options|
211     // while still being able to fallback to system config for DoH.
212     // For now, clear the nameservers for extra security if parts of the system
213     // config are unhandled.
214     if (config.unhandled_options)
215       config.nameservers.clear();
216 
217     if (!config.IsValid())
218       return base::nullopt;
219 
220     return config;
221   }
222 
UpdateDnsConfig()223   bool UpdateDnsConfig() {
224     base::Optional<DnsConfig> new_effective_config = BuildEffectiveConfig();
225 
226     if (IsEqual(new_effective_config, GetEffectiveConfig()))
227       return false;
228 
229     insecure_fallback_failures_ = 0;
230     UpdateSession(std::move(new_effective_config));
231 
232     if (net_log_) {
233       net_log_->AddGlobalEntry(NetLogEventType::DNS_CONFIG_CHANGED, [&] {
234         return NetLogDnsConfigParams(GetEffectiveConfig());
235       });
236     }
237 
238     return true;
239   }
240 
UpdateSession(base::Optional<DnsConfig> new_effective_config)241   void UpdateSession(base::Optional<DnsConfig> new_effective_config) {
242     factory_.reset();
243     session_ = nullptr;
244 
245     if (new_effective_config) {
246       DCHECK(new_effective_config.value().IsValid());
247 
248       std::unique_ptr<DnsSocketPool> socket_pool(
249           new_effective_config.value().randomize_ports
250               ? DnsSocketPool::CreateDefault(socket_factory_,
251                                              rand_int_callback_)
252               : DnsSocketPool::CreateNull(socket_factory_, rand_int_callback_));
253       session_ =
254           new DnsSession(std::move(new_effective_config).value(),
255                          std::move(socket_pool), rand_int_callback_, net_log_);
256       factory_ = DnsTransactionFactory::CreateFactory(session_.get());
257     }
258   }
259 
260   bool insecure_enabled_ = false;
261   int insecure_fallback_failures_ = 0;
262 
263   base::Optional<DnsConfig> system_config_;
264   DnsConfigOverrides config_overrides_;
265 
266   scoped_refptr<DnsSession> session_;
267   std::unique_ptr<DnsTransactionFactory> factory_;
268   std::unique_ptr<AddressSorter> address_sorter_ =
269       AddressSorter::CreateAddressSorter();
270 
271   NetLog* net_log_;
272 
273   ClientSocketFactory* socket_factory_;
274   const RandIntCallback rand_int_callback_;
275 
276   DISALLOW_COPY_AND_ASSIGN(DnsClientImpl);
277 };
278 
279 }  // namespace
280 
281 // static
CreateClient(NetLog * net_log)282 std::unique_ptr<DnsClient> DnsClient::CreateClient(NetLog* net_log) {
283   return std::make_unique<DnsClientImpl>(
284       net_log, ClientSocketFactory::GetDefaultFactory(),
285       base::BindRepeating(&base::RandInt));
286 }
287 
288 // static
CreateClientForTesting(NetLog * net_log,ClientSocketFactory * socket_factory,const RandIntCallback & rand_int_callback)289 std::unique_ptr<DnsClient> DnsClient::CreateClientForTesting(
290     NetLog* net_log,
291     ClientSocketFactory* socket_factory,
292     const RandIntCallback& rand_int_callback) {
293   return std::make_unique<DnsClientImpl>(net_log, socket_factory,
294                                          rand_int_callback);
295 }
296 
297 }  // namespace net
298