| 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 |