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
3 // found in the LICENSE file.
4
5 #include "net/dns/dns_config_service_posix.h"
6
7 #include <memory>
8 #include <string>
9 #include <type_traits>
10
11 #include "base/bind.h"
12 #include "base/files/file.h"
13 #include "base/files/file_path.h"
14 #include "base/files/file_path_watcher.h"
15 #include "base/lazy_instance.h"
16 #include "base/location.h"
17 #include "base/logging.h"
18 #include "base/macros.h"
19 #include "base/metrics/histogram_macros.h"
20 #include "base/single_thread_task_runner.h"
21 #include "base/threading/scoped_blocking_call.h"
22 #include "base/threading/sequenced_task_runner_handle.h"
23 #include "base/time/time.h"
24 #include "build/build_config.h"
25 #include "net/base/ip_address.h"
26 #include "net/base/ip_endpoint.h"
27 #include "net/dns/dns_config.h"
28 #include "net/dns/dns_hosts.h"
29 #include "net/dns/notify_watcher_mac.h"
30 #include "net/dns/public/dns_protocol.h"
31 #include "net/dns/serial_worker.h"
32
33 #if defined(OS_MAC)
34 #include "net/dns/dns_config_watcher_mac.h"
35 #endif
36
37 #if defined(OS_ANDROID)
38 #include <sys/system_properties.h>
39 #include "base/android/build_info.h"
40 #include "net/android/network_library.h"
41 #include "net/base/address_tracker_linux.h"
42 #include "net/base/network_change_notifier.h"
43 #include "net/base/network_interfaces.h"
44 #endif
45
46 namespace net {
47
48 namespace internal {
49
50 namespace {
51
52 #if defined(OS_ANDROID)
53 const base::FilePath::CharType kFilePathHosts[] =
54 FILE_PATH_LITERAL("/system/etc/hosts");
55 #else
56 const base::FilePath::CharType kFilePathHosts[] =
57 FILE_PATH_LITERAL("/etc/hosts");
58 #endif
59
60 #if defined(OS_IOS)
61 // There is no public API to watch the DNS configuration on iOS.
62 class DnsConfigWatcher {
63 public:
64 using CallbackType = base::RepeatingCallback<void(bool succeeded)>;
65
Watch(const CallbackType & callback)66 bool Watch(const CallbackType& callback) {
67 return false;
68 }
69 };
70
71 #elif defined(OS_ANDROID)
72
73 // On Android, assume DNS config may have changed on every network change.
74 class DnsConfigWatcher : public NetworkChangeNotifier::NetworkChangeObserver {
75 public:
DnsConfigWatcher()76 DnsConfigWatcher() { NetworkChangeNotifier::AddNetworkChangeObserver(this); }
77
~DnsConfigWatcher()78 ~DnsConfigWatcher() override {
79 NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
80 }
81
82 using CallbackType = base::RepeatingCallback<void(bool succeeded)>;
83
Watch(const CallbackType & callback)84 bool Watch(const CallbackType& callback) {
85 callback_ = callback;
86 return true;
87 }
88
89 // NetworkChangeNotifier::NetworkChangeObserver implementation:
OnNetworkChanged(NetworkChangeNotifier::ConnectionType type)90 void OnNetworkChanged(NetworkChangeNotifier::ConnectionType type) override {
91 if (!callback_.is_null() && type != NetworkChangeNotifier::CONNECTION_NONE)
92 callback_.Run(true);
93 }
94
95 private:
96 CallbackType callback_;
97 };
98
99 #elif defined(OS_MAC)
100
101 // DnsConfigWatcher for OS_MAC is in dns_config_watcher_mac.{hh,cc}.
102
103 #else // !defined(OS_IOS) && !defined(OS_ANDROID) && !defined(OS_MAC)
104
105 #ifndef _PATH_RESCONF // Normally defined in <resolv.h>
106 #define _PATH_RESCONF "/etc/resolv.conf"
107 #endif
108
109 const base::FilePath::CharType kFilePathConfig[] =
110 FILE_PATH_LITERAL(_PATH_RESCONF);
111
112 class DnsConfigWatcher {
113 public:
114 using CallbackType = base::RepeatingCallback<void(bool succeeded)>;
115
Watch(const CallbackType & callback)116 bool Watch(const CallbackType& callback) {
117 callback_ = callback;
118 return watcher_.Watch(base::FilePath(kFilePathConfig), false,
119 base::BindRepeating(&DnsConfigWatcher::OnCallback,
120 base::Unretained(this)));
121 }
122
123 private:
OnCallback(const base::FilePath & path,bool error)124 void OnCallback(const base::FilePath& path, bool error) {
125 callback_.Run(!error);
126 }
127
128 base::FilePathWatcher watcher_;
129 CallbackType callback_;
130 };
131 #endif // defined(OS_IOS)
132
133 #if defined(OS_ANDROID)
IsVpnPresent()134 bool IsVpnPresent() {
135 NetworkInterfaceList networks;
136 if (!GetNetworkList(&networks, INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES))
137 return false;
138
139 for (NetworkInterface network : networks) {
140 if (AddressTrackerLinux::IsTunnelInterfaceName(network.name.c_str()))
141 return true;
142 }
143 return false;
144 }
145 #endif // defined(OS_ANDROID)
146
ReadDnsConfig(DnsConfig * dns_config)147 ConfigParsePosixResult ReadDnsConfig(DnsConfig* dns_config) {
148 base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
149 base::BlockingType::MAY_BLOCK);
150 dns_config->unhandled_options = false;
151 #if !defined(OS_ANDROID)
152 ConfigParsePosixResult result;
153 // TODO(fuchsia): Use res_ninit() when it's implemented on Fuchsia.
154 #if defined(OS_OPENBSD) || defined(OS_FUCHSIA)
155 // Note: res_ninit in glibc always returns 0 and sets RES_INIT.
156 // res_init behaves the same way.
157 memset(&_res, 0, sizeof(_res));
158 if (res_init() == 0) {
159 result = ConvertResStateToDnsConfig(_res, dns_config);
160 } else {
161 result = CONFIG_PARSE_POSIX_RES_INIT_FAILED;
162 }
163 #else // all other OS_POSIX
164 struct __res_state res;
165 memset(&res, 0, sizeof(res));
166 if (res_ninit(&res) == 0) {
167 result = ConvertResStateToDnsConfig(res, dns_config);
168 } else {
169 result = CONFIG_PARSE_POSIX_RES_INIT_FAILED;
170 }
171 // Prefer res_ndestroy where available.
172 #if defined(OS_APPLE) || defined(OS_FREEBSD) || defined(OS_DRAGONFLY)
173 res_ndestroy(&res);
174 #else
175 res_nclose(&res);
176 #endif // defined(OS_APPLE) || defined(OS_FREEBSD)
177 #endif // defined(OS_OPENBSD)
178
179 #if defined(OS_MAC)
180 ConfigParsePosixResult error = DnsConfigWatcher::CheckDnsConfig();
181 switch (error) {
182 case CONFIG_PARSE_POSIX_OK:
183 break;
184 case CONFIG_PARSE_POSIX_UNHANDLED_OPTIONS:
185 LOG(WARNING) << "dns_config has unhandled options!";
186 dns_config->unhandled_options = true;
187 FALLTHROUGH;
188 default:
189 return error;
190 }
191 #endif // defined(OS_MAC)
192 // Override |fallback_period| value to match default setting on Windows.
193 dns_config->fallback_period = kDnsDefaultFallbackPeriod;
194 return result;
195 #else // defined(OS_ANDROID)
196 dns_config->nameservers.clear();
197
198 if (base::android::BuildInfo::GetInstance()->sdk_int() >=
199 base::android::SDK_VERSION_MARSHMALLOW) {
200 return net::android::GetDnsServers(&dns_config->nameservers,
201 &dns_config->dns_over_tls_active,
202 &dns_config->dns_over_tls_hostname);
203 }
204
205 if (IsVpnPresent()) {
206 dns_config->unhandled_options = true;
207 return CONFIG_PARSE_POSIX_UNHANDLED_OPTIONS;
208 }
209
210 // NOTE(pauljensen): __system_property_get and the net.dns1/2 properties are
211 // not supported APIs, but they're only read on pre-Marshmallow Android which
212 // was released years ago and isn't changing.
213 char property_value[PROP_VALUE_MAX];
214 __system_property_get("net.dns1", property_value);
215 std::string dns1_string = property_value;
216 __system_property_get("net.dns2", property_value);
217 std::string dns2_string = property_value;
218 if (dns1_string.empty() && dns2_string.empty())
219 return CONFIG_PARSE_POSIX_NO_NAMESERVERS;
220
221 IPAddress dns1_address;
222 IPAddress dns2_address;
223 bool parsed1 = dns1_address.AssignFromIPLiteral(dns1_string);
224 bool parsed2 = dns2_address.AssignFromIPLiteral(dns2_string);
225 if (!parsed1 && !parsed2)
226 return CONFIG_PARSE_POSIX_BAD_ADDRESS;
227
228 if (parsed1) {
229 IPEndPoint dns1(dns1_address, dns_protocol::kDefaultPort);
230 dns_config->nameservers.push_back(dns1);
231 }
232 if (parsed2) {
233 IPEndPoint dns2(dns2_address, dns_protocol::kDefaultPort);
234 dns_config->nameservers.push_back(dns2);
235 }
236
237 return CONFIG_PARSE_POSIX_OK;
238 #endif // !defined(OS_ANDROID)
239 }
240
241 } // namespace
242
243 class DnsConfigServicePosix::Watcher {
244 public:
Watcher(DnsConfigServicePosix * service)245 explicit Watcher(DnsConfigServicePosix* service) : service_(service) {}
246 ~Watcher() = default;
247
Watch()248 bool Watch() {
249 bool success = true;
250 if (!config_watcher_.Watch(base::BindRepeating(&Watcher::OnConfigChanged,
251 base::Unretained(this)))) {
252 LOG(ERROR) << "DNS config watch failed to start.";
253 success = false;
254 UMA_HISTOGRAM_ENUMERATION("AsyncDNS.WatchStatus",
255 DNS_CONFIG_WATCH_FAILED_TO_START_CONFIG,
256 DNS_CONFIG_WATCH_MAX);
257 }
258 // Hosts file should never change on Android or iOS (and watching it on Android
259 // is problematic; see http://crbug.com/600442), so don't watch it there.
260 #if !defined(OS_ANDROID) && !defined(OS_IOS)
261 if (!hosts_watcher_.Watch(base::FilePath(service_->file_path_hosts_), false,
262 base::BindRepeating(&Watcher::OnHostsChanged,
263 base::Unretained(this)))) {
264 LOG(ERROR) << "DNS hosts watch failed to start.";
265 success = false;
266 UMA_HISTOGRAM_ENUMERATION("AsyncDNS.WatchStatus",
267 DNS_CONFIG_WATCH_FAILED_TO_START_HOSTS,
268 DNS_CONFIG_WATCH_MAX);
269 }
270 #endif // !defined(OS_ANDROID) && !defined(OS_IOS)
271 return success;
272 }
273
274 private:
OnConfigChanged(bool succeeded)275 void OnConfigChanged(bool succeeded) {
276 // Ignore transient flutter of resolv.conf by delaying the signal a bit.
277 const base::TimeDelta kDelay = base::TimeDelta::FromMilliseconds(50);
278 base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
279 FROM_HERE,
280 base::BindOnce(&Watcher::OnConfigChangedDelayed,
281 weak_factory_.GetWeakPtr(), succeeded),
282 kDelay);
283 }
284
OnConfigChangedDelayed(bool succeeded)285 void OnConfigChangedDelayed(bool succeeded) {
286 service_->OnConfigChanged(succeeded);
287 }
288
OnHostsChanged(const base::FilePath & path,bool error)289 void OnHostsChanged(const base::FilePath& path, bool error) {
290 service_->OnHostsChanged(!error);
291 }
292
293 DnsConfigServicePosix* const service_;
294 DnsConfigWatcher config_watcher_;
295 #if !defined(OS_ANDROID) && !defined(OS_IOS)
296 base::FilePathWatcher hosts_watcher_;
297 #endif // !defined(OS_ANDROID) && !defined(OS_IOS)
298
299 base::WeakPtrFactory<Watcher> weak_factory_{this};
300
301 DISALLOW_COPY_AND_ASSIGN(Watcher);
302 };
303
304 // A SerialWorker that uses libresolv to initialize res_state and converts
305 // it to DnsConfig (except on Android, where it reads system properties
306 // net.dns1 and net.dns2; see #if around ReadDnsConfig above.)
307 class DnsConfigServicePosix::ConfigReader : public SerialWorker {
308 public:
ConfigReader(DnsConfigServicePosix * service)309 explicit ConfigReader(DnsConfigServicePosix* service)
310 : service_(service), success_(false) {
311 // Allow execution on another thread; nothing thread-specific about
312 // constructor.
313 DETACH_FROM_SEQUENCE(sequence_checker_);
314 }
315
DoWork()316 void DoWork() override {
317 base::TimeTicks start_time = base::TimeTicks::Now();
318 ConfigParsePosixResult result = ReadDnsConfig(&dns_config_);
319 switch (result) {
320 case CONFIG_PARSE_POSIX_MISSING_OPTIONS:
321 case CONFIG_PARSE_POSIX_UNHANDLED_OPTIONS:
322 DCHECK(dns_config_.unhandled_options);
323 FALLTHROUGH;
324 case CONFIG_PARSE_POSIX_OK:
325 success_ = true;
326 break;
327 default:
328 success_ = false;
329 break;
330 }
331 UMA_HISTOGRAM_ENUMERATION("AsyncDNS.ConfigParsePosix",
332 result, CONFIG_PARSE_POSIX_MAX);
333 UMA_HISTOGRAM_TIMES("AsyncDNS.ConfigParseDuration",
334 base::TimeTicks::Now() - start_time);
335 }
336
OnWorkFinished()337 void OnWorkFinished() override {
338 DCHECK(!IsCancelled());
339 if (success_) {
340 service_->OnConfigRead(dns_config_);
341 } else {
342 LOG(WARNING) << "Failed to read DnsConfig.";
343 }
344 }
345
346 private:
347 ~ConfigReader() override = default;
348
349 // Raw pointer to owning DnsConfigService. This must never be accessed inside
350 // DoWork(), since service may be destroyed while SerialWorker is running
351 // on worker thread.
352 DnsConfigServicePosix* const service_;
353 // Written in DoWork, read in OnWorkFinished, no locking necessary.
354 DnsConfig dns_config_;
355 bool success_;
356
357 DISALLOW_COPY_AND_ASSIGN(ConfigReader);
358 };
359
360 // A SerialWorker that reads the HOSTS file and runs Callback.
361 class DnsConfigServicePosix::HostsReader : public SerialWorker {
362 public:
HostsReader(DnsConfigServicePosix * service)363 explicit HostsReader(DnsConfigServicePosix* service)
364 : service_(service),
365 file_path_hosts_(service->file_path_hosts_),
366 success_(false) {
367 // Allow execution on another thread; nothing thread-specific about
368 // constructor.
369 DETACH_FROM_SEQUENCE(sequence_checker_);
370 }
371
372 private:
~HostsReader()373 ~HostsReader() override {}
374
DoWork()375 void DoWork() override {
376 base::TimeTicks start_time = base::TimeTicks::Now();
377 base::ScopedBlockingCall scoped_blocking_call(
378 FROM_HERE, base::BlockingType::MAY_BLOCK);
379 success_ = ParseHostsFile(file_path_hosts_, &hosts_);
380 UMA_HISTOGRAM_BOOLEAN("AsyncDNS.HostParseResult", success_);
381 UMA_HISTOGRAM_TIMES("AsyncDNS.HostsParseDuration",
382 base::TimeTicks::Now() - start_time);
383 }
384
OnWorkFinished()385 void OnWorkFinished() override {
386 if (success_) {
387 service_->OnHostsRead(hosts_);
388 } else {
389 LOG(WARNING) << "Failed to read DnsHosts.";
390 }
391 }
392
393 // Raw pointer to owning DnsConfigService. This must never be accessed inside
394 // DoWork(), since service may be destroyed while SerialWorker is running
395 // on worker thread.
396 DnsConfigServicePosix* const service_;
397 // Hosts file path to parse.
398 const base::FilePath file_path_hosts_;
399 // Written in DoWork, read in OnWorkFinished, no locking necessary.
400 DnsHosts hosts_;
401 bool success_;
402
403 DISALLOW_COPY_AND_ASSIGN(HostsReader);
404 };
405
DnsConfigServicePosix()406 DnsConfigServicePosix::DnsConfigServicePosix()
407 : file_path_hosts_(kFilePathHosts) {
408 // Allow constructing on one thread and living on another.
409 DETACH_FROM_SEQUENCE(sequence_checker_);
410 }
411
~DnsConfigServicePosix()412 DnsConfigServicePosix::~DnsConfigServicePosix() {
413 config_reader_->Cancel();
414 hosts_reader_->Cancel();
415 }
416
RefreshConfig()417 void DnsConfigServicePosix::RefreshConfig() {
418 InvalidateConfig();
419 InvalidateHosts();
420 ReadNow();
421 }
422
ReadNow()423 void DnsConfigServicePosix::ReadNow() {
424 config_reader_->WorkNow();
425 hosts_reader_->WorkNow();
426 }
427
StartWatching()428 bool DnsConfigServicePosix::StartWatching() {
429 CreateReaders();
430 // TODO(szym): re-start watcher if that makes sense. http://crbug.com/116139
431 watcher_.reset(new Watcher(this));
432 UMA_HISTOGRAM_ENUMERATION("AsyncDNS.WatchStatus", DNS_CONFIG_WATCH_STARTED,
433 DNS_CONFIG_WATCH_MAX);
434 return watcher_->Watch();
435 }
436
OnConfigChanged(bool succeeded)437 void DnsConfigServicePosix::OnConfigChanged(bool succeeded) {
438 InvalidateConfig();
439 if (succeeded) {
440 config_reader_->WorkNow();
441 } else {
442 LOG(ERROR) << "DNS config watch failed.";
443 set_watch_failed(true);
444 UMA_HISTOGRAM_ENUMERATION("AsyncDNS.WatchStatus",
445 DNS_CONFIG_WATCH_FAILED_CONFIG,
446 DNS_CONFIG_WATCH_MAX);
447 }
448 }
449
OnHostsChanged(bool succeeded)450 void DnsConfigServicePosix::OnHostsChanged(bool succeeded) {
451 InvalidateHosts();
452 if (succeeded) {
453 hosts_reader_->WorkNow();
454 } else {
455 LOG(ERROR) << "DNS hosts watch failed.";
456 set_watch_failed(true);
457 UMA_HISTOGRAM_ENUMERATION("AsyncDNS.WatchStatus",
458 DNS_CONFIG_WATCH_FAILED_HOSTS,
459 DNS_CONFIG_WATCH_MAX);
460 }
461 }
462
CreateReaders()463 void DnsConfigServicePosix::CreateReaders() {
464 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
465 DCHECK(!config_reader_);
466 config_reader_ = base::MakeRefCounted<ConfigReader>(this);
467 DCHECK(!hosts_reader_);
468 hosts_reader_ = base::MakeRefCounted<HostsReader>(this);
469 }
470
471 #if !defined(OS_ANDROID)
ConvertResStateToDnsConfig(const struct __res_state & res,DnsConfig * dns_config)472 ConfigParsePosixResult ConvertResStateToDnsConfig(const struct __res_state& res,
473 DnsConfig* dns_config) {
474 DCHECK(dns_config);
475
476 if (!(res.options & RES_INIT))
477 return CONFIG_PARSE_POSIX_RES_INIT_UNSET;
478
479 dns_config->nameservers.clear();
480
481 #if defined(OS_APPLE) || defined(OS_FREEBSD) || defined(OS_DRAGONFLY)
482 union res_sockaddr_union addresses[MAXNS];
483 int nscount = res_getservers(const_cast<res_state>(&res), addresses, MAXNS);
484 DCHECK_GE(nscount, 0);
485 DCHECK_LE(nscount, MAXNS);
486 for (int i = 0; i < nscount; ++i) {
487 IPEndPoint ipe;
488 if (!ipe.FromSockAddr(
489 reinterpret_cast<const struct sockaddr*>(&addresses[i]),
490 sizeof addresses[i])) {
491 return CONFIG_PARSE_POSIX_BAD_ADDRESS;
492 }
493 dns_config->nameservers.push_back(ipe);
494 }
495 #elif defined(OS_LINUX) || defined(OS_CHROMEOS)
496 static_assert(std::extent<decltype(res.nsaddr_list)>() >= MAXNS &&
497 std::extent<decltype(res._u._ext.nsaddrs)>() >= MAXNS,
498 "incompatible libresolv res_state");
499 DCHECK_LE(res.nscount, MAXNS);
500 // Initially, glibc stores IPv6 in |_ext.nsaddrs| and IPv4 in |nsaddr_list|.
501 // In res_send.c:res_nsend, it merges |nsaddr_list| into |nsaddrs|,
502 // but we have to combine the two arrays ourselves.
503 for (int i = 0; i < res.nscount; ++i) {
504 IPEndPoint ipe;
505 const struct sockaddr* addr = nullptr;
506 size_t addr_len = 0;
507 if (res.nsaddr_list[i].sin_family) { // The indicator used by res_nsend.
508 addr = reinterpret_cast<const struct sockaddr*>(&res.nsaddr_list[i]);
509 addr_len = sizeof res.nsaddr_list[i];
510 } else if (res._u._ext.nsaddrs[i]) {
511 addr = reinterpret_cast<const struct sockaddr*>(res._u._ext.nsaddrs[i]);
512 addr_len = sizeof *res._u._ext.nsaddrs[i];
513 } else {
514 return CONFIG_PARSE_POSIX_BAD_EXT_STRUCT;
515 }
516 if (!ipe.FromSockAddr(addr, addr_len))
517 return CONFIG_PARSE_POSIX_BAD_ADDRESS;
518 dns_config->nameservers.push_back(ipe);
519 }
520 #else // !(defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_APPLE) ||
521 // defined(OS_FREEBSD)) || defined(OS_DRAGONFLY)
522 DCHECK_LE(res.nscount, MAXNS);
523 for (int i = 0; i < res.nscount; ++i) {
524 IPEndPoint ipe;
525 if (!ipe.FromSockAddr(
526 reinterpret_cast<const struct sockaddr*>(&res.nsaddr_list[i]),
527 sizeof res.nsaddr_list[i])) {
528 return CONFIG_PARSE_POSIX_BAD_ADDRESS;
529 }
530 dns_config->nameservers.push_back(ipe);
531 }
532 #endif // defined(OS_APPLE) || defined(OS_FREEBSD) || defined(OS_DRAGONFLY)
533
534 dns_config->search.clear();
535 for (int i = 0; (i < MAXDNSRCH) && res.dnsrch[i]; ++i) {
536 dns_config->search.push_back(std::string(res.dnsrch[i]));
537 }
538
539 dns_config->ndots = res.ndots;
540 dns_config->fallback_period = base::TimeDelta::FromSeconds(res.retrans);
541 dns_config->attempts = res.retry;
542 #if defined(RES_ROTATE)
543 dns_config->rotate = res.options & RES_ROTATE;
544 #endif
545 #if !defined(RES_USE_DNSSEC)
546 // Some versions of libresolv don't have support for the DO bit. In this
547 // case, we proceed without it.
548 static const int RES_USE_DNSSEC = 0;
549 #endif
550
551 // The current implementation assumes these options are set. They normally
552 // cannot be overwritten by /etc/resolv.conf
553 const unsigned kRequiredOptions = RES_RECURSE | RES_DEFNAMES | RES_DNSRCH;
554 if ((res.options & kRequiredOptions) != kRequiredOptions) {
555 dns_config->unhandled_options = true;
556 return CONFIG_PARSE_POSIX_MISSING_OPTIONS;
557 }
558
559 const unsigned kUnhandledOptions = RES_USEVC | RES_IGNTC | RES_USE_DNSSEC;
560 if (res.options & kUnhandledOptions) {
561 dns_config->unhandled_options = true;
562 return CONFIG_PARSE_POSIX_UNHANDLED_OPTIONS;
563 }
564
565 if (dns_config->nameservers.empty())
566 return CONFIG_PARSE_POSIX_NO_NAMESERVERS;
567
568 // If any name server is 0.0.0.0, assume the configuration is invalid.
569 // TODO(szym): Measure how often this happens. http://crbug.com/125599
570 for (unsigned i = 0; i < dns_config->nameservers.size(); ++i) {
571 if (dns_config->nameservers[i].address().IsZero())
572 return CONFIG_PARSE_POSIX_NULL_ADDRESS;
573 }
574 return CONFIG_PARSE_POSIX_OK;
575 }
576
577 #endif // !defined(OS_ANDROID)
578
579 } // namespace internal
580
581 // static
CreateSystemService()582 std::unique_ptr<DnsConfigService> DnsConfigService::CreateSystemService() {
583 // DnsConfigService on iOS doesn't watch the config so its result can become
584 // inaccurate at any time. Disable it to prevent promulgation of inaccurate
585 // DnsConfigs.
586 #ifdef OS_IOS
587 return nullptr;
588 #else // defined(OS_IOS)
589 return std::unique_ptr<DnsConfigService>(
590 new internal::DnsConfigServicePosix());
591 #endif // defined(OS_IOS)
592 }
593
594 } // namespace net
595