Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(78)

Side by Side Diff: net/dns/dns_config_service_posix.cc

Issue 21368005: Detect domain-specific resolvers on OS X and disable DnsClient in such cases. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: remove blank line Created 7 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 #include "third_party/apple_apsl/dnsinfo.h"
mmenke 2013/08/16 17:35:39 nit: Blank line between system and non-system hea
szym 2013/08/17 05:08:51 Done.
27 namespace {
28
29 // dnsinfo symbols are available via libSystem.dylib, but can also be present in
30 // SystemConfiguration.framework. To avoid confusion, load them explicitly from
31 // libSystem.dylib.
32 class DnsInfoApi {
33 public:
34 typedef const char* (*dns_configuration_notify_key_t)();
35 typedef dns_config_t* (*dns_configuration_copy_t)();
36 typedef void (*dns_configuration_free_t)(dns_config_t*);
37
38 DnsInfoApi() {
39 handle_ = dlopen("/usr/lib/libSystem.dylib",
40 RTLD_LAZY | RTLD_NOLOAD);
41 if (!handle_) return;
mmenke 2013/08/16 17:35:39 Splirt onto two lines.
szym 2013/08/17 05:08:51 Done.
42 dns_configuration_notify_key =
mmenke 2013/08/16 17:35:39 These should be initialized to NULL.
szym 2013/08/17 05:08:51 Done.
43 reinterpret_cast<dns_configuration_notify_key_t>(
44 dlsym(handle_, "dns_configuration_notify_key"));
45 dns_configuration_copy =
46 reinterpret_cast<dns_configuration_copy_t>(
47 dlsym(handle_, "dns_configuration_copy"));
48 dns_configuration_free =
49 reinterpret_cast<dns_configuration_free_t>(
50 dlsym(handle_, "dns_configuration_free"));
51 }
52 ~DnsInfoApi() {
mmenke 2013/08/16 17:35:39 nit: Blank line between functions.
szym 2013/08/17 05:08:51 Done.
53 if (handle_) dlclose(handle_);
mmenke 2013/08/16 17:35:39 nit: Should be on two different lines.
szym 2013/08/17 05:08:51 Done.
54 }
55
56 dns_configuration_notify_key_t dns_configuration_notify_key;
57 dns_configuration_copy_t dns_configuration_copy;
58 dns_configuration_free_t dns_configuration_free;
59
60 private:
61 void* handle_;
62 };
63
64 const DnsInfoApi& dns_info_api() {
65 base::LazyInstance<DnsInfoApi>::Leaky api = LAZY_INSTANCE_INITIALIZER;
mmenke 2013/08/16 17:35:39 I can't find another instance where this is done -
szym 2013/08/16 17:48:27 There is no need for it to be global, and I'd pref
szym 2013/08/17 05:08:51 I added static.
66 return api.Get();
67 }
68
69 struct DnsConfigTDeleter {
70 inline void operator()(dns_config_t* ptr) const {
71 if (dns_info_api().dns_configuration_free)
72 dns_info_api().dns_configuration_free(ptr);
73 }
74 };
75
76 } // namespace
77 #endif
mmenke 2013/08/16 17:35:39 nit: #endif // defined(OS_MACOSX)
szym 2013/08/17 05:08:51 Done.
78
23 namespace net { 79 namespace net {
24 80
25 #if !defined(OS_ANDROID) 81 #if !defined(OS_ANDROID)
26 namespace internal { 82 namespace internal {
27 83
28 namespace { 84 namespace {
29 85
30 const base::FilePath::CharType* kFilePathHosts = 86 const base::FilePath::CharType* kFilePathHosts =
31 FILE_PATH_LITERAL("/etc/hosts"); 87 FILE_PATH_LITERAL("/etc/hosts");
32 88
33 #if defined(OS_MACOSX) 89 #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 { 90 class ConfigWatcher {
39 public: 91 public:
40 bool Watch(const base::Callback<void(bool succeeded)>& callback) { 92 bool Watch(const base::Callback<void(bool succeeded)>& callback) {
41 return watcher_.Watch(kDnsNotifyKey, callback); 93 if (!dns_info_api().dns_configuration_notify_key) return false;
mmenke 2013/08/16 17:35:39 Split onto two lines.
szym 2013/08/17 05:08:51 Done.
94 return watcher_.Watch(dns_info_api().dns_configuration_notify_key(),
95 callback);
42 } 96 }
43 97
44 private: 98 private:
45 NotifyWatcherMac watcher_; 99 NotifyWatcherMac watcher_;
46 }; 100 };
47 #else 101 #else
48 102
49 #ifndef _PATH_RESCONF // Normally defined in <resolv.h> 103 #ifndef _PATH_RESCONF // Normally defined in <resolv.h>
50 #define _PATH_RESCONF "/etc/resolv.conf" 104 #define _PATH_RESCONF "/etc/resolv.conf"
51 #endif 105 #endif
(...skipping 17 matching lines...) Expand all
69 callback_.Run(!error); 123 callback_.Run(!error);
70 } 124 }
71 125
72 base::FilePathWatcher watcher_; 126 base::FilePathWatcher watcher_;
73 CallbackType callback_; 127 CallbackType callback_;
74 }; 128 };
75 #endif 129 #endif
76 130
77 ConfigParsePosixResult ReadDnsConfig(DnsConfig* config) { 131 ConfigParsePosixResult ReadDnsConfig(DnsConfig* config) {
78 ConfigParsePosixResult result; 132 ConfigParsePosixResult result;
133 config->unhandled_options = false;
79 #if defined(OS_OPENBSD) 134 #if defined(OS_OPENBSD)
80 // Note: res_ninit in glibc always returns 0 and sets RES_INIT. 135 // Note: res_ninit in glibc always returns 0 and sets RES_INIT.
81 // res_init behaves the same way. 136 // res_init behaves the same way.
82 memset(&_res, 0, sizeof(_res)); 137 memset(&_res, 0, sizeof(_res));
83 if (res_init() == 0) { 138 if (res_init() == 0) {
84 result = ConvertResStateToDnsConfig(_res, config); 139 result = ConvertResStateToDnsConfig(_res, config);
85 } else { 140 } else {
86 result = CONFIG_PARSE_POSIX_RES_INIT_FAILED; 141 result = CONFIG_PARSE_POSIX_RES_INIT_FAILED;
87 } 142 }
88 #else // all other OS_POSIX 143 #else // all other OS_POSIX
89 struct __res_state res; 144 struct __res_state res;
90 memset(&res, 0, sizeof(res)); 145 memset(&res, 0, sizeof(res));
91 if (res_ninit(&res) == 0) { 146 if (res_ninit(&res) == 0) {
92 result = ConvertResStateToDnsConfig(res, config); 147 result = ConvertResStateToDnsConfig(res, config);
93 } else { 148 } else {
94 result = CONFIG_PARSE_POSIX_RES_INIT_FAILED; 149 result = CONFIG_PARSE_POSIX_RES_INIT_FAILED;
95 } 150 }
96 // Prefer res_ndestroy where available. 151 // Prefer res_ndestroy where available.
97 #if defined(OS_MACOSX) || defined(OS_FREEBSD) 152 #if defined(OS_MACOSX) || defined(OS_FREEBSD)
98 res_ndestroy(&res); 153 res_ndestroy(&res);
99 #else 154 #else
100 res_nclose(&res); 155 res_nclose(&res);
101 #endif 156 #endif
102 #endif 157 #endif
158
159 #if defined(OS_MACOSX)
160 if (!dns_info_api().dns_configuration_copy)
161 return CONFIG_PARSE_POSIX_NO_DNSINFO;
162 scoped_ptr<dns_config_t, DnsConfigTDeleter> dns_config(
163 dns_info_api().dns_configuration_copy());
164 if (!dns_config)
165 return CONFIG_PARSE_POSIX_NO_DNSINFO;
166
167 // TODO(szym): Parse dns_config_t for resolvers rather than res_state.
mmenke 2013/08/16 17:35:39 This comment isn't quite right - we actually do st
szym 2013/08/16 17:48:27 We do right now, and that's why I left a TODO here
mmenke 2013/08/16 18:24:19 Right, missed the TODO.
168 // DnsClient can't handle domain-specific unscoped resolvers.
169 unsigned num_resolvers = 0;
170 for (int i = 0; i < dns_config->n_resolver; ++i) {
mmenke 2013/08/16 17:35:39 Is there documentation on this data structure some
szym 2013/08/16 17:48:27 The source code is the only documentation. In part
171 dns_resolver_t* resolver = dns_config->resolver[i];
172 if (!resolver->n_nameserver)
173 continue;
174 if (resolver->options && !strcmp(resolver->options, "mdns"))
175 continue;
176 ++num_resolvers;
177 }
178 if (num_resolvers > 1) {
mmenke 2013/08/16 18:24:19 Rather then checking if there's more than one reso
szym 2013/08/16 18:40:40 That is what we need to check.
mmenke 2013/08/16 18:43:26 Thanks for the explanation. Seems reasonable, the
179 LOG(WARNING) << "dns_config has unhandled options!";
180 config->unhandled_options = true;
181 return CONFIG_PARSE_POSIX_UNHANDLED_OPTIONS;
182 }
183 #endif
mmenke 2013/08/16 17:35:39 nit: #endif // defined(OS_MACOSX)
szym 2013/08/17 05:08:51 Done.
103 // Override timeout value to match default setting on Windows. 184 // Override timeout value to match default setting on Windows.
104 config->timeout = base::TimeDelta::FromSeconds(kDnsTimeoutSeconds); 185 config->timeout = base::TimeDelta::FromSeconds(kDnsTimeoutSeconds);
105 return result; 186 return result;
106 } 187 }
107 188
108 } // namespace 189 } // namespace
109 190
110 class DnsConfigServicePosix::Watcher { 191 class DnsConfigServicePosix::Watcher {
111 public: 192 public:
112 explicit Watcher(DnsConfigServicePosix* service) 193 explicit Watcher(DnsConfigServicePosix* service)
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
165 // A SerialWorker that uses libresolv to initialize res_state and converts 246 // A SerialWorker that uses libresolv to initialize res_state and converts
166 // it to DnsConfig. 247 // it to DnsConfig.
167 class DnsConfigServicePosix::ConfigReader : public SerialWorker { 248 class DnsConfigServicePosix::ConfigReader : public SerialWorker {
168 public: 249 public:
169 explicit ConfigReader(DnsConfigServicePosix* service) 250 explicit ConfigReader(DnsConfigServicePosix* service)
170 : service_(service), success_(false) {} 251 : service_(service), success_(false) {}
171 252
172 virtual void DoWork() OVERRIDE { 253 virtual void DoWork() OVERRIDE {
173 base::TimeTicks start_time = base::TimeTicks::Now(); 254 base::TimeTicks start_time = base::TimeTicks::Now();
174 ConfigParsePosixResult result = ReadDnsConfig(&dns_config_); 255 ConfigParsePosixResult result = ReadDnsConfig(&dns_config_);
175 success_ = (result == CONFIG_PARSE_POSIX_OK); 256 switch (result) {
257 case CONFIG_PARSE_POSIX_MISSING_OPTIONS:
258 case CONFIG_PARSE_POSIX_UNHANDLED_OPTIONS:
259 DCHECK(dns_config_.unhandled_options);
mmenke 2013/08/16 17:35:39 Think it's worth a comment why this shouldn't happ
mmenke 2013/08/16 17:51:30 Sorry, misread this code.
260 // Fall through.
261 case CONFIG_PARSE_POSIX_OK:
262 success_ = true;
263 break;
264 default:
265 success_ = false;
266 break;
267 }
176 UMA_HISTOGRAM_ENUMERATION("AsyncDNS.ConfigParsePosix", 268 UMA_HISTOGRAM_ENUMERATION("AsyncDNS.ConfigParsePosix",
177 result, CONFIG_PARSE_POSIX_MAX); 269 result, CONFIG_PARSE_POSIX_MAX);
178 UMA_HISTOGRAM_BOOLEAN("AsyncDNS.ConfigParseResult", success_); 270 UMA_HISTOGRAM_BOOLEAN("AsyncDNS.ConfigParseResult", success_);
179 UMA_HISTOGRAM_TIMES("AsyncDNS.ConfigParseDuration", 271 UMA_HISTOGRAM_TIMES("AsyncDNS.ConfigParseDuration",
180 base::TimeTicks::Now() - start_time); 272 base::TimeTicks::Now() - start_time);
181 } 273 }
182 274
183 virtual void OnWorkFinished() OVERRIDE { 275 virtual void OnWorkFinished() OVERRIDE {
184 DCHECK(!IsCancelled()); 276 DCHECK(!IsCancelled());
185 if (success_) { 277 if (success_) {
(...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after
351 dns_config->timeout = base::TimeDelta::FromSeconds(res.retrans); 443 dns_config->timeout = base::TimeDelta::FromSeconds(res.retrans);
352 dns_config->attempts = res.retry; 444 dns_config->attempts = res.retry;
353 #if defined(RES_ROTATE) 445 #if defined(RES_ROTATE)
354 dns_config->rotate = res.options & RES_ROTATE; 446 dns_config->rotate = res.options & RES_ROTATE;
355 #endif 447 #endif
356 dns_config->edns0 = res.options & RES_USE_EDNS0; 448 dns_config->edns0 = res.options & RES_USE_EDNS0;
357 449
358 // The current implementation assumes these options are set. They normally 450 // The current implementation assumes these options are set. They normally
359 // cannot be overwritten by /etc/resolv.conf 451 // cannot be overwritten by /etc/resolv.conf
360 unsigned kRequiredOptions = RES_RECURSE | RES_DEFNAMES | RES_DNSRCH; 452 unsigned kRequiredOptions = RES_RECURSE | RES_DEFNAMES | RES_DNSRCH;
361 if ((res.options & kRequiredOptions) != kRequiredOptions) 453 if ((res.options & kRequiredOptions) != kRequiredOptions) {
454 dns_config->unhandled_options = true;
362 return CONFIG_PARSE_POSIX_MISSING_OPTIONS; 455 return CONFIG_PARSE_POSIX_MISSING_OPTIONS;
456 }
363 457
364 unsigned kUnhandledOptions = RES_USEVC | RES_IGNTC | RES_USE_DNSSEC; 458 unsigned kUnhandledOptions = RES_USEVC | RES_IGNTC | RES_USE_DNSSEC;
365 if (res.options & kUnhandledOptions) 459 if (res.options & kUnhandledOptions) {
460 dns_config->unhandled_options = true;
366 return CONFIG_PARSE_POSIX_UNHANDLED_OPTIONS; 461 return CONFIG_PARSE_POSIX_UNHANDLED_OPTIONS;
462 }
367 463
368 if (dns_config->nameservers.empty()) 464 if (dns_config->nameservers.empty())
369 return CONFIG_PARSE_POSIX_NO_NAMESERVERS; 465 return CONFIG_PARSE_POSIX_NO_NAMESERVERS;
370 466
371 // If any name server is 0.0.0.0, assume the configuration is invalid. 467 // 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 468 // TODO(szym): Measure how often this happens. http://crbug.com/125599
373 const IPAddressNumber kEmptyAddress(kIPv4AddressSize); 469 const IPAddressNumber kEmptyAddress(kIPv4AddressSize);
374 for (unsigned i = 0; i < dns_config->nameservers.size(); ++i) { 470 for (unsigned i = 0; i < dns_config->nameservers.size(); ++i) {
375 if (dns_config->nameservers[i].address() == kEmptyAddress) 471 if (dns_config->nameservers[i].address() == kEmptyAddress)
376 return CONFIG_PARSE_POSIX_NULL_ADDRESS; 472 return CONFIG_PARSE_POSIX_NULL_ADDRESS;
(...skipping 18 matching lines...) Expand all
395 virtual void ReadNow() OVERRIDE {} 491 virtual void ReadNow() OVERRIDE {}
396 virtual bool StartWatching() OVERRIDE { return false; } 492 virtual bool StartWatching() OVERRIDE { return false; }
397 }; 493 };
398 // static 494 // static
399 scoped_ptr<DnsConfigService> DnsConfigService::CreateSystemService() { 495 scoped_ptr<DnsConfigService> DnsConfigService::CreateSystemService() {
400 return scoped_ptr<DnsConfigService>(new StubDnsConfigService()); 496 return scoped_ptr<DnsConfigService>(new StubDnsConfigService());
401 } 497 }
402 #endif 498 #endif
403 499
404 } // namespace net 500 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698