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
29 #define LOG_TAG "DnsProxyListener"
30 #define DBG 0
31
32 #include <cutils/log.h>
33 #include <sysutils/SocketClient.h>
34
35 #include "DnsProxyListener.h"
36 #include "ResponseCode.h"
37
DnsProxyListener()38 DnsProxyListener::DnsProxyListener() :
39 FrameworkListener("dnsproxyd") {
40 registerCmd(new GetAddrInfoCmd());
41 registerCmd(new GetHostByAddrCmd());
42 }
43
~GetAddrInfoHandler()44 DnsProxyListener::GetAddrInfoHandler::~GetAddrInfoHandler() {
45 free(mHost);
46 free(mService);
47 free(mHints);
48 }
49
start()50 void DnsProxyListener::GetAddrInfoHandler::start() {
51 pthread_t thread;
52 pthread_create(&thread, NULL,
53 DnsProxyListener::GetAddrInfoHandler::threadStart, this);
54 }
55
threadStart(void * obj)56 void* DnsProxyListener::GetAddrInfoHandler::threadStart(void* obj) {
57 GetAddrInfoHandler* handler = reinterpret_cast<GetAddrInfoHandler*>(obj);
58 handler->run();
59 delete handler;
60 pthread_exit(NULL);
61 return NULL;
62 }
63
64 // Sends 4 bytes of big-endian length, followed by the data.
65 // Returns true on success.
sendLenAndData(SocketClient * c,const int len,const void * data)66 static bool sendLenAndData(SocketClient *c, const int len, const void* data) {
67 uint32_t len_be = htonl(len);
68 return c->sendData(&len_be, 4) == 0 &&
69 (len == 0 || c->sendData(data, len) == 0);
70 }
71
run()72 void DnsProxyListener::GetAddrInfoHandler::run() {
73 if (DBG) {
74 ALOGD("GetAddrInfoHandler, now for %s / %s", mHost, mService);
75 }
76
77 struct addrinfo* result = NULL;
78 uint32_t rv = getaddrinfo(mHost, mService, mHints, &result);
79 if (rv) {
80 // getaddrinfo failed
81 mClient->sendBinaryMsg(ResponseCode::DnsProxyOperationFailed, &rv, sizeof(rv));
82 } else {
83 bool success = !mClient->sendCode(ResponseCode::DnsProxyQueryResult);
84 struct addrinfo* ai = result;
85 while (ai && success) {
86 success = sendLenAndData(mClient, sizeof(struct addrinfo), ai)
87 && sendLenAndData(mClient, ai->ai_addrlen, ai->ai_addr)
88 && sendLenAndData(mClient,
89 ai->ai_canonname ? strlen(ai->ai_canonname) + 1 : 0,
90 ai->ai_canonname);
91 ai = ai->ai_next;
92 }
93 success = success && sendLenAndData(mClient, 0, "");
94 if (!success) {
95 ALOGW("Error writing DNS result to client");
96 }
97 }
98 if (result) {
99 freeaddrinfo(result);
100 }
101 mClient->decRef();
102 }
103
GetAddrInfoCmd()104 DnsProxyListener::GetAddrInfoCmd::GetAddrInfoCmd() :
105 NetdCommand("getaddrinfo") {
106 }
107
runCommand(SocketClient * cli,int argc,char ** argv)108 int DnsProxyListener::GetAddrInfoCmd::runCommand(SocketClient *cli,
109 int argc, char **argv) {
110 if (DBG) {
111 for (int i = 0; i < argc; i++) {
112 ALOGD("argv[%i]=%s", i, argv[i]);
113 }
114 }
115 if (argc != 7) {
116 char* msg = NULL;
117 asprintf( &msg, "Invalid number of arguments to getaddrinfo: %i", argc);
118 ALOGW("%s", msg);
119 cli->sendMsg(ResponseCode::CommandParameterError, msg, false);
120 free(msg);
121 return -1;
122 }
123
124 char* name = argv[1];
125 if (strcmp("^", name) == 0) {
126 name = NULL;
127 } else {
128 name = strdup(name);
129 }
130
131 char* service = argv[2];
132 if (strcmp("^", service) == 0) {
133 service = NULL;
134 } else {
135 service = strdup(service);
136 }
137
138 struct addrinfo* hints = NULL;
139 int ai_flags = atoi(argv[3]);
140 int ai_family = atoi(argv[4]);
141 int ai_socktype = atoi(argv[5]);
142 int ai_protocol = atoi(argv[6]);
143 if (ai_flags != -1 || ai_family != -1 ||
144 ai_socktype != -1 || ai_protocol != -1) {
145 hints = (struct addrinfo*) calloc(1, sizeof(struct addrinfo));
146 hints->ai_flags = ai_flags;
147 hints->ai_family = ai_family;
148 hints->ai_socktype = ai_socktype;
149 hints->ai_protocol = ai_protocol;
150 }
151
152 if (DBG) {
153 ALOGD("GetAddrInfoHandler for %s / %s",
154 name ? name : "[nullhost]",
155 service ? service : "[nullservice]");
156 }
157
158 cli->incRef();
159 DnsProxyListener::GetAddrInfoHandler* handler =
160 new DnsProxyListener::GetAddrInfoHandler(cli, name, service, hints);
161 handler->start();
162
163 return 0;
164 }
165
166 /*******************************************************
167 * GetHostByAddr *
168 *******************************************************/
GetHostByAddrCmd()169 DnsProxyListener::GetHostByAddrCmd::GetHostByAddrCmd() :
170 NetdCommand("gethostbyaddr") {
171 }
172
runCommand(SocketClient * cli,int argc,char ** argv)173 int DnsProxyListener::GetHostByAddrCmd::runCommand(SocketClient *cli,
174 int argc, char **argv) {
175 if (DBG) {
176 for (int i = 0; i < argc; i++) {
177 ALOGD("argv[%i]=%s", i, argv[i]);
178 }
179 }
180
181 if (argc != 4) {
182 char* msg = NULL;
183 asprintf(&msg, "Invalid number of arguments to gethostbyaddr: %i", argc);
184 ALOGW("%s", msg);
185 cli->sendMsg(ResponseCode::CommandParameterError, msg, false);
186 free(msg);
187 return -1;
188 }
189
190 char* addrStr = argv[1];
191 int addrLen = atoi(argv[2]);
192 int addrFamily = atoi(argv[3]);
193
194 void* addr = malloc(sizeof(struct in6_addr));
195 errno = 0;
196 int result = inet_pton(addrFamily, addrStr, addr);
197 if (result <= 0) {
198 char* msg = NULL;
199 asprintf(&msg, "inet_pton(\"%s\") failed %s", addrStr, strerror(errno));
200 ALOGW("%s", msg);
201 cli->sendMsg(ResponseCode::OperationFailed, msg, false);
202 free(addr);
203 free(msg);
204 return -1;
205 }
206
207 cli->incRef();
208 DnsProxyListener::GetHostByAddrHandler* handler =
209 new DnsProxyListener::GetHostByAddrHandler(cli, addr, addrLen, addrFamily);
210 handler->start();
211
212 return 0;
213 }
214
~GetHostByAddrHandler()215 DnsProxyListener::GetHostByAddrHandler::~GetHostByAddrHandler() {
216 free(mAddress);
217 }
218
start()219 void DnsProxyListener::GetHostByAddrHandler::start() {
220 pthread_t thread;
221 pthread_create(&thread, NULL,
222 DnsProxyListener::GetHostByAddrHandler::threadStart, this);
223 }
224
threadStart(void * obj)225 void* DnsProxyListener::GetHostByAddrHandler::threadStart(void* obj) {
226 GetHostByAddrHandler* handler = reinterpret_cast<GetHostByAddrHandler*>(obj);
227 handler->run();
228 delete handler;
229 pthread_exit(NULL);
230 return NULL;
231 }
232
run()233 void DnsProxyListener::GetHostByAddrHandler::run() {
234 if (DBG) {
235 ALOGD("DnsProxyListener::GetHostByAddrHandler::run\n");
236 }
237
238 struct hostent* hp;
239
240 // NOTE gethostbyaddr should take a void* but bionic thinks it should be char*
241 hp = gethostbyaddr((char*)mAddress, mAddressLen, mAddressFamily);
242
243 if (DBG) {
244 ALOGD("GetHostByAddrHandler::run gethostbyaddr errno: %s hp->h_name = %s, name_len = %d\n",
245 hp ? "success" : strerror(errno),
246 (hp && hp->h_name) ? hp->h_name: "null",
247 (hp && hp->h_name) ? strlen(hp->h_name)+ 1 : 0);
248 }
249
250 bool failed = true;
251 if (hp) {
252 failed = mClient->sendBinaryMsg(ResponseCode::DnsProxyQueryResult,
253 hp->h_name ? hp->h_name : "",
254 hp->h_name ? strlen(hp->h_name)+ 1 : 0);
255 } else {
256 uint32_t error = h_errno;
257 failed = mClient->sendBinaryMsg(ResponseCode::DnsProxyOperationFailed,
258 &error, sizeof(error));
259 }
260
261 if (failed) {
262 ALOGW("GetHostByAddrHandler: Error writing DNS result to client\n");
263 }
264 mClient->decRef();
265 }
266