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