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