dns_config_watcher_mac.cc 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  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. #include "net/dns/dns_config_watcher_mac.h"
  5. #include <dlfcn.h>
  6. #include "base/lazy_instance.h"
  7. #include "base/memory/raw_ptr.h"
  8. #include "third_party/apple_apsl/dnsinfo.h"
  9. namespace {
  10. // dnsinfo symbols are available via libSystem.dylib, but can also be present in
  11. // SystemConfiguration.framework. To avoid confusion, load them explicitly from
  12. // libSystem.dylib.
  13. class DnsInfoApi {
  14. public:
  15. typedef const char* (*dns_configuration_notify_key_t)();
  16. typedef dns_config_t* (*dns_configuration_copy_t)();
  17. typedef void (*dns_configuration_free_t)(dns_config_t*);
  18. DnsInfoApi() {
  19. handle_ = dlopen("/usr/lib/libSystem.dylib",
  20. RTLD_LAZY | RTLD_NOLOAD);
  21. if (!handle_)
  22. return;
  23. dns_configuration_notify_key =
  24. reinterpret_cast<dns_configuration_notify_key_t>(
  25. dlsym(handle_, "dns_configuration_notify_key"));
  26. dns_configuration_copy =
  27. reinterpret_cast<dns_configuration_copy_t>(
  28. dlsym(handle_, "dns_configuration_copy"));
  29. dns_configuration_free =
  30. reinterpret_cast<dns_configuration_free_t>(
  31. dlsym(handle_, "dns_configuration_free"));
  32. }
  33. ~DnsInfoApi() {
  34. if (handle_)
  35. dlclose(handle_);
  36. }
  37. dns_configuration_notify_key_t dns_configuration_notify_key = nullptr;
  38. dns_configuration_copy_t dns_configuration_copy = nullptr;
  39. dns_configuration_free_t dns_configuration_free = nullptr;
  40. private:
  41. raw_ptr<void> handle_;
  42. };
  43. const DnsInfoApi& GetDnsInfoApi() {
  44. static base::LazyInstance<DnsInfoApi>::Leaky api = LAZY_INSTANCE_INITIALIZER;
  45. return api.Get();
  46. }
  47. struct DnsConfigTDeleter {
  48. inline void operator()(dns_config_t* ptr) const {
  49. if (GetDnsInfoApi().dns_configuration_free)
  50. GetDnsInfoApi().dns_configuration_free(ptr);
  51. }
  52. };
  53. } // namespace
  54. namespace net {
  55. namespace internal {
  56. bool DnsConfigWatcher::Watch(
  57. const base::RepeatingCallback<void(bool succeeded)>& callback) {
  58. if (!GetDnsInfoApi().dns_configuration_notify_key)
  59. return false;
  60. return watcher_.Watch(GetDnsInfoApi().dns_configuration_notify_key(),
  61. callback);
  62. }
  63. // static
  64. bool DnsConfigWatcher::CheckDnsConfig(bool& out_unhandled_options) {
  65. if (!GetDnsInfoApi().dns_configuration_copy)
  66. return false;
  67. std::unique_ptr<dns_config_t, DnsConfigTDeleter> dns_config(
  68. GetDnsInfoApi().dns_configuration_copy());
  69. if (!dns_config)
  70. return false;
  71. // TODO(szym): Parse dns_config_t for resolvers rather than res_state.
  72. // DnsClient can't handle domain-specific unscoped resolvers.
  73. unsigned num_resolvers = 0;
  74. for (int i = 0; i < dns_config->n_resolver; ++i) {
  75. dns_resolver_t* resolver = dns_config->resolver[i];
  76. if (!resolver->n_nameserver)
  77. continue;
  78. if (resolver->options && !strcmp(resolver->options, "mdns"))
  79. continue;
  80. ++num_resolvers;
  81. }
  82. out_unhandled_options = num_resolvers > 1;
  83. return true;
  84. }
  85. } // namespace internal
  86. } // namespace net