1 // Copyright 2019 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 #ifdef UNSAFE_BUFFERS_BUILD
6 // TODO(crbug.com/40284755): Remove this and spanify to fix the errors.
7 #pragma allow_unsafe_buffers
8 #endif
9
10 #include "net/dns/address_info.h"
11
12 #include <stdint.h>
13 #include <stdlib.h>
14 #include <string.h>
15
16 #include <array>
17 #include <memory>
18 #include <optional>
19 #include <string_view>
20
21 #include "base/check_op.h"
22 #include "base/numerics/safe_conversions.h"
23 #include "base/sys_byteorder.h"
24 #include "build/build_config.h"
25 #include "net/base/address_list.h"
26 #include "net/base/net_errors.h"
27 #include "net/base/sys_addrinfo.h"
28 #include "testing/gmock/include/gmock/gmock.h"
29 #include "testing/gtest/include/gtest/gtest.h"
30
31 namespace net {
32
33 namespace {
34
35 class MockAddrInfoGetter : public AddrInfoGetter {
36 public:
37 std::unique_ptr<addrinfo, FreeAddrInfoFunc> getaddrinfo(
38 const std::string& host,
39 const addrinfo* hints,
40 int* out_os_error,
41 handles::NetworkHandle network) override;
42
43 private:
44 struct IpAndPort {
45 struct Ip {
46 uint8_t a;
47 uint8_t b;
48 uint8_t c;
49 uint8_t d;
50 };
51 Ip ip;
52 int port;
53 };
54
55 // Initialises `addr` and `ai` from `ip_and_port`, `canonical_name` and
56 // `ai_next`.
57 static void InitializeAddrinfo(const IpAndPort& ip_and_port,
58 char* canonical_name,
59 addrinfo* ai_next,
60 sockaddr_in* addr,
61 addrinfo* ai);
62
63 // Allocates and initialises an addrinfo structure containing the ip addresses
64 // and ports from `ipp` and the name `canonical_name`. This function is
65 // designed to be used within getaddrinfo(), which returns a raw pointer even
66 // though it transfers ownership. So this function does the same. Since
67 // addrinfo is a C-style variable-sized structure it cannot be allocated with
68 // new. It is allocated with malloc() instead, so it must be freed with
69 // free().
70 template <size_t N>
71 static std::unique_ptr<addrinfo, FreeAddrInfoFunc> MakeAddrInfoList(
72 const IpAndPort (&ipp)[N],
73 std::string_view canonical_name);
74
75 static std::unique_ptr<addrinfo, FreeAddrInfoFunc> MakeAddrInfo(
76 IpAndPort ipp,
77 std::string_view canonical_name);
78 };
79
80 template <size_t N>
81 std::unique_ptr<addrinfo, FreeAddrInfoFunc>
MakeAddrInfoList(const IpAndPort (& ipp)[N],std::string_view canonical_name)82 MockAddrInfoGetter::MakeAddrInfoList(const IpAndPort (&ipp)[N],
83 std::string_view canonical_name) {
84 struct Buffer {
85 addrinfo ai[N];
86 sockaddr_in addr[N];
87 char canonical_name[256];
88 };
89
90 CHECK_LE(canonical_name.size(), 255u);
91
92 Buffer* const buffer = new Buffer();
93 memset(buffer, 0x0, sizeof(Buffer));
94
95 // At least one trailing nul byte on buffer->canonical_name was added by
96 // memset() above.
97 memcpy(buffer->canonical_name, canonical_name.data(), canonical_name.size());
98
99 for (size_t i = 0; i < N; ++i) {
100 InitializeAddrinfo(ipp[i], buffer->canonical_name,
101 i + 1 < N ? buffer->ai + i + 1 : nullptr,
102 buffer->addr + i, buffer->ai + i);
103 }
104
105 return {reinterpret_cast<addrinfo*>(buffer),
106 [](addrinfo* ai) { delete reinterpret_cast<Buffer*>(ai); }};
107 }
108
MakeAddrInfo(IpAndPort ipp,std::string_view canonical_name)109 std::unique_ptr<addrinfo, FreeAddrInfoFunc> MockAddrInfoGetter::MakeAddrInfo(
110 IpAndPort ipp,
111 std::string_view canonical_name) {
112 return MakeAddrInfoList({ipp}, canonical_name);
113 }
114
InitializeAddrinfo(const IpAndPort & ip_and_port,char * canonical_name,addrinfo * ai_next,sockaddr_in * addr,addrinfo * ai)115 void MockAddrInfoGetter::InitializeAddrinfo(const IpAndPort& ip_and_port,
116 char* canonical_name,
117 addrinfo* ai_next,
118 sockaddr_in* addr,
119 addrinfo* ai) {
120 const uint8_t ip[4] = {ip_and_port.ip.a, ip_and_port.ip.b, ip_and_port.ip.c,
121 ip_and_port.ip.d};
122 memcpy(&addr->sin_addr, ip, 4);
123 addr->sin_family = AF_INET;
124 addr->sin_port =
125 base::HostToNet16(base::checked_cast<uint16_t>(ip_and_port.port));
126
127 ai->ai_family = AF_INET;
128 ai->ai_socktype = SOCK_STREAM;
129 ai->ai_addrlen = sizeof(sockaddr_in);
130 ai->ai_addr = reinterpret_cast<sockaddr*>(addr);
131 ai->ai_canonname =
132 reinterpret_cast<decltype(ai->ai_canonname)>(canonical_name);
133 if (ai_next)
134 ai->ai_next = ai_next;
135 }
136
getaddrinfo(const std::string & host,const addrinfo *,int * out_os_error,handles::NetworkHandle)137 std::unique_ptr<addrinfo, FreeAddrInfoFunc> MockAddrInfoGetter::getaddrinfo(
138 const std::string& host,
139 const addrinfo* /* hints */,
140 int* out_os_error,
141 handles::NetworkHandle) {
142 // Presume success
143 *out_os_error = 0;
144
145 if (host == std::string("canonical.bar.com"))
146 return MakeAddrInfo({{1, 2, 3, 4}, 80}, "canonical.bar.com");
147 else if (host == "iteration.test")
148 return MakeAddrInfoList({{{10, 20, 30, 40}, 80},
149 {{11, 21, 31, 41}, 81},
150 {{12, 22, 32, 42}, 82}},
151 "iteration.test");
152 else if (host == "alllocalhost.com")
153 return MakeAddrInfoList(
154 {{{127, 0, 0, 1}, 80}, {{127, 0, 0, 2}, 80}, {{127, 0, 0, 3}, 80}},
155 "alllocalhost.com");
156 else if (host == "not.alllocalhost.com")
157 return MakeAddrInfoList(
158 {{{128, 0, 0, 1}, 80}, {{127, 0, 0, 2}, 80}, {{127, 0, 0, 3}, 80}},
159 "not.alllocalhost.com");
160 else if (host == "www.example.com")
161 return MakeAddrInfo({{8, 8, 8, 8}, 80}, "www.example.com");
162
163 // Failure
164 *out_os_error = 1;
165
166 return {nullptr, [](addrinfo*) {}};
167 }
168
MakeHints(AddressFamily address_family,HostResolverFlags host_resolver_flags)169 std::unique_ptr<addrinfo> MakeHints(AddressFamily address_family,
170 HostResolverFlags host_resolver_flags) {
171 auto hints = std::make_unique<addrinfo>();
172 *hints = {0};
173
174 switch (address_family) {
175 case ADDRESS_FAMILY_IPV4:
176 hints->ai_family = AF_INET;
177 break;
178 case ADDRESS_FAMILY_IPV6:
179 hints->ai_family = AF_INET6;
180 break;
181 case ADDRESS_FAMILY_UNSPECIFIED:
182 hints->ai_family = AF_UNSPEC;
183 break;
184 }
185
186 if (host_resolver_flags & HOST_RESOLVER_CANONNAME)
187 hints->ai_flags |= AI_CANONNAME;
188
189 hints->ai_socktype = SOCK_STREAM;
190
191 return hints;
192 }
193
TEST(AddressInfoTest,Failure)194 TEST(AddressInfoTest, Failure) {
195 auto getter = std::make_unique<MockAddrInfoGetter>();
196 auto [ai, err, os_error] = AddressInfo::Get(
197 "failure.com", *MakeHints(ADDRESS_FAMILY_IPV4, HOST_RESOLVER_CANONNAME),
198 std::move(getter));
199
200 EXPECT_FALSE(ai);
201 EXPECT_NE(err, OK);
202 EXPECT_NE(os_error, 0);
203 }
204
205 #if BUILDFLAG(IS_WIN)
206 // Note: this test is descriptive, not prescriptive.
TEST(AddressInfoTest,FailureWin)207 TEST(AddressInfoTest, FailureWin) {
208 auto getter = std::make_unique<MockAddrInfoGetter>();
209 auto [ai, err, os_error] = AddressInfo::Get(
210 "failure.com", *MakeHints(ADDRESS_FAMILY_IPV4, HOST_RESOLVER_CANONNAME),
211 std::move(getter));
212
213 EXPECT_FALSE(ai);
214 EXPECT_EQ(err, ERR_NAME_RESOLUTION_FAILED);
215 EXPECT_NE(os_error, 0);
216 }
217 #endif // BUILDFLAG(IS_WIN)
218
219 #if BUILDFLAG(IS_ANDROID)
220 // Note: this test is descriptive, not prescriptive.
TEST(AddressInfoTest,FailureAndroid)221 TEST(AddressInfoTest, FailureAndroid) {
222 auto getter = std::make_unique<MockAddrInfoGetter>();
223 auto [ai, err, os_error] = AddressInfo::Get(
224 "failure.com", *MakeHints(ADDRESS_FAMILY_IPV4, HOST_RESOLVER_CANONNAME),
225 std::move(getter));
226
227 EXPECT_FALSE(ai);
228 EXPECT_EQ(err, ERR_NAME_NOT_RESOLVED);
229 EXPECT_NE(os_error, 0);
230 }
231 #endif // BUILDFLAG(IS_ANDROID)
232
TEST(AddressInfoTest,Canonical)233 TEST(AddressInfoTest, Canonical) {
234 auto [ai, err, os_error] =
235 AddressInfo::Get("canonical.bar.com",
236 *MakeHints(ADDRESS_FAMILY_IPV4, HOST_RESOLVER_CANONNAME),
237 std::make_unique<MockAddrInfoGetter>());
238
239 EXPECT_TRUE(ai);
240 EXPECT_EQ(err, OK);
241 EXPECT_EQ(os_error, 0);
242 EXPECT_THAT(ai->GetCanonicalName(),
243 std::optional<std::string>("canonical.bar.com"));
244 }
245
TEST(AddressInfoTest,Iteration)246 TEST(AddressInfoTest, Iteration) {
247 auto [ai, err, os_error] =
248 AddressInfo::Get("iteration.test",
249 *MakeHints(ADDRESS_FAMILY_IPV4, HOST_RESOLVER_CANONNAME),
250 std::make_unique<MockAddrInfoGetter>());
251
252 EXPECT_TRUE(ai);
253 EXPECT_EQ(err, OK);
254 EXPECT_EQ(os_error, 0);
255
256 {
257 int count = 0;
258 for (const auto& addr_info : *ai) {
259 const sockaddr_in* addr =
260 reinterpret_cast<sockaddr_in*>(addr_info.ai_addr);
261 EXPECT_EQ(base::HostToNet16(addr->sin_port) % 10, count % 10);
262 ++count;
263 }
264
265 EXPECT_EQ(count, 3);
266 }
267
268 {
269 int count = 0;
270 for (auto&& aii : ai.value()) {
271 const sockaddr_in* addr = reinterpret_cast<sockaddr_in*>(aii.ai_addr);
272 EXPECT_EQ(base::HostToNet16(addr->sin_port) % 10, count % 10);
273 ++count;
274 }
275
276 EXPECT_EQ(count, 3);
277 }
278 }
279
TEST(AddressInfoTest,IsAllLocalhostOfOneFamily)280 TEST(AddressInfoTest, IsAllLocalhostOfOneFamily) {
281 auto [ai, err, os_error] =
282 AddressInfo::Get("alllocalhost.com",
283 *MakeHints(ADDRESS_FAMILY_IPV4, HOST_RESOLVER_CANONNAME),
284 std::make_unique<MockAddrInfoGetter>());
285
286 EXPECT_TRUE(ai);
287 EXPECT_EQ(err, OK);
288 EXPECT_EQ(os_error, 0);
289 EXPECT_TRUE(ai->IsAllLocalhostOfOneFamily());
290 }
291
TEST(AddressInfoTest,IsAllLocalhostOfOneFamilyFalse)292 TEST(AddressInfoTest, IsAllLocalhostOfOneFamilyFalse) {
293 auto [ai, err, os_error] =
294 AddressInfo::Get("not.alllocalhost.com",
295 *MakeHints(ADDRESS_FAMILY_IPV4, HOST_RESOLVER_CANONNAME),
296 std::make_unique<MockAddrInfoGetter>());
297
298 EXPECT_TRUE(ai);
299 EXPECT_EQ(err, OK);
300 EXPECT_EQ(os_error, 0);
301 EXPECT_FALSE(ai->IsAllLocalhostOfOneFamily());
302 }
303
TEST(AddressInfoTest,CreateAddressList)304 TEST(AddressInfoTest, CreateAddressList) {
305 auto [ai, err, os_error] =
306 AddressInfo::Get("www.example.com",
307 *MakeHints(ADDRESS_FAMILY_IPV4, HOST_RESOLVER_CANONNAME),
308 std::make_unique<MockAddrInfoGetter>());
309
310 EXPECT_TRUE(ai);
311 EXPECT_EQ(err, OK);
312 EXPECT_EQ(os_error, 0);
313
314 AddressList list = ai->CreateAddressList();
315
316 // Verify one result.
317 ASSERT_EQ(1u, list.size());
318 ASSERT_EQ(ADDRESS_FAMILY_IPV4, list[0].GetFamily());
319
320 // Check if operator= works.
321 AddressList copy;
322 copy = list;
323 ASSERT_EQ(1u, copy.size());
324 }
325
326 } // namespace
327 } // namespace net
328