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_android.h"
6
7 #include <memory>
8 #include <string>
9 #include <utility>
10 #include <vector>
11
12 #include "base/android/build_info.h"
13 #include "base/functional/bind.h"
14 #include "base/memory/ref_counted.h"
15 #include "base/memory/scoped_refptr.h"
16 #include "base/test/task_environment.h"
17 #include "net/android/network_library.h"
18 #include "net/base/ip_endpoint.h"
19 #include "net/base/mock_network_change_notifier.h"
20 #include "net/base/network_change_notifier.h"
21 #include "net/dns/dns_config.h"
22 #include "net/test/test_with_task_environment.h"
23 #include "testing/gmock/include/gmock/gmock.h"
24 #include "testing/gtest/include/gtest/gtest.h"
25
26 namespace net::internal {
27 namespace {
28
29 const IPEndPoint kNameserver1(IPAddress(1, 2, 3, 4), 53);
30 const IPEndPoint kNameserver2(IPAddress(1, 2, 3, 8), 53);
31
32 // DnsConfigServiceAndroid uses a simplified implementation for Android versions
33 // before relevant APIs were added in Android M. Most of these tests are
34 // targeting the logic used in M and beyond.
35 #define SKIP_ANDROID_VERSIONS_BEFORE_M() \
36 { \
37 if (base::android::BuildInfo::GetInstance()->sdk_int() < \
38 base::android::SDK_VERSION_MARSHMALLOW) { \
39 GTEST_SKIP() << "Test not necessary or compatible with pre-M."; \
40 } \
41 }
42
43 // RefCountedThreadSafe to allow safe usage and reference storage in
44 // DnsConfigServiceAndroid's off-sequence utility classes.
45 class MockDnsServerGetter
46 : public base::RefCountedThreadSafe<MockDnsServerGetter> {
47 public:
set_retval(bool retval)48 void set_retval(bool retval) { retval_ = retval; }
49
set_dns_servers(std::vector<IPEndPoint> dns_servers)50 void set_dns_servers(std::vector<IPEndPoint> dns_servers) {
51 dns_servers_ = std::move(dns_servers);
52 }
53
set_dns_over_tls_active(bool dns_over_tls_active)54 void set_dns_over_tls_active(bool dns_over_tls_active) {
55 dns_over_tls_active_ = dns_over_tls_active;
56 }
57
set_dns_over_tls_hostname(std::string dns_over_tls_hostname)58 void set_dns_over_tls_hostname(std::string dns_over_tls_hostname) {
59 dns_over_tls_hostname_ = std::move(dns_over_tls_hostname);
60 }
61
set_search_suffixes(std::vector<std::string> search_suffixes)62 void set_search_suffixes(std::vector<std::string> search_suffixes) {
63 search_suffixes_ = std::move(search_suffixes);
64 }
65
ConstructGetter()66 android::DnsServerGetter ConstructGetter() {
67 return base::BindRepeating(&MockDnsServerGetter::GetDnsServers, this);
68 }
69
70 private:
71 friend base::RefCountedThreadSafe<MockDnsServerGetter>;
72 ~MockDnsServerGetter() = default;
73
GetDnsServers(std::vector<IPEndPoint> * dns_servers,bool * dns_over_tls_active,std::string * dns_over_tls_hostname,std::vector<std::string> * search_suffixes)74 bool GetDnsServers(std::vector<IPEndPoint>* dns_servers,
75 bool* dns_over_tls_active,
76 std::string* dns_over_tls_hostname,
77 std::vector<std::string>* search_suffixes) {
78 if (retval_) {
79 *dns_servers = dns_servers_;
80 *dns_over_tls_active = dns_over_tls_active_;
81 *dns_over_tls_hostname = dns_over_tls_hostname_;
82 *search_suffixes = search_suffixes_;
83 }
84 return retval_;
85 }
86
87 bool retval_ = false;
88 std::vector<IPEndPoint> dns_servers_;
89 bool dns_over_tls_active_ = false;
90 std::string dns_over_tls_hostname_;
91 std::vector<std::string> search_suffixes_;
92 };
93
94 class DnsConfigServiceAndroidTest : public testing::Test,
95 public WithTaskEnvironment {
96 public:
DnsConfigServiceAndroidTest()97 DnsConfigServiceAndroidTest()
98 : WithTaskEnvironment(
99 base::test::TaskEnvironment::TimeSource::MOCK_TIME) {
100 service_->set_dns_server_getter_for_testing(
101 mock_dns_server_getter_->ConstructGetter());
102 }
103 ~DnsConfigServiceAndroidTest() override = default;
104
OnConfigChanged(const DnsConfig & config)105 void OnConfigChanged(const DnsConfig& config) {
106 EXPECT_TRUE(config.IsValid());
107 seen_config_ = true;
108 real_config_ = config;
109 }
110
111 protected:
112 bool seen_config_ = false;
113 std::unique_ptr<DnsConfigServiceAndroid> service_ =
114 std::make_unique<DnsConfigServiceAndroid>();
115 DnsConfig real_config_;
116
117 scoped_refptr<MockDnsServerGetter> mock_dns_server_getter_ =
118 base::MakeRefCounted<MockDnsServerGetter>();
119 test::ScopedMockNetworkChangeNotifier mock_notifier_;
120 };
121
TEST_F(DnsConfigServiceAndroidTest,HandlesNetworkChangeNotifications)122 TEST_F(DnsConfigServiceAndroidTest, HandlesNetworkChangeNotifications) {
123 service_->WatchConfig(base::BindRepeating(
124 &DnsConfigServiceAndroidTest::OnConfigChanged, base::Unretained(this)));
125 FastForwardBy(DnsConfigServiceAndroid::kConfigChangeDelay);
126 RunUntilIdle();
127
128 // Cannot validate any behavior other than not crashing because this test runs
129 // on Android versions with unmocked behavior.
130 }
131
TEST_F(DnsConfigServiceAndroidTest,NewConfigReadOnNetworkChange)132 TEST_F(DnsConfigServiceAndroidTest, NewConfigReadOnNetworkChange) {
133 SKIP_ANDROID_VERSIONS_BEFORE_M();
134
135 mock_dns_server_getter_->set_retval(true);
136 mock_dns_server_getter_->set_dns_servers({kNameserver1});
137
138 service_->WatchConfig(base::BindRepeating(
139 &DnsConfigServiceAndroidTest::OnConfigChanged, base::Unretained(this)));
140 FastForwardBy(DnsConfigServiceAndroid::kConfigChangeDelay);
141 RunUntilIdle();
142 ASSERT_TRUE(seen_config_);
143 EXPECT_THAT(real_config_.nameservers, testing::ElementsAre(kNameserver1));
144
145 mock_dns_server_getter_->set_dns_servers({kNameserver2});
146
147 seen_config_ = false;
148 NetworkChangeNotifier::NotifyObserversOfConnectionTypeChangeForTests(
149 NetworkChangeNotifier::CONNECTION_WIFI);
150 FastForwardBy(DnsConfigServiceAndroid::kConfigChangeDelay);
151 RunUntilIdle();
152 ASSERT_TRUE(seen_config_);
153 EXPECT_THAT(real_config_.nameservers, testing::ElementsAre(kNameserver2));
154 }
155
TEST_F(DnsConfigServiceAndroidTest,NoConfigNotificationWhenUnchanged)156 TEST_F(DnsConfigServiceAndroidTest, NoConfigNotificationWhenUnchanged) {
157 SKIP_ANDROID_VERSIONS_BEFORE_M();
158
159 mock_dns_server_getter_->set_retval(true);
160 mock_dns_server_getter_->set_dns_servers({kNameserver1});
161
162 service_->WatchConfig(base::BindRepeating(
163 &DnsConfigServiceAndroidTest::OnConfigChanged, base::Unretained(this)));
164 FastForwardBy(DnsConfigServiceAndroid::kConfigChangeDelay);
165 RunUntilIdle();
166 ASSERT_TRUE(seen_config_);
167 EXPECT_THAT(real_config_.nameservers, testing::ElementsAre(kNameserver1));
168
169 seen_config_ = false;
170 NetworkChangeNotifier::NotifyObserversOfConnectionTypeChangeForTests(
171 NetworkChangeNotifier::CONNECTION_WIFI);
172 FastForwardBy(DnsConfigServiceAndroid::kConfigChangeDelay);
173 RunUntilIdle();
174
175 // Because the DNS config hasn't changed, no new config should be seen.
176 EXPECT_FALSE(seen_config_);
177 }
178
TEST_F(DnsConfigServiceAndroidTest,IgnoresConnectionNoneChangeNotifications)179 TEST_F(DnsConfigServiceAndroidTest, IgnoresConnectionNoneChangeNotifications) {
180 SKIP_ANDROID_VERSIONS_BEFORE_M();
181
182 mock_dns_server_getter_->set_retval(true);
183 mock_dns_server_getter_->set_dns_servers({kNameserver1});
184
185 service_->WatchConfig(base::BindRepeating(
186 &DnsConfigServiceAndroidTest::OnConfigChanged, base::Unretained(this)));
187 FastForwardBy(DnsConfigServiceAndroid::kConfigChangeDelay);
188 RunUntilIdle();
189 ASSERT_TRUE(seen_config_);
190 EXPECT_THAT(real_config_.nameservers, testing::ElementsAre(kNameserver1));
191
192 // Change the DNS config to ensure the lack of notification is due to not
193 // being checked for.
194 mock_dns_server_getter_->set_dns_servers({kNameserver2});
195
196 seen_config_ = false;
197 NetworkChangeNotifier::NotifyObserversOfConnectionTypeChangeForTests(
198 NetworkChangeNotifier::CONNECTION_NONE);
199 FastForwardBy(DnsConfigServiceAndroid::kConfigChangeDelay);
200 RunUntilIdle();
201
202 // Expect no new config read for network change to NONE.
203 EXPECT_FALSE(seen_config_);
204 }
205
206 // Regression test for https://crbug.com/704662.
TEST_F(DnsConfigServiceAndroidTest,ChangeConfigMultipleTimes)207 TEST_F(DnsConfigServiceAndroidTest, ChangeConfigMultipleTimes) {
208 SKIP_ANDROID_VERSIONS_BEFORE_M();
209
210 mock_dns_server_getter_->set_retval(true);
211 mock_dns_server_getter_->set_dns_servers({kNameserver1});
212
213 service_->WatchConfig(base::BindRepeating(
214 &DnsConfigServiceAndroidTest::OnConfigChanged, base::Unretained(this)));
215 FastForwardBy(DnsConfigServiceAndroid::kConfigChangeDelay);
216 RunUntilIdle();
217 ASSERT_TRUE(seen_config_);
218 EXPECT_THAT(real_config_.nameservers, testing::ElementsAre(kNameserver1));
219
220 for (int i = 0; i < 5; i++) {
221 mock_dns_server_getter_->set_dns_servers({kNameserver2});
222
223 seen_config_ = false;
224 NetworkChangeNotifier::NotifyObserversOfConnectionTypeChangeForTests(
225 NetworkChangeNotifier::CONNECTION_WIFI);
226 FastForwardBy(DnsConfigServiceAndroid::kConfigChangeDelay);
227 RunUntilIdle();
228 ASSERT_TRUE(seen_config_);
229 EXPECT_THAT(real_config_.nameservers, testing::ElementsAre(kNameserver2));
230
231 mock_dns_server_getter_->set_dns_servers({kNameserver1});
232
233 seen_config_ = false;
234 NetworkChangeNotifier::NotifyObserversOfConnectionTypeChangeForTests(
235 NetworkChangeNotifier::CONNECTION_WIFI);
236 FastForwardBy(DnsConfigServiceAndroid::kConfigChangeDelay);
237 RunUntilIdle();
238 ASSERT_TRUE(seen_config_);
239 EXPECT_THAT(real_config_.nameservers, testing::ElementsAre(kNameserver1));
240 }
241 }
242
TEST_F(DnsConfigServiceAndroidTest,ReadsSearchSuffixes)243 TEST_F(DnsConfigServiceAndroidTest, ReadsSearchSuffixes) {
244 SKIP_ANDROID_VERSIONS_BEFORE_M();
245
246 const std::vector<std::string> kSuffixes{"name1.test", "name2.test"};
247
248 mock_dns_server_getter_->set_retval(true);
249 mock_dns_server_getter_->set_dns_servers({kNameserver1});
250 mock_dns_server_getter_->set_search_suffixes(kSuffixes);
251
252 service_->ReadConfig(base::BindRepeating(
253 &DnsConfigServiceAndroidTest::OnConfigChanged, base::Unretained(this)));
254 FastForwardBy(DnsConfigServiceAndroid::kConfigChangeDelay);
255 RunUntilIdle();
256 ASSERT_TRUE(seen_config_);
257 EXPECT_EQ(real_config_.search, kSuffixes);
258 }
259
TEST_F(DnsConfigServiceAndroidTest,ReadsEmptySearchSuffixes)260 TEST_F(DnsConfigServiceAndroidTest, ReadsEmptySearchSuffixes) {
261 SKIP_ANDROID_VERSIONS_BEFORE_M();
262
263 mock_dns_server_getter_->set_retval(true);
264 mock_dns_server_getter_->set_dns_servers({kNameserver1});
265
266 service_->ReadConfig(base::BindRepeating(
267 &DnsConfigServiceAndroidTest::OnConfigChanged, base::Unretained(this)));
268 FastForwardBy(DnsConfigServiceAndroid::kConfigChangeDelay);
269 RunUntilIdle();
270 ASSERT_TRUE(seen_config_);
271 EXPECT_TRUE(real_config_.search.empty());
272 }
273
274 } // namespace
275 } // namespace net::internal
276