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/logging.h" 8 #include "base/win/windows_version.h" 9 #include "net/dns/dns_protocol.h" 10 #include "testing/gtest/include/gtest/gtest.h" 11 12 namespace net { 13 14 namespace { 15 16 TEST(DnsConfigServiceWinTest, ParseSearchList) { 17 const struct TestCase { 18 const wchar_t* input; 19 const char* output[4]; // NULL-terminated, empty if expected false 20 } cases[] = { 21 { L"chromium.org", { "chromium.org", NULL } }, 22 { L"chromium.org,org", { "chromium.org", "org", NULL } }, 23 // Empty suffixes terminate the list 24 { L"crbug.com,com,,org", { "crbug.com", "com", NULL } }, 25 // IDN are converted to punycode 26 { L"\u017c\xf3\u0142ta.pi\u0119\u015b\u0107.pl,pl", 27 { "xn--ta-4ja03asj.xn--pi-wla5e0q.pl", "pl", NULL } }, 28 // Empty search list is invalid 29 { L"", { NULL } }, 30 { L",,", { NULL } }, 31 }; 32 33 std::vector<std::string> actual_output, expected_output; 34 for (unsigned i = 0; i < arraysize(cases); ++i) { 35 const TestCase& t = cases[i]; 36 actual_output.clear(); 37 actual_output.push_back("UNSET"); 38 expected_output.clear(); 39 for (const char* const* output = t.output; *output; ++output) { 40 expected_output.push_back(*output); 41 } 42 bool result = internal::ParseSearchList(t.input, &actual_output); 43 if (!expected_output.empty()) { 44 EXPECT_TRUE(result); 45 EXPECT_EQ(expected_output, actual_output); 46 } else { 47 EXPECT_FALSE(result) << "Unexpected parse success on " << t.input; 48 } 49 } 50 } 51 52 struct AdapterInfo { 53 IFTYPE if_type; 54 IF_OPER_STATUS oper_status; 55 const WCHAR* dns_suffix; 56 std::string dns_server_addresses[4]; // Empty string indicates end. 57 int ports[4]; 58 }; 59 60 scoped_ptr_malloc<IP_ADAPTER_ADDRESSES> CreateAdapterAddresses( 61 const AdapterInfo* infos) { 62 size_t num_adapters = 0; 63 size_t num_addresses = 0; 64 for (size_t i = 0; infos[i].if_type; ++i) { 65 ++num_adapters; 66 for (size_t j = 0; !infos[i].dns_server_addresses[j].empty(); ++j) { 67 ++num_addresses; 68 } 69 } 70 71 size_t heap_size = num_adapters * sizeof(IP_ADAPTER_ADDRESSES) + 72 num_addresses * (sizeof(IP_ADAPTER_DNS_SERVER_ADDRESS) + 73 sizeof(struct sockaddr_storage)); 74 scoped_ptr_malloc<IP_ADAPTER_ADDRESSES> heap( 75 reinterpret_cast<IP_ADAPTER_ADDRESSES*>(malloc(heap_size))); 76 CHECK(heap.get()); 77 memset(heap.get(), 0, heap_size); 78 79 IP_ADAPTER_ADDRESSES* adapters = heap.get(); 80 IP_ADAPTER_DNS_SERVER_ADDRESS* addresses = 81 reinterpret_cast<IP_ADAPTER_DNS_SERVER_ADDRESS*>(adapters + num_adapters); 82 struct sockaddr_storage* storage = 83 reinterpret_cast<struct sockaddr_storage*>(addresses + num_addresses); 84 85 for (size_t i = 0; i < num_adapters; ++i) { 86 const AdapterInfo& info = infos[i]; 87 IP_ADAPTER_ADDRESSES* adapter = adapters + i; 88 if (i + 1 < num_adapters) 89 adapter->Next = adapter + 1; 90 adapter->IfType = info.if_type; 91 adapter->OperStatus = info.oper_status; 92 adapter->DnsSuffix = const_cast<PWCHAR>(info.dns_suffix); 93 IP_ADAPTER_DNS_SERVER_ADDRESS* address = NULL; 94 for (size_t j = 0; !info.dns_server_addresses[j].empty(); ++j) { 95 --num_addresses; 96 if (j == 0) { 97 address = adapter->FirstDnsServerAddress = addresses + num_addresses; 98 } else { 99 // Note that |address| is moving backwards. 100 address = address->Next = address - 1; 101 } 102 IPAddressNumber ip; 103 CHECK(ParseIPLiteralToNumber(info.dns_server_addresses[j], &ip)); 104 IPEndPoint ipe(ip, info.ports[j]); 105 address->Address.lpSockaddr = 106 reinterpret_cast<LPSOCKADDR>(storage + num_addresses); 107 socklen_t length = sizeof(struct sockaddr_storage); 108 CHECK(ipe.ToSockAddr(address->Address.lpSockaddr, &length)); 109 address->Address.iSockaddrLength = static_cast<int>(length); 110 } 111 } 112 113 return heap.Pass(); 114 } 115 116 TEST(DnsConfigServiceWinTest, ConvertAdapterAddresses) { 117 // Check nameservers and connection-specific suffix. 118 const struct TestCase { 119 AdapterInfo input_adapters[4]; // |if_type| == 0 indicates end. 120 std::string expected_nameservers[4]; // Empty string indicates end. 121 std::string expected_suffix; 122 int expected_ports[4]; 123 } cases[] = { 124 { // Ignore loopback and inactive adapters. 125 { 126 { IF_TYPE_SOFTWARE_LOOPBACK, IfOperStatusUp, L"funnyloop", 127 { "2.0.0.2" } }, 128 { IF_TYPE_FASTETHER, IfOperStatusDormant, L"example.com", 129 { "1.0.0.1" } }, 130 { IF_TYPE_USB, IfOperStatusUp, L"chromium.org", 131 { "10.0.0.10", "2001:FFFF::1111" } }, 132 { 0 }, 133 }, 134 { "10.0.0.10", "2001:FFFF::1111" }, 135 "chromium.org", 136 }, 137 { // Respect configured ports. 138 { 139 { IF_TYPE_USB, IfOperStatusUp, L"chromium.org", 140 { "10.0.0.10", "2001:FFFF::1111" }, { 1024, 24 } }, 141 { 0 }, 142 }, 143 { "10.0.0.10", "2001:FFFF::1111" }, 144 "chromium.org", 145 { 1024, 24 }, 146 }, 147 { // Use the preferred adapter (first in binding order) and filter 148 // stateless DNS discovery addresses. 149 { 150 { IF_TYPE_SOFTWARE_LOOPBACK, IfOperStatusUp, L"funnyloop", 151 { "2.0.0.2" } }, 152 { IF_TYPE_FASTETHER, IfOperStatusUp, L"example.com", 153 { "1.0.0.1", "fec0:0:0:ffff::2", "8.8.8.8" } }, 154 { IF_TYPE_USB, IfOperStatusUp, L"chromium.org", 155 { "10.0.0.10", "2001:FFFF::1111" } }, 156 { 0 }, 157 }, 158 { "1.0.0.1", "8.8.8.8" }, 159 "example.com", 160 }, 161 { // No usable adapters. 162 { 163 { IF_TYPE_SOFTWARE_LOOPBACK, IfOperStatusUp, L"localhost", 164 { "2.0.0.2" } }, 165 { IF_TYPE_FASTETHER, IfOperStatusDormant, L"example.com", 166 { "1.0.0.1" } }, 167 { IF_TYPE_USB, IfOperStatusUp, L"chromium.org" }, 168 { 0 }, 169 }, 170 }, 171 }; 172 173 for (size_t i = 0; i < arraysize(cases); ++i) { 174 const TestCase& t = cases[i]; 175 internal::DnsSystemSettings settings = { 176 CreateAdapterAddresses(t.input_adapters), 177 // Default settings for the rest. 178 }; 179 std::vector<IPEndPoint> expected_nameservers; 180 for (size_t j = 0; !t.expected_nameservers[j].empty(); ++j) { 181 IPAddressNumber ip; 182 ASSERT_TRUE(ParseIPLiteralToNumber(t.expected_nameservers[j], &ip)); 183 int port = t.expected_ports[j]; 184 if (!port) 185 port = dns_protocol::kDefaultPort; 186 expected_nameservers.push_back(IPEndPoint(ip, port)); 187 } 188 189 DnsConfig config; 190 internal::ConfigParseWinResult result = 191 internal::ConvertSettingsToDnsConfig(settings, &config); 192 internal::ConfigParseWinResult expected_result = 193 expected_nameservers.empty() ? internal::CONFIG_PARSE_WIN_NO_NAMESERVERS 194 : internal::CONFIG_PARSE_WIN_OK; 195 EXPECT_EQ(expected_result, result); 196 EXPECT_EQ(expected_nameservers, config.nameservers); 197 if (result == internal::CONFIG_PARSE_WIN_OK) { 198 ASSERT_EQ(1u, config.search.size()); 199 EXPECT_EQ(t.expected_suffix, config.search[0]); 200 } 201 } 202 } 203 204 TEST(DnsConfigServiceWinTest, ConvertSuffixSearch) { 205 AdapterInfo infos[2] = { 206 { IF_TYPE_USB, IfOperStatusUp, L"connection.suffix", { "1.0.0.1" } }, 207 { 0 }, 208 }; 209 210 const struct TestCase { 211 internal::DnsSystemSettings input_settings; 212 std::string expected_search[5]; 213 } cases[] = { 214 { // Policy SearchList override. 215 { 216 CreateAdapterAddresses(infos), 217 { true, L"policy.searchlist.a,policy.searchlist.b" }, 218 { true, L"tcpip.searchlist.a,tcpip.searchlist.b" }, 219 { true, L"tcpip.domain" }, 220 { true, L"primary.dns.suffix" }, 221 }, 222 { "policy.searchlist.a", "policy.searchlist.b" }, 223 }, 224 { // User-specified SearchList override. 225 { 226 CreateAdapterAddresses(infos), 227 { false }, 228 { true, L"tcpip.searchlist.a,tcpip.searchlist.b" }, 229 { true, L"tcpip.domain" }, 230 { true, L"primary.dns.suffix" }, 231 }, 232 { "tcpip.searchlist.a", "tcpip.searchlist.b" }, 233 }, 234 { // Void SearchList. Using tcpip.domain 235 { 236 CreateAdapterAddresses(infos), 237 { true, L",bad.searchlist,parsed.as.empty" }, 238 { true, L"tcpip.searchlist,good.but.overridden" }, 239 { true, L"tcpip.domain" }, 240 { false }, 241 }, 242 { "tcpip.domain", "connection.suffix" }, 243 }, 244 { // Void SearchList. Using primary.dns.suffix 245 { 246 CreateAdapterAddresses(infos), 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" }, 251 }, 252 { "primary.dns.suffix", "connection.suffix" }, 253 }, 254 { // Void SearchList. Using tcpip.domain when primary.dns.suffix is empty 255 { 256 CreateAdapterAddresses(infos), 257 { true, L",bad.searchlist,parsed.as.empty" }, 258 { true, L"tcpip.searchlist,good.but.overridden" }, 259 { true, L"tcpip.domain" }, 260 { true, L"" }, 261 }, 262 { "tcpip.domain", "connection.suffix" }, 263 }, 264 { // Void SearchList. Using tcpip.domain when primary.dns.suffix is NULL 265 { 266 CreateAdapterAddresses(infos), 267 { true, L",bad.searchlist,parsed.as.empty" }, 268 { true, L"tcpip.searchlist,good.but.overridden" }, 269 { true, L"tcpip.domain" }, 270 { true }, 271 }, 272 { "tcpip.domain", "connection.suffix" }, 273 }, 274 { // No primary suffix. Devolution does not matter. 275 { 276 CreateAdapterAddresses(infos), 277 { false }, 278 { false }, 279 { true }, 280 { true }, 281 { { true, 1 }, { true, 2 } }, 282 }, 283 { "connection.suffix" }, 284 }, 285 { // Devolution enabled by policy, level by dnscache. 286 { 287 CreateAdapterAddresses(infos), 288 { false }, 289 { false }, 290 { true, L"a.b.c.d.e" }, 291 { false }, 292 { { true, 1 }, { false } }, // policy_devolution: enabled, level 293 { { true, 0 }, { true, 3 } }, // dnscache_devolution 294 { { true, 0 }, { true, 1 } }, // tcpip_devolution 295 }, 296 { "a.b.c.d.e", "connection.suffix", "b.c.d.e", "c.d.e" }, 297 }, 298 { // Devolution enabled by dnscache, level by policy. 299 { 300 CreateAdapterAddresses(infos), 301 { false }, 302 { false }, 303 { true, L"a.b.c.d.e" }, 304 { true, L"f.g.i.l.j" }, 305 { { false }, { true, 4 } }, 306 { { true, 1 }, { false } }, 307 { { true, 0 }, { true, 3 } }, 308 }, 309 { "f.g.i.l.j", "connection.suffix", "g.i.l.j" }, 310 }, 311 { // Devolution enabled by default. 312 { 313 CreateAdapterAddresses(infos), 314 { false }, 315 { false }, 316 { true, L"a.b.c.d.e" }, 317 { false }, 318 { { false }, { false } }, 319 { { false }, { true, 3 } }, 320 { { false }, { true, 1 } }, 321 }, 322 { "a.b.c.d.e", "connection.suffix", "b.c.d.e", "c.d.e" }, 323 }, 324 { // Devolution enabled at level = 2, but nothing to devolve. 325 { 326 CreateAdapterAddresses(infos), 327 { false }, 328 { false }, 329 { true, L"a.b" }, 330 { false }, 331 { { false }, { false } }, 332 { { false }, { true, 2 } }, 333 { { false }, { true, 2 } }, 334 }, 335 { "a.b", "connection.suffix" }, 336 }, 337 { // Devolution disabled when no explicit level. 338 // Windows XP and Vista use a default level = 2, but we don't. 339 { 340 CreateAdapterAddresses(infos), 341 { false }, 342 { false }, 343 { true, L"a.b.c.d.e" }, 344 { false }, 345 { { true, 1 }, { false } }, 346 { { true, 1 }, { false } }, 347 { { true, 1 }, { false } }, 348 }, 349 { "a.b.c.d.e", "connection.suffix" }, 350 }, 351 { // Devolution disabled by policy level. 352 { 353 CreateAdapterAddresses(infos), 354 { false }, 355 { false }, 356 { true, L"a.b.c.d.e" }, 357 { false }, 358 { { false }, { true, 1 } }, 359 { { true, 1 }, { true, 3 } }, 360 { { true, 1 }, { true, 4 } }, 361 }, 362 { "a.b.c.d.e", "connection.suffix" }, 363 }, 364 { // Devolution disabled by user setting. 365 { 366 CreateAdapterAddresses(infos), 367 { false }, 368 { false }, 369 { true, L"a.b.c.d.e" }, 370 { false }, 371 { { false }, { true, 3 } }, 372 { { false }, { true, 3 } }, 373 { { true, 0 }, { true, 3 } }, 374 }, 375 { "a.b.c.d.e", "connection.suffix" }, 376 }, 377 }; 378 379 for (size_t i = 0; i < arraysize(cases); ++i) { 380 const TestCase& t = cases[i]; 381 DnsConfig config; 382 EXPECT_EQ(internal::CONFIG_PARSE_WIN_OK, 383 internal::ConvertSettingsToDnsConfig(t.input_settings, &config)); 384 std::vector<std::string> expected_search; 385 for (size_t j = 0; !t.expected_search[j].empty(); ++j) { 386 expected_search.push_back(t.expected_search[j]); 387 } 388 EXPECT_EQ(expected_search, config.search); 389 } 390 } 391 392 TEST(DnsConfigServiceWinTest, AppendToMultiLabelName) { 393 AdapterInfo infos[2] = { 394 { IF_TYPE_USB, IfOperStatusUp, L"connection.suffix", { "1.0.0.1" } }, 395 { 0 }, 396 }; 397 398 // The default setting was true pre-Vista. 399 bool default_value = (base::win::GetVersion() < base::win::VERSION_VISTA); 400 401 const struct TestCase { 402 internal::DnsSystemSettings::RegDword input; 403 bool expected_output; 404 } cases[] = { 405 { { true, 0 }, false }, 406 { { true, 1 }, true }, 407 { { false, 0 }, default_value }, 408 }; 409 410 for (size_t i = 0; i < arraysize(cases); ++i) { 411 const TestCase& t = cases[i]; 412 internal::DnsSystemSettings settings = { 413 CreateAdapterAddresses(infos), 414 { false }, { false }, { false }, { false }, 415 { { false }, { false } }, 416 { { false }, { false } }, 417 { { false }, { false } }, 418 t.input, 419 }; 420 DnsConfig config; 421 EXPECT_EQ(internal::CONFIG_PARSE_WIN_OK, 422 internal::ConvertSettingsToDnsConfig(settings, &config)); 423 EXPECT_EQ(config.append_to_multi_label_name, t.expected_output); 424 } 425 } 426 427 } // namespace 428 429 } // namespace net 430 431