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()53const 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)70bool 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)79bool 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