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, ®_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, ®_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", ®_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", ®_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", ®_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", ®_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", ®_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