1 /*
2 * Copyright (C) 2018 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 #define LOG_TAG "resolv"
18
19 #include <aidl/android/net/IDnsResolver.h>
20 #include <android-base/stringprintf.h>
21 #include <arpa/inet.h>
22 #include <gmock/gmock-matchers.h>
23 #include <gtest/gtest.h>
24 #include <netdb.h>
25 #include <netdutils/InternetAddresses.h>
26 #include <resolv_stats_test_utils.h>
27
28 #include "dns_responder.h"
29 #include "getaddrinfo.h"
30 #include "gethnamaddr.h"
31 #include "resolv_cache.h"
32 #include "stats.pb.h"
33 #include "tests/resolv_test_utils.h"
34
35 #define NAME(variable) #variable
36
37 namespace android {
38 namespace net {
39
40 using aidl::android::net::IDnsResolver;
41 using android::base::StringPrintf;
42 using android::net::NetworkDnsEventReported;
43 using android::netdutils::ScopedAddrinfo;
44
45 // The buffer size of resolv_gethostbyname().
46 constexpr unsigned int MAXPACKET = 8 * 1024;
47
48 // Specifying 0 in ai_socktype or ai_protocol of struct addrinfo indicates
49 // that any type or protocol can be returned by getaddrinfo().
50 constexpr unsigned int ANY = 0;
51
52 class TestBase : public ::testing::Test {
53 protected:
54 struct DnsMessage {
55 std::string host_name; // host name
56 ns_type type; // record type
57 test::DNSHeader header; // dns header
58 };
59
SetUp()60 void SetUp() override {
61 // Create cache for test
62 resolv_create_cache_for_net(TEST_NETID);
63 }
TearDown()64 void TearDown() override {
65 // Delete cache for test
66 resolv_delete_cache_for_net(TEST_NETID);
67 }
68
MakeAnswerRecord(const std::string & name,unsigned rclass,unsigned rtype,const std::string & rdata,unsigned ttl=kAnswerRecordTtlSec)69 test::DNSRecord MakeAnswerRecord(const std::string& name, unsigned rclass, unsigned rtype,
70 const std::string& rdata, unsigned ttl = kAnswerRecordTtlSec) {
71 test::DNSRecord record{
72 .name = {.name = name},
73 .rtype = rtype,
74 .rclass = rclass,
75 .ttl = ttl,
76 };
77 EXPECT_TRUE(test::DNSResponder::fillRdata(rdata, record));
78 return record;
79 }
80
MakeDnsMessage(const std::string & qname,ns_type qtype,const std::vector<std::string> & rdata)81 DnsMessage MakeDnsMessage(const std::string& qname, ns_type qtype,
82 const std::vector<std::string>& rdata) {
83 const unsigned qclass = ns_c_in;
84 // Build a DNSHeader in the following format.
85 // Question
86 // <qname> IN <qtype>
87 // Answer
88 // <qname> IN <qtype> <rdata[0]>
89 // ..
90 // <qname> IN <qtype> <rdata[n]>
91 //
92 // Example:
93 // Question
94 // hello.example.com. IN A
95 // Answer
96 // hello.example.com. IN A 1.2.3.1
97 // ..
98 // hello.example.com. IN A 1.2.3.9
99 test::DNSHeader header(kDefaultDnsHeader);
100
101 // Question section
102 test::DNSQuestion question{
103 .qname = {.name = qname},
104 .qtype = qtype,
105 .qclass = qclass,
106 };
107 header.questions.push_back(std::move(question));
108
109 // Answer section
110 for (const auto& r : rdata) {
111 test::DNSRecord record = MakeAnswerRecord(qname, qclass, qtype, r);
112 header.answers.push_back(std::move(record));
113 }
114 // TODO: Perhaps add support for authority RRs and additional RRs.
115 return {qname, qtype, header};
116 }
117
StartDns(test::DNSResponder & dns,const std::vector<DnsMessage> & messages)118 void StartDns(test::DNSResponder& dns, const std::vector<DnsMessage>& messages) {
119 for (const auto& m : messages) {
120 dns.addMappingDnsHeader(m.host_name, m.type, m.header);
121 }
122 ASSERT_TRUE(dns.startServer());
123 dns.clearQueries();
124 }
125
SetResolvers()126 int SetResolvers() {
127 return resolv_set_nameservers(TEST_NETID, servers, domains, params);
128 }
129
130 const android_net_context mNetcontext = {
131 .app_netid = TEST_NETID,
132 .app_mark = MARK_UNSET,
133 .dns_netid = TEST_NETID,
134 .dns_mark = MARK_UNSET,
135 .uid = NET_CONTEXT_INVALID_UID,
136 };
137 const std::vector<std::string> servers = {test::kDefaultListenAddr};
138 const std::vector<std::string> domains = {"example.com"};
139 const res_params params = {
140 .sample_validity = 300,
141 .success_threshold = 25,
142 .min_samples = 8,
143 .max_samples = 8,
144 .base_timeout_msec = 1000,
145 .retry_count = 2,
146 };
147 };
148
149 class ResolvGetAddrInfoTest : public TestBase {};
150 class GetHostByNameForNetContextTest : public TestBase {};
151 class ResolvCommonFunctionTest : public TestBase {};
152
TEST_F(ResolvGetAddrInfoTest,InvalidParameters)153 TEST_F(ResolvGetAddrInfoTest, InvalidParameters) {
154 // Both null "netcontext" and null "res" of resolv_getaddrinfo() are not tested
155 // here because they are checked by assert() without returning any error number.
156
157 // Invalid hostname and servname.
158 // Both hostname and servname are null pointers. Expect error number EAI_NONAME.
159 {
160 addrinfo* result = nullptr;
161 NetworkDnsEventReported event;
162 int rv = resolv_getaddrinfo(nullptr /*hostname*/, nullptr /*servname*/, nullptr /*hints*/,
163 &mNetcontext, &result, &event);
164 ScopedAddrinfo result_cleanup(result);
165 EXPECT_EQ(EAI_NONAME, rv);
166 }
167
168 // Invalid hints.
169 // These place holders are used to test function call with unrequired parameters.
170 // The content is not important because function call returns error directly if
171 // there have any unrequired parameter.
172 char placeholder_cname[] = "invalid_cname";
173 sockaddr placeholder_addr = {};
174 addrinfo placeholder_next = {};
175 static const struct TestConfig {
176 int ai_flags;
177 socklen_t ai_addrlen;
178 char* ai_canonname;
179 sockaddr* ai_addr;
180 addrinfo* ai_next;
181
182 int expected_eai_error;
183
184 std::string asParameters() const {
185 return StringPrintf("0x%x/%u/%s/%p/%p", ai_flags, ai_addrlen,
186 ai_canonname ? ai_canonname : "(null)", (void*)ai_addr,
187 (void*)ai_next);
188 }
189 } testConfigs[]{
190 {0, sizeof(in_addr) /*bad*/, nullptr, nullptr, nullptr, EAI_BADHINTS},
191 {0, 0, placeholder_cname /*bad*/, nullptr, nullptr, EAI_BADHINTS},
192 {0, 0, nullptr, &placeholder_addr /*bad*/, nullptr, EAI_BADHINTS},
193 {0, 0, nullptr, nullptr, &placeholder_next /*bad*/, EAI_BADHINTS},
194 {AI_ALL /*bad*/, 0, nullptr, nullptr, nullptr, EAI_BADFLAGS},
195 {AI_V4MAPPED_CFG /*bad*/, 0, nullptr, nullptr, nullptr, EAI_BADFLAGS},
196 {AI_V4MAPPED /*bad*/, 0, nullptr, nullptr, nullptr, EAI_BADFLAGS},
197 {AI_DEFAULT /*bad*/, 0, nullptr, nullptr, nullptr, EAI_BADFLAGS},
198 };
199
200 for (const auto& config : testConfigs) {
201 SCOPED_TRACE(config.asParameters());
202
203 addrinfo* result = nullptr;
204 // In current test configuration set, ai_family, ai_protocol and ai_socktype are not
205 // checked because other fields cause hints error check failed first.
206 const addrinfo hints = {
207 .ai_flags = config.ai_flags,
208 .ai_family = AF_UNSPEC,
209 .ai_socktype = ANY,
210 .ai_protocol = ANY,
211 .ai_addrlen = config.ai_addrlen,
212 .ai_canonname = config.ai_canonname,
213 .ai_addr = config.ai_addr,
214 .ai_next = config.ai_next,
215 };
216 NetworkDnsEventReported event;
217 int rv = resolv_getaddrinfo("localhost", nullptr /*servname*/, &hints, &mNetcontext,
218 &result, &event);
219 ScopedAddrinfo result_cleanup(result);
220 EXPECT_EQ(config.expected_eai_error, rv);
221 }
222 }
223
TEST_F(ResolvGetAddrInfoTest,InvalidParameters_Family)224 TEST_F(ResolvGetAddrInfoTest, InvalidParameters_Family) {
225 for (int family = 0; family < AF_MAX; ++family) {
226 if (family == AF_UNSPEC || family == AF_INET || family == AF_INET6) {
227 continue; // skip supported family
228 }
229 SCOPED_TRACE(StringPrintf("family: %d", family));
230
231 addrinfo* result = nullptr;
232 const addrinfo hints = {
233 .ai_family = family, // unsupported family
234 };
235 NetworkDnsEventReported event;
236 int rv = resolv_getaddrinfo("localhost", nullptr /*servname*/, &hints, &mNetcontext,
237 &result, &event);
238 ScopedAddrinfo result_cleanup(result);
239 EXPECT_EQ(EAI_FAMILY, rv);
240 }
241 }
242
TEST_F(ResolvGetAddrInfoTest,InvalidParameters_SocketType)243 TEST_F(ResolvGetAddrInfoTest, InvalidParameters_SocketType) {
244 for (const auto& family : {AF_INET, AF_INET6, AF_UNSPEC}) {
245 for (int protocol = 0; protocol < IPPROTO_MAX; ++protocol) {
246 // Socket types which are not in explore_options.
247 for (const auto& socktype : {SOCK_RDM, SOCK_SEQPACKET, SOCK_DCCP, SOCK_PACKET}) {
248 const addrinfo hints = {
249 .ai_family = family,
250 .ai_socktype = socktype,
251 .ai_protocol = protocol,
252 };
253 for (const char* service : {static_cast<const char*>(nullptr), // service is null
254 "80",
255 "", // empty service name
256 "ftp",
257 "65536", // out of valid port range from 0 to 65535
258 "invalid"}) {
259 SCOPED_TRACE(StringPrintf("family: %d, socktype: %d, protocol: %d, service: %s",
260 family, socktype, protocol,
261 service ? service : "service is nullptr"));
262 addrinfo* result = nullptr;
263 NetworkDnsEventReported event;
264 int rv = resolv_getaddrinfo("localhost", service, &hints, &mNetcontext, &result,
265 &event);
266 ScopedAddrinfo result_cleanup(result);
267 EXPECT_EQ(EAI_SOCKTYPE, rv);
268 }
269 }
270 }
271 }
272 }
273
TEST_F(ResolvGetAddrInfoTest,InvalidParameters_MeaningfulSocktypeAndProtocolCombination)274 TEST_F(ResolvGetAddrInfoTest, InvalidParameters_MeaningfulSocktypeAndProtocolCombination) {
275 static const int families[] = {PF_INET, PF_INET6, PF_UNSPEC};
276 // Skip to test socket type SOCK_RAW in meaningful combination (explore_options[]) of
277 // system\netd\resolv\getaddrinfo.cpp. In explore_options[], the socket type SOCK_RAW always
278 // comes with protocol ANY which causes skipping meaningful socktype/protocol combination
279 // check. So it nerver returns error number EAI_BADHINTS which we want to test in this test
280 // case.
281 static const int socktypes[] = {SOCK_STREAM, SOCK_DGRAM};
282
283 // If both socktype/protocol are specified, check non-meaningful combination returns
284 // expected error number EAI_BADHINTS. See meaningful combination in explore_options[] of
285 // system\netd\resolv\getaddrinfo.cpp.
286 for (const auto& family : families) {
287 for (const auto& socktype : socktypes) {
288 for (int protocol = 0; protocol < IPPROTO_MAX; ++protocol) {
289 SCOPED_TRACE(StringPrintf("family: %d, socktype: %d, protocol: %d", family,
290 socktype, protocol));
291
292 // Both socktype/protocol need to be specified.
293 if (!socktype || !protocol) continue;
294
295 // Skip meaningful combination in explore_options[] of
296 // system\netd\resolv\getaddrinfo.cpp.
297 if ((family == AF_INET6 && socktype == SOCK_DGRAM && protocol == IPPROTO_UDP) ||
298 (family == AF_INET6 && socktype == SOCK_STREAM && protocol == IPPROTO_TCP) ||
299 (family == AF_INET && socktype == SOCK_DGRAM && protocol == IPPROTO_UDP) ||
300 (family == AF_INET && socktype == SOCK_STREAM && protocol == IPPROTO_TCP) ||
301 (family == AF_UNSPEC && socktype == SOCK_DGRAM && protocol == IPPROTO_UDP) ||
302 (family == AF_UNSPEC && socktype == SOCK_STREAM && protocol == IPPROTO_TCP)) {
303 continue;
304 }
305
306 addrinfo* result = nullptr;
307 const addrinfo hints = {
308 .ai_family = family,
309 .ai_socktype = socktype,
310 .ai_protocol = protocol,
311 };
312 NetworkDnsEventReported event;
313 int rv = resolv_getaddrinfo("localhost", nullptr /*servname*/, &hints, &mNetcontext,
314 &result, &event);
315 ScopedAddrinfo result_cleanup(result);
316 EXPECT_EQ(EAI_BADHINTS, rv);
317 }
318 }
319 }
320 }
321
322 // The test configs are used for verifying the error path of get_port().
323 // Note that the EAI_SOCKTYPE verification are moved to an independent
324 // test case because validateHints() verify invalid socket type early now.
325 // See also InvalidParameters_SocketType.
TEST_F(ResolvGetAddrInfoTest,InvalidParameters_PortNameAndNumber)326 TEST_F(ResolvGetAddrInfoTest, InvalidParameters_PortNameAndNumber) {
327 constexpr char http_portno[] = "80";
328 constexpr char invalid_portno[] = "65536"; // out of valid port range from 0 to 65535
329 constexpr char http_portname[] = "http";
330 constexpr char invalid_portname[] = "invalid_portname";
331
332 static const struct TestConfig {
333 int ai_flags;
334 int ai_family;
335 int ai_socktype;
336 const char* servname;
337
338 int expected_eai_error;
339
340 std::string asParameters() const {
341 return StringPrintf("0x%x/%d/%d/%s", ai_flags, ai_family, ai_socktype,
342 servname ? servname : "(null)");
343 }
344 } testConfigs[]{
345 {0, AF_INET, SOCK_RAW /*bad*/, http_portno, EAI_SERVICE},
346 {0, AF_INET6, SOCK_RAW /*bad*/, http_portno, EAI_SERVICE},
347 {0, AF_UNSPEC, SOCK_RAW /*bad*/, http_portno, EAI_SERVICE},
348 {0, AF_INET, ANY, invalid_portno /*bad*/, EAI_SERVICE},
349 {0, AF_INET, SOCK_STREAM, invalid_portno /*bad*/, EAI_SERVICE},
350 {0, AF_INET, SOCK_DGRAM, invalid_portno /*bad*/, EAI_SERVICE},
351 {0, AF_INET6, ANY, invalid_portno /*bad*/, EAI_SERVICE},
352 {0, AF_INET6, SOCK_STREAM, invalid_portno /*bad*/, EAI_SERVICE},
353 {0, AF_INET6, SOCK_DGRAM, invalid_portno /*bad*/, EAI_SERVICE},
354 {0, AF_UNSPEC, ANY, invalid_portno /*bad*/, EAI_SERVICE},
355 {0, AF_UNSPEC, SOCK_STREAM, invalid_portno /*bad*/, EAI_SERVICE},
356 {0, AF_UNSPEC, SOCK_DGRAM, invalid_portno /*bad*/, EAI_SERVICE},
357 {AI_NUMERICSERV, AF_INET, ANY, http_portname /*bad*/, EAI_NONAME},
358 {AI_NUMERICSERV, AF_INET, SOCK_STREAM, http_portname /*bad*/, EAI_NONAME},
359 {AI_NUMERICSERV, AF_INET, SOCK_DGRAM, http_portname /*bad*/, EAI_NONAME},
360 {AI_NUMERICSERV, AF_INET6, ANY, http_portname /*bad*/, EAI_NONAME},
361 {AI_NUMERICSERV, AF_INET6, SOCK_STREAM, http_portname /*bad*/, EAI_NONAME},
362 {AI_NUMERICSERV, AF_INET6, SOCK_DGRAM, http_portname /*bad*/, EAI_NONAME},
363 {AI_NUMERICSERV, AF_UNSPEC, ANY, http_portname /*bad*/, EAI_NONAME},
364 {AI_NUMERICSERV, AF_UNSPEC, SOCK_STREAM, http_portname /*bad*/, EAI_NONAME},
365 {AI_NUMERICSERV, AF_UNSPEC, SOCK_DGRAM, http_portname /*bad*/, EAI_NONAME},
366 {0, AF_INET, ANY, invalid_portname /*bad*/, EAI_SERVICE},
367 {0, AF_INET, SOCK_STREAM, invalid_portname /*bad*/, EAI_SERVICE},
368 {0, AF_INET, SOCK_DGRAM, invalid_portname /*bad*/, EAI_SERVICE},
369 {0, AF_INET6, ANY, invalid_portname /*bad*/, EAI_SERVICE},
370 {0, AF_INET6, SOCK_STREAM, invalid_portname /*bad*/, EAI_SERVICE},
371 {0, AF_INET6, SOCK_DGRAM, invalid_portname /*bad*/, EAI_SERVICE},
372 {0, AF_UNSPEC, ANY, invalid_portname /*bad*/, EAI_SERVICE},
373 {0, AF_UNSPEC, SOCK_STREAM, invalid_portname /*bad*/, EAI_SERVICE},
374 {0, AF_UNSPEC, SOCK_DGRAM, invalid_portname /*bad*/, EAI_SERVICE},
375 };
376
377 for (const auto& config : testConfigs) {
378 const std::string testParameters = config.asParameters();
379 SCOPED_TRACE(testParameters);
380
381 const addrinfo hints = {
382 .ai_flags = config.ai_flags,
383 .ai_family = config.ai_family,
384 .ai_socktype = config.ai_socktype,
385 };
386
387 addrinfo* result = nullptr;
388 NetworkDnsEventReported event;
389 int rv = resolv_getaddrinfo("localhost", config.servname, &hints, &mNetcontext, &result,
390 &event);
391 ScopedAddrinfo result_cleanup(result);
392 EXPECT_EQ(config.expected_eai_error, rv);
393 }
394 }
395
TEST_F(ResolvGetAddrInfoTest,AlphabeticalHostname_NoData)396 TEST_F(ResolvGetAddrInfoTest, AlphabeticalHostname_NoData) {
397 constexpr char v4_host_name[] = "v4only.example.com.";
398 // Following fields will not be verified during the test in proto NetworkDnsEventReported.
399 // So don't need to config those values: event_type, return_code, latency_micros,
400 // hints_ai_flags, res_nsend_flags, network_type, private_dns_modes.
401 constexpr char event_ipv6[] = R"Event(
402 NetworkDnsEventReported {
403 dns_query_events:
404 {
405 dns_query_event:[
406 {
407 rcode: 0,
408 type: 28,
409 cache_hit: 1,
410 ip_version: 1,
411 protocol: 1,
412 retry_times: 0,
413 dns_server_index: 0,
414 connected: 0,
415 latency_micros: 0,
416 linux_errno: 0,
417 },
418 {
419 rcode: 0,
420 type: 28,
421 cache_hit: 1,
422 ip_version: 1,
423 protocol: 1,
424 retry_times: 0,
425 dns_server_index: 0,
426 connected: 0,
427 latency_micros: 0,
428 linux_errno: 0,
429 },
430 {
431 rcode: 0,
432 type: 28,
433 cache_hit: 1,
434 ip_version: 1,
435 protocol: 1,
436 retry_times: 0,
437 dns_server_index: 0,
438 connected: 0,
439 latency_micros: 0,
440 linux_errno: 0,
441 },
442 {
443 rcode: 0,
444 type: 28,
445 cache_hit: 1,
446 ip_version: 1,
447 protocol: 1,
448 retry_times: 0,
449 dns_server_index: 0,
450 connected: 0,
451 latency_micros: 0,
452 linux_errno: 0,
453 }
454 ]
455 }
456 })Event";
457
458 test::DNSResponder dns;
459 dns.addMapping(v4_host_name, ns_type::ns_t_a, "1.2.3.3");
460 ASSERT_TRUE(dns.startServer());
461 ASSERT_EQ(0, SetResolvers());
462
463 // Want AAAA answer but DNS server has A answer only.
464 addrinfo* result = nullptr;
465 const addrinfo hints = {.ai_family = AF_INET6};
466 NetworkDnsEventReported event;
467 int rv = resolv_getaddrinfo("v4only", nullptr, &hints, &mNetcontext, &result, &event);
468 EXPECT_THAT(event, NetworkDnsEventEq(fromNetworkDnsEventReportedStr(event_ipv6)));
469 ScopedAddrinfo result_cleanup(result);
470 EXPECT_LE(1U, GetNumQueries(dns, v4_host_name));
471 EXPECT_EQ(nullptr, result);
472 EXPECT_EQ(EAI_NODATA, rv);
473 }
474
TEST_F(ResolvGetAddrInfoTest,AlphabeticalHostname)475 TEST_F(ResolvGetAddrInfoTest, AlphabeticalHostname) {
476 constexpr char host_name[] = "sawadee.example.com.";
477 constexpr char v4addr[] = "1.2.3.4";
478 constexpr char v6addr[] = "::1.2.3.4";
479 // Following fields will not be verified during the test in proto NetworkDnsEventReported.
480 // So don't need to config those values: event_type, return_code, latency_micros,
481 // hints_ai_flags, res_nsend_flags, network_type, private_dns_modes.
482 constexpr char event_ipv4[] = R"Event(
483 NetworkDnsEventReported {
484 dns_query_events:
485 {
486 dns_query_event:[
487 {
488 rcode: 0,
489 type: 1,
490 cache_hit: 1,
491 ip_version: 1,
492 protocol: 1,
493 retry_times: 0,
494 dns_server_index: 0,
495 connected: 0,
496 linux_errno: 0,
497 },
498 {
499 rcode: 0,
500 type: 1,
501 cache_hit: 2,
502 ip_version: 0,
503 protocol: 0,
504 retry_times: 0,
505 dns_server_index: 0,
506 connected: 0,
507 linux_errno: 0,
508 }
509 ]
510 }
511 })Event";
512
513 constexpr char event_ipv6[] = R"Event(
514 NetworkDnsEventReported {
515 dns_query_events:
516 {
517 dns_query_event:[
518 {
519 rcode: 0,
520 type: 28,
521 cache_hit: 1,
522 ip_version: 1,
523 protocol: 1,
524 retry_times: 0,
525 dns_server_index: 0,
526 connected: 0,
527 linux_errno: 0,
528 },
529 {
530 rcode: 0,
531 type: 28,
532 cache_hit: 2,
533 ip_version: 0,
534 protocol: 0,
535 retry_times: 0,
536 dns_server_index: 0,
537 connected: 0,
538 linux_errno: 0,
539 }
540 ]
541 }
542 })Event";
543 test::DNSResponder dns;
544 dns.addMapping(host_name, ns_type::ns_t_a, v4addr);
545 dns.addMapping(host_name, ns_type::ns_t_aaaa, v6addr);
546 ASSERT_TRUE(dns.startServer());
547 ASSERT_EQ(0, SetResolvers());
548
549 static const struct TestConfig {
550 int ai_family;
551 const std::string expected_addr;
552 const std::string expected_event;
553 } testConfigs[]{
554 {AF_INET, v4addr, event_ipv4},
555 {AF_INET6, v6addr, event_ipv6},
556 };
557
558 for (const auto& config : testConfigs) {
559 SCOPED_TRACE(StringPrintf("family: %d", config.ai_family));
560 dns.clearQueries();
561
562 addrinfo* result = nullptr;
563 const addrinfo hints = {.ai_family = config.ai_family};
564 NetworkDnsEventReported event;
565 int rv = resolv_getaddrinfo("sawadee", nullptr, &hints, &mNetcontext, &result, &event);
566 EXPECT_THAT(event,
567 NetworkDnsEventEq(fromNetworkDnsEventReportedStr(config.expected_event)));
568 ScopedAddrinfo result_cleanup(result);
569 EXPECT_EQ(0, rv);
570 EXPECT_TRUE(result != nullptr);
571 EXPECT_EQ(1U, GetNumQueries(dns, host_name));
572 EXPECT_EQ(config.expected_addr, ToString(result));
573 }
574 }
575
TEST_F(ResolvGetAddrInfoTest,IllegalHostname)576 TEST_F(ResolvGetAddrInfoTest, IllegalHostname) {
577 test::DNSResponder dns;
578 ASSERT_TRUE(dns.startServer());
579 ASSERT_EQ(0, SetResolvers());
580
581 // Illegal hostname is verified by res_hnok() in system/netd/resolv/res_comp.cpp.
582 static constexpr char const* illegalHostnames[] = {
583 kBadCharAfterPeriodHost,
584 kBadCharBeforePeriodHost,
585 kBadCharAtTheEndHost,
586 kBadCharInTheMiddleOfLabelHost,
587 };
588
589 for (const auto& hostname : illegalHostnames) {
590 // Expect to get no address because hostname format is illegal.
591 //
592 // Ex:
593 // ANSWER SECTION:
594 // a.ex^ample.com. IN A 1.2.3.3
595 // a.ex^ample.com. IN AAAA 2001:db8::42
596 //
597 // In this example, querying "a.ex^ample.com" should get no address because
598 // "a.ex^ample.com" has an illegal char '^' in the middle of label.
599 dns.addMapping(hostname, ns_type::ns_t_a, "1.2.3.3");
600 dns.addMapping(hostname, ns_type::ns_t_aaaa, "2001:db8::42");
601
602 for (const auto& family : {AF_INET, AF_INET6, AF_UNSPEC}) {
603 SCOPED_TRACE(StringPrintf("family: %d, config.name: %s", family, hostname));
604
605 addrinfo* res = nullptr;
606 const addrinfo hints = {.ai_family = family};
607 NetworkDnsEventReported event;
608 int rv = resolv_getaddrinfo(hostname, nullptr, &hints, &mNetcontext, &res, &event);
609 ScopedAddrinfo result(res);
610 EXPECT_EQ(nullptr, result);
611 EXPECT_EQ(EAI_FAIL, rv);
612 }
613 }
614 }
615
TEST_F(ResolvGetAddrInfoTest,ServerResponseError)616 TEST_F(ResolvGetAddrInfoTest, ServerResponseError) {
617 constexpr char host_name[] = "hello.example.com.";
618
619 static const struct TestConfig {
620 ns_rcode rcode;
621 int expected_eai_error;
622
623 // Only test failure RCODE [1..5] in RFC 1035 section 4.1.1 and skip successful RCODE 0
624 // which means no error.
625 } testConfigs[]{
626 // clang-format off
627 {ns_rcode::ns_r_formerr, EAI_FAIL},
628 {ns_rcode::ns_r_servfail, EAI_AGAIN},
629 {ns_rcode::ns_r_nxdomain, EAI_NODATA},
630 {ns_rcode::ns_r_notimpl, EAI_FAIL},
631 {ns_rcode::ns_r_refused, EAI_FAIL},
632 // clang-format on
633 };
634
635 for (const auto& config : testConfigs) {
636 SCOPED_TRACE(StringPrintf("rcode: %d", config.rcode));
637
638 test::DNSResponder dns(config.rcode);
639 dns.addMapping(host_name, ns_type::ns_t_a, "1.2.3.4");
640 dns.setResponseProbability(0.0); // always ignore requests and response preset rcode
641 ASSERT_TRUE(dns.startServer());
642 ASSERT_EQ(0, SetResolvers());
643
644 addrinfo* result = nullptr;
645 const addrinfo hints = {.ai_family = AF_UNSPEC};
646 NetworkDnsEventReported event;
647 int rv = resolv_getaddrinfo(host_name, nullptr, &hints, &mNetcontext, &result, &event);
648 EXPECT_EQ(config.expected_eai_error, rv);
649 }
650 }
651
652 // TODO: Add private DNS server timeout test.
TEST_F(ResolvGetAddrInfoTest,ServerTimeout)653 TEST_F(ResolvGetAddrInfoTest, ServerTimeout) {
654 constexpr char host_name[] = "hello.example.com.";
655 // Following fields will not be verified during the test in proto NetworkDnsEventReported.
656 // So don't need to config those values: event_type, return_code, latency_micros,
657 // hints_ai_flags, res_nsend_flags, network_type, private_dns_modes.
658 // Expected_event is 16 DNS queries and only "type" and "retry_times" fields are changed.
659 // 2(T_AAAA + T_A) * 2(w/ retry) * 2(query w/ and w/o domain) * 2(SOCK_DGRAM and SOCK_STREAM)
660 constexpr char expected_event[] = R"Event(
661 NetworkDnsEventReported {
662 dns_query_events:
663 {
664 dns_query_event:[
665 {
666 rcode: 255,
667 type: 28,
668 cache_hit: 1,
669 ip_version: 1,
670 protocol: 1,
671 retry_times: 0,
672 dns_server_index: 0,
673 connected: 0,
674 linux_errno: 110,
675 },
676 {
677 rcode: 255,
678 type: 28,
679 cache_hit: 1,
680 ip_version: 1,
681 protocol: 1,
682 retry_times: 1,
683 dns_server_index: 0,
684 connected: 0,
685 linux_errno: 110,
686 }
687 {
688 rcode: 255,
689 type: 1,
690 cache_hit: 1,
691 ip_version: 1,
692 protocol: 1,
693 retry_times: 0,
694 dns_server_index: 0,
695 connected: 0,
696 linux_errno: 110,
697 },
698 {
699 rcode: 255,
700 type: 1,
701 cache_hit: 1,
702 ip_version: 1,
703 protocol: 1,
704 retry_times: 1,
705 dns_server_index: 0,
706 connected: 0,
707 linux_errno: 110,
708 },
709 {
710 rcode: 255,
711 type: 28,
712 cache_hit: 1,
713 ip_version: 1,
714 protocol: 1,
715 retry_times: 0,
716 dns_server_index: 0,
717 connected: 0,
718 linux_errno: 110,
719 },
720 {
721 rcode: 255,
722 type: 28,
723 cache_hit: 1,
724 ip_version: 1,
725 protocol: 1,
726 retry_times: 1,
727 dns_server_index: 0,
728 connected: 0,
729 linux_errno: 110,
730 }
731 {
732 rcode: 255,
733 type: 1,
734 cache_hit: 1,
735 ip_version: 1,
736 protocol: 1,
737 retry_times: 0,
738 dns_server_index: 0,
739 connected: 0,
740 linux_errno: 110,
741 },
742 {
743 rcode: 255,
744 type: 1,
745 cache_hit: 1,
746 ip_version: 1,
747 protocol: 1,
748 retry_times: 1,
749 dns_server_index: 0,
750 connected: 0,
751 linux_errno: 110,
752 },
753 {
754 rcode: 255,
755 type: 28,
756 cache_hit: 1,
757 ip_version: 1,
758 protocol: 1,
759 retry_times: 0,
760 dns_server_index: 0,
761 connected: 0,
762 linux_errno: 110,
763 },
764 {
765 rcode: 255,
766 type: 28,
767 cache_hit: 1,
768 ip_version: 1,
769 protocol: 1,
770 retry_times: 1,
771 dns_server_index: 0,
772 connected: 0,
773 linux_errno: 110,
774 }
775 {
776 rcode: 255,
777 type: 1,
778 cache_hit: 1,
779 ip_version: 1,
780 protocol: 1,
781 retry_times: 0,
782 dns_server_index: 0,
783 connected: 0,
784 linux_errno: 110,
785 },
786 {
787 rcode: 255,
788 type: 1,
789 cache_hit: 1,
790 ip_version: 1,
791 protocol: 1,
792 retry_times: 1,
793 dns_server_index: 0,
794 connected: 0,
795 linux_errno: 110,
796 },
797 {
798 rcode: 255,
799 type: 28,
800 cache_hit: 1,
801 ip_version: 1,
802 protocol: 1,
803 retry_times: 0,
804 dns_server_index: 0,
805 connected: 0,
806 linux_errno: 110,
807 },
808 {
809 rcode: 255,
810 type: 28,
811 cache_hit: 1,
812 ip_version: 1,
813 protocol: 1,
814 retry_times: 1,
815 dns_server_index: 0,
816 connected: 0,
817 linux_errno: 110,
818 }
819 {
820 rcode: 255,
821 type: 1,
822 cache_hit: 1,
823 ip_version: 1,
824 protocol: 1,
825 retry_times: 0,
826 dns_server_index: 0,
827 connected: 0,
828 linux_errno: 110,
829 },
830 {
831 rcode: 255,
832 type: 1,
833 cache_hit: 1,
834 ip_version: 1,
835 protocol: 1,
836 retry_times: 1,
837 dns_server_index: 0,
838 connected: 0,
839 linux_errno: 110,
840 },
841 ]
842 }
843 })Event";
844 test::DNSResponder dns(static_cast<ns_rcode>(-1) /*no response*/);
845 dns.addMapping(host_name, ns_type::ns_t_a, "1.2.3.4");
846 dns.setResponseProbability(0.0); // always ignore requests and don't response
847 ASSERT_TRUE(dns.startServer());
848 ASSERT_EQ(0, SetResolvers());
849
850 addrinfo* result = nullptr;
851 const addrinfo hints = {.ai_family = AF_UNSPEC};
852 NetworkDnsEventReported event;
853 int rv = resolv_getaddrinfo("hello", nullptr, &hints, &mNetcontext, &result, &event);
854 EXPECT_THAT(event, NetworkDnsEventEq(fromNetworkDnsEventReportedStr(expected_event)));
855 EXPECT_EQ(NETD_RESOLV_TIMEOUT, rv);
856 }
857
TEST_F(ResolvGetAddrInfoTest,CnamesNoIpAddress)858 TEST_F(ResolvGetAddrInfoTest, CnamesNoIpAddress) {
859 constexpr char ACNAME[] = "acname"; // expect a cname in answer
860 constexpr char CNAMES[] = "cnames"; // expect cname chain in answer
861
862 test::DNSResponder dns;
863 dns.addMapping("cnames.example.com.", ns_type::ns_t_cname, "acname.example.com.");
864 dns.addMapping("acname.example.com.", ns_type::ns_t_cname, "hello.example.com.");
865 ASSERT_TRUE(dns.startServer());
866 ASSERT_EQ(0, SetResolvers());
867
868 static const struct TestConfig {
869 const char* name;
870 int family;
871 } testConfigs[]{
872 // clang-format off
873 {ACNAME, AF_INET},
874 {ACNAME, AF_INET6},
875 {ACNAME, AF_UNSPEC},
876 {CNAMES, AF_INET},
877 {CNAMES, AF_INET6},
878 {CNAMES, AF_UNSPEC},
879 // clang-format on
880 };
881
882 for (const auto& config : testConfigs) {
883 SCOPED_TRACE(
884 StringPrintf("config.family: %d, config.name: %s", config.family, config.name));
885
886 addrinfo* res = nullptr;
887 const addrinfo hints = {.ai_family = config.family};
888 NetworkDnsEventReported event;
889 int rv = resolv_getaddrinfo(config.name, nullptr, &hints, &mNetcontext, &res, &event);
890 ScopedAddrinfo result(res);
891 EXPECT_EQ(nullptr, result);
892 EXPECT_EQ(EAI_FAIL, rv);
893 }
894 }
895
TEST_F(ResolvGetAddrInfoTest,CnamesBrokenChainByIllegalCname)896 TEST_F(ResolvGetAddrInfoTest, CnamesBrokenChainByIllegalCname) {
897 test::DNSResponder dns;
898 ASSERT_TRUE(dns.startServer());
899 ASSERT_EQ(0, SetResolvers());
900
901 static const struct TestConfig {
902 const char* name;
903 const char* cname;
904 std::string asHostName() const { return StringPrintf("%s.example.com.", name); }
905
906 // Illegal cname is verified by res_hnok() in system/netd/resolv/res_comp.cpp.
907 } testConfigs[]{
908 // clang-format off
909 {NAME(kBadCharAfterPeriodHost), kBadCharAfterPeriodHost},
910 {NAME(kBadCharBeforePeriodHost), kBadCharBeforePeriodHost},
911 {NAME(kBadCharAtTheEndHost), kBadCharAtTheEndHost},
912 {NAME(kBadCharInTheMiddleOfLabelHost), kBadCharInTheMiddleOfLabelHost},
913 // clang-format on
914 };
915
916 for (const auto& config : testConfigs) {
917 const std::string testHostName = config.asHostName();
918
919 // Expect to get no address because the cname chain is broken by an illegal cname format.
920 //
921 // Ex:
922 // ANSWER SECTION:
923 // hello.example.com. IN CNAME a.ex^ample.com.
924 // a.ex^ample.com. IN A 1.2.3.3
925 // a.ex^ample.com. IN AAAA 2001:db8::42
926 //
927 // In this example, querying hello.example.com should get no address because
928 // "a.ex^ample.com" has an illegal char '^' in the middle of label.
929 dns.addMapping(testHostName.c_str(), ns_type::ns_t_cname, config.cname);
930 dns.addMapping(config.cname, ns_type::ns_t_a, "1.2.3.3");
931 dns.addMapping(config.cname, ns_type::ns_t_aaaa, "2001:db8::42");
932
933 for (const auto& family : {AF_INET, AF_INET6, AF_UNSPEC}) {
934 SCOPED_TRACE(
935 StringPrintf("family: %d, testHostName: %s", family, testHostName.c_str()));
936
937 addrinfo* res = nullptr;
938 const addrinfo hints = {.ai_family = family};
939 NetworkDnsEventReported event;
940 int rv = resolv_getaddrinfo(config.name, nullptr, &hints, &mNetcontext, &res, &event);
941 ScopedAddrinfo result(res);
942 EXPECT_EQ(nullptr, result);
943 EXPECT_EQ(EAI_FAIL, rv);
944 }
945 }
946 }
947
TEST_F(ResolvGetAddrInfoTest,CnamesInfiniteLoop)948 TEST_F(ResolvGetAddrInfoTest, CnamesInfiniteLoop) {
949 test::DNSResponder dns;
950 dns.addMapping("hello.example.com.", ns_type::ns_t_cname, "a.example.com.");
951 dns.addMapping("a.example.com.", ns_type::ns_t_cname, "hello.example.com.");
952 ASSERT_TRUE(dns.startServer());
953 ASSERT_EQ(0, SetResolvers());
954
955 for (const auto& family : {AF_INET, AF_INET6, AF_UNSPEC}) {
956 SCOPED_TRACE(StringPrintf("family: %d", family));
957
958 addrinfo* res = nullptr;
959 const addrinfo hints = {.ai_family = family};
960 NetworkDnsEventReported event;
961 int rv = resolv_getaddrinfo("hello", nullptr, &hints, &mNetcontext, &res, &event);
962 ScopedAddrinfo result(res);
963 EXPECT_EQ(nullptr, result);
964 EXPECT_EQ(EAI_FAIL, rv);
965 }
966 }
967
TEST_F(ResolvGetAddrInfoTest,MultiAnswerSections)968 TEST_F(ResolvGetAddrInfoTest, MultiAnswerSections) {
969 test::DNSResponder dns(test::DNSResponder::MappingType::DNS_HEADER);
970 // Answer section for query type {A, AAAA}
971 // Type A:
972 // hello.example.com. IN A 1.2.3.1
973 // hello.example.com. IN A 1.2.3.2
974 // Type AAAA:
975 // hello.example.com. IN AAAA 2001:db8::41
976 // hello.example.com. IN AAAA 2001:db8::42
977 StartDns(dns, {MakeDnsMessage(kHelloExampleCom, ns_type::ns_t_a, {"1.2.3.1", "1.2.3.2"}),
978 MakeDnsMessage(kHelloExampleCom, ns_type::ns_t_aaaa,
979 {"2001:db8::41", "2001:db8::42"})});
980 ASSERT_EQ(0, SetResolvers());
981
982 for (const auto& family : {AF_INET, AF_INET6, AF_UNSPEC}) {
983 SCOPED_TRACE(StringPrintf("family: %d", family));
984
985 addrinfo* res = nullptr;
986 // If the socket type is not specified, every address will appear twice, once for
987 // SOCK_STREAM and one for SOCK_DGRAM. Just pick one because the addresses for
988 // the second query of different socket type are responded by the cache.
989 const addrinfo hints = {.ai_family = family, .ai_socktype = SOCK_STREAM};
990 NetworkDnsEventReported event;
991 int rv = resolv_getaddrinfo("hello", nullptr, &hints, &mNetcontext, &res, &event);
992 ScopedAddrinfo result(res);
993 ASSERT_NE(nullptr, result);
994 ASSERT_EQ(0, rv);
995
996 const std::vector<std::string> result_strs = ToStrings(result);
997 if (family == AF_INET) {
998 EXPECT_EQ(1U, GetNumQueries(dns, kHelloExampleCom));
999 EXPECT_THAT(result_strs, testing::UnorderedElementsAreArray({"1.2.3.1", "1.2.3.2"}));
1000 } else if (family == AF_INET6) {
1001 EXPECT_EQ(1U, GetNumQueries(dns, kHelloExampleCom));
1002 EXPECT_THAT(result_strs,
1003 testing::UnorderedElementsAreArray({"2001:db8::41", "2001:db8::42"}));
1004 } else if (family == AF_UNSPEC) {
1005 EXPECT_EQ(0U, GetNumQueries(dns, kHelloExampleCom)); // no query because of the cache
1006 EXPECT_THAT(result_strs,
1007 testing::UnorderedElementsAreArray(
1008 {"1.2.3.1", "1.2.3.2", "2001:db8::41", "2001:db8::42"}));
1009 }
1010 dns.clearQueries();
1011 }
1012 }
1013
TEST_F(ResolvGetAddrInfoTest,TruncatedResponse)1014 TEST_F(ResolvGetAddrInfoTest, TruncatedResponse) {
1015 // Following fields will not be verified during the test in proto NetworkDnsEventReported.
1016 // So don't need to config those values: event_type, return_code, latency_micros,
1017 // hints_ai_flags, res_nsend_flags, network_type, private_dns_modes.
1018 constexpr char event_ipv4[] = R"Event(
1019 NetworkDnsEventReported {
1020 dns_query_events:
1021 {
1022 dns_query_event:[
1023 {
1024 rcode: 254,
1025 type: 1,
1026 cache_hit: 1,
1027 ip_version: 1,
1028 protocol: 1,
1029 retry_times: 0,
1030 dns_server_index: 0,
1031 connected: 0,
1032 linux_errno: 7,
1033 },
1034 {
1035 rcode: 0,
1036 type: 1,
1037 cache_hit: 1,
1038 ip_version: 1,
1039 protocol: 2,
1040 retry_times: 0,
1041 dns_server_index: 0,
1042 connected: 0,
1043 linux_errno: 0,
1044 },
1045 {
1046 rcode: 0,
1047 type: 1,
1048 cache_hit: 2,
1049 ip_version: 0,
1050 protocol: 0,
1051 retry_times: 0,
1052 dns_server_index: 0,
1053 connected: 0,
1054 linux_errno: 0,
1055 }
1056 ]
1057 }
1058 })Event";
1059
1060 constexpr char event_ipv6[] = R"Event(
1061 NetworkDnsEventReported {
1062 dns_query_events:
1063 {
1064 dns_query_event:[
1065 {
1066 rcode: 254,
1067 type: 28,
1068 cache_hit: 1,
1069 ip_version: 1,
1070 protocol: 1,
1071 retry_times: 0,
1072 dns_server_index: 0,
1073 connected: 0,
1074 linux_errno: 7,
1075 },
1076 {
1077 rcode: 0,
1078 type: 28,
1079 cache_hit: 1,
1080 ip_version: 1,
1081 protocol: 2,
1082 retry_times: 0,
1083 dns_server_index: 0,
1084 connected: 0,
1085 linux_errno: 0,
1086 },
1087 {
1088 rcode: 0,
1089 type: 28,
1090 cache_hit: 2,
1091 ip_version: 0,
1092 protocol: 0,
1093 retry_times: 0,
1094 dns_server_index: 0,
1095 connected: 0,
1096 linux_errno: 0,
1097 }
1098 ]
1099 }
1100 })Event";
1101
1102 test::DNSResponder dns;
1103 dns.addMapping(kHelloExampleCom, ns_type::ns_t_cname, kCnameA);
1104 dns.addMapping(kCnameA, ns_type::ns_t_cname, kCnameB);
1105 dns.addMapping(kCnameB, ns_type::ns_t_cname, kCnameC);
1106 dns.addMapping(kCnameC, ns_type::ns_t_cname, kCnameD);
1107 dns.addMapping(kCnameD, ns_type::ns_t_a, kHelloExampleComAddrV4);
1108 dns.addMapping(kCnameD, ns_type::ns_t_aaaa, kHelloExampleComAddrV6);
1109 ASSERT_TRUE(dns.startServer());
1110 ASSERT_EQ(0, SetResolvers());
1111
1112 static const struct TestConfig {
1113 int ai_family;
1114 const std::string expected_addr;
1115 const std::string expected_event;
1116 } testConfigs[]{
1117 {AF_INET, kHelloExampleComAddrV4, event_ipv4},
1118 {AF_INET6, kHelloExampleComAddrV6, event_ipv6},
1119 };
1120
1121 for (const auto& config : testConfigs) {
1122 SCOPED_TRACE(StringPrintf("family: %d", config.ai_family));
1123 dns.clearQueries();
1124
1125 addrinfo* result = nullptr;
1126 const addrinfo hints = {.ai_family = config.ai_family};
1127 NetworkDnsEventReported event;
1128 int rv = resolv_getaddrinfo("hello", nullptr, &hints, &mNetcontext, &result, &event);
1129 EXPECT_THAT(event,
1130 NetworkDnsEventEq(fromNetworkDnsEventReportedStr(config.expected_event)));
1131 ScopedAddrinfo result_cleanup(result);
1132 EXPECT_EQ(rv, 0);
1133 EXPECT_TRUE(result != nullptr);
1134 // Expect UDP response is truncated. The resolver retries over TCP. See RFC 1035
1135 // section 4.2.1.
1136 EXPECT_EQ(GetNumQueriesForProtocol(dns, IPPROTO_UDP, kHelloExampleCom), 1U);
1137 EXPECT_EQ(GetNumQueriesForProtocol(dns, IPPROTO_TCP, kHelloExampleCom), 1U);
1138 EXPECT_EQ(ToString(result), config.expected_addr);
1139 }
1140 }
1141
TEST_F(GetHostByNameForNetContextTest,AlphabeticalHostname)1142 TEST_F(GetHostByNameForNetContextTest, AlphabeticalHostname) {
1143 constexpr char host_name[] = "jiababuei.example.com.";
1144 constexpr char v4addr[] = "1.2.3.4";
1145 constexpr char v6addr[] = "::1.2.3.4";
1146 // Following fields will not be verified during the test in proto NetworkDnsEventReported.
1147 // So don't need to config those values: event_type, return_code, latency_micros,
1148 // hints_ai_flags, res_nsend_flags, network_type, private_dns_modes.
1149 constexpr char event_ipv4[] = R"Event(
1150 NetworkDnsEventReported {
1151 dns_query_events:
1152 {
1153 dns_query_event:[
1154 {
1155 rcode: 0,
1156 type: 1,
1157 cache_hit: 1,
1158 ip_version: 1,
1159 protocol: 1,
1160 retry_times: 0,
1161 dns_server_index: 0,
1162 connected: 0,
1163 latency_micros: 0,
1164 linux_errno: 0,
1165 }
1166 ]
1167 }
1168 })Event";
1169
1170 constexpr char event_ipv6[] = R"Event(
1171 NetworkDnsEventReported {
1172 dns_query_events:
1173 {
1174 dns_query_event:[
1175 {
1176 rcode: 0,
1177 type: 28,
1178 cache_hit: 1,
1179 ip_version: 1,
1180 protocol: 1,
1181 retry_times: 0,
1182 dns_server_index: 0,
1183 connected: 0,
1184 latency_micros: 0,
1185 linux_errno: 0,
1186 }
1187 ]
1188 }
1189 })Event";
1190 test::DNSResponder dns;
1191 dns.addMapping(host_name, ns_type::ns_t_a, v4addr);
1192 dns.addMapping(host_name, ns_type::ns_t_aaaa, v6addr);
1193 ASSERT_TRUE(dns.startServer());
1194 ASSERT_EQ(0, SetResolvers());
1195
1196 static const struct TestConfig {
1197 int ai_family;
1198 const std::string expected_addr;
1199 const std::string expected_event;
1200 } testConfigs[]{
1201 {AF_INET, v4addr, event_ipv4},
1202 {AF_INET6, v6addr, event_ipv6},
1203 };
1204
1205 for (const auto& config : testConfigs) {
1206 SCOPED_TRACE(StringPrintf("family: %d", config.ai_family));
1207 dns.clearQueries();
1208
1209 hostent* hp = nullptr;
1210 hostent hbuf;
1211 char tmpbuf[MAXPACKET];
1212 NetworkDnsEventReported event;
1213 int rv = resolv_gethostbyname("jiababuei", config.ai_family, &hbuf, tmpbuf, sizeof(tmpbuf),
1214 &mNetcontext, &hp, &event);
1215 EXPECT_THAT(event,
1216 NetworkDnsEventEq(fromNetworkDnsEventReportedStr(config.expected_event)));
1217 EXPECT_EQ(0, rv);
1218 EXPECT_TRUE(hp != nullptr);
1219 EXPECT_EQ(1U, GetNumQueries(dns, host_name));
1220 EXPECT_EQ(config.expected_addr, ToString(hp));
1221 }
1222 }
1223
TEST_F(GetHostByNameForNetContextTest,IllegalHostname)1224 TEST_F(GetHostByNameForNetContextTest, IllegalHostname) {
1225 test::DNSResponder dns;
1226 ASSERT_TRUE(dns.startServer());
1227 ASSERT_EQ(0, SetResolvers());
1228
1229 // Illegal hostname is verified by res_hnok() in system/netd/resolv/res_comp.cpp.
1230 static constexpr char const* illegalHostnames[] = {
1231 kBadCharAfterPeriodHost,
1232 kBadCharBeforePeriodHost,
1233 kBadCharAtTheEndHost,
1234 kBadCharInTheMiddleOfLabelHost,
1235 };
1236
1237 for (const auto& hostname : illegalHostnames) {
1238 // Expect to get no address because hostname format is illegal.
1239 //
1240 // Ex:
1241 // ANSWER SECTION:
1242 // a.ex^ample.com. IN A 1.2.3.3
1243 // a.ex^ample.com. IN AAAA 2001:db8::42
1244 //
1245 // In this example, querying "a.ex^ample.com" should get no address because
1246 // "a.ex^ample.com" has an illegal char '^' in the middle of label.
1247 dns.addMapping(hostname, ns_type::ns_t_a, "1.2.3.3");
1248 dns.addMapping(hostname, ns_type::ns_t_aaaa, "2001:db8::42");
1249
1250 for (const auto& family : {AF_INET, AF_INET6}) {
1251 SCOPED_TRACE(StringPrintf("family: %d, config.name: %s", family, hostname));
1252
1253 struct hostent* hp = nullptr;
1254 hostent hbuf;
1255 char tmpbuf[MAXPACKET];
1256 NetworkDnsEventReported event;
1257 int rv = resolv_gethostbyname(hostname, family, &hbuf, tmpbuf, sizeof(tmpbuf),
1258 &mNetcontext, &hp, &event);
1259 EXPECT_EQ(nullptr, hp);
1260 EXPECT_EQ(EAI_FAIL, rv);
1261 }
1262 }
1263 }
1264
TEST_F(GetHostByNameForNetContextTest,NoData)1265 TEST_F(GetHostByNameForNetContextTest, NoData) {
1266 constexpr char v4_host_name[] = "v4only.example.com.";
1267
1268 test::DNSResponder dns;
1269 dns.addMapping(v4_host_name, ns_type::ns_t_a, "1.2.3.3");
1270 ASSERT_TRUE(dns.startServer());
1271 ASSERT_EQ(0, SetResolvers());
1272 dns.clearQueries();
1273
1274 // Want AAAA answer but DNS server has A answer only.
1275 hostent* hp = nullptr;
1276 hostent hbuf;
1277 char tmpbuf[MAXPACKET];
1278 NetworkDnsEventReported event;
1279 int rv = resolv_gethostbyname("v4only", AF_INET6, &hbuf, tmpbuf, sizeof tmpbuf, &mNetcontext,
1280 &hp, &event);
1281 EXPECT_LE(1U, GetNumQueries(dns, v4_host_name));
1282 EXPECT_EQ(nullptr, hp);
1283 EXPECT_EQ(EAI_NODATA, rv);
1284 }
1285
TEST_F(GetHostByNameForNetContextTest,ServerResponseError)1286 TEST_F(GetHostByNameForNetContextTest, ServerResponseError) {
1287 constexpr char host_name[] = "hello.example.com.";
1288
1289 static const struct TestConfig {
1290 ns_rcode rcode;
1291 int expected_eai_error; // expected result
1292
1293 // Only test failure RCODE [1..5] in RFC 1035 section 4.1.1 and skip successful RCODE 0
1294 // which means no error. Note that the return error codes aren't mapped by rcode in the
1295 // test case SERVFAIL, NOTIMP and REFUSED. See the comment of res_nsend()
1296 // in system\netd\resolv\res_query.cpp for more detail.
1297 } testConfigs[]{
1298 // clang-format off
1299 {ns_rcode::ns_r_formerr, EAI_FAIL},
1300 {ns_rcode::ns_r_servfail, EAI_AGAIN}, // Not mapped by rcode.
1301 {ns_rcode::ns_r_nxdomain, EAI_NODATA},
1302 {ns_rcode::ns_r_notimpl, EAI_AGAIN}, // Not mapped by rcode.
1303 {ns_rcode::ns_r_refused, EAI_AGAIN}, // Not mapped by rcode.
1304 // clang-format on
1305 };
1306
1307 for (const auto& config : testConfigs) {
1308 SCOPED_TRACE(StringPrintf("rcode: %d", config.rcode));
1309
1310 test::DNSResponder dns(config.rcode);
1311 dns.addMapping(host_name, ns_type::ns_t_a, "1.2.3.4");
1312 dns.setResponseProbability(0.0); // always ignore requests and response preset rcode
1313 ASSERT_TRUE(dns.startServer());
1314 ASSERT_EQ(0, SetResolvers());
1315
1316 hostent* hp = nullptr;
1317 hostent hbuf;
1318 char tmpbuf[MAXPACKET];
1319 NetworkDnsEventReported event;
1320 int rv = resolv_gethostbyname(host_name, AF_INET, &hbuf, tmpbuf, sizeof tmpbuf,
1321 &mNetcontext, &hp, &event);
1322 EXPECT_EQ(nullptr, hp);
1323 EXPECT_EQ(config.expected_eai_error, rv);
1324 }
1325 }
1326
1327 // TODO: Add private DNS server timeout test.
TEST_F(GetHostByNameForNetContextTest,ServerTimeout)1328 TEST_F(GetHostByNameForNetContextTest, ServerTimeout) {
1329 constexpr char host_name[] = "hello.example.com.";
1330 test::DNSResponder dns(static_cast<ns_rcode>(-1) /*no response*/);
1331 dns.addMapping(host_name, ns_type::ns_t_a, "1.2.3.4");
1332 dns.setResponseProbability(0.0); // always ignore requests and don't response
1333 ASSERT_TRUE(dns.startServer());
1334 ASSERT_EQ(0, SetResolvers());
1335
1336 hostent* hp = nullptr;
1337 hostent hbuf;
1338 char tmpbuf[MAXPACKET];
1339 NetworkDnsEventReported event;
1340 int rv = resolv_gethostbyname(host_name, AF_INET, &hbuf, tmpbuf, sizeof tmpbuf, &mNetcontext,
1341 &hp, &event);
1342 EXPECT_EQ(NETD_RESOLV_TIMEOUT, rv);
1343 }
1344
TEST_F(GetHostByNameForNetContextTest,CnamesNoIpAddress)1345 TEST_F(GetHostByNameForNetContextTest, CnamesNoIpAddress) {
1346 constexpr char ACNAME[] = "acname"; // expect a cname in answer
1347 constexpr char CNAMES[] = "cnames"; // expect cname chain in answer
1348
1349 test::DNSResponder dns;
1350 dns.addMapping("cnames.example.com.", ns_type::ns_t_cname, "acname.example.com.");
1351 dns.addMapping("acname.example.com.", ns_type::ns_t_cname, "hello.example.com.");
1352 ASSERT_TRUE(dns.startServer());
1353 ASSERT_EQ(0, SetResolvers());
1354
1355 static const struct TestConfig {
1356 const char* name;
1357 int family;
1358 } testConfigs[]{
1359 {ACNAME, AF_INET},
1360 {ACNAME, AF_INET6},
1361 {CNAMES, AF_INET},
1362 {CNAMES, AF_INET6},
1363 };
1364
1365 for (const auto& config : testConfigs) {
1366 SCOPED_TRACE(
1367 StringPrintf("config.family: %d, config.name: %s", config.family, config.name));
1368
1369 struct hostent* hp = nullptr;
1370 hostent hbuf;
1371 char tmpbuf[MAXPACKET];
1372 NetworkDnsEventReported event;
1373 int rv = resolv_gethostbyname(config.name, config.family, &hbuf, tmpbuf, sizeof tmpbuf,
1374 &mNetcontext, &hp, &event);
1375 EXPECT_EQ(nullptr, hp);
1376 EXPECT_EQ(EAI_FAIL, rv);
1377 }
1378 }
1379
TEST_F(GetHostByNameForNetContextTest,CnamesBrokenChainByIllegalCname)1380 TEST_F(GetHostByNameForNetContextTest, CnamesBrokenChainByIllegalCname) {
1381 test::DNSResponder dns;
1382 ASSERT_TRUE(dns.startServer());
1383 ASSERT_EQ(0, SetResolvers());
1384
1385 static const struct TestConfig {
1386 const char* name;
1387 const char* cname;
1388 std::string asHostName() const { return StringPrintf("%s.example.com.", name); }
1389
1390 // Illegal cname is verified by res_hnok() in system/netd/resolv/res_comp.cpp
1391 } testConfigs[]{
1392 // clang-format off
1393 {NAME(kBadCharAfterPeriodHost), kBadCharAfterPeriodHost},
1394 {NAME(kBadCharBeforePeriodHost), kBadCharBeforePeriodHost},
1395 {NAME(kBadCharAtTheEndHost), kBadCharAtTheEndHost},
1396 {NAME(kBadCharInTheMiddleOfLabelHost), kBadCharInTheMiddleOfLabelHost},
1397 // clang-format on
1398 };
1399
1400 for (const auto& config : testConfigs) {
1401 const std::string testHostName = config.asHostName();
1402
1403 // Expect to get no address because the cname chain is broken by an illegal cname format.
1404 //
1405 // Ex:
1406 // ANSWER SECTION:
1407 // hello.example.com. IN CNAME a.ex^ample.com.
1408 // a.ex^ample.com. IN A 1.2.3.3
1409 // a.ex^ample.com. IN AAAA 2001:db8::42
1410 //
1411 // In this example, querying hello.example.com should get no address because
1412 // "a.ex^ample.com" has an illegal char '^' in the middle of label.
1413 dns.addMapping(testHostName.c_str(), ns_type::ns_t_cname, config.cname);
1414 dns.addMapping(config.cname, ns_type::ns_t_a, "1.2.3.3");
1415 dns.addMapping(config.cname, ns_type::ns_t_aaaa, "2001:db8::42");
1416
1417 for (const auto& family : {AF_INET, AF_INET6}) {
1418 SCOPED_TRACE(
1419 StringPrintf("family: %d, testHostName: %s", family, testHostName.c_str()));
1420
1421 struct hostent* hp = nullptr;
1422 hostent hbuf;
1423 char tmpbuf[MAXPACKET];
1424 NetworkDnsEventReported event;
1425 int rv = resolv_gethostbyname(config.name, family, &hbuf, tmpbuf, sizeof tmpbuf,
1426 &mNetcontext, &hp, &event);
1427 EXPECT_EQ(nullptr, hp);
1428 EXPECT_EQ(EAI_FAIL, rv);
1429 }
1430 }
1431 }
1432
TEST_F(GetHostByNameForNetContextTest,CnamesInfiniteLoop)1433 TEST_F(GetHostByNameForNetContextTest, CnamesInfiniteLoop) {
1434 test::DNSResponder dns;
1435 dns.addMapping("hello.example.com.", ns_type::ns_t_cname, "a.example.com.");
1436 dns.addMapping("a.example.com.", ns_type::ns_t_cname, "hello.example.com.");
1437 ASSERT_TRUE(dns.startServer());
1438 ASSERT_EQ(0, SetResolvers());
1439
1440 for (const auto& family : {AF_INET, AF_INET6}) {
1441 SCOPED_TRACE(StringPrintf("family: %d", family));
1442
1443 struct hostent* hp = nullptr;
1444 hostent hbuf;
1445 char tmpbuf[MAXPACKET];
1446 NetworkDnsEventReported event;
1447 int rv = resolv_gethostbyname("hello", family, &hbuf, tmpbuf, sizeof tmpbuf, &mNetcontext,
1448 &hp, &event);
1449 EXPECT_EQ(nullptr, hp);
1450 EXPECT_EQ(EAI_FAIL, rv);
1451 }
1452 }
1453
TEST_F(ResolvCommonFunctionTest,GetCustTableByName)1454 TEST_F(ResolvCommonFunctionTest, GetCustTableByName) {
1455 const char custAddrV4[] = "1.2.3.4";
1456 const char custAddrV6[] = "::1.2.3.4";
1457 const char hostnameV4V6[] = "v4v6.example.com.";
1458 const aidl::android::net::ResolverOptionsParcel& resolverOptions = {
1459 {
1460 {custAddrV4, hostnameV4V6},
1461 {custAddrV6, hostnameV4V6},
1462 },
1463 aidl::android::net::IDnsResolver::TC_MODE_DEFAULT};
1464 const std::vector<int32_t>& transportTypes = {IDnsResolver::TRANSPORT_WIFI};
1465 EXPECT_EQ(0, resolv_set_nameservers(TEST_NETID, servers, domains, params, resolverOptions,
1466 transportTypes));
1467 EXPECT_THAT(getCustomizedTableByName(TEST_NETID, hostnameV4V6),
1468 testing::UnorderedElementsAreArray({custAddrV4, custAddrV6}));
1469
1470 // Query address by mismatch hostname.
1471 ASSERT_TRUE(getCustomizedTableByName(TEST_NETID, "not.in.cust.table").empty());
1472
1473 // Query address by different netid.
1474 ASSERT_TRUE(getCustomizedTableByName(TEST_NETID + 1, hostnameV4V6).empty());
1475 resolv_create_cache_for_net(TEST_NETID + 1);
1476 EXPECT_EQ(0, resolv_set_nameservers(TEST_NETID + 1, servers, domains, params, resolverOptions,
1477 transportTypes));
1478 EXPECT_THAT(getCustomizedTableByName(TEST_NETID + 1, hostnameV4V6),
1479 testing::UnorderedElementsAreArray({custAddrV4, custAddrV6}));
1480 }
1481
TEST_F(ResolvCommonFunctionTest,GetNetworkTypesForNet)1482 TEST_F(ResolvCommonFunctionTest, GetNetworkTypesForNet) {
1483 const aidl::android::net::ResolverOptionsParcel& resolverOptions = {
1484 {} /* hosts */, aidl::android::net::IDnsResolver::TC_MODE_DEFAULT};
1485 const std::vector<int32_t>& transportTypes = {IDnsResolver::TRANSPORT_WIFI,
1486 IDnsResolver::TRANSPORT_VPN};
1487 EXPECT_EQ(0, resolv_set_nameservers(TEST_NETID, servers, domains, params, resolverOptions,
1488 transportTypes));
1489 EXPECT_EQ(android::net::NT_WIFI_VPN, resolv_get_network_types_for_net(TEST_NETID));
1490 }
1491
TEST_F(ResolvCommonFunctionTest,ConvertTransportsToNetworkType)1492 TEST_F(ResolvCommonFunctionTest, ConvertTransportsToNetworkType) {
1493 static const struct TestConfig {
1494 int32_t networkType;
1495 std::vector<int32_t> transportTypes;
1496 } testConfigs[] = {
1497 {android::net::NT_CELLULAR, {IDnsResolver::TRANSPORT_CELLULAR}},
1498 {android::net::NT_WIFI, {IDnsResolver::TRANSPORT_WIFI}},
1499 {android::net::NT_BLUETOOTH, {IDnsResolver::TRANSPORT_BLUETOOTH}},
1500 {android::net::NT_ETHERNET, {IDnsResolver::TRANSPORT_ETHERNET}},
1501 {android::net::NT_VPN, {IDnsResolver::TRANSPORT_VPN}},
1502 {android::net::NT_WIFI_AWARE, {IDnsResolver::TRANSPORT_WIFI_AWARE}},
1503 {android::net::NT_LOWPAN, {IDnsResolver::TRANSPORT_LOWPAN}},
1504 {android::net::NT_CELLULAR_VPN,
1505 {IDnsResolver::TRANSPORT_CELLULAR, IDnsResolver::TRANSPORT_VPN}},
1506 {android::net::NT_CELLULAR_VPN,
1507 {IDnsResolver::TRANSPORT_VPN, IDnsResolver::TRANSPORT_CELLULAR}},
1508 {android::net::NT_WIFI_VPN,
1509 {IDnsResolver::TRANSPORT_WIFI, IDnsResolver::TRANSPORT_VPN}},
1510 {android::net::NT_WIFI_VPN,
1511 {IDnsResolver::TRANSPORT_VPN, IDnsResolver::TRANSPORT_WIFI}},
1512 {android::net::NT_BLUETOOTH_VPN,
1513 {IDnsResolver::TRANSPORT_BLUETOOTH, IDnsResolver::TRANSPORT_VPN}},
1514 {android::net::NT_BLUETOOTH_VPN,
1515 {IDnsResolver::TRANSPORT_VPN, IDnsResolver::TRANSPORT_BLUETOOTH}},
1516 {android::net::NT_ETHERNET_VPN,
1517 {IDnsResolver::TRANSPORT_ETHERNET, IDnsResolver::TRANSPORT_VPN}},
1518 {android::net::NT_ETHERNET_VPN,
1519 {IDnsResolver::TRANSPORT_VPN, IDnsResolver::TRANSPORT_ETHERNET}},
1520 {android::net::NT_UNKNOWN, {IDnsResolver::TRANSPORT_VPN, IDnsResolver::TRANSPORT_VPN}},
1521 {android::net::NT_UNKNOWN,
1522 {IDnsResolver::TRANSPORT_WIFI, IDnsResolver::TRANSPORT_LOWPAN}},
1523 {android::net::NT_UNKNOWN, {}},
1524 {android::net::NT_UNKNOWN,
1525 {IDnsResolver::TRANSPORT_CELLULAR, IDnsResolver::TRANSPORT_BLUETOOTH,
1526 IDnsResolver::TRANSPORT_VPN}},
1527 {android::net::NT_WIFI_CELLULAR_VPN,
1528 {IDnsResolver::TRANSPORT_CELLULAR, IDnsResolver::TRANSPORT_WIFI,
1529 IDnsResolver::TRANSPORT_VPN}},
1530 {android::net::NT_WIFI_CELLULAR_VPN,
1531 {IDnsResolver::TRANSPORT_VPN, IDnsResolver::TRANSPORT_WIFI,
1532 IDnsResolver::TRANSPORT_CELLULAR}},
1533 };
1534 for (const auto& config : testConfigs) {
1535 EXPECT_EQ(config.networkType, convert_network_type(config.transportTypes));
1536 }
1537 }
1538
1539 // Note that local host file function, files_getaddrinfo(), of resolv_getaddrinfo()
1540 // is not tested because it only returns a boolean (success or failure) without any error number.
1541
1542 // TODO: Add test for resolv_getaddrinfo().
1543 // - DNS response message parsing.
1544 // - Unexpected type of resource record (RR).
1545 // - Invalid length CNAME, or QNAME.
1546 // - Unexpected amount of questions.
1547 // - CNAME RDATA with the domain name which has null label(s).
1548 // TODO: Add test for resolv_gethostbyname().
1549 // - Invalid parameters.
1550 // - DNS response message parsing.
1551 // - Unexpected type of resource record (RR).
1552 // - Invalid length CNAME, or QNAME.
1553 // - Unexpected amount of questions.
1554 // - CNAME RDATA with the domain name which has null label(s).
1555 // TODO: Add test for resolv_gethostbyaddr().
1556
1557 } // end of namespace net
1558 } // end of namespace android
1559