• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 The Chromium Authors
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/public/win_dns_system_settings.h"
6 
7 #include <sysinfoapi.h>
8 
9 #include <algorithm>
10 #include <memory>
11 #include <optional>
12 #include <string>
13 #include <vector>
14 
15 #include "base/compiler_specific.h"
16 #include "base/functional/bind.h"
17 #include "base/location.h"
18 #include "base/logging.h"
19 #include "base/memory/free_deleter.h"
20 #include "base/sequence_checker.h"
21 #include "base/strings/string_split.h"
22 #include "base/strings/string_util.h"
23 #include "base/strings/utf_string_conversions.h"
24 #include "base/task/single_thread_task_runner.h"
25 #include "base/threading/scoped_blocking_call.h"
26 #include "base/types/expected.h"
27 #include "base/win/registry.h"
28 #include "base/win/scoped_handle.h"
29 #include "base/win/windows_types.h"
30 #include "net/base/ip_address.h"
31 #include "net/base/ip_endpoint.h"
32 #include "net/dns/public/dns_protocol.h"
33 
34 namespace net {
35 
36 namespace {
37 
38 // Registry key paths.
39 const wchar_t kTcpipPath[] =
40     L"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters";
41 const wchar_t kTcpip6Path[] =
42     L"SYSTEM\\CurrentControlSet\\Services\\Tcpip6\\Parameters";
43 const wchar_t kDnscachePath[] =
44     L"SYSTEM\\CurrentControlSet\\Services\\Dnscache\\Parameters";
45 const wchar_t kPolicyPath[] =
46     L"SOFTWARE\\Policies\\Microsoft\\Windows NT\\DNSClient";
47 const wchar_t kPrimaryDnsSuffixPath[] =
48     L"SOFTWARE\\Policies\\Microsoft\\System\\DNSClient";
49 const wchar_t kNrptPath[] =
50     L"SOFTWARE\\Policies\\Microsoft\\Windows NT\\DNSClient\\DnsPolicyConfig";
51 const wchar_t kControlSetNrptPath[] =
52     L"SYSTEM\\CurrentControlSet\\Services\\Dnscache\\Parameters\\"
53     L"DnsPolicyConfig";
54 const wchar_t kDnsConnectionsPath[] =
55     L"SYSTEM\\CurrentControlSet\\Services\\Dnscache\\Parameters\\"
56     L"DnsConnections";
57 const wchar_t kDnsConnectionsProxies[] =
58     L"SYSTEM\\CurrentControlSet\\Services\\Dnscache\\Parameters\\"
59     L"DnsConnectionsProxies";
60 
61 // Convenience for reading values using RegKey.
62 class RegistryReader {
63  public:
RegistryReader(const wchar_t key[])64   explicit RegistryReader(const wchar_t key[]) {
65     // Ignoring the result. |key_.Valid()| will catch failures.
66     (void)key_.Open(HKEY_LOCAL_MACHINE, key, KEY_QUERY_VALUE);
67   }
68 
69   RegistryReader(const RegistryReader&) = delete;
70   RegistryReader& operator=(const RegistryReader&) = delete;
71 
~RegistryReader()72   ~RegistryReader() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); }
73 
74   // Returns `false` if any error occurs, but not if the value is unset.
ReadString(const wchar_t name[],std::optional<std::wstring> * output) const75   bool ReadString(const wchar_t name[],
76                   std::optional<std::wstring>* output) const {
77     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
78     std::wstring reg_string;
79     if (!key_.Valid()) {
80       // Assume that if the |key_| is invalid then the key is missing.
81       *output = std::nullopt;
82       return true;
83     }
84     LONG result = key_.ReadValue(name, &reg_string);
85     if (result == ERROR_SUCCESS) {
86       *output = std::move(reg_string);
87       return true;
88     }
89 
90     if (result == ERROR_FILE_NOT_FOUND) {
91       *output = std::nullopt;
92       return true;
93     }
94 
95     return false;
96   }
97 
98   // Returns `false` if any error occurs, but not if the value is unset.
ReadDword(const wchar_t name[],std::optional<DWORD> * output) const99   bool ReadDword(const wchar_t name[], std::optional<DWORD>* output) const {
100     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
101 
102     DWORD reg_dword;
103     if (!key_.Valid()) {
104       // Assume that if the |key_| is invalid then the key is missing.
105       *output = std::nullopt;
106       return true;
107     }
108 
109     LONG result = key_.ReadValueDW(name, &reg_dword);
110     if (result == ERROR_SUCCESS) {
111       *output = reg_dword;
112       return true;
113     }
114 
115     if (result == ERROR_FILE_NOT_FOUND) {
116       *output = std::nullopt;
117       return true;
118     }
119 
120     return false;
121   }
122 
123  private:
124   base::win::RegKey key_;
125 
126   SEQUENCE_CHECKER(sequence_checker_);
127 };
128 
129 // Wrapper for GetAdaptersAddresses to get DNS addresses.
130 // Returns nullptr if failed.
131 std::unique_ptr<IP_ADAPTER_ADDRESSES, base::FreeDeleter>
ReadAdapterDnsAddresses()132 ReadAdapterDnsAddresses() {
133   base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
134                                                 base::BlockingType::MAY_BLOCK);
135 
136   std::unique_ptr<IP_ADAPTER_ADDRESSES, base::FreeDeleter> out;
137   ULONG len = 15000;  // As recommended by MSDN for GetAdaptersAddresses.
138   UINT rv = ERROR_BUFFER_OVERFLOW;
139   // Try up to three times.
140   for (unsigned tries = 0; (tries < 3) && (rv == ERROR_BUFFER_OVERFLOW);
141        tries++) {
142     out.reset(static_cast<PIP_ADAPTER_ADDRESSES>(malloc(len)));
143     memset(out.get(), 0, len);
144     rv = GetAdaptersAddresses(AF_UNSPEC,
145                               GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_UNICAST |
146                               GAA_FLAG_SKIP_MULTICAST |
147                               GAA_FLAG_SKIP_FRIENDLY_NAME,
148                               nullptr, out.get(), &len);
149   }
150   if (rv != NO_ERROR)
151     out.reset();
152   return out;
153 }
154 
155 // Returns `false` if any error occurs, but not if the value is unset.
ReadDevolutionSetting(const RegistryReader & reader,WinDnsSystemSettings::DevolutionSetting * output)156 bool ReadDevolutionSetting(const RegistryReader& reader,
157                            WinDnsSystemSettings::DevolutionSetting* output) {
158   std::optional<DWORD> enabled;
159   std::optional<DWORD> level;
160   if (!reader.ReadDword(L"UseDomainNameDevolution", &enabled) ||
161       !reader.ReadDword(L"DomainNameDevolutionLevel", &level)) {
162     return false;
163   }
164 
165   *output = {enabled, level};
166   return true;
167 }
168 
169 }  // namespace
170 
171 WinDnsSystemSettings::WinDnsSystemSettings() = default;
172 WinDnsSystemSettings::~WinDnsSystemSettings() = default;
173 
174 WinDnsSystemSettings::DevolutionSetting::DevolutionSetting() = default;
DevolutionSetting(std::optional<DWORD> enabled,std::optional<DWORD> level)175 WinDnsSystemSettings::DevolutionSetting::DevolutionSetting(
176     std::optional<DWORD> enabled,
177     std::optional<DWORD> level)
178     : enabled(enabled), level(level) {}
179 WinDnsSystemSettings::DevolutionSetting::DevolutionSetting(
180     const DevolutionSetting&) = default;
181 WinDnsSystemSettings::DevolutionSetting&
182 WinDnsSystemSettings::DevolutionSetting::operator=(
183     const WinDnsSystemSettings::DevolutionSetting&) = default;
184 WinDnsSystemSettings::DevolutionSetting::~DevolutionSetting() = default;
185 
186 WinDnsSystemSettings::WinDnsSystemSettings(WinDnsSystemSettings&&) = default;
187 WinDnsSystemSettings& WinDnsSystemSettings::operator=(WinDnsSystemSettings&&) =
188     default;
189 
190 // static
IsStatelessDiscoveryAddress(const IPAddress & address)191 bool WinDnsSystemSettings::IsStatelessDiscoveryAddress(
192     const IPAddress& address) {
193   if (!address.IsIPv6())
194     return false;
195   const uint8_t kPrefix[] = {0xfe, 0xc0, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
196                              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
197   return IPAddressStartsWith(address, kPrefix) && (address.bytes().back() < 4);
198 }
199 
200 std::optional<std::vector<IPEndPoint>>
GetAllNameservers()201 WinDnsSystemSettings::GetAllNameservers() {
202   std::vector<IPEndPoint> nameservers;
203   for (const IP_ADAPTER_ADDRESSES* adapter = addresses.get();
204        adapter != nullptr; adapter = adapter->Next) {
205     for (const IP_ADAPTER_DNS_SERVER_ADDRESS* address =
206              adapter->FirstDnsServerAddress;
207          address != nullptr; address = address->Next) {
208       IPEndPoint ipe;
209       if (ipe.FromSockAddr(address->Address.lpSockaddr,
210                            address->Address.iSockaddrLength)) {
211         if (IsStatelessDiscoveryAddress(ipe.address()))
212           continue;
213         // Override unset port.
214         if (!ipe.port())
215           ipe = IPEndPoint(ipe.address(), dns_protocol::kDefaultPort);
216         nameservers.push_back(ipe);
217       } else {
218         return std::nullopt;
219       }
220     }
221   }
222   return nameservers;
223 }
224 
225 base::expected<WinDnsSystemSettings, ReadWinSystemDnsSettingsError>
ReadWinSystemDnsSettings()226 ReadWinSystemDnsSettings() {
227   base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
228                                                 base::BlockingType::MAY_BLOCK);
229   WinDnsSystemSettings settings;
230 
231   // Filled in by GetAdapterAddresses. Note that the alternative
232   // GetNetworkParams does not include IPv6 addresses.
233   settings.addresses = ReadAdapterDnsAddresses();
234   if (!settings.addresses.get()) {
235     return base::unexpected(
236         ReadWinSystemDnsSettingsError::kReadAdapterDnsAddressesFailed);
237   }
238 
239   RegistryReader tcpip_reader(kTcpipPath);
240   RegistryReader tcpip6_reader(kTcpip6Path);
241   RegistryReader dnscache_reader(kDnscachePath);
242   RegistryReader policy_reader(kPolicyPath);
243   RegistryReader primary_dns_suffix_reader(kPrimaryDnsSuffixPath);
244 
245   std::optional<std::wstring> reg_string;
246   if (!policy_reader.ReadString(L"SearchList", &reg_string)) {
247     return base::unexpected(
248         ReadWinSystemDnsSettingsError::kReadPolicySearchListFailed);
249   }
250   settings.policy_search_list = std::move(reg_string);
251 
252   if (!tcpip_reader.ReadString(L"SearchList", &reg_string)) {
253     return base::unexpected(
254         ReadWinSystemDnsSettingsError::kReadTcpipSearchListFailed);
255   }
256   settings.tcpip_search_list = std::move(reg_string);
257 
258   if (!tcpip_reader.ReadString(L"Domain", &reg_string)) {
259     return base::unexpected(
260         ReadWinSystemDnsSettingsError::kReadTcpipDomainFailed);
261   }
262   settings.tcpip_domain = std::move(reg_string);
263 
264   WinDnsSystemSettings::DevolutionSetting devolution_setting;
265   if (!ReadDevolutionSetting(policy_reader, &devolution_setting)) {
266     return base::unexpected(
267         ReadWinSystemDnsSettingsError::kReadPolicyDevolutionSettingFailed);
268   }
269   settings.policy_devolution = devolution_setting;
270 
271   if (!ReadDevolutionSetting(dnscache_reader, &devolution_setting)) {
272     return base::unexpected(
273         ReadWinSystemDnsSettingsError::kReadDnscacheDevolutionSettingFailed);
274   }
275   settings.dnscache_devolution = devolution_setting;
276 
277   if (!ReadDevolutionSetting(tcpip_reader, &devolution_setting)) {
278     return base::unexpected(
279         ReadWinSystemDnsSettingsError::kReadTcpipDevolutionSettingFailed);
280   }
281   settings.tcpip_devolution = devolution_setting;
282 
283   std::optional<DWORD> reg_dword;
284   if (!policy_reader.ReadDword(L"AppendToMultiLabelName", &reg_dword)) {
285     return base::unexpected(
286         ReadWinSystemDnsSettingsError::kReadPolicyAppendToMultiLabelNameFailed);
287   }
288   settings.append_to_multi_label_name = reg_dword;
289 
290   if (!primary_dns_suffix_reader.ReadString(L"PrimaryDnsSuffix", &reg_string)) {
291     return base::unexpected(
292         ReadWinSystemDnsSettingsError::kReadPrimaryDnsSuffixPathFailed);
293   }
294   settings.primary_dns_suffix = std::move(reg_string);
295 
296   base::win::RegistryKeyIterator nrpt_rules(HKEY_LOCAL_MACHINE, kNrptPath);
297   base::win::RegistryKeyIterator cs_nrpt_rules(HKEY_LOCAL_MACHINE,
298                                                kControlSetNrptPath);
299   settings.have_name_resolution_policy =
300       (nrpt_rules.SubkeyCount() > 0 || cs_nrpt_rules.SubkeyCount() > 0);
301 
302   base::win::RegistryKeyIterator dns_connections(HKEY_LOCAL_MACHINE,
303                                                  kDnsConnectionsPath);
304   base::win::RegistryKeyIterator dns_connections_proxies(
305       HKEY_LOCAL_MACHINE, kDnsConnectionsProxies);
306   settings.have_proxy = (dns_connections.SubkeyCount() > 0 ||
307                          dns_connections_proxies.SubkeyCount() > 0);
308 
309   return settings;
310 }
311 
312 }  // namespace net
313