1 // Copyright 2021 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_linux.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/files/file_util.h"
23 #include "base/functional/bind.h"
24 #include "base/memory/raw_ptr.h"
25 #include "base/memory/scoped_refptr.h"
26 #include "base/run_loop.h"
27 #include "base/sys_byteorder.h"
28 #include "base/task/sequenced_task_runner.h"
29 #include "base/task/single_thread_task_runner.h"
30 #include "base/task/task_traits.h"
31 #include "base/task/thread_pool.h"
32 #include "base/test/metrics/histogram_tester.h"
33 #include "base/test/task_environment.h"
34 #include "base/test/test_waitable_event.h"
35 #include "net/base/ip_address.h"
36 #include "net/base/test_completion_callback.h"
37 #include "net/dns/dns_config.h"
38 #include "net/dns/dns_config_service.h"
39 #include "net/dns/nsswitch_reader.h"
40 #include "net/dns/public/dns_protocol.h"
41 #include "net/test/test_with_task_environment.h"
42 #include "testing/gmock/include/gmock/gmock.h"
43 #include "testing/gtest/include/gtest/gtest.h"
44
45 namespace net {
46
47 namespace {
48
49 // MAXNS is normally 3, but let's test 4 if possible.
50 const char* const kNameserversIPv4[] = {
51 "8.8.8.8",
52 "192.168.1.1",
53 "63.1.2.4",
54 "1.0.0.1",
55 };
56
57 const char* const kNameserversIPv6[] = {
58 nullptr,
59 "2001:db8::42",
60 nullptr,
61 "::FFFF:129.144.52.38",
62 };
63
64 const std::vector<NsswitchReader::ServiceSpecification> kBasicNsswitchConfig = {
65 NsswitchReader::ServiceSpecification(NsswitchReader::Service::kFiles),
66 NsswitchReader::ServiceSpecification(NsswitchReader::Service::kDns)};
67
DummyConfigCallback(const DnsConfig & config)68 void DummyConfigCallback(const DnsConfig& config) {
69 // Do nothing
70 }
71
72 // Fills in |res| with sane configuration.
InitializeResState(res_state res)73 void InitializeResState(res_state res) {
74 memset(res, 0, sizeof(*res));
75 res->options =
76 RES_INIT | RES_RECURSE | RES_DEFNAMES | RES_DNSRCH | RES_ROTATE;
77 res->ndots = 2;
78 res->retrans = 4;
79 res->retry = 7;
80
81 const char kDnsrch[] =
82 "chromium.org"
83 "\0"
84 "example.com";
85 memcpy(res->defdname, kDnsrch, sizeof(kDnsrch));
86 res->dnsrch[0] = res->defdname;
87 res->dnsrch[1] = res->defdname + sizeof("chromium.org");
88
89 for (unsigned i = 0; i < std::size(kNameserversIPv4) && i < MAXNS; ++i) {
90 struct sockaddr_in sa;
91 sa.sin_family = AF_INET;
92 sa.sin_port = base::HostToNet16(NS_DEFAULTPORT + i);
93 inet_pton(AF_INET, kNameserversIPv4[i], &sa.sin_addr);
94 res->nsaddr_list[i] = sa;
95 ++res->nscount;
96 }
97
98 // Install IPv6 addresses, replacing the corresponding IPv4 addresses.
99 unsigned nscount6 = 0;
100 for (unsigned i = 0; i < std::size(kNameserversIPv6) && i < MAXNS; ++i) {
101 if (!kNameserversIPv6[i])
102 continue;
103 // Must use malloc to mimic res_ninit. Expect to be freed in
104 // `TestResolvReader::CloseResState()`.
105 struct sockaddr_in6* sa6;
106 sa6 = static_cast<sockaddr_in6*>(malloc(sizeof(*sa6)));
107 memset(sa6, 0, sizeof(*sa6));
108 sa6->sin6_family = AF_INET6;
109 sa6->sin6_port = base::HostToNet16(NS_DEFAULTPORT - i);
110 inet_pton(AF_INET6, kNameserversIPv6[i], &sa6->sin6_addr);
111 res->_u._ext.nsaddrs[i] = sa6;
112 memset(&res->nsaddr_list[i], 0, sizeof res->nsaddr_list[i]);
113 ++nscount6;
114 }
115 res->_u._ext.nscount6 = nscount6;
116 }
117
InitializeExpectedConfig(DnsConfig * config)118 void InitializeExpectedConfig(DnsConfig* config) {
119 config->ndots = 2;
120 config->fallback_period = kDnsDefaultFallbackPeriod;
121 config->attempts = 7;
122 config->rotate = true;
123 config->append_to_multi_label_name = true;
124 config->search.clear();
125 config->search.push_back("chromium.org");
126 config->search.push_back("example.com");
127
128 config->nameservers.clear();
129 for (unsigned i = 0; i < std::size(kNameserversIPv4) && i < MAXNS; ++i) {
130 IPAddress ip;
131 EXPECT_TRUE(ip.AssignFromIPLiteral(kNameserversIPv4[i]));
132 config->nameservers.emplace_back(ip, NS_DEFAULTPORT + i);
133 }
134
135 for (unsigned i = 0; i < std::size(kNameserversIPv6) && i < MAXNS; ++i) {
136 if (!kNameserversIPv6[i])
137 continue;
138 IPAddress ip;
139 EXPECT_TRUE(ip.AssignFromIPLiteral(kNameserversIPv6[i]));
140 config->nameservers[i] = IPEndPoint(ip, NS_DEFAULTPORT - i);
141 }
142 }
143
144 class CallbackHelper {
145 public:
WaitForResult()146 std::optional<DnsConfig> WaitForResult() {
147 run_loop_.Run();
148 return GetResult();
149 }
150
GetResult()151 std::optional<DnsConfig> GetResult() {
152 std::optional<DnsConfig> result = std::move(config_);
153 return result;
154 }
155
GetCallback()156 DnsConfigService::CallbackType GetCallback() {
157 return base::BindRepeating(&CallbackHelper::OnComplete,
158 base::Unretained(this));
159 }
160
161 private:
OnComplete(const DnsConfig & config)162 void OnComplete(const DnsConfig& config) {
163 config_ = config;
164 run_loop_.Quit();
165 }
166
167 std::optional<DnsConfig> config_;
168 base::RunLoop run_loop_;
169 };
170
171 // Helper to allow blocking on some point in the ThreadPool.
172 class BlockingHelper {
173 public:
~BlockingHelper()174 ~BlockingHelper() { EXPECT_EQ(state_, State::kUnblocked); }
175
176 // Called by the test code to wait for the block point to be reached.
WaitUntilBlocked()177 void WaitUntilBlocked() {
178 CHECK_EQ(state_, State::kUnblocked);
179 state_ = State::kRunningUntilBlock;
180
181 CHECK(!run_loop_ || !run_loop_->running());
182 run_loop_.emplace();
183 run_loop_->Run();
184
185 CHECK_EQ(state_, State::kBlocked);
186 }
187
188 // Called by the ThreadPool code on reaching the block point.
WaitUntilUnblocked()189 void WaitUntilUnblocked() {
190 block_event_.Reset();
191 task_runner_->PostTask(FROM_HERE,
192 base::BindOnce(&BlockingHelper::OnBlockedCallback,
193 base::Unretained(this)));
194 block_event_.Wait();
195 blocker_event_.Signal();
196 }
197
198 // Called by the test code to unblock the ThreadPool code.
Unblock()199 void Unblock() {
200 CHECK_EQ(state_, State::kBlocked);
201 CHECK(!block_event_.IsSignaled());
202
203 state_ = State::kUnblocked;
204
205 blocker_event_.Reset();
206 block_event_.Signal();
207 blocker_event_.Wait();
208 }
209
210 private:
211 enum class State {
212 kRunningUntilBlock,
213 kBlocked,
214 kUnblocked,
215 };
216
OnBlockedCallback()217 void OnBlockedCallback() {
218 CHECK_EQ(state_, State::kRunningUntilBlock);
219 CHECK(run_loop_.has_value());
220 CHECK(run_loop_->running());
221
222 state_ = State::kBlocked;
223 run_loop_->Quit();
224 }
225
226 State state_ = State::kUnblocked;
227 std::optional<base::RunLoop> run_loop_;
228 base::TestWaitableEvent block_event_;
229 base::TestWaitableEvent blocker_event_;
230 scoped_refptr<base::SingleThreadTaskRunner> task_runner_ =
231 base::SingleThreadTaskRunner::GetCurrentDefault();
232 };
233
234 class TestScopedResState : public ScopedResState {
235 public:
TestScopedResState(std::unique_ptr<struct __res_state> res)236 explicit TestScopedResState(std::unique_ptr<struct __res_state> res)
237 : res_(std::move(res)) {}
238
~TestScopedResState()239 ~TestScopedResState() override {
240 if (res_) {
241 // Assume `res->_u._ext.nsaddrs` memory allocated via malloc, e.g. by
242 // `InitializeResState()`.
243 for (int i = 0; i < res_->nscount; ++i) {
244 if (res_->_u._ext.nsaddrs[i] != nullptr)
245 free(res_->_u._ext.nsaddrs[i]);
246 }
247 }
248 }
249
state() const250 const struct __res_state& state() const override {
251 EXPECT_TRUE(res_);
252 return *res_;
253 }
254
255 private:
256 std::unique_ptr<struct __res_state> res_;
257 };
258
259 class TestResolvReader : public ResolvReader {
260 public:
261 ~TestResolvReader() override = default;
262
set_value(std::unique_ptr<struct __res_state> value)263 void set_value(std::unique_ptr<struct __res_state> value) {
264 CHECK(!value_);
265 value_ = std::make_unique<TestScopedResState>(std::move(value));
266 }
267
closed()268 bool closed() { return !value_; }
269
270 // ResolvReader:
GetResState()271 std::unique_ptr<ScopedResState> GetResState() override {
272 if (blocking_helper_)
273 blocking_helper_->WaitUntilUnblocked();
274
275 CHECK(value_);
276 return std::move(value_);
277 }
278
set_blocking_helper(BlockingHelper * blocking_helper)279 void set_blocking_helper(BlockingHelper* blocking_helper) {
280 blocking_helper_ = blocking_helper;
281 }
282
283 private:
284 std::unique_ptr<TestScopedResState> value_;
285 raw_ptr<BlockingHelper> blocking_helper_ = nullptr;
286 };
287
288 class TestNsswitchReader : public NsswitchReader {
289 public:
set_value(std::vector<ServiceSpecification> value)290 void set_value(std::vector<ServiceSpecification> value) {
291 value_ = std::move(value);
292 }
293
294 // NsswitchReader:
ReadAndParseHosts()295 std::vector<ServiceSpecification> ReadAndParseHosts() override {
296 return value_;
297 }
298
299 private:
300 std::vector<ServiceSpecification> value_;
301 };
302
303 class DnsConfigServiceLinuxTest : public ::testing::Test,
304 public WithTaskEnvironment {
305 public:
DnsConfigServiceLinuxTest()306 DnsConfigServiceLinuxTest()
307 : WithTaskEnvironment(
308 base::test::TaskEnvironment::TimeSource::MOCK_TIME) {
309 auto resolv_reader = std::make_unique<TestResolvReader>();
310 resolv_reader_ = resolv_reader.get();
311 service_.set_resolv_reader_for_testing(std::move(resolv_reader));
312
313 auto nsswitch_reader = std::make_unique<TestNsswitchReader>();
314 nsswitch_reader_ = nsswitch_reader.get();
315 service_.set_nsswitch_reader_for_testing(std::move(nsswitch_reader));
316 }
317
318 protected:
319 internal::DnsConfigServiceLinux service_;
320 raw_ptr<TestResolvReader> resolv_reader_;
321 raw_ptr<TestNsswitchReader> nsswitch_reader_;
322 };
323
324 // Regression test to verify crash does not occur if DnsConfigServiceLinux
325 // instance is destroyed without calling WatchConfig()
TEST_F(DnsConfigServiceLinuxTest,CreateAndDestroy)326 TEST_F(DnsConfigServiceLinuxTest, CreateAndDestroy) {
327 auto service = std::make_unique<internal::DnsConfigServiceLinux>();
328 service.reset();
329 RunUntilIdle();
330 }
331
TEST_F(DnsConfigServiceLinuxTest,ConvertResStateToDnsConfig)332 TEST_F(DnsConfigServiceLinuxTest, ConvertResStateToDnsConfig) {
333 auto res = std::make_unique<struct __res_state>();
334 InitializeResState(res.get());
335 resolv_reader_->set_value(std::move(res));
336 nsswitch_reader_->set_value(kBasicNsswitchConfig);
337
338 CallbackHelper callback_helper;
339 service_.ReadConfig(callback_helper.GetCallback());
340 std::optional<DnsConfig> config = callback_helper.WaitForResult();
341
342 ASSERT_TRUE(config.has_value());
343 EXPECT_TRUE(config->IsValid());
344
345 DnsConfig expected_config;
346 EXPECT_FALSE(expected_config.EqualsIgnoreHosts(config.value()));
347 InitializeExpectedConfig(&expected_config);
348 EXPECT_TRUE(expected_config.EqualsIgnoreHosts(config.value()));
349
350 EXPECT_TRUE(resolv_reader_->closed());
351 }
352
TEST_F(DnsConfigServiceLinuxTest,RejectEmptyNameserver)353 TEST_F(DnsConfigServiceLinuxTest, RejectEmptyNameserver) {
354 auto res = std::make_unique<struct __res_state>();
355 res->options = RES_INIT | RES_RECURSE | RES_DEFNAMES | RES_DNSRCH;
356 const char kDnsrch[] = "chromium.org";
357 memcpy(res->defdname, kDnsrch, sizeof(kDnsrch));
358 res->dnsrch[0] = res->defdname;
359
360 struct sockaddr_in sa = {};
361 sa.sin_family = AF_INET;
362 sa.sin_port = base::HostToNet16(NS_DEFAULTPORT);
363 sa.sin_addr.s_addr = INADDR_ANY;
364 res->nsaddr_list[0] = sa;
365 sa.sin_addr.s_addr = 0xCAFE1337;
366 res->nsaddr_list[1] = sa;
367 res->nscount = 2;
368
369 resolv_reader_->set_value(std::move(res));
370 nsswitch_reader_->set_value(kBasicNsswitchConfig);
371
372 CallbackHelper callback_helper;
373 service_.ReadConfig(callback_helper.GetCallback());
374 RunUntilIdle();
375 std::optional<DnsConfig> config = callback_helper.GetResult();
376
377 EXPECT_FALSE(config.has_value());
378 EXPECT_TRUE(resolv_reader_->closed());
379 }
380
TEST_F(DnsConfigServiceLinuxTest,AcceptNonEmptyNameserver)381 TEST_F(DnsConfigServiceLinuxTest, AcceptNonEmptyNameserver) {
382 auto res = std::make_unique<struct __res_state>();
383 res->options = RES_INIT | RES_RECURSE | RES_DEFNAMES | RES_DNSRCH;
384 const char kDnsrch[] = "chromium.org";
385 memcpy(res->defdname, kDnsrch, sizeof(kDnsrch));
386 res->dnsrch[0] = res->defdname;
387
388 struct sockaddr_in sa = {};
389 sa.sin_family = AF_INET;
390 sa.sin_port = base::HostToNet16(NS_DEFAULTPORT);
391 sa.sin_addr.s_addr = 0xDEADBEEF;
392 res->nsaddr_list[0] = sa;
393 sa.sin_addr.s_addr = 0xCAFE1337;
394 res->nsaddr_list[1] = sa;
395 res->nscount = 2;
396
397 resolv_reader_->set_value(std::move(res));
398 nsswitch_reader_->set_value(kBasicNsswitchConfig);
399
400 CallbackHelper callback_helper;
401 service_.ReadConfig(callback_helper.GetCallback());
402 std::optional<DnsConfig> config = callback_helper.WaitForResult();
403
404 EXPECT_TRUE(config.has_value());
405 EXPECT_TRUE(resolv_reader_->closed());
406 }
407
408 // Regression test to verify crash does not occur if DnsConfigServiceLinux
409 // instance is destroyed while SerialWorker jobs have posted to worker pool.
TEST_F(DnsConfigServiceLinuxTest,DestroyWhileJobsWorking)410 TEST_F(DnsConfigServiceLinuxTest, DestroyWhileJobsWorking) {
411 auto service = std::make_unique<internal::DnsConfigServiceLinux>();
412 // Call WatchConfig() which also tests ReadConfig().
413 service->WatchConfig(base::BindRepeating(&DummyConfigCallback));
414 service.reset();
415 FastForwardUntilNoTasksRemain();
416 }
417
418 // Regression test to verify crash does not occur if DnsConfigServiceLinux
419 // instance is destroyed on another thread.
TEST_F(DnsConfigServiceLinuxTest,DestroyOnDifferentThread)420 TEST_F(DnsConfigServiceLinuxTest, DestroyOnDifferentThread) {
421 scoped_refptr<base::SequencedTaskRunner> runner =
422 base::ThreadPool::CreateSequencedTaskRunner({base::MayBlock()});
423 std::unique_ptr<internal::DnsConfigServiceLinux, base::OnTaskRunnerDeleter>
424 service(new internal::DnsConfigServiceLinux(),
425 base::OnTaskRunnerDeleter(runner));
426
427 runner->PostTask(FROM_HERE,
428 base::BindOnce(&internal::DnsConfigServiceLinux::WatchConfig,
429 base::Unretained(service.get()),
430 base::BindRepeating(&DummyConfigCallback)));
431 service.reset();
432 RunUntilIdle();
433 }
434
TEST_F(DnsConfigServiceLinuxTest,AcceptsBasicNsswitchConfig)435 TEST_F(DnsConfigServiceLinuxTest, AcceptsBasicNsswitchConfig) {
436 auto res = std::make_unique<struct __res_state>();
437 InitializeResState(res.get());
438 resolv_reader_->set_value(std::move(res));
439 nsswitch_reader_->set_value(kBasicNsswitchConfig);
440
441 CallbackHelper callback_helper;
442 service_.ReadConfig(callback_helper.GetCallback());
443 std::optional<DnsConfig> config = callback_helper.WaitForResult();
444 EXPECT_TRUE(resolv_reader_->closed());
445
446 ASSERT_TRUE(config.has_value());
447 EXPECT_TRUE(config->IsValid());
448 EXPECT_FALSE(config->unhandled_options);
449 }
450
TEST_F(DnsConfigServiceLinuxTest,IgnoresBasicNsswitchConfigIfResolvConfigUnhandled)451 TEST_F(DnsConfigServiceLinuxTest,
452 IgnoresBasicNsswitchConfigIfResolvConfigUnhandled) {
453 auto res = std::make_unique<struct __res_state>();
454 InitializeResState(res.get());
455 res->options |= RES_USE_DNSSEC; // Expect unhandled.
456 resolv_reader_->set_value(std::move(res));
457 nsswitch_reader_->set_value(kBasicNsswitchConfig);
458
459 CallbackHelper callback_helper;
460 service_.ReadConfig(callback_helper.GetCallback());
461 std::optional<DnsConfig> config = callback_helper.WaitForResult();
462 EXPECT_TRUE(resolv_reader_->closed());
463
464 ASSERT_TRUE(config.has_value());
465 EXPECT_TRUE(config->IsValid());
466 EXPECT_TRUE(config->unhandled_options);
467 }
468
TEST_F(DnsConfigServiceLinuxTest,RejectsNsswitchWithoutFiles)469 TEST_F(DnsConfigServiceLinuxTest, RejectsNsswitchWithoutFiles) {
470 auto res = std::make_unique<struct __res_state>();
471 InitializeResState(res.get());
472 resolv_reader_->set_value(std::move(res));
473
474 nsswitch_reader_->set_value(
475 {NsswitchReader::ServiceSpecification(NsswitchReader::Service::kDns)});
476
477 CallbackHelper callback_helper;
478 service_.ReadConfig(callback_helper.GetCallback());
479 std::optional<DnsConfig> config = callback_helper.WaitForResult();
480 EXPECT_TRUE(resolv_reader_->closed());
481
482 ASSERT_TRUE(config.has_value());
483 EXPECT_TRUE(config->IsValid());
484 EXPECT_TRUE(config->unhandled_options);
485 }
486
TEST_F(DnsConfigServiceLinuxTest,RejectsWithExtraFiles)487 TEST_F(DnsConfigServiceLinuxTest, RejectsWithExtraFiles) {
488 auto res = std::make_unique<struct __res_state>();
489 InitializeResState(res.get());
490 resolv_reader_->set_value(std::move(res));
491
492 nsswitch_reader_->set_value(
493 {NsswitchReader::ServiceSpecification(NsswitchReader::Service::kFiles),
494 NsswitchReader::ServiceSpecification(NsswitchReader::Service::kFiles),
495 NsswitchReader::ServiceSpecification(NsswitchReader::Service::kDns)});
496
497 CallbackHelper callback_helper;
498 service_.ReadConfig(callback_helper.GetCallback());
499 std::optional<DnsConfig> config = callback_helper.WaitForResult();
500 EXPECT_TRUE(resolv_reader_->closed());
501
502 ASSERT_TRUE(config.has_value());
503 EXPECT_TRUE(config->IsValid());
504 EXPECT_TRUE(config->unhandled_options);
505 }
506
TEST_F(DnsConfigServiceLinuxTest,IgnoresRedundantActions)507 TEST_F(DnsConfigServiceLinuxTest, IgnoresRedundantActions) {
508 auto res = std::make_unique<struct __res_state>();
509 InitializeResState(res.get());
510 resolv_reader_->set_value(std::move(res));
511
512 nsswitch_reader_->set_value(
513 {NsswitchReader::ServiceSpecification(
514 NsswitchReader::Service::kFiles,
515 {{/*negated=*/false, NsswitchReader::Status::kSuccess,
516 NsswitchReader::Action::kReturn},
517 {/*negated=*/true, NsswitchReader::Status::kSuccess,
518 NsswitchReader::Action::kContinue}}),
519 NsswitchReader::ServiceSpecification(
520 NsswitchReader::Service::kDns,
521 {{/*negated=*/false, NsswitchReader::Status::kSuccess,
522 NsswitchReader::Action::kReturn},
523 {/*negated=*/true, NsswitchReader::Status::kSuccess,
524 NsswitchReader::Action::kContinue}})});
525
526 CallbackHelper callback_helper;
527 service_.ReadConfig(callback_helper.GetCallback());
528 std::optional<DnsConfig> config = callback_helper.WaitForResult();
529 EXPECT_TRUE(resolv_reader_->closed());
530
531 ASSERT_TRUE(config.has_value());
532 EXPECT_TRUE(config->IsValid());
533 EXPECT_FALSE(config->unhandled_options);
534 }
535
TEST_F(DnsConfigServiceLinuxTest,RejectsInconsistentActions)536 TEST_F(DnsConfigServiceLinuxTest, RejectsInconsistentActions) {
537 auto res = std::make_unique<struct __res_state>();
538 InitializeResState(res.get());
539 resolv_reader_->set_value(std::move(res));
540
541 nsswitch_reader_->set_value(
542 {NsswitchReader::ServiceSpecification(NsswitchReader::Service::kFiles),
543 NsswitchReader::ServiceSpecification(
544 NsswitchReader::Service::kDns,
545 {{/*negated=*/false, NsswitchReader::Status::kUnavailable,
546 NsswitchReader::Action::kReturn},
547 {/*negated=*/true, NsswitchReader::Status::kSuccess,
548 NsswitchReader::Action::kContinue}})});
549
550 CallbackHelper callback_helper;
551 service_.ReadConfig(callback_helper.GetCallback());
552 std::optional<DnsConfig> config = callback_helper.WaitForResult();
553 EXPECT_TRUE(resolv_reader_->closed());
554
555 ASSERT_TRUE(config.has_value());
556 EXPECT_TRUE(config->IsValid());
557 EXPECT_TRUE(config->unhandled_options);
558 }
559
TEST_F(DnsConfigServiceLinuxTest,RejectsWithBadFilesSuccessAction)560 TEST_F(DnsConfigServiceLinuxTest, RejectsWithBadFilesSuccessAction) {
561 auto res = std::make_unique<struct __res_state>();
562 InitializeResState(res.get());
563 resolv_reader_->set_value(std::move(res));
564
565 nsswitch_reader_->set_value(
566 {NsswitchReader::ServiceSpecification(
567 NsswitchReader::Service::kFiles,
568 {{/*negated=*/false, NsswitchReader::Status::kSuccess,
569 NsswitchReader::Action::kContinue}}),
570 NsswitchReader::ServiceSpecification(NsswitchReader::Service::kDns)});
571
572 CallbackHelper callback_helper;
573 service_.ReadConfig(callback_helper.GetCallback());
574 std::optional<DnsConfig> config = callback_helper.WaitForResult();
575 EXPECT_TRUE(resolv_reader_->closed());
576
577 ASSERT_TRUE(config.has_value());
578 EXPECT_TRUE(config->IsValid());
579 EXPECT_TRUE(config->unhandled_options);
580 }
581
TEST_F(DnsConfigServiceLinuxTest,RejectsWithBadFilesNotFoundAction)582 TEST_F(DnsConfigServiceLinuxTest, RejectsWithBadFilesNotFoundAction) {
583 auto res = std::make_unique<struct __res_state>();
584 InitializeResState(res.get());
585 resolv_reader_->set_value(std::move(res));
586
587 nsswitch_reader_->set_value(
588 {NsswitchReader::ServiceSpecification(
589 NsswitchReader::Service::kFiles,
590 {{/*negated=*/false, NsswitchReader::Status::kNotFound,
591 NsswitchReader::Action::kReturn}}),
592 NsswitchReader::ServiceSpecification(NsswitchReader::Service::kDns)});
593
594 CallbackHelper callback_helper;
595 service_.ReadConfig(callback_helper.GetCallback());
596 std::optional<DnsConfig> config = callback_helper.WaitForResult();
597 EXPECT_TRUE(resolv_reader_->closed());
598
599 ASSERT_TRUE(config.has_value());
600 EXPECT_TRUE(config->IsValid());
601 EXPECT_TRUE(config->unhandled_options);
602 }
603
TEST_F(DnsConfigServiceLinuxTest,RejectsNsswitchWithoutDns)604 TEST_F(DnsConfigServiceLinuxTest, RejectsNsswitchWithoutDns) {
605 auto res = std::make_unique<struct __res_state>();
606 InitializeResState(res.get());
607 resolv_reader_->set_value(std::move(res));
608
609 nsswitch_reader_->set_value(
610 {NsswitchReader::ServiceSpecification(NsswitchReader::Service::kFiles)});
611
612 CallbackHelper callback_helper;
613 service_.ReadConfig(callback_helper.GetCallback());
614 std::optional<DnsConfig> config = callback_helper.WaitForResult();
615 EXPECT_TRUE(resolv_reader_->closed());
616
617 ASSERT_TRUE(config.has_value());
618 EXPECT_TRUE(config->IsValid());
619 EXPECT_TRUE(config->unhandled_options);
620 }
621
TEST_F(DnsConfigServiceLinuxTest,RejectsWithBadDnsSuccessAction)622 TEST_F(DnsConfigServiceLinuxTest, RejectsWithBadDnsSuccessAction) {
623 auto res = std::make_unique<struct __res_state>();
624 InitializeResState(res.get());
625 resolv_reader_->set_value(std::move(res));
626
627 nsswitch_reader_->set_value(
628 {NsswitchReader::ServiceSpecification(NsswitchReader::Service::kFiles),
629 NsswitchReader::ServiceSpecification(
630 NsswitchReader::Service::kDns,
631 {{/*negated=*/false, NsswitchReader::Status::kSuccess,
632 NsswitchReader::Action::kContinue}})});
633
634 CallbackHelper callback_helper;
635 service_.ReadConfig(callback_helper.GetCallback());
636 std::optional<DnsConfig> config = callback_helper.WaitForResult();
637 EXPECT_TRUE(resolv_reader_->closed());
638
639 ASSERT_TRUE(config.has_value());
640 EXPECT_TRUE(config->IsValid());
641 EXPECT_TRUE(config->unhandled_options);
642 }
643
TEST_F(DnsConfigServiceLinuxTest,RejectsNsswitchWithMisorderedServices)644 TEST_F(DnsConfigServiceLinuxTest, RejectsNsswitchWithMisorderedServices) {
645 auto res = std::make_unique<struct __res_state>();
646 InitializeResState(res.get());
647 resolv_reader_->set_value(std::move(res));
648
649 nsswitch_reader_->set_value(
650 {NsswitchReader::ServiceSpecification(NsswitchReader::Service::kDns),
651 NsswitchReader::ServiceSpecification(NsswitchReader::Service::kFiles)});
652
653 CallbackHelper callback_helper;
654 service_.ReadConfig(callback_helper.GetCallback());
655 std::optional<DnsConfig> config = callback_helper.WaitForResult();
656 EXPECT_TRUE(resolv_reader_->closed());
657
658 ASSERT_TRUE(config.has_value());
659 EXPECT_TRUE(config->IsValid());
660 EXPECT_TRUE(config->unhandled_options);
661 }
662
TEST_F(DnsConfigServiceLinuxTest,AcceptsIncompatibleNsswitchServicesAfterDns)663 TEST_F(DnsConfigServiceLinuxTest, AcceptsIncompatibleNsswitchServicesAfterDns) {
664 auto res = std::make_unique<struct __res_state>();
665 InitializeResState(res.get());
666 resolv_reader_->set_value(std::move(res));
667
668 nsswitch_reader_->set_value(
669 {NsswitchReader::ServiceSpecification(NsswitchReader::Service::kFiles),
670 NsswitchReader::ServiceSpecification(NsswitchReader::Service::kDns),
671 NsswitchReader::ServiceSpecification(NsswitchReader::Service::kMdns)});
672
673 CallbackHelper callback_helper;
674 service_.ReadConfig(callback_helper.GetCallback());
675 std::optional<DnsConfig> config = callback_helper.WaitForResult();
676 EXPECT_TRUE(resolv_reader_->closed());
677
678 ASSERT_TRUE(config.has_value());
679 EXPECT_TRUE(config->IsValid());
680 EXPECT_FALSE(config->unhandled_options);
681 }
682
TEST_F(DnsConfigServiceLinuxTest,RejectsNsswitchMdns)683 TEST_F(DnsConfigServiceLinuxTest, RejectsNsswitchMdns) {
684 auto res = std::make_unique<struct __res_state>();
685 InitializeResState(res.get());
686 resolv_reader_->set_value(std::move(res));
687
688 nsswitch_reader_->set_value(
689 {NsswitchReader::ServiceSpecification(NsswitchReader::Service::kFiles),
690 NsswitchReader::ServiceSpecification(NsswitchReader::Service::kMdns),
691 NsswitchReader::ServiceSpecification(NsswitchReader::Service::kDns)});
692
693 CallbackHelper callback_helper;
694 service_.ReadConfig(callback_helper.GetCallback());
695 std::optional<DnsConfig> config = callback_helper.WaitForResult();
696 EXPECT_TRUE(resolv_reader_->closed());
697
698 ASSERT_TRUE(config.has_value());
699 EXPECT_TRUE(config->IsValid());
700 EXPECT_TRUE(config->unhandled_options);
701 }
702
TEST_F(DnsConfigServiceLinuxTest,RejectsNsswitchMdns4)703 TEST_F(DnsConfigServiceLinuxTest, RejectsNsswitchMdns4) {
704 auto res = std::make_unique<struct __res_state>();
705 InitializeResState(res.get());
706 resolv_reader_->set_value(std::move(res));
707
708 nsswitch_reader_->set_value(
709 {NsswitchReader::ServiceSpecification(NsswitchReader::Service::kFiles),
710 NsswitchReader::ServiceSpecification(NsswitchReader::Service::kMdns4),
711 NsswitchReader::ServiceSpecification(NsswitchReader::Service::kDns)});
712
713 CallbackHelper callback_helper;
714 service_.ReadConfig(callback_helper.GetCallback());
715 std::optional<DnsConfig> config = callback_helper.WaitForResult();
716 EXPECT_TRUE(resolv_reader_->closed());
717
718 ASSERT_TRUE(config.has_value());
719 EXPECT_TRUE(config->IsValid());
720 EXPECT_TRUE(config->unhandled_options);
721 }
722
TEST_F(DnsConfigServiceLinuxTest,RejectsNsswitchMdns6)723 TEST_F(DnsConfigServiceLinuxTest, RejectsNsswitchMdns6) {
724 auto res = std::make_unique<struct __res_state>();
725 InitializeResState(res.get());
726 resolv_reader_->set_value(std::move(res));
727
728 nsswitch_reader_->set_value(
729 {NsswitchReader::ServiceSpecification(NsswitchReader::Service::kFiles),
730 NsswitchReader::ServiceSpecification(NsswitchReader::Service::kMdns6),
731 NsswitchReader::ServiceSpecification(NsswitchReader::Service::kDns)});
732
733 CallbackHelper callback_helper;
734 service_.ReadConfig(callback_helper.GetCallback());
735 std::optional<DnsConfig> config = callback_helper.WaitForResult();
736 EXPECT_TRUE(resolv_reader_->closed());
737
738 ASSERT_TRUE(config.has_value());
739 EXPECT_TRUE(config->IsValid());
740 EXPECT_TRUE(config->unhandled_options);
741 }
742
TEST_F(DnsConfigServiceLinuxTest,AcceptsNsswitchMdnsMinimal)743 TEST_F(DnsConfigServiceLinuxTest, AcceptsNsswitchMdnsMinimal) {
744 auto res = std::make_unique<struct __res_state>();
745 InitializeResState(res.get());
746 resolv_reader_->set_value(std::move(res));
747
748 nsswitch_reader_->set_value(
749 {NsswitchReader::ServiceSpecification(NsswitchReader::Service::kFiles),
750 NsswitchReader::ServiceSpecification(
751 NsswitchReader::Service::kMdnsMinimal),
752 NsswitchReader::ServiceSpecification(
753 NsswitchReader::Service::kMdns4Minimal),
754 NsswitchReader::ServiceSpecification(
755 NsswitchReader::Service::kMdns6Minimal),
756 NsswitchReader::ServiceSpecification(NsswitchReader::Service::kDns)});
757
758 CallbackHelper callback_helper;
759 service_.ReadConfig(callback_helper.GetCallback());
760 std::optional<DnsConfig> config = callback_helper.WaitForResult();
761 EXPECT_TRUE(resolv_reader_->closed());
762
763 ASSERT_TRUE(config.has_value());
764 EXPECT_TRUE(config->IsValid());
765 EXPECT_FALSE(config->unhandled_options);
766 }
767
768 // mdns*_minimal is often paired with [!UNAVAIL=RETURN] or [NOTFOUND=RETURN]
769 // actions. Ensure that is accepted.
TEST_F(DnsConfigServiceLinuxTest,AcceptsNsswitchMdnsMinimalWithCommonActions)770 TEST_F(DnsConfigServiceLinuxTest, AcceptsNsswitchMdnsMinimalWithCommonActions) {
771 auto res = std::make_unique<struct __res_state>();
772 InitializeResState(res.get());
773 resolv_reader_->set_value(std::move(res));
774
775 nsswitch_reader_->set_value(
776 {NsswitchReader::ServiceSpecification(NsswitchReader::Service::kFiles),
777 NsswitchReader::ServiceSpecification(
778 NsswitchReader::Service::kMdnsMinimal,
779 {{/*negated=*/true, NsswitchReader::Status::kUnavailable,
780 NsswitchReader::Action::kReturn}}),
781 NsswitchReader::ServiceSpecification(
782 NsswitchReader::Service::kMdns4Minimal,
783 {{/*negated=*/false, NsswitchReader::Status::kNotFound,
784 NsswitchReader::Action::kReturn}}),
785 NsswitchReader::ServiceSpecification(
786 NsswitchReader::Service::kMdns6Minimal,
787 {{/*negated=*/true, NsswitchReader::Status::kUnavailable,
788 NsswitchReader::Action::kReturn}}),
789 NsswitchReader::ServiceSpecification(NsswitchReader::Service::kDns)});
790
791 CallbackHelper callback_helper;
792 service_.ReadConfig(callback_helper.GetCallback());
793 std::optional<DnsConfig> config = callback_helper.WaitForResult();
794 EXPECT_TRUE(resolv_reader_->closed());
795
796 ASSERT_TRUE(config.has_value());
797 EXPECT_TRUE(config->IsValid());
798 EXPECT_FALSE(config->unhandled_options);
799 }
800
TEST_F(DnsConfigServiceLinuxTest,RejectsWithBadMdnsMinimalUnavailableAction)801 TEST_F(DnsConfigServiceLinuxTest, RejectsWithBadMdnsMinimalUnavailableAction) {
802 auto res = std::make_unique<struct __res_state>();
803 InitializeResState(res.get());
804 resolv_reader_->set_value(std::move(res));
805
806 nsswitch_reader_->set_value(
807 {NsswitchReader::ServiceSpecification(NsswitchReader::Service::kFiles),
808 NsswitchReader::ServiceSpecification(
809 NsswitchReader::Service::kMdnsMinimal,
810 {{/*negated=*/false, NsswitchReader::Status::kUnavailable,
811 NsswitchReader::Action::kReturn}}),
812 NsswitchReader::ServiceSpecification(NsswitchReader::Service::kDns)});
813
814 CallbackHelper callback_helper;
815 service_.ReadConfig(callback_helper.GetCallback());
816 std::optional<DnsConfig> config = callback_helper.WaitForResult();
817 EXPECT_TRUE(resolv_reader_->closed());
818
819 ASSERT_TRUE(config.has_value());
820 EXPECT_TRUE(config->IsValid());
821 EXPECT_TRUE(config->unhandled_options);
822 }
823
TEST_F(DnsConfigServiceLinuxTest,AcceptsNsswitchMyHostname)824 TEST_F(DnsConfigServiceLinuxTest, AcceptsNsswitchMyHostname) {
825 auto res = std::make_unique<struct __res_state>();
826 InitializeResState(res.get());
827 resolv_reader_->set_value(std::move(res));
828
829 nsswitch_reader_->set_value(
830 {NsswitchReader::ServiceSpecification(NsswitchReader::Service::kFiles),
831 NsswitchReader::ServiceSpecification(
832 NsswitchReader::Service::kMyHostname),
833 NsswitchReader::ServiceSpecification(NsswitchReader::Service::kDns)});
834
835 CallbackHelper callback_helper;
836 service_.ReadConfig(callback_helper.GetCallback());
837 std::optional<DnsConfig> config = callback_helper.WaitForResult();
838 EXPECT_TRUE(resolv_reader_->closed());
839
840 ASSERT_TRUE(config.has_value());
841 EXPECT_TRUE(config->IsValid());
842 EXPECT_FALSE(config->unhandled_options);
843 }
844
TEST_F(DnsConfigServiceLinuxTest,RejectsWithBadMyHostnameNotFoundAction)845 TEST_F(DnsConfigServiceLinuxTest, RejectsWithBadMyHostnameNotFoundAction) {
846 auto res = std::make_unique<struct __res_state>();
847 InitializeResState(res.get());
848 resolv_reader_->set_value(std::move(res));
849
850 nsswitch_reader_->set_value(
851 {NsswitchReader::ServiceSpecification(NsswitchReader::Service::kFiles),
852 NsswitchReader::ServiceSpecification(
853 NsswitchReader::Service::kMyHostname,
854 {{/*negated=*/false, NsswitchReader::Status::kNotFound,
855 NsswitchReader::Action::kReturn}}),
856 NsswitchReader::ServiceSpecification(NsswitchReader::Service::kDns)});
857
858 CallbackHelper callback_helper;
859 service_.ReadConfig(callback_helper.GetCallback());
860 std::optional<DnsConfig> config = callback_helper.WaitForResult();
861 EXPECT_TRUE(resolv_reader_->closed());
862
863 ASSERT_TRUE(config.has_value());
864 EXPECT_TRUE(config->IsValid());
865 EXPECT_TRUE(config->unhandled_options);
866 }
867
TEST_F(DnsConfigServiceLinuxTest,RejectsNsswitchResolve)868 TEST_F(DnsConfigServiceLinuxTest, RejectsNsswitchResolve) {
869 auto res = std::make_unique<struct __res_state>();
870 InitializeResState(res.get());
871 resolv_reader_->set_value(std::move(res));
872
873 nsswitch_reader_->set_value(
874 {NsswitchReader::ServiceSpecification(NsswitchReader::Service::kFiles),
875 NsswitchReader::ServiceSpecification(NsswitchReader::Service::kResolve),
876 NsswitchReader::ServiceSpecification(NsswitchReader::Service::kDns)});
877
878 CallbackHelper callback_helper;
879 service_.ReadConfig(callback_helper.GetCallback());
880 std::optional<DnsConfig> config = callback_helper.WaitForResult();
881 EXPECT_TRUE(resolv_reader_->closed());
882
883 ASSERT_TRUE(config.has_value());
884 EXPECT_TRUE(config->IsValid());
885 EXPECT_TRUE(config->unhandled_options);
886 }
887
TEST_F(DnsConfigServiceLinuxTest,RejectsNsswitchNis)888 TEST_F(DnsConfigServiceLinuxTest, RejectsNsswitchNis) {
889 auto res = std::make_unique<struct __res_state>();
890 InitializeResState(res.get());
891 resolv_reader_->set_value(std::move(res));
892
893 nsswitch_reader_->set_value(
894 {NsswitchReader::ServiceSpecification(NsswitchReader::Service::kFiles),
895 NsswitchReader::ServiceSpecification(NsswitchReader::Service::kNis),
896 NsswitchReader::ServiceSpecification(NsswitchReader::Service::kDns)});
897
898 CallbackHelper callback_helper;
899 service_.ReadConfig(callback_helper.GetCallback());
900 std::optional<DnsConfig> config = callback_helper.WaitForResult();
901 EXPECT_TRUE(resolv_reader_->closed());
902
903 ASSERT_TRUE(config.has_value());
904 EXPECT_TRUE(config->IsValid());
905 EXPECT_TRUE(config->unhandled_options);
906 }
907
TEST_F(DnsConfigServiceLinuxTest,RejectsWithBadNisNotFoundAction)908 TEST_F(DnsConfigServiceLinuxTest, RejectsWithBadNisNotFoundAction) {
909 auto res = std::make_unique<struct __res_state>();
910 InitializeResState(res.get());
911 resolv_reader_->set_value(std::move(res));
912
913 nsswitch_reader_->set_value(
914 {NsswitchReader::ServiceSpecification(NsswitchReader::Service::kFiles),
915 NsswitchReader::ServiceSpecification(
916 NsswitchReader::Service::kNis,
917 {{/*negated=*/false, NsswitchReader::Status::kNotFound,
918 NsswitchReader::Action::kReturn}}),
919 NsswitchReader::ServiceSpecification(NsswitchReader::Service::kDns)});
920
921 CallbackHelper callback_helper;
922 service_.ReadConfig(callback_helper.GetCallback());
923 std::optional<DnsConfig> config = callback_helper.WaitForResult();
924 EXPECT_TRUE(resolv_reader_->closed());
925
926 ASSERT_TRUE(config.has_value());
927 EXPECT_TRUE(config->IsValid());
928 EXPECT_TRUE(config->unhandled_options);
929 }
930
TEST_F(DnsConfigServiceLinuxTest,RejectsNsswitchUnknown)931 TEST_F(DnsConfigServiceLinuxTest, RejectsNsswitchUnknown) {
932 auto res = std::make_unique<struct __res_state>();
933 InitializeResState(res.get());
934 resolv_reader_->set_value(std::move(res));
935
936 nsswitch_reader_->set_value(
937 {NsswitchReader::ServiceSpecification(NsswitchReader::Service::kFiles),
938 NsswitchReader::ServiceSpecification(NsswitchReader::Service::kUnknown),
939 NsswitchReader::ServiceSpecification(NsswitchReader::Service::kDns)});
940
941 CallbackHelper callback_helper;
942 service_.ReadConfig(callback_helper.GetCallback());
943 std::optional<DnsConfig> config = callback_helper.WaitForResult();
944 EXPECT_TRUE(resolv_reader_->closed());
945
946 ASSERT_TRUE(config.has_value());
947 EXPECT_TRUE(config->IsValid());
948 EXPECT_TRUE(config->unhandled_options);
949 }
950
TEST_F(DnsConfigServiceLinuxTest,FreshReadsAfterAdditionalTriggers)951 TEST_F(DnsConfigServiceLinuxTest, FreshReadsAfterAdditionalTriggers) {
952 BlockingHelper blocking_helper;
953 resolv_reader_->set_blocking_helper(&blocking_helper);
954
955 CallbackHelper callback_helper;
956 service_.ReadConfig(callback_helper.GetCallback());
957
958 // Expect work to be blocked.
959 blocking_helper.WaitUntilBlocked();
960 ASSERT_FALSE(callback_helper.GetResult());
961
962 // Signal config changes (trigger a few times to confirm only one fresh read
963 // is performed).
964 service_.TriggerOnConfigChangedForTesting(/*succeeded=*/true);
965 service_.TriggerOnConfigChangedForTesting(/*succeeded=*/true);
966 service_.TriggerOnConfigChangedForTesting(/*succeeded=*/true);
967
968 // Initial results (expect to be replaced with second read)
969 auto res = std::make_unique<struct __res_state>();
970 InitializeResState(res.get());
971 resolv_reader_->set_value(std::move(res));
972 nsswitch_reader_->set_value(kBasicNsswitchConfig);
973
974 // Unblock first read (expect no completion because second read should begin
975 // immediately)
976 blocking_helper.Unblock();
977 blocking_helper.WaitUntilBlocked();
978 ASSERT_FALSE(callback_helper.GetResult());
979 EXPECT_TRUE(resolv_reader_->closed());
980
981 // Setup a new config to confirm a fresh read is performed.
982 res = std::make_unique<struct __res_state>();
983 res->options = RES_INIT | RES_RECURSE | RES_DEFNAMES | RES_DNSRCH;
984 struct sockaddr_in sa = {};
985 sa.sin_family = AF_INET;
986 sa.sin_port = base::HostToNet16(1000);
987 inet_pton(AF_INET, "1.2.3.4", &sa.sin_addr);
988 res->nsaddr_list[0] = sa;
989 res->nscount = 1;
990 resolv_reader_->set_value(std::move(res));
991
992 // Unblock second read (expect completion)
993 blocking_helper.Unblock();
994 std::optional<DnsConfig> config = callback_helper.WaitForResult();
995
996 ASSERT_TRUE(config.has_value());
997 EXPECT_TRUE(config->IsValid());
998
999 IPEndPoint expected(IPAddress(1, 2, 3, 4), 1000);
1000 EXPECT_THAT(config.value().nameservers, testing::ElementsAre(expected));
1001
1002 EXPECT_TRUE(resolv_reader_->closed());
1003 }
1004
1005 } // namespace
1006
1007 } // namespace net
1008