dns_config_service_win.cc 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685
  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_win.h"
  5. #include <sysinfoapi.h>
  6. #include <algorithm>
  7. #include <memory>
  8. #include <set>
  9. #include <string>
  10. #include "base/bind.h"
  11. #include "base/callback.h"
  12. #include "base/compiler_specific.h"
  13. #include "base/files/file_path.h"
  14. #include "base/files/file_path_watcher.h"
  15. #include "base/location.h"
  16. #include "base/logging.h"
  17. #include "base/memory/free_deleter.h"
  18. #include "base/memory/raw_ptr.h"
  19. #include "base/memory/weak_ptr.h"
  20. #include "base/metrics/histogram_functions.h"
  21. #include "base/sequence_checker.h"
  22. #include "base/strings/string_piece.h"
  23. #include "base/strings/string_split.h"
  24. #include "base/strings/string_util.h"
  25. #include "base/strings/utf_string_conversions.h"
  26. #include "base/synchronization/lock.h"
  27. #include "base/task/single_thread_task_runner.h"
  28. #include "base/threading/scoped_blocking_call.h"
  29. #include "base/win/registry.h"
  30. #include "base/win/scoped_handle.h"
  31. #include "base/win/windows_types.h"
  32. #include "net/base/ip_address.h"
  33. #include "net/base/network_change_notifier.h"
  34. #include "net/dns/dns_hosts.h"
  35. #include "net/dns/public/dns_protocol.h"
  36. #include "net/dns/serial_worker.h"
  37. #include "url/url_canon.h"
  38. namespace net {
  39. namespace internal {
  40. namespace {
  41. // Registry key paths.
  42. const wchar_t kTcpipPath[] =
  43. L"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters";
  44. const wchar_t kTcpip6Path[] =
  45. L"SYSTEM\\CurrentControlSet\\Services\\Tcpip6\\Parameters";
  46. const wchar_t kDnscachePath[] =
  47. L"SYSTEM\\CurrentControlSet\\Services\\Dnscache\\Parameters";
  48. const wchar_t kPolicyPath[] =
  49. L"SOFTWARE\\Policies\\Microsoft\\Windows NT\\DNSClient";
  50. // These values are persisted to logs. Entries should not be renumbered and
  51. // numeric values should never be reused.
  52. enum class DnsWindowsCompatibility {
  53. kCompatible = 0,
  54. kIncompatibleResolutionPolicy = 1,
  55. kIncompatibleProxy = 1 << 1,
  56. kIncompatibleVpn = 1 << 2,
  57. kIncompatibleAdapterSpecificNameserver = 1 << 3,
  58. KAllIncompatibleFlags = (1 << 4) - 1,
  59. kMaxValue = KAllIncompatibleFlags
  60. };
  61. inline constexpr DnsWindowsCompatibility operator|(DnsWindowsCompatibility a,
  62. DnsWindowsCompatibility b) {
  63. return static_cast<DnsWindowsCompatibility>(static_cast<int>(a) |
  64. static_cast<int>(b));
  65. }
  66. inline DnsWindowsCompatibility& operator|=(DnsWindowsCompatibility& a,
  67. DnsWindowsCompatibility b) {
  68. return a = a | b;
  69. }
  70. // Wrapper for GetAdaptersAddresses to get unicast addresses.
  71. // Returns nullptr if failed.
  72. std::unique_ptr<IP_ADAPTER_ADDRESSES, base::FreeDeleter>
  73. ReadAdapterUnicastAddresses() {
  74. base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
  75. base::BlockingType::MAY_BLOCK);
  76. std::unique_ptr<IP_ADAPTER_ADDRESSES, base::FreeDeleter> out;
  77. ULONG len = 15000; // As recommended by MSDN for GetAdaptersAddresses.
  78. UINT rv = ERROR_BUFFER_OVERFLOW;
  79. // Try up to three times.
  80. for (unsigned tries = 0; (tries < 3) && (rv == ERROR_BUFFER_OVERFLOW);
  81. tries++) {
  82. out.reset(static_cast<PIP_ADAPTER_ADDRESSES>(malloc(len)));
  83. memset(out.get(), 0, len);
  84. rv = GetAdaptersAddresses(AF_UNSPEC,
  85. GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_DNS_SERVER |
  86. GAA_FLAG_SKIP_MULTICAST |
  87. GAA_FLAG_SKIP_FRIENDLY_NAME,
  88. nullptr, out.get(), &len);
  89. }
  90. if (rv != NO_ERROR)
  91. out.reset();
  92. return out;
  93. }
  94. // Default address of "localhost" and local computer name can be overridden
  95. // by the HOSTS file, but if it's not there, then we need to fill it in.
  96. bool AddLocalhostEntriesTo(DnsHosts& in_out_hosts) {
  97. IPAddress loopback_ipv4 = IPAddress::IPv4Localhost();
  98. IPAddress loopback_ipv6 = IPAddress::IPv6Localhost();
  99. // This does not override any pre-existing entries from the HOSTS file.
  100. in_out_hosts.insert(std::make_pair(
  101. DnsHostsKey("localhost", ADDRESS_FAMILY_IPV4), loopback_ipv4));
  102. in_out_hosts.insert(std::make_pair(
  103. DnsHostsKey("localhost", ADDRESS_FAMILY_IPV6), loopback_ipv6));
  104. wchar_t buffer[MAX_PATH];
  105. DWORD size = MAX_PATH;
  106. if (!GetComputerNameExW(ComputerNameDnsHostname, buffer, &size))
  107. return false;
  108. std::string localname = ParseDomainASCII(buffer);
  109. if (localname.empty())
  110. return false;
  111. localname = base::ToLowerASCII(localname);
  112. bool have_ipv4 =
  113. in_out_hosts.count(DnsHostsKey(localname, ADDRESS_FAMILY_IPV4)) > 0;
  114. bool have_ipv6 =
  115. in_out_hosts.count(DnsHostsKey(localname, ADDRESS_FAMILY_IPV6)) > 0;
  116. if (have_ipv4 && have_ipv6)
  117. return true;
  118. std::unique_ptr<IP_ADAPTER_ADDRESSES, base::FreeDeleter> addresses =
  119. ReadAdapterUnicastAddresses();
  120. if (!addresses.get())
  121. return false;
  122. // The order of adapters is the network binding order, so stick to the
  123. // first good adapter for each family.
  124. for (const IP_ADAPTER_ADDRESSES* adapter = addresses.get();
  125. adapter != nullptr && (!have_ipv4 || !have_ipv6);
  126. adapter = adapter->Next) {
  127. if (adapter->OperStatus != IfOperStatusUp)
  128. continue;
  129. if (adapter->IfType == IF_TYPE_SOFTWARE_LOOPBACK)
  130. continue;
  131. for (const IP_ADAPTER_UNICAST_ADDRESS* address =
  132. adapter->FirstUnicastAddress;
  133. address != nullptr; address = address->Next) {
  134. IPEndPoint ipe;
  135. if (!ipe.FromSockAddr(address->Address.lpSockaddr,
  136. address->Address.iSockaddrLength)) {
  137. return false;
  138. }
  139. if (!have_ipv4 && (ipe.GetFamily() == ADDRESS_FAMILY_IPV4)) {
  140. have_ipv4 = true;
  141. in_out_hosts[DnsHostsKey(localname, ADDRESS_FAMILY_IPV4)] =
  142. ipe.address();
  143. } else if (!have_ipv6 && (ipe.GetFamily() == ADDRESS_FAMILY_IPV6)) {
  144. have_ipv6 = true;
  145. in_out_hosts[DnsHostsKey(localname, ADDRESS_FAMILY_IPV6)] =
  146. ipe.address();
  147. }
  148. }
  149. }
  150. return true;
  151. }
  152. // Watches a single registry key for changes.
  153. class RegistryWatcher {
  154. public:
  155. typedef base::RepeatingCallback<void(bool succeeded)> CallbackType;
  156. RegistryWatcher() {}
  157. RegistryWatcher(const RegistryWatcher&) = delete;
  158. RegistryWatcher& operator=(const RegistryWatcher&) = delete;
  159. ~RegistryWatcher() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); }
  160. bool Watch(const wchar_t key[], const CallbackType& callback) {
  161. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  162. DCHECK(!callback.is_null());
  163. DCHECK(callback_.is_null());
  164. callback_ = callback;
  165. if (key_.Open(HKEY_LOCAL_MACHINE, key, KEY_NOTIFY) != ERROR_SUCCESS)
  166. return false;
  167. return key_.StartWatching(base::BindOnce(&RegistryWatcher::OnObjectSignaled,
  168. base::Unretained(this)));
  169. }
  170. void OnObjectSignaled() {
  171. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  172. DCHECK(!callback_.is_null());
  173. if (key_.StartWatching(base::BindOnce(&RegistryWatcher::OnObjectSignaled,
  174. base::Unretained(this)))) {
  175. callback_.Run(true);
  176. } else {
  177. key_.Close();
  178. callback_.Run(false);
  179. }
  180. }
  181. private:
  182. CallbackType callback_;
  183. base::win::RegKey key_;
  184. SEQUENCE_CHECKER(sequence_checker_);
  185. };
  186. // Returns the path to the HOSTS file.
  187. base::FilePath GetHostsPath() {
  188. wchar_t buffer[MAX_PATH];
  189. UINT rc = GetSystemDirectory(buffer, MAX_PATH);
  190. DCHECK(0 < rc && rc < MAX_PATH);
  191. return base::FilePath(buffer).Append(
  192. FILE_PATH_LITERAL("drivers\\etc\\hosts"));
  193. }
  194. void ConfigureSuffixSearch(const WinDnsSystemSettings& settings,
  195. DnsConfig& in_out_config) {
  196. // SearchList takes precedence, so check it first.
  197. if (settings.policy_search_list.has_value()) {
  198. std::vector<std::string> search =
  199. ParseSearchList(settings.policy_search_list.value());
  200. if (!search.empty()) {
  201. in_out_config.search = std::move(search);
  202. return;
  203. }
  204. // Even if invalid, the policy disables the user-specified setting below.
  205. } else if (settings.tcpip_search_list.has_value()) {
  206. std::vector<std::string> search =
  207. ParseSearchList(settings.tcpip_search_list.value());
  208. if (!search.empty()) {
  209. in_out_config.search = std::move(search);
  210. return;
  211. }
  212. }
  213. // In absence of explicit search list, suffix search is:
  214. // [primary suffix, connection-specific suffix, devolution of primary suffix].
  215. // Primary suffix can be set by policy (primary_dns_suffix) or
  216. // user setting (tcpip_domain).
  217. //
  218. // The policy (primary_dns_suffix) can be edited via Group Policy Editor
  219. // (gpedit.msc) at Local Computer Policy => Computer Configuration
  220. // => Administrative Template => Network => DNS Client => Primary DNS Suffix.
  221. //
  222. // The user setting (tcpip_domain) can be configurred at Computer Name in
  223. // System Settings
  224. std::string primary_suffix;
  225. if (settings.primary_dns_suffix.has_value())
  226. primary_suffix = ParseDomainASCII(settings.primary_dns_suffix.value());
  227. if (primary_suffix.empty() && settings.tcpip_domain.has_value())
  228. primary_suffix = ParseDomainASCII(settings.tcpip_domain.value());
  229. if (primary_suffix.empty())
  230. return; // No primary suffix, hence no devolution.
  231. // Primary suffix goes in front.
  232. in_out_config.search.insert(in_out_config.search.begin(), primary_suffix);
  233. // Devolution is determined by precedence: policy > dnscache > tcpip.
  234. // |enabled|: UseDomainNameDevolution and |level|: DomainNameDevolutionLevel
  235. // are overridden independently.
  236. WinDnsSystemSettings::DevolutionSetting devolution =
  237. settings.policy_devolution;
  238. if (!devolution.enabled.has_value())
  239. devolution.enabled = settings.dnscache_devolution.enabled;
  240. if (!devolution.enabled.has_value())
  241. devolution.enabled = settings.tcpip_devolution.enabled;
  242. if (devolution.enabled.has_value() && (devolution.enabled.value() == 0))
  243. return; // Devolution disabled.
  244. // By default devolution is enabled.
  245. if (!devolution.level.has_value())
  246. devolution.level = settings.dnscache_devolution.level;
  247. if (!devolution.level.has_value())
  248. devolution.level = settings.tcpip_devolution.level;
  249. // After the recent update, Windows will try to determine a safe default
  250. // value by comparing the forest root domain (FRD) to the primary suffix.
  251. // See http://support.microsoft.com/kb/957579 for details.
  252. // For now, if the level is not set, we disable devolution, assuming that
  253. // we will fallback to the system getaddrinfo anyway. This might cause
  254. // performance loss for resolutions which depend on the system default
  255. // devolution setting.
  256. //
  257. // If the level is explicitly set below 2, devolution is disabled.
  258. if (!devolution.level.has_value() || devolution.level.value() < 2)
  259. return; // Devolution disabled.
  260. // Devolve the primary suffix. This naive logic matches the observed
  261. // behavior (see also ParseSearchList). If a suffix is not valid, it will be
  262. // discarded when the fully-qualified name is converted to DNS format.
  263. unsigned num_dots = std::count(primary_suffix.begin(),
  264. primary_suffix.end(), '.');
  265. for (size_t offset = 0; num_dots >= devolution.level.value(); --num_dots) {
  266. offset = primary_suffix.find('.', offset + 1);
  267. in_out_config.search.push_back(primary_suffix.substr(offset + 1));
  268. }
  269. }
  270. absl::optional<std::vector<IPEndPoint>> GetNameServers(
  271. const IP_ADAPTER_ADDRESSES* adapter) {
  272. std::vector<IPEndPoint> nameservers;
  273. for (const IP_ADAPTER_DNS_SERVER_ADDRESS* address =
  274. adapter->FirstDnsServerAddress;
  275. address != nullptr; address = address->Next) {
  276. IPEndPoint ipe;
  277. if (ipe.FromSockAddr(address->Address.lpSockaddr,
  278. address->Address.iSockaddrLength)) {
  279. if (WinDnsSystemSettings::IsStatelessDiscoveryAddress(ipe.address()))
  280. continue;
  281. // Override unset port.
  282. if (!ipe.port())
  283. ipe = IPEndPoint(ipe.address(), dns_protocol::kDefaultPort);
  284. nameservers.push_back(ipe);
  285. } else {
  286. return absl::nullopt;
  287. }
  288. }
  289. return nameservers;
  290. }
  291. bool CheckAndRecordCompatibility(bool have_name_resolution_policy,
  292. bool have_proxy,
  293. bool uses_vpn,
  294. bool has_adapter_specific_nameservers) {
  295. DnsWindowsCompatibility compatibility = DnsWindowsCompatibility::kCompatible;
  296. if (have_name_resolution_policy)
  297. compatibility |= DnsWindowsCompatibility::kIncompatibleResolutionPolicy;
  298. if (have_proxy)
  299. compatibility |= DnsWindowsCompatibility::kIncompatibleProxy;
  300. if (uses_vpn)
  301. compatibility |= DnsWindowsCompatibility::kIncompatibleVpn;
  302. if (has_adapter_specific_nameservers) {
  303. compatibility |=
  304. DnsWindowsCompatibility::kIncompatibleAdapterSpecificNameserver;
  305. }
  306. base::UmaHistogramEnumeration("Net.DNS.DnsConfig.Windows.Compatibility",
  307. compatibility);
  308. return compatibility == DnsWindowsCompatibility::kCompatible;
  309. }
  310. } // namespace
  311. std::string ParseDomainASCII(base::WStringPiece widestr) {
  312. if (widestr.empty())
  313. return "";
  314. // Check if already ASCII.
  315. if (base::IsStringASCII(base::AsStringPiece16(widestr))) {
  316. return std::string(widestr.begin(), widestr.end());
  317. }
  318. // Otherwise try to convert it from IDN to punycode.
  319. const int kInitialBufferSize = 256;
  320. url::RawCanonOutputT<char16_t, kInitialBufferSize> punycode;
  321. if (!url::IDNToASCII(base::as_u16cstr(widestr), widestr.length(), &punycode))
  322. return "";
  323. // |punycode_output| should now be ASCII; convert it to a std::string.
  324. // (We could use UTF16ToASCII() instead, but that requires an extra string
  325. // copy. Since ASCII is a subset of UTF8 the following is equivalent).
  326. std::string converted;
  327. bool success =
  328. base::UTF16ToUTF8(punycode.data(), punycode.length(), &converted);
  329. DCHECK(success);
  330. DCHECK(base::IsStringASCII(converted));
  331. return converted;
  332. }
  333. std::vector<std::string> ParseSearchList(base::WStringPiece value) {
  334. if (value.empty())
  335. return {};
  336. std::vector<std::string> output;
  337. // If the list includes an empty hostname (",," or ", ,"), it is terminated.
  338. // Although nslookup and network connection property tab ignore such
  339. // fragments ("a,b,,c" becomes ["a", "b", "c"]), our reference is getaddrinfo
  340. // (which sees ["a", "b"]). WMI queries also return a matching search list.
  341. for (base::WStringPiece t : base::SplitStringPiece(
  342. value, L",", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) {
  343. // Convert non-ASCII to punycode, although getaddrinfo does not properly
  344. // handle such suffixes.
  345. std::string parsed = ParseDomainASCII(t);
  346. if (parsed.empty())
  347. break;
  348. output.push_back(std::move(parsed));
  349. }
  350. return output;
  351. }
  352. absl::optional<DnsConfig> ConvertSettingsToDnsConfig(
  353. const WinDnsSystemSettings& settings) {
  354. bool uses_vpn = false;
  355. bool has_adapter_specific_nameservers = false;
  356. DnsConfig dns_config;
  357. std::set<IPEndPoint> previous_nameservers_set;
  358. // Use GetAdapterAddresses to get effective DNS server order and
  359. // connection-specific DNS suffix. Ignore disconnected and loopback adapters.
  360. // The order of adapters is the network binding order, so stick to the
  361. // first good adapter.
  362. for (const IP_ADAPTER_ADDRESSES* adapter = settings.addresses.get();
  363. adapter != nullptr; adapter = adapter->Next) {
  364. // Check each adapter for a VPN interface. Even if a single such interface
  365. // is present, treat this as an unhandled configuration.
  366. if (adapter->IfType == IF_TYPE_PPP) {
  367. uses_vpn = true;
  368. }
  369. absl::optional<std::vector<IPEndPoint>> nameservers =
  370. GetNameServers(adapter);
  371. if (!nameservers)
  372. return absl::nullopt;
  373. if (!nameservers->empty() && (adapter->OperStatus == IfOperStatusUp)) {
  374. // Check if the |adapter| has adapter specific nameservers.
  375. std::set<IPEndPoint> nameservers_set(nameservers->begin(),
  376. nameservers->end());
  377. if (!previous_nameservers_set.empty() &&
  378. (previous_nameservers_set != nameservers_set)) {
  379. has_adapter_specific_nameservers = true;
  380. }
  381. previous_nameservers_set = std::move(nameservers_set);
  382. }
  383. // Skip disconnected and loopback adapters. If a good configuration was
  384. // previously found, skip processing another adapter.
  385. if (adapter->OperStatus != IfOperStatusUp ||
  386. adapter->IfType == IF_TYPE_SOFTWARE_LOOPBACK ||
  387. !dns_config.nameservers.empty())
  388. continue;
  389. dns_config.nameservers = std::move(*nameservers);
  390. // IP_ADAPTER_ADDRESSES in Vista+ has a search list at |FirstDnsSuffix|,
  391. // but it came up empty in all trials.
  392. // |DnsSuffix| stores the effective connection-specific suffix, which is
  393. // obtained via DHCP (regkey: Tcpip\Parameters\Interfaces\{XXX}\DhcpDomain)
  394. // or specified by the user (regkey: Tcpip\Parameters\Domain).
  395. std::string dns_suffix = ParseDomainASCII(adapter->DnsSuffix);
  396. if (!dns_suffix.empty())
  397. dns_config.search.push_back(std::move(dns_suffix));
  398. }
  399. if (dns_config.nameservers.empty())
  400. return absl::nullopt; // No point continuing.
  401. // Windows always tries a multi-label name "as is" before using suffixes.
  402. dns_config.ndots = 1;
  403. if (!settings.append_to_multi_label_name.has_value()) {
  404. dns_config.append_to_multi_label_name = false;
  405. } else {
  406. dns_config.append_to_multi_label_name =
  407. (settings.append_to_multi_label_name.value() != 0);
  408. }
  409. if (settings.have_name_resolution_policy) {
  410. // TODO(szym): only set this to true if NRPT has DirectAccess rules.
  411. dns_config.use_local_ipv6 = true;
  412. }
  413. if (!CheckAndRecordCompatibility(settings.have_name_resolution_policy,
  414. settings.have_proxy, uses_vpn,
  415. has_adapter_specific_nameservers)) {
  416. dns_config.unhandled_options = true;
  417. }
  418. ConfigureSuffixSearch(settings, dns_config);
  419. return dns_config;
  420. }
  421. // Watches registry and HOSTS file for changes. Must live on a sequence which
  422. // allows IO.
  423. class DnsConfigServiceWin::Watcher
  424. : public NetworkChangeNotifier::IPAddressObserver,
  425. public DnsConfigService::Watcher {
  426. public:
  427. explicit Watcher(DnsConfigServiceWin& service)
  428. : DnsConfigService::Watcher(service) {}
  429. Watcher(const Watcher&) = delete;
  430. Watcher& operator=(const Watcher&) = delete;
  431. ~Watcher() override { NetworkChangeNotifier::RemoveIPAddressObserver(this); }
  432. bool Watch() override {
  433. CheckOnCorrectSequence();
  434. RegistryWatcher::CallbackType callback =
  435. base::BindRepeating(&Watcher::OnConfigChanged, base::Unretained(this));
  436. bool success = true;
  437. // The Tcpip key must be present.
  438. if (!tcpip_watcher_.Watch(kTcpipPath, callback)) {
  439. LOG(ERROR) << "DNS registry watch failed to start.";
  440. success = false;
  441. }
  442. // Watch for IPv6 nameservers.
  443. tcpip6_watcher_.Watch(kTcpip6Path, callback);
  444. // DNS suffix search list and devolution can be configured via group
  445. // policy which sets this registry key. If the key is missing, the policy
  446. // does not apply, and the DNS client uses Tcpip and Dnscache settings.
  447. // If a policy is installed, DnsConfigService will need to be restarted.
  448. // BUG=99509
  449. dnscache_watcher_.Watch(kDnscachePath, callback);
  450. policy_watcher_.Watch(kPolicyPath, callback);
  451. if (!hosts_watcher_.Watch(
  452. GetHostsPath(), base::FilePathWatcher::Type::kNonRecursive,
  453. base::BindRepeating(&Watcher::OnHostsFilePathWatcherChange,
  454. base::Unretained(this)))) {
  455. LOG(ERROR) << "DNS hosts watch failed to start.";
  456. success = false;
  457. } else {
  458. // Also need to observe changes to local non-loopback IP for DnsHosts.
  459. NetworkChangeNotifier::AddIPAddressObserver(this);
  460. }
  461. return success;
  462. }
  463. private:
  464. void OnHostsFilePathWatcherChange(const base::FilePath& path, bool error) {
  465. if (error)
  466. NetworkChangeNotifier::RemoveIPAddressObserver(this);
  467. OnHostsChanged(!error);
  468. }
  469. // NetworkChangeNotifier::IPAddressObserver:
  470. void OnIPAddressChanged() override {
  471. // Need to update non-loopback IP of local host.
  472. OnHostsChanged(true);
  473. }
  474. RegistryWatcher tcpip_watcher_;
  475. RegistryWatcher tcpip6_watcher_;
  476. RegistryWatcher dnscache_watcher_;
  477. RegistryWatcher policy_watcher_;
  478. base::FilePathWatcher hosts_watcher_;
  479. };
  480. // Reads config from registry and IpHelper. All work performed in ThreadPool.
  481. class DnsConfigServiceWin::ConfigReader : public SerialWorker {
  482. public:
  483. explicit ConfigReader(DnsConfigServiceWin& service)
  484. : SerialWorker(/*max_number_of_retries=*/3), service_(&service) {}
  485. ~ConfigReader() override {}
  486. // SerialWorker::
  487. std::unique_ptr<SerialWorker::WorkItem> CreateWorkItem() override {
  488. return std::make_unique<WorkItem>();
  489. }
  490. bool OnWorkFinished(std::unique_ptr<SerialWorker::WorkItem>
  491. serial_worker_work_item) override {
  492. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  493. DCHECK(serial_worker_work_item);
  494. DCHECK(!IsCancelled());
  495. WorkItem* work_item = static_cast<WorkItem*>(serial_worker_work_item.get());
  496. if (work_item->dns_config_.has_value()) {
  497. service_->OnConfigRead(std::move(work_item->dns_config_).value());
  498. return true;
  499. } else {
  500. LOG(WARNING) << "Failed to read DnsConfig.";
  501. return false;
  502. }
  503. }
  504. private:
  505. class WorkItem : public SerialWorker::WorkItem {
  506. public:
  507. ~WorkItem() override = default;
  508. void DoWork() override {
  509. absl::optional<WinDnsSystemSettings> settings =
  510. ReadWinSystemDnsSettings();
  511. if (settings.has_value())
  512. dns_config_ = ConvertSettingsToDnsConfig(settings.value());
  513. }
  514. private:
  515. friend DnsConfigServiceWin::ConfigReader;
  516. absl::optional<DnsConfig> dns_config_;
  517. };
  518. raw_ptr<DnsConfigServiceWin> service_;
  519. // Written in DoWork(), read in OnWorkFinished(). No locking required.
  520. };
  521. // Extension of DnsConfigService::HostsReader that fills in localhost and local
  522. // computer name if necessary.
  523. class DnsConfigServiceWin::HostsReader : public DnsConfigService::HostsReader {
  524. public:
  525. explicit HostsReader(DnsConfigServiceWin& service)
  526. : DnsConfigService::HostsReader(GetHostsPath().value(), service) {}
  527. ~HostsReader() override = default;
  528. HostsReader(const HostsReader&) = delete;
  529. HostsReader& operator=(const HostsReader&) = delete;
  530. // SerialWorker:
  531. std::unique_ptr<SerialWorker::WorkItem> CreateWorkItem() override {
  532. return std::make_unique<WorkItem>(GetHostsPath());
  533. }
  534. private:
  535. class WorkItem : public DnsConfigService::HostsReader::WorkItem {
  536. public:
  537. explicit WorkItem(base::FilePath hosts_file_path)
  538. : DnsConfigService::HostsReader::WorkItem(
  539. std::make_unique<DnsHostsFileParser>(
  540. std::move(hosts_file_path))) {}
  541. ~WorkItem() override = default;
  542. bool AddAdditionalHostsTo(DnsHosts& in_out_dns_hosts) override {
  543. base::ScopedBlockingCall scoped_blocking_call(
  544. FROM_HERE, base::BlockingType::MAY_BLOCK);
  545. return AddLocalhostEntriesTo(in_out_dns_hosts);
  546. }
  547. };
  548. };
  549. DnsConfigServiceWin::DnsConfigServiceWin()
  550. : DnsConfigService(GetHostsPath().value(),
  551. absl::nullopt /* config_change_delay */) {
  552. // Allow constructing on one sequence and living on another.
  553. DETACH_FROM_SEQUENCE(sequence_checker_);
  554. }
  555. DnsConfigServiceWin::~DnsConfigServiceWin() {
  556. if (config_reader_)
  557. config_reader_->Cancel();
  558. if (hosts_reader_)
  559. hosts_reader_->Cancel();
  560. }
  561. void DnsConfigServiceWin::ReadConfigNow() {
  562. if (!config_reader_)
  563. config_reader_ = std::make_unique<ConfigReader>(*this);
  564. config_reader_->WorkNow();
  565. }
  566. void DnsConfigServiceWin::ReadHostsNow() {
  567. if (!hosts_reader_)
  568. hosts_reader_ = std::make_unique<HostsReader>(*this);
  569. hosts_reader_->WorkNow();
  570. }
  571. bool DnsConfigServiceWin::StartWatching() {
  572. DCHECK(!watcher_);
  573. // TODO(szym): re-start watcher if that makes sense. http://crbug.com/116139
  574. watcher_ = std::make_unique<Watcher>(*this);
  575. return watcher_->Watch();
  576. }
  577. } // namespace internal
  578. // static
  579. std::unique_ptr<DnsConfigService> DnsConfigService::CreateSystemService() {
  580. return std::make_unique<internal::DnsConfigServiceWin>();
  581. }
  582. } // namespace net