1 // Copyright 2012 The Chromium Authors
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_hosts.h"
6
7 #include "base/test/metrics/histogram_tester.h"
8 #include "base/trace_event/memory_usage_estimator.h"
9 #include "build/build_config.h"
10 #include "net/base/cronet_buildflags.h"
11 #include "net/base/ip_address.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13
14 namespace net {
15
16 namespace {
17
18 struct ExpectedHostsEntry {
19 const char* host;
20 AddressFamily family;
21 const char* ip;
22 };
23
PopulateExpectedHosts(const ExpectedHostsEntry * entries,size_t num_entries,DnsHosts * expected_hosts_out)24 void PopulateExpectedHosts(const ExpectedHostsEntry* entries,
25 size_t num_entries,
26 DnsHosts* expected_hosts_out) {
27 for (size_t i = 0; i < num_entries; ++i) {
28 DnsHostsKey key(entries[i].host, entries[i].family);
29 IPAddress& ip_ref = (*expected_hosts_out)[key];
30 ASSERT_TRUE(ip_ref.empty());
31 ASSERT_TRUE(ip_ref.AssignFromIPLiteral(entries[i].ip));
32 ASSERT_EQ(ip_ref.size(),
33 (entries[i].family == ADDRESS_FAMILY_IPV4) ? 4u : 16u);
34 }
35 }
36
TEST(DnsHostsTest,ParseHosts)37 TEST(DnsHostsTest, ParseHosts) {
38 const std::string kContents =
39 "127.0.0.1 localhost # standard\n"
40 "\n"
41 "1.0.0.1 localhost # ignored, first hit above\n"
42 "fe00::x example company # ignored, malformed IPv6\n"
43 "1.0.0.300 company # ignored, malformed IPv4\n"
44 "1.0.0.1 # ignored, missing hostname\n"
45 "1.0.0.1\t CoMpANy # normalized to 'company' \n"
46 "::1\tlocalhost ip6-localhost ip6-loopback # comment # within a comment\n"
47 "\t fe00::0 ip6-localnet\r\n"
48 "2048::2 example\n"
49 "2048::1 company example # ignored for 'example' \n"
50 "127.0.0.1 cache1\n"
51 "127.0.0.1 cache2 # should reuse parsed IP\n"
52 "256.0.0.0 cache3 # bogus IP should not clear parsed IP cache\n"
53 "127.0.0.1 cache4 # should still be reused\n"
54 "127.0.0.2 cache5\n"
55 "127.0.0.3 .foo # entries with leading dot are ignored\n"
56 "127.0.0.3 . # just a dot is ignored\n"
57 "127.0.0.4 bar. # trailing dot is allowed, for now\n"
58 "gibberish\n"
59 "127.0.0.5 fóó.test # canonicalizes to 'xn--f-vgaa.test' due to RFC3490\n"
60 "127.0.0.6 127.0.0.1 # ignore IP host\n"
61 "2048::3 [::1] # ignore IP host";
62
63 const ExpectedHostsEntry kEntries[] = {
64 {"localhost", ADDRESS_FAMILY_IPV4, "127.0.0.1"},
65 {"company", ADDRESS_FAMILY_IPV4, "1.0.0.1"},
66 {"localhost", ADDRESS_FAMILY_IPV6, "::1"},
67 {"ip6-localhost", ADDRESS_FAMILY_IPV6, "::1"},
68 {"ip6-loopback", ADDRESS_FAMILY_IPV6, "::1"},
69 {"ip6-localnet", ADDRESS_FAMILY_IPV6, "fe00::0"},
70 {"company", ADDRESS_FAMILY_IPV6, "2048::1"},
71 {"example", ADDRESS_FAMILY_IPV6, "2048::2"},
72 {"cache1", ADDRESS_FAMILY_IPV4, "127.0.0.1"},
73 {"cache2", ADDRESS_FAMILY_IPV4, "127.0.0.1"},
74 {"cache4", ADDRESS_FAMILY_IPV4, "127.0.0.1"},
75 {"cache5", ADDRESS_FAMILY_IPV4, "127.0.0.2"},
76 {"bar.", ADDRESS_FAMILY_IPV4, "127.0.0.4"},
77 {"xn--f-vgaa.test", ADDRESS_FAMILY_IPV4, "127.0.0.5"},
78 };
79
80 DnsHosts expected_hosts, actual_hosts;
81 PopulateExpectedHosts(kEntries, std::size(kEntries), &expected_hosts);
82
83 base::HistogramTester histograms;
84 ParseHosts(kContents, &actual_hosts);
85 ASSERT_EQ(expected_hosts, actual_hosts);
86 histograms.ExpectUniqueSample("Net.DNS.DnsHosts.Count", std::size(kEntries),
87 1);
88 #if !BUILDFLAG(CRONET_BUILD)
89 histograms.ExpectUniqueSample(
90 "Net.DNS.DnsHosts.EstimateMemoryUsage",
91 base::trace_event::EstimateMemoryUsage(actual_hosts), 1);
92 #endif
93 }
94
TEST(DnsHostsTest,ParseHosts_CommaIsToken)95 TEST(DnsHostsTest, ParseHosts_CommaIsToken) {
96 const std::string kContents = "127.0.0.1 comma1,comma2";
97
98 const ExpectedHostsEntry kEntries[] = {
99 { "comma1,comma2", ADDRESS_FAMILY_IPV4, "127.0.0.1" },
100 };
101
102 DnsHosts expected_hosts, actual_hosts;
103 PopulateExpectedHosts(kEntries, std::size(kEntries), &expected_hosts);
104 ParseHostsWithCommaModeForTesting(
105 kContents, &actual_hosts, PARSE_HOSTS_COMMA_IS_TOKEN);
106 ASSERT_EQ(0UL, actual_hosts.size());
107 }
108
TEST(DnsHostsTest,ParseHosts_CommaIsWhitespace)109 TEST(DnsHostsTest, ParseHosts_CommaIsWhitespace) {
110 std::string kContents = "127.0.0.1 comma1,comma2";
111
112 const ExpectedHostsEntry kEntries[] = {
113 { "comma1", ADDRESS_FAMILY_IPV4, "127.0.0.1" },
114 { "comma2", ADDRESS_FAMILY_IPV4, "127.0.0.1" },
115 };
116
117 DnsHosts expected_hosts, actual_hosts;
118 PopulateExpectedHosts(kEntries, std::size(kEntries), &expected_hosts);
119 ParseHostsWithCommaModeForTesting(
120 kContents, &actual_hosts, PARSE_HOSTS_COMMA_IS_WHITESPACE);
121 ASSERT_EQ(expected_hosts, actual_hosts);
122 }
123
124 // Test that the right comma mode is used on each platform.
TEST(DnsHostsTest,ParseHosts_CommaModeByPlatform)125 TEST(DnsHostsTest, ParseHosts_CommaModeByPlatform) {
126 std::string kContents = "127.0.0.1 comma1,comma2";
127 DnsHosts actual_hosts;
128 ParseHosts(kContents, &actual_hosts);
129
130 #if BUILDFLAG(IS_APPLE)
131 const ExpectedHostsEntry kEntries[] = {
132 { "comma1", ADDRESS_FAMILY_IPV4, "127.0.0.1" },
133 { "comma2", ADDRESS_FAMILY_IPV4, "127.0.0.1" },
134 };
135 DnsHosts expected_hosts;
136 PopulateExpectedHosts(kEntries, std::size(kEntries), &expected_hosts);
137 ASSERT_EQ(expected_hosts, actual_hosts);
138 #else
139 ASSERT_EQ(0UL, actual_hosts.size());
140 #endif
141 }
142
TEST(DnsHostsTest,HostsParser_Empty)143 TEST(DnsHostsTest, HostsParser_Empty) {
144 DnsHosts hosts;
145 ParseHosts("", &hosts);
146 EXPECT_EQ(0u, hosts.size());
147 }
148
TEST(DnsHostsTest,HostsParser_OnlyWhitespace)149 TEST(DnsHostsTest, HostsParser_OnlyWhitespace) {
150 DnsHosts hosts;
151 ParseHosts(" ", &hosts);
152 EXPECT_EQ(0u, hosts.size());
153 }
154
TEST(DnsHostsTest,HostsParser_EndsWithNothing)155 TEST(DnsHostsTest, HostsParser_EndsWithNothing) {
156 DnsHosts hosts;
157 ParseHosts("127.0.0.1 localhost", &hosts);
158 EXPECT_EQ(1u, hosts.size());
159 }
160
TEST(DnsHostsTest,HostsParser_EndsWithWhitespace)161 TEST(DnsHostsTest, HostsParser_EndsWithWhitespace) {
162 DnsHosts hosts;
163 ParseHosts("127.0.0.1 localhost ", &hosts);
164 EXPECT_EQ(1u, hosts.size());
165 }
166
TEST(DnsHostsTest,HostsParser_EndsWithComment)167 TEST(DnsHostsTest, HostsParser_EndsWithComment) {
168 DnsHosts hosts;
169 ParseHosts("127.0.0.1 localhost # comment", &hosts);
170 EXPECT_EQ(1u, hosts.size());
171 }
172
TEST(DnsHostsTest,HostsParser_EndsWithNewline)173 TEST(DnsHostsTest, HostsParser_EndsWithNewline) {
174 DnsHosts hosts;
175 ParseHosts("127.0.0.1 localhost\n", &hosts);
176 EXPECT_EQ(1u, hosts.size());
177 }
178
TEST(DnsHostsTest,HostsParser_EndsWithTwoNewlines)179 TEST(DnsHostsTest, HostsParser_EndsWithTwoNewlines) {
180 DnsHosts hosts;
181 ParseHosts("127.0.0.1 localhost\n\n", &hosts);
182 EXPECT_EQ(1u, hosts.size());
183 }
184
TEST(DnsHostsTest,HostsParser_EndsWithNewlineAndWhitespace)185 TEST(DnsHostsTest, HostsParser_EndsWithNewlineAndWhitespace) {
186 DnsHosts hosts;
187 ParseHosts("127.0.0.1 localhost\n ", &hosts);
188 EXPECT_EQ(1u, hosts.size());
189 }
190
TEST(DnsHostsTest,HostsParser_EndsWithNewlineAndToken)191 TEST(DnsHostsTest, HostsParser_EndsWithNewlineAndToken) {
192 DnsHosts hosts;
193 ParseHosts("127.0.0.1 localhost\ntoken", &hosts);
194 EXPECT_EQ(1u, hosts.size());
195 }
196
197 } // namespace
198
199 } // namespace net
200