blob: 381634629a1b0e32e89115471bd5292a5861a748 [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
40class ResponseCode {
41public:
42 // Keep in sync with
43 // frameworks/base/services/java/com/android/server/NetworkManagementService.java
44 static const int CommandOkay = 200;
45 static const int DnsProxyQueryResult = 222;
46
47 static const int DnsProxyOperationFailed = 401;
48
49 static const int CommandSyntaxError = 500;
50 static const int CommandParameterError = 501;
51};
52
53
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
84bool expectNetdResult(int code, const char* sockname, const char* format, ...) {
85 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);
91 EXPECT_EQ(code, result) << command;
92 return (200 <= code && code < 300);
93}
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
141 const char* ToString(const addrinfo* result) const {
142 if (!result)
143 return "<null>";
144 sockaddr_in* addr = reinterpret_cast<sockaddr_in*>(result->ai_addr);
145 return inet_ntoa(addr->sin_addr);
146 }
147
148 const char* ToString(const hostent* result) const {
149 in_addr addr;
150 memcpy(reinterpret_cast<char*>(&addr), result->h_addr_list[0],
151 sizeof(addr));
152 return inet_ntoa(addr);
153 }
154
155 int pid;
156 int uid;
157 int oemNetId = -1;
158};
159
160
161TEST_F(ResolverTest, GetHostByName) {
162 const char* listen_addr = "127.0.0.3";
163 const char* listen_srv = "53";
164 test::DNSResponder resp(listen_addr, listen_srv, 250,
165 ns_rcode::ns_r_servfail);
166 resp.addMapping("hello.example.com.", ns_type::ns_t_a, "1.2.3.3");
167 ASSERT_TRUE(resp.startServer());
168 ASSERT_TRUE(SetResolverForNetwork(listen_addr));
169
170 resp.clearQueries();
171 const hostent* result = gethostbyname("hello");
172 auto queries = resp.queries();
173 size_t found = 0;
174 for (const auto& p : queries) {
175 if (p.second == ns_type::ns_t_a && p.first == "hello.example.com.") {
176 ++found;
177 }
178 }
179 EXPECT_EQ(1, found);
180 ASSERT_FALSE(result == nullptr);
181 ASSERT_EQ(4, result->h_length);
182 ASSERT_FALSE(result->h_addr_list[0] == nullptr);
183 EXPECT_STREQ("1.2.3.3", ToString(result));
184 EXPECT_TRUE(result->h_addr_list[1] == nullptr);
185 resp.stopServer();
186}
187
188TEST_F(ResolverTest, GetAddrInfo) {
189 addrinfo* result = nullptr;
190
191 const char* listen_addr = "127.0.0.4";
192 const char* listen_srv = "53";
193 test::DNSResponder resp(listen_addr, listen_srv, 250,
194 ns_rcode::ns_r_servfail);
195 resp.addMapping("howdie.example.com.", ns_type::ns_t_a, "1.2.3.4");
196 resp.addMapping("howdie.example.com.", ns_type::ns_t_aaaa, "::1.2.3.4");
197 ASSERT_TRUE(resp.startServer());
198 ASSERT_TRUE(SetResolverForNetwork(listen_addr));
199
200 resp.clearQueries();
201 EXPECT_EQ(0, getaddrinfo("howdie", nullptr, nullptr, &result));
202 auto queries = resp.queries();
203 size_t found = 0;
204 for (const auto& p : queries) {
205 if (p.first == "howdie.example.com.") {
206 ++found;
207 }
208 }
209 EXPECT_LE(1, found);
210 // Could be A or AAAA
211 std::string result_str = ToString(result);
212 EXPECT_TRUE(result_str == "1.2.3.4" || result_str == "::1.2.3.4");
213 if (result) freeaddrinfo(result);
214 result = nullptr;
215
216 // Verify that it's cached.
217 EXPECT_EQ(0, getaddrinfo("howdie", nullptr, nullptr, &result));
218 result_str = ToString(result);
219 EXPECT_TRUE(result_str == "1.2.3.4" || result_str == "::1.2.3.4");
220 if (result) freeaddrinfo(result);
221 result = nullptr;
222
223 // Verify that cache can be flushed.
224 resp.clearQueries();
225 ASSERT_TRUE(FlushCache());
226 resp.addMapping("howdie.example.com.", ns_type::ns_t_a, "1.2.3.44");
227 resp.addMapping("howdie.example.com.", ns_type::ns_t_aaaa, "::1.2.3.44");
228
229 EXPECT_EQ(0, getaddrinfo("howdie", nullptr, nullptr, &result));
230 queries = resp.queries();
231 found = 0;
232 for (const auto& p : queries) {
233 if (p.first == "howdie.example.com.") {
234 ++found;
235 }
236 }
237 EXPECT_LE(1, found);
238 // Could be A or AAAA
239 result_str = ToString(result);
240 EXPECT_TRUE(result_str == "1.2.3.44" || result_str == "::1.2.3.44");
241 if (result) freeaddrinfo(result);
242}
243
244TEST_F(ResolverTest, GetAddrInfoV4) {
245 addrinfo* result = nullptr;
246
247 const char* listen_addr = "127.0.0.5";
248 const char* listen_srv = "53";
249 test::DNSResponder resp(listen_addr, listen_srv, 250,
250 ns_rcode::ns_r_servfail);
251 resp.addMapping("hola.example.com.", ns_type::ns_t_a, "1.2.3.5");
252 ASSERT_TRUE(resp.startServer());
253 ASSERT_TRUE(SetResolverForNetwork(listen_addr));
254
255 addrinfo hints;
256 memset(&hints, 0, sizeof(hints));
257 hints.ai_family = AF_INET;
258 EXPECT_EQ(0, getaddrinfo("hola", nullptr, &hints, &result));
259 auto queries = resp.queries();
260 size_t found = 0;
261 for (const auto& p : queries) {
262 if (p.first == "hola.example.com.") {
263 ++found;
264 }
265 }
266 EXPECT_LE(1, found);
267 EXPECT_STREQ("1.2.3.5", ToString(result));
268 if (result) freeaddrinfo(result);
269}