Home | History | Annotate | Download | only in dns
      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