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