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/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   int 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(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     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 
    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 
    468