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 13namespace net { 14 15namespace { 16 17TEST(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 53struct 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 61scoped_ptr_malloc<IP_ADAPTER_ADDRESSES> 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_malloc<IP_ADAPTER_ADDRESSES> heap( 76 reinterpret_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 117TEST(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 205TEST(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 393TEST(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. 429TEST(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