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 #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/dns_config_service_posix.h"
11
12 #include <resolv.h>
13
14 #include <memory>
15 #include <optional>
16
17 #include "base/cancelable_callback.h"
18 #include "base/files/file_util.h"
19 #include "base/functional/bind.h"
20 #include "base/run_loop.h"
21 #include "base/sys_byteorder.h"
22 #include "base/task/sequenced_task_runner.h"
23 #include "base/task/task_traits.h"
24 #include "base/task/thread_pool.h"
25 #include "base/test/task_environment.h"
26 #include "base/test/test_timeouts.h"
27 #include "build/build_config.h"
28 #include "net/base/ip_address.h"
29 #include "net/dns/dns_config.h"
30 #include "net/dns/public/dns_protocol.h"
31 #include "testing/gtest/include/gtest/gtest.h"
32
33 #if BUILDFLAG(IS_ANDROID)
34 #include "base/android/path_utils.h"
35 #endif // BUILDFLAG(IS_ANDROID)
36
37 // Required for inet_pton()
38 #if BUILDFLAG(IS_WIN)
39 #include <winsock2.h>
40 #else
41 #include <arpa/inet.h>
42 #endif
43
44 namespace net {
45
46 namespace {
47
48 // MAXNS is normally 3, but let's test 4 if possible.
49 const char* const kNameserversIPv4[] = {
50 "8.8.8.8",
51 "192.168.1.1",
52 "63.1.2.4",
53 "1.0.0.1",
54 };
55
56 #if BUILDFLAG(IS_CHROMEOS)
57 const char* const kNameserversIPv6[] = {
58 nullptr,
59 "2001:DB8:0::42",
60 nullptr,
61 "::FFFF:129.144.52.38",
62 };
63 #endif
64
DummyConfigCallback(const DnsConfig & config)65 void DummyConfigCallback(const DnsConfig& config) {
66 // Do nothing
67 }
68
69 // Fills in |res| with sane configuration.
InitializeResState(res_state res)70 void InitializeResState(res_state res) {
71 memset(res, 0, sizeof(*res));
72 res->options = RES_INIT | RES_RECURSE | RES_DEFNAMES | RES_DNSRCH |
73 RES_ROTATE;
74 res->ndots = 2;
75 res->retrans = 4;
76 res->retry = 7;
77
78 const char kDnsrch[] = "chromium.org" "\0" "example.com";
79 memcpy(res->defdname, kDnsrch, sizeof(kDnsrch));
80 res->dnsrch[0] = res->defdname;
81 res->dnsrch[1] = res->defdname + sizeof("chromium.org");
82
83 for (unsigned i = 0; i < std::size(kNameserversIPv4) && i < MAXNS; ++i) {
84 struct sockaddr_in sa;
85 sa.sin_family = AF_INET;
86 sa.sin_port = base::HostToNet16(NS_DEFAULTPORT + i);
87 inet_pton(AF_INET, kNameserversIPv4[i], &sa.sin_addr);
88 res->nsaddr_list[i] = sa;
89 ++res->nscount;
90 }
91
92 #if BUILDFLAG(IS_CHROMEOS)
93 // Install IPv6 addresses, replacing the corresponding IPv4 addresses.
94 unsigned nscount6 = 0;
95 for (unsigned i = 0; i < std::size(kNameserversIPv6) && i < MAXNS; ++i) {
96 if (!kNameserversIPv6[i])
97 continue;
98 // Must use malloc to mimick res_ninit.
99 struct sockaddr_in6 *sa6;
100 sa6 = (struct sockaddr_in6 *)malloc(sizeof(*sa6));
101 sa6->sin6_family = AF_INET6;
102 sa6->sin6_port = base::HostToNet16(NS_DEFAULTPORT - i);
103 inet_pton(AF_INET6, kNameserversIPv6[i], &sa6->sin6_addr);
104 res->_u._ext.nsaddrs[i] = sa6;
105 memset(&res->nsaddr_list[i], 0, sizeof res->nsaddr_list[i]);
106 ++nscount6;
107 }
108 res->_u._ext.nscount6 = nscount6;
109 #endif
110 }
111
CloseResState(res_state res)112 void CloseResState(res_state res) {
113 #if BUILDFLAG(IS_CHROMEOS)
114 for (int i = 0; i < res->nscount; ++i) {
115 if (res->_u._ext.nsaddrs[i] != nullptr)
116 free(res->_u._ext.nsaddrs[i]);
117 }
118 #endif
119 }
120
InitializeExpectedConfig(DnsConfig * config)121 void InitializeExpectedConfig(DnsConfig* config) {
122 config->ndots = 2;
123 config->fallback_period = base::Seconds(4);
124 config->attempts = 7;
125 config->rotate = true;
126 config->append_to_multi_label_name = true;
127 config->search.clear();
128 config->search.push_back("chromium.org");
129 config->search.push_back("example.com");
130
131 config->nameservers.clear();
132 for (unsigned i = 0; i < std::size(kNameserversIPv4) && i < MAXNS; ++i) {
133 IPAddress ip;
134 EXPECT_TRUE(ip.AssignFromIPLiteral(kNameserversIPv4[i]));
135 config->nameservers.push_back(IPEndPoint(ip, NS_DEFAULTPORT + i));
136 }
137
138 #if BUILDFLAG(IS_CHROMEOS)
139 for (unsigned i = 0; i < std::size(kNameserversIPv6) && i < MAXNS; ++i) {
140 if (!kNameserversIPv6[i])
141 continue;
142 IPAddress ip;
143 EXPECT_TRUE(ip.AssignFromIPLiteral(kNameserversIPv6[i]));
144 config->nameservers[i] = IPEndPoint(ip, NS_DEFAULTPORT - i);
145 }
146 #endif
147 }
148
TEST(DnsConfigServicePosixTest,CreateAndDestroy)149 TEST(DnsConfigServicePosixTest, CreateAndDestroy) {
150 // Regression test to verify crash does not occur if DnsConfigServicePosix
151 // instance is destroyed without calling WatchConfig()
152 base::test::TaskEnvironment task_environment(
153 base::test::TaskEnvironment::MainThreadType::IO);
154
155 auto service = std::make_unique<internal::DnsConfigServicePosix>();
156 service.reset();
157 task_environment.RunUntilIdle();
158 }
159
TEST(DnsConfigServicePosixTest,ConvertResStateToDnsConfig)160 TEST(DnsConfigServicePosixTest, ConvertResStateToDnsConfig) {
161 struct __res_state res;
162 InitializeResState(&res);
163 std::optional<DnsConfig> config = internal::ConvertResStateToDnsConfig(res);
164 CloseResState(&res);
165 ASSERT_TRUE(config.has_value());
166 EXPECT_TRUE(config->IsValid());
167
168 DnsConfig expected_config;
169 EXPECT_FALSE(expected_config.EqualsIgnoreHosts(config.value()));
170 InitializeExpectedConfig(&expected_config);
171 EXPECT_TRUE(expected_config.EqualsIgnoreHosts(config.value()));
172 }
173
TEST(DnsConfigServicePosixTest,RejectEmptyNameserver)174 TEST(DnsConfigServicePosixTest, RejectEmptyNameserver) {
175 struct __res_state res = {};
176 res.options = RES_INIT | RES_RECURSE | RES_DEFNAMES | RES_DNSRCH;
177 const char kDnsrch[] = "chromium.org";
178 memcpy(res.defdname, kDnsrch, sizeof(kDnsrch));
179 res.dnsrch[0] = res.defdname;
180
181 struct sockaddr_in sa = {};
182 sa.sin_family = AF_INET;
183 sa.sin_port = base::HostToNet16(NS_DEFAULTPORT);
184 sa.sin_addr.s_addr = INADDR_ANY;
185 res.nsaddr_list[0] = sa;
186 sa.sin_addr.s_addr = 0xCAFE1337;
187 res.nsaddr_list[1] = sa;
188 res.nscount = 2;
189
190 EXPECT_FALSE(internal::ConvertResStateToDnsConfig(res));
191
192 sa.sin_addr.s_addr = 0xDEADBEEF;
193 res.nsaddr_list[0] = sa;
194 EXPECT_TRUE(internal::ConvertResStateToDnsConfig(res));
195 }
196
TEST(DnsConfigServicePosixTest,DestroyWhileJobsWorking)197 TEST(DnsConfigServicePosixTest, DestroyWhileJobsWorking) {
198 // Regression test to verify crash does not occur if DnsConfigServicePosix
199 // instance is destroyed while SerialWorker jobs have posted to worker pool.
200 base::test::TaskEnvironment task_environment(
201 base::test::TaskEnvironment::MainThreadType::IO,
202 base::test::TaskEnvironment::TimeSource::MOCK_TIME);
203
204 auto service = std::make_unique<internal::DnsConfigServicePosix>();
205 // Call WatchConfig() which also tests ReadConfig().
206 service->WatchConfig(base::BindRepeating(&DummyConfigCallback));
207 service.reset();
208 task_environment.FastForwardUntilNoTasksRemain();
209 }
210
TEST(DnsConfigServicePosixTest,DestroyOnDifferentThread)211 TEST(DnsConfigServicePosixTest, DestroyOnDifferentThread) {
212 // Regression test to verify crash does not occur if DnsConfigServicePosix
213 // instance is destroyed on another thread.
214 base::test::TaskEnvironment task_environment;
215
216 scoped_refptr<base::SequencedTaskRunner> runner =
217 base::ThreadPool::CreateSequencedTaskRunner({base::MayBlock()});
218 std::unique_ptr<internal::DnsConfigServicePosix, base::OnTaskRunnerDeleter>
219 service(new internal::DnsConfigServicePosix(),
220 base::OnTaskRunnerDeleter(runner));
221
222 runner->PostTask(FROM_HERE,
223 base::BindOnce(&internal::DnsConfigServicePosix::WatchConfig,
224 base::Unretained(service.get()),
225 base::BindRepeating(&DummyConfigCallback)));
226 service.reset();
227 task_environment.RunUntilIdle();
228 }
229
230 } // namespace
231
232
233 } // namespace net
234