Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / net / dns / dns_config_service_win_unittest.cc
blobdc521ecefb2a26e0112bc2f21ad753349e9760c8
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.
5 #include "net/dns/dns_config_service_win.h"
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"
13 namespace net {
15 namespace {
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 } },
34 for (const auto& t : cases) {
35 std::vector<std::string> actual_output, expected_output;
36 actual_output.push_back("UNSET");
37 for (const char* const* output = t.output; *output; ++output) {
38 expected_output.push_back(*output);
40 bool result = internal::ParseSearchList(t.input, &actual_output);
41 if (!expected_output.empty()) {
42 EXPECT_TRUE(result);
43 EXPECT_EQ(expected_output, actual_output);
44 } else {
45 EXPECT_FALSE(result) << "Unexpected parse success on " << t.input;
50 struct AdapterInfo {
51 IFTYPE if_type;
52 IF_OPER_STATUS oper_status;
53 const WCHAR* dns_suffix;
54 std::string dns_server_addresses[4]; // Empty string indicates end.
55 uint16 ports[4];
58 scoped_ptr<IP_ADAPTER_ADDRESSES, base::FreeDeleter> CreateAdapterAddresses(
59 const AdapterInfo* infos) {
60 size_t num_adapters = 0;
61 size_t num_addresses = 0;
62 for (size_t i = 0; infos[i].if_type; ++i) {
63 ++num_adapters;
64 for (size_t j = 0; !infos[i].dns_server_addresses[j].empty(); ++j) {
65 ++num_addresses;
69 size_t heap_size = num_adapters * sizeof(IP_ADAPTER_ADDRESSES) +
70 num_addresses * (sizeof(IP_ADAPTER_DNS_SERVER_ADDRESS) +
71 sizeof(struct sockaddr_storage));
72 scoped_ptr<IP_ADAPTER_ADDRESSES, base::FreeDeleter> heap(
73 static_cast<IP_ADAPTER_ADDRESSES*>(malloc(heap_size)));
74 CHECK(heap.get());
75 memset(heap.get(), 0, heap_size);
77 IP_ADAPTER_ADDRESSES* adapters = heap.get();
78 IP_ADAPTER_DNS_SERVER_ADDRESS* addresses =
79 reinterpret_cast<IP_ADAPTER_DNS_SERVER_ADDRESS*>(adapters + num_adapters);
80 struct sockaddr_storage* storage =
81 reinterpret_cast<struct sockaddr_storage*>(addresses + num_addresses);
83 for (size_t i = 0; i < num_adapters; ++i) {
84 const AdapterInfo& info = infos[i];
85 IP_ADAPTER_ADDRESSES* adapter = adapters + i;
86 if (i + 1 < num_adapters)
87 adapter->Next = adapter + 1;
88 adapter->IfType = info.if_type;
89 adapter->OperStatus = info.oper_status;
90 adapter->DnsSuffix = const_cast<PWCHAR>(info.dns_suffix);
91 IP_ADAPTER_DNS_SERVER_ADDRESS* address = NULL;
92 for (size_t j = 0; !info.dns_server_addresses[j].empty(); ++j) {
93 --num_addresses;
94 if (j == 0) {
95 address = adapter->FirstDnsServerAddress = addresses + num_addresses;
96 } else {
97 // Note that |address| is moving backwards.
98 address = address->Next = address - 1;
100 IPAddressNumber ip;
101 CHECK(ParseIPLiteralToNumber(info.dns_server_addresses[j], &ip));
102 IPEndPoint ipe = IPEndPoint(ip, info.ports[j]);
103 address->Address.lpSockaddr =
104 reinterpret_cast<LPSOCKADDR>(storage + num_addresses);
105 socklen_t length = sizeof(struct sockaddr_storage);
106 CHECK(ipe.ToSockAddr(address->Address.lpSockaddr, &length));
107 address->Address.iSockaddrLength = static_cast<int>(length);
111 return heap.Pass();
114 TEST(DnsConfigServiceWinTest, ConvertAdapterAddresses) {
115 // Check nameservers and connection-specific suffix.
116 const struct TestCase {
117 AdapterInfo input_adapters[4]; // |if_type| == 0 indicates end.
118 std::string expected_nameservers[4]; // Empty string indicates end.
119 std::string expected_suffix;
120 uint16 expected_ports[4];
121 } cases[] = {
122 { // Ignore loopback and inactive adapters.
124 { IF_TYPE_SOFTWARE_LOOPBACK, IfOperStatusUp, L"funnyloop",
125 { "2.0.0.2" } },
126 { IF_TYPE_FASTETHER, IfOperStatusDormant, L"example.com",
127 { "1.0.0.1" } },
128 { IF_TYPE_USB, IfOperStatusUp, L"chromium.org",
129 { "10.0.0.10", "2001:FFFF::1111" } },
130 { 0 },
132 { "10.0.0.10", "2001:FFFF::1111" },
133 "chromium.org",
135 { // Respect configured ports.
137 { IF_TYPE_USB, IfOperStatusUp, L"chromium.org",
138 { "10.0.0.10", "2001:FFFF::1111" }, { 1024, 24 } },
139 { 0 },
141 { "10.0.0.10", "2001:FFFF::1111" },
142 "chromium.org",
143 { 1024, 24 },
145 { // Use the preferred adapter (first in binding order) and filter
146 // stateless DNS discovery addresses.
148 { IF_TYPE_SOFTWARE_LOOPBACK, IfOperStatusUp, L"funnyloop",
149 { "2.0.0.2" } },
150 { IF_TYPE_FASTETHER, IfOperStatusUp, L"example.com",
151 { "1.0.0.1", "fec0:0:0:ffff::2", "8.8.8.8" } },
152 { IF_TYPE_USB, IfOperStatusUp, L"chromium.org",
153 { "10.0.0.10", "2001:FFFF::1111" } },
154 { 0 },
156 { "1.0.0.1", "8.8.8.8" },
157 "example.com",
159 { // No usable adapters.
161 { IF_TYPE_SOFTWARE_LOOPBACK, IfOperStatusUp, L"localhost",
162 { "2.0.0.2" } },
163 { IF_TYPE_FASTETHER, IfOperStatusDormant, L"example.com",
164 { "1.0.0.1" } },
165 { IF_TYPE_USB, IfOperStatusUp, L"chromium.org" },
166 { 0 },
171 for (const auto& t : cases) {
172 internal::DnsSystemSettings settings;
173 settings.addresses = CreateAdapterAddresses(t.input_adapters);
174 // Default settings for the rest.
175 std::vector<IPEndPoint> expected_nameservers;
176 for (size_t j = 0; !t.expected_nameservers[j].empty(); ++j) {
177 IPAddressNumber ip;
178 ASSERT_TRUE(ParseIPLiteralToNumber(t.expected_nameservers[j], &ip));
179 uint16 port = t.expected_ports[j];
180 if (!port)
181 port = dns_protocol::kDefaultPort;
182 expected_nameservers.push_back(IPEndPoint(ip, port));
185 DnsConfig config;
186 internal::ConfigParseWinResult result =
187 internal::ConvertSettingsToDnsConfig(settings, &config);
188 internal::ConfigParseWinResult expected_result =
189 expected_nameservers.empty() ? internal::CONFIG_PARSE_WIN_NO_NAMESERVERS
190 : internal::CONFIG_PARSE_WIN_OK;
191 EXPECT_EQ(expected_result, result);
192 EXPECT_EQ(expected_nameservers, config.nameservers);
193 if (result == internal::CONFIG_PARSE_WIN_OK) {
194 ASSERT_EQ(1u, config.search.size());
195 EXPECT_EQ(t.expected_suffix, config.search[0]);
200 TEST(DnsConfigServiceWinTest, ConvertSuffixSearch) {
201 AdapterInfo infos[2] = {
202 { IF_TYPE_USB, IfOperStatusUp, L"connection.suffix", { "1.0.0.1" } },
203 { 0 },
206 const struct TestCase {
207 struct {
208 internal::DnsSystemSettings::RegString policy_search_list;
209 internal::DnsSystemSettings::RegString tcpip_search_list;
210 internal::DnsSystemSettings::RegString tcpip_domain;
211 internal::DnsSystemSettings::RegString primary_dns_suffix;
212 internal::DnsSystemSettings::DevolutionSetting policy_devolution;
213 internal::DnsSystemSettings::DevolutionSetting dnscache_devolution;
214 internal::DnsSystemSettings::DevolutionSetting tcpip_devolution;
215 } input_settings;
216 std::string expected_search[5];
217 } cases[] = {
218 { // Policy SearchList override.
220 { true, L"policy.searchlist.a,policy.searchlist.b" },
221 { true, L"tcpip.searchlist.a,tcpip.searchlist.b" },
222 { true, L"tcpip.domain" },
223 { true, L"primary.dns.suffix" },
225 { "policy.searchlist.a", "policy.searchlist.b" },
227 { // User-specified SearchList override.
229 { false },
230 { true, L"tcpip.searchlist.a,tcpip.searchlist.b" },
231 { true, L"tcpip.domain" },
232 { true, L"primary.dns.suffix" },
234 { "tcpip.searchlist.a", "tcpip.searchlist.b" },
236 { // Void SearchList. Using tcpip.domain
238 { true, L",bad.searchlist,parsed.as.empty" },
239 { true, L"tcpip.searchlist,good.but.overridden" },
240 { true, L"tcpip.domain" },
241 { false },
243 { "tcpip.domain", "connection.suffix" },
245 { // Void SearchList. Using primary.dns.suffix
247 { true, L",bad.searchlist,parsed.as.empty" },
248 { true, L"tcpip.searchlist,good.but.overridden" },
249 { true, L"tcpip.domain" },
250 { true, L"primary.dns.suffix" },
252 { "primary.dns.suffix", "connection.suffix" },
254 { // Void SearchList. Using tcpip.domain when primary.dns.suffix is empty
256 { true, L",bad.searchlist,parsed.as.empty" },
257 { true, L"tcpip.searchlist,good.but.overridden" },
258 { true, L"tcpip.domain" },
259 { true, L"" },
261 { "tcpip.domain", "connection.suffix" },
263 { // Void SearchList. Using tcpip.domain when primary.dns.suffix is NULL
265 { true, L",bad.searchlist,parsed.as.empty" },
266 { true, L"tcpip.searchlist,good.but.overridden" },
267 { true, L"tcpip.domain" },
268 { true },
270 { "tcpip.domain", "connection.suffix" },
272 { // No primary suffix. Devolution does not matter.
274 { false },
275 { false },
276 { true },
277 { true },
278 { { true, 1 }, { true, 2 } },
280 { "connection.suffix" },
282 { // Devolution enabled by policy, level by dnscache.
284 { false },
285 { false },
286 { true, L"a.b.c.d.e" },
287 { false },
288 { { true, 1 }, { false } }, // policy_devolution: enabled, level
289 { { true, 0 }, { true, 3 } }, // dnscache_devolution
290 { { true, 0 }, { true, 1 } }, // tcpip_devolution
292 { "a.b.c.d.e", "connection.suffix", "b.c.d.e", "c.d.e" },
294 { // Devolution enabled by dnscache, level by policy.
296 { false },
297 { false },
298 { true, L"a.b.c.d.e" },
299 { true, L"f.g.i.l.j" },
300 { { false }, { true, 4 } },
301 { { true, 1 }, { false } },
302 { { true, 0 }, { true, 3 } },
304 { "f.g.i.l.j", "connection.suffix", "g.i.l.j" },
306 { // Devolution enabled by default.
308 { false },
309 { false },
310 { true, L"a.b.c.d.e" },
311 { false },
312 { { false }, { false } },
313 { { false }, { true, 3 } },
314 { { false }, { true, 1 } },
316 { "a.b.c.d.e", "connection.suffix", "b.c.d.e", "c.d.e" },
318 { // Devolution enabled at level = 2, but nothing to devolve.
320 { false },
321 { false },
322 { true, L"a.b" },
323 { false },
324 { { false }, { false } },
325 { { false }, { true, 2 } },
326 { { false }, { true, 2 } },
328 { "a.b", "connection.suffix" },
330 { // Devolution disabled when no explicit level.
331 // Windows XP and Vista use a default level = 2, but we don't.
333 { false },
334 { false },
335 { true, L"a.b.c.d.e" },
336 { false },
337 { { true, 1 }, { false } },
338 { { true, 1 }, { false } },
339 { { true, 1 }, { false } },
341 { "a.b.c.d.e", "connection.suffix" },
343 { // Devolution disabled by policy level.
345 { false },
346 { false },
347 { true, L"a.b.c.d.e" },
348 { false },
349 { { false }, { true, 1 } },
350 { { true, 1 }, { true, 3 } },
351 { { true, 1 }, { true, 4 } },
353 { "a.b.c.d.e", "connection.suffix" },
355 { // Devolution disabled by user setting.
357 { false },
358 { false },
359 { true, L"a.b.c.d.e" },
360 { false },
361 { { false }, { true, 3 } },
362 { { false }, { true, 3 } },
363 { { true, 0 }, { true, 3 } },
365 { "a.b.c.d.e", "connection.suffix" },
369 for (auto& t : cases) {
370 internal::DnsSystemSettings settings;
371 settings.addresses = CreateAdapterAddresses(infos);
372 settings.policy_search_list = t.input_settings.policy_search_list;
373 settings.tcpip_search_list = t.input_settings.tcpip_search_list;
374 settings.tcpip_domain = t.input_settings.tcpip_domain;
375 settings.primary_dns_suffix = t.input_settings.primary_dns_suffix;
376 settings.policy_devolution = t.input_settings.policy_devolution;
377 settings.dnscache_devolution = t.input_settings.dnscache_devolution;
378 settings.tcpip_devolution = t.input_settings.tcpip_devolution;
380 DnsConfig config;
381 EXPECT_EQ(internal::CONFIG_PARSE_WIN_OK,
382 internal::ConvertSettingsToDnsConfig(settings, &config));
383 std::vector<std::string> expected_search;
384 for (size_t j = 0; !t.expected_search[j].empty(); ++j) {
385 expected_search.push_back(t.expected_search[j]);
387 EXPECT_EQ(expected_search, config.search);
391 TEST(DnsConfigServiceWinTest, AppendToMultiLabelName) {
392 AdapterInfo infos[2] = {
393 { IF_TYPE_USB, IfOperStatusUp, L"connection.suffix", { "1.0.0.1" } },
394 { 0 },
397 // The default setting was true pre-Vista.
398 bool default_value = (base::win::GetVersion() < base::win::VERSION_VISTA);
400 const struct TestCase {
401 internal::DnsSystemSettings::RegDword input;
402 bool expected_output;
403 } cases[] = {
404 { { true, 0 }, false },
405 { { true, 1 }, true },
406 { { false, 0 }, default_value },
409 for (const auto& t : cases) {
410 internal::DnsSystemSettings settings;
411 settings.addresses = CreateAdapterAddresses(infos);
412 settings.append_to_multi_label_name = t.input;
413 DnsConfig config;
414 EXPECT_EQ(internal::CONFIG_PARSE_WIN_OK,
415 internal::ConvertSettingsToDnsConfig(settings, &config));
416 EXPECT_EQ(t.expected_output, config.append_to_multi_label_name);
420 // Setting have_name_resolution_policy_table should set unhandled_options.
421 TEST(DnsConfigServiceWinTest, HaveNRPT) {
422 AdapterInfo infos[2] = {
423 { IF_TYPE_USB, IfOperStatusUp, L"connection.suffix", { "1.0.0.1" } },
424 { 0 },
427 const struct TestCase {
428 bool have_nrpt;
429 bool unhandled_options;
430 internal::ConfigParseWinResult result;
431 } cases[] = {
432 { false, false, internal::CONFIG_PARSE_WIN_OK },
433 { true, true, internal::CONFIG_PARSE_WIN_UNHANDLED_OPTIONS },
436 for (const auto& t : cases) {
437 internal::DnsSystemSettings settings;
438 settings.addresses = CreateAdapterAddresses(infos);
439 settings.have_name_resolution_policy = t.have_nrpt;
440 DnsConfig config;
441 EXPECT_EQ(t.result,
442 internal::ConvertSettingsToDnsConfig(settings, &config));
443 EXPECT_EQ(t.unhandled_options, config.unhandled_options);
444 EXPECT_EQ(t.have_nrpt, config.use_local_ipv6);
449 } // namespace
451 } // namespace net