blob: 492e7ecc8dad8b9c55e5adc24b779ab0b69275e8 [file] [log] [blame]
Mike Yu0ee1dc92020-11-09 14:56:54 +08001/*
2 * Copyright (C) 2020 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <gmock/gmock.h>
18#include <gtest/gtest.h>
19
20#include "PrivateDnsConfiguration.h"
21#include "tests/dns_responder/dns_responder.h"
22#include "tests/dns_responder/dns_tls_frontend.h"
23#include "tests/resolv_test_utils.h"
24
25namespace android::net {
26
27using namespace std::chrono_literals;
28
29class PrivateDnsConfigurationTest : public ::testing::Test {
30 public:
Mike Yuad96ef82021-02-20 18:35:14 +080031 using ServerIdentity = PrivateDnsConfiguration::ServerIdentity;
32
Mike Yu0ee1dc92020-11-09 14:56:54 +080033 static void SetUpTestSuite() {
34 // stopServer() will be called in their destructor.
35 ASSERT_TRUE(tls1.startServer());
36 ASSERT_TRUE(tls2.startServer());
37 ASSERT_TRUE(backend.startServer());
38 }
39
40 void SetUp() {
41 mPdc.setObserver(&mObserver);
Mike Yu8058bd02021-05-13 16:44:18 +080042 mPdc.mBackoffBuilder.withInitialRetransmissionTime(std::chrono::seconds(1))
43 .withMaximumRetransmissionTime(std::chrono::seconds(1));
Mike Yu0ee1dc92020-11-09 14:56:54 +080044
45 // The default and sole action when the observer is notified of onValidationStateUpdate.
46 // Don't override the action. In other words, don't use WillOnce() or WillRepeatedly()
47 // when mObserver.onValidationStateUpdate is expected to be called, like:
48 //
49 // EXPECT_CALL(mObserver, onValidationStateUpdate).WillOnce(Return());
50 //
51 // This is to ensure that tests can monitor how many validation threads are running. Tests
52 // must wait until every validation thread finishes.
53 ON_CALL(mObserver, onValidationStateUpdate)
54 .WillByDefault([&](const std::string& server, Validation validation, uint32_t) {
55 if (validation == Validation::in_process) {
Mike Yu8058bd02021-05-13 16:44:18 +080056 std::lock_guard guard(mObserver.lock);
57 auto it = mObserver.serverStateMap.find(server);
58 if (it == mObserver.serverStateMap.end() ||
59 it->second != Validation::in_process) {
60 // Increment runningThreads only when receive the first in_process
61 // notification. The rest of the continuous in_process notifications
62 // are due to probe retry which runs on the same thread.
63 // TODO: consider adding onValidationThreadStart() and
64 // onValidationThreadEnd() callbacks.
65 mObserver.runningThreads++;
66 }
Mike Yu0ee1dc92020-11-09 14:56:54 +080067 } else if (validation == Validation::success ||
68 validation == Validation::fail) {
69 mObserver.runningThreads--;
70 }
71 std::lock_guard guard(mObserver.lock);
72 mObserver.serverStateMap[server] = validation;
73 });
74 }
75
76 protected:
Mike Yua6853e82020-12-11 19:47:06 +080077 class MockObserver : public PrivateDnsValidationObserver {
Mike Yu0ee1dc92020-11-09 14:56:54 +080078 public:
79 MOCK_METHOD(void, onValidationStateUpdate,
Mike Yufa985f72020-11-23 20:24:21 +080080 (const std::string& serverIp, Validation validation, uint32_t netId),
81 (override));
Mike Yu0ee1dc92020-11-09 14:56:54 +080082
83 std::map<std::string, Validation> getServerStateMap() const {
84 std::lock_guard guard(lock);
85 return serverStateMap;
86 }
87
88 void removeFromServerStateMap(const std::string& server) {
89 std::lock_guard guard(lock);
90 if (const auto it = serverStateMap.find(server); it != serverStateMap.end())
91 serverStateMap.erase(it);
92 }
93
94 // The current number of validation threads running.
95 std::atomic<int> runningThreads = 0;
96
97 mutable std::mutex lock;
98 std::map<std::string, Validation> serverStateMap GUARDED_BY(lock);
99 };
100
101 void expectPrivateDnsStatus(PrivateDnsMode mode) {
Mike Yu82ae84b2020-12-02 21:04:40 +0800102 // Use PollForCondition because mObserver is notified asynchronously.
103 EXPECT_TRUE(PollForCondition([&]() { return checkPrivateDnsStatus(mode); }));
104 }
105
106 bool checkPrivateDnsStatus(PrivateDnsMode mode) {
Mike Yu0ee1dc92020-11-09 14:56:54 +0800107 const PrivateDnsStatus status = mPdc.getStatus(kNetId);
Mike Yu82ae84b2020-12-02 21:04:40 +0800108 if (status.mode != mode) return false;
Mike Yu0ee1dc92020-11-09 14:56:54 +0800109
110 std::map<std::string, Validation> serverStateMap;
111 for (const auto& [server, validation] : status.serversMap) {
112 serverStateMap[ToString(&server.ss)] = validation;
113 }
Mike Yu82ae84b2020-12-02 21:04:40 +0800114 return (serverStateMap == mObserver.getServerStateMap());
Mike Yu0ee1dc92020-11-09 14:56:54 +0800115 }
116
Mike Yuad96ef82021-02-20 18:35:14 +0800117 bool hasPrivateDnsServer(const ServerIdentity& identity, unsigned netId) {
118 return mPdc.getPrivateDns(identity, netId).ok();
119 }
120
Mike Yu0ee1dc92020-11-09 14:56:54 +0800121 static constexpr uint32_t kNetId = 30;
122 static constexpr uint32_t kMark = 30;
123 static constexpr char kBackend[] = "127.0.2.1";
124 static constexpr char kServer1[] = "127.0.2.2";
125 static constexpr char kServer2[] = "127.0.2.3";
126
127 MockObserver mObserver;
128 PrivateDnsConfiguration mPdc;
129
130 // TODO: Because incorrect CAs result in validation failed in strict mode, have
131 // PrivateDnsConfiguration run mocked code rather than DnsTlsTransport::validate().
132 inline static test::DnsTlsFrontend tls1{kServer1, "853", kBackend, "53"};
133 inline static test::DnsTlsFrontend tls2{kServer2, "853", kBackend, "53"};
134 inline static test::DNSResponder backend{kBackend, "53"};
135};
136
137TEST_F(PrivateDnsConfigurationTest, ValidationSuccess) {
138 testing::InSequence seq;
139 EXPECT_CALL(mObserver, onValidationStateUpdate(kServer1, Validation::in_process, kNetId));
140 EXPECT_CALL(mObserver, onValidationStateUpdate(kServer1, Validation::success, kNetId));
141
142 EXPECT_EQ(mPdc.set(kNetId, kMark, {kServer1}, {}, {}), 0);
143 expectPrivateDnsStatus(PrivateDnsMode::OPPORTUNISTIC);
144
145 ASSERT_TRUE(PollForCondition([&]() { return mObserver.runningThreads == 0; }));
146}
147
148TEST_F(PrivateDnsConfigurationTest, ValidationFail_Opportunistic) {
149 ASSERT_TRUE(backend.stopServer());
150
151 testing::InSequence seq;
152 EXPECT_CALL(mObserver, onValidationStateUpdate(kServer1, Validation::in_process, kNetId));
153 EXPECT_CALL(mObserver, onValidationStateUpdate(kServer1, Validation::fail, kNetId));
154
155 EXPECT_EQ(mPdc.set(kNetId, kMark, {kServer1}, {}, {}), 0);
156 expectPrivateDnsStatus(PrivateDnsMode::OPPORTUNISTIC);
157
158 // Strictly wait for all of the validation finish; otherwise, the test can crash somehow.
159 ASSERT_TRUE(PollForCondition([&]() { return mObserver.runningThreads == 0; }));
160 ASSERT_TRUE(backend.startServer());
161}
162
Mike Yu8058bd02021-05-13 16:44:18 +0800163TEST_F(PrivateDnsConfigurationTest, Revalidation_Opportunistic) {
164 const DnsTlsServer server(netdutils::IPSockAddr::toIPSockAddr(kServer1, 853));
165
166 // Step 1: Set up and wait for validation complete.
167 testing::InSequence seq;
168 EXPECT_CALL(mObserver, onValidationStateUpdate(kServer1, Validation::in_process, kNetId));
169 EXPECT_CALL(mObserver, onValidationStateUpdate(kServer1, Validation::success, kNetId));
170
171 EXPECT_EQ(mPdc.set(kNetId, kMark, {kServer1}, {}, {}), 0);
172 expectPrivateDnsStatus(PrivateDnsMode::OPPORTUNISTIC);
173 ASSERT_TRUE(PollForCondition([&]() { return mObserver.runningThreads == 0; }));
174
175 // Step 2: Simulate the DNS is temporarily broken, and then request a validation.
176 // Expect the validation to run as follows:
177 // 1. DnsResolver notifies of Validation::in_process when the validation is about to run.
178 // 2. The first probing fails. DnsResolver notifies of Validation::in_process.
179 // 3. One second later, the second probing begins and succeeds. DnsResolver notifies of
180 // Validation::success.
181 EXPECT_CALL(mObserver, onValidationStateUpdate(kServer1, Validation::in_process, kNetId))
182 .Times(2);
183 EXPECT_CALL(mObserver, onValidationStateUpdate(kServer1, Validation::success, kNetId));
184
185 std::thread t([] {
186 std::this_thread::sleep_for(1000ms);
187 backend.startServer();
188 });
189 backend.stopServer();
190 EXPECT_TRUE(mPdc.requestValidation(kNetId, ServerIdentity(server), kMark).ok());
191
192 t.join();
193 expectPrivateDnsStatus(PrivateDnsMode::OPPORTUNISTIC);
194 ASSERT_TRUE(PollForCondition([&]() { return mObserver.runningThreads == 0; }));
195}
196
Mike Yu0ee1dc92020-11-09 14:56:54 +0800197TEST_F(PrivateDnsConfigurationTest, ValidationBlock) {
198 backend.setDeferredResp(true);
199
200 // onValidationStateUpdate() is called in sequence.
201 {
202 testing::InSequence seq;
203 EXPECT_CALL(mObserver, onValidationStateUpdate(kServer1, Validation::in_process, kNetId));
204 EXPECT_EQ(mPdc.set(kNetId, kMark, {kServer1}, {}, {}), 0);
205 ASSERT_TRUE(PollForCondition([&]() { return mObserver.runningThreads == 1; }));
206 expectPrivateDnsStatus(PrivateDnsMode::OPPORTUNISTIC);
207
208 EXPECT_CALL(mObserver, onValidationStateUpdate(kServer2, Validation::in_process, kNetId));
209 EXPECT_EQ(mPdc.set(kNetId, kMark, {kServer2}, {}, {}), 0);
210 ASSERT_TRUE(PollForCondition([&]() { return mObserver.runningThreads == 2; }));
211 mObserver.removeFromServerStateMap(kServer1);
212 expectPrivateDnsStatus(PrivateDnsMode::OPPORTUNISTIC);
213
214 // No duplicate validation as long as not in OFF mode; otherwise, an unexpected
215 // onValidationStateUpdate() will be caught.
216 EXPECT_EQ(mPdc.set(kNetId, kMark, {kServer1}, {}, {}), 0);
217 EXPECT_EQ(mPdc.set(kNetId, kMark, {kServer1, kServer2}, {}, {}), 0);
218 EXPECT_EQ(mPdc.set(kNetId, kMark, {kServer2}, {}, {}), 0);
219 expectPrivateDnsStatus(PrivateDnsMode::OPPORTUNISTIC);
220
221 // The status keeps unchanged if pass invalid arguments.
222 EXPECT_EQ(mPdc.set(kNetId, kMark, {"invalid_addr"}, {}, {}), -EINVAL);
223 expectPrivateDnsStatus(PrivateDnsMode::OPPORTUNISTIC);
224 }
225
226 // The update for |kServer1| will be Validation::fail because |kServer1| is not an expected
227 // server for the network.
228 EXPECT_CALL(mObserver, onValidationStateUpdate(kServer1, Validation::fail, kNetId));
229 EXPECT_CALL(mObserver, onValidationStateUpdate(kServer2, Validation::success, kNetId));
230 backend.setDeferredResp(false);
231
232 ASSERT_TRUE(PollForCondition([&]() { return mObserver.runningThreads == 0; }));
Mike Yufa985f72020-11-23 20:24:21 +0800233
234 // kServer1 is not a present server and thus should not be available from
235 // PrivateDnsConfiguration::getStatus().
236 mObserver.removeFromServerStateMap(kServer1);
237
Mike Yu0ee1dc92020-11-09 14:56:54 +0800238 expectPrivateDnsStatus(PrivateDnsMode::OPPORTUNISTIC);
239}
240
241TEST_F(PrivateDnsConfigurationTest, Validation_NetworkDestroyedOrOffMode) {
242 for (const std::string_view config : {"OFF", "NETWORK_DESTROYED"}) {
243 SCOPED_TRACE(config);
244 backend.setDeferredResp(true);
245
246 testing::InSequence seq;
247 EXPECT_CALL(mObserver, onValidationStateUpdate(kServer1, Validation::in_process, kNetId));
248 EXPECT_EQ(mPdc.set(kNetId, kMark, {kServer1}, {}, {}), 0);
249 ASSERT_TRUE(PollForCondition([&]() { return mObserver.runningThreads == 1; }));
250 expectPrivateDnsStatus(PrivateDnsMode::OPPORTUNISTIC);
251
252 if (config == "OFF") {
253 EXPECT_EQ(mPdc.set(kNetId, kMark, {}, {}, {}), 0);
254 } else if (config == "NETWORK_DESTROYED") {
255 mPdc.clear(kNetId);
256 }
257
258 EXPECT_CALL(mObserver, onValidationStateUpdate(kServer1, Validation::fail, kNetId));
259 backend.setDeferredResp(false);
260
261 ASSERT_TRUE(PollForCondition([&]() { return mObserver.runningThreads == 0; }));
262 mObserver.removeFromServerStateMap(kServer1);
263 expectPrivateDnsStatus(PrivateDnsMode::OFF);
264 }
265}
266
267TEST_F(PrivateDnsConfigurationTest, NoValidation) {
268 // If onValidationStateUpdate() is called, the test will fail with uninteresting mock
269 // function calls in the end of the test.
270
271 const auto expectStatus = [&]() {
272 const PrivateDnsStatus status = mPdc.getStatus(kNetId);
273 EXPECT_EQ(status.mode, PrivateDnsMode::OFF);
274 EXPECT_THAT(status.serversMap, testing::IsEmpty());
275 };
276
277 EXPECT_EQ(mPdc.set(kNetId, kMark, {"invalid_addr"}, {}, {}), -EINVAL);
278 expectStatus();
279
280 EXPECT_EQ(mPdc.set(kNetId, kMark, {}, {}, {}), 0);
281 expectStatus();
282}
283
Mike Yufa985f72020-11-23 20:24:21 +0800284TEST_F(PrivateDnsConfigurationTest, ServerIdentity_Comparison) {
Mike Yufa985f72020-11-23 20:24:21 +0800285 DnsTlsServer server(netdutils::IPSockAddr::toIPSockAddr("127.0.0.1", 853));
286 server.name = "dns.example.com";
Mike Yufa985f72020-11-23 20:24:21 +0800287
Mike Yu453b5e42021-02-19 20:03:07 +0800288 // Different socket address.
Mike Yufa985f72020-11-23 20:24:21 +0800289 DnsTlsServer other = server;
290 EXPECT_EQ(ServerIdentity(server), ServerIdentity(other));
291 other.ss = netdutils::IPSockAddr::toIPSockAddr("127.0.0.1", 5353);
Mike Yu453b5e42021-02-19 20:03:07 +0800292 EXPECT_NE(ServerIdentity(server), ServerIdentity(other));
Mike Yufa985f72020-11-23 20:24:21 +0800293 other.ss = netdutils::IPSockAddr::toIPSockAddr("127.0.0.2", 853);
294 EXPECT_NE(ServerIdentity(server), ServerIdentity(other));
295
296 // Different provider hostname.
297 other = server;
298 EXPECT_EQ(ServerIdentity(server), ServerIdentity(other));
299 other.name = "other.example.com";
300 EXPECT_NE(ServerIdentity(server), ServerIdentity(other));
301 other.name = "";
302 EXPECT_NE(ServerIdentity(server), ServerIdentity(other));
Mike Yufa985f72020-11-23 20:24:21 +0800303}
304
Mike Yue60ab412020-12-01 17:56:12 +0800305TEST_F(PrivateDnsConfigurationTest, RequestValidation) {
306 const DnsTlsServer server(netdutils::IPSockAddr::toIPSockAddr(kServer1, 853));
Mike Yuad96ef82021-02-20 18:35:14 +0800307 const ServerIdentity identity(server);
Mike Yue60ab412020-12-01 17:56:12 +0800308
309 testing::InSequence seq;
310
311 for (const std::string_view config : {"SUCCESS", "IN_PROGRESS", "FAIL"}) {
312 SCOPED_TRACE(config);
313
314 EXPECT_CALL(mObserver, onValidationStateUpdate(kServer1, Validation::in_process, kNetId));
315 if (config == "SUCCESS") {
316 EXPECT_CALL(mObserver, onValidationStateUpdate(kServer1, Validation::success, kNetId));
317 } else if (config == "IN_PROGRESS") {
318 backend.setDeferredResp(true);
319 } else {
320 // config = "FAIL"
321 ASSERT_TRUE(backend.stopServer());
322 EXPECT_CALL(mObserver, onValidationStateUpdate(kServer1, Validation::fail, kNetId));
323 }
324 EXPECT_EQ(mPdc.set(kNetId, kMark, {kServer1}, {}, {}), 0);
325 expectPrivateDnsStatus(PrivateDnsMode::OPPORTUNISTIC);
326
327 // Wait until the validation state is transitioned.
328 const int runningThreads = (config == "IN_PROGRESS") ? 1 : 0;
329 ASSERT_TRUE(PollForCondition([&]() { return mObserver.runningThreads == runningThreads; }));
330
Mike Yue60ab412020-12-01 17:56:12 +0800331 if (config == "SUCCESS") {
332 EXPECT_CALL(mObserver,
333 onValidationStateUpdate(kServer1, Validation::in_process, kNetId));
334 EXPECT_CALL(mObserver, onValidationStateUpdate(kServer1, Validation::success, kNetId));
Mike Yuad96ef82021-02-20 18:35:14 +0800335 EXPECT_TRUE(mPdc.requestValidation(kNetId, identity, kMark).ok());
Mike Yue60ab412020-12-01 17:56:12 +0800336 } else if (config == "IN_PROGRESS") {
337 EXPECT_CALL(mObserver, onValidationStateUpdate(kServer1, Validation::success, kNetId));
Mike Yuad96ef82021-02-20 18:35:14 +0800338 EXPECT_FALSE(mPdc.requestValidation(kNetId, identity, kMark).ok());
Mike Yu82ae84b2020-12-02 21:04:40 +0800339 } else if (config == "FAIL") {
Mike Yuad96ef82021-02-20 18:35:14 +0800340 EXPECT_FALSE(mPdc.requestValidation(kNetId, identity, kMark).ok());
Mike Yue60ab412020-12-01 17:56:12 +0800341 }
342
Mike Yue60ab412020-12-01 17:56:12 +0800343 // Resending the same request or requesting nonexistent servers are denied.
Mike Yuad96ef82021-02-20 18:35:14 +0800344 EXPECT_FALSE(mPdc.requestValidation(kNetId, identity, kMark).ok());
345 EXPECT_FALSE(mPdc.requestValidation(kNetId, identity, kMark + 1).ok());
346 EXPECT_FALSE(mPdc.requestValidation(kNetId + 1, identity, kMark).ok());
Mike Yue60ab412020-12-01 17:56:12 +0800347
348 // Reset the test state.
349 backend.setDeferredResp(false);
350 backend.startServer();
Mike Yu82ae84b2020-12-02 21:04:40 +0800351
352 // Ensure the status of mObserver is synced.
353 expectPrivateDnsStatus(PrivateDnsMode::OPPORTUNISTIC);
354
Mike Yue60ab412020-12-01 17:56:12 +0800355 ASSERT_TRUE(PollForCondition([&]() { return mObserver.runningThreads == 0; }));
356 mPdc.clear(kNetId);
357 }
358}
359
Mike Yuad96ef82021-02-20 18:35:14 +0800360TEST_F(PrivateDnsConfigurationTest, GetPrivateDns) {
361 const DnsTlsServer server1(netdutils::IPSockAddr::toIPSockAddr(kServer1, 853));
362 const DnsTlsServer server2(netdutils::IPSockAddr::toIPSockAddr(kServer2, 853));
363
364 EXPECT_FALSE(hasPrivateDnsServer(ServerIdentity(server1), kNetId));
365 EXPECT_FALSE(hasPrivateDnsServer(ServerIdentity(server2), kNetId));
366
367 // Suppress the warning.
368 EXPECT_CALL(mObserver, onValidationStateUpdate).Times(2);
369
370 EXPECT_EQ(mPdc.set(kNetId, kMark, {kServer1}, {}, {}), 0);
371 expectPrivateDnsStatus(PrivateDnsMode::OPPORTUNISTIC);
372
373 EXPECT_TRUE(hasPrivateDnsServer(ServerIdentity(server1), kNetId));
374 EXPECT_FALSE(hasPrivateDnsServer(ServerIdentity(server2), kNetId));
375 EXPECT_FALSE(hasPrivateDnsServer(ServerIdentity(server1), kNetId + 1));
376
377 ASSERT_TRUE(PollForCondition([&]() { return mObserver.runningThreads == 0; }));
378}
379
Mike Yu0ee1dc92020-11-09 14:56:54 +0800380// TODO: add ValidationFail_Strict test.
381
382} // namespace android::net