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