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