15d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
25d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// found in the LICENSE file.
45d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
55d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "net/dns/dns_config_watcher_mac.h"
65d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <dlfcn.h>
85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/lazy_instance.h"
105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "third_party/apple_apsl/dnsinfo.h"
115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace {
135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// dnsinfo symbols are available via libSystem.dylib, but can also be present in
155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// SystemConfiguration.framework. To avoid confusion, load them explicitly from
165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// libSystem.dylib.
175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)class DnsInfoApi {
185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) public:
195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  typedef const char* (*dns_configuration_notify_key_t)();
205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  typedef dns_config_t* (*dns_configuration_copy_t)();
215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  typedef void (*dns_configuration_free_t)(dns_config_t*);
225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DnsInfoApi()
245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      : dns_configuration_notify_key(NULL),
255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        dns_configuration_copy(NULL),
265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        dns_configuration_free(NULL) {
275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    handle_ = dlopen("/usr/lib/libSystem.dylib",
285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                     RTLD_LAZY | RTLD_NOLOAD);
295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!handle_)
305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return;
315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    dns_configuration_notify_key =
325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        reinterpret_cast<dns_configuration_notify_key_t>(
335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            dlsym(handle_, "dns_configuration_notify_key"));
345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    dns_configuration_copy =
355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        reinterpret_cast<dns_configuration_copy_t>(
365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            dlsym(handle_, "dns_configuration_copy"));
375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    dns_configuration_free =
385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        reinterpret_cast<dns_configuration_free_t>(
395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            dlsym(handle_, "dns_configuration_free"));
405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ~DnsInfoApi() {
435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (handle_)
445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      dlclose(handle_);
455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  dns_configuration_notify_key_t dns_configuration_notify_key;
485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  dns_configuration_copy_t dns_configuration_copy;
495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  dns_configuration_free_t dns_configuration_free;
505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) private:
525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void* handle_;
535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const DnsInfoApi& GetDnsInfoApi() {
565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  static base::LazyInstance<DnsInfoApi>::Leaky api = LAZY_INSTANCE_INITIALIZER;
575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return api.Get();
585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)struct DnsConfigTDeleter {
615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  inline void operator()(dns_config_t* ptr) const {
625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (GetDnsInfoApi().dns_configuration_free)
635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      GetDnsInfoApi().dns_configuration_free(ptr);
645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace
685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace net {
705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace internal {
715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool DnsConfigWatcher::Watch(
735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::Callback<void(bool succeeded)>& callback) {
745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!GetDnsInfoApi().dns_configuration_notify_key)
755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return false;
765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return watcher_.Watch(GetDnsInfoApi().dns_configuration_notify_key(),
775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                        callback);
785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// static
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)ConfigParsePosixResult DnsConfigWatcher::CheckDnsConfig() {
825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!GetDnsInfoApi().dns_configuration_copy)
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return CONFIG_PARSE_POSIX_NO_DNSINFO;
845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<dns_config_t, DnsConfigTDeleter> dns_config(
855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      GetDnsInfoApi().dns_configuration_copy());
865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!dns_config)
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return CONFIG_PARSE_POSIX_NO_DNSINFO;
885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // TODO(szym): Parse dns_config_t for resolvers rather than res_state.
905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // DnsClient can't handle domain-specific unscoped resolvers.
915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  unsigned num_resolvers = 0;
925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (int i = 0; i < dns_config->n_resolver; ++i) {
935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    dns_resolver_t* resolver = dns_config->resolver[i];
945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!resolver->n_nameserver)
955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      continue;
965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (resolver->options && !strcmp(resolver->options, "mdns"))
975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      continue;
985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ++num_resolvers;
995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (num_resolvers > 1)
1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return CONFIG_PARSE_POSIX_UNHANDLED_OPTIONS;
1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return CONFIG_PARSE_POSIX_OK;
1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace internal
1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace net
107