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