• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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