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/stringprintf.h>
33 #include <android-base/strings.h>
34 #include <android-base/unique_fd.h>
35 #include <android/binder_manager.h>
36 #include <android/binder_process.h>
37 #include <gmock/gmock-matchers.h>
38 #include <gtest/gtest.h>
39 #include <netdutils/Stopwatch.h>
40
41 #include "dns_metrics_listener/base_metrics_listener.h"
42 #include "dns_metrics_listener/test_metrics.h"
43 #include "unsolicited_listener/unsolicited_event_listener.h"
44
45 #include "ResolverStats.h"
46 #include "dns_responder.h"
47 #include "dns_responder_client_ndk.h"
48
49 using aidl::android::net::IDnsResolver;
50 using aidl::android::net::ResolverHostsParcel;
51 using aidl::android::net::ResolverOptionsParcel;
52 using aidl::android::net::ResolverParamsParcel;
53 using aidl::android::net::metrics::INetdEventListener;
54 using android::base::ReadFdToString;
55 using android::base::StringPrintf;
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 ::testing::Test {
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 from S that will add "(null)" to
142 // the log on method's argument if binder object is null. But Q and R don't
143 // have this format in log. So to make register null listener tests are
144 // compatible from all version, just remove the "(null)" argument from
145 // output logs if existed.
146 const std::string output = android::base::StringReplace(
147 match[1].str(), "(null)", "", /*all=*/true);
148 return output == td.output;
149 });
150 EXPECT_TRUE(found) << "Didn't find line '" << td.output << "' in dumpsys output.";
151 if (found) continue;
152 std::cerr << "Similar lines" << std::endl;
153 for (const auto& line : lines) {
154 if (std::regex_search(line, std::basic_regex(td.hintRegex))) {
155 std::cerr << line << std::endl;
156 }
157 }
158 }
159
160 // The log output is different between R and S, either one is fine for the
161 // test to avoid test compatible issue.
162 // TODO: Remove after S.
163 for (const auto& td : mExpectedLogDataWithPacel) {
164 const bool found =
165 std::any_of(lines.begin(), lines.end(), [&](const std::string& line) {
166 std::smatch match;
167 if (!std::regex_match(line, match, lineRegex)) return false;
168 return (match.size() == 2) && ((match[1].str() == td.withPacel.output) ||
169 (match[1].str() == td.withoutPacel.output));
170 });
171 EXPECT_TRUE(found) << fmt::format("Didn't find line '{}' or '{}' in dumpsys output.",
172 td.withPacel.output, td.withoutPacel.output);
173 if (found) continue;
174 std::cerr << "Similar lines" << std::endl;
175 for (const auto& line : lines) {
176 if (std::regex_search(line, std::basic_regex(td.withPacel.hintRegex))) {
177 std::cerr << line << std::endl;
178 }
179 if (std::regex_search(line, std::basic_regex(td.withoutPacel.hintRegex))) {
180 std::cerr << line << std::endl;
181 }
182 }
183 }
184 }
185
186 struct LogData {
187 // Expected contents of the dump command.
188 const std::string output;
189 // A regex that might be helpful in matching relevant lines in the output.
190 // Used to make it easier to add test cases for this code.
191 const std::string hintRegex;
192 };
193
194 // TODO: Remove this struct and below toString methods after S.
195 struct PossibleLogData {
196 LogData withPacel;
197 LogData withoutPacel;
198 };
199
toString(const std::vector<ResolverHostsParcel> & parms)200 std::string toString(const std::vector<ResolverHostsParcel>& parms) {
201 std::string o;
202 const size_t size = parms.size();
203 for (size_t i = 0; i < size; ++i) {
204 o.append(fmt::format("ResolverHostsParcel{{ipAddr: {}, hostName: {}}}", parms[i].ipAddr,
205 parms[i].hostName));
206 if (i + 1 < size) o.append(", ");
207 }
208 return o;
209 }
210
toString(const std::optional<ResolverOptionsParcel> & parms)211 std::string toString(const std::optional<ResolverOptionsParcel>& parms) {
212 if (!parms.has_value()) return "(null)";
213 return fmt::format("ResolverOptionsParcel{{hosts: [{}], tcMode: {}, enforceDnsUid: {}}}",
214 toString(parms->hosts), parms->tcMode, parms->enforceDnsUid);
215 }
216
toString(const ResolverParamsParcel & parms)217 std::string toString(const ResolverParamsParcel& parms) {
218 return fmt::format(
219 "ResolverParamsParcel{{netId: {}, sampleValiditySeconds: {}, successThreshold: {}, "
220 "minSamples: {}, "
221 "maxSamples: {}, baseTimeoutMsec: {}, retryCount: {}, "
222 "servers: [{}], domains: [{}], "
223 "tlsName: {}, tlsServers: [{}], "
224 "tlsFingerprints: [{}], "
225 "caCertificate: {}, tlsConnectTimeoutMs: {}, "
226 "resolverOptions: {}, transportTypes: [{}]}}",
227 parms.netId, parms.sampleValiditySeconds, parms.successThreshold, parms.minSamples,
228 parms.maxSamples, parms.baseTimeoutMsec, parms.retryCount,
229 fmt::join(parms.servers, ", "), fmt::join(parms.domains, ", "), parms.tlsName,
230 fmt::join(parms.tlsServers, ", "), fmt::join(parms.tlsFingerprints, ", "),
231 android::base::StringReplace(parms.caCertificate, "\n", "\\n", true),
232 parms.tlsConnectTimeoutMs, toString(parms.resolverOptions),
233 fmt::join(parms.transportTypes, ", "));
234 }
235
toSetResolverConfigurationLogData(const ResolverParamsParcel & parms,int returnCode=0)236 PossibleLogData toSetResolverConfigurationLogData(const ResolverParamsParcel& parms,
237 int returnCode = 0) {
238 std::string outputWithParcel = "setResolverConfiguration(" + toString(parms) + ")";
239 std::string hintRegexWithParcel = fmt::format("setResolverConfiguration.*{}", parms.netId);
240
241 std::string outputWithoutParcel = "setResolverConfiguration()";
242 std::string hintRegexWithoutParcel = "setResolverConfiguration";
243 if (returnCode != 0) {
244 outputWithParcel.append(fmt::format(" -> ServiceSpecificException({}, \"{}\")",
245 returnCode, strerror(returnCode)));
246 hintRegexWithParcel.append(fmt::format(".*{}", returnCode));
247 outputWithoutParcel.append(fmt::format(" -> ServiceSpecificException({}, \"{}\")",
248 returnCode, strerror(returnCode)));
249 hintRegexWithoutParcel.append(fmt::format(".*{}", returnCode));
250 }
251 return {{std::move(outputWithParcel), std::move(hintRegexWithParcel)},
252 {std::move(outputWithoutParcel), std::move(hintRegexWithoutParcel)}};
253 }
254
255 std::shared_ptr<aidl::android::net::IDnsResolver> mDnsResolver;
256 std::vector<LogData> mExpectedLogData;
257 std::vector<PossibleLogData> mExpectedLogDataWithPacel;
258 };
259
260 class TimedOperation : public Stopwatch {
261 public:
TimedOperation(const std::string & name)262 explicit TimedOperation(const std::string& name) : mName(name) {}
~TimedOperation()263 virtual ~TimedOperation() {
264 std::cerr << " " << mName << ": " << timeTakenUs() << "us" << std::endl;
265 }
266
267 private:
268 std::string mName;
269 };
270
TEST_F(DnsResolverBinderTest,IsAlive)271 TEST_F(DnsResolverBinderTest, IsAlive) {
272 TimedOperation t("isAlive RPC");
273 bool isAlive = false;
274 mDnsResolver->isAlive(&isAlive);
275 ASSERT_TRUE(isAlive);
276 }
277
TEST_F(DnsResolverBinderTest,RegisterEventListener_NullListener)278 TEST_F(DnsResolverBinderTest, RegisterEventListener_NullListener) {
279 ::ndk::ScopedAStatus status = mDnsResolver->registerEventListener(nullptr);
280 ASSERT_FALSE(status.isOk());
281 ASSERT_EQ(EINVAL, status.getServiceSpecificError());
282 mExpectedLogData.push_back(
283 {"registerEventListener() -> ServiceSpecificException(22, \"Invalid argument\")",
284 "registerEventListener.*22"});
285 }
286
TEST_F(DnsResolverBinderTest,RegisterEventListener_DuplicateSubscription)287 TEST_F(DnsResolverBinderTest, RegisterEventListener_DuplicateSubscription) {
288 class FakeListener : public android::net::metrics::BaseMetricsListener {};
289
290 // Expect to subscribe successfully.
291 std::shared_ptr<FakeListener> fakeListener = ndk::SharedRefBase::make<FakeListener>();
292 ::ndk::ScopedAStatus status = mDnsResolver->registerEventListener(fakeListener);
293 ASSERT_TRUE(status.isOk()) << status.getMessage();
294 mExpectedLogData.push_back({"registerEventListener()", "registerEventListener.*"});
295
296 // Expect to subscribe failed with registered listener instance.
297 status = mDnsResolver->registerEventListener(fakeListener);
298 ASSERT_FALSE(status.isOk());
299 ASSERT_EQ(EEXIST, status.getServiceSpecificError());
300 mExpectedLogData.push_back(
301 {"registerEventListener() -> ServiceSpecificException(17, \"File exists\")",
302 "registerEventListener.*17"});
303 }
304
TEST_F(DnsResolverBinderTest,RegisterUnsolicitedEventListener_NullListener)305 TEST_F(DnsResolverBinderTest, RegisterUnsolicitedEventListener_NullListener) {
306 ::ndk::ScopedAStatus status = mDnsResolver->registerUnsolicitedEventListener(nullptr);
307 ASSERT_FALSE(status.isOk());
308 ASSERT_EQ(EINVAL, status.getServiceSpecificError());
309 mExpectedLogData.push_back(
310 {"registerUnsolicitedEventListener() -> ServiceSpecificException(22, \"Invalid "
311 "argument\")",
312 "registerUnsolicitedEventListener.*22"});
313 }
314
TEST_F(DnsResolverBinderTest,RegisterUnsolicitedEventListener_DuplicateSubscription)315 TEST_F(DnsResolverBinderTest, RegisterUnsolicitedEventListener_DuplicateSubscription) {
316 // Expect to subscribe successfully.
317 std::shared_ptr<UnsolicitedEventListener> listener =
318 ndk::SharedRefBase::make<UnsolicitedEventListener>(TEST_NETID);
319 ::ndk::ScopedAStatus status = mDnsResolver->registerUnsolicitedEventListener(listener);
320 ASSERT_TRUE(status.isOk()) << status.getMessage();
321 mExpectedLogData.push_back(
322 {"registerUnsolicitedEventListener()", "registerUnsolicitedEventListener.*"});
323
324 // Expect to subscribe failed with registered listener instance.
325 status = mDnsResolver->registerUnsolicitedEventListener(listener);
326 ASSERT_FALSE(status.isOk());
327 ASSERT_EQ(EEXIST, status.getServiceSpecificError());
328 mExpectedLogData.push_back(
329 {"registerUnsolicitedEventListener() -> ServiceSpecificException(17, \"File exists\")",
330 "registerUnsolicitedEventListener.*17"});
331 }
332
333 // TODO: Move this test to resolv_integration_test.cpp
TEST_F(DnsResolverBinderTest,RegisterEventListener_onDnsEvent)334 TEST_F(DnsResolverBinderTest, RegisterEventListener_onDnsEvent) {
335 // The test configs are used to trigger expected events. The expected results are defined in
336 // expectedResults.
337 static const struct TestConfig {
338 std::string hostname;
339 int returnCode;
340 } testConfigs[] = {
341 {"hi", 0 /*success*/},
342 {"nonexistent", EAI_NODATA},
343 };
344
345 // The expected results define expected event content for test verification.
346 static const std::vector<TestOnDnsEvent::TestResult> expectedResults = {
347 {TEST_NETID, INetdEventListener::EVENT_GETADDRINFO, 0 /*success*/, 1, "hi", "1.2.3.4"},
348 {TEST_NETID, INetdEventListener::EVENT_GETADDRINFO, EAI_NODATA, 0, "nonexistent", ""},
349 };
350
351 // Start the Binder thread pool.
352 // TODO: Consider doing this once if there has another event listener unit test.
353 ABinderProcess_startThreadPool();
354
355 // Setup network.
356 // TODO: Setup device configuration and DNS responser server as resolver test does.
357 // Currently, leave DNS related configuration in this test because only it needs DNS
358 // client-server testing environment.
359 DnsResponderClient dnsClient;
360 dnsClient.SetUp();
361
362 // Setup DNS responder server.
363 constexpr char listen_addr[] = "127.0.0.3";
364 constexpr char listen_srv[] = "53";
365 test::DNSResponder dns(listen_addr, 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 const std::vector<std::string> test_servers = {listen_addr};
371 std::vector<std::string> test_domains = {"example.com"};
372 std::vector<int> test_params = {300 /*sample_validity*/, 25 /*success_threshold*/,
373 8 /*min_samples*/, 8 /*max_samples*/};
374
375 ASSERT_TRUE(dnsClient.SetResolversForNetwork(test_servers, test_domains, test_params));
376 dns.clearQueries();
377
378 // Register event listener.
379 std::shared_ptr<TestOnDnsEvent> testOnDnsEvent =
380 ndk::SharedRefBase::make<TestOnDnsEvent>(expectedResults);
381 ::ndk::ScopedAStatus status = mDnsResolver->registerEventListener(testOnDnsEvent);
382 ASSERT_TRUE(status.isOk()) << status.getMessage();
383 mExpectedLogData.push_back({"registerEventListener()", "registerEventListener.*"});
384
385 // DNS queries.
386 // Once all expected events of expectedResults are received by the listener, the unit test will
387 // be notified. Otherwise, notified with a timeout expired failure.
388 auto& cv = testOnDnsEvent->getCv();
389 auto& cvMutex = testOnDnsEvent->getCvMutex();
390 {
391 std::unique_lock lock(cvMutex);
392
393 for (const auto& config : testConfigs) {
394 SCOPED_TRACE(config.hostname);
395
396 addrinfo* result = nullptr;
397 addrinfo hints = {.ai_family = AF_INET, .ai_socktype = SOCK_DGRAM};
398 int status = getaddrinfo(config.hostname.c_str(), nullptr, &hints, &result);
399 EXPECT_EQ(config.returnCode, status);
400
401 if (result) freeaddrinfo(result);
402 }
403
404 // Wait for receiving expected events.
405 EXPECT_EQ(std::cv_status::no_timeout, cv.wait_for(lock, std::chrono::seconds(2)));
406 }
407
408 // Verify that all testcases are passed.
409 EXPECT_TRUE(testOnDnsEvent->isVerified());
410
411 dnsClient.TearDown();
412 }
413
414 // TODO: Need to test more than one server cases.
TEST_F(DnsResolverBinderTest,SetResolverConfiguration_Tls)415 TEST_F(DnsResolverBinderTest, SetResolverConfiguration_Tls) {
416 const std::vector<std::string> LOCALLY_ASSIGNED_DNS{"8.8.8.8", "2001:4860:4860::8888"};
417 static const std::vector<std::string> valid_v4_addr = {"192.0.2.1"};
418 static const std::vector<std::string> valid_v6_addr = {"2001:db8::2"};
419 static const std::vector<std::string> invalid_v4_addr = {"192.0.*.5"};
420 static const std::vector<std::string> invalid_v6_addr = {"2001:dg8::6"};
421 constexpr char valid_tls_name[] = "example.com";
422 std::vector<int> test_params = {300, 25, 8, 8};
423 // We enumerate valid and invalid v4/v6 address, and several different TLS names
424 // to be the input data and verify the binder status.
425 static const struct TestData {
426 const std::vector<std::string> servers;
427 const std::string tlsName;
428 const int expectedReturnCode;
429 } kTlsTestData[] = {
430 {valid_v4_addr, valid_tls_name, 0},
431 {valid_v4_addr, "host.com", 0},
432 {valid_v4_addr, "@@@@", 0},
433 {valid_v4_addr, "", 0},
434 {valid_v6_addr, valid_tls_name, 0},
435 {valid_v6_addr, "host.com", 0},
436 {valid_v6_addr, "@@@@", 0},
437 {valid_v6_addr, "", 0},
438 {invalid_v4_addr, valid_tls_name, EINVAL},
439 {invalid_v4_addr, "host.com", EINVAL},
440 {invalid_v4_addr, "@@@@", EINVAL},
441 {invalid_v4_addr, "", EINVAL},
442 {invalid_v6_addr, valid_tls_name, EINVAL},
443 {invalid_v6_addr, "host.com", EINVAL},
444 {invalid_v6_addr, "@@@@", EINVAL},
445 {invalid_v6_addr, "", EINVAL},
446 {{}, "", 0},
447 {{""}, "", EINVAL},
448 };
449
450 for (size_t i = 0; i < std::size(kTlsTestData); i++) {
451 const auto& td = kTlsTestData[i];
452
453 const auto resolverParams = DnsResponderClient::makeResolverParamsParcel(
454 TEST_NETID, test_params, LOCALLY_ASSIGNED_DNS, {}, td.tlsName, td.servers);
455 ::ndk::ScopedAStatus status = mDnsResolver->setResolverConfiguration(resolverParams);
456
457 if (td.expectedReturnCode == 0) {
458 SCOPED_TRACE(StringPrintf("test case %zu should have passed", i));
459 SCOPED_TRACE(status.getMessage());
460 EXPECT_EQ(0, status.getServiceSpecificError());
461 mExpectedLogDataWithPacel.push_back(toSetResolverConfigurationLogData(resolverParams));
462 } else {
463 SCOPED_TRACE(StringPrintf("test case %zu should have failed", i));
464 EXPECT_EQ(EX_SERVICE_SPECIFIC, status.getExceptionCode());
465 EXPECT_EQ(td.expectedReturnCode, status.getServiceSpecificError());
466 mExpectedLogDataWithPacel.push_back(
467 toSetResolverConfigurationLogData(resolverParams, td.expectedReturnCode));
468 }
469 }
470 }
471
TEST_F(DnsResolverBinderTest,SetResolverConfiguration_TransportTypes)472 TEST_F(DnsResolverBinderTest, SetResolverConfiguration_TransportTypes) {
473 using ::testing::HasSubstr;
474 auto resolverParams = DnsResponderClient::GetDefaultResolverParamsParcel();
475 resolverParams.transportTypes = {IDnsResolver::TRANSPORT_WIFI, IDnsResolver::TRANSPORT_VPN};
476 ::ndk::ScopedAStatus status = mDnsResolver->setResolverConfiguration(resolverParams);
477 EXPECT_TRUE(status.isOk()) << status.getMessage();
478 mExpectedLogDataWithPacel.push_back(toSetResolverConfigurationLogData(resolverParams));
479 // TODO: Find a way to fix a potential deadlock here if it's larger than pipe buffer
480 // size(65535).
481 android::base::unique_fd writeFd, readFd;
482 EXPECT_TRUE(Pipe(&readFd, &writeFd));
483 EXPECT_EQ(mDnsResolver->dump(writeFd.get(), nullptr, 0), 0);
484 writeFd.reset();
485 std::string str;
486 ASSERT_TRUE(ReadFdToString(readFd, &str)) << strerror(errno);
487 EXPECT_THAT(str, HasSubstr("WIFI_VPN"));
488 }
489
TEST_F(DnsResolverBinderTest,SetResolverConfiguration_TransportTypes_Default)490 TEST_F(DnsResolverBinderTest, SetResolverConfiguration_TransportTypes_Default) {
491 using ::testing::HasSubstr;
492 auto resolverParams = DnsResponderClient::GetDefaultResolverParamsParcel();
493 ::ndk::ScopedAStatus status = mDnsResolver->setResolverConfiguration(resolverParams);
494 EXPECT_TRUE(status.isOk()) << status.getMessage();
495 mExpectedLogDataWithPacel.push_back(toSetResolverConfigurationLogData(resolverParams));
496 android::base::unique_fd writeFd, readFd;
497 EXPECT_TRUE(Pipe(&readFd, &writeFd));
498 EXPECT_EQ(mDnsResolver->dump(writeFd.get(), nullptr, 0), 0);
499 writeFd.reset();
500 std::string str;
501 ASSERT_TRUE(ReadFdToString(readFd, &str)) << strerror(errno);
502 EXPECT_THAT(str, HasSubstr("UNKNOWN"));
503 }
504
TEST_F(DnsResolverBinderTest,GetResolverInfo)505 TEST_F(DnsResolverBinderTest, GetResolverInfo) {
506 std::vector<std::string> servers = {"127.0.0.1", "127.0.0.2"};
507 std::vector<std::string> domains = {"example.com"};
508 std::vector<int> testParams = {
509 300, // sample validity in seconds
510 25, // success threshod in percent
511 8, 8, // {MIN,MAX}_SAMPLES
512 100, // BASE_TIMEOUT_MSEC
513 3, // retry count
514 };
515 const auto resolverParams = DnsResponderClient::makeResolverParamsParcel(
516 TEST_NETID, testParams, servers, domains, "", {});
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
626 EXPECT_TRUE(mDnsResolver->setLogSeverity(IDnsResolver::DNS_RESOLVER_LOG_WARNING).isOk());
627 mExpectedLogData.push_back({"setLogSeverity(3)", "setLogSeverity.*3"});
628 }
629
TEST_F(DnsResolverBinderTest,SetResolverOptions)630 TEST_F(DnsResolverBinderTest, SetResolverOptions) {
631 SKIP_IF_REMOTE_VERSION_LESS_THAN(mDnsResolver.get(), 9);
632 ResolverOptionsParcel options;
633 options.tcMode = 1;
634 options.enforceDnsUid = true;
635 EXPECT_TRUE(mDnsResolver->setResolverOptions(TEST_NETID, options).isOk());
636 mExpectedLogData.push_back(
637 {"setResolverOptions(30, " + toString(options) + ")", "setResolverOptions.*30"});
638 EXPECT_EQ(ENONET, mDnsResolver->setResolverOptions(-1, options).getServiceSpecificError());
639 mExpectedLogData.push_back({"setResolverOptions(-1, " + toString(options) +
640 ") -> ServiceSpecificException(64, \"Machine is not on the "
641 "network\")",
642 "setResolverOptions.*-1.*64"});
643 }
644