• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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