1*6777b538SAndroid Build Coastguard Worker // Copyright 2012 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker
5*6777b538SAndroid Build Coastguard Worker #include "net/dns/dns_reloader.h"
6*6777b538SAndroid Build Coastguard Worker
7*6777b538SAndroid Build Coastguard Worker #include "build/build_config.h"
8*6777b538SAndroid Build Coastguard Worker
9*6777b538SAndroid Build Coastguard Worker // If we're not on a POSIX system, it's not even safe to try to include resolv.h
10*6777b538SAndroid Build Coastguard Worker // - there's not guarantee it exists at all. :(
11*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_POSIX)
12*6777b538SAndroid Build Coastguard Worker
13*6777b538SAndroid Build Coastguard Worker #include <resolv.h>
14*6777b538SAndroid Build Coastguard Worker
15*6777b538SAndroid Build Coastguard Worker // This code only works on systems where the C library provides res_ninit(3) and
16*6777b538SAndroid Build Coastguard Worker // res_nclose(3), which requires __RES >= 19991006 (most libcs at this point,
17*6777b538SAndroid Build Coastguard Worker // but not all).
18*6777b538SAndroid Build Coastguard Worker //
19*6777b538SAndroid Build Coastguard Worker // This code is also not used on either macOS or iOS, even though both platforms
20*6777b538SAndroid Build Coastguard Worker // have res_ninit(3). On iOS, /etc/hosts is immutable so there's no reason for
21*6777b538SAndroid Build Coastguard Worker // us to watch it; on macOS, there is a system mechanism for listening to DNS
22*6777b538SAndroid Build Coastguard Worker // changes which does not require use to do this kind of reloading. See
23*6777b538SAndroid Build Coastguard Worker // //net/dns/dns_config_watcher_mac.cc.
24*6777b538SAndroid Build Coastguard Worker //
25*6777b538SAndroid Build Coastguard Worker // It *also* is not used on Android, because Android handles nameserver changes
26*6777b538SAndroid Build Coastguard Worker // for us and has no /etc/resolv.conf. Despite that, Bionic does export these
27*6777b538SAndroid Build Coastguard Worker // interfaces, so we need to not use them.
28*6777b538SAndroid Build Coastguard Worker //
29*6777b538SAndroid Build Coastguard Worker // It is also also not used on Fuchsia. Regrettably, Fuchsia's resolv.h has
30*6777b538SAndroid Build Coastguard Worker // __RES set to 19991006, but does not actually provide res_ninit(3). This was
31*6777b538SAndroid Build Coastguard Worker // an old musl bug that was fixed by musl c8fdcfe5, but Fuchsia's SDK doesn't
32*6777b538SAndroid Build Coastguard Worker // have that change.
33*6777b538SAndroid Build Coastguard Worker #if defined(__RES) && __RES >= 19991006 && !BUILDFLAG(IS_APPLE) && \
34*6777b538SAndroid Build Coastguard Worker !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_FUCHSIA)
35*6777b538SAndroid Build Coastguard Worker // We define this so we don't need to restate the complex condition here twice
36*6777b538SAndroid Build Coastguard Worker // below - it would be easy for the copies below to get out of sync.
37*6777b538SAndroid Build Coastguard Worker #define USE_RES_NINIT
38*6777b538SAndroid Build Coastguard Worker #endif // defined(_RES) && ...
39*6777b538SAndroid Build Coastguard Worker #endif // BUILDFLAG(IS_POSIX)
40*6777b538SAndroid Build Coastguard Worker
41*6777b538SAndroid Build Coastguard Worker #if defined(USE_RES_NINIT)
42*6777b538SAndroid Build Coastguard Worker
43*6777b538SAndroid Build Coastguard Worker #include "base/lazy_instance.h"
44*6777b538SAndroid Build Coastguard Worker #include "base/notreached.h"
45*6777b538SAndroid Build Coastguard Worker #include "base/synchronization/lock.h"
46*6777b538SAndroid Build Coastguard Worker #include "base/task/current_thread.h"
47*6777b538SAndroid Build Coastguard Worker #include "base/threading/thread_local.h"
48*6777b538SAndroid Build Coastguard Worker #include "net/base/network_change_notifier.h"
49*6777b538SAndroid Build Coastguard Worker
50*6777b538SAndroid Build Coastguard Worker namespace net {
51*6777b538SAndroid Build Coastguard Worker
52*6777b538SAndroid Build Coastguard Worker namespace {
53*6777b538SAndroid Build Coastguard Worker
54*6777b538SAndroid Build Coastguard Worker // On Linux/BSD, changes to /etc/resolv.conf can go unnoticed thus resulting
55*6777b538SAndroid Build Coastguard Worker // in DNS queries failing either because nameservers are unknown on startup
56*6777b538SAndroid Build Coastguard Worker // or because nameserver info has changed as a result of e.g. connecting to
57*6777b538SAndroid Build Coastguard Worker // a new network. Some distributions patch glibc to stat /etc/resolv.conf
58*6777b538SAndroid Build Coastguard Worker // to try to automatically detect such changes but these patches are not
59*6777b538SAndroid Build Coastguard Worker // universal and even patched systems such as Jaunty appear to need calls
60*6777b538SAndroid Build Coastguard Worker // to res_ninit to reload the nameserver information in different threads.
61*6777b538SAndroid Build Coastguard Worker //
62*6777b538SAndroid Build Coastguard Worker // To fix this, on systems with FilePathWatcher support, we use
63*6777b538SAndroid Build Coastguard Worker // NetworkChangeNotifier::DNSObserver to monitor /etc/resolv.conf to
64*6777b538SAndroid Build Coastguard Worker // enable us to respond to DNS changes and reload the resolver state.
65*6777b538SAndroid Build Coastguard Worker //
66*6777b538SAndroid Build Coastguard Worker // Android does not have /etc/resolv.conf. The system takes care of nameserver
67*6777b538SAndroid Build Coastguard Worker // changes, so none of this is needed.
68*6777b538SAndroid Build Coastguard Worker //
69*6777b538SAndroid Build Coastguard Worker // TODO(crbug.com/971411): Convert to SystemDnsConfigChangeNotifier because this
70*6777b538SAndroid Build Coastguard Worker // really only cares about system DNS config changes, not Chrome effective
71*6777b538SAndroid Build Coastguard Worker // config changes.
72*6777b538SAndroid Build Coastguard Worker
73*6777b538SAndroid Build Coastguard Worker class DnsReloader : public NetworkChangeNotifier::DNSObserver {
74*6777b538SAndroid Build Coastguard Worker public:
75*6777b538SAndroid Build Coastguard Worker DnsReloader(const DnsReloader&) = delete;
76*6777b538SAndroid Build Coastguard Worker DnsReloader& operator=(const DnsReloader&) = delete;
77*6777b538SAndroid Build Coastguard Worker
78*6777b538SAndroid Build Coastguard Worker // NetworkChangeNotifier::DNSObserver:
OnDNSChanged()79*6777b538SAndroid Build Coastguard Worker void OnDNSChanged() override {
80*6777b538SAndroid Build Coastguard Worker base::AutoLock lock(lock_);
81*6777b538SAndroid Build Coastguard Worker resolver_generation_++;
82*6777b538SAndroid Build Coastguard Worker }
83*6777b538SAndroid Build Coastguard Worker
MaybeReload()84*6777b538SAndroid Build Coastguard Worker void MaybeReload() {
85*6777b538SAndroid Build Coastguard Worker ReloadState* reload_state = tls_reload_state_.Get();
86*6777b538SAndroid Build Coastguard Worker base::AutoLock lock(lock_);
87*6777b538SAndroid Build Coastguard Worker
88*6777b538SAndroid Build Coastguard Worker if (!reload_state) {
89*6777b538SAndroid Build Coastguard Worker auto new_reload_state = std::make_unique<ReloadState>();
90*6777b538SAndroid Build Coastguard Worker new_reload_state->resolver_generation = resolver_generation_;
91*6777b538SAndroid Build Coastguard Worker res_ninit(&_res);
92*6777b538SAndroid Build Coastguard Worker tls_reload_state_.Set(std::move(new_reload_state));
93*6777b538SAndroid Build Coastguard Worker } else if (reload_state->resolver_generation != resolver_generation_) {
94*6777b538SAndroid Build Coastguard Worker reload_state->resolver_generation = resolver_generation_;
95*6777b538SAndroid Build Coastguard Worker // It is safe to call res_nclose here since we know res_ninit will have
96*6777b538SAndroid Build Coastguard Worker // been called above.
97*6777b538SAndroid Build Coastguard Worker res_nclose(&_res);
98*6777b538SAndroid Build Coastguard Worker res_ninit(&_res);
99*6777b538SAndroid Build Coastguard Worker }
100*6777b538SAndroid Build Coastguard Worker }
101*6777b538SAndroid Build Coastguard Worker
102*6777b538SAndroid Build Coastguard Worker private:
103*6777b538SAndroid Build Coastguard Worker struct ReloadState {
~ReloadStatenet::__anona71a6bf10111::DnsReloader::ReloadState104*6777b538SAndroid Build Coastguard Worker ~ReloadState() { res_nclose(&_res); }
105*6777b538SAndroid Build Coastguard Worker
106*6777b538SAndroid Build Coastguard Worker int resolver_generation;
107*6777b538SAndroid Build Coastguard Worker };
108*6777b538SAndroid Build Coastguard Worker
DnsReloader()109*6777b538SAndroid Build Coastguard Worker DnsReloader() { NetworkChangeNotifier::AddDNSObserver(this); }
110*6777b538SAndroid Build Coastguard Worker
~DnsReloader()111*6777b538SAndroid Build Coastguard Worker ~DnsReloader() override {
112*6777b538SAndroid Build Coastguard Worker NOTREACHED(); // LeakyLazyInstance is not destructed.
113*6777b538SAndroid Build Coastguard Worker }
114*6777b538SAndroid Build Coastguard Worker
115*6777b538SAndroid Build Coastguard Worker base::Lock lock_; // Protects resolver_generation_.
116*6777b538SAndroid Build Coastguard Worker int resolver_generation_ = 0;
117*6777b538SAndroid Build Coastguard Worker friend struct base::LazyInstanceTraitsBase<DnsReloader>;
118*6777b538SAndroid Build Coastguard Worker
119*6777b538SAndroid Build Coastguard Worker // We use thread local storage to identify which ReloadState to interact with.
120*6777b538SAndroid Build Coastguard Worker base::ThreadLocalOwnedPointer<ReloadState> tls_reload_state_;
121*6777b538SAndroid Build Coastguard Worker };
122*6777b538SAndroid Build Coastguard Worker
123*6777b538SAndroid Build Coastguard Worker base::LazyInstance<DnsReloader>::Leaky
124*6777b538SAndroid Build Coastguard Worker g_dns_reloader = LAZY_INSTANCE_INITIALIZER;
125*6777b538SAndroid Build Coastguard Worker
126*6777b538SAndroid Build Coastguard Worker } // namespace
127*6777b538SAndroid Build Coastguard Worker
EnsureDnsReloaderInit()128*6777b538SAndroid Build Coastguard Worker void EnsureDnsReloaderInit() {
129*6777b538SAndroid Build Coastguard Worker g_dns_reloader.Pointer();
130*6777b538SAndroid Build Coastguard Worker }
131*6777b538SAndroid Build Coastguard Worker
DnsReloaderMaybeReload()132*6777b538SAndroid Build Coastguard Worker void DnsReloaderMaybeReload() {
133*6777b538SAndroid Build Coastguard Worker // This routine can be called by any of the DNS worker threads.
134*6777b538SAndroid Build Coastguard Worker DnsReloader* dns_reloader = g_dns_reloader.Pointer();
135*6777b538SAndroid Build Coastguard Worker dns_reloader->MaybeReload();
136*6777b538SAndroid Build Coastguard Worker }
137*6777b538SAndroid Build Coastguard Worker
138*6777b538SAndroid Build Coastguard Worker } // namespace net
139*6777b538SAndroid Build Coastguard Worker
140*6777b538SAndroid Build Coastguard Worker #else // !USE_RES_NINIT
141*6777b538SAndroid Build Coastguard Worker
142*6777b538SAndroid Build Coastguard Worker namespace net {
143*6777b538SAndroid Build Coastguard Worker
EnsureDnsReloaderInit()144*6777b538SAndroid Build Coastguard Worker void EnsureDnsReloaderInit() {}
145*6777b538SAndroid Build Coastguard Worker
DnsReloaderMaybeReload()146*6777b538SAndroid Build Coastguard Worker void DnsReloaderMaybeReload() {}
147*6777b538SAndroid Build Coastguard Worker
148*6777b538SAndroid Build Coastguard Worker } // namespace net
149*6777b538SAndroid Build Coastguard Worker
150*6777b538SAndroid Build Coastguard Worker #endif // defined(USE_RES_NINIT)
151