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