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 <math.h> 22 #include <netdb.h> 23 #include <netinet/in.h> 24 #include <stdlib.h> 25 #include <sys/socket.h> 26 #include <sys/types.h> 27 #include <string.h> 28 #include <pthread.h> 29 #include <resolv_netid.h> 30 #include <net/if.h> 31 32 #define LOG_TAG "DnsProxyListener" 33 #define DBG 0 34 #define VDBG 0 35 36 #include <chrono> 37 #include <vector> 38 39 #include <cutils/log.h> 40 #include <utils/String16.h> 41 #include <sysutils/SocketClient.h> 42 43 #include "Controllers.h" 44 #include "Fwmark.h" 45 #include "DnsProxyListener.h" 46 #include "dns/DnsTlsTransport.h" 47 #include "NetdConstants.h" 48 #include "NetworkController.h" 49 #include "ResponseCode.h" 50 #include "Stopwatch.h" 51 #include "thread_util.h" 52 #include "android/net/metrics/INetdEventListener.h" 53 54 using android::String16; 55 using android::net::metrics::INetdEventListener; 56 57 namespace android { 58 namespace net { 59 60 namespace { 61 62 template<typename T> 63 void tryThreadOrError(SocketClient* cli, T* handler) { 64 cli->incRef(); 65 66 const int rval = threadLaunch(handler); 67 if (rval == 0) { 68 // SocketClient decRef() happens in the handler's run() method. 69 return; 70 } 71 72 char* msg = NULL; 73 asprintf(&msg, "%s (%d)", strerror(-rval), -rval); 74 cli->sendMsg(ResponseCode::OperationFailed, msg, false); 75 free(msg); 76 77 delete handler; 78 cli->decRef(); 79 } 80 81 thread_local android_net_context thread_netcontext = {}; 82 83 res_sendhookact qhook(sockaddr* const * nsap, const u_char** buf, int* buflen, 84 u_char* ans, int anssiz, int* resplen) { 85 if (!thread_netcontext.qhook) { 86 ALOGE("qhook abort: thread qhook is null"); 87 return res_goahead; 88 } 89 if (!net::gCtls) { 90 ALOGE("qhook abort: gCtls is null"); 91 return res_goahead; 92 } 93 // Safely read the data from nsap without violating strict-aliasing. 94 sockaddr_storage insecureResolver; 95 if ((*nsap)->sa_family == AF_INET) { 96 std::memcpy(&insecureResolver, *nsap, sizeof(sockaddr_in)); 97 } else if ((*nsap)->sa_family == AF_INET6) { 98 std::memcpy(&insecureResolver, *nsap, sizeof(sockaddr_in6)); 99 } else { 100 ALOGE("qhook abort: unknown address family"); 101 return res_goahead; 102 } 103 sockaddr_storage secureResolver; 104 std::set<std::vector<uint8_t>> fingerprints; 105 if (net::gCtls->resolverCtrl.shouldUseTls(thread_netcontext.dns_netid, 106 insecureResolver, &secureResolver, &fingerprints)) { 107 if (DBG) { 108 ALOGD("qhook using TLS"); 109 } 110 DnsTlsTransport xport(thread_netcontext.dns_mark, IPPROTO_TCP, 111 secureResolver, fingerprints); 112 auto response = xport.doQuery(*buf, *buflen, ans, anssiz, resplen); 113 if (response == DnsTlsTransport::Response::success) { 114 if (DBG) { 115 ALOGD("qhook success"); 116 } 117 return res_done; 118 } 119 if (DBG) { 120 ALOGW("qhook abort: doQuery failed: %d", (int)response); 121 } 122 // If there was a network error, try a different name server. 123 // Otherwise, fail hard. 124 if (response == DnsTlsTransport::Response::network_error) { 125 return res_nextns; 126 } 127 return res_error; 128 } 129 130 if (DBG) { 131 ALOGD("qhook not using TLS"); 132 } 133 return res_goahead; 134 } 135 136 } // namespace 137 138 DnsProxyListener::DnsProxyListener(const NetworkController* netCtrl, EventReporter* eventReporter) : 139 FrameworkListener(SOCKET_NAME), mNetCtrl(netCtrl), mEventReporter(eventReporter) { 140 registerCmd(new GetAddrInfoCmd(this)); 141 registerCmd(new GetHostByAddrCmd(this)); 142 registerCmd(new GetHostByNameCmd(this)); 143 } 144 145 DnsProxyListener::GetAddrInfoHandler::GetAddrInfoHandler( 146 SocketClient *c, char* host, char* service, struct addrinfo* hints, 147 const android_net_context& netcontext, const int reportingLevel, 148 const android::sp<android::net::metrics::INetdEventListener>& netdEventListener) 149 : mClient(c), 150 mHost(host), 151 mService(service), 152 mHints(hints), 153 mNetContext(netcontext), 154 mReportingLevel(reportingLevel), 155 mNetdEventListener(netdEventListener) { 156 } 157 158 DnsProxyListener::GetAddrInfoHandler::~GetAddrInfoHandler() { 159 free(mHost); 160 free(mService); 161 free(mHints); 162 } 163 164 static bool sendBE32(SocketClient* c, uint32_t data) { 165 uint32_t be_data = htonl(data); 166 return c->sendData(&be_data, sizeof(be_data)) == 0; 167 } 168 169 // Sends 4 bytes of big-endian length, followed by the data. 170 // Returns true on success. 171 static bool sendLenAndData(SocketClient* c, const int len, const void* data) { 172 return sendBE32(c, len) && (len == 0 || c->sendData(data, len) == 0); 173 } 174 175 // Returns true on success 176 static bool sendhostent(SocketClient *c, struct hostent *hp) { 177 bool success = true; 178 int i; 179 if (hp->h_name != NULL) { 180 success &= sendLenAndData(c, strlen(hp->h_name)+1, hp->h_name); 181 } else { 182 success &= sendLenAndData(c, 0, "") == 0; 183 } 184 185 for (i=0; hp->h_aliases[i] != NULL; i++) { 186 success &= sendLenAndData(c, strlen(hp->h_aliases[i])+1, hp->h_aliases[i]); 187 } 188 success &= sendLenAndData(c, 0, ""); // null to indicate we're done 189 190 uint32_t buf = htonl(hp->h_addrtype); 191 success &= c->sendData(&buf, sizeof(buf)) == 0; 192 193 buf = htonl(hp->h_length); 194 success &= c->sendData(&buf, sizeof(buf)) == 0; 195 196 for (i=0; hp->h_addr_list[i] != NULL; i++) { 197 success &= sendLenAndData(c, 16, hp->h_addr_list[i]); 198 } 199 success &= sendLenAndData(c, 0, ""); // null to indicate we're done 200 return success; 201 } 202 203 static bool sendaddrinfo(SocketClient* c, struct addrinfo* ai) { 204 // struct addrinfo { 205 // int ai_flags; /* AI_PASSIVE, AI_CANONNAME, AI_NUMERICHOST */ 206 // int ai_family; /* PF_xxx */ 207 // int ai_socktype; /* SOCK_xxx */ 208 // int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */ 209 // socklen_t ai_addrlen; /* length of ai_addr */ 210 // char *ai_canonname; /* canonical name for hostname */ 211 // struct sockaddr *ai_addr; /* binary address */ 212 // struct addrinfo *ai_next; /* next structure in linked list */ 213 // }; 214 215 // Write the struct piece by piece because we might be a 64-bit netd 216 // talking to a 32-bit process. 217 bool success = 218 sendBE32(c, ai->ai_flags) && 219 sendBE32(c, ai->ai_family) && 220 sendBE32(c, ai->ai_socktype) && 221 sendBE32(c, ai->ai_protocol); 222 if (!success) { 223 return false; 224 } 225 226 // ai_addrlen and ai_addr. 227 if (!sendLenAndData(c, ai->ai_addrlen, ai->ai_addr)) { 228 return false; 229 } 230 231 // strlen(ai_canonname) and ai_canonname. 232 if (!sendLenAndData(c, ai->ai_canonname ? strlen(ai->ai_canonname) + 1 : 0, ai->ai_canonname)) { 233 return false; 234 } 235 236 return true; 237 } 238 239 void DnsProxyListener::GetAddrInfoHandler::run() { 240 if (DBG) { 241 ALOGD("GetAddrInfoHandler, now for %s / %s / {%u,%u,%u,%u,%u}", mHost, mService, 242 mNetContext.app_netid, mNetContext.app_mark, 243 mNetContext.dns_netid, mNetContext.dns_mark, 244 mNetContext.uid); 245 } 246 247 struct addrinfo* result = NULL; 248 Stopwatch s; 249 thread_netcontext = mNetContext; 250 uint32_t rv = android_getaddrinfofornetcontext(mHost, mService, mHints, &mNetContext, &result); 251 const int latencyMs = lround(s.timeTaken()); 252 253 if (rv) { 254 // getaddrinfo failed 255 mClient->sendBinaryMsg(ResponseCode::DnsProxyOperationFailed, &rv, sizeof(rv)); 256 } else { 257 bool success = !mClient->sendCode(ResponseCode::DnsProxyQueryResult); 258 struct addrinfo* ai = result; 259 while (ai && success) { 260 success = sendBE32(mClient, 1) && sendaddrinfo(mClient, ai); 261 ai = ai->ai_next; 262 } 263 success = success && sendBE32(mClient, 0); 264 if (!success) { 265 ALOGW("Error writing DNS result to client"); 266 } 267 } 268 std::vector<String16> ip_addrs; 269 int total_ip_addr_count = 0; 270 if (result) { 271 if (mNetdEventListener != nullptr 272 && mReportingLevel == INetdEventListener::REPORTING_LEVEL_FULL) { 273 for (addrinfo* ai = result; ai; ai = ai->ai_next) { 274 sockaddr* ai_addr = ai->ai_addr; 275 if (ai_addr) { 276 addIpAddrWithinLimit(ip_addrs, ai_addr, ai->ai_addrlen); 277 total_ip_addr_count++; 278 } 279 } 280 } 281 freeaddrinfo(result); 282 } 283 mClient->decRef(); 284 if (mNetdEventListener != nullptr) { 285 switch (mReportingLevel) { 286 case INetdEventListener::REPORTING_LEVEL_NONE: 287 // Skip reporting. 288 break; 289 case INetdEventListener::REPORTING_LEVEL_METRICS: 290 // Metrics reporting is on. Send metrics. 291 mNetdEventListener->onDnsEvent(mNetContext.dns_netid, 292 INetdEventListener::EVENT_GETADDRINFO, (int32_t) rv, 293 latencyMs, String16(""), {}, -1, -1); 294 break; 295 case INetdEventListener::REPORTING_LEVEL_FULL: 296 // Full event info reporting is on. Send full info. 297 mNetdEventListener->onDnsEvent(mNetContext.dns_netid, 298 INetdEventListener::EVENT_GETADDRINFO, (int32_t) rv, 299 latencyMs, String16(mHost), ip_addrs, 300 total_ip_addr_count, mNetContext.uid); 301 break; 302 } 303 } else { 304 ALOGW("Netd event listener is not available; skipping."); 305 } 306 } 307 308 void DnsProxyListener::addIpAddrWithinLimit(std::vector<android::String16>& ip_addrs, 309 const sockaddr* addr, socklen_t addrlen) { 310 // ipAddresses array is limited to first INetdEventListener::DNS_REPORTED_IP_ADDRESSES_LIMIT 311 // addresses for A and AAAA. Total count of addresses is provided, to be able to tell whether 312 // some addresses didn't get logged. 313 if (ip_addrs.size() < INetdEventListener::DNS_REPORTED_IP_ADDRESSES_LIMIT) { 314 char ip_addr[INET6_ADDRSTRLEN]; 315 if (getnameinfo(addr, addrlen, ip_addr, sizeof(ip_addr), nullptr, 0, NI_NUMERICHOST) == 0) { 316 ip_addrs.push_back(String16(ip_addr)); 317 } 318 } 319 } 320 321 DnsProxyListener::GetAddrInfoCmd::GetAddrInfoCmd(DnsProxyListener* dnsProxyListener) : 322 NetdCommand("getaddrinfo"), 323 mDnsProxyListener(dnsProxyListener) { 324 } 325 326 int DnsProxyListener::GetAddrInfoCmd::runCommand(SocketClient *cli, 327 int argc, char **argv) { 328 if (DBG) { 329 for (int i = 0; i < argc; i++) { 330 ALOGD("argv[%i]=%s", i, argv[i]); 331 } 332 } 333 if (argc != 8) { 334 char* msg = NULL; 335 asprintf( &msg, "Invalid number of arguments to getaddrinfo: %i", argc); 336 ALOGW("%s", msg); 337 cli->sendMsg(ResponseCode::CommandParameterError, msg, false); 338 free(msg); 339 return -1; 340 } 341 342 char* name = argv[1]; 343 if (strcmp("^", name) == 0) { 344 name = NULL; 345 } else { 346 name = strdup(name); 347 } 348 349 char* service = argv[2]; 350 if (strcmp("^", service) == 0) { 351 service = NULL; 352 } else { 353 service = strdup(service); 354 } 355 356 struct addrinfo* hints = NULL; 357 int ai_flags = atoi(argv[3]); 358 int ai_family = atoi(argv[4]); 359 int ai_socktype = atoi(argv[5]); 360 int ai_protocol = atoi(argv[6]); 361 unsigned netId = strtoul(argv[7], NULL, 10); 362 uid_t uid = cli->getUid(); 363 364 android_net_context netcontext; 365 mDnsProxyListener->mNetCtrl->getNetworkContext(netId, uid, &netcontext); 366 netcontext.qhook = &qhook; 367 368 if (ai_flags != -1 || ai_family != -1 || 369 ai_socktype != -1 || ai_protocol != -1) { 370 hints = (struct addrinfo*) calloc(1, sizeof(struct addrinfo)); 371 hints->ai_flags = ai_flags; 372 hints->ai_family = ai_family; 373 hints->ai_socktype = ai_socktype; 374 hints->ai_protocol = ai_protocol; 375 } 376 377 if (DBG) { 378 ALOGD("GetAddrInfoHandler for %s / %s / {%u,%u,%u,%u,%u}", 379 name ? name : "[nullhost]", 380 service ? service : "[nullservice]", 381 netcontext.app_netid, netcontext.app_mark, 382 netcontext.dns_netid, netcontext.dns_mark, 383 netcontext.uid); 384 } 385 386 const int metricsLevel = mDnsProxyListener->mEventReporter->getMetricsReportingLevel(); 387 388 DnsProxyListener::GetAddrInfoHandler* handler = 389 new DnsProxyListener::GetAddrInfoHandler(cli, name, service, hints, netcontext, 390 metricsLevel, mDnsProxyListener->mEventReporter->getNetdEventListener()); 391 tryThreadOrError(cli, handler); 392 return 0; 393 } 394 395 /******************************************************* 396 * GetHostByName * 397 *******************************************************/ 398 DnsProxyListener::GetHostByNameCmd::GetHostByNameCmd(DnsProxyListener* dnsProxyListener) : 399 NetdCommand("gethostbyname"), 400 mDnsProxyListener(dnsProxyListener) { 401 } 402 403 int DnsProxyListener::GetHostByNameCmd::runCommand(SocketClient *cli, 404 int argc, char **argv) { 405 if (DBG) { 406 for (int i = 0; i < argc; i++) { 407 ALOGD("argv[%i]=%s", i, argv[i]); 408 } 409 } 410 if (argc != 4) { 411 char* msg = NULL; 412 asprintf(&msg, "Invalid number of arguments to gethostbyname: %i", argc); 413 ALOGW("%s", msg); 414 cli->sendMsg(ResponseCode::CommandParameterError, msg, false); 415 free(msg); 416 return -1; 417 } 418 419 uid_t uid = cli->getUid(); 420 unsigned netId = strtoul(argv[1], NULL, 10); 421 char* name = argv[2]; 422 int af = atoi(argv[3]); 423 424 if (strcmp(name, "^") == 0) { 425 name = NULL; 426 } else { 427 name = strdup(name); 428 } 429 430 android_net_context netcontext; 431 mDnsProxyListener->mNetCtrl->getNetworkContext(netId, uid, &netcontext); 432 netcontext.qhook = &qhook; 433 434 const int metricsLevel = mDnsProxyListener->mEventReporter->getMetricsReportingLevel(); 435 436 DnsProxyListener::GetHostByNameHandler* handler = 437 new DnsProxyListener::GetHostByNameHandler(cli, name, af, netcontext, metricsLevel, 438 mDnsProxyListener->mEventReporter->getNetdEventListener()); 439 tryThreadOrError(cli, handler); 440 return 0; 441 } 442 443 DnsProxyListener::GetHostByNameHandler::GetHostByNameHandler(SocketClient* c, char* name, int af, 444 const android_net_context& netcontext, const int metricsLevel, 445 const android::sp<android::net::metrics::INetdEventListener>& netdEventListener) 446 : mClient(c), 447 mName(name), 448 mAf(af), 449 mNetContext(netcontext), 450 mReportingLevel(metricsLevel), 451 mNetdEventListener(netdEventListener) { 452 } 453 454 DnsProxyListener::GetHostByNameHandler::~GetHostByNameHandler() { 455 free(mName); 456 } 457 458 void DnsProxyListener::GetHostByNameHandler::run() { 459 if (DBG) { 460 ALOGD("DnsProxyListener::GetHostByNameHandler::run\n"); 461 } 462 463 Stopwatch s; 464 thread_netcontext = mNetContext; 465 struct hostent* hp = android_gethostbynamefornetcontext(mName, mAf, &mNetContext); 466 const int latencyMs = lround(s.timeTaken()); 467 468 if (DBG) { 469 ALOGD("GetHostByNameHandler::run gethostbyname errno: %s hp->h_name = %s, name_len = %zu\n", 470 hp ? "success" : strerror(errno), 471 (hp && hp->h_name) ? hp->h_name : "null", 472 (hp && hp->h_name) ? strlen(hp->h_name) + 1 : 0); 473 } 474 475 bool success = true; 476 if (hp) { 477 success = mClient->sendCode(ResponseCode::DnsProxyQueryResult) == 0; 478 success &= sendhostent(mClient, hp); 479 } else { 480 success = mClient->sendBinaryMsg(ResponseCode::DnsProxyOperationFailed, NULL, 0) == 0; 481 } 482 483 if (!success) { 484 ALOGW("GetHostByNameHandler: Error writing DNS result to client\n"); 485 } 486 487 if (mNetdEventListener != nullptr) { 488 std::vector<String16> ip_addrs; 489 int total_ip_addr_count = 0; 490 if (mReportingLevel == INetdEventListener::REPORTING_LEVEL_FULL) { 491 if (hp != nullptr && hp->h_addrtype == AF_INET) { 492 in_addr** list = (in_addr**) hp->h_addr_list; 493 for (int i = 0; list[i] != NULL; i++) { 494 sockaddr_in sin = { .sin_family = AF_INET, .sin_addr = *list[i] }; 495 addIpAddrWithinLimit(ip_addrs, (sockaddr*) &sin, sizeof(sin)); 496 total_ip_addr_count++; 497 } 498 } else if (hp != nullptr && hp->h_addrtype == AF_INET6) { 499 in6_addr** list = (in6_addr**) hp->h_addr_list; 500 for (int i = 0; list[i] != NULL; i++) { 501 sockaddr_in6 sin6 = { .sin6_family = AF_INET6, .sin6_addr = *list[i] }; 502 addIpAddrWithinLimit(ip_addrs, (sockaddr*) &sin6, sizeof(sin6)); 503 total_ip_addr_count++; 504 } 505 } 506 } 507 switch (mReportingLevel) { 508 case INetdEventListener::REPORTING_LEVEL_NONE: 509 // Reporting is off. 510 break; 511 case INetdEventListener::REPORTING_LEVEL_METRICS: 512 // Metrics reporting is on. Send metrics. 513 mNetdEventListener->onDnsEvent(mNetContext.dns_netid, 514 INetdEventListener::EVENT_GETHOSTBYNAME, 515 h_errno, latencyMs, String16(""), {}, -1, -1); 516 break; 517 case INetdEventListener::REPORTING_LEVEL_FULL: 518 // Full event info reporting is on. Send full info. 519 mNetdEventListener->onDnsEvent(mNetContext.dns_netid, 520 INetdEventListener::EVENT_GETHOSTBYNAME, 521 h_errno, latencyMs, String16(mName), ip_addrs, 522 total_ip_addr_count, mClient->getUid()); 523 break; 524 } 525 } 526 527 mClient->decRef(); 528 } 529 530 531 /******************************************************* 532 * GetHostByAddr * 533 *******************************************************/ 534 DnsProxyListener::GetHostByAddrCmd::GetHostByAddrCmd(const DnsProxyListener* dnsProxyListener) : 535 NetdCommand("gethostbyaddr"), 536 mDnsProxyListener(dnsProxyListener) { 537 } 538 539 int DnsProxyListener::GetHostByAddrCmd::runCommand(SocketClient *cli, 540 int argc, char **argv) { 541 if (DBG) { 542 for (int i = 0; i < argc; i++) { 543 ALOGD("argv[%i]=%s", i, argv[i]); 544 } 545 } 546 if (argc != 5) { 547 char* msg = NULL; 548 asprintf(&msg, "Invalid number of arguments to gethostbyaddr: %i", argc); 549 ALOGW("%s", msg); 550 cli->sendMsg(ResponseCode::CommandParameterError, msg, false); 551 free(msg); 552 return -1; 553 } 554 555 char* addrStr = argv[1]; 556 int addrLen = atoi(argv[2]); 557 int addrFamily = atoi(argv[3]); 558 uid_t uid = cli->getUid(); 559 unsigned netId = strtoul(argv[4], NULL, 10); 560 561 void* addr = malloc(sizeof(struct in6_addr)); 562 errno = 0; 563 int result = inet_pton(addrFamily, addrStr, addr); 564 if (result <= 0) { 565 char* msg = NULL; 566 asprintf(&msg, "inet_pton(\"%s\") failed %s", addrStr, strerror(errno)); 567 ALOGW("%s", msg); 568 cli->sendMsg(ResponseCode::OperationFailed, msg, false); 569 free(addr); 570 free(msg); 571 return -1; 572 } 573 574 android_net_context netcontext; 575 mDnsProxyListener->mNetCtrl->getNetworkContext(netId, uid, &netcontext); 576 netcontext.qhook = &qhook; 577 578 DnsProxyListener::GetHostByAddrHandler* handler = 579 new DnsProxyListener::GetHostByAddrHandler(cli, addr, addrLen, addrFamily, netcontext); 580 tryThreadOrError(cli, handler); 581 return 0; 582 } 583 584 DnsProxyListener::GetHostByAddrHandler::GetHostByAddrHandler( 585 SocketClient* c, 586 void* address, 587 int addressLen, 588 int addressFamily, 589 const android_net_context& netcontext) 590 : mClient(c), 591 mAddress(address), 592 mAddressLen(addressLen), 593 mAddressFamily(addressFamily), 594 mNetContext(netcontext) { 595 } 596 597 DnsProxyListener::GetHostByAddrHandler::~GetHostByAddrHandler() { 598 free(mAddress); 599 } 600 601 void DnsProxyListener::GetHostByAddrHandler::run() { 602 if (DBG) { 603 ALOGD("DnsProxyListener::GetHostByAddrHandler::run\n"); 604 } 605 struct hostent* hp; 606 607 // NOTE gethostbyaddr should take a void* but bionic thinks it should be char* 608 thread_netcontext = mNetContext; 609 hp = android_gethostbyaddrfornetcontext( 610 (char*)mAddress, mAddressLen, mAddressFamily, &mNetContext); 611 612 if (DBG) { 613 ALOGD("GetHostByAddrHandler::run gethostbyaddr errno: %s hp->h_name = %s, name_len = %zu\n", 614 hp ? "success" : strerror(errno), 615 (hp && hp->h_name) ? hp->h_name : "null", 616 (hp && hp->h_name) ? strlen(hp->h_name) + 1 : 0); 617 } 618 619 bool success = true; 620 if (hp) { 621 success = mClient->sendCode(ResponseCode::DnsProxyQueryResult) == 0; 622 success &= sendhostent(mClient, hp); 623 } else { 624 success = mClient->sendBinaryMsg(ResponseCode::DnsProxyOperationFailed, NULL, 0) == 0; 625 } 626 627 if (!success) { 628 ALOGW("GetHostByAddrHandler: Error writing DNS result to client\n"); 629 } 630 mClient->decRef(); 631 } 632 633 } // namespace net 634 } // namespace android 635