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 "base/compiler_specific.h"
15 #include "base/functional/bind.h"
16 #include "base/location.h"
17 #include "base/logging.h"
18 #include "base/memory/free_deleter.h"
19 #include "base/sequence_checker.h"
20 #include "base/strings/string_piece.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/win/registry.h"
27 #include "base/win/scoped_handle.h"
28 #include "base/win/windows_types.h"
29 #include "net/base/ip_address.h"
30 #include "net/base/ip_endpoint.h"
31 #include "net/dns/public/dns_protocol.h"
32 #include "third_party/abseil-cpp/absl/types/optional.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 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[],absl::optional<std::wstring> * output) const75 bool ReadString(const wchar_t name[],
76 absl::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 = absl::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 = absl::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[],absl::optional<DWORD> * output) const99 bool ReadDword(const wchar_t name[], absl::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 = absl::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 = absl::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 absl::optional<DWORD> enabled;
159 absl::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(absl::optional<DWORD> enabled,absl::optional<DWORD> level)175 WinDnsSystemSettings::DevolutionSetting::DevolutionSetting(
176 absl::optional<DWORD> enabled,
177 absl::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 absl::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 absl::nullopt;
219 }
220 }
221 }
222 return nameservers;
223 }
224
ReadWinSystemDnsSettings()225 absl::optional<WinDnsSystemSettings> ReadWinSystemDnsSettings() {
226 base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
227 base::BlockingType::MAY_BLOCK);
228 WinDnsSystemSettings settings;
229
230 // Filled in by GetAdapterAddresses. Note that the alternative
231 // GetNetworkParams does not include IPv6 addresses.
232 settings.addresses = ReadAdapterDnsAddresses();
233 if (!settings.addresses.get())
234 return absl::nullopt;
235
236 RegistryReader tcpip_reader(kTcpipPath);
237 RegistryReader tcpip6_reader(kTcpip6Path);
238 RegistryReader dnscache_reader(kDnscachePath);
239 RegistryReader policy_reader(kPolicyPath);
240 RegistryReader primary_dns_suffix_reader(kPrimaryDnsSuffixPath);
241
242 absl::optional<std::wstring> reg_string;
243 if (!policy_reader.ReadString(L"SearchList", ®_string))
244 return absl::nullopt;
245 settings.policy_search_list = std::move(reg_string);
246
247 if (!tcpip_reader.ReadString(L"SearchList", ®_string))
248 return absl::nullopt;
249 settings.tcpip_search_list = std::move(reg_string);
250
251 if (!tcpip_reader.ReadString(L"Domain", ®_string))
252 return absl::nullopt;
253 settings.tcpip_domain = std::move(reg_string);
254
255 WinDnsSystemSettings::DevolutionSetting devolution_setting;
256 if (!ReadDevolutionSetting(policy_reader, &devolution_setting))
257 return absl::nullopt;
258 settings.policy_devolution = devolution_setting;
259
260 if (!ReadDevolutionSetting(dnscache_reader, &devolution_setting))
261 return absl::nullopt;
262 settings.dnscache_devolution = devolution_setting;
263
264 if (!ReadDevolutionSetting(tcpip_reader, &devolution_setting))
265 return absl::nullopt;
266 settings.tcpip_devolution = devolution_setting;
267
268 absl::optional<DWORD> reg_dword;
269 if (!policy_reader.ReadDword(L"AppendToMultiLabelName", ®_dword))
270 return absl::nullopt;
271 settings.append_to_multi_label_name = reg_dword;
272
273 if (!primary_dns_suffix_reader.ReadString(L"PrimaryDnsSuffix", ®_string))
274 return absl::nullopt;
275 settings.primary_dns_suffix = std::move(reg_string);
276
277 base::win::RegistryKeyIterator nrpt_rules(HKEY_LOCAL_MACHINE, kNrptPath);
278 base::win::RegistryKeyIterator cs_nrpt_rules(HKEY_LOCAL_MACHINE,
279 kControlSetNrptPath);
280 settings.have_name_resolution_policy =
281 (nrpt_rules.SubkeyCount() > 0 || cs_nrpt_rules.SubkeyCount() > 0);
282
283 base::win::RegistryKeyIterator dns_connections(HKEY_LOCAL_MACHINE,
284 kDnsConnectionsPath);
285 base::win::RegistryKeyIterator dns_connections_proxies(
286 HKEY_LOCAL_MACHINE, kDnsConnectionsProxies);
287 settings.have_proxy = (dns_connections.SubkeyCount() > 0 ||
288 dns_connections_proxies.SubkeyCount() > 0);
289
290 return settings;
291 }
292
293 } // namespace net
294