1 /*
2 * Copyright (C) 2010 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 #include <arpa/inet.h>
18 #include <dirent.h>
19 #include <errno.h>
20 #include <linux/if.h>
21 #include <netdb.h>
22 #include <netinet/in.h>
23 #include <stdlib.h>
24 #include <sys/socket.h>
25 #include <sys/types.h>
26 #include <string.h>
27 #include <pthread.h>
28 #include <resolv_iface.h>
29 #include <net/if.h>
30
31 #define LOG_TAG "DnsProxyListener"
32 #define DBG 0
33 #define VDBG 0
34
35 #include <cutils/log.h>
36 #include <sysutils/SocketClient.h>
37
38 #include "DnsProxyListener.h"
39 #include "ResponseCode.h"
40
DnsProxyListener()41 DnsProxyListener::DnsProxyListener() :
42 FrameworkListener("dnsproxyd") {
43 registerCmd(new GetAddrInfoCmd());
44 registerCmd(new GetHostByAddrCmd());
45 registerCmd(new GetHostByNameCmd());
46 }
47
GetAddrInfoHandler(SocketClient * c,char * host,char * service,struct addrinfo * hints,char * iface,pid_t pid)48 DnsProxyListener::GetAddrInfoHandler::GetAddrInfoHandler(SocketClient *c,
49 char* host,
50 char* service,
51 struct addrinfo* hints,
52 char* iface,
53 pid_t pid)
54 : mClient(c),
55 mHost(host),
56 mService(service),
57 mHints(hints),
58 mIface(iface),
59 mPid(pid) {
60 }
61
~GetAddrInfoHandler()62 DnsProxyListener::GetAddrInfoHandler::~GetAddrInfoHandler() {
63 free(mHost);
64 free(mService);
65 free(mHints);
66 free(mIface);
67 }
68
start()69 void DnsProxyListener::GetAddrInfoHandler::start() {
70 pthread_t thread;
71 pthread_create(&thread, NULL,
72 DnsProxyListener::GetAddrInfoHandler::threadStart, this);
73 pthread_detach(thread);
74 }
75
threadStart(void * obj)76 void* DnsProxyListener::GetAddrInfoHandler::threadStart(void* obj) {
77 GetAddrInfoHandler* handler = reinterpret_cast<GetAddrInfoHandler*>(obj);
78 handler->run();
79 delete handler;
80 pthread_exit(NULL);
81 return NULL;
82 }
83
84 // Sends 4 bytes of big-endian length, followed by the data.
85 // Returns true on success.
sendLenAndData(SocketClient * c,const int len,const void * data)86 static bool sendLenAndData(SocketClient *c, const int len, const void* data) {
87 uint32_t len_be = htonl(len);
88 return c->sendData(&len_be, 4) == 0 &&
89 (len == 0 || c->sendData(data, len) == 0);
90 }
91
92 // Returns true on success
sendhostent(SocketClient * c,struct hostent * hp)93 static bool sendhostent(SocketClient *c, struct hostent *hp) {
94 bool success = true;
95 int i;
96 if (hp->h_name != NULL) {
97 success &= sendLenAndData(c, strlen(hp->h_name)+1, hp->h_name);
98 } else {
99 success &= sendLenAndData(c, 0, "") == 0;
100 }
101
102 for (i=0; hp->h_aliases[i] != NULL; i++) {
103 success &= sendLenAndData(c, strlen(hp->h_aliases[i])+1, hp->h_aliases[i]);
104 }
105 success &= sendLenAndData(c, 0, ""); // null to indicate we're done
106
107 uint32_t buf = htonl(hp->h_addrtype);
108 success &= c->sendData(&buf, sizeof(buf)) == 0;
109
110 buf = htonl(hp->h_length);
111 success &= c->sendData(&buf, sizeof(buf)) == 0;
112
113 for (i=0; hp->h_addr_list[i] != NULL; i++) {
114 success &= sendLenAndData(c, 16, hp->h_addr_list[i]);
115 }
116 success &= sendLenAndData(c, 0, ""); // null to indicate we're done
117 return success;
118 }
119
run()120 void DnsProxyListener::GetAddrInfoHandler::run() {
121 if (DBG) {
122 ALOGD("GetAddrInfoHandler, now for %s / %s / %s", mHost, mService, mIface);
123 }
124
125 char tmp[IF_NAMESIZE + 1];
126 if (mIface == NULL) {
127 _resolv_get_pids_associated_interface(mPid, tmp, sizeof(tmp));
128 }
129
130 struct addrinfo* result = NULL;
131 uint32_t rv = android_getaddrinfoforiface(mHost, mService, mHints, mIface ? mIface : tmp,
132 &result);
133 if (rv) {
134 // getaddrinfo failed
135 mClient->sendBinaryMsg(ResponseCode::DnsProxyOperationFailed, &rv, sizeof(rv));
136 } else {
137 bool success = !mClient->sendCode(ResponseCode::DnsProxyQueryResult);
138 struct addrinfo* ai = result;
139 while (ai && success) {
140 success = sendLenAndData(mClient, sizeof(struct addrinfo), ai)
141 && sendLenAndData(mClient, ai->ai_addrlen, ai->ai_addr)
142 && sendLenAndData(mClient,
143 ai->ai_canonname ? strlen(ai->ai_canonname) + 1 : 0,
144 ai->ai_canonname);
145 ai = ai->ai_next;
146 }
147 success = success && sendLenAndData(mClient, 0, "");
148 if (!success) {
149 ALOGW("Error writing DNS result to client");
150 }
151 }
152 if (result) {
153 freeaddrinfo(result);
154 }
155 mClient->decRef();
156 }
157
GetAddrInfoCmd()158 DnsProxyListener::GetAddrInfoCmd::GetAddrInfoCmd() :
159 NetdCommand("getaddrinfo") {
160 }
161
runCommand(SocketClient * cli,int argc,char ** argv)162 int DnsProxyListener::GetAddrInfoCmd::runCommand(SocketClient *cli,
163 int argc, char **argv) {
164 if (DBG) {
165 for (int i = 0; i < argc; i++) {
166 ALOGD("argv[%i]=%s", i, argv[i]);
167 }
168 }
169 if (argc != 8) {
170 char* msg = NULL;
171 asprintf( &msg, "Invalid number of arguments to getaddrinfo: %i", argc);
172 ALOGW("%s", msg);
173 cli->sendMsg(ResponseCode::CommandParameterError, msg, false);
174 free(msg);
175 return -1;
176 }
177
178 char* name = argv[1];
179 if (strcmp("^", name) == 0) {
180 name = NULL;
181 } else {
182 name = strdup(name);
183 }
184
185 char* service = argv[2];
186 if (strcmp("^", service) == 0) {
187 service = NULL;
188 } else {
189 service = strdup(service);
190 }
191
192 char* iface = argv[7];
193 if (strcmp(iface, "^") == 0) {
194 iface = NULL;
195 } else {
196 iface = strdup(iface);
197 }
198
199 struct addrinfo* hints = NULL;
200 int ai_flags = atoi(argv[3]);
201 int ai_family = atoi(argv[4]);
202 int ai_socktype = atoi(argv[5]);
203 int ai_protocol = atoi(argv[6]);
204 pid_t pid = cli->getPid();
205
206 if (ai_flags != -1 || ai_family != -1 ||
207 ai_socktype != -1 || ai_protocol != -1) {
208 hints = (struct addrinfo*) calloc(1, sizeof(struct addrinfo));
209 hints->ai_flags = ai_flags;
210 hints->ai_family = ai_family;
211 hints->ai_socktype = ai_socktype;
212 hints->ai_protocol = ai_protocol;
213 }
214
215 if (DBG) {
216 ALOGD("GetAddrInfoHandler for %s / %s / %s / %d",
217 name ? name : "[nullhost]",
218 service ? service : "[nullservice]",
219 iface ? iface : "[nulliface]",
220 pid);
221 }
222
223 cli->incRef();
224 DnsProxyListener::GetAddrInfoHandler* handler =
225 new DnsProxyListener::GetAddrInfoHandler(cli, name, service, hints, iface, pid);
226 handler->start();
227
228 return 0;
229 }
230
231 /*******************************************************
232 * GetHostByName *
233 *******************************************************/
GetHostByNameCmd()234 DnsProxyListener::GetHostByNameCmd::GetHostByNameCmd() :
235 NetdCommand("gethostbyname") {
236 }
237
runCommand(SocketClient * cli,int argc,char ** argv)238 int DnsProxyListener::GetHostByNameCmd::runCommand(SocketClient *cli,
239 int argc, char **argv) {
240 if (DBG) {
241 for (int i = 0; i < argc; i++) {
242 ALOGD("argv[%i]=%s", i, argv[i]);
243 }
244 }
245 if (argc != 4) {
246 char* msg = NULL;
247 asprintf(&msg, "Invalid number of arguments to gethostbyname: %i", argc);
248 ALOGW("%s", msg);
249 cli->sendMsg(ResponseCode::CommandParameterError, msg, false);
250 free(msg);
251 return -1;
252 }
253
254 pid_t pid = cli->getPid();
255 char* iface = argv[1];
256 char* name = argv[2];
257 int af = atoi(argv[3]);
258
259 if (strcmp(iface, "^") == 0) {
260 iface = NULL;
261 } else {
262 iface = strdup(iface);
263 }
264
265 if (strcmp(name, "^") == 0) {
266 name = NULL;
267 } else {
268 name = strdup(name);
269 }
270
271 cli->incRef();
272 DnsProxyListener::GetHostByNameHandler* handler =
273 new DnsProxyListener::GetHostByNameHandler(cli, pid, iface, name, af);
274 handler->start();
275
276 return 0;
277 }
278
GetHostByNameHandler(SocketClient * c,pid_t pid,char * iface,char * name,int af)279 DnsProxyListener::GetHostByNameHandler::GetHostByNameHandler(SocketClient* c,
280 pid_t pid,
281 char* iface,
282 char* name,
283 int af)
284 : mClient(c),
285 mPid(pid),
286 mIface(iface),
287 mName(name),
288 mAf(af) {
289 }
290
~GetHostByNameHandler()291 DnsProxyListener::GetHostByNameHandler::~GetHostByNameHandler() {
292 free(mIface);
293 free(mName);
294 }
295
start()296 void DnsProxyListener::GetHostByNameHandler::start() {
297 pthread_t thread;
298 pthread_create(&thread, NULL,
299 DnsProxyListener::GetHostByNameHandler::threadStart, this);
300 pthread_detach(thread);
301 }
302
threadStart(void * obj)303 void* DnsProxyListener::GetHostByNameHandler::threadStart(void* obj) {
304 GetHostByNameHandler* handler = reinterpret_cast<GetHostByNameHandler*>(obj);
305 handler->run();
306 delete handler;
307 pthread_exit(NULL);
308 return NULL;
309 }
310
run()311 void DnsProxyListener::GetHostByNameHandler::run() {
312 if (DBG) {
313 ALOGD("DnsProxyListener::GetHostByNameHandler::run\n");
314 }
315
316 char iface[IF_NAMESIZE + 1];
317 if (mIface == NULL) {
318 _resolv_get_pids_associated_interface(mPid, iface, sizeof(iface));
319 }
320
321 struct hostent* hp;
322
323 hp = android_gethostbynameforiface(mName, mAf, mIface ? mIface : iface);
324
325 if (DBG) {
326 ALOGD("GetHostByNameHandler::run gethostbyname errno: %s hp->h_name = %s, name_len = %d\n",
327 hp ? "success" : strerror(errno),
328 (hp && hp->h_name) ? hp->h_name: "null",
329 (hp && hp->h_name) ? strlen(hp->h_name)+ 1 : 0);
330 }
331
332 bool success = true;
333 if (hp) {
334 success = mClient->sendCode(ResponseCode::DnsProxyQueryResult) == 0;
335 success &= sendhostent(mClient, hp);
336 } else {
337 success = mClient->sendBinaryMsg(ResponseCode::DnsProxyOperationFailed, NULL, 0) == 0;
338 }
339
340 if (!success) {
341 ALOGW("GetHostByNameHandler: Error writing DNS result to client\n");
342 }
343 mClient->decRef();
344 }
345
346
347 /*******************************************************
348 * GetHostByAddr *
349 *******************************************************/
GetHostByAddrCmd()350 DnsProxyListener::GetHostByAddrCmd::GetHostByAddrCmd() :
351 NetdCommand("gethostbyaddr") {
352 }
353
runCommand(SocketClient * cli,int argc,char ** argv)354 int DnsProxyListener::GetHostByAddrCmd::runCommand(SocketClient *cli,
355 int argc, char **argv) {
356 if (DBG) {
357 for (int i = 0; i < argc; i++) {
358 ALOGD("argv[%i]=%s", i, argv[i]);
359 }
360 }
361 if (argc != 5) {
362 char* msg = NULL;
363 asprintf(&msg, "Invalid number of arguments to gethostbyaddr: %i", argc);
364 ALOGW("%s", msg);
365 cli->sendMsg(ResponseCode::CommandParameterError, msg, false);
366 free(msg);
367 return -1;
368 }
369
370 char* addrStr = argv[1];
371 int addrLen = atoi(argv[2]);
372 int addrFamily = atoi(argv[3]);
373 pid_t pid = cli->getPid();
374 char* iface = argv[4];
375
376 if (strcmp(iface, "^") == 0) {
377 iface = NULL;
378 } else {
379 iface = strdup(iface);
380 }
381
382 void* addr = malloc(sizeof(struct in6_addr));
383 errno = 0;
384 int result = inet_pton(addrFamily, addrStr, addr);
385 if (result <= 0) {
386 char* msg = NULL;
387 asprintf(&msg, "inet_pton(\"%s\") failed %s", addrStr, strerror(errno));
388 ALOGW("%s", msg);
389 cli->sendMsg(ResponseCode::OperationFailed, msg, false);
390 free(addr);
391 free(msg);
392 return -1;
393 }
394
395 cli->incRef();
396 DnsProxyListener::GetHostByAddrHandler* handler =
397 new DnsProxyListener::GetHostByAddrHandler(cli, addr, addrLen, addrFamily, iface ,pid);
398 handler->start();
399
400 return 0;
401 }
402
GetHostByAddrHandler(SocketClient * c,void * address,int addressLen,int addressFamily,char * iface,pid_t pid)403 DnsProxyListener::GetHostByAddrHandler::GetHostByAddrHandler(SocketClient* c,
404 void* address,
405 int addressLen,
406 int addressFamily,
407 char* iface,
408 pid_t pid)
409 : mClient(c),
410 mAddress(address),
411 mAddressLen(addressLen),
412 mAddressFamily(addressFamily),
413 mIface(iface),
414 mPid(pid) {
415 }
416
~GetHostByAddrHandler()417 DnsProxyListener::GetHostByAddrHandler::~GetHostByAddrHandler() {
418 free(mAddress);
419 free(mIface);
420 }
421
start()422 void DnsProxyListener::GetHostByAddrHandler::start() {
423 pthread_t thread;
424 pthread_create(&thread, NULL,
425 DnsProxyListener::GetHostByAddrHandler::threadStart, this);
426 pthread_detach(thread);
427 }
428
threadStart(void * obj)429 void* DnsProxyListener::GetHostByAddrHandler::threadStart(void* obj) {
430 GetHostByAddrHandler* handler = reinterpret_cast<GetHostByAddrHandler*>(obj);
431 handler->run();
432 delete handler;
433 pthread_exit(NULL);
434 return NULL;
435 }
436
run()437 void DnsProxyListener::GetHostByAddrHandler::run() {
438 if (DBG) {
439 ALOGD("DnsProxyListener::GetHostByAddrHandler::run\n");
440 }
441
442 char tmp[IF_NAMESIZE + 1];
443 if (mIface == NULL) {
444 _resolv_get_pids_associated_interface(mPid, tmp, sizeof(tmp));
445 }
446
447 struct hostent* hp;
448
449 // NOTE gethostbyaddr should take a void* but bionic thinks it should be char*
450 hp = android_gethostbyaddrforiface((char*)mAddress, mAddressLen, mAddressFamily,
451 mIface ? mIface : tmp);
452
453 if (DBG) {
454 ALOGD("GetHostByAddrHandler::run gethostbyaddr errno: %s hp->h_name = %s, name_len = %d\n",
455 hp ? "success" : strerror(errno),
456 (hp && hp->h_name) ? hp->h_name: "null",
457 (hp && hp->h_name) ? strlen(hp->h_name)+ 1 : 0);
458 }
459
460 bool success = true;
461 if (hp) {
462 success = mClient->sendCode(ResponseCode::DnsProxyQueryResult) == 0;
463 success &= sendhostent(mClient, hp);
464 } else {
465 success = mClient->sendBinaryMsg(ResponseCode::DnsProxyOperationFailed, NULL, 0) == 0;
466 }
467
468 if (!success) {
469 ALOGW("GetHostByAddrHandler: Error writing DNS result to client\n");
470 }
471 mClient->decRef();
472 }
473