// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include #include "base/sys_byteorder.h" #include "net/dns/dns_config_service_posix.h" #include "testing/gtest/include/gtest/gtest.h" #if !defined(OS_ANDROID) namespace net { namespace { // MAXNS is normally 3, but let's test 4 if possible. const char* kNameserversIPv4[] = { "8.8.8.8", "192.168.1.1", "63.1.2.4", "1.0.0.1", }; #if defined(OS_LINUX) const char* kNameserversIPv6[] = { NULL, "2001:DB8:0::42", NULL, "::FFFF:129.144.52.38", }; #endif // Fills in |res| with sane configuration. void InitializeResState(res_state res) { memset(res, 0, sizeof(*res)); res->options = RES_INIT | RES_RECURSE | RES_DEFNAMES | RES_DNSRCH | RES_ROTATE; res->ndots = 2; res->retrans = 4; res->retry = 7; const char kDnsrch[] = "chromium.org" "\0" "example.com"; memcpy(res->defdname, kDnsrch, sizeof(kDnsrch)); res->dnsrch[0] = res->defdname; res->dnsrch[1] = res->defdname + sizeof("chromium.org"); for (unsigned i = 0; i < arraysize(kNameserversIPv4) && i < MAXNS; ++i) { struct sockaddr_in sa; sa.sin_family = AF_INET; sa.sin_port = base::HostToNet16(NS_DEFAULTPORT + i); inet_pton(AF_INET, kNameserversIPv4[i], &sa.sin_addr); res->nsaddr_list[i] = sa; ++res->nscount; } #if defined(OS_LINUX) // Install IPv6 addresses, replacing the corresponding IPv4 addresses. unsigned nscount6 = 0; for (unsigned i = 0; i < arraysize(kNameserversIPv6) && i < MAXNS; ++i) { if (!kNameserversIPv6[i]) continue; // Must use malloc to mimick res_ninit. struct sockaddr_in6 *sa6; sa6 = (struct sockaddr_in6 *)malloc(sizeof(*sa6)); sa6->sin6_family = AF_INET6; sa6->sin6_port = base::HostToNet16(NS_DEFAULTPORT - i); inet_pton(AF_INET6, kNameserversIPv6[i], &sa6->sin6_addr); res->_u._ext.nsaddrs[i] = sa6; memset(&res->nsaddr_list[i], 0, sizeof res->nsaddr_list[i]); ++nscount6; } res->_u._ext.nscount6 = nscount6; #endif } void CloseResState(res_state res) { #if defined(OS_LINUX) for (int i = 0; i < res->nscount; ++i) { if (res->_u._ext.nsaddrs[i] != NULL) free(res->_u._ext.nsaddrs[i]); } #endif } void InitializeExpectedConfig(DnsConfig* config) { config->ndots = 2; config->timeout = base::TimeDelta::FromSeconds(4); config->attempts = 7; config->rotate = true; config->edns0 = false; config->append_to_multi_label_name = true; config->search.clear(); config->search.push_back("chromium.org"); config->search.push_back("example.com"); config->nameservers.clear(); for (unsigned i = 0; i < arraysize(kNameserversIPv4) && i < MAXNS; ++i) { IPAddressNumber ip; ParseIPLiteralToNumber(kNameserversIPv4[i], &ip); config->nameservers.push_back(IPEndPoint(ip, NS_DEFAULTPORT + i)); } #if defined(OS_LINUX) for (unsigned i = 0; i < arraysize(kNameserversIPv6) && i < MAXNS; ++i) { if (!kNameserversIPv6[i]) continue; IPAddressNumber ip; ParseIPLiteralToNumber(kNameserversIPv6[i], &ip); config->nameservers[i] = IPEndPoint(ip, NS_DEFAULTPORT - i); } #endif } TEST(DnsConfigServicePosixTest, ConvertResStateToDnsConfig) { struct __res_state res; DnsConfig config; EXPECT_FALSE(config.IsValid()); InitializeResState(&res); ASSERT_EQ(internal::CONFIG_PARSE_POSIX_OK, internal::ConvertResStateToDnsConfig(res, &config)); CloseResState(&res); EXPECT_TRUE(config.IsValid()); DnsConfig expected_config; EXPECT_FALSE(expected_config.EqualsIgnoreHosts(config)); InitializeExpectedConfig(&expected_config); EXPECT_TRUE(expected_config.EqualsIgnoreHosts(config)); } TEST(DnsConfigServicePosixTest, RejectEmptyNameserver) { struct __res_state res = {}; res.options = RES_INIT | RES_RECURSE | RES_DEFNAMES | RES_DNSRCH; const char kDnsrch[] = "chromium.org"; memcpy(res.defdname, kDnsrch, sizeof(kDnsrch)); res.dnsrch[0] = res.defdname; struct sockaddr_in sa = {}; sa.sin_family = AF_INET; sa.sin_port = base::HostToNet16(NS_DEFAULTPORT); sa.sin_addr.s_addr = INADDR_ANY; res.nsaddr_list[0] = sa; sa.sin_addr.s_addr = 0xCAFE1337; res.nsaddr_list[1] = sa; res.nscount = 2; DnsConfig config; EXPECT_EQ(internal::CONFIG_PARSE_POSIX_NULL_ADDRESS, internal::ConvertResStateToDnsConfig(res, &config)); sa.sin_addr.s_addr = 0xDEADBEEF; res.nsaddr_list[0] = sa; EXPECT_EQ(internal::CONFIG_PARSE_POSIX_OK, internal::ConvertResStateToDnsConfig(res, &config)); } } // namespace } // namespace net #endif // !OS_ANDROID