OSDN Git Service

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