• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 The Chromium Authors
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 <memory>
8 #include <string>
9 #include <utility>
10 
11 #include "base/functional/bind.h"
12 #include "base/memory/raw_ptr.h"
13 #include "base/metrics/histogram_macros.h"
14 #include "base/rand_util.h"
15 #include "base/ranges/algorithm.h"
16 #include "base/values.h"
17 #include "net/base/ip_address.h"
18 #include "net/base/ip_endpoint.h"
19 #include "net/dns/address_sorter.h"
20 #include "net/dns/dns_session.h"
21 #include "net/dns/dns_transaction.h"
22 #include "net/dns/dns_util.h"
23 #include "net/dns/public/dns_over_https_config.h"
24 #include "net/dns/public/secure_dns_mode.h"
25 #include "net/dns/resolve_context.h"
26 #include "net/log/net_log.h"
27 #include "net/log/net_log_event_type.h"
28 #include "net/socket/client_socket_factory.h"
29 #include "net/third_party/uri_template/uri_template.h"
30 #include "url/gurl.h"
31 #include "url/scheme_host_port.h"
32 
33 namespace net {
34 
35 namespace {
36 
IsEqual(const absl::optional<DnsConfig> & c1,const DnsConfig * c2)37 bool IsEqual(const absl::optional<DnsConfig>& c1, const DnsConfig* c2) {
38   if (!c1.has_value() && c2 == nullptr)
39     return true;
40 
41   if (!c1.has_value() || c2 == nullptr)
42     return false;
43 
44   return c1.value() == *c2;
45 }
46 
UpdateConfigForDohUpgrade(DnsConfig * config)47 void UpdateConfigForDohUpgrade(DnsConfig* config) {
48   bool has_doh_servers = !config->doh_config.servers().empty();
49   // Do not attempt upgrade when there are already DoH servers specified or
50   // when there are aspects of the system DNS config that are unhandled.
51   if (!config->unhandled_options && config->allow_dns_over_https_upgrade &&
52       !has_doh_servers &&
53       config->secure_dns_mode == SecureDnsMode::kAutomatic) {
54     // If we're in strict mode on Android, only attempt to upgrade the
55     // specified DoT hostname.
56     if (!config->dns_over_tls_hostname.empty()) {
57       config->doh_config = DnsOverHttpsConfig(
58           GetDohUpgradeServersFromDotHostname(config->dns_over_tls_hostname));
59       has_doh_servers = !config->doh_config.servers().empty();
60       UMA_HISTOGRAM_BOOLEAN("Net.DNS.UpgradeConfig.DotUpgradeSucceeded",
61                             has_doh_servers);
62     } else {
63       bool all_local = true;
64       for (const auto& server : config->nameservers) {
65         if (server.address().IsPubliclyRoutable()) {
66           all_local = false;
67           break;
68         }
69       }
70       UMA_HISTOGRAM_BOOLEAN("Net.DNS.UpgradeConfig.HasPublicInsecureNameserver",
71                             !all_local);
72 
73       config->doh_config = DnsOverHttpsConfig(
74           GetDohUpgradeServersFromNameservers(config->nameservers));
75       has_doh_servers = !config->doh_config.servers().empty();
76       UMA_HISTOGRAM_BOOLEAN("Net.DNS.UpgradeConfig.InsecureUpgradeSucceeded",
77                             has_doh_servers);
78     }
79   } else {
80     UMA_HISTOGRAM_BOOLEAN("Net.DNS.UpgradeConfig.Ineligible.DohSpecified",
81                           has_doh_servers);
82     UMA_HISTOGRAM_BOOLEAN("Net.DNS.UpgradeConfig.Ineligible.UnhandledOptions",
83                           config->unhandled_options);
84   }
85 }
86 
87 class DnsClientImpl : public DnsClient {
88  public:
DnsClientImpl(NetLog * net_log,const RandIntCallback & rand_int_callback)89   DnsClientImpl(NetLog* net_log, const RandIntCallback& rand_int_callback)
90       : net_log_(net_log), rand_int_callback_(rand_int_callback) {}
91 
92   DnsClientImpl(const DnsClientImpl&) = delete;
93   DnsClientImpl& operator=(const DnsClientImpl&) = delete;
94 
95   ~DnsClientImpl() override = default;
96 
CanUseSecureDnsTransactions() const97   bool CanUseSecureDnsTransactions() const override {
98     const DnsConfig* config = GetEffectiveConfig();
99     return config && !config->doh_config.servers().empty();
100   }
101 
CanUseInsecureDnsTransactions() const102   bool CanUseInsecureDnsTransactions() const override {
103     const DnsConfig* config = GetEffectiveConfig();
104     return config && config->nameservers.size() > 0 && insecure_enabled_ &&
105            !config->unhandled_options && !config->dns_over_tls_active;
106   }
107 
CanQueryAdditionalTypesViaInsecureDns() const108   bool CanQueryAdditionalTypesViaInsecureDns() const override {
109     // Only useful information if insecure DNS is usable, so expect this to
110     // never be called if that is not the case.
111     DCHECK(CanUseInsecureDnsTransactions());
112 
113     return can_query_additional_types_via_insecure_;
114   }
115 
SetInsecureEnabled(bool enabled,bool additional_types_enabled)116   void SetInsecureEnabled(bool enabled,
117                           bool additional_types_enabled) override {
118     insecure_enabled_ = enabled;
119     can_query_additional_types_via_insecure_ = additional_types_enabled;
120   }
121 
FallbackFromSecureTransactionPreferred(ResolveContext * context) const122   bool FallbackFromSecureTransactionPreferred(
123       ResolveContext* context) const override {
124     if (!CanUseSecureDnsTransactions())
125       return true;
126 
127     DCHECK(session_);  // Should be true if CanUseSecureDnsTransactions() true.
128     return context->NumAvailableDohServers(session_.get()) == 0;
129   }
130 
FallbackFromInsecureTransactionPreferred() const131   bool FallbackFromInsecureTransactionPreferred() const override {
132     return !CanUseInsecureDnsTransactions() ||
133            insecure_fallback_failures_ >= kMaxInsecureFallbackFailures;
134   }
135 
SetSystemConfig(absl::optional<DnsConfig> system_config)136   bool SetSystemConfig(absl::optional<DnsConfig> system_config) override {
137     if (system_config == system_config_)
138       return false;
139 
140     system_config_ = std::move(system_config);
141 
142     return UpdateDnsConfig();
143   }
144 
SetConfigOverrides(DnsConfigOverrides config_overrides)145   bool SetConfigOverrides(DnsConfigOverrides config_overrides) override {
146     if (config_overrides == config_overrides_)
147       return false;
148 
149     config_overrides_ = std::move(config_overrides);
150 
151     return UpdateDnsConfig();
152   }
153 
ReplaceCurrentSession()154   void ReplaceCurrentSession() override {
155     if (!session_)
156       return;
157 
158     UpdateSession(session_->config());
159   }
160 
GetCurrentSession()161   DnsSession* GetCurrentSession() override { return session_.get(); }
162 
GetEffectiveConfig() const163   const DnsConfig* GetEffectiveConfig() const override {
164     if (!session_)
165       return nullptr;
166 
167     DCHECK(session_->config().IsValid());
168     return &session_->config();
169   }
170 
GetHosts() const171   const DnsHosts* GetHosts() const override {
172     const DnsConfig* config = GetEffectiveConfig();
173     if (!config)
174       return nullptr;
175 
176     return &config->hosts;
177   }
178 
GetPresetAddrs(const url::SchemeHostPort & endpoint) const179   absl::optional<std::vector<IPEndPoint>> GetPresetAddrs(
180       const url::SchemeHostPort& endpoint) const override {
181     DCHECK(endpoint.IsValid());
182     if (!session_)
183       return absl::nullopt;
184     const auto& servers = session_->config().doh_config.servers();
185     auto it = base::ranges::find_if(servers, [&](const auto& server) {
186       std::string uri;
187       bool valid = uri_template::Expand(server.server_template(), {}, &uri);
188       // Server templates are validated before being allowed into the config.
189       DCHECK(valid);
190       GURL gurl(uri);
191       return url::SchemeHostPort(gurl) == endpoint;
192     });
193     if (it == servers.end())
194       return absl::nullopt;
195     std::vector<IPEndPoint> combined;
196     for (const IPAddressList& ips : it->endpoints()) {
197       for (const IPAddress& ip : ips) {
198         combined.emplace_back(ip, endpoint.port());
199       }
200     }
201     return combined;
202   }
203 
GetTransactionFactory()204   DnsTransactionFactory* GetTransactionFactory() override {
205     return session_.get() ? factory_.get() : nullptr;
206   }
207 
GetAddressSorter()208   AddressSorter* GetAddressSorter() override { return address_sorter_.get(); }
209 
IncrementInsecureFallbackFailures()210   void IncrementInsecureFallbackFailures() override {
211     ++insecure_fallback_failures_;
212   }
213 
ClearInsecureFallbackFailures()214   void ClearInsecureFallbackFailures() override {
215     insecure_fallback_failures_ = 0;
216   }
217 
GetDnsConfigAsValueForNetLog() const218   base::Value::Dict GetDnsConfigAsValueForNetLog() const override {
219     const DnsConfig* config = GetEffectiveConfig();
220     if (config == nullptr)
221       return base::Value::Dict();
222     base::Value::Dict dict = config->ToDict();
223     dict.Set("can_use_secure_dns_transactions", CanUseSecureDnsTransactions());
224     dict.Set("can_use_insecure_dns_transactions",
225              CanUseInsecureDnsTransactions());
226     return dict;
227   }
228 
GetSystemConfigForTesting() const229   absl::optional<DnsConfig> GetSystemConfigForTesting() const override {
230     return system_config_;
231   }
232 
GetConfigOverridesForTesting() const233   DnsConfigOverrides GetConfigOverridesForTesting() const override {
234     return config_overrides_;
235   }
236 
SetTransactionFactoryForTesting(std::unique_ptr<DnsTransactionFactory> factory)237   void SetTransactionFactoryForTesting(
238       std::unique_ptr<DnsTransactionFactory> factory) override {
239     factory_ = std::move(factory);
240   }
241 
242  private:
BuildEffectiveConfig() const243   absl::optional<DnsConfig> BuildEffectiveConfig() const {
244     DnsConfig config;
245     if (config_overrides_.OverridesEverything()) {
246       config = config_overrides_.ApplyOverrides(DnsConfig());
247     } else {
248       if (!system_config_)
249         return absl::nullopt;
250 
251       config = config_overrides_.ApplyOverrides(system_config_.value());
252     }
253 
254     UpdateConfigForDohUpgrade(&config);
255 
256     // TODO(ericorth): Consider keeping a separate DnsConfig for pure Chrome-
257     // produced configs to allow respecting all fields like |unhandled_options|
258     // while still being able to fallback to system config for DoH.
259     // For now, clear the nameservers for extra security if parts of the system
260     // config are unhandled.
261     if (config.unhandled_options)
262       config.nameservers.clear();
263 
264     if (!config.IsValid())
265       return absl::nullopt;
266 
267     return config;
268   }
269 
UpdateDnsConfig()270   bool UpdateDnsConfig() {
271     absl::optional<DnsConfig> new_effective_config = BuildEffectiveConfig();
272 
273     if (IsEqual(new_effective_config, GetEffectiveConfig()))
274       return false;
275 
276     insecure_fallback_failures_ = 0;
277     UpdateSession(std::move(new_effective_config));
278 
279     if (net_log_) {
280       net_log_->AddGlobalEntry(NetLogEventType::DNS_CONFIG_CHANGED, [this] {
281         return GetDnsConfigAsValueForNetLog();
282       });
283     }
284 
285     return true;
286   }
287 
UpdateSession(absl::optional<DnsConfig> new_effective_config)288   void UpdateSession(absl::optional<DnsConfig> new_effective_config) {
289     factory_.reset();
290     session_ = nullptr;
291 
292     if (new_effective_config) {
293       DCHECK(new_effective_config.value().IsValid());
294 
295       session_ = base::MakeRefCounted<DnsSession>(
296           std::move(new_effective_config).value(), rand_int_callback_,
297           net_log_);
298       factory_ = DnsTransactionFactory::CreateFactory(session_.get());
299     }
300   }
301 
302   bool insecure_enabled_ = false;
303   bool can_query_additional_types_via_insecure_ = false;
304   int insecure_fallback_failures_ = 0;
305 
306   absl::optional<DnsConfig> system_config_;
307   DnsConfigOverrides config_overrides_;
308 
309   scoped_refptr<DnsSession> session_;
310   std::unique_ptr<DnsTransactionFactory> factory_;
311   std::unique_ptr<AddressSorter> address_sorter_ =
312       AddressSorter::CreateAddressSorter();
313 
314   raw_ptr<NetLog> net_log_;
315 
316   const RandIntCallback rand_int_callback_;
317 };
318 
319 }  // namespace
320 
321 // static
CreateClient(NetLog * net_log)322 std::unique_ptr<DnsClient> DnsClient::CreateClient(NetLog* net_log) {
323   return std::make_unique<DnsClientImpl>(net_log,
324                                          base::BindRepeating(&base::RandInt));
325 }
326 
327 // static
CreateClientForTesting(NetLog * net_log,const RandIntCallback & rand_int_callback)328 std::unique_ptr<DnsClient> DnsClient::CreateClientForTesting(
329     NetLog* net_log,
330     const RandIntCallback& rand_int_callback) {
331   return std::make_unique<DnsClientImpl>(net_log, rand_int_callback);
332 }
333 
334 }  // namespace net
335