blob: 73c9a021038be13504b6bb64f57b4db77de77075 [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>
24
25#include <cutils/sockets.h>
26#include <private/android_filesystem_config.h>
27#include "NetdClient.h"
28
29#include <gtest/gtest.h>
30#define LOG_TAG "resolverTest"
31#include <utils/Log.h>
32#include <testUtil.h>
33
34#include "dns_responder.h"
35
36// TODO: make this dynamic and stop depending on implementation details.
37#define TEST_OEM_NETWORK "oem29"
38#define TEST_NETID 30
39
Pierre Imaiccf7b992016-02-25 16:34:29 +090040enum class ResponseCode : int {
Pierre Imai904ce3a2016-02-18 13:13:12 +090041 // Keep in sync with
42 // frameworks/base/services/java/com/android/server/NetworkManagementService.java
Pierre Imaiccf7b992016-02-25 16:34:29 +090043 CommandOkay = 200,
44 DnsProxyQueryResult = 222,
Pierre Imai904ce3a2016-02-18 13:13:12 +090045
Pierre Imaiccf7b992016-02-25 16:34:29 +090046 DnsProxyOperationFailed = 401,
Pierre Imai904ce3a2016-02-18 13:13:12 +090047
Pierre Imaiccf7b992016-02-25 16:34:29 +090048 CommandSyntaxError = 500,
49 CommandParameterError = 501
Pierre Imai904ce3a2016-02-18 13:13:12 +090050};
51
52
53// Returns ResponseCode.
54int netdCommand(const char* sockname, const char* command) {
55 int sock = socket_local_client(sockname,
56 ANDROID_SOCKET_NAMESPACE_RESERVED,
57 SOCK_STREAM);
58 if (sock < 0) {
59 perror("Error connecting");
60 return -1;
61 }
62
63 // FrameworkListener expects the whole command in one read.
64 char buffer[256];
65 int nwritten = snprintf(buffer, sizeof(buffer), "0 %s", command);
66 if (write(sock, buffer, nwritten + 1) < 0) {
67 perror("Error sending netd command");
68 close(sock);
69 return -1;
70 }
71
72 int nread = read(sock, buffer, sizeof(buffer));
73 if (nread < 0) {
74 perror("Error reading response");
75 close(sock);
76 return -1;
77 }
78 close(sock);
79 return atoi(buffer);
80}
81
82
Pierre Imaiccf7b992016-02-25 16:34:29 +090083bool expectNetdResult(ResponseCode code, const char* sockname, const char* format, ...) {
Pierre Imai904ce3a2016-02-18 13:13:12 +090084 char command[256];
85 va_list args;
86 va_start(args, format);
87 vsnprintf(command, sizeof(command), format, args);
88 va_end(args);
89 int result = netdCommand(sockname, command);
Pierre Imaiccf7b992016-02-25 16:34:29 +090090 int rc = static_cast<int>(code);
91 EXPECT_EQ(rc, result) << command;
92 return (200 <= rc && rc < 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);
113 if (expectNetdResult(ResponseCode::CommandOkay, "netd",
114 "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) {
123 expectNetdResult(ResponseCode::CommandOkay, "netd",
124 "network destroy %s", TEST_OEM_NETWORK);
125 }
126 }
127
128 bool SetResolverForNetwork(const char* address) const {
129 return
130 expectNetdResult(ResponseCode::CommandOkay, "netd",
131 "resolver setnetdns %d \"example.com\" %s", oemNetId,
132 address) &&
133 FlushCache();
134 }
135
136 bool FlushCache() const {
137 return expectNetdResult(ResponseCode::CommandOkay, "netd",
138 "resolver flushnet %d", oemNetId);
139 }
140
Pierre Imaiccf7b992016-02-25 16:34:29 +0900141 std::string ToString(const hostent* result) const {
142 if (result == nullptr) return std::string();
143 return std::string(result->h_name);
144 }
145
146 std::string ToString(const addrinfo* result) const {
Pierre Imai904ce3a2016-02-18 13:13:12 +0900147 if (!result)
148 return "<null>";
149 sockaddr_in* addr = reinterpret_cast<sockaddr_in*>(result->ai_addr);
Pierre Imaiccf7b992016-02-25 16:34:29 +0900150 return std::string(inet_ntoa(addr->sin_addr));
Pierre Imai904ce3a2016-02-18 13:13:12 +0900151 }
152
153 int pid;
154 int uid;
155 int oemNetId = -1;
156};
157
158
159TEST_F(ResolverTest, GetHostByName) {
160 const char* listen_addr = "127.0.0.3";
161 const char* listen_srv = "53";
162 test::DNSResponder resp(listen_addr, listen_srv, 250,
163 ns_rcode::ns_r_servfail);
164 resp.addMapping("hello.example.com.", ns_type::ns_t_a, "1.2.3.3");
165 ASSERT_TRUE(resp.startServer());
166 ASSERT_TRUE(SetResolverForNetwork(listen_addr));
167
168 resp.clearQueries();
169 const hostent* result = gethostbyname("hello");
170 auto queries = resp.queries();
171 size_t found = 0;
172 for (const auto& p : queries) {
173 if (p.second == ns_type::ns_t_a && p.first == "hello.example.com.") {
174 ++found;
175 }
176 }
177 EXPECT_EQ(1, found);
178 ASSERT_FALSE(result == nullptr);
179 ASSERT_EQ(4, result->h_length);
180 ASSERT_FALSE(result->h_addr_list[0] == nullptr);
Pierre Imaiccf7b992016-02-25 16:34:29 +0900181 EXPECT_EQ("hello.example.com", ToString(result));
Pierre Imai904ce3a2016-02-18 13:13:12 +0900182 EXPECT_TRUE(result->h_addr_list[1] == nullptr);
183 resp.stopServer();
184}
185
186TEST_F(ResolverTest, GetAddrInfo) {
187 addrinfo* result = nullptr;
188
189 const char* listen_addr = "127.0.0.4";
190 const char* listen_srv = "53";
191 test::DNSResponder resp(listen_addr, listen_srv, 250,
192 ns_rcode::ns_r_servfail);
193 resp.addMapping("howdie.example.com.", ns_type::ns_t_a, "1.2.3.4");
194 resp.addMapping("howdie.example.com.", ns_type::ns_t_aaaa, "::1.2.3.4");
195 ASSERT_TRUE(resp.startServer());
196 ASSERT_TRUE(SetResolverForNetwork(listen_addr));
197
198 resp.clearQueries();
199 EXPECT_EQ(0, getaddrinfo("howdie", nullptr, nullptr, &result));
200 auto queries = resp.queries();
201 size_t found = 0;
202 for (const auto& p : queries) {
203 if (p.first == "howdie.example.com.") {
204 ++found;
205 }
206 }
207 EXPECT_LE(1, found);
208 // Could be A or AAAA
209 std::string result_str = ToString(result);
210 EXPECT_TRUE(result_str == "1.2.3.4" || result_str == "::1.2.3.4");
211 if (result) freeaddrinfo(result);
212 result = nullptr;
213
214 // Verify that it's cached.
Pierre Imaiccf7b992016-02-25 16:34:29 +0900215 size_t old_found = found;
Pierre Imai904ce3a2016-02-18 13:13:12 +0900216 EXPECT_EQ(0, getaddrinfo("howdie", nullptr, nullptr, &result));
Pierre Imaiccf7b992016-02-25 16:34:29 +0900217 queries = resp.queries();
218 found = 0;
219 for (const auto& p : queries) {
220 if (p.first == "howdie.example.com.") {
221 ++found;
222 }
223 }
224 EXPECT_EQ(old_found, found);
Pierre Imai904ce3a2016-02-18 13:13:12 +0900225 result_str = ToString(result);
226 EXPECT_TRUE(result_str == "1.2.3.4" || result_str == "::1.2.3.4");
227 if (result) freeaddrinfo(result);
228 result = nullptr;
229
230 // Verify that cache can be flushed.
231 resp.clearQueries();
232 ASSERT_TRUE(FlushCache());
233 resp.addMapping("howdie.example.com.", ns_type::ns_t_a, "1.2.3.44");
234 resp.addMapping("howdie.example.com.", ns_type::ns_t_aaaa, "::1.2.3.44");
235
236 EXPECT_EQ(0, getaddrinfo("howdie", nullptr, nullptr, &result));
237 queries = resp.queries();
238 found = 0;
239 for (const auto& p : queries) {
240 if (p.first == "howdie.example.com.") {
241 ++found;
242 }
243 }
244 EXPECT_LE(1, found);
245 // Could be A or AAAA
246 result_str = ToString(result);
247 EXPECT_TRUE(result_str == "1.2.3.44" || result_str == "::1.2.3.44");
248 if (result) freeaddrinfo(result);
249}
250
251TEST_F(ResolverTest, GetAddrInfoV4) {
252 addrinfo* result = nullptr;
253
254 const char* listen_addr = "127.0.0.5";
255 const char* listen_srv = "53";
256 test::DNSResponder resp(listen_addr, listen_srv, 250,
257 ns_rcode::ns_r_servfail);
258 resp.addMapping("hola.example.com.", ns_type::ns_t_a, "1.2.3.5");
259 ASSERT_TRUE(resp.startServer());
260 ASSERT_TRUE(SetResolverForNetwork(listen_addr));
261
262 addrinfo hints;
263 memset(&hints, 0, sizeof(hints));
264 hints.ai_family = AF_INET;
265 EXPECT_EQ(0, getaddrinfo("hola", nullptr, &hints, &result));
266 auto queries = resp.queries();
267 size_t found = 0;
268 for (const auto& p : queries) {
269 if (p.first == "hola.example.com.") {
270 ++found;
271 }
272 }
273 EXPECT_LE(1, found);
Pierre Imaiccf7b992016-02-25 16:34:29 +0900274 EXPECT_EQ("1.2.3.5", ToString(result));
Pierre Imai904ce3a2016-02-18 13:13:12 +0900275 if (result) freeaddrinfo(result);
276}