dns_config_service_posix.cc 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  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. #include "net/dns/dns_config_service_posix.h"
  5. #include <memory>
  6. #include <string>
  7. #include <type_traits>
  8. #include <utility>
  9. #include "base/bind.h"
  10. #include "base/files/file.h"
  11. #include "base/files/file_path.h"
  12. #include "base/files/file_path_watcher.h"
  13. #include "base/lazy_instance.h"
  14. #include "base/location.h"
  15. #include "base/logging.h"
  16. #include "base/memory/raw_ptr.h"
  17. #include "base/sequence_checker.h"
  18. #include "base/task/single_thread_task_runner.h"
  19. #include "base/threading/scoped_blocking_call.h"
  20. #include "base/time/time.h"
  21. #include "build/build_config.h"
  22. #include "net/base/ip_endpoint.h"
  23. #include "net/dns/dns_config.h"
  24. #include "net/dns/dns_hosts.h"
  25. #include "net/dns/notify_watcher_mac.h"
  26. #include "net/dns/public/resolv_reader.h"
  27. #include "net/dns/serial_worker.h"
  28. #include "third_party/abseil-cpp/absl/types/optional.h"
  29. #if BUILDFLAG(IS_MAC)
  30. #include "net/dns/dns_config_watcher_mac.h"
  31. #endif
  32. namespace net {
  33. namespace internal {
  34. namespace {
  35. const base::FilePath::CharType kFilePathHosts[] =
  36. FILE_PATH_LITERAL("/etc/hosts");
  37. #if BUILDFLAG(IS_IOS)
  38. // There is no public API to watch the DNS configuration on iOS.
  39. class DnsConfigWatcher {
  40. public:
  41. using CallbackType = base::RepeatingCallback<void(bool succeeded)>;
  42. bool Watch(const CallbackType& callback) {
  43. return false;
  44. }
  45. };
  46. #elif BUILDFLAG(IS_MAC)
  47. // DnsConfigWatcher for OS_MAC is in dns_config_watcher_mac.{hh,cc}.
  48. #else // !BUILDFLAG(IS_IOS) && !BUILDFLAG(IS_MAC)
  49. #ifndef _PATH_RESCONF // Normally defined in <resolv.h>
  50. #define _PATH_RESCONF "/etc/resolv.conf"
  51. #endif
  52. const base::FilePath::CharType kFilePathConfig[] =
  53. FILE_PATH_LITERAL(_PATH_RESCONF);
  54. class DnsConfigWatcher {
  55. public:
  56. using CallbackType = base::RepeatingCallback<void(bool succeeded)>;
  57. bool Watch(const CallbackType& callback) {
  58. callback_ = callback;
  59. return watcher_.Watch(base::FilePath(kFilePathConfig),
  60. base::FilePathWatcher::Type::kNonRecursive,
  61. base::BindRepeating(&DnsConfigWatcher::OnCallback,
  62. base::Unretained(this)));
  63. }
  64. private:
  65. void OnCallback(const base::FilePath& path, bool error) {
  66. callback_.Run(!error);
  67. }
  68. base::FilePathWatcher watcher_;
  69. CallbackType callback_;
  70. };
  71. #endif // BUILDFLAG(IS_IOS)
  72. absl::optional<DnsConfig> ReadDnsConfig() {
  73. base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
  74. base::BlockingType::MAY_BLOCK);
  75. absl::optional<DnsConfig> dns_config;
  76. {
  77. std::unique_ptr<ScopedResState> scoped_res_state =
  78. ResolvReader().GetResState();
  79. if (scoped_res_state) {
  80. dns_config = ConvertResStateToDnsConfig(scoped_res_state->state());
  81. }
  82. }
  83. if (!dns_config.has_value())
  84. return dns_config;
  85. #if BUILDFLAG(IS_MAC)
  86. if (!DnsConfigWatcher::CheckDnsConfig(
  87. dns_config->unhandled_options /* out_unhandled_options */)) {
  88. return absl::nullopt;
  89. }
  90. #endif // BUILDFLAG(IS_MAC)
  91. // Override |fallback_period| value to match default setting on Windows.
  92. dns_config->fallback_period = kDnsDefaultFallbackPeriod;
  93. return dns_config;
  94. }
  95. } // namespace
  96. class DnsConfigServicePosix::Watcher : public DnsConfigService::Watcher {
  97. public:
  98. explicit Watcher(DnsConfigServicePosix& service)
  99. : DnsConfigService::Watcher(service) {}
  100. Watcher(const Watcher&) = delete;
  101. Watcher& operator=(const Watcher&) = delete;
  102. ~Watcher() override = default;
  103. bool Watch() override {
  104. CheckOnCorrectSequence();
  105. bool success = true;
  106. if (!config_watcher_.Watch(base::BindRepeating(&Watcher::OnConfigChanged,
  107. base::Unretained(this)))) {
  108. LOG(ERROR) << "DNS config watch failed to start.";
  109. success = false;
  110. }
  111. // Hosts file should never change on iOS, so don't watch it there.
  112. #if !BUILDFLAG(IS_IOS)
  113. if (!hosts_watcher_.Watch(
  114. base::FilePath(kFilePathHosts),
  115. base::FilePathWatcher::Type::kNonRecursive,
  116. base::BindRepeating(&Watcher::OnHostsFilePathWatcherChange,
  117. base::Unretained(this)))) {
  118. LOG(ERROR) << "DNS hosts watch failed to start.";
  119. success = false;
  120. }
  121. #endif // !BUILDFLAG(IS_IOS)
  122. return success;
  123. }
  124. private:
  125. #if !BUILDFLAG(IS_IOS)
  126. void OnHostsFilePathWatcherChange(const base::FilePath& path, bool error) {
  127. OnHostsChanged(!error);
  128. }
  129. #endif // !BUILDFLAG(IS_IOS)
  130. DnsConfigWatcher config_watcher_;
  131. #if !BUILDFLAG(IS_IOS)
  132. base::FilePathWatcher hosts_watcher_;
  133. #endif // !BUILDFLAG(IS_IOS)
  134. };
  135. // A SerialWorker that uses libresolv to initialize res_state and converts
  136. // it to DnsConfig.
  137. class DnsConfigServicePosix::ConfigReader : public SerialWorker {
  138. public:
  139. explicit ConfigReader(DnsConfigServicePosix& service) : service_(&service) {
  140. // Allow execution on another thread; nothing thread-specific about
  141. // constructor.
  142. DETACH_FROM_SEQUENCE(sequence_checker_);
  143. }
  144. ~ConfigReader() override = default;
  145. ConfigReader(const ConfigReader&) = delete;
  146. ConfigReader& operator=(const ConfigReader&) = delete;
  147. std::unique_ptr<SerialWorker::WorkItem> CreateWorkItem() override {
  148. return std::make_unique<WorkItem>();
  149. }
  150. bool OnWorkFinished(std::unique_ptr<SerialWorker::WorkItem>
  151. serial_worker_work_item) override {
  152. DCHECK(serial_worker_work_item);
  153. DCHECK(!IsCancelled());
  154. WorkItem* work_item = static_cast<WorkItem*>(serial_worker_work_item.get());
  155. if (work_item->dns_config_.has_value()) {
  156. service_->OnConfigRead(std::move(work_item->dns_config_).value());
  157. return true;
  158. } else {
  159. LOG(WARNING) << "Failed to read DnsConfig.";
  160. return false;
  161. }
  162. }
  163. private:
  164. class WorkItem : public SerialWorker::WorkItem {
  165. public:
  166. void DoWork() override { dns_config_ = ReadDnsConfig(); }
  167. private:
  168. friend class ConfigReader;
  169. absl::optional<DnsConfig> dns_config_;
  170. };
  171. // Raw pointer to owning DnsConfigService.
  172. const raw_ptr<DnsConfigServicePosix> service_;
  173. };
  174. DnsConfigServicePosix::DnsConfigServicePosix()
  175. : DnsConfigService(kFilePathHosts) {
  176. // Allow constructing on one thread and living on another.
  177. DETACH_FROM_SEQUENCE(sequence_checker_);
  178. }
  179. DnsConfigServicePosix::~DnsConfigServicePosix() {
  180. if (config_reader_)
  181. config_reader_->Cancel();
  182. }
  183. void DnsConfigServicePosix::RefreshConfig() {
  184. InvalidateConfig();
  185. InvalidateHosts();
  186. ReadConfigNow();
  187. ReadHostsNow();
  188. }
  189. void DnsConfigServicePosix::ReadConfigNow() {
  190. if (!config_reader_)
  191. CreateReader();
  192. config_reader_->WorkNow();
  193. }
  194. bool DnsConfigServicePosix::StartWatching() {
  195. CreateReader();
  196. // TODO(szym): re-start watcher if that makes sense. http://crbug.com/116139
  197. watcher_ = std::make_unique<Watcher>(*this);
  198. return watcher_->Watch();
  199. }
  200. void DnsConfigServicePosix::CreateReader() {
  201. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  202. DCHECK(!config_reader_);
  203. config_reader_ = std::make_unique<ConfigReader>(*this);
  204. }
  205. absl::optional<DnsConfig> ConvertResStateToDnsConfig(
  206. const struct __res_state& res) {
  207. DnsConfig dns_config;
  208. dns_config.unhandled_options = false;
  209. if (!(res.options & RES_INIT))
  210. return absl::nullopt;
  211. absl::optional<std::vector<IPEndPoint>> nameservers = GetNameservers(res);
  212. if (!nameservers)
  213. return absl::nullopt;
  214. dns_config.nameservers = std::move(*nameservers);
  215. dns_config.search.clear();
  216. for (int i = 0; (i < MAXDNSRCH) && res.dnsrch[i]; ++i) {
  217. dns_config.search.emplace_back(res.dnsrch[i]);
  218. }
  219. dns_config.ndots = res.ndots;
  220. dns_config.fallback_period = base::Seconds(res.retrans);
  221. dns_config.attempts = res.retry;
  222. #if defined(RES_ROTATE)
  223. dns_config.rotate = res.options & RES_ROTATE;
  224. #endif
  225. #if !defined(RES_USE_DNSSEC)
  226. // Some versions of libresolv don't have support for the DO bit. In this
  227. // case, we proceed without it.
  228. static const int RES_USE_DNSSEC = 0;
  229. #endif
  230. // The current implementation assumes these options are set. They normally
  231. // cannot be overwritten by /etc/resolv.conf
  232. const unsigned kRequiredOptions = RES_RECURSE | RES_DEFNAMES | RES_DNSRCH;
  233. if ((res.options & kRequiredOptions) != kRequiredOptions) {
  234. dns_config.unhandled_options = true;
  235. return dns_config;
  236. }
  237. const unsigned kUnhandledOptions = RES_USEVC | RES_IGNTC | RES_USE_DNSSEC;
  238. if (res.options & kUnhandledOptions) {
  239. dns_config.unhandled_options = true;
  240. return dns_config;
  241. }
  242. if (dns_config.nameservers.empty())
  243. return absl::nullopt;
  244. // If any name server is 0.0.0.0, assume the configuration is invalid.
  245. // TODO(szym): Measure how often this happens. http://crbug.com/125599
  246. for (const IPEndPoint& nameserver : dns_config.nameservers) {
  247. if (nameserver.address().IsZero())
  248. return absl::nullopt;
  249. }
  250. return dns_config;
  251. }
  252. } // namespace internal
  253. // static
  254. std::unique_ptr<DnsConfigService> DnsConfigService::CreateSystemService() {
  255. // DnsConfigService on iOS doesn't watch the config so its result can become
  256. // inaccurate at any time. Disable it to prevent promulgation of inaccurate
  257. // DnsConfigs.
  258. #if BUILDFLAG(IS_IOS)
  259. return nullptr;
  260. #else // BUILDFLAG(IS_IOS)
  261. return std::make_unique<internal::DnsConfigServicePosix>();
  262. #endif // BUILDFLAG(IS_IOS)
  263. }
  264. } // namespace net