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/public/resolv_reader.h"
11
12 #include <arpa/inet.h>
13 #include <resolv.h>
14
15 #include <memory>
16 #include <optional>
17 #include <utility>
18 #include <vector>
19
20 #include "base/cancelable_callback.h"
21 #include "base/check.h"
22 #include "base/functional/bind.h"
23 #include "base/run_loop.h"
24 #include "base/sys_byteorder.h"
25 #include "base/task/sequenced_task_runner.h"
26 #include "base/task/task_traits.h"
27 #include "base/task/thread_pool.h"
28 #include "build/build_config.h"
29 #include "net/base/ip_address.h"
30 #include "net/dns/public/dns_protocol.h"
31 #include "testing/gtest/include/gtest/gtest.h"
32
33 namespace net {
34
35 namespace {
36
37 // MAXNS is normally 3, but let's test 4 if possible.
38 const char* const kNameserversIPv4[] = {
39 "8.8.8.8",
40 "192.168.1.1",
41 "63.1.2.4",
42 "1.0.0.1",
43 };
44
45 #if BUILDFLAG(IS_LINUX)
46 const char* const kNameserversIPv6[] = {
47 nullptr,
48 "2001:db8::42",
49 nullptr,
50 "::FFFF:129.144.52.38",
51 };
52 #endif
53
54 // Fills in |res| with sane configuration.
InitializeResState(res_state res)55 void InitializeResState(res_state res) {
56 memset(res, 0, sizeof(*res));
57 res->options = RES_INIT;
58
59 for (unsigned i = 0; i < std::size(kNameserversIPv4) && i < MAXNS; ++i) {
60 struct sockaddr_in sa;
61 sa.sin_family = AF_INET;
62 sa.sin_port = base::HostToNet16(NS_DEFAULTPORT + i);
63 inet_pton(AF_INET, kNameserversIPv4[i], &sa.sin_addr);
64 res->nsaddr_list[i] = sa;
65 ++res->nscount;
66 }
67
68 #if BUILDFLAG(IS_LINUX)
69 // Install IPv6 addresses, replacing the corresponding IPv4 addresses.
70 unsigned nscount6 = 0;
71 for (unsigned i = 0; i < std::size(kNameserversIPv6) && i < MAXNS; ++i) {
72 if (!kNameserversIPv6[i])
73 continue;
74 // Must use malloc to mimic res_ninit. Expect to be freed in
75 // `TestResolvReader::CloseResState()`.
76 struct sockaddr_in6* sa6;
77 sa6 = static_cast<sockaddr_in6*>(malloc(sizeof(*sa6)));
78 sa6->sin6_family = AF_INET6;
79 sa6->sin6_port = base::HostToNet16(NS_DEFAULTPORT - i);
80 inet_pton(AF_INET6, kNameserversIPv6[i], &sa6->sin6_addr);
81 res->_u._ext.nsaddrs[i] = sa6;
82 memset(&res->nsaddr_list[i], 0, sizeof res->nsaddr_list[i]);
83 ++nscount6;
84 }
85 res->_u._ext.nscount6 = nscount6;
86 #endif
87 }
88
FreeResState(struct __res_state * res)89 void FreeResState(struct __res_state* res) {
90 #if BUILDFLAG(IS_LINUX)
91 for (int i = 0; i < res->nscount; ++i) {
92 if (res->_u._ext.nsaddrs[i] != nullptr)
93 free(res->_u._ext.nsaddrs[i]);
94 }
95 #endif
96 }
97
TEST(ResolvReaderTest,GetNameservers)98 TEST(ResolvReaderTest, GetNameservers) {
99 auto res = std::make_unique<struct __res_state>();
100 InitializeResState(res.get());
101
102 std::optional<std::vector<IPEndPoint>> nameservers =
103 GetNameservers(*res.get());
104 EXPECT_TRUE(nameservers.has_value());
105
106 #if BUILDFLAG(IS_LINUX)
107 EXPECT_EQ(kNameserversIPv4[0], nameservers->at(0).ToStringWithoutPort());
108 EXPECT_EQ(kNameserversIPv6[1], nameservers->at(1).ToStringWithoutPort());
109 EXPECT_EQ(kNameserversIPv4[2], nameservers->at(2).ToStringWithoutPort());
110 #else
111 EXPECT_EQ(kNameserversIPv4[0], nameservers->at(0).ToStringWithoutPort());
112 EXPECT_EQ(kNameserversIPv4[1], nameservers->at(1).ToStringWithoutPort());
113 EXPECT_EQ(kNameserversIPv4[2], nameservers->at(2).ToStringWithoutPort());
114 #endif
115
116 FreeResState(res.get());
117 }
118
119 } // namespace
120
121 } // namespace net
122