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