• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
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 "base/basictypes.h"
8 #include "base/logging.h"
9 #include "base/win/windows_version.h"
10 #include "net/dns/dns_protocol.h"
11 #include "testing/gtest/include/gtest/gtest.h"
12 
13 namespace net {
14 
15 namespace {
16 
TEST(DnsConfigServiceWinTest,ParseSearchList)17 TEST(DnsConfigServiceWinTest, ParseSearchList) {
18   const struct TestCase {
19     const wchar_t* input;
20     const char* output[4];  // NULL-terminated, empty if expected false
21   } cases[] = {
22     { L"chromium.org", { "chromium.org", NULL } },
23     { L"chromium.org,org", { "chromium.org", "org", NULL } },
24     // Empty suffixes terminate the list
25     { L"crbug.com,com,,org", { "crbug.com", "com", NULL } },
26     // IDN are converted to punycode
27     { L"\u017c\xf3\u0142ta.pi\u0119\u015b\u0107.pl,pl",
28         { "xn--ta-4ja03asj.xn--pi-wla5e0q.pl", "pl", NULL } },
29     // Empty search list is invalid
30     { L"", { NULL } },
31     { L",,", { NULL } },
32   };
33 
34   std::vector<std::string> actual_output, expected_output;
35   for (unsigned i = 0; i < arraysize(cases); ++i) {
36     const TestCase& t = cases[i];
37     actual_output.clear();
38     actual_output.push_back("UNSET");
39     expected_output.clear();
40     for (const char* const* output = t.output; *output; ++output) {
41       expected_output.push_back(*output);
42     }
43     bool result = internal::ParseSearchList(t.input, &actual_output);
44     if (!expected_output.empty()) {
45       EXPECT_TRUE(result);
46       EXPECT_EQ(expected_output, actual_output);
47     } else {
48       EXPECT_FALSE(result) << "Unexpected parse success on " << t.input;
49     }
50   }
51 }
52 
53 struct AdapterInfo {
54   IFTYPE if_type;
55   IF_OPER_STATUS oper_status;
56   const WCHAR* dns_suffix;
57   std::string dns_server_addresses[4];  // Empty string indicates end.
58   int ports[4];
59 };
60 
CreateAdapterAddresses(const AdapterInfo * infos)61 scoped_ptr<IP_ADAPTER_ADDRESSES, base::FreeDeleter> CreateAdapterAddresses(
62     const AdapterInfo* infos) {
63   size_t num_adapters = 0;
64   size_t num_addresses = 0;
65   for (size_t i = 0; infos[i].if_type; ++i) {
66     ++num_adapters;
67     for (size_t j = 0; !infos[i].dns_server_addresses[j].empty(); ++j) {
68       ++num_addresses;
69     }
70   }
71 
72   size_t heap_size = num_adapters * sizeof(IP_ADAPTER_ADDRESSES) +
73                      num_addresses * (sizeof(IP_ADAPTER_DNS_SERVER_ADDRESS) +
74                                       sizeof(struct sockaddr_storage));
75   scoped_ptr<IP_ADAPTER_ADDRESSES, base::FreeDeleter> heap(
76       static_cast<IP_ADAPTER_ADDRESSES*>(malloc(heap_size)));
77   CHECK(heap.get());
78   memset(heap.get(), 0, heap_size);
79 
80   IP_ADAPTER_ADDRESSES* adapters = heap.get();
81   IP_ADAPTER_DNS_SERVER_ADDRESS* addresses =
82       reinterpret_cast<IP_ADAPTER_DNS_SERVER_ADDRESS*>(adapters + num_adapters);
83   struct sockaddr_storage* storage =
84       reinterpret_cast<struct sockaddr_storage*>(addresses + num_addresses);
85 
86   for (size_t i = 0; i < num_adapters; ++i) {
87     const AdapterInfo& info = infos[i];
88     IP_ADAPTER_ADDRESSES* adapter = adapters + i;
89     if (i + 1 < num_adapters)
90       adapter->Next = adapter + 1;
91     adapter->IfType = info.if_type;
92     adapter->OperStatus = info.oper_status;
93     adapter->DnsSuffix = const_cast<PWCHAR>(info.dns_suffix);
94     IP_ADAPTER_DNS_SERVER_ADDRESS* address = NULL;
95     for (size_t j = 0; !info.dns_server_addresses[j].empty(); ++j) {
96       --num_addresses;
97       if (j == 0) {
98         address = adapter->FirstDnsServerAddress = addresses + num_addresses;
99       } else {
100         // Note that |address| is moving backwards.
101         address = address->Next = address - 1;
102       }
103       IPAddressNumber ip;
104       CHECK(ParseIPLiteralToNumber(info.dns_server_addresses[j], &ip));
105       IPEndPoint ipe(ip, info.ports[j]);
106       address->Address.lpSockaddr =
107           reinterpret_cast<LPSOCKADDR>(storage + num_addresses);
108       socklen_t length = sizeof(struct sockaddr_storage);
109       CHECK(ipe.ToSockAddr(address->Address.lpSockaddr, &length));
110       address->Address.iSockaddrLength = static_cast<int>(length);
111     }
112   }
113 
114   return heap.Pass();
115 }
116 
TEST(DnsConfigServiceWinTest,ConvertAdapterAddresses)117 TEST(DnsConfigServiceWinTest, ConvertAdapterAddresses) {
118   // Check nameservers and connection-specific suffix.
119   const struct TestCase {
120     AdapterInfo input_adapters[4];        // |if_type| == 0 indicates end.
121     std::string expected_nameservers[4];  // Empty string indicates end.
122     std::string expected_suffix;
123     int expected_ports[4];
124   } cases[] = {
125     {  // Ignore loopback and inactive adapters.
126       {
127         { IF_TYPE_SOFTWARE_LOOPBACK, IfOperStatusUp, L"funnyloop",
128           { "2.0.0.2" } },
129         { IF_TYPE_FASTETHER, IfOperStatusDormant, L"example.com",
130           { "1.0.0.1" } },
131         { IF_TYPE_USB, IfOperStatusUp, L"chromium.org",
132           { "10.0.0.10", "2001:FFFF::1111" } },
133         { 0 },
134       },
135       { "10.0.0.10", "2001:FFFF::1111" },
136       "chromium.org",
137     },
138     {  // Respect configured ports.
139       {
140         { IF_TYPE_USB, IfOperStatusUp, L"chromium.org",
141         { "10.0.0.10", "2001:FFFF::1111" }, { 1024, 24 } },
142         { 0 },
143       },
144       { "10.0.0.10", "2001:FFFF::1111" },
145       "chromium.org",
146       { 1024, 24 },
147     },
148     {  // Use the preferred adapter (first in binding order) and filter
149        // stateless DNS discovery addresses.
150       {
151         { IF_TYPE_SOFTWARE_LOOPBACK, IfOperStatusUp, L"funnyloop",
152           { "2.0.0.2" } },
153         { IF_TYPE_FASTETHER, IfOperStatusUp, L"example.com",
154           { "1.0.0.1", "fec0:0:0:ffff::2", "8.8.8.8" } },
155         { IF_TYPE_USB, IfOperStatusUp, L"chromium.org",
156           { "10.0.0.10", "2001:FFFF::1111" } },
157         { 0 },
158       },
159       { "1.0.0.1", "8.8.8.8" },
160       "example.com",
161     },
162     {  // No usable adapters.
163       {
164         { IF_TYPE_SOFTWARE_LOOPBACK, IfOperStatusUp, L"localhost",
165           { "2.0.0.2" } },
166         { IF_TYPE_FASTETHER, IfOperStatusDormant, L"example.com",
167           { "1.0.0.1" } },
168         { IF_TYPE_USB, IfOperStatusUp, L"chromium.org" },
169         { 0 },
170       },
171     },
172   };
173 
174   for (size_t i = 0; i < arraysize(cases); ++i) {
175     const TestCase& t = cases[i];
176     internal::DnsSystemSettings settings = {
177       CreateAdapterAddresses(t.input_adapters),
178       // Default settings for the rest.
179     };
180     std::vector<IPEndPoint> expected_nameservers;
181     for (size_t j = 0; !t.expected_nameservers[j].empty(); ++j) {
182       IPAddressNumber ip;
183       ASSERT_TRUE(ParseIPLiteralToNumber(t.expected_nameservers[j], &ip));
184       int port = t.expected_ports[j];
185       if (!port)
186         port = dns_protocol::kDefaultPort;
187       expected_nameservers.push_back(IPEndPoint(ip, port));
188     }
189 
190     DnsConfig config;
191     internal::ConfigParseWinResult result =
192         internal::ConvertSettingsToDnsConfig(settings, &config);
193     internal::ConfigParseWinResult expected_result =
194         expected_nameservers.empty() ? internal::CONFIG_PARSE_WIN_NO_NAMESERVERS
195             : internal::CONFIG_PARSE_WIN_OK;
196     EXPECT_EQ(expected_result, result);
197     EXPECT_EQ(expected_nameservers, config.nameservers);
198     if (result == internal::CONFIG_PARSE_WIN_OK) {
199       ASSERT_EQ(1u, config.search.size());
200       EXPECT_EQ(t.expected_suffix, config.search[0]);
201     }
202   }
203 }
204 
TEST(DnsConfigServiceWinTest,ConvertSuffixSearch)205 TEST(DnsConfigServiceWinTest, ConvertSuffixSearch) {
206   AdapterInfo infos[2] = {
207     { IF_TYPE_USB, IfOperStatusUp, L"connection.suffix", { "1.0.0.1" } },
208     { 0 },
209   };
210 
211   const struct TestCase {
212     internal::DnsSystemSettings input_settings;
213     std::string expected_search[5];
214   } cases[] = {
215     {  // Policy SearchList override.
216       {
217         CreateAdapterAddresses(infos),
218         { true, L"policy.searchlist.a,policy.searchlist.b" },
219         { true, L"tcpip.searchlist.a,tcpip.searchlist.b" },
220         { true, L"tcpip.domain" },
221         { true, L"primary.dns.suffix" },
222       },
223       { "policy.searchlist.a", "policy.searchlist.b" },
224     },
225     {  // User-specified SearchList override.
226       {
227         CreateAdapterAddresses(infos),
228         { false },
229         { true, L"tcpip.searchlist.a,tcpip.searchlist.b" },
230         { true, L"tcpip.domain" },
231         { true, L"primary.dns.suffix" },
232       },
233       { "tcpip.searchlist.a", "tcpip.searchlist.b" },
234     },
235     {  // Void SearchList. Using tcpip.domain
236       {
237         CreateAdapterAddresses(infos),
238         { true, L",bad.searchlist,parsed.as.empty" },
239         { true, L"tcpip.searchlist,good.but.overridden" },
240         { true, L"tcpip.domain" },
241         { false },
242       },
243       { "tcpip.domain", "connection.suffix" },
244     },
245     {  // Void SearchList. Using primary.dns.suffix
246       {
247         CreateAdapterAddresses(infos),
248         { true, L",bad.searchlist,parsed.as.empty" },
249         { true, L"tcpip.searchlist,good.but.overridden" },
250         { true, L"tcpip.domain" },
251         { true, L"primary.dns.suffix" },
252       },
253       { "primary.dns.suffix", "connection.suffix" },
254     },
255     {  // Void SearchList. Using tcpip.domain when primary.dns.suffix is empty
256       {
257         CreateAdapterAddresses(infos),
258         { true, L",bad.searchlist,parsed.as.empty" },
259         { true, L"tcpip.searchlist,good.but.overridden" },
260         { true, L"tcpip.domain" },
261         { true, L"" },
262       },
263       { "tcpip.domain", "connection.suffix" },
264     },
265     {  // Void SearchList. Using tcpip.domain when primary.dns.suffix is NULL
266       {
267         CreateAdapterAddresses(infos),
268         { true, L",bad.searchlist,parsed.as.empty" },
269         { true, L"tcpip.searchlist,good.but.overridden" },
270         { true, L"tcpip.domain" },
271         { true },
272       },
273       { "tcpip.domain", "connection.suffix" },
274     },
275     {  // No primary suffix. Devolution does not matter.
276       {
277         CreateAdapterAddresses(infos),
278         { false },
279         { false },
280         { true },
281         { true },
282         { { true, 1 }, { true, 2 } },
283       },
284       { "connection.suffix" },
285     },
286     {  // Devolution enabled by policy, level by dnscache.
287       {
288         CreateAdapterAddresses(infos),
289         { false },
290         { false },
291         { true, L"a.b.c.d.e" },
292         { false },
293         { { true, 1 }, { false } },   // policy_devolution: enabled, level
294         { { true, 0 }, { true, 3 } }, // dnscache_devolution
295         { { true, 0 }, { true, 1 } }, // tcpip_devolution
296       },
297       { "a.b.c.d.e", "connection.suffix", "b.c.d.e", "c.d.e" },
298     },
299     {  // Devolution enabled by dnscache, level by policy.
300       {
301         CreateAdapterAddresses(infos),
302         { false },
303         { false },
304         { true, L"a.b.c.d.e" },
305         { true, L"f.g.i.l.j" },
306         { { false }, { true, 4 } },
307         { { true, 1 }, { false } },
308         { { true, 0 }, { true, 3 } },
309       },
310       { "f.g.i.l.j", "connection.suffix", "g.i.l.j" },
311     },
312     {  // Devolution enabled by default.
313       {
314         CreateAdapterAddresses(infos),
315         { false },
316         { false },
317         { true, L"a.b.c.d.e" },
318         { false },
319         { { false }, { false } },
320         { { false }, { true, 3 } },
321         { { false }, { true, 1 } },
322       },
323       { "a.b.c.d.e", "connection.suffix", "b.c.d.e", "c.d.e" },
324     },
325     {  // Devolution enabled at level = 2, but nothing to devolve.
326       {
327         CreateAdapterAddresses(infos),
328         { false },
329         { false },
330         { true, L"a.b" },
331         { false },
332         { { false }, { false } },
333         { { false }, { true, 2 } },
334         { { false }, { true, 2 } },
335       },
336       { "a.b", "connection.suffix" },
337     },
338     {  // Devolution disabled when no explicit level.
339        // Windows XP and Vista use a default level = 2, but we don't.
340       {
341         CreateAdapterAddresses(infos),
342         { false },
343         { false },
344         { true, L"a.b.c.d.e" },
345         { false },
346         { { true, 1 }, { false } },
347         { { true, 1 }, { false } },
348         { { true, 1 }, { false } },
349       },
350       { "a.b.c.d.e", "connection.suffix" },
351     },
352     {  // Devolution disabled by policy level.
353       {
354         CreateAdapterAddresses(infos),
355         { false },
356         { false },
357         { true, L"a.b.c.d.e" },
358         { false },
359         { { false }, { true, 1 } },
360         { { true, 1 }, { true, 3 } },
361         { { true, 1 }, { true, 4 } },
362       },
363       { "a.b.c.d.e", "connection.suffix" },
364     },
365     {  // Devolution disabled by user setting.
366       {
367         CreateAdapterAddresses(infos),
368         { false },
369         { false },
370         { true, L"a.b.c.d.e" },
371         { false },
372         { { false }, { true, 3 } },
373         { { false }, { true, 3 } },
374         { { true, 0 }, { true, 3 } },
375       },
376       { "a.b.c.d.e", "connection.suffix" },
377     },
378   };
379 
380   for (size_t i = 0; i < arraysize(cases); ++i) {
381     const TestCase& t = cases[i];
382     DnsConfig config;
383     EXPECT_EQ(internal::CONFIG_PARSE_WIN_OK,
384               internal::ConvertSettingsToDnsConfig(t.input_settings, &config));
385     std::vector<std::string> expected_search;
386     for (size_t j = 0; !t.expected_search[j].empty(); ++j) {
387       expected_search.push_back(t.expected_search[j]);
388     }
389     EXPECT_EQ(expected_search, config.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   // The default setting was true pre-Vista.
400   bool default_value = (base::win::GetVersion() < base::win::VERSION_VISTA);
401 
402   const struct TestCase {
403     internal::DnsSystemSettings::RegDword input;
404     bool expected_output;
405   } cases[] = {
406     { { true, 0 }, false },
407     { { true, 1 }, true },
408     { { false, 0 }, default_value },
409   };
410 
411   for (size_t i = 0; i < arraysize(cases); ++i) {
412     const TestCase& t = cases[i];
413     internal::DnsSystemSettings settings = {
414       CreateAdapterAddresses(infos),
415       { false }, { false }, { false }, { false },
416       { { false }, { false } },
417       { { false }, { false } },
418       { { false }, { false } },
419       t.input,
420     };
421     DnsConfig config;
422     EXPECT_EQ(internal::CONFIG_PARSE_WIN_OK,
423               internal::ConvertSettingsToDnsConfig(settings, &config));
424     EXPECT_EQ(t.expected_output, config.append_to_multi_label_name);
425   }
426 }
427 
428 // Setting have_name_resolution_policy_table should set unhandled_options.
TEST(DnsConfigServiceWinTest,HaveNRPT)429 TEST(DnsConfigServiceWinTest, HaveNRPT) {
430   AdapterInfo infos[2] = {
431     { IF_TYPE_USB, IfOperStatusUp, L"connection.suffix", { "1.0.0.1" } },
432     { 0 },
433   };
434 
435   const struct TestCase {
436     bool have_nrpt;
437     bool unhandled_options;
438     internal::ConfigParseWinResult result;
439   } cases[] = {
440     { false, false, internal::CONFIG_PARSE_WIN_OK },
441     { true, true, internal::CONFIG_PARSE_WIN_UNHANDLED_OPTIONS },
442   };
443 
444   for (size_t i = 0; i < arraysize(cases); ++i) {
445     const TestCase& t = cases[i];
446     internal::DnsSystemSettings settings = {
447       CreateAdapterAddresses(infos),
448       { false }, { false }, { false }, { false },
449       { { false }, { false } },
450       { { false }, { false } },
451       { { false }, { false } },
452       { false },
453       t.have_nrpt,
454     };
455     DnsConfig config;
456     EXPECT_EQ(t.result,
457               internal::ConvertSettingsToDnsConfig(settings, &config));
458     EXPECT_EQ(t.unhandled_options, config.unhandled_options);
459     EXPECT_EQ(t.have_nrpt, config.use_local_ipv6);
460   }
461 }
462 
463 
464 }  // namespace
465 
466 }  // namespace net
467 
468