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