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