• 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 <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, &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 = 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, &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 = 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", &reg_string))
244     return absl::nullopt;
245   settings.policy_search_list = std::move(reg_string);
246 
247   if (!tcpip_reader.ReadString(L"SearchList", &reg_string))
248     return absl::nullopt;
249   settings.tcpip_search_list = std::move(reg_string);
250 
251   if (!tcpip_reader.ReadString(L"Domain", &reg_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", &reg_dword))
270     return absl::nullopt;
271   settings.append_to_multi_label_name = reg_dword;
272 
273   if (!primary_dns_suffix_reader.ReadString(L"PrimaryDnsSuffix", &reg_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