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