1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com// Use of this source code is governed by a BSD-style license that can be
3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com// found in the LICENSE file.
4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com
5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com#include "net/dns/dns_config_service_win.h"
6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com
7ab9e2c6fc8ea08b167f2a68abd93772ea07f0edbbsalomon@google.com#include "base/basictypes.h"
8b1b7f707907b8c63b955cd2aef1cc454623e3656tfarina@chromium.org#include "base/logging.h"
9b1b7f707907b8c63b955cd2aef1cc454623e3656tfarina@chromium.org#include "base/win/windows_version.h"
1034245c7871f6339de8cc2be8fb1090ca3cba54efreed@android.com#include "net/dns/dns_protocol.h"
11ab9e2c6fc8ea08b167f2a68abd93772ea07f0edbbsalomon@google.com#include "testing/gtest/include/gtest/gtest.h"
1234245c7871f6339de8cc2be8fb1090ca3cba54efreed@android.com
1334245c7871f6339de8cc2be8fb1090ca3cba54efreed@android.comnamespace net {
1434245c7871f6339de8cc2be8fb1090ca3cba54efreed@android.com
15ab13167410206c5371508101949213d46e8dded9commit-bot@chromium.orgnamespace {
16ab13167410206c5371508101949213d46e8dded9commit-bot@chromium.org
17ab13167410206c5371508101949213d46e8dded9commit-bot@chromium.orgTEST(DnsConfigServiceWinTest, ParseSearchList) {
18ab13167410206c5371508101949213d46e8dded9commit-bot@chromium.org  const struct TestCase {
1934245c7871f6339de8cc2be8fb1090ca3cba54efreed@android.com    const wchar_t* input;
2034245c7871f6339de8cc2be8fb1090ca3cba54efreed@android.com    const char* output[4];  // NULL-terminated, empty if expected false
2134245c7871f6339de8cc2be8fb1090ca3cba54efreed@android.com  } cases[] = {
2248dd1a26ec07c5baa04856202e4e7e2a53e4d7e5bsalomon@google.com    { L"chromium.org", { "chromium.org", NULL } },
2334245c7871f6339de8cc2be8fb1090ca3cba54efreed@android.com    { L"chromium.org,org", { "chromium.org", "org", NULL } },
2434245c7871f6339de8cc2be8fb1090ca3cba54efreed@android.com    // Empty suffixes terminate the list
25ab9e2c6fc8ea08b167f2a68abd93772ea07f0edbbsalomon@google.com    { L"crbug.com,com,,org", { "crbug.com", "com", NULL } },
26ab9e2c6fc8ea08b167f2a68abd93772ea07f0edbbsalomon@google.com    // IDN are converted to punycode
27ab9e2c6fc8ea08b167f2a68abd93772ea07f0edbbsalomon@google.com    { L"\u017c\xf3\u0142ta.pi\u0119\u015b\u0107.pl,pl",
28ab9e2c6fc8ea08b167f2a68abd93772ea07f0edbbsalomon@google.com        { "xn--ta-4ja03asj.xn--pi-wla5e0q.pl", "pl", NULL } },
2934245c7871f6339de8cc2be8fb1090ca3cba54efreed@android.com    // Empty search list is invalid
3034245c7871f6339de8cc2be8fb1090ca3cba54efreed@android.com    { L"", { NULL } },
3134245c7871f6339de8cc2be8fb1090ca3cba54efreed@android.com    { L",,", { NULL } },
3234245c7871f6339de8cc2be8fb1090ca3cba54efreed@android.com  };
33ef7bdfac618f60e9edc9f42cd4661d563937e6d8yangsu@google.com
34ef7bdfac618f60e9edc9f42cd4661d563937e6d8yangsu@google.com  std::vector<std::string> actual_output, expected_output;
35ef7bdfac618f60e9edc9f42cd4661d563937e6d8yangsu@google.com  for (unsigned i = 0; i < arraysize(cases); ++i) {
3634245c7871f6339de8cc2be8fb1090ca3cba54efreed@android.com    const TestCase& t = cases[i];
3734245c7871f6339de8cc2be8fb1090ca3cba54efreed@android.com    actual_output.clear();
3834245c7871f6339de8cc2be8fb1090ca3cba54efreed@android.com    actual_output.push_back("UNSET");
39ab9e2c6fc8ea08b167f2a68abd93772ea07f0edbbsalomon@google.com    expected_output.clear();
40ab9e2c6fc8ea08b167f2a68abd93772ea07f0edbbsalomon@google.com    for (const char* const* output = t.output; *output; ++output) {
41ab9e2c6fc8ea08b167f2a68abd93772ea07f0edbbsalomon@google.com      expected_output.push_back(*output);
42ab9e2c6fc8ea08b167f2a68abd93772ea07f0edbbsalomon@google.com    }
43ab9e2c6fc8ea08b167f2a68abd93772ea07f0edbbsalomon@google.com    bool result = internal::ParseSearchList(t.input, &actual_output);
44ab9e2c6fc8ea08b167f2a68abd93772ea07f0edbbsalomon@google.com    if (!expected_output.empty()) {
45ab9e2c6fc8ea08b167f2a68abd93772ea07f0edbbsalomon@google.com      EXPECT_TRUE(result);
46ab9e2c6fc8ea08b167f2a68abd93772ea07f0edbbsalomon@google.com      EXPECT_EQ(expected_output, actual_output);
47ab9e2c6fc8ea08b167f2a68abd93772ea07f0edbbsalomon@google.com    } else {
4872708fa18d23ff9d97b90c98a4ead6717045c8c6reed@google.com      EXPECT_FALSE(result) << "Unexpected parse success on " << t.input;
49e72fee513a5f903d6aa17066d2f3b79ac31f05dereed@android.com    }
50e72fee513a5f903d6aa17066d2f3b79ac31f05dereed@android.com  }
51e72fee513a5f903d6aa17066d2f3b79ac31f05dereed@android.com}
5272708fa18d23ff9d97b90c98a4ead6717045c8c6reed@google.com
53ab9e2c6fc8ea08b167f2a68abd93772ea07f0edbbsalomon@google.comstruct AdapterInfo {
54ab9e2c6fc8ea08b167f2a68abd93772ea07f0edbbsalomon@google.com  IFTYPE if_type;
5534245c7871f6339de8cc2be8fb1090ca3cba54efreed@android.com  IF_OPER_STATUS oper_status;
5634245c7871f6339de8cc2be8fb1090ca3cba54efreed@android.com  const WCHAR* dns_suffix;
5734245c7871f6339de8cc2be8fb1090ca3cba54efreed@android.com  std::string dns_server_addresses[4];  // Empty string indicates end.
5834245c7871f6339de8cc2be8fb1090ca3cba54efreed@android.com  int ports[4];
5934245c7871f6339de8cc2be8fb1090ca3cba54efreed@android.com};
6034245c7871f6339de8cc2be8fb1090ca3cba54efreed@android.com
6134245c7871f6339de8cc2be8fb1090ca3cba54efreed@android.comscoped_ptr<IP_ADAPTER_ADDRESSES, base::FreeDeleter> CreateAdapterAddresses(
6234245c7871f6339de8cc2be8fb1090ca3cba54efreed@android.com    const AdapterInfo* infos) {
6334245c7871f6339de8cc2be8fb1090ca3cba54efreed@android.com  size_t num_adapters = 0;
64ab9e2c6fc8ea08b167f2a68abd93772ea07f0edbbsalomon@google.com  size_t num_addresses = 0;
65ab9e2c6fc8ea08b167f2a68abd93772ea07f0edbbsalomon@google.com  for (size_t i = 0; infos[i].if_type; ++i) {
6634245c7871f6339de8cc2be8fb1090ca3cba54efreed@android.com    ++num_adapters;
6734245c7871f6339de8cc2be8fb1090ca3cba54efreed@android.com    for (size_t j = 0; !infos[i].dns_server_addresses[j].empty(); ++j) {
6834245c7871f6339de8cc2be8fb1090ca3cba54efreed@android.com      ++num_addresses;
6934245c7871f6339de8cc2be8fb1090ca3cba54efreed@android.com    }
7048dd1a26ec07c5baa04856202e4e7e2a53e4d7e5bsalomon@google.com  }
7134245c7871f6339de8cc2be8fb1090ca3cba54efreed@android.com
72ab9e2c6fc8ea08b167f2a68abd93772ea07f0edbbsalomon@google.com  size_t heap_size = num_adapters * sizeof(IP_ADAPTER_ADDRESSES) +
73ab9e2c6fc8ea08b167f2a68abd93772ea07f0edbbsalomon@google.com                     num_addresses * (sizeof(IP_ADAPTER_DNS_SERVER_ADDRESS) +
74ab9e2c6fc8ea08b167f2a68abd93772ea07f0edbbsalomon@google.com                                      sizeof(struct sockaddr_storage));
75ab9e2c6fc8ea08b167f2a68abd93772ea07f0edbbsalomon@google.com  scoped_ptr<IP_ADAPTER_ADDRESSES, base::FreeDeleter> heap(
76ab9e2c6fc8ea08b167f2a68abd93772ea07f0edbbsalomon@google.com      static_cast<IP_ADAPTER_ADDRESSES*>(malloc(heap_size)));
77ab9e2c6fc8ea08b167f2a68abd93772ea07f0edbbsalomon@google.com  CHECK(heap.get());
7834245c7871f6339de8cc2be8fb1090ca3cba54efreed@android.com  memset(heap.get(), 0, heap_size);
7948dd1a26ec07c5baa04856202e4e7e2a53e4d7e5bsalomon@google.com
8034245c7871f6339de8cc2be8fb1090ca3cba54efreed@android.com  IP_ADAPTER_ADDRESSES* adapters = heap.get();
8134245c7871f6339de8cc2be8fb1090ca3cba54efreed@android.com  IP_ADAPTER_DNS_SERVER_ADDRESS* addresses =
8234245c7871f6339de8cc2be8fb1090ca3cba54efreed@android.com      reinterpret_cast<IP_ADAPTER_DNS_SERVER_ADDRESS*>(adapters + num_adapters);
8334245c7871f6339de8cc2be8fb1090ca3cba54efreed@android.com  struct sockaddr_storage* storage =
8434245c7871f6339de8cc2be8fb1090ca3cba54efreed@android.com      reinterpret_cast<struct sockaddr_storage*>(addresses + num_addresses);
8534245c7871f6339de8cc2be8fb1090ca3cba54efreed@android.com
8634245c7871f6339de8cc2be8fb1090ca3cba54efreed@android.com  for (size_t i = 0; i < num_adapters; ++i) {
8734245c7871f6339de8cc2be8fb1090ca3cba54efreed@android.com    const AdapterInfo& info = infos[i];
8834245c7871f6339de8cc2be8fb1090ca3cba54efreed@android.com    IP_ADAPTER_ADDRESSES* adapter = adapters + i;
8934245c7871f6339de8cc2be8fb1090ca3cba54efreed@android.com    if (i + 1 < num_adapters)
9034245c7871f6339de8cc2be8fb1090ca3cba54efreed@android.com      adapter->Next = adapter + 1;
9134245c7871f6339de8cc2be8fb1090ca3cba54efreed@android.com    adapter->IfType = info.if_type;
9234245c7871f6339de8cc2be8fb1090ca3cba54efreed@android.com    adapter->OperStatus = info.oper_status;
93ab9e2c6fc8ea08b167f2a68abd93772ea07f0edbbsalomon@google.com    adapter->DnsSuffix = const_cast<PWCHAR>(info.dns_suffix);
9434245c7871f6339de8cc2be8fb1090ca3cba54efreed@android.com    IP_ADAPTER_DNS_SERVER_ADDRESS* address = NULL;
9534245c7871f6339de8cc2be8fb1090ca3cba54efreed@android.com    for (size_t j = 0; !info.dns_server_addresses[j].empty(); ++j) {
9634245c7871f6339de8cc2be8fb1090ca3cba54efreed@android.com      --num_addresses;
9748dd1a26ec07c5baa04856202e4e7e2a53e4d7e5bsalomon@google.com      if (j == 0) {
9834245c7871f6339de8cc2be8fb1090ca3cba54efreed@android.com        address = adapter->FirstDnsServerAddress = addresses + num_addresses;
9934245c7871f6339de8cc2be8fb1090ca3cba54efreed@android.com      } else {
10034245c7871f6339de8cc2be8fb1090ca3cba54efreed@android.com        // Note that |address| is moving backwards.
101ab9e2c6fc8ea08b167f2a68abd93772ea07f0edbbsalomon@google.com        address = address->Next = address - 1;
102ab9e2c6fc8ea08b167f2a68abd93772ea07f0edbbsalomon@google.com      }
10334245c7871f6339de8cc2be8fb1090ca3cba54efreed@android.com      IPAddressNumber ip;
104ab9e2c6fc8ea08b167f2a68abd93772ea07f0edbbsalomon@google.com      CHECK(ParseIPLiteralToNumber(info.dns_server_addresses[j], &ip));
10534245c7871f6339de8cc2be8fb1090ca3cba54efreed@android.com      IPEndPoint ipe(ip, info.ports[j]);
10634245c7871f6339de8cc2be8fb1090ca3cba54efreed@android.com      address->Address.lpSockaddr =
10734245c7871f6339de8cc2be8fb1090ca3cba54efreed@android.com          reinterpret_cast<LPSOCKADDR>(storage + num_addresses);
10834245c7871f6339de8cc2be8fb1090ca3cba54efreed@android.com      socklen_t length = sizeof(struct sockaddr_storage);
10934245c7871f6339de8cc2be8fb1090ca3cba54efreed@android.com      CHECK(ipe.ToSockAddr(address->Address.lpSockaddr, &length));
11034245c7871f6339de8cc2be8fb1090ca3cba54efreed@android.com      address->Address.iSockaddrLength = static_cast<int>(length);
11134245c7871f6339de8cc2be8fb1090ca3cba54efreed@android.com    }
11234245c7871f6339de8cc2be8fb1090ca3cba54efreed@android.com  }
11334245c7871f6339de8cc2be8fb1090ca3cba54efreed@android.com
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