Home | History | Annotate | Download | only in dns
      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