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