blob: 55453f21a29c49c9e8b2d7f93fa3c52cb13253e3 [file] [log] [blame]
Pierre Imai904ce3a2016-02-18 13:13:12 +09001/*
2 * Copyright (C) 2016 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 requied 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
18#include <arpa/inet.h>
19#include <errno.h>
20#include <netdb.h>
21#include <stdarg.h>
22#include <stdio.h>
23#include <stdlib.h>
Pierre Imai95f5f942016-03-09 18:09:25 +090024#include <unistd.h>
Pierre Imai904ce3a2016-02-18 13:13:12 +090025
26#include <cutils/sockets.h>
Pierre Imai95f5f942016-03-09 18:09:25 +090027#include <android-base/stringprintf.h>
Pierre Imai904ce3a2016-02-18 13:13:12 +090028#include <private/android_filesystem_config.h>
Pierre Imai95f5f942016-03-09 18:09:25 +090029
30#include <thread>
31
Pierre Imai904ce3a2016-02-18 13:13:12 +090032#include "NetdClient.h"
33
34#include <gtest/gtest.h>
35#define LOG_TAG "resolverTest"
36#include <utils/Log.h>
37#include <testUtil.h>
38
39#include "dns_responder.h"
Pierre Imai95f5f942016-03-09 18:09:25 +090040#include "resolv_params.h"
41
42using android::base::StringPrintf;
43using android::base::StringAppendF;
Pierre Imai904ce3a2016-02-18 13:13:12 +090044
45// TODO: make this dynamic and stop depending on implementation details.
46#define TEST_OEM_NETWORK "oem29"
47#define TEST_NETID 30
48
Pierre Imai95f5f942016-03-09 18:09:25 +090049// The only response code used in this test, see
50// frameworks/base/services/java/com/android/server/NetworkManagementService.java
51// for others.
52static constexpr int ResponseCodeOK = 200;
Pierre Imai904ce3a2016-02-18 13:13:12 +090053
54// Returns ResponseCode.
55int netdCommand(const char* sockname, const char* command) {
56 int sock = socket_local_client(sockname,
57 ANDROID_SOCKET_NAMESPACE_RESERVED,
58 SOCK_STREAM);
59 if (sock < 0) {
60 perror("Error connecting");
61 return -1;
62 }
63
64 // FrameworkListener expects the whole command in one read.
65 char buffer[256];
66 int nwritten = snprintf(buffer, sizeof(buffer), "0 %s", command);
67 if (write(sock, buffer, nwritten + 1) < 0) {
68 perror("Error sending netd command");
69 close(sock);
70 return -1;
71 }
72
73 int nread = read(sock, buffer, sizeof(buffer));
74 if (nread < 0) {
75 perror("Error reading response");
76 close(sock);
77 return -1;
78 }
79 close(sock);
80 return atoi(buffer);
81}
82
83
Pierre Imai95f5f942016-03-09 18:09:25 +090084bool expectNetdResult(int expected, const char* sockname, const char* format, ...) {
Pierre Imai904ce3a2016-02-18 13:13:12 +090085 char command[256];
86 va_list args;
87 va_start(args, format);
88 vsnprintf(command, sizeof(command), format, args);
89 va_end(args);
90 int result = netdCommand(sockname, command);
Pierre Imai95f5f942016-03-09 18:09:25 +090091 EXPECT_EQ(expected, result) << command;
92 return (200 <= expected && expected < 300);
Pierre Imai904ce3a2016-02-18 13:13:12 +090093}
94
95
96class ResolverTest : public ::testing::Test {
97protected:
98 virtual void SetUp() {
99 // Ensure resolutions go via proxy.
100 setenv("ANDROID_DNS_MODE", "", 1);
101 uid = getuid();
102 pid = getpid();
103 SetupOemNetwork();
104 }
105
106 virtual void TearDown() {
107 TearDownOemNetwork();
108 netdCommand("netd", "network destroy " TEST_OEM_NETWORK);
109 }
110
111 void SetupOemNetwork() {
112 netdCommand("netd", "network destroy " TEST_OEM_NETWORK);
Pierre Imai95f5f942016-03-09 18:09:25 +0900113 if (expectNetdResult(ResponseCodeOK, "netd",
Pierre Imai904ce3a2016-02-18 13:13:12 +0900114 "network create %s", TEST_OEM_NETWORK)) {
115 oemNetId = TEST_NETID;
116 }
117 setNetworkForProcess(oemNetId);
118 ASSERT_EQ((unsigned) oemNetId, getNetworkForProcess());
119 }
120
121 void TearDownOemNetwork() {
122 if (oemNetId != -1) {
Pierre Imai95f5f942016-03-09 18:09:25 +0900123 expectNetdResult(ResponseCodeOK, "netd",
Pierre Imai904ce3a2016-02-18 13:13:12 +0900124 "network destroy %s", TEST_OEM_NETWORK);
125 }
126 }
127
Pierre Imai95f5f942016-03-09 18:09:25 +0900128 bool SetResolversForNetwork(const std::vector<std::string>& searchDomains,
129 const std::vector<std::string>& servers, const std::string& params) {
130 // No use case for empty domains / servers (yet).
131 if (searchDomains.empty() || servers.empty()) return false;
132
133 std::string cmd = StringPrintf("resolver setnetdns %d \"%s", oemNetId,
134 searchDomains[0].c_str());
135 for (size_t i = 1 ; i < searchDomains.size() ; ++i) {
136 cmd += " ";
137 cmd += searchDomains[i];
138 }
139 cmd += "\" ";
140
141 cmd += servers[0];
142 for (size_t i = 1 ; i < servers.size() ; ++i) {
143 cmd += " ";
144 cmd += servers[i];
145 }
146
147 if (!params.empty()) {
148 cmd += " --params \"";
149 cmd += params;
150 cmd += "\"";
151 }
152
153 int rv = netdCommand("netd", cmd.c_str());
Pierre Imai95f5f942016-03-09 18:09:25 +0900154 if (rv != ResponseCodeOK) {
155 return false;
156 }
157 return true;
Pierre Imai904ce3a2016-02-18 13:13:12 +0900158 }
159
Pierre Imai95f5f942016-03-09 18:09:25 +0900160 std::string ToString(const hostent* he) const {
161 if (he == nullptr) return "<null>";
162 char buffer[INET6_ADDRSTRLEN];
163 if (!inet_ntop(he->h_addrtype, he->h_addr_list[0], buffer, sizeof(buffer))) {
164 return "<invalid>";
165 }
166 return buffer;
Pierre Imaiccf7b992016-02-25 16:34:29 +0900167 }
168
Pierre Imai95f5f942016-03-09 18:09:25 +0900169 std::string ToString(const addrinfo* ai) const {
170 if (!ai)
Pierre Imai904ce3a2016-02-18 13:13:12 +0900171 return "<null>";
Pierre Imai95f5f942016-03-09 18:09:25 +0900172 for (const auto* aip = ai ; aip != nullptr ; aip = aip->ai_next) {
173 char host[NI_MAXHOST];
174 int rv = getnameinfo(aip->ai_addr, aip->ai_addrlen, host, sizeof(host), nullptr, 0,
175 NI_NUMERICHOST);
176 if (rv != 0)
177 return gai_strerror(rv);
178 return host;
179 }
180 return "<invalid>";
181 }
182
183 size_t GetNumQueries(const test::DNSResponder& dns, const char* name) const {
184 auto queries = dns.queries();
185 size_t found = 0;
186 for (const auto& p : queries) {
187 std::cout << "query " << p.first << "\n";
188 if (p.first == name) {
189 ++found;
190 }
191 }
192 return found;
193 }
194
195 size_t GetNumQueriesForType(const test::DNSResponder& dns, ns_type type,
196 const char* name) const {
197 auto queries = dns.queries();
198 size_t found = 0;
199 for (const auto& p : queries) {
200 std::cout << "query " << p.first << "\n";
201 if (p.second == type && p.first == name) {
202 ++found;
203 }
204 }
205 return found;
Pierre Imai904ce3a2016-02-18 13:13:12 +0900206 }
207
208 int pid;
209 int uid;
210 int oemNetId = -1;
Pierre Imai95f5f942016-03-09 18:09:25 +0900211 const std::vector<std::string> mDefaultSearchDomains = { "example.com" };
212 // <sample validity in s> <success threshold in percent> <min samples> <max samples>
213 const std::string mDefaultParams = "300 25 8 8";
Pierre Imai904ce3a2016-02-18 13:13:12 +0900214};
215
Pierre Imai904ce3a2016-02-18 13:13:12 +0900216TEST_F(ResolverTest, GetHostByName) {
217 const char* listen_addr = "127.0.0.3";
218 const char* listen_srv = "53";
Pierre Imai95f5f942016-03-09 18:09:25 +0900219 const char* host_name = "hello.example.com.";
220 test::DNSResponder dns(listen_addr, listen_srv, 250, ns_rcode::ns_r_servfail, 1.0);
221 dns.addMapping(host_name, ns_type::ns_t_a, "1.2.3.3");
222 ASSERT_TRUE(dns.startServer());
223 std::vector<std::string> servers = { listen_addr };
224 ASSERT_TRUE(SetResolversForNetwork(mDefaultSearchDomains, servers, mDefaultParams));
Pierre Imai904ce3a2016-02-18 13:13:12 +0900225
Pierre Imai95f5f942016-03-09 18:09:25 +0900226 dns.clearQueries();
Pierre Imai904ce3a2016-02-18 13:13:12 +0900227 const hostent* result = gethostbyname("hello");
Pierre Imai95f5f942016-03-09 18:09:25 +0900228 EXPECT_EQ(1U, GetNumQueriesForType(dns, ns_type::ns_t_a, host_name));
Pierre Imai904ce3a2016-02-18 13:13:12 +0900229 ASSERT_FALSE(result == nullptr);
230 ASSERT_EQ(4, result->h_length);
231 ASSERT_FALSE(result->h_addr_list[0] == nullptr);
Pierre Imai95f5f942016-03-09 18:09:25 +0900232 EXPECT_EQ("1.2.3.3", ToString(result));
Pierre Imai904ce3a2016-02-18 13:13:12 +0900233 EXPECT_TRUE(result->h_addr_list[1] == nullptr);
Pierre Imai95f5f942016-03-09 18:09:25 +0900234 dns.stopServer();
Pierre Imai904ce3a2016-02-18 13:13:12 +0900235}
236
237TEST_F(ResolverTest, GetAddrInfo) {
238 addrinfo* result = nullptr;
239
240 const char* listen_addr = "127.0.0.4";
Pierre Imai6f4f86d2016-04-08 13:15:27 +0900241 const char* listen_addr2 = "127.0.0.5";
Pierre Imai904ce3a2016-02-18 13:13:12 +0900242 const char* listen_srv = "53";
Pierre Imai95f5f942016-03-09 18:09:25 +0900243 const char* host_name = "howdie.example.com.";
244 test::DNSResponder dns(listen_addr, listen_srv, 250,
245 ns_rcode::ns_r_servfail, 1.0);
246 dns.addMapping(host_name, ns_type::ns_t_a, "1.2.3.4");
247 dns.addMapping(host_name, ns_type::ns_t_aaaa, "::1.2.3.4");
248 ASSERT_TRUE(dns.startServer());
249 std::vector<std::string> servers = { listen_addr };
250 ASSERT_TRUE(SetResolversForNetwork(mDefaultSearchDomains, servers, mDefaultParams));
Pierre Imai904ce3a2016-02-18 13:13:12 +0900251
Pierre Imai95f5f942016-03-09 18:09:25 +0900252 dns.clearQueries();
Pierre Imai904ce3a2016-02-18 13:13:12 +0900253 EXPECT_EQ(0, getaddrinfo("howdie", nullptr, nullptr, &result));
Pierre Imai95f5f942016-03-09 18:09:25 +0900254 size_t found = GetNumQueries(dns, host_name);
Pierre Imaib19fcc72016-03-11 17:54:48 +0900255 EXPECT_LE(1U, found);
Pierre Imai904ce3a2016-02-18 13:13:12 +0900256 // Could be A or AAAA
257 std::string result_str = ToString(result);
Pierre Imai95f5f942016-03-09 18:09:25 +0900258 EXPECT_TRUE(result_str == "1.2.3.4" || result_str == "::1.2.3.4")
259 << ", result_str='" << result_str << "'";
Pierre Imai904ce3a2016-02-18 13:13:12 +0900260 if (result) freeaddrinfo(result);
261 result = nullptr;
262
Pierre Imai6f4f86d2016-04-08 13:15:27 +0900263 // Verify that the name is cached.
Pierre Imaiccf7b992016-02-25 16:34:29 +0900264 size_t old_found = found;
Pierre Imai904ce3a2016-02-18 13:13:12 +0900265 EXPECT_EQ(0, getaddrinfo("howdie", nullptr, nullptr, &result));
Pierre Imai95f5f942016-03-09 18:09:25 +0900266 found = GetNumQueries(dns, host_name);
Pierre Imaiccf7b992016-02-25 16:34:29 +0900267 EXPECT_EQ(old_found, found);
Pierre Imai904ce3a2016-02-18 13:13:12 +0900268 result_str = ToString(result);
Pierre Imai95f5f942016-03-09 18:09:25 +0900269 EXPECT_TRUE(result_str == "1.2.3.4" || result_str == "::1.2.3.4")
270 << result_str;
Pierre Imai904ce3a2016-02-18 13:13:12 +0900271 if (result) freeaddrinfo(result);
272 result = nullptr;
273
Pierre Imai6f4f86d2016-04-08 13:15:27 +0900274 // Change the DNS resolver, ensure that queries are no longer cached.
Pierre Imai95f5f942016-03-09 18:09:25 +0900275 dns.clearQueries();
Pierre Imai6f4f86d2016-04-08 13:15:27 +0900276 test::DNSResponder dns2(listen_addr2, listen_srv, 250,
277 ns_rcode::ns_r_servfail, 1.0);
278 dns2.addMapping(host_name, ns_type::ns_t_a, "1.2.3.4");
279 dns2.addMapping(host_name, ns_type::ns_t_aaaa, "::1.2.3.4");
280 ASSERT_TRUE(dns2.startServer());
281 servers = { listen_addr2 };
282 ASSERT_TRUE(SetResolversForNetwork(mDefaultSearchDomains, servers, mDefaultParams));
Pierre Imai904ce3a2016-02-18 13:13:12 +0900283 EXPECT_EQ(0, getaddrinfo("howdie", nullptr, nullptr, &result));
Pierre Imai6f4f86d2016-04-08 13:15:27 +0900284 found = GetNumQueries(dns, host_name);
285 size_t found2 = GetNumQueries(dns2, host_name);
286 EXPECT_EQ(0U, found);
287 EXPECT_LE(1U, found2);
288
Pierre Imai904ce3a2016-02-18 13:13:12 +0900289 // Could be A or AAAA
290 result_str = ToString(result);
Pierre Imai6f4f86d2016-04-08 13:15:27 +0900291 EXPECT_TRUE(result_str == "1.2.3.4" || result_str == "::1.2.3.4")
Pierre Imai95f5f942016-03-09 18:09:25 +0900292 << ", result_str='" << result_str << "'";
Pierre Imai904ce3a2016-02-18 13:13:12 +0900293 if (result) freeaddrinfo(result);
Pierre Imai6f4f86d2016-04-08 13:15:27 +0900294 result = nullptr;
295 dns.stopServer();
296 dns2.stopServer();
Pierre Imai904ce3a2016-02-18 13:13:12 +0900297}
298
299TEST_F(ResolverTest, GetAddrInfoV4) {
300 addrinfo* result = nullptr;
301
302 const char* listen_addr = "127.0.0.5";
303 const char* listen_srv = "53";
Pierre Imai95f5f942016-03-09 18:09:25 +0900304 const char* host_name = "hola.example.com.";
305 test::DNSResponder dns(listen_addr, listen_srv, 250,
306 ns_rcode::ns_r_servfail, 1.0);
307 dns.addMapping(host_name, ns_type::ns_t_a, "1.2.3.5");
308 ASSERT_TRUE(dns.startServer());
309 std::vector<std::string> servers = { listen_addr };
310 ASSERT_TRUE(SetResolversForNetwork(mDefaultSearchDomains, servers, mDefaultParams));
Pierre Imai904ce3a2016-02-18 13:13:12 +0900311
312 addrinfo hints;
313 memset(&hints, 0, sizeof(hints));
314 hints.ai_family = AF_INET;
315 EXPECT_EQ(0, getaddrinfo("hola", nullptr, &hints, &result));
Pierre Imai95f5f942016-03-09 18:09:25 +0900316 EXPECT_EQ(1U, GetNumQueries(dns, host_name));
Pierre Imaiccf7b992016-02-25 16:34:29 +0900317 EXPECT_EQ("1.2.3.5", ToString(result));
Pierre Imai904ce3a2016-02-18 13:13:12 +0900318 if (result) freeaddrinfo(result);
319}
Pierre Imai95f5f942016-03-09 18:09:25 +0900320
321TEST_F(ResolverTest, MultidomainResolution) {
322 std::vector<std::string> searchDomains = { "example1.com", "example2.com", "example3.com" };
323 const char* listen_addr = "127.0.0.6";
324 const char* listen_srv = "53";
325 const char* host_name = "nihao.example2.com.";
326 test::DNSResponder dns(listen_addr, listen_srv, 250,
327 ns_rcode::ns_r_servfail, 1.0);
328 dns.addMapping(host_name, ns_type::ns_t_a, "1.2.3.3");
329 ASSERT_TRUE(dns.startServer());
330 std::vector<std::string> servers = { listen_addr };
331 ASSERT_TRUE(SetResolversForNetwork(searchDomains, servers, mDefaultParams));
332
333 dns.clearQueries();
334 const hostent* result = gethostbyname("nihao");
335 EXPECT_EQ(1U, GetNumQueriesForType(dns, ns_type::ns_t_a, host_name));
336 ASSERT_FALSE(result == nullptr);
337 ASSERT_EQ(4, result->h_length);
338 ASSERT_FALSE(result->h_addr_list[0] == nullptr);
339 EXPECT_EQ("1.2.3.3", ToString(result));
340 EXPECT_TRUE(result->h_addr_list[1] == nullptr);
341 dns.stopServer();
342}
343
344TEST_F(ResolverTest, GetAddrInfoV6_failing) {
345 addrinfo* result = nullptr;
346
347 const char* listen_addr0 = "127.0.0.7";
348 const char* listen_addr1 = "127.0.0.8";
349 const char* listen_srv = "53";
350 const char* host_name = "ohayou.example.com.";
351 test::DNSResponder dns0(listen_addr0, listen_srv, 250,
352 ns_rcode::ns_r_servfail, 0.0);
353 test::DNSResponder dns1(listen_addr1, listen_srv, 250,
354 ns_rcode::ns_r_servfail, 1.0);
355 dns0.addMapping(host_name, ns_type::ns_t_aaaa, "2001:db8::5");
356 dns1.addMapping(host_name, ns_type::ns_t_aaaa, "2001:db8::6");
357 ASSERT_TRUE(dns0.startServer());
358 ASSERT_TRUE(dns1.startServer());
359 std::vector<std::string> servers = { listen_addr0, listen_addr1 };
360 // <sample validity in s> <success threshold in percent> <min samples> <max samples>
361 unsigned sample_validity = 300;
362 int success_threshold = 25;
363 int sample_count = 8;
364 std::string params = StringPrintf("%u %d %d %d", sample_validity, success_threshold,
365 sample_count, sample_count);
366 ASSERT_TRUE(SetResolversForNetwork(mDefaultSearchDomains, servers, params));
367
368 // Repeatedly perform resolutions for non-existing domains until MAXNSSAMPLES resolutions have
369 // reached the dns0, which is set to fail. No more requests should then arrive at that server
370 // for the next sample_lifetime seconds.
371 // TODO: This approach is implementation-dependent, change once metrics reporting is available.
372 addrinfo hints;
373 memset(&hints, 0, sizeof(hints));
374 hints.ai_family = AF_INET6;
375 for (int i = 0 ; i < sample_count ; ++i) {
376 std::string domain = StringPrintf("nonexistent%d", i);
377 getaddrinfo(domain.c_str(), nullptr, &hints, &result);
378 }
379 // Due to 100% errors for all possible samples, the server should be ignored from now on and
380 // only the second one used for all following queries, until NSSAMPLE_VALIDITY is reached.
381 dns0.clearQueries();
382 dns1.clearQueries();
383 EXPECT_EQ(0, getaddrinfo("ohayou", nullptr, &hints, &result));
384 EXPECT_EQ(0U, GetNumQueries(dns0, host_name));
385 EXPECT_EQ(1U, GetNumQueries(dns1, host_name));
386 if (result) freeaddrinfo(result);
387}
388
389TEST_F(ResolverTest, GetAddrInfoV6_concurrent) {
390 const char* listen_addr0 = "127.0.0.9";
391 const char* listen_addr1 = "127.0.0.10";
392 const char* listen_addr2 = "127.0.0.11";
393 const char* listen_srv = "53";
394 const char* host_name = "konbanha.example.com.";
395 test::DNSResponder dns0(listen_addr0, listen_srv, 250,
396 ns_rcode::ns_r_servfail, 1.0);
397 test::DNSResponder dns1(listen_addr1, listen_srv, 250,
398 ns_rcode::ns_r_servfail, 1.0);
399 test::DNSResponder dns2(listen_addr2, listen_srv, 250,
400 ns_rcode::ns_r_servfail, 1.0);
401 dns0.addMapping(host_name, ns_type::ns_t_aaaa, "2001:db8::5");
402 dns1.addMapping(host_name, ns_type::ns_t_aaaa, "2001:db8::6");
403 dns2.addMapping(host_name, ns_type::ns_t_aaaa, "2001:db8::7");
404 ASSERT_TRUE(dns0.startServer());
405 ASSERT_TRUE(dns1.startServer());
406 ASSERT_TRUE(dns2.startServer());
407 const std::vector<std::string> servers = { listen_addr0, listen_addr1, listen_addr2 };
408 std::vector<std::thread> threads(10);
409 for (std::thread& thread : threads) {
410 thread = std::thread([this, &servers, &dns0, &dns1, &dns2]() {
411 unsigned delay = arc4random_uniform(1*1000*1000); // <= 1s
412 usleep(delay);
413 std::vector<std::string> serverSubset;
414 for (const auto& server : servers) {
415 if (arc4random_uniform(2)) {
416 serverSubset.push_back(server);
417 }
418 }
419 if (serverSubset.empty()) serverSubset = servers;
420 ASSERT_TRUE(SetResolversForNetwork(mDefaultSearchDomains, serverSubset,
421 mDefaultParams));
422 addrinfo hints;
423 memset(&hints, 0, sizeof(hints));
424 hints.ai_family = AF_INET6;
425 addrinfo* result = nullptr;
426 int rv = getaddrinfo("konbanha", nullptr, &hints, &result);
427 EXPECT_EQ(0, rv) << "error [" << rv << "] " << gai_strerror(rv);
428 });
429 }
430 for (std::thread& thread : threads) {
431 thread.join();
432 }
433}