• 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 #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