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"
17 TEST(DnsConfigServiceWinTest
, ParseSearchList
) {
18 const struct TestCase
{
20 const char* output
[4]; // NULL-terminated, empty if expected false
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
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()) {
43 EXPECT_EQ(expected_output
, actual_output
);
45 EXPECT_FALSE(result
) << "Unexpected parse success on " << t
.input
;
52 IF_OPER_STATUS oper_status
;
53 const WCHAR
* dns_suffix
;
54 std::string dns_server_addresses
[4]; // Empty string indicates end.
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
) {
64 for (size_t j
= 0; !infos
[i
].dns_server_addresses
[j
].empty(); ++j
) {
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
)));
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
) {
95 address
= adapter
->FirstDnsServerAddress
= addresses
+ num_addresses
;
97 // Note that |address| is moving backwards.
98 address
= address
->Next
= address
- 1;
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
);
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];
122 { // Ignore loopback and inactive adapters.
124 { IF_TYPE_SOFTWARE_LOOPBACK
, IfOperStatusUp
, L
"funnyloop",
126 { IF_TYPE_FASTETHER
, IfOperStatusDormant
, L
"example.com",
128 { IF_TYPE_USB
, IfOperStatusUp
, L
"chromium.org",
129 { "10.0.0.10", "2001:FFFF::1111" } },
132 { "10.0.0.10", "2001:FFFF::1111" },
135 { // Respect configured ports.
137 { IF_TYPE_USB
, IfOperStatusUp
, L
"chromium.org",
138 { "10.0.0.10", "2001:FFFF::1111" }, { 1024, 24 } },
141 { "10.0.0.10", "2001:FFFF::1111" },
145 { // Use the preferred adapter (first in binding order) and filter
146 // stateless DNS discovery addresses.
148 { IF_TYPE_SOFTWARE_LOOPBACK
, IfOperStatusUp
, L
"funnyloop",
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" } },
156 { "1.0.0.1", "8.8.8.8" },
159 { // No usable adapters.
161 { IF_TYPE_SOFTWARE_LOOPBACK
, IfOperStatusUp
, L
"localhost",
163 { IF_TYPE_FASTETHER
, IfOperStatusDormant
, L
"example.com",
165 { IF_TYPE_USB
, IfOperStatusUp
, L
"chromium.org" },
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
) {
178 ASSERT_TRUE(ParseIPLiteralToNumber(t
.expected_nameservers
[j
], &ip
));
179 uint16 port
= t
.expected_ports
[j
];
181 port
= dns_protocol::kDefaultPort
;
182 expected_nameservers
.push_back(IPEndPoint(ip
, port
));
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" } },
206 const struct TestCase
{
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
;
216 std::string expected_search
[5];
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.
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" },
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" },
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" },
270 { "tcpip.domain", "connection.suffix" },
272 { // No primary suffix. Devolution does not matter.
278 { { true, 1 }, { true, 2 } },
280 { "connection.suffix" },
282 { // Devolution enabled by policy, level by dnscache.
286 { true, L
"a.b.c.d.e" },
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.
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.
310 { true, L
"a.b.c.d.e" },
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.
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.
335 { true, L
"a.b.c.d.e" },
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.
347 { true, L
"a.b.c.d.e" },
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.
359 { true, L
"a.b.c.d.e" },
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
;
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" } },
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
;
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
;
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" } },
427 const struct TestCase
{
429 bool unhandled_options
;
430 internal::ConfigParseWinResult result
;
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
;
442 internal::ConvertSettingsToDnsConfig(settings
, &config
));
443 EXPECT_EQ(t
.unhandled_options
, config
.unhandled_options
);
444 EXPECT_EQ(t
.have_nrpt
, config
.use_local_ipv6
);