xref: /aosp_15_r20/external/cronet/net/dns/dns_config_watcher_mac.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2014 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_config_watcher_mac.h"
6 
7 #include <dlfcn.h>
8 
9 #include "base/lazy_instance.h"
10 #include "base/memory/raw_ptr.h"
11 #include "third_party/apple_apsl/dnsinfo.h"
12 
13 namespace {
14 
15 // dnsinfo symbols are available via libSystem.dylib, but can also be present in
16 // SystemConfiguration.framework. To avoid confusion, load them explicitly from
17 // libSystem.dylib.
18 class DnsInfoApi {
19  public:
20   typedef const char* (*dns_configuration_notify_key_t)();
21   typedef dns_config_t* (*dns_configuration_copy_t)();
22   typedef void (*dns_configuration_free_t)(dns_config_t*);
23 
DnsInfoApi()24   DnsInfoApi() {
25     handle_ = dlopen("/usr/lib/libSystem.dylib",
26                      RTLD_LAZY | RTLD_NOLOAD);
27     if (!handle_)
28       return;
29     dns_configuration_notify_key =
30         reinterpret_cast<dns_configuration_notify_key_t>(
31             dlsym(handle_, "dns_configuration_notify_key"));
32     dns_configuration_copy =
33         reinterpret_cast<dns_configuration_copy_t>(
34             dlsym(handle_, "dns_configuration_copy"));
35     dns_configuration_free =
36         reinterpret_cast<dns_configuration_free_t>(
37             dlsym(handle_, "dns_configuration_free"));
38   }
39 
~DnsInfoApi()40   ~DnsInfoApi() {
41     if (handle_)
42       dlclose(handle_);
43   }
44 
45   dns_configuration_notify_key_t dns_configuration_notify_key = nullptr;
46   dns_configuration_copy_t dns_configuration_copy = nullptr;
47   dns_configuration_free_t dns_configuration_free = nullptr;
48 
49  private:
50   raw_ptr<void> handle_;
51 };
52 
GetDnsInfoApi()53 const DnsInfoApi& GetDnsInfoApi() {
54   static base::LazyInstance<DnsInfoApi>::Leaky api = LAZY_INSTANCE_INITIALIZER;
55   return api.Get();
56 }
57 
58 struct DnsConfigTDeleter {
operator ()__anondd5642960111::DnsConfigTDeleter59   inline void operator()(dns_config_t* ptr) const {
60     if (GetDnsInfoApi().dns_configuration_free)
61       GetDnsInfoApi().dns_configuration_free(ptr);
62   }
63 };
64 
65 }  // namespace
66 
67 namespace net {
68 namespace internal {
69 
Watch(const base::RepeatingCallback<void (bool succeeded)> & callback)70 bool DnsConfigWatcher::Watch(
71     const base::RepeatingCallback<void(bool succeeded)>& callback) {
72   if (!GetDnsInfoApi().dns_configuration_notify_key)
73     return false;
74   return watcher_.Watch(GetDnsInfoApi().dns_configuration_notify_key(),
75                         callback);
76 }
77 
78 // static
CheckDnsConfig(bool & out_unhandled_options)79 bool DnsConfigWatcher::CheckDnsConfig(bool& out_unhandled_options) {
80   if (!GetDnsInfoApi().dns_configuration_copy)
81     return false;
82   std::unique_ptr<dns_config_t, DnsConfigTDeleter> dns_config(
83       GetDnsInfoApi().dns_configuration_copy());
84   if (!dns_config)
85     return false;
86 
87   // TODO(szym): Parse dns_config_t for resolvers rather than res_state.
88   // DnsClient can't handle domain-specific unscoped resolvers.
89   unsigned num_resolvers = 0;
90   for (int i = 0; i < dns_config->n_resolver; ++i) {
91     dns_resolver_t* resolver = dns_config->resolver[i];
92     if (!resolver->n_nameserver)
93       continue;
94     if (resolver->options && !strcmp(resolver->options, "mdns"))
95       continue;
96     ++num_resolvers;
97   }
98 
99   out_unhandled_options = num_resolvers > 1;
100   return true;
101 }
102 
103 }  // namespace internal
104 }  // namespace net
105