OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/dns/dns_config_service_posix.h" | 5 #include "net/dns/dns_config_service_posix.h" |
6 | 6 |
7 #include <string> | 7 #include <string> |
8 | 8 |
9 #include "base/basictypes.h" | 9 #include "base/basictypes.h" |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
11 #include "base/files/file_path.h" | 11 #include "base/files/file_path.h" |
12 #include "base/files/file_path_watcher.h" | 12 #include "base/files/file_path_watcher.h" |
| 13 #include "base/lazy_instance.h" |
13 #include "base/memory/scoped_ptr.h" | 14 #include "base/memory/scoped_ptr.h" |
14 #include "base/metrics/histogram.h" | 15 #include "base/metrics/histogram.h" |
15 #include "base/time/time.h" | 16 #include "base/time/time.h" |
16 #include "net/base/ip_endpoint.h" | 17 #include "net/base/ip_endpoint.h" |
17 #include "net/base/net_util.h" | 18 #include "net/base/net_util.h" |
18 #include "net/dns/dns_hosts.h" | 19 #include "net/dns/dns_hosts.h" |
19 #include "net/dns/dns_protocol.h" | 20 #include "net/dns/dns_protocol.h" |
20 #include "net/dns/notify_watcher_mac.h" | 21 #include "net/dns/notify_watcher_mac.h" |
21 #include "net/dns/serial_worker.h" | 22 #include "net/dns/serial_worker.h" |
22 | 23 |
| 24 #if defined(OS_MACOSX) |
| 25 #include <dlfcn.h> |
| 26 |
| 27 #include "third_party/apple_apsl/dnsinfo.h" |
| 28 |
| 29 namespace { |
| 30 |
| 31 // dnsinfo symbols are available via libSystem.dylib, but can also be present in |
| 32 // SystemConfiguration.framework. To avoid confusion, load them explicitly from |
| 33 // libSystem.dylib. |
| 34 class DnsInfoApi { |
| 35 public: |
| 36 typedef const char* (*dns_configuration_notify_key_t)(); |
| 37 typedef dns_config_t* (*dns_configuration_copy_t)(); |
| 38 typedef void (*dns_configuration_free_t)(dns_config_t*); |
| 39 |
| 40 DnsInfoApi() |
| 41 : dns_configuration_notify_key(NULL), |
| 42 dns_configuration_copy(NULL), |
| 43 dns_configuration_free(NULL) { |
| 44 handle_ = dlopen("/usr/lib/libSystem.dylib", |
| 45 RTLD_LAZY | RTLD_NOLOAD); |
| 46 if (!handle_) |
| 47 return; |
| 48 dns_configuration_notify_key = |
| 49 reinterpret_cast<dns_configuration_notify_key_t>( |
| 50 dlsym(handle_, "dns_configuration_notify_key")); |
| 51 dns_configuration_copy = |
| 52 reinterpret_cast<dns_configuration_copy_t>( |
| 53 dlsym(handle_, "dns_configuration_copy")); |
| 54 dns_configuration_free = |
| 55 reinterpret_cast<dns_configuration_free_t>( |
| 56 dlsym(handle_, "dns_configuration_free")); |
| 57 } |
| 58 |
| 59 ~DnsInfoApi() { |
| 60 if (handle_) |
| 61 dlclose(handle_); |
| 62 } |
| 63 |
| 64 dns_configuration_notify_key_t dns_configuration_notify_key; |
| 65 dns_configuration_copy_t dns_configuration_copy; |
| 66 dns_configuration_free_t dns_configuration_free; |
| 67 |
| 68 private: |
| 69 void* handle_; |
| 70 }; |
| 71 |
| 72 const DnsInfoApi& GetDnsInfoApi() { |
| 73 static base::LazyInstance<DnsInfoApi>::Leaky api = LAZY_INSTANCE_INITIALIZER; |
| 74 return api.Get(); |
| 75 } |
| 76 |
| 77 struct DnsConfigTDeleter { |
| 78 inline void operator()(dns_config_t* ptr) const { |
| 79 if (GetDnsInfoApi().dns_configuration_free) |
| 80 GetDnsInfoApi().dns_configuration_free(ptr); |
| 81 } |
| 82 }; |
| 83 |
| 84 } // namespace |
| 85 #endif // defined(OS_MACOSX) |
| 86 |
23 namespace net { | 87 namespace net { |
24 | 88 |
25 #if !defined(OS_ANDROID) | 89 #if !defined(OS_ANDROID) |
26 namespace internal { | 90 namespace internal { |
27 | 91 |
28 namespace { | 92 namespace { |
29 | 93 |
30 const base::FilePath::CharType* kFilePathHosts = | 94 const base::FilePath::CharType* kFilePathHosts = |
31 FILE_PATH_LITERAL("/etc/hosts"); | 95 FILE_PATH_LITERAL("/etc/hosts"); |
32 | 96 |
33 #if defined(OS_MACOSX) | 97 #if defined(OS_MACOSX) |
34 // From 10.7.3 configd-395.10/dnsinfo/dnsinfo.h | |
35 static const char* kDnsNotifyKey = | |
36 "com.apple.system.SystemConfiguration.dns_configuration"; | |
37 | |
38 class ConfigWatcher { | 98 class ConfigWatcher { |
39 public: | 99 public: |
40 bool Watch(const base::Callback<void(bool succeeded)>& callback) { | 100 bool Watch(const base::Callback<void(bool succeeded)>& callback) { |
41 return watcher_.Watch(kDnsNotifyKey, callback); | 101 if (!GetDnsInfoApi().dns_configuration_notify_key) |
| 102 return false; |
| 103 return watcher_.Watch(GetDnsInfoApi().dns_configuration_notify_key(), |
| 104 callback); |
42 } | 105 } |
43 | 106 |
44 private: | 107 private: |
45 NotifyWatcherMac watcher_; | 108 NotifyWatcherMac watcher_; |
46 }; | 109 }; |
47 #else | 110 #else |
48 | 111 |
49 #ifndef _PATH_RESCONF // Normally defined in <resolv.h> | 112 #ifndef _PATH_RESCONF // Normally defined in <resolv.h> |
50 #define _PATH_RESCONF "/etc/resolv.conf" | 113 #define _PATH_RESCONF "/etc/resolv.conf" |
51 #endif | 114 #endif |
(...skipping 17 matching lines...) Expand all Loading... |
69 callback_.Run(!error); | 132 callback_.Run(!error); |
70 } | 133 } |
71 | 134 |
72 base::FilePathWatcher watcher_; | 135 base::FilePathWatcher watcher_; |
73 CallbackType callback_; | 136 CallbackType callback_; |
74 }; | 137 }; |
75 #endif | 138 #endif |
76 | 139 |
77 ConfigParsePosixResult ReadDnsConfig(DnsConfig* config) { | 140 ConfigParsePosixResult ReadDnsConfig(DnsConfig* config) { |
78 ConfigParsePosixResult result; | 141 ConfigParsePosixResult result; |
| 142 config->unhandled_options = false; |
79 #if defined(OS_OPENBSD) | 143 #if defined(OS_OPENBSD) |
80 // Note: res_ninit in glibc always returns 0 and sets RES_INIT. | 144 // Note: res_ninit in glibc always returns 0 and sets RES_INIT. |
81 // res_init behaves the same way. | 145 // res_init behaves the same way. |
82 memset(&_res, 0, sizeof(_res)); | 146 memset(&_res, 0, sizeof(_res)); |
83 if (res_init() == 0) { | 147 if (res_init() == 0) { |
84 result = ConvertResStateToDnsConfig(_res, config); | 148 result = ConvertResStateToDnsConfig(_res, config); |
85 } else { | 149 } else { |
86 result = CONFIG_PARSE_POSIX_RES_INIT_FAILED; | 150 result = CONFIG_PARSE_POSIX_RES_INIT_FAILED; |
87 } | 151 } |
88 #else // all other OS_POSIX | 152 #else // all other OS_POSIX |
89 struct __res_state res; | 153 struct __res_state res; |
90 memset(&res, 0, sizeof(res)); | 154 memset(&res, 0, sizeof(res)); |
91 if (res_ninit(&res) == 0) { | 155 if (res_ninit(&res) == 0) { |
92 result = ConvertResStateToDnsConfig(res, config); | 156 result = ConvertResStateToDnsConfig(res, config); |
93 } else { | 157 } else { |
94 result = CONFIG_PARSE_POSIX_RES_INIT_FAILED; | 158 result = CONFIG_PARSE_POSIX_RES_INIT_FAILED; |
95 } | 159 } |
96 // Prefer res_ndestroy where available. | 160 // Prefer res_ndestroy where available. |
97 #if defined(OS_MACOSX) || defined(OS_FREEBSD) | 161 #if defined(OS_MACOSX) || defined(OS_FREEBSD) |
98 res_ndestroy(&res); | 162 res_ndestroy(&res); |
99 #else | 163 #else |
100 res_nclose(&res); | 164 res_nclose(&res); |
101 #endif | 165 #endif |
102 #endif | 166 #endif |
| 167 |
| 168 #if defined(OS_MACOSX) |
| 169 if (!GetDnsInfoApi().dns_configuration_copy) |
| 170 return CONFIG_PARSE_POSIX_NO_DNSINFO; |
| 171 scoped_ptr<dns_config_t, DnsConfigTDeleter> dns_config( |
| 172 GetDnsInfoApi().dns_configuration_copy()); |
| 173 if (!dns_config) |
| 174 return CONFIG_PARSE_POSIX_NO_DNSINFO; |
| 175 |
| 176 // TODO(szym): Parse dns_config_t for resolvers rather than res_state. |
| 177 // DnsClient can't handle domain-specific unscoped resolvers. |
| 178 unsigned num_resolvers = 0; |
| 179 for (int i = 0; i < dns_config->n_resolver; ++i) { |
| 180 dns_resolver_t* resolver = dns_config->resolver[i]; |
| 181 if (!resolver->n_nameserver) |
| 182 continue; |
| 183 if (resolver->options && !strcmp(resolver->options, "mdns")) |
| 184 continue; |
| 185 ++num_resolvers; |
| 186 } |
| 187 if (num_resolvers > 1) { |
| 188 LOG(WARNING) << "dns_config has unhandled options!"; |
| 189 config->unhandled_options = true; |
| 190 return CONFIG_PARSE_POSIX_UNHANDLED_OPTIONS; |
| 191 } |
| 192 #endif // defined(OS_MACOSX) |
103 // Override timeout value to match default setting on Windows. | 193 // Override timeout value to match default setting on Windows. |
104 config->timeout = base::TimeDelta::FromSeconds(kDnsTimeoutSeconds); | 194 config->timeout = base::TimeDelta::FromSeconds(kDnsTimeoutSeconds); |
105 return result; | 195 return result; |
106 } | 196 } |
107 | 197 |
108 } // namespace | 198 } // namespace |
109 | 199 |
110 class DnsConfigServicePosix::Watcher { | 200 class DnsConfigServicePosix::Watcher { |
111 public: | 201 public: |
112 explicit Watcher(DnsConfigServicePosix* service) | 202 explicit Watcher(DnsConfigServicePosix* service) |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
165 // A SerialWorker that uses libresolv to initialize res_state and converts | 255 // A SerialWorker that uses libresolv to initialize res_state and converts |
166 // it to DnsConfig. | 256 // it to DnsConfig. |
167 class DnsConfigServicePosix::ConfigReader : public SerialWorker { | 257 class DnsConfigServicePosix::ConfigReader : public SerialWorker { |
168 public: | 258 public: |
169 explicit ConfigReader(DnsConfigServicePosix* service) | 259 explicit ConfigReader(DnsConfigServicePosix* service) |
170 : service_(service), success_(false) {} | 260 : service_(service), success_(false) {} |
171 | 261 |
172 virtual void DoWork() OVERRIDE { | 262 virtual void DoWork() OVERRIDE { |
173 base::TimeTicks start_time = base::TimeTicks::Now(); | 263 base::TimeTicks start_time = base::TimeTicks::Now(); |
174 ConfigParsePosixResult result = ReadDnsConfig(&dns_config_); | 264 ConfigParsePosixResult result = ReadDnsConfig(&dns_config_); |
175 success_ = (result == CONFIG_PARSE_POSIX_OK); | 265 switch (result) { |
| 266 case CONFIG_PARSE_POSIX_MISSING_OPTIONS: |
| 267 case CONFIG_PARSE_POSIX_UNHANDLED_OPTIONS: |
| 268 DCHECK(dns_config_.unhandled_options); |
| 269 // Fall through. |
| 270 case CONFIG_PARSE_POSIX_OK: |
| 271 success_ = true; |
| 272 break; |
| 273 default: |
| 274 success_ = false; |
| 275 break; |
| 276 } |
176 UMA_HISTOGRAM_ENUMERATION("AsyncDNS.ConfigParsePosix", | 277 UMA_HISTOGRAM_ENUMERATION("AsyncDNS.ConfigParsePosix", |
177 result, CONFIG_PARSE_POSIX_MAX); | 278 result, CONFIG_PARSE_POSIX_MAX); |
178 UMA_HISTOGRAM_BOOLEAN("AsyncDNS.ConfigParseResult", success_); | 279 UMA_HISTOGRAM_BOOLEAN("AsyncDNS.ConfigParseResult", success_); |
179 UMA_HISTOGRAM_TIMES("AsyncDNS.ConfigParseDuration", | 280 UMA_HISTOGRAM_TIMES("AsyncDNS.ConfigParseDuration", |
180 base::TimeTicks::Now() - start_time); | 281 base::TimeTicks::Now() - start_time); |
181 } | 282 } |
182 | 283 |
183 virtual void OnWorkFinished() OVERRIDE { | 284 virtual void OnWorkFinished() OVERRIDE { |
184 DCHECK(!IsCancelled()); | 285 DCHECK(!IsCancelled()); |
185 if (success_) { | 286 if (success_) { |
(...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
351 dns_config->timeout = base::TimeDelta::FromSeconds(res.retrans); | 452 dns_config->timeout = base::TimeDelta::FromSeconds(res.retrans); |
352 dns_config->attempts = res.retry; | 453 dns_config->attempts = res.retry; |
353 #if defined(RES_ROTATE) | 454 #if defined(RES_ROTATE) |
354 dns_config->rotate = res.options & RES_ROTATE; | 455 dns_config->rotate = res.options & RES_ROTATE; |
355 #endif | 456 #endif |
356 dns_config->edns0 = res.options & RES_USE_EDNS0; | 457 dns_config->edns0 = res.options & RES_USE_EDNS0; |
357 | 458 |
358 // The current implementation assumes these options are set. They normally | 459 // The current implementation assumes these options are set. They normally |
359 // cannot be overwritten by /etc/resolv.conf | 460 // cannot be overwritten by /etc/resolv.conf |
360 unsigned kRequiredOptions = RES_RECURSE | RES_DEFNAMES | RES_DNSRCH; | 461 unsigned kRequiredOptions = RES_RECURSE | RES_DEFNAMES | RES_DNSRCH; |
361 if ((res.options & kRequiredOptions) != kRequiredOptions) | 462 if ((res.options & kRequiredOptions) != kRequiredOptions) { |
| 463 dns_config->unhandled_options = true; |
362 return CONFIG_PARSE_POSIX_MISSING_OPTIONS; | 464 return CONFIG_PARSE_POSIX_MISSING_OPTIONS; |
| 465 } |
363 | 466 |
364 unsigned kUnhandledOptions = RES_USEVC | RES_IGNTC | RES_USE_DNSSEC; | 467 unsigned kUnhandledOptions = RES_USEVC | RES_IGNTC | RES_USE_DNSSEC; |
365 if (res.options & kUnhandledOptions) | 468 if (res.options & kUnhandledOptions) { |
| 469 dns_config->unhandled_options = true; |
366 return CONFIG_PARSE_POSIX_UNHANDLED_OPTIONS; | 470 return CONFIG_PARSE_POSIX_UNHANDLED_OPTIONS; |
| 471 } |
367 | 472 |
368 if (dns_config->nameservers.empty()) | 473 if (dns_config->nameservers.empty()) |
369 return CONFIG_PARSE_POSIX_NO_NAMESERVERS; | 474 return CONFIG_PARSE_POSIX_NO_NAMESERVERS; |
370 | 475 |
371 // If any name server is 0.0.0.0, assume the configuration is invalid. | 476 // If any name server is 0.0.0.0, assume the configuration is invalid. |
372 // TODO(szym): Measure how often this happens. http://crbug.com/125599 | 477 // TODO(szym): Measure how often this happens. http://crbug.com/125599 |
373 const IPAddressNumber kEmptyAddress(kIPv4AddressSize); | 478 const IPAddressNumber kEmptyAddress(kIPv4AddressSize); |
374 for (unsigned i = 0; i < dns_config->nameservers.size(); ++i) { | 479 for (unsigned i = 0; i < dns_config->nameservers.size(); ++i) { |
375 if (dns_config->nameservers[i].address() == kEmptyAddress) | 480 if (dns_config->nameservers[i].address() == kEmptyAddress) |
376 return CONFIG_PARSE_POSIX_NULL_ADDRESS; | 481 return CONFIG_PARSE_POSIX_NULL_ADDRESS; |
(...skipping 18 matching lines...) Expand all Loading... |
395 virtual void ReadNow() OVERRIDE {} | 500 virtual void ReadNow() OVERRIDE {} |
396 virtual bool StartWatching() OVERRIDE { return false; } | 501 virtual bool StartWatching() OVERRIDE { return false; } |
397 }; | 502 }; |
398 // static | 503 // static |
399 scoped_ptr<DnsConfigService> DnsConfigService::CreateSystemService() { | 504 scoped_ptr<DnsConfigService> DnsConfigService::CreateSystemService() { |
400 return scoped_ptr<DnsConfigService>(new StubDnsConfigService()); | 505 return scoped_ptr<DnsConfigService>(new StubDnsConfigService()); |
401 } | 506 } |
402 #endif | 507 #endif |
403 | 508 |
404 } // namespace net | 509 } // namespace net |
OLD | NEW |