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 #ifdef UNSAFE_BUFFERS_BUILD
6 // TODO(crbug.com/40284755): Remove this and spanify to fix the errors.
7 #pragma allow_unsafe_buffers
8 #endif
9
10 #include "net/dns/dns_config_service_win.h"
11
12 #include <optional>
13 #include <string>
14 #include <vector>
15
16 #include "base/check.h"
17 #include "base/memory/free_deleter.h"
18 #include "base/test/gmock_expected_support.h"
19 #include "net/base/ip_address.h"
20 #include "net/base/ip_endpoint.h"
21 #include "net/dns/public/dns_protocol.h"
22 #include "net/dns/public/win_dns_system_settings.h"
23 #include "testing/gmock/include/gmock/gmock.h"
24 #include "testing/gtest/include/gtest/gtest.h"
25
26 namespace net {
27
28 namespace {
29
TEST(DnsConfigServiceWinTest,ParseSearchList)30 TEST(DnsConfigServiceWinTest, ParseSearchList) {
31 const struct TestCase {
32 const wchar_t* input;
33 std::vector<std::string> expected;
34 } cases[] = {
35 {L"chromium.org", {"chromium.org"}},
36 {L"chromium.org,org", {"chromium.org", "org"}},
37 // Empty suffixes terminate the list
38 {L"crbug.com,com,,org", {"crbug.com", "com"}},
39 // IDN are converted to punycode
40 {L"\u017c\xf3\u0142ta.pi\u0119\u015b\u0107.pl,pl",
41 {"xn--ta-4ja03asj.xn--pi-wla5e0q.pl", "pl"}},
42 // Empty search list is invalid
43 {L"", {}},
44 {L",,", {}},
45 };
46
47 for (const auto& t : cases) {
48 EXPECT_EQ(internal::ParseSearchList(t.input), t.expected);
49 }
50 }
51
52 struct AdapterInfo {
53 IFTYPE if_type;
54 IF_OPER_STATUS oper_status;
55 const WCHAR* dns_suffix;
56 std::string dns_server_addresses[4]; // Empty string indicates end.
57 uint16_t ports[4];
58 };
59
CreateAdapterAddresses(const AdapterInfo * infos)60 std::unique_ptr<IP_ADAPTER_ADDRESSES, base::FreeDeleter> CreateAdapterAddresses(
61 const AdapterInfo* infos) {
62 size_t num_adapters = 0;
63 size_t num_addresses = 0;
64 for (size_t i = 0; infos[i].if_type; ++i) {
65 ++num_adapters;
66 for (size_t j = 0; !infos[i].dns_server_addresses[j].empty(); ++j) {
67 ++num_addresses;
68 }
69 }
70
71 size_t heap_size = num_adapters * sizeof(IP_ADAPTER_ADDRESSES) +
72 num_addresses * (sizeof(IP_ADAPTER_DNS_SERVER_ADDRESS) +
73 sizeof(struct sockaddr_storage));
74 std::unique_ptr<IP_ADAPTER_ADDRESSES, base::FreeDeleter> heap(
75 static_cast<IP_ADAPTER_ADDRESSES*>(malloc(heap_size)));
76 CHECK(heap.get());
77 memset(heap.get(), 0, heap_size);
78
79 IP_ADAPTER_ADDRESSES* adapters = heap.get();
80 IP_ADAPTER_DNS_SERVER_ADDRESS* addresses =
81 reinterpret_cast<IP_ADAPTER_DNS_SERVER_ADDRESS*>(adapters + num_adapters);
82 struct sockaddr_storage* storage =
83 reinterpret_cast<struct sockaddr_storage*>(addresses + num_addresses);
84
85 for (size_t i = 0; i < num_adapters; ++i) {
86 const AdapterInfo& info = infos[i];
87 IP_ADAPTER_ADDRESSES* adapter = adapters + i;
88 if (i + 1 < num_adapters)
89 adapter->Next = adapter + 1;
90 adapter->IfType = info.if_type;
91 adapter->OperStatus = info.oper_status;
92 adapter->DnsSuffix = const_cast<PWCHAR>(info.dns_suffix);
93 IP_ADAPTER_DNS_SERVER_ADDRESS* address = nullptr;
94 for (size_t j = 0; !info.dns_server_addresses[j].empty(); ++j) {
95 --num_addresses;
96 if (j == 0) {
97 address = adapter->FirstDnsServerAddress = addresses + num_addresses;
98 } else {
99 // Note that |address| is moving backwards.
100 address = address->Next = address - 1;
101 }
102 IPAddress ip;
103 CHECK(ip.AssignFromIPLiteral(info.dns_server_addresses[j]));
104 IPEndPoint ipe = IPEndPoint(ip, info.ports[j]);
105 address->Address.lpSockaddr =
106 reinterpret_cast<LPSOCKADDR>(storage + num_addresses);
107 socklen_t length = sizeof(struct sockaddr_storage);
108 CHECK(ipe.ToSockAddr(address->Address.lpSockaddr, &length));
109 address->Address.iSockaddrLength = static_cast<int>(length);
110 }
111 }
112
113 return heap;
114 }
115
TEST(DnsConfigServiceWinTest,ConvertAdapterAddresses)116 TEST(DnsConfigServiceWinTest, ConvertAdapterAddresses) {
117 // Check nameservers and connection-specific suffix.
118 const struct TestCase {
119 AdapterInfo input_adapters[4]; // |if_type| == 0 indicates end.
120 std::string expected_nameservers[4]; // Empty string indicates end.
121 std::string expected_suffix;
122 uint16_t expected_ports[4];
123 } cases[] = {
124 { // Ignore loopback and inactive adapters.
125 {
126 { IF_TYPE_SOFTWARE_LOOPBACK, IfOperStatusUp, L"funnyloop",
127 { "2.0.0.2" } },
128 { IF_TYPE_FASTETHER, IfOperStatusDormant, L"example.com",
129 { "1.0.0.1" } },
130 { IF_TYPE_USB, IfOperStatusUp, L"chromium.org",
131 { "10.0.0.10", "2001:FFFF::1111" } },
132 { 0 },
133 },
134 { "10.0.0.10", "2001:FFFF::1111" },
135 "chromium.org",
136 },
137 { // Respect configured ports.
138 {
139 { IF_TYPE_USB, IfOperStatusUp, L"chromium.org",
140 { "10.0.0.10", "2001:FFFF::1111" }, { 1024, 24 } },
141 { 0 },
142 },
143 { "10.0.0.10", "2001:FFFF::1111" },
144 "chromium.org",
145 { 1024, 24 },
146 },
147 { // Use the preferred adapter (first in binding order) and filter
148 // stateless DNS discovery addresses.
149 {
150 { IF_TYPE_SOFTWARE_LOOPBACK, IfOperStatusUp, L"funnyloop",
151 { "2.0.0.2" } },
152 { IF_TYPE_FASTETHER, IfOperStatusUp, L"example.com",
153 { "1.0.0.1", "fec0:0:0:ffff::2", "8.8.8.8" } },
154 { IF_TYPE_USB, IfOperStatusUp, L"chromium.org",
155 { "10.0.0.10", "2001:FFFF::1111" } },
156 { 0 },
157 },
158 { "1.0.0.1", "8.8.8.8" },
159 "example.com",
160 },
161 { // No usable adapters.
162 {
163 { IF_TYPE_SOFTWARE_LOOPBACK, IfOperStatusUp, L"localhost",
164 { "2.0.0.2" } },
165 { IF_TYPE_FASTETHER, IfOperStatusDormant, L"example.com",
166 { "1.0.0.1" } },
167 { IF_TYPE_USB, IfOperStatusUp, L"chromium.org" },
168 { 0 },
169 },
170 },
171 };
172
173 for (const auto& t : cases) {
174 WinDnsSystemSettings settings;
175 settings.addresses = CreateAdapterAddresses(t.input_adapters);
176 // Default settings for the rest.
177 std::vector<IPEndPoint> expected_nameservers;
178 for (size_t j = 0; !t.expected_nameservers[j].empty(); ++j) {
179 IPAddress ip;
180 ASSERT_TRUE(ip.AssignFromIPLiteral(t.expected_nameservers[j]));
181 uint16_t port = t.expected_ports[j];
182 if (!port)
183 port = dns_protocol::kDefaultPort;
184 expected_nameservers.push_back(IPEndPoint(ip, port));
185 }
186
187 base::expected<DnsConfig, ReadWinSystemDnsSettingsError> config_or_error =
188 internal::ConvertSettingsToDnsConfig(std::move(settings));
189 bool expected_success = !expected_nameservers.empty();
190 EXPECT_EQ(expected_success, config_or_error.has_value());
191 if (config_or_error.has_value()) {
192 EXPECT_EQ(expected_nameservers, config_or_error->nameservers);
193 EXPECT_THAT(config_or_error->search,
194 testing::ElementsAre(t.expected_suffix));
195 }
196 }
197 }
198
TEST(DnsConfigServiceWinTest,ConvertSuffixSearch)199 TEST(DnsConfigServiceWinTest, ConvertSuffixSearch) {
200 AdapterInfo infos[2] = {
201 { IF_TYPE_USB, IfOperStatusUp, L"connection.suffix", { "1.0.0.1" } },
202 { 0 },
203 };
204
205 const struct TestCase {
206 struct {
207 std::optional<std::wstring> policy_search_list;
208 std::optional<std::wstring> tcpip_search_list;
209 std::optional<std::wstring> tcpip_domain;
210 std::optional<std::wstring> primary_dns_suffix;
211 WinDnsSystemSettings::DevolutionSetting policy_devolution;
212 WinDnsSystemSettings::DevolutionSetting dnscache_devolution;
213 WinDnsSystemSettings::DevolutionSetting tcpip_devolution;
214 } input_settings;
215 std::vector<std::string> expected_search;
216 } cases[] = {
217 {
218 // Policy SearchList override.
219 {
220 L"policy.searchlist.a,policy.searchlist.b",
221 L"tcpip.searchlist.a,tcpip.searchlist.b",
222 L"tcpip.domain",
223 L"primary.dns.suffix",
224 },
225 {"policy.searchlist.a", "policy.searchlist.b"},
226 },
227 {
228 // User-specified SearchList override.
229 {
230 std::nullopt,
231 L"tcpip.searchlist.a,tcpip.searchlist.b",
232 L"tcpip.domain",
233 L"primary.dns.suffix",
234 },
235 {"tcpip.searchlist.a", "tcpip.searchlist.b"},
236 },
237 {
238 // Void SearchList. Using tcpip.domain
239 {
240 L",bad.searchlist,parsed.as.empty",
241 L"tcpip.searchlist,good.but.overridden",
242 L"tcpip.domain",
243 std::nullopt,
244 },
245 {"tcpip.domain", "connection.suffix"},
246 },
247 {
248 // Void SearchList. Using primary.dns.suffix
249 {
250 L",bad.searchlist,parsed.as.empty",
251 L"tcpip.searchlist,good.but.overridden",
252 L"tcpip.domain",
253 L"primary.dns.suffix",
254 },
255 {"primary.dns.suffix", "connection.suffix"},
256 },
257 {
258 // Void SearchList. Using tcpip.domain when primary.dns.suffix is
259 // empty
260 {
261 L",bad.searchlist,parsed.as.empty",
262 L"tcpip.searchlist,good.but.overridden",
263 L"tcpip.domain",
264 L"",
265 },
266 {"tcpip.domain", "connection.suffix"},
267 },
268 {
269 // Void SearchList. Using tcpip.domain when primary.dns.suffix is NULL
270 {
271 L",bad.searchlist,parsed.as.empty",
272 L"tcpip.searchlist,good.but.overridden",
273 L"tcpip.domain",
274 L"",
275 },
276 {"tcpip.domain", "connection.suffix"},
277 },
278 {
279 // No primary suffix. Devolution does not matter.
280 {
281 std::nullopt,
282 std::nullopt,
283 L"",
284 L"",
285 {1, 2},
286 },
287 {"connection.suffix"},
288 },
289 {
290 // Devolution enabled by policy, level by dnscache.
291 {
292 std::nullopt,
293 std::nullopt,
294 L"a.b.c.d.e",
295 std::nullopt,
296 {1, std::nullopt}, // policy_devolution: enabled, level
297 {0, 3}, // dnscache_devolution
298 {0, 1}, // tcpip_devolution
299 },
300 {"a.b.c.d.e", "connection.suffix", "b.c.d.e", "c.d.e"},
301 },
302 {
303 // Devolution enabled by dnscache, level by policy.
304 {
305 std::nullopt,
306 std::nullopt,
307 L"a.b.c.d.e",
308 L"f.g.i.l.j",
309 {std::nullopt, 4},
310 {1, std::nullopt},
311 {0, 3},
312 },
313 {"f.g.i.l.j", "connection.suffix", "g.i.l.j"},
314 },
315 {
316 // Devolution enabled by default.
317 {
318 std::nullopt,
319 std::nullopt,
320 L"a.b.c.d.e",
321 std::nullopt,
322 {std::nullopt, std::nullopt},
323 {std::nullopt, 3},
324 {std::nullopt, 1},
325 },
326 {"a.b.c.d.e", "connection.suffix", "b.c.d.e", "c.d.e"},
327 },
328 {
329 // Devolution enabled at level = 2, but nothing to devolve.
330 {
331 std::nullopt,
332 std::nullopt,
333 L"a.b",
334 std::nullopt,
335 {std::nullopt, std::nullopt},
336 {std::nullopt, 2},
337 {std::nullopt, 2},
338 },
339 {"a.b", "connection.suffix"},
340 },
341 {
342 // Devolution disabled when no explicit level.
343 {
344 std::nullopt,
345 std::nullopt,
346 L"a.b.c.d.e",
347 std::nullopt,
348 {1, std::nullopt},
349 {1, std::nullopt},
350 {1, std::nullopt},
351 },
352 {"a.b.c.d.e", "connection.suffix"},
353 },
354 {
355 // Devolution disabled by policy level.
356 {
357 std::nullopt,
358 std::nullopt,
359 L"a.b.c.d.e",
360 std::nullopt,
361 {std::nullopt, 1},
362 {1, 3},
363 {1, 4},
364 },
365 {"a.b.c.d.e", "connection.suffix"},
366 },
367 {
368 // Devolution disabled by user setting.
369 {
370 std::nullopt,
371 std::nullopt,
372 L"a.b.c.d.e",
373 std::nullopt,
374 {std::nullopt, 3},
375 {std::nullopt, 3},
376 {0, 3},
377 },
378 {"a.b.c.d.e", "connection.suffix"},
379 },
380 };
381
382 for (auto& t : cases) {
383 WinDnsSystemSettings settings;
384 settings.addresses = CreateAdapterAddresses(infos);
385 settings.policy_search_list = t.input_settings.policy_search_list;
386 settings.tcpip_search_list = t.input_settings.tcpip_search_list;
387 settings.tcpip_domain = t.input_settings.tcpip_domain;
388 settings.primary_dns_suffix = t.input_settings.primary_dns_suffix;
389 settings.policy_devolution = t.input_settings.policy_devolution;
390 settings.dnscache_devolution = t.input_settings.dnscache_devolution;
391 settings.tcpip_devolution = t.input_settings.tcpip_devolution;
392
393 ASSERT_OK_AND_ASSIGN(
394 DnsConfig dns_config,
395 internal::ConvertSettingsToDnsConfig(std::move(settings)));
396 EXPECT_THAT(dns_config,
397 testing::Field(&DnsConfig::search,
398 testing::ElementsAreArray(t.expected_search)));
399 }
400 }
401
TEST(DnsConfigServiceWinTest,AppendToMultiLabelName)402 TEST(DnsConfigServiceWinTest, AppendToMultiLabelName) {
403 AdapterInfo infos[2] = {
404 { IF_TYPE_USB, IfOperStatusUp, L"connection.suffix", { "1.0.0.1" } },
405 { 0 },
406 };
407
408 const struct TestCase {
409 std::optional<DWORD> input;
410 bool expected_output;
411 } cases[] = {
412 {0, false},
413 {1, true},
414 {std::nullopt, false},
415 };
416
417 for (const auto& t : cases) {
418 WinDnsSystemSettings settings;
419 settings.addresses = CreateAdapterAddresses(infos);
420 settings.append_to_multi_label_name = t.input;
421 ASSERT_OK_AND_ASSIGN(
422 DnsConfig dns_config,
423 internal::ConvertSettingsToDnsConfig(std::move(settings)));
424 EXPECT_THAT(dns_config,
425 testing::Field(&DnsConfig::append_to_multi_label_name,
426 testing::Eq(t.expected_output)));
427 }
428 }
429
430 // Setting have_name_resolution_policy_table should set `unhandled_options`.
TEST(DnsConfigServiceWinTest,HaveNRPT)431 TEST(DnsConfigServiceWinTest, HaveNRPT) {
432 AdapterInfo infos[2] = {
433 { IF_TYPE_USB, IfOperStatusUp, L"connection.suffix", { "1.0.0.1" } },
434 { 0 },
435 };
436
437 const struct TestCase {
438 bool have_nrpt;
439 bool unhandled_options;
440 } cases[] = {
441 {false, false},
442 {true, true},
443 };
444
445 for (const auto& t : cases) {
446 WinDnsSystemSettings settings;
447 settings.addresses = CreateAdapterAddresses(infos);
448 settings.have_name_resolution_policy = t.have_nrpt;
449 ASSERT_OK_AND_ASSIGN(
450 DnsConfig dns_config,
451 internal::ConvertSettingsToDnsConfig(std::move(settings)));
452 EXPECT_EQ(t.unhandled_options, dns_config.unhandled_options);
453 EXPECT_EQ(t.have_nrpt, dns_config.use_local_ipv6);
454 }
455 }
456
457 // Setting have_proxy should set `unhandled_options`.
TEST(DnsConfigServiceWinTest,HaveProxy)458 TEST(DnsConfigServiceWinTest, HaveProxy) {
459 AdapterInfo infos[2] = {
460 {IF_TYPE_USB, IfOperStatusUp, L"connection.suffix", {"1.0.0.1"}},
461 {0},
462 };
463
464 const struct TestCase {
465 bool have_proxy;
466 bool unhandled_options;
467 } cases[] = {
468 {false, false},
469 {true, true},
470 };
471
472 for (const auto& t : cases) {
473 WinDnsSystemSettings settings;
474 settings.addresses = CreateAdapterAddresses(infos);
475 settings.have_proxy = t.have_proxy;
476 ASSERT_OK_AND_ASSIGN(
477 DnsConfig dns_config,
478 internal::ConvertSettingsToDnsConfig(std::move(settings)));
479 EXPECT_THAT(dns_config, testing::Field(&DnsConfig::unhandled_options,
480 testing::Eq(t.unhandled_options)));
481 }
482 }
483
484 // Setting uses_vpn should set `unhandled_options`.
TEST(DnsConfigServiceWinTest,UsesVpn)485 TEST(DnsConfigServiceWinTest, UsesVpn) {
486 AdapterInfo infos[3] = {
487 {IF_TYPE_USB, IfOperStatusUp, L"connection.suffix", {"1.0.0.1"}},
488 {IF_TYPE_PPP, IfOperStatusUp, L"connection.suffix", {"1.0.0.1"}},
489 {0},
490 };
491
492 WinDnsSystemSettings settings;
493 settings.addresses = CreateAdapterAddresses(infos);
494 ASSERT_OK_AND_ASSIGN(
495 DnsConfig dns_config,
496 internal::ConvertSettingsToDnsConfig(std::move(settings)));
497 EXPECT_THAT(dns_config,
498 testing::Field(&DnsConfig::unhandled_options, testing::IsTrue()));
499 }
500
501 // Setting adapter specific nameservers should set `unhandled_options`.
TEST(DnsConfigServiceWinTest,AdapterSpecificNameservers)502 TEST(DnsConfigServiceWinTest, AdapterSpecificNameservers) {
503 AdapterInfo infos[3] = {
504 {IF_TYPE_FASTETHER,
505 IfOperStatusUp,
506 L"example.com",
507 {"1.0.0.1", "fec0:0:0:ffff::2", "8.8.8.8"}},
508 {IF_TYPE_USB,
509 IfOperStatusUp,
510 L"chromium.org",
511 {"10.0.0.10", "2001:FFFF::1111"}},
512 {0},
513 };
514
515 WinDnsSystemSettings settings;
516 settings.addresses = CreateAdapterAddresses(infos);
517 ASSERT_OK_AND_ASSIGN(
518 DnsConfig dns_config,
519 internal::ConvertSettingsToDnsConfig(std::move(settings)));
520 EXPECT_THAT(dns_config,
521 testing::Field(&DnsConfig::unhandled_options, testing::IsTrue()));
522 }
523
524 // Setting adapter specific nameservers for non operational adapter should not
525 // set `unhandled_options`.
TEST(DnsConfigServiceWinTest,AdapterSpecificNameserversForNo)526 TEST(DnsConfigServiceWinTest, AdapterSpecificNameserversForNo) {
527 AdapterInfo infos[3] = {
528 {IF_TYPE_FASTETHER,
529 IfOperStatusUp,
530 L"example.com",
531 {"1.0.0.1", "fec0:0:0:ffff::2", "8.8.8.8"}},
532 {IF_TYPE_USB,
533 IfOperStatusDown,
534 L"chromium.org",
535 {"10.0.0.10", "2001:FFFF::1111"}},
536 {0},
537 };
538
539 WinDnsSystemSettings settings;
540 settings.addresses = CreateAdapterAddresses(infos);
541 ASSERT_OK_AND_ASSIGN(
542 DnsConfig dns_config,
543 internal::ConvertSettingsToDnsConfig(std::move(settings)));
544 EXPECT_THAT(dns_config, testing::Field(&DnsConfig::unhandled_options,
545 testing::IsFalse()));
546 }
547
548 } // namespace
549
550 } // namespace net
551