OLD | NEW |
| (Empty) |
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 | |
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 uint16 ports[4]; | |
59 }; | |
60 | |
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 = IPEndPoint(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 | |
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 uint16 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 uint16 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 | |
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 | |
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. | |
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 | |
OLD | NEW |