1 /*
2 * Copyright 2019 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 #ifdef NDEBUG
18 #undef NDEBUG
19 #endif
20
21 #include <netdb.h>
22
23 #include <iostream>
24 #include <regex>
25 #include <string>
26 #include <thread>
27 #include <vector>
28
29 #include <aidl/android/net/IDnsResolver.h>
30 #include <android-base/file.h>
31 #include <android-base/format.h>
32 #include <android-base/strings.h>
33 #include <android-base/unique_fd.h>
34 #include <android/binder_manager.h>
35 #include <android/binder_process.h>
36 #include <gmock/gmock-matchers.h>
37 #include <gtest/gtest.h>
38 #include <netdutils/NetNativeTestBase.h>
39 #include <netdutils/Stopwatch.h>
40
41 #include <util.h>
42 #include "dns_metrics_listener/base_metrics_listener.h"
43 #include "dns_metrics_listener/test_metrics.h"
44 #include "unsolicited_listener/unsolicited_event_listener.h"
45
46 #include "ResolverStats.h"
47 #include "dns_responder.h"
48 #include "dns_responder_client_ndk.h"
49
50 using aidl::android::net::IDnsResolver;
51 using aidl::android::net::ResolverHostsParcel;
52 using aidl::android::net::ResolverOptionsParcel;
53 using aidl::android::net::ResolverParamsParcel;
54 using aidl::android::net::metrics::INetdEventListener;
55 using android::base::ReadFdToString;
56 using android::base::unique_fd;
57 using android::net::ResolverStats;
58 using android::net::metrics::TestOnDnsEvent;
59 using android::net::resolv::aidl::UnsolicitedEventListener;
60 using android::netdutils::Stopwatch;
61
62 // TODO: make this dynamic and stop depending on implementation details.
63 // Sync from TEST_NETID in dns_responder_client.cpp as resolv_integration_test.cpp does.
64 constexpr int TEST_NETID = 30;
65
66 namespace {
67
dumpService(ndk::SpAIBinder binder)68 std::vector<std::string> dumpService(ndk::SpAIBinder binder) {
69 unique_fd localFd, remoteFd;
70 bool success = Pipe(&localFd, &remoteFd);
71 EXPECT_TRUE(success) << "Failed to open pipe for dumping: " << strerror(errno);
72 if (!success) return {};
73
74 // dump() blocks until another thread has consumed all its output.
75 std::thread dumpThread = std::thread([binder, remoteFd{std::move(remoteFd)}]() {
76 EXPECT_EQ(STATUS_OK, AIBinder_dump(binder.get(), remoteFd, nullptr, 0));
77 });
78
79 std::string dumpContent;
80
81 EXPECT_TRUE(ReadFdToString(localFd.get(), &dumpContent))
82 << "Error during dump: " << strerror(errno);
83 dumpThread.join();
84
85 std::stringstream dumpStream(std::move(dumpContent));
86 std::vector<std::string> lines;
87 std::string line;
88 while (std::getline(dumpStream, line)) {
89 lines.push_back(std::move(line));
90 }
91
92 return lines;
93 }
94
95 } // namespace
96
97 class DnsResolverBinderTest : public NetNativeTestBase {
98 public:
DnsResolverBinderTest()99 DnsResolverBinderTest() {
100 ndk::SpAIBinder resolvBinder = ndk::SpAIBinder(AServiceManager_getService("dnsresolver"));
101
102 mDnsResolver = IDnsResolver::fromBinder(resolvBinder);
103 // This could happen when the test isn't running as root, or if netd isn't running.
104 assert(nullptr != mDnsResolver.get());
105 // Create cache for test
106 mDnsResolver->createNetworkCache(TEST_NETID);
107 }
108
~DnsResolverBinderTest()109 ~DnsResolverBinderTest() {
110 expectLog();
111 // Destroy cache for test
112 mDnsResolver->destroyNetworkCache(TEST_NETID);
113 }
114
115 protected:
expectLog()116 void expectLog() {
117 ndk::SpAIBinder netdBinder = ndk::SpAIBinder(AServiceManager_getService("netd"));
118 // This could happen when the test isn't running as root, or if netd isn't running.
119 assert(nullptr != netdBinder.get());
120 // Send the service dump request to netd.
121 std::vector<std::string> lines = dumpService(netdBinder);
122
123 // Basic regexp to match dump output lines. Matches the beginning and end of the line, and
124 // puts the output of the command itself into the first match group.
125 // Example: " 11-05 00:23:39.481 myCommand(args) <2.02ms>".
126 // Accept any number of the leading space.
127 const std::basic_regex lineRegex(
128 "^\\s*[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}[.][0-9]{3} "
129 "(.*)"
130 " <[0-9]+[.][0-9]{2}ms>$");
131
132 // For each element of testdata, check that the expected output appears in the dump output.
133 // If not, fail the test and use hintRegex to print similar lines to assist in debugging.
134 for (const auto& td : mExpectedLogData) {
135 const bool found =
136 std::any_of(lines.begin(), lines.end(), [&](const std::string& line) {
137 std::smatch match;
138 if (!std::regex_match(line, match, lineRegex)) return false;
139 if (match.size() != 2) return false;
140
141 // The binder_to_string format is changed over time to include more
142 // information. To keep it working on Q/R/..., remove what has been
143 // added for now. TODO(b/266248339)
144 std::string output = match[1].str();
145 using android::base::StringReplace;
146 output = StringReplace(output, "(null)", "", /*all=*/true);
147 output = StringReplace(output, "<unimplemented>", "", /*all=*/true);
148 output = StringReplace(output, "<interface>", "", /*all=*/true);
149 return output == td.output;
150 });
151 EXPECT_TRUE(found) << "Didn't find line '" << td.output << "' in dumpsys output.";
152 if (found) continue;
153 std::cerr << "Similar lines" << std::endl;
154 for (const auto& line : lines) {
155 if (std::regex_search(line, std::basic_regex(td.hintRegex))) {
156 std::cerr << line << std::endl;
157 }
158 }
159 }
160
161 // The log output is different between R and S, either one is fine for the
162 // test to avoid test compatible issue.
163 // TODO: Remove after S.
164 for (const auto& td : mExpectedLogDataWithPacel) {
165 const bool found =
166 std::any_of(lines.begin(), lines.end(), [&](const std::string& line) {
167 std::smatch match;
168 if (!std::regex_match(line, match, lineRegex)) return false;
169 return (match.size() == 2) && ((match[1].str() == td.withPacel.output) ||
170 (match[1].str() == td.withoutPacel.output));
171 });
172 EXPECT_TRUE(found) << fmt::format("Didn't find line '{}' or '{}' in dumpsys output.",
173 td.withPacel.output, td.withoutPacel.output);
174 if (found) continue;
175 std::cerr << "Similar lines" << std::endl;
176 for (const auto& line : lines) {
177 if (std::regex_search(line, std::basic_regex(td.withPacel.hintRegex))) {
178 std::cerr << line << std::endl;
179 }
180 if (std::regex_search(line, std::basic_regex(td.withoutPacel.hintRegex))) {
181 std::cerr << line << std::endl;
182 }
183 }
184 }
185 }
186
187 struct LogData {
188 // Expected contents of the dump command.
189 const std::string output;
190 // A regex that might be helpful in matching relevant lines in the output.
191 // Used to make it easier to add test cases for this code.
192 const std::string hintRegex;
193 };
194
195 // TODO: Remove this struct and below toString methods after S.
196 struct PossibleLogData {
197 LogData withPacel;
198 LogData withoutPacel;
199 };
200
toString(const std::vector<ResolverHostsParcel> & parms)201 std::string toString(const std::vector<ResolverHostsParcel>& parms) {
202 std::string o;
203 const size_t size = parms.size();
204 for (size_t i = 0; i < size; ++i) {
205 o.append(fmt::format("ResolverHostsParcel{{ipAddr: {}, hostName: {}}}", parms[i].ipAddr,
206 parms[i].hostName));
207 if (i + 1 < size) o.append(", ");
208 }
209 return o;
210 }
211
toString(const std::optional<ResolverOptionsParcel> & parms)212 std::string toString(const std::optional<ResolverOptionsParcel>& parms) {
213 if (!parms.has_value()) return "(null)";
214 return fmt::format("ResolverOptionsParcel{{hosts: [{}], tcMode: {}, enforceDnsUid: {}}}",
215 toString(parms->hosts), parms->tcMode, parms->enforceDnsUid);
216 }
217
toString(const ResolverParamsParcel & parms)218 std::string toString(const ResolverParamsParcel& parms) {
219 return fmt::format(
220 "ResolverParamsParcel{{netId: {}, sampleValiditySeconds: {}, successThreshold: {}, "
221 "minSamples: {}, "
222 "maxSamples: {}, baseTimeoutMsec: {}, retryCount: {}, "
223 "servers: [{}], domains: [{}], "
224 "tlsName: {}, tlsServers: [{}], "
225 "tlsFingerprints: [{}], "
226 "caCertificate: {}, tlsConnectTimeoutMs: {}, "
227 "resolverOptions: {}, transportTypes: [{}]}}",
228 parms.netId, parms.sampleValiditySeconds, parms.successThreshold, parms.minSamples,
229 parms.maxSamples, parms.baseTimeoutMsec, parms.retryCount,
230 fmt::join(parms.servers, ", "), fmt::join(parms.domains, ", "), parms.tlsName,
231 fmt::join(parms.tlsServers, ", "), fmt::join(parms.tlsFingerprints, ", "),
232 android::base::StringReplace(parms.caCertificate, "\n", "\\n", true),
233 parms.tlsConnectTimeoutMs, toString(parms.resolverOptions),
234 fmt::join(parms.transportTypes, ", "));
235 }
236
toSetResolverConfigurationLogData(const ResolverParamsParcel & parms,int returnCode=0)237 PossibleLogData toSetResolverConfigurationLogData(const ResolverParamsParcel& parms,
238 int returnCode = 0) {
239 std::string outputWithParcel = "setResolverConfiguration(" + toString(parms) + ")";
240 std::string hintRegexWithParcel = fmt::format("setResolverConfiguration.*{}", parms.netId);
241
242 std::string outputWithoutParcel = "setResolverConfiguration()";
243 std::string hintRegexWithoutParcel = "setResolverConfiguration";
244 if (returnCode != 0) {
245 outputWithParcel.append(fmt::format(" -> ServiceSpecificException({}, \"{}\")",
246 returnCode, strerror(returnCode)));
247 hintRegexWithParcel.append(fmt::format(".*{}", returnCode));
248 outputWithoutParcel.append(fmt::format(" -> ServiceSpecificException({}, \"{}\")",
249 returnCode, strerror(returnCode)));
250 hintRegexWithoutParcel.append(fmt::format(".*{}", returnCode));
251 }
252 return {{std::move(outputWithParcel), std::move(hintRegexWithParcel)},
253 {std::move(outputWithoutParcel), std::move(hintRegexWithoutParcel)}};
254 }
255
256 std::shared_ptr<aidl::android::net::IDnsResolver> mDnsResolver;
257 std::vector<LogData> mExpectedLogData;
258 std::vector<PossibleLogData> mExpectedLogDataWithPacel;
259 };
260
261 class TimedOperation : public Stopwatch {
262 public:
TimedOperation(const std::string & name)263 explicit TimedOperation(const std::string& name) : mName(name) {}
~TimedOperation()264 virtual ~TimedOperation() {
265 std::cerr << " " << mName << ": " << timeTakenUs() << "us" << std::endl;
266 }
267
268 private:
269 std::string mName;
270 };
271
TEST_F(DnsResolverBinderTest,IsAlive)272 TEST_F(DnsResolverBinderTest, IsAlive) {
273 TimedOperation t("isAlive RPC");
274 bool isAlive = false;
275 mDnsResolver->isAlive(&isAlive);
276 ASSERT_TRUE(isAlive);
277 }
278
TEST_F(DnsResolverBinderTest,RegisterEventListener_NullListener)279 TEST_F(DnsResolverBinderTest, RegisterEventListener_NullListener) {
280 ::ndk::ScopedAStatus status = mDnsResolver->registerEventListener(nullptr);
281 ASSERT_FALSE(status.isOk());
282 ASSERT_EQ(EINVAL, status.getServiceSpecificError());
283 mExpectedLogData.push_back(
284 {"registerEventListener() -> ServiceSpecificException(22, \"Invalid argument\")",
285 "registerEventListener.*22"});
286 }
287
TEST_F(DnsResolverBinderTest,RegisterEventListener_DuplicateSubscription)288 TEST_F(DnsResolverBinderTest, RegisterEventListener_DuplicateSubscription) {
289 class FakeListener : public android::net::metrics::BaseMetricsListener {};
290
291 // Expect to subscribe successfully.
292 std::shared_ptr<FakeListener> fakeListener = ndk::SharedRefBase::make<FakeListener>();
293 ::ndk::ScopedAStatus status = mDnsResolver->registerEventListener(fakeListener);
294 ASSERT_TRUE(status.isOk()) << status.getMessage();
295 mExpectedLogData.push_back({"registerEventListener()", "registerEventListener.*"});
296
297 // Expect to subscribe failed with registered listener instance.
298 status = mDnsResolver->registerEventListener(fakeListener);
299 ASSERT_FALSE(status.isOk());
300 ASSERT_EQ(EEXIST, status.getServiceSpecificError());
301 mExpectedLogData.push_back(
302 {"registerEventListener() -> ServiceSpecificException(17, \"File exists\")",
303 "registerEventListener.*17"});
304 }
305
TEST_F(DnsResolverBinderTest,RegisterUnsolicitedEventListener_NullListener)306 TEST_F(DnsResolverBinderTest, RegisterUnsolicitedEventListener_NullListener) {
307 ::ndk::ScopedAStatus status = mDnsResolver->registerUnsolicitedEventListener(nullptr);
308 ASSERT_FALSE(status.isOk());
309 ASSERT_EQ(EINVAL, status.getServiceSpecificError());
310 mExpectedLogData.push_back(
311 {"registerUnsolicitedEventListener() -> ServiceSpecificException(22, \"Invalid "
312 "argument\")",
313 "registerUnsolicitedEventListener.*22"});
314 }
315
TEST_F(DnsResolverBinderTest,RegisterUnsolicitedEventListener_DuplicateSubscription)316 TEST_F(DnsResolverBinderTest, RegisterUnsolicitedEventListener_DuplicateSubscription) {
317 // Expect to subscribe successfully.
318 std::shared_ptr<UnsolicitedEventListener> listener =
319 ndk::SharedRefBase::make<UnsolicitedEventListener>(TEST_NETID);
320 ::ndk::ScopedAStatus status = mDnsResolver->registerUnsolicitedEventListener(listener);
321 ASSERT_TRUE(status.isOk()) << status.getMessage();
322 mExpectedLogData.push_back(
323 {"registerUnsolicitedEventListener()", "registerUnsolicitedEventListener.*"});
324
325 // Expect to subscribe failed with registered listener instance.
326 status = mDnsResolver->registerUnsolicitedEventListener(listener);
327 ASSERT_FALSE(status.isOk());
328 ASSERT_EQ(EEXIST, status.getServiceSpecificError());
329 mExpectedLogData.push_back(
330 {"registerUnsolicitedEventListener() -> ServiceSpecificException(17, \"File exists\")",
331 "registerUnsolicitedEventListener.*17"});
332 }
333
334 // TODO: Move this test to resolv_integration_test.cpp
TEST_F(DnsResolverBinderTest,RegisterEventListener_onDnsEvent)335 TEST_F(DnsResolverBinderTest, RegisterEventListener_onDnsEvent) {
336 // The test configs are used to trigger expected events. The expected results are defined in
337 // expectedResults.
338 static const struct TestConfig {
339 std::string hostname;
340 int returnCode;
341 } testConfigs[] = {
342 {"hi", 0 /*success*/},
343 {"nonexistent", EAI_NODATA},
344 };
345
346 // The expected results define expected event content for test verification.
347 static const std::vector<TestOnDnsEvent::TestResult> expectedResults = {
348 {TEST_NETID, INetdEventListener::EVENT_GETADDRINFO, 0 /*success*/, 1, "hi", "1.2.3.4"},
349 {TEST_NETID, INetdEventListener::EVENT_GETADDRINFO, EAI_NODATA, 0, "nonexistent", ""},
350 };
351
352 // Start the Binder thread pool.
353 // TODO: Consider doing this once if there has another event listener unit test.
354 ABinderProcess_startThreadPool();
355
356 // Setup network.
357 // TODO: Setup device configuration and DNS responser server as resolver test does.
358 // Currently, leave DNS related configuration in this test because only it needs DNS
359 // client-server testing environment.
360 DnsResponderClient dnsClient;
361 dnsClient.SetUp();
362
363 // Setup DNS responder server.
364 constexpr char listen_srv[] = "53";
365 test::DNSResponder dns(kDefaultServer, listen_srv, ns_rcode::ns_r_servfail);
366 dns.addMapping("hi.example.com.", ns_type::ns_t_a, "1.2.3.4");
367 ASSERT_TRUE(dns.startServer());
368
369 // Setup DNS configuration.
370 ASSERT_TRUE(dnsClient.SetResolversForNetwork());
371 dns.clearQueries();
372
373 // Register event listener.
374 std::shared_ptr<TestOnDnsEvent> testOnDnsEvent =
375 ndk::SharedRefBase::make<TestOnDnsEvent>(expectedResults);
376 ::ndk::ScopedAStatus status = mDnsResolver->registerEventListener(testOnDnsEvent);
377 ASSERT_TRUE(status.isOk()) << status.getMessage();
378 mExpectedLogData.push_back({"registerEventListener()", "registerEventListener.*"});
379
380 // DNS queries.
381 // Once all expected events of expectedResults are received by the listener, the unit test will
382 // be notified. Otherwise, notified with a timeout expired failure.
383 auto& cv = testOnDnsEvent->getCv();
384 auto& cvMutex = testOnDnsEvent->getCvMutex();
385 {
386 std::unique_lock lock(cvMutex);
387
388 for (const auto& config : testConfigs) {
389 SCOPED_TRACE(config.hostname);
390
391 addrinfo* result = nullptr;
392 addrinfo hints = {.ai_family = AF_INET, .ai_socktype = SOCK_DGRAM};
393 int status = getaddrinfo(config.hostname.c_str(), nullptr, &hints, &result);
394 EXPECT_EQ(config.returnCode, status);
395
396 if (result) freeaddrinfo(result);
397 }
398
399 // Wait for receiving expected events.
400 EXPECT_EQ(std::cv_status::no_timeout, cv.wait_for(lock, std::chrono::seconds(2)));
401 }
402
403 // Verify that all testcases are passed.
404 EXPECT_TRUE(testOnDnsEvent->isVerified());
405
406 dnsClient.TearDown();
407 }
408
409 // TODO: Need to test more than one server cases.
TEST_F(DnsResolverBinderTest,SetResolverConfiguration_Tls)410 TEST_F(DnsResolverBinderTest, SetResolverConfiguration_Tls) {
411 const std::vector<std::string> LOCALLY_ASSIGNED_DNS{"8.8.8.8", "2001:4860:4860::8888"};
412 static const std::vector<std::string> valid_v4_addr = {"192.0.2.1"};
413 static const std::vector<std::string> valid_v6_addr = {"2001:db8::2"};
414 static const std::vector<std::string> invalid_v4_addr = {"192.0.*.5"};
415 static const std::vector<std::string> invalid_v6_addr = {"2001:dg8::6"};
416 constexpr char valid_tls_name[] = "example.com";
417 // We enumerate valid and invalid v4/v6 address, and several different TLS names
418 // to be the input data and verify the binder status.
419 static const struct TestData {
420 const std::vector<std::string> servers;
421 const std::string tlsName;
422 const int expectedReturnCode;
423 } kTlsTestData[] = {
424 {valid_v4_addr, valid_tls_name, 0},
425 {valid_v4_addr, "host.com", 0},
426 {valid_v4_addr, "@@@@", 0},
427 {valid_v4_addr, "", 0},
428 {valid_v6_addr, valid_tls_name, 0},
429 {valid_v6_addr, "host.com", 0},
430 {valid_v6_addr, "@@@@", 0},
431 {valid_v6_addr, "", 0},
432 {invalid_v4_addr, valid_tls_name, EINVAL},
433 {invalid_v4_addr, "host.com", EINVAL},
434 {invalid_v4_addr, "@@@@", EINVAL},
435 {invalid_v4_addr, "", EINVAL},
436 {invalid_v6_addr, valid_tls_name, EINVAL},
437 {invalid_v6_addr, "host.com", EINVAL},
438 {invalid_v6_addr, "@@@@", EINVAL},
439 {invalid_v6_addr, "", EINVAL},
440 {{}, "", 0},
441 {{""}, "", EINVAL},
442 };
443
444 for (size_t i = 0; i < std::size(kTlsTestData); i++) {
445 const auto& td = kTlsTestData[i];
446 const auto resolverParams = ResolverParams::Builder()
447 .setDnsServers(LOCALLY_ASSIGNED_DNS)
448 .setDotServers(td.servers)
449 .setPrivateDnsProvider(td.tlsName)
450 .build();
451 ::ndk::ScopedAStatus status = mDnsResolver->setResolverConfiguration(resolverParams);
452
453 if (td.expectedReturnCode == 0) {
454 SCOPED_TRACE(fmt::format("test case {} should have passed", i));
455 SCOPED_TRACE(status.getMessage());
456 EXPECT_EQ(0, status.getServiceSpecificError());
457 mExpectedLogDataWithPacel.push_back(toSetResolverConfigurationLogData(resolverParams));
458 } else {
459 SCOPED_TRACE(fmt::format("test case {} should have failed", i));
460 EXPECT_EQ(EX_SERVICE_SPECIFIC, status.getExceptionCode());
461 EXPECT_EQ(td.expectedReturnCode, status.getServiceSpecificError());
462 mExpectedLogDataWithPacel.push_back(
463 toSetResolverConfigurationLogData(resolverParams, td.expectedReturnCode));
464 }
465 }
466 }
467
TEST_F(DnsResolverBinderTest,SetResolverConfiguration_TransportTypes)468 TEST_F(DnsResolverBinderTest, SetResolverConfiguration_TransportTypes) {
469 using ::testing::HasSubstr;
470 auto resolverParams = DnsResponderClient::GetDefaultResolverParamsParcel();
471 resolverParams.transportTypes = {IDnsResolver::TRANSPORT_WIFI, IDnsResolver::TRANSPORT_VPN};
472 ::ndk::ScopedAStatus status = mDnsResolver->setResolverConfiguration(resolverParams);
473 EXPECT_TRUE(status.isOk()) << status.getMessage();
474 mExpectedLogDataWithPacel.push_back(toSetResolverConfigurationLogData(resolverParams));
475 // TODO: Find a way to fix a potential deadlock here if it's larger than pipe buffer
476 // size(65535).
477 android::base::unique_fd writeFd, readFd;
478 EXPECT_TRUE(Pipe(&readFd, &writeFd));
479 EXPECT_EQ(mDnsResolver->dump(writeFd.get(), nullptr, 0), 0);
480 writeFd.reset();
481 std::string str;
482 ASSERT_TRUE(ReadFdToString(readFd, &str)) << strerror(errno);
483 EXPECT_THAT(str, HasSubstr("WIFI_VPN"));
484 }
485
TEST_F(DnsResolverBinderTest,SetResolverConfiguration_TransportTypes_Default)486 TEST_F(DnsResolverBinderTest, SetResolverConfiguration_TransportTypes_Default) {
487 using ::testing::HasSubstr;
488 auto resolverParams = DnsResponderClient::GetDefaultResolverParamsParcel();
489 ::ndk::ScopedAStatus status = mDnsResolver->setResolverConfiguration(resolverParams);
490 EXPECT_TRUE(status.isOk()) << status.getMessage();
491 mExpectedLogDataWithPacel.push_back(toSetResolverConfigurationLogData(resolverParams));
492 android::base::unique_fd writeFd, readFd;
493 EXPECT_TRUE(Pipe(&readFd, &writeFd));
494 EXPECT_EQ(mDnsResolver->dump(writeFd.get(), nullptr, 0), 0);
495 writeFd.reset();
496 std::string str;
497 ASSERT_TRUE(ReadFdToString(readFd, &str)) << strerror(errno);
498 EXPECT_THAT(str, HasSubstr("UNKNOWN"));
499 }
500
TEST_F(DnsResolverBinderTest,GetResolverInfo)501 TEST_F(DnsResolverBinderTest, GetResolverInfo) {
502 std::vector<std::string> servers = {"127.0.0.1", "127.0.0.2"};
503 std::vector<std::string> domains = {"example.com"};
504 std::array<int, aidl::android::net::IDnsResolver::RESOLVER_PARAMS_COUNT> testParams = {
505 300, // sample validity in seconds
506 25, // success threshod in percent
507 8, 8, // {MIN,MAX}_SAMPLES
508 100, // BASE_TIMEOUT_MSEC
509 3, // retry count
510 };
511 const auto resolverParams = ResolverParams::Builder()
512 .setDomains(domains)
513 .setDnsServers(servers)
514 .setDotServers({})
515 .setParams(testParams)
516 .build();
517 ::ndk::ScopedAStatus status = mDnsResolver->setResolverConfiguration(resolverParams);
518 EXPECT_TRUE(status.isOk()) << status.getMessage();
519 mExpectedLogDataWithPacel.push_back(toSetResolverConfigurationLogData(resolverParams));
520
521 std::vector<std::string> res_servers;
522 std::vector<std::string> res_domains;
523 std::vector<std::string> res_tls_servers;
524 std::vector<int32_t> params32;
525 std::vector<int32_t> stats32;
526 std::vector<int32_t> wait_for_pending_req_timeout_count32{0};
527 status = mDnsResolver->getResolverInfo(TEST_NETID, &res_servers, &res_domains, &res_tls_servers,
528 ¶ms32, &stats32,
529 &wait_for_pending_req_timeout_count32);
530
531 EXPECT_TRUE(status.isOk()) << status.getMessage();
532 EXPECT_EQ(servers.size(), res_servers.size());
533 EXPECT_EQ(domains.size(), res_domains.size());
534 EXPECT_EQ(0U, res_tls_servers.size());
535 ASSERT_EQ(static_cast<size_t>(IDnsResolver::RESOLVER_PARAMS_COUNT), testParams.size());
536 EXPECT_EQ(testParams[IDnsResolver::RESOLVER_PARAMS_SAMPLE_VALIDITY],
537 params32[IDnsResolver::RESOLVER_PARAMS_SAMPLE_VALIDITY]);
538 EXPECT_EQ(testParams[IDnsResolver::RESOLVER_PARAMS_SUCCESS_THRESHOLD],
539 params32[IDnsResolver::RESOLVER_PARAMS_SUCCESS_THRESHOLD]);
540 EXPECT_EQ(testParams[IDnsResolver::RESOLVER_PARAMS_MIN_SAMPLES],
541 params32[IDnsResolver::RESOLVER_PARAMS_MIN_SAMPLES]);
542 EXPECT_EQ(testParams[IDnsResolver::RESOLVER_PARAMS_MAX_SAMPLES],
543 params32[IDnsResolver::RESOLVER_PARAMS_MAX_SAMPLES]);
544 EXPECT_EQ(testParams[IDnsResolver::RESOLVER_PARAMS_BASE_TIMEOUT_MSEC],
545 params32[IDnsResolver::RESOLVER_PARAMS_BASE_TIMEOUT_MSEC]);
546 EXPECT_EQ(testParams[IDnsResolver::RESOLVER_PARAMS_RETRY_COUNT],
547 params32[IDnsResolver::RESOLVER_PARAMS_RETRY_COUNT]);
548
549 std::vector<ResolverStats> stats;
550 ResolverStats::decodeAll(stats32, &stats);
551
552 EXPECT_EQ(servers.size(), stats.size());
553
554 EXPECT_THAT(res_servers, testing::UnorderedElementsAreArray(servers));
555 EXPECT_THAT(res_domains, testing::UnorderedElementsAreArray(domains));
556 }
557
TEST_F(DnsResolverBinderTest,CreateDestroyNetworkCache)558 TEST_F(DnsResolverBinderTest, CreateDestroyNetworkCache) {
559 // Must not be the same as TEST_NETID
560 const int ANOTHER_TEST_NETID = TEST_NETID + 1;
561
562 // Create a new network cache.
563 EXPECT_TRUE(mDnsResolver->createNetworkCache(ANOTHER_TEST_NETID).isOk());
564 mExpectedLogData.push_back({"createNetworkCache(31)", "createNetworkCache.*31"});
565
566 // create it again, expect a EEXIST.
567 EXPECT_EQ(EEXIST,
568 mDnsResolver->createNetworkCache(ANOTHER_TEST_NETID).getServiceSpecificError());
569 mExpectedLogData.push_back(
570 {"createNetworkCache(31) -> ServiceSpecificException(17, \"File exists\")",
571 "createNetworkCache.*31.*17"});
572
573 // destroy it.
574 EXPECT_TRUE(mDnsResolver->destroyNetworkCache(ANOTHER_TEST_NETID).isOk());
575 mExpectedLogData.push_back({"destroyNetworkCache(31)", "destroyNetworkCache.*31"});
576
577 // re-create it
578 EXPECT_TRUE(mDnsResolver->createNetworkCache(ANOTHER_TEST_NETID).isOk());
579 mExpectedLogData.push_back({"createNetworkCache(31)", "createNetworkCache.*31"});
580
581 // destroy it.
582 EXPECT_TRUE(mDnsResolver->destroyNetworkCache(ANOTHER_TEST_NETID).isOk());
583 mExpectedLogData.push_back({"destroyNetworkCache(31)", "destroyNetworkCache.*31"});
584
585 // re-destroy it
586 EXPECT_TRUE(mDnsResolver->destroyNetworkCache(ANOTHER_TEST_NETID).isOk());
587 mExpectedLogData.push_back({"destroyNetworkCache(31)", "destroyNetworkCache.*31"});
588 }
589
TEST_F(DnsResolverBinderTest,FlushNetworkCache)590 TEST_F(DnsResolverBinderTest, FlushNetworkCache) {
591 SKIP_IF_REMOTE_VERSION_LESS_THAN(mDnsResolver.get(), 4);
592 // cache has beed created in DnsResolverBinderTest constructor
593 EXPECT_TRUE(mDnsResolver->flushNetworkCache(TEST_NETID).isOk());
594 mExpectedLogData.push_back({"flushNetworkCache(30)", "destroyNetworkCache.*30"});
595 EXPECT_EQ(ENONET, mDnsResolver->flushNetworkCache(-1).getServiceSpecificError());
596 mExpectedLogData.push_back(
597 {"flushNetworkCache(-1) -> ServiceSpecificException(64, \"Machine is not on the "
598 "network\")",
599 "flushNetworkCache.*-1.*64"});
600 }
601
TEST_F(DnsResolverBinderTest,setLogSeverity)602 TEST_F(DnsResolverBinderTest, setLogSeverity) {
603 // Expect fail
604 EXPECT_EQ(EINVAL, mDnsResolver->setLogSeverity(-1).getServiceSpecificError());
605 mExpectedLogData.push_back(
606 {"setLogSeverity(-1) -> ServiceSpecificException(22, \"Invalid argument\")",
607 "flushNetworkCache.*-1.*22"});
608
609 // Test set different log level
610 EXPECT_TRUE(mDnsResolver->setLogSeverity(IDnsResolver::DNS_RESOLVER_LOG_VERBOSE).isOk());
611 mExpectedLogData.push_back({"setLogSeverity(0)", "setLogSeverity.*0"});
612
613 EXPECT_TRUE(mDnsResolver->setLogSeverity(IDnsResolver::DNS_RESOLVER_LOG_DEBUG).isOk());
614 mExpectedLogData.push_back({"setLogSeverity(1)", "setLogSeverity.*1"});
615
616 EXPECT_TRUE(mDnsResolver->setLogSeverity(IDnsResolver::DNS_RESOLVER_LOG_INFO).isOk());
617 mExpectedLogData.push_back({"setLogSeverity(2)", "setLogSeverity.*2"});
618
619 EXPECT_TRUE(mDnsResolver->setLogSeverity(IDnsResolver::DNS_RESOLVER_LOG_WARNING).isOk());
620 mExpectedLogData.push_back({"setLogSeverity(3)", "setLogSeverity.*3"});
621
622 EXPECT_TRUE(mDnsResolver->setLogSeverity(IDnsResolver::DNS_RESOLVER_LOG_ERROR).isOk());
623 mExpectedLogData.push_back({"setLogSeverity(4)", "setLogSeverity.*4"});
624
625 // Set back to default based off resolv_init(), the default is INFO for userdebug/eng builds
626 // and is WARNING for the other builds.
627 if (isDebuggable()) {
628 EXPECT_TRUE(mDnsResolver->setLogSeverity(IDnsResolver::DNS_RESOLVER_LOG_INFO).isOk());
629 mExpectedLogData.push_back({"setLogSeverity(2)", "setLogSeverity.*2"});
630 } else {
631 EXPECT_TRUE(mDnsResolver->setLogSeverity(IDnsResolver::DNS_RESOLVER_LOG_WARNING).isOk());
632 mExpectedLogData.push_back({"setLogSeverity(3)", "setLogSeverity.*3"});
633 }
634 }
635
TEST_F(DnsResolverBinderTest,SetResolverOptions)636 TEST_F(DnsResolverBinderTest, SetResolverOptions) {
637 SKIP_IF_REMOTE_VERSION_LESS_THAN(mDnsResolver.get(), 9);
638 ResolverOptionsParcel options;
639 options.tcMode = 1;
640 options.enforceDnsUid = true;
641 EXPECT_TRUE(mDnsResolver->setResolverOptions(TEST_NETID, options).isOk());
642 mExpectedLogData.push_back(
643 {"setResolverOptions(30, " + toString(options) + ")", "setResolverOptions.*30"});
644 EXPECT_EQ(ENONET, mDnsResolver->setResolverOptions(-1, options).getServiceSpecificError());
645 mExpectedLogData.push_back({"setResolverOptions(-1, " + toString(options) +
646 ") -> ServiceSpecificException(64, \"Machine is not on the "
647 "network\")",
648 "setResolverOptions.*-1.*64"});
649 }
650