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