blob: 1c014a6501990b42c44a162a0995d439428a5843 [file] [log] [blame]
[email protected]9fc44162012-01-23 22:56:411// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]46018c9d2011-09-06 03:42:342// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
tfarina47598f042015-10-07 23:08:355#include "net/dns/dns_reloader.h"
[email protected]46018c9d2011-09-06 03:42:346
[email protected]ae7c9f42011-11-21 11:41:167#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_OPENBSD) && \
Sergey Ulanov49085572017-07-10 23:25:468 !defined(OS_ANDROID) && !defined(OS_FUCHSIA)
[email protected]46018c9d2011-09-06 03:42:349
10#include <resolv.h>
11
[email protected]46018c9d2011-09-06 03:42:3412#include "base/lazy_instance.h"
13#include "base/logging.h"
Avi Drissman13fc8932015-12-20 04:40:4614#include "base/macros.h"
Carlos Caballerofeae871482019-08-12 14:14:4315#include "base/message_loop/message_loop_current.h"
[email protected]46018c9d2011-09-06 03:42:3416#include "base/synchronization/lock.h"
Gabriel Charettef9d72da2019-01-24 13:34:3217#include "base/threading/thread_local.h"
[email protected]46018c9d2011-09-06 03:42:3418#include "net/base/network_change_notifier.h"
19
ttuttle859dc7a2015-04-23 19:42:2920namespace net {
21
[email protected]46018c9d2011-09-06 03:42:3422namespace {
23
24// On Linux/BSD, changes to /etc/resolv.conf can go unnoticed thus resulting
25// in DNS queries failing either because nameservers are unknown on startup
26// or because nameserver info has changed as a result of e.g. connecting to
27// a new network. Some distributions patch glibc to stat /etc/resolv.conf
28// to try to automatically detect such changes but these patches are not
29// universal and even patched systems such as Jaunty appear to need calls
30// to res_ninit to reload the nameserver information in different threads.
31//
32// To fix this, on systems with FilePathWatcher support, we use
33// NetworkChangeNotifier::DNSObserver to monitor /etc/resolv.conf to
34// enable us to respond to DNS changes and reload the resolver state.
35//
36// OpenBSD does not have thread-safe res_ninit/res_nclose so we can't do
37// the same trick there and most *BSD's don't yet have support for
38// FilePathWatcher (but perhaps the new kqueue mac code just needs to be
39// ported to *BSD to support that).
[email protected]ae7c9f42011-11-21 11:41:1640//
41// Android does not have /etc/resolv.conf. The system takes care of nameserver
42// changes, so none of this is needed.
Eric Ortha3559ca2019-09-05 23:40:5443//
44// TODO(crbug.com/971411): Convert to SystemDnsConfigChangeNotifier because this
45// really only cares about system DNS config changes, not Chrome effective
46// config changes.
[email protected]46018c9d2011-09-06 03:42:3447
ttuttle859dc7a2015-04-23 19:42:2948class DnsReloader : public NetworkChangeNotifier::DNSObserver {
[email protected]46018c9d2011-09-06 03:42:3449 public:
[email protected]446df2952012-02-28 07:22:5150 // NetworkChangeNotifier::DNSObserver:
dcheng67be2b1f2014-10-27 21:47:2951 void OnDNSChanged() override {
eroman6f506dcc2017-06-21 23:40:5952 base::AutoLock lock(lock_);
[email protected]46018c9d2011-09-06 03:42:3453 resolver_generation_++;
54 }
55
56 void MaybeReload() {
Gabriel Charettef9d72da2019-01-24 13:34:3257 ReloadState* reload_state = tls_reload_state_.Get();
eroman6f506dcc2017-06-21 23:40:5958 base::AutoLock lock(lock_);
[email protected]46018c9d2011-09-06 03:42:3459
60 if (!reload_state) {
Gabriel Charettef9d72da2019-01-24 13:34:3261 auto new_reload_state = std::make_unique<ReloadState>();
62 new_reload_state->resolver_generation = resolver_generation_;
[email protected]46018c9d2011-09-06 03:42:3463 res_ninit(&_res);
Gabriel Charettef9d72da2019-01-24 13:34:3264 tls_reload_state_.Set(std::move(new_reload_state));
[email protected]46018c9d2011-09-06 03:42:3465 } else if (reload_state->resolver_generation != resolver_generation_) {
66 reload_state->resolver_generation = resolver_generation_;
67 // It is safe to call res_nclose here since we know res_ninit will have
68 // been called above.
69 res_nclose(&_res);
70 res_ninit(&_res);
71 }
72 }
73
[email protected]46018c9d2011-09-06 03:42:3474 private:
Gabriel Charettef9d72da2019-01-24 13:34:3275 struct ReloadState {
76 ~ReloadState() { res_nclose(&_res); }
77
78 int resolver_generation;
79 };
80
Alexander Khaustovfd6d8022018-02-19 19:18:4981 DnsReloader() { NetworkChangeNotifier::AddDNSObserver(this); }
[email protected]46018c9d2011-09-06 03:42:3482
dcheng67be2b1f2014-10-27 21:47:2983 ~DnsReloader() override {
[email protected]46018c9d2011-09-06 03:42:3484 NOTREACHED(); // LeakyLazyInstance is not destructed.
85 }
86
87 base::Lock lock_; // Protects resolver_generation_.
Alexander Khaustovfd6d8022018-02-19 19:18:4988 int resolver_generation_ = 0;
scottmg5e65e3a2017-03-08 08:48:4689 friend struct base::LazyInstanceTraitsBase<DnsReloader>;
[email protected]46018c9d2011-09-06 03:42:3490
91 // We use thread local storage to identify which ReloadState to interact with.
Gabriel Charettef9d72da2019-01-24 13:34:3292 base::ThreadLocalOwnedPointer<ReloadState> tls_reload_state_;
[email protected]46018c9d2011-09-06 03:42:3493
94 DISALLOW_COPY_AND_ASSIGN(DnsReloader);
95};
96
[email protected]9fc44162012-01-23 22:56:4197base::LazyInstance<DnsReloader>::Leaky
[email protected]6de0fd1d2011-11-15 13:31:4998 g_dns_reloader = LAZY_INSTANCE_INITIALIZER;
[email protected]46018c9d2011-09-06 03:42:3499
100} // namespace
101
[email protected]46018c9d2011-09-06 03:42:34102void EnsureDnsReloaderInit() {
pkasting47ceb872014-10-09 18:53:22103 g_dns_reloader.Pointer();
[email protected]46018c9d2011-09-06 03:42:34104}
105
106void DnsReloaderMaybeReload() {
107 // This routine can be called by any of the DNS worker threads.
108 DnsReloader* dns_reloader = g_dns_reloader.Pointer();
109 dns_reloader->MaybeReload();
110}
111
112} // namespace net
113
[email protected]ae7c9f42011-11-21 11:41:16114#endif // defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_OPENBSD) &&
115 // !defined(OS_ANDROID)