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