• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #ifdef UNSAFE_BUFFERS_BUILD
6 // TODO(crbug.com/40284755): Remove this and spanify to fix the errors.
7 #pragma allow_unsafe_buffers
8 #endif
9 
10 #include "net/dns/dns_config_watcher_mac.h"
11 
12 #include <dlfcn.h>
13 
14 #include "base/compiler_specific.h"
15 #include "base/lazy_instance.h"
16 #include "base/memory/raw_ptr.h"
17 #include "third_party/apple_apsl/dnsinfo.h"
18 
19 namespace {
20 
21 // dnsinfo symbols are available via libSystem.dylib, but can also be present in
22 // SystemConfiguration.framework. To avoid confusion, load them explicitly from
23 // libSystem.dylib.
24 class DnsInfoApi {
25  public:
26   typedef const char* (*dns_configuration_notify_key_t)();
27   typedef dns_config_t* (*dns_configuration_copy_t)();
28   typedef void (*dns_configuration_free_t)(dns_config_t*);
29 
DnsInfoApi()30   DnsInfoApi() {
31     handle_ = dlopen("/usr/lib/libSystem.dylib",
32                      RTLD_LAZY | RTLD_NOLOAD);
33     if (!handle_)
34       return;
35     dns_configuration_notify_key =
36         reinterpret_cast<dns_configuration_notify_key_t>(
37             dlsym(handle_, "dns_configuration_notify_key"));
38     dns_configuration_copy =
39         reinterpret_cast<dns_configuration_copy_t>(
40             dlsym(handle_, "dns_configuration_copy"));
41     dns_configuration_free =
42         reinterpret_cast<dns_configuration_free_t>(
43             dlsym(handle_, "dns_configuration_free"));
44   }
45 
~DnsInfoApi()46   ~DnsInfoApi() {
47     if (handle_)
48       dlclose(handle_);
49   }
50 
51   dns_configuration_notify_key_t dns_configuration_notify_key = nullptr;
52   dns_configuration_copy_t dns_configuration_copy = nullptr;
53   dns_configuration_free_t dns_configuration_free = nullptr;
54 
55  private:
56   raw_ptr<void> handle_;
57 };
58 
GetDnsInfoApi()59 const DnsInfoApi& GetDnsInfoApi() {
60   static base::LazyInstance<DnsInfoApi>::Leaky api = LAZY_INSTANCE_INITIALIZER;
61   return api.Get();
62 }
63 
64 struct DnsConfigTDeleter {
operator ()__anona84d699c0111::DnsConfigTDeleter65   inline void operator()(dns_config_t* ptr) const {
66     if (GetDnsInfoApi().dns_configuration_free)
67       GetDnsInfoApi().dns_configuration_free(ptr);
68   }
69 };
70 
71 }  // namespace
72 
73 namespace net {
74 namespace internal {
75 
Watch(const base::RepeatingCallback<void (bool succeeded)> & callback)76 bool DnsConfigWatcher::Watch(
77     const base::RepeatingCallback<void(bool succeeded)>& callback) {
78   if (!GetDnsInfoApi().dns_configuration_notify_key)
79     return false;
80   return watcher_.Watch(GetDnsInfoApi().dns_configuration_notify_key(),
81                         callback);
82 }
83 
84 // `dns_config->resolver` contains an array of pointers but is not correctly
85 // aligned. Pointers, on 64-bit, have 8-byte alignment but everything in
86 // dnsinfo.h is modified to have 4-byte alignment with pragma pack. Those
87 // pragmas are not sufficient to realign the `dns_resolver_t*` elements of
88 // `dns_config->resolver`. The header would need to be patched to replace
89 // `dns_resolver_t**` with, say, a `dns_resolver_ptr*` where `dns_resolver_ptr`
90 // is a less aligned `dns_resolver_t*` type.
91 NO_SANITIZE("alignment")
CheckDnsConfig(bool & out_unhandled_options)92 bool DnsConfigWatcher::CheckDnsConfig(bool& out_unhandled_options) {
93   if (!GetDnsInfoApi().dns_configuration_copy)
94     return false;
95   std::unique_ptr<dns_config_t, DnsConfigTDeleter> dns_config(
96       GetDnsInfoApi().dns_configuration_copy());
97   if (!dns_config)
98     return false;
99 
100   // TODO(szym): Parse dns_config_t for resolvers rather than res_state.
101   // DnsClient can't handle domain-specific unscoped resolvers.
102   unsigned num_resolvers = 0;
103   for (int i = 0; i < dns_config->n_resolver; ++i) {
104     dns_resolver_t* resolver = dns_config->resolver[i];
105     if (!resolver->n_nameserver)
106       continue;
107     if (resolver->options && !strcmp(resolver->options, "mdns"))
108       continue;
109     ++num_resolvers;
110   }
111 
112   out_unhandled_options = num_resolvers > 1;
113   return true;
114 }
115 
116 }  // namespace internal
117 }  // namespace net
118