1 /* $NetBSD: gethnamaddr.c,v 1.70 2006/03/22 00:03:51 christos Exp $ */
2
3 /*
4 * ++Copyright++ 1985, 1988, 1993
5 * -
6 * Copyright (c) 1985, 1988, 1993
7 * The Regents of the University of California. All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 * -
33 * Portions Copyright (c) 1993 by Digital Equipment Corporation.
34 *
35 * Permission to use, copy, modify, and distribute this software for any
36 * purpose with or without fee is hereby granted, provided that the above
37 * copyright notice and this permission notice appear in all copies, and that
38 * the name of Digital Equipment Corporation not be used in advertising or
39 * publicity pertaining to distribution of the document or software without
40 * specific, written prior permission.
41 *
42 * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
43 * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
44 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
45 * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
46 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
47 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
48 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
49 * SOFTWARE.
50 * -
51 * --Copyright--
52 */
53
54 #include <sys/cdefs.h>
55 #include <sys/types.h>
56
57 #include <sys/param.h>
58 #include <sys/socket.h>
59 #include <sys/un.h>
60 #include <netinet/in.h>
61 #include <arpa/inet.h>
62 #include <arpa/nameser.h>
63 #include "NetdClientDispatch.h"
64 #include "resolv_netid.h"
65 #include "resolv_private.h"
66 #include "resolv_cache.h"
67 #include <assert.h>
68 #include <ctype.h>
69 #include <errno.h>
70 #include <netdb.h>
71 #include <stdarg.h>
72 #include <stdio.h>
73 #include <strings.h>
74 #include <syslog.h>
75 #include <unistd.h>
76
77 #define ALIGNBYTES (sizeof(uintptr_t) - 1)
78 #define ALIGN(p) (((uintptr_t)(p) + ALIGNBYTES) &~ ALIGNBYTES)
79
80 #ifndef LOG_AUTH
81 # define LOG_AUTH 0
82 #endif
83
84 #define MULTI_PTRS_ARE_ALIASES 1 /* XXX - experimental */
85
86 #include "nsswitch.h"
87 #include <stdlib.h>
88 #include <string.h>
89
90 // This should be synchronized to ResponseCode.h
91 static const int DnsProxyQueryResult = 222;
92
93 static const char AskedForGot[] =
94 "gethostby*.getanswer: asked for \"%s\", got \"%s\"";
95
96 #define MAXPACKET (64*1024)
97
98 typedef union {
99 HEADER hdr;
100 u_char buf[MAXPACKET];
101 } querybuf;
102
103 typedef union {
104 int32_t al;
105 char ac;
106 } align;
107
108 #ifdef DEBUG
109 static void dprintf(const char *, res_state, ...)
110 __attribute__((__format__(__printf__, 1, 3)));
111 #endif
112 static struct hostent *getanswer(const querybuf *, int, const char *, int,
113 res_state);
114 static void map_v4v6_address(const char *, char *);
115 static void map_v4v6_hostent(struct hostent *, char **, char *);
116 static void addrsort(char **, int, res_state);
117
118 static void _sethtent(int);
119 static void _endhtent(void);
120 static struct hostent *_gethtent(void);
121 void ht_sethostent(int);
122 void ht_endhostent(void);
123 struct hostent *ht_gethostbyname(char *);
124 struct hostent *ht_gethostbyaddr(const char *, int, int);
125 void dns_service(void);
126 #undef dn_skipname
127 int dn_skipname(const u_char *, const u_char *);
128 static int _gethtbyaddr(void *, void *, va_list);
129 static int _gethtbyname(void *, void *, va_list);
130 static struct hostent *_gethtbyname2(const char *, int);
131 static int _dns_gethtbyaddr(void *, void *, va_list);
132 static int _dns_gethtbyname(void *, void *, va_list);
133
134 static struct hostent *gethostbyname_internal(const char *, int, res_state, unsigned, unsigned);
135
136 static const ns_src default_dns_files[] = {
137 { NSSRC_FILES, NS_SUCCESS },
138 { NSSRC_DNS, NS_SUCCESS },
139 { 0, 0 }
140 };
141
142
143 #ifdef DEBUG
144 static void
dprintf(const char * msg,res_state res,...)145 dprintf(const char *msg, res_state res, ...)
146 {
147 assert(msg != NULL);
148
149 if (res->options & RES_DEBUG) {
150 int save = errno;
151 va_list ap;
152
153 va_start (ap, res);
154 vprintf(msg, ap);
155 va_end (ap);
156
157 errno = save;
158 }
159 }
160 #else
161 # define dprintf(msg, res, num) ((void)0) /*nada*/
162 #endif
163
164 #define BOUNDED_INCR(x) \
165 do { \
166 cp += (x); \
167 if (cp > eom) { \
168 h_errno = NO_RECOVERY; \
169 return NULL; \
170 } \
171 } while (/*CONSTCOND*/0)
172
173 #define BOUNDS_CHECK(ptr, count) \
174 do { \
175 if ((ptr) + (count) > eom) { \
176 h_errno = NO_RECOVERY; \
177 return NULL; \
178 } \
179 } while (/*CONSTCOND*/0)
180
181 static struct hostent *
getanswer(const querybuf * answer,int anslen,const char * qname,int qtype,res_state res)182 getanswer(const querybuf *answer, int anslen, const char *qname, int qtype,
183 res_state res)
184 {
185 const HEADER *hp;
186 const u_char *cp;
187 int n;
188 const u_char *eom, *erdata;
189 char *bp, **ap, **hap, *ep;
190 int type, class, ancount, qdcount;
191 int haveanswer, had_error;
192 int toobig = 0;
193 char tbuf[MAXDNAME];
194 const char *tname;
195 int (*name_ok)(const char *);
196 res_static rs = __res_get_static();
197
198 assert(answer != NULL);
199 assert(qname != NULL);
200
201 tname = qname;
202 rs->host.h_name = NULL;
203 eom = answer->buf + anslen;
204 switch (qtype) {
205 case T_A:
206 case T_AAAA:
207 name_ok = res_hnok;
208 break;
209 case T_PTR:
210 name_ok = res_dnok;
211 break;
212 default:
213 return NULL; /* XXX should be abort(); */
214 }
215 /*
216 * find first satisfactory answer
217 */
218 hp = &answer->hdr;
219 ancount = ntohs(hp->ancount);
220 qdcount = ntohs(hp->qdcount);
221 bp = rs->hostbuf;
222 ep = rs->hostbuf + sizeof rs->hostbuf;
223 cp = answer->buf;
224 BOUNDED_INCR(HFIXEDSZ);
225 if (qdcount != 1) {
226 h_errno = NO_RECOVERY;
227 return NULL;
228 }
229 n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
230 if ((n < 0) || !(*name_ok)(bp)) {
231 h_errno = NO_RECOVERY;
232 return NULL;
233 }
234 BOUNDED_INCR(n + QFIXEDSZ);
235 if (qtype == T_A || qtype == T_AAAA) {
236 /* res_send() has already verified that the query name is the
237 * same as the one we sent; this just gets the expanded name
238 * (i.e., with the succeeding search-domain tacked on).
239 */
240 n = strlen(bp) + 1; /* for the \0 */
241 if (n >= MAXHOSTNAMELEN) {
242 h_errno = NO_RECOVERY;
243 return NULL;
244 }
245 rs->host.h_name = bp;
246 bp += n;
247 /* The qname can be abbreviated, but h_name is now absolute. */
248 qname = rs->host.h_name;
249 }
250 ap = rs->host_aliases;
251 *ap = NULL;
252 rs->host.h_aliases = rs->host_aliases;
253 hap = rs->h_addr_ptrs;
254 *hap = NULL;
255 rs->host.h_addr_list = rs->h_addr_ptrs;
256 haveanswer = 0;
257 had_error = 0;
258 while (ancount-- > 0 && cp < eom && !had_error) {
259 n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
260 if ((n < 0) || !(*name_ok)(bp)) {
261 had_error++;
262 continue;
263 }
264 cp += n; /* name */
265 BOUNDS_CHECK(cp, 3 * INT16SZ + INT32SZ);
266 type = _getshort(cp);
267 cp += INT16SZ; /* type */
268 class = _getshort(cp);
269 cp += INT16SZ + INT32SZ; /* class, TTL */
270 n = _getshort(cp);
271 cp += INT16SZ; /* len */
272 BOUNDS_CHECK(cp, n);
273 erdata = cp + n;
274 if (class != C_IN) {
275 /* XXX - debug? syslog? */
276 cp += n;
277 continue; /* XXX - had_error++ ? */
278 }
279 if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME) {
280 if (ap >= &rs->host_aliases[MAXALIASES-1])
281 continue;
282 n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
283 if ((n < 0) || !(*name_ok)(tbuf)) {
284 had_error++;
285 continue;
286 }
287 cp += n;
288 if (cp != erdata) {
289 h_errno = NO_RECOVERY;
290 return NULL;
291 }
292 /* Store alias. */
293 *ap++ = bp;
294 n = strlen(bp) + 1; /* for the \0 */
295 if (n >= MAXHOSTNAMELEN) {
296 had_error++;
297 continue;
298 }
299 bp += n;
300 /* Get canonical name. */
301 n = strlen(tbuf) + 1; /* for the \0 */
302 if (n > ep - bp || n >= MAXHOSTNAMELEN) {
303 had_error++;
304 continue;
305 }
306 strlcpy(bp, tbuf, (size_t)(ep - bp));
307 rs->host.h_name = bp;
308 bp += n;
309 continue;
310 }
311 if (qtype == T_PTR && type == T_CNAME) {
312 n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
313 if (n < 0 || !res_dnok(tbuf)) {
314 had_error++;
315 continue;
316 }
317 cp += n;
318 if (cp != erdata) {
319 h_errno = NO_RECOVERY;
320 return NULL;
321 }
322 /* Get canonical name. */
323 n = strlen(tbuf) + 1; /* for the \0 */
324 if (n > ep - bp || n >= MAXHOSTNAMELEN) {
325 had_error++;
326 continue;
327 }
328 strlcpy(bp, tbuf, (size_t)(ep - bp));
329 tname = bp;
330 bp += n;
331 continue;
332 }
333 if (type != qtype) {
334 if (type != T_KEY && type != T_SIG)
335 syslog(LOG_NOTICE|LOG_AUTH,
336 "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"",
337 qname, p_class(C_IN), p_type(qtype),
338 p_type(type));
339 cp += n;
340 continue; /* XXX - had_error++ ? */
341 }
342 switch (type) {
343 case T_PTR:
344 if (strcasecmp(tname, bp) != 0) {
345 syslog(LOG_NOTICE|LOG_AUTH,
346 AskedForGot, qname, bp);
347 cp += n;
348 continue; /* XXX - had_error++ ? */
349 }
350 n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
351 if ((n < 0) || !res_hnok(bp)) {
352 had_error++;
353 break;
354 }
355 #if MULTI_PTRS_ARE_ALIASES
356 cp += n;
357 if (cp != erdata) {
358 h_errno = NO_RECOVERY;
359 return NULL;
360 }
361 if (!haveanswer)
362 rs->host.h_name = bp;
363 else if (ap < &rs->host_aliases[MAXALIASES-1])
364 *ap++ = bp;
365 else
366 n = -1;
367 if (n != -1) {
368 n = strlen(bp) + 1; /* for the \0 */
369 if (n >= MAXHOSTNAMELEN) {
370 had_error++;
371 break;
372 }
373 bp += n;
374 }
375 break;
376 #else
377 rs->host.h_name = bp;
378 if (res->options & RES_USE_INET6) {
379 n = strlen(bp) + 1; /* for the \0 */
380 if (n >= MAXHOSTNAMELEN) {
381 had_error++;
382 break;
383 }
384 bp += n;
385 map_v4v6_hostent(&rs->host, &bp, ep);
386 }
387 h_errno = NETDB_SUCCESS;
388 return &rs->host;
389 #endif
390 case T_A:
391 case T_AAAA:
392 if (strcasecmp(rs->host.h_name, bp) != 0) {
393 syslog(LOG_NOTICE|LOG_AUTH,
394 AskedForGot, rs->host.h_name, bp);
395 cp += n;
396 continue; /* XXX - had_error++ ? */
397 }
398 if (n != rs->host.h_length) {
399 cp += n;
400 continue;
401 }
402 if (type == T_AAAA) {
403 struct in6_addr in6;
404 memcpy(&in6, cp, IN6ADDRSZ);
405 if (IN6_IS_ADDR_V4MAPPED(&in6)) {
406 cp += n;
407 continue;
408 }
409 }
410 if (!haveanswer) {
411 int nn;
412
413 rs->host.h_name = bp;
414 nn = strlen(bp) + 1; /* for the \0 */
415 bp += nn;
416 }
417
418 bp += sizeof(align) -
419 (size_t)((u_long)bp % sizeof(align));
420
421 if (bp + n >= &rs->hostbuf[sizeof rs->hostbuf]) {
422 dprintf("size (%d) too big\n", res, n);
423 had_error++;
424 continue;
425 }
426 if (hap >= &rs->h_addr_ptrs[MAXADDRS-1]) {
427 if (!toobig++)
428 dprintf("Too many addresses (%d)\n",
429 res, MAXADDRS);
430 cp += n;
431 continue;
432 }
433 (void)memcpy(*hap++ = bp, cp, (size_t)n);
434 bp += n;
435 cp += n;
436 if (cp != erdata) {
437 h_errno = NO_RECOVERY;
438 return NULL;
439 }
440 break;
441 default:
442 abort();
443 }
444 if (!had_error)
445 haveanswer++;
446 }
447 if (haveanswer) {
448 *ap = NULL;
449 *hap = NULL;
450 /*
451 * Note: we sort even if host can take only one address
452 * in its return structures - should give it the "best"
453 * address in that case, not some random one
454 */
455 if (res->nsort && haveanswer > 1 && qtype == T_A)
456 addrsort(rs->h_addr_ptrs, haveanswer, res);
457 if (!rs->host.h_name) {
458 n = strlen(qname) + 1; /* for the \0 */
459 if (n > ep - bp || n >= MAXHOSTNAMELEN)
460 goto no_recovery;
461 strlcpy(bp, qname, (size_t)(ep - bp));
462 rs->host.h_name = bp;
463 bp += n;
464 }
465 if (res->options & RES_USE_INET6)
466 map_v4v6_hostent(&rs->host, &bp, ep);
467 h_errno = NETDB_SUCCESS;
468 return &rs->host;
469 }
470 no_recovery:
471 h_errno = NO_RECOVERY;
472 return NULL;
473 }
474
475 int
gethostbyname_r(const char * name,struct hostent * hp,char * buf,size_t buflen,struct hostent ** result,int * errorp)476 gethostbyname_r(const char *name, struct hostent *hp, char *buf, size_t buflen,
477 struct hostent**result, int *errorp)
478 {
479 struct hostent *res;
480
481 res = gethostbyname(name);
482 *errorp = h_errno;
483 if (res == NULL) {
484 *result = NULL;
485 return -1;
486 }
487 memcpy(hp, res, sizeof *hp);
488 *result = hp;
489 return 0;
490 }
491
492 struct hostent *
gethostbyname(const char * name)493 gethostbyname(const char *name)
494 {
495 struct hostent *hp;
496 res_state res = __res_get_state();
497
498 if (res == NULL)
499 return NULL;
500
501 assert(name != NULL);
502
503 /* try IPv6 first - if that fails do IPv4 */
504 if (res->options & RES_USE_INET6) {
505 hp = gethostbyname_internal(name, AF_INET6, res, NETID_UNSET, MARK_UNSET);
506 if (hp) {
507 __res_put_state(res);
508 return hp;
509 }
510 }
511 hp = gethostbyname_internal(name, AF_INET, res, NETID_UNSET, MARK_UNSET);
512 __res_put_state(res);
513 return hp;
514 }
515
516 struct hostent *
gethostbyname2(const char * name,int af)517 gethostbyname2(const char *name, int af)
518 {
519 return android_gethostbynamefornet(name, af, NETID_UNSET, MARK_UNSET);
520 }
521
522 struct hostent *
android_gethostbynamefornet(const char * name,int af,unsigned netid,unsigned mark)523 android_gethostbynamefornet(const char *name, int af, unsigned netid, unsigned mark)
524 {
525 struct hostent *hp;
526 res_state res = __res_get_state();
527
528 if (res == NULL)
529 return NULL;
530 hp = gethostbyname_internal(name, af, res, netid, mark);
531 __res_put_state(res);
532 return hp;
533 }
534
535
android_open_proxy()536 static FILE* android_open_proxy()
537 {
538 int sock;
539 const int one = 1;
540 struct sockaddr_un proxy_addr;
541
542 sock = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
543 if (sock < 0) {
544 return NULL;
545 }
546
547 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
548 memset(&proxy_addr, 0, sizeof(proxy_addr));
549 proxy_addr.sun_family = AF_UNIX;
550 strlcpy(proxy_addr.sun_path, "/dev/socket/dnsproxyd", sizeof(proxy_addr.sun_path));
551 if (TEMP_FAILURE_RETRY(connect(sock,
552 (const struct sockaddr*) &proxy_addr,
553 sizeof(proxy_addr))) != 0) {
554 close(sock);
555 return NULL;
556 }
557
558 return fdopen(sock, "r+");
559 }
560
561 static struct hostent *
android_read_hostent(FILE * proxy)562 android_read_hostent(FILE* proxy)
563 {
564 uint32_t size;
565 char buf[4];
566 if (fread(buf, 1, sizeof(buf), proxy) != sizeof(buf)) return NULL;
567
568 /* This is reading serialized data from system/netd/server/DnsProxyListener.cpp
569 * and changes here need to be matched there */
570 int result_code = strtol(buf, NULL, 10);
571 if (result_code != DnsProxyQueryResult) {
572 fread(&size, 1, sizeof(size), proxy);
573 return NULL;
574 }
575
576 if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return NULL;
577 size = ntohl(size);
578 res_static rs = __res_get_static();
579 memset(&rs->host, 0, sizeof(rs->host));
580 char *ptr = rs->hostbuf;
581
582 if (fread(ptr, 1, size, proxy) != size) return NULL;
583 ptr += size;
584 rs->host.h_name = rs->hostbuf;
585
586 char **aliases = rs->host_aliases;
587 rs->host.h_aliases = rs->host_aliases;
588 while (1) {
589 if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return NULL;
590 size = ntohl(size);
591
592 if (size == 0) {
593 *aliases = NULL;
594 break;
595 }
596 if (fread(ptr, 1, size, proxy) != size) return NULL;
597 *aliases++ = ptr;
598 ptr += size;
599 }
600
601 if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return NULL;
602 rs->host.h_addrtype = ntohl(size);
603
604 if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return NULL;
605 rs->host.h_length = ntohl(size);
606
607 char **addrs = rs->h_addr_ptrs;
608 rs->host.h_addr_list = rs->h_addr_ptrs;
609 while (1) {
610 if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return NULL;
611 size = ntohl(size);
612 if (size == 0) {
613 *addrs = NULL;
614 break;
615 }
616 if (fread(ptr, 1, size, proxy) != size) return NULL;
617 *addrs++ = ptr;
618 ptr += size;
619 }
620
621 return &rs->host;
622 }
623
624
625 static struct hostent *
gethostbyname_internal_real(const char * name,int af,res_state res)626 gethostbyname_internal_real(const char *name, int af, res_state res)
627 {
628 const char *cp;
629 char *bp, *ep;
630 int size;
631 struct hostent *hp;
632 res_static rs = __res_get_static();
633
634 static const ns_dtab dtab[] = {
635 NS_FILES_CB(_gethtbyname, NULL)
636 { NSSRC_DNS, _dns_gethtbyname, NULL }, /* force -DHESIOD */
637 { 0, 0, 0 }
638 };
639
640 assert(name != NULL);
641
642 switch (af) {
643 case AF_INET:
644 size = INADDRSZ;
645 break;
646 case AF_INET6:
647 size = IN6ADDRSZ;
648 break;
649 default:
650 h_errno = NETDB_INTERNAL;
651 errno = EAFNOSUPPORT;
652 return NULL;
653 }
654
655 rs->host.h_addrtype = af;
656 rs->host.h_length = size;
657
658 /*
659 * if there aren't any dots, it could be a user-level alias.
660 * this is also done in res_nquery() since we are not the only
661 * function that looks up host names.
662 */
663 if (!strchr(name, '.') && (cp = __hostalias(name)))
664 name = cp;
665
666 /*
667 * disallow names consisting only of digits/dots, unless
668 * they end in a dot.
669 */
670 if (isdigit((u_char) name[0]))
671 for (cp = name;; ++cp) {
672 if (!*cp) {
673 if (*--cp == '.')
674 break;
675 /*
676 * All-numeric, no dot at the end.
677 * Fake up a hostent as if we'd actually
678 * done a lookup.
679 */
680 if (inet_pton(af, name,
681 (char *)(void *)rs->host_addr) <= 0) {
682 h_errno = HOST_NOT_FOUND;
683 return NULL;
684 }
685 strncpy(rs->hostbuf, name, MAXDNAME);
686 rs->hostbuf[MAXDNAME] = '\0';
687 bp = rs->hostbuf + MAXDNAME;
688 ep = rs->hostbuf + sizeof rs->hostbuf;
689 rs->host.h_name = rs->hostbuf;
690 rs->host.h_aliases = rs->host_aliases;
691 rs->host_aliases[0] = NULL;
692 rs->h_addr_ptrs[0] = (char *)(void *)rs->host_addr;
693 rs->h_addr_ptrs[1] = NULL;
694 rs->host.h_addr_list = rs->h_addr_ptrs;
695 if (res->options & RES_USE_INET6)
696 map_v4v6_hostent(&rs->host, &bp, ep);
697 h_errno = NETDB_SUCCESS;
698 return &rs->host;
699 }
700 if (!isdigit((u_char) *cp) && *cp != '.')
701 break;
702 }
703 if ((isxdigit((u_char) name[0]) && strchr(name, ':') != NULL) ||
704 name[0] == ':')
705 for (cp = name;; ++cp) {
706 if (!*cp) {
707 if (*--cp == '.')
708 break;
709 /*
710 * All-IPv6-legal, no dot at the end.
711 * Fake up a hostent as if we'd actually
712 * done a lookup.
713 */
714 if (inet_pton(af, name,
715 (char *)(void *)rs->host_addr) <= 0) {
716 h_errno = HOST_NOT_FOUND;
717 return NULL;
718 }
719 strncpy(rs->hostbuf, name, MAXDNAME);
720 rs->hostbuf[MAXDNAME] = '\0';
721 bp = rs->hostbuf + MAXDNAME;
722 ep = rs->hostbuf + sizeof rs->hostbuf;
723 rs->host.h_name = rs->hostbuf;
724 rs->host.h_aliases = rs->host_aliases;
725 rs->host_aliases[0] = NULL;
726 rs->h_addr_ptrs[0] = (char *)(void *)rs->host_addr;
727 rs->h_addr_ptrs[1] = NULL;
728 rs->host.h_addr_list = rs->h_addr_ptrs;
729 h_errno = NETDB_SUCCESS;
730 return &rs->host;
731 }
732 if (!isxdigit((u_char) *cp) && *cp != ':' && *cp != '.')
733 break;
734 }
735
736 hp = NULL;
737 h_errno = NETDB_INTERNAL;
738 if (nsdispatch(&hp, dtab, NSDB_HOSTS, "gethostbyname",
739 default_dns_files, name, strlen(name), af) != NS_SUCCESS) {
740 return NULL;
741 }
742 h_errno = NETDB_SUCCESS;
743 return hp;
744 }
745
746
747 // very similar in proxy-ness to android_getaddrinfo_proxy
748 static struct hostent *
gethostbyname_internal(const char * name,int af,res_state res,unsigned netid,unsigned mark)749 gethostbyname_internal(const char *name, int af, res_state res, unsigned netid, unsigned mark)
750 {
751 const char *cache_mode = getenv("ANDROID_DNS_MODE");
752 FILE* proxy = NULL;
753 struct hostent *result = NULL;
754
755 if (cache_mode != NULL && strcmp(cache_mode, "local") == 0) {
756 res_setnetid(res, netid);
757 res_setmark(res, mark);
758 return gethostbyname_internal_real(name, af, res);
759 }
760
761 proxy = android_open_proxy();
762 if (proxy == NULL) goto exit;
763
764 netid = __netdClientDispatch.netIdForResolv(netid);
765
766 /* This is writing to system/netd/server/DnsProxyListener.cpp and changes
767 * here need to be matched there */
768 if (fprintf(proxy, "gethostbyname %u %s %d",
769 netid,
770 name == NULL ? "^" : name,
771 af) < 0) {
772 goto exit;
773 }
774
775 if (fputc(0, proxy) == EOF || fflush(proxy) != 0) {
776 goto exit;
777 }
778
779 result = android_read_hostent(proxy);
780
781 exit:
782 if (proxy != NULL) {
783 fclose(proxy);
784 }
785 return result;
786 }
787
788
789 struct hostent *
android_gethostbyaddrfornet_proxy(const void * addr,socklen_t len,int af,unsigned netid)790 android_gethostbyaddrfornet_proxy(const void *addr,
791 socklen_t len, int af, unsigned netid)
792 {
793 struct hostent *result = NULL;
794 FILE* proxy = android_open_proxy();
795
796 if (proxy == NULL) goto exit;
797
798 char buf[INET6_ADDRSTRLEN]; //big enough for IPv4 and IPv6
799 const char * addrStr = inet_ntop(af, addr, buf, sizeof(buf));
800 if (addrStr == NULL) goto exit;
801
802 netid = __netdClientDispatch.netIdForResolv(netid);
803
804 if (fprintf(proxy, "gethostbyaddr %s %d %d %u",
805 addrStr, len, af, netid) < 0) {
806 goto exit;
807 }
808
809 if (fputc(0, proxy) == EOF || fflush(proxy) != 0) {
810 goto exit;
811 }
812
813 result = android_read_hostent(proxy);
814 exit:
815 if (proxy != NULL) {
816 fclose(proxy);
817 }
818 return result;
819 }
820
821 struct hostent *
android_gethostbyaddrfornet_real(const void * addr,socklen_t len,int af,unsigned netid,unsigned mark)822 android_gethostbyaddrfornet_real(const void *addr,
823 socklen_t len, int af, unsigned netid, unsigned mark)
824 {
825 const u_char *uaddr = (const u_char *)addr;
826 socklen_t size;
827 struct hostent *hp;
828 static const ns_dtab dtab[] = {
829 NS_FILES_CB(_gethtbyaddr, NULL)
830 { NSSRC_DNS, _dns_gethtbyaddr, NULL }, /* force -DHESIOD */
831 { 0, 0, 0 }
832 };
833
834 assert(addr != NULL);
835
836 if (af == AF_INET6 && len == NS_IN6ADDRSZ &&
837 (IN6_IS_ADDR_LINKLOCAL((const struct in6_addr *)addr) ||
838 IN6_IS_ADDR_SITELOCAL((const struct in6_addr *)addr))) {
839 h_errno = HOST_NOT_FOUND;
840 return NULL;
841 }
842 if (af == AF_INET6 && len == NS_IN6ADDRSZ &&
843 (IN6_IS_ADDR_V4MAPPED((const struct in6_addr *)addr) ||
844 IN6_IS_ADDR_V4COMPAT((const struct in6_addr *)addr))) {
845 /* Unmap. */
846 uaddr += NS_IN6ADDRSZ - NS_INADDRSZ;
847 addr = uaddr;
848 af = AF_INET;
849 len = NS_INADDRSZ;
850 }
851 switch (af) {
852 case AF_INET:
853 size = NS_INADDRSZ;
854 break;
855 case AF_INET6:
856 size = NS_IN6ADDRSZ;
857 break;
858 default:
859 errno = EAFNOSUPPORT;
860 h_errno = NETDB_INTERNAL;
861 return NULL;
862 }
863 if (size != len) {
864 errno = EINVAL;
865 h_errno = NETDB_INTERNAL;
866 return NULL;
867 }
868 hp = NULL;
869 h_errno = NETDB_INTERNAL;
870 if (nsdispatch(&hp, dtab, NSDB_HOSTS, "gethostbyaddr",
871 default_dns_files, uaddr, len, af, netid, mark) != NS_SUCCESS)
872 return NULL;
873 h_errno = NETDB_SUCCESS;
874 return hp;
875 }
876
877 struct hostent *
android_gethostbyaddrfornet(const void * addr,socklen_t len,int af,unsigned netid,unsigned mark)878 android_gethostbyaddrfornet(const void *addr, socklen_t len, int af, unsigned netid, unsigned mark)
879 {
880 const char *cache_mode = getenv("ANDROID_DNS_MODE");
881
882 if (cache_mode == NULL || strcmp(cache_mode, "local") != 0) {
883 return android_gethostbyaddrfornet_proxy(addr, len, af, netid);
884 } else {
885 return android_gethostbyaddrfornet_real(addr,len, af, netid, mark);
886 }
887 }
888
889 struct hostent *
gethostbyaddr(const void * addr,socklen_t len,int af)890 gethostbyaddr(const void *addr, socklen_t len, int af)
891 {
892 return android_gethostbyaddrfornet(addr, len, af, NETID_UNSET, MARK_UNSET);
893 }
894
895
896 static void
_sethtent(int f)897 _sethtent(int f)
898 {
899 res_static rs = __res_get_static();
900 if (rs == NULL) return;
901 if (!rs->hostf)
902 rs->hostf = fopen(_PATH_HOSTS, "r" );
903 else
904 rewind(rs->hostf);
905 rs->stayopen = f;
906 }
907
908 static void
_endhtent(void)909 _endhtent(void)
910 {
911 res_static rs = __res_get_static();
912 if (rs == NULL) return;
913
914 if (rs->hostf && !rs->stayopen) {
915 (void) fclose(rs->hostf);
916 rs->hostf = NULL;
917 }
918 }
919
920 static struct hostent *
_gethtent(void)921 _gethtent(void)
922 {
923 char *p;
924 char *cp, **q;
925 int af, len;
926 res_static rs = __res_get_static();
927
928 if (!rs->hostf && !(rs->hostf = fopen(_PATH_HOSTS, "r" ))) {
929 h_errno = NETDB_INTERNAL;
930 return NULL;
931 }
932 again:
933 if (!(p = fgets(rs->hostbuf, sizeof rs->hostbuf, rs->hostf))) {
934 h_errno = HOST_NOT_FOUND;
935 return NULL;
936 }
937 if (*p == '#')
938 goto again;
939 if (!(cp = strpbrk(p, "#\n")))
940 goto again;
941 *cp = '\0';
942 if (!(cp = strpbrk(p, " \t")))
943 goto again;
944 *cp++ = '\0';
945 if (inet_pton(AF_INET6, p, (char *)(void *)rs->host_addr) > 0) {
946 af = AF_INET6;
947 len = IN6ADDRSZ;
948 } else if (inet_pton(AF_INET, p, (char *)(void *)rs->host_addr) > 0) {
949 res_state res = __res_get_state();
950 if (res == NULL)
951 return NULL;
952 if (res->options & RES_USE_INET6) {
953 map_v4v6_address((char *)(void *)rs->host_addr,
954 (char *)(void *)rs->host_addr);
955 af = AF_INET6;
956 len = IN6ADDRSZ;
957 } else {
958 af = AF_INET;
959 len = INADDRSZ;
960 }
961 __res_put_state(res);
962 } else {
963 goto again;
964 }
965 /* if this is not something we're looking for, skip it. */
966 if (rs->host.h_addrtype != 0 && rs->host.h_addrtype != af)
967 goto again;
968 if (rs->host.h_length != 0 && rs->host.h_length != len)
969 goto again;
970 rs->h_addr_ptrs[0] = (char *)(void *)rs->host_addr;
971 rs->h_addr_ptrs[1] = NULL;
972 rs->host.h_addr_list = rs->h_addr_ptrs;
973 rs->host.h_length = len;
974 rs->host.h_addrtype = af;
975 while (*cp == ' ' || *cp == '\t')
976 cp++;
977 rs->host.h_name = cp;
978 q = rs->host.h_aliases = rs->host_aliases;
979 if ((cp = strpbrk(cp, " \t")) != NULL)
980 *cp++ = '\0';
981 while (cp && *cp) {
982 if (*cp == ' ' || *cp == '\t') {
983 cp++;
984 continue;
985 }
986 if (q < &rs->host_aliases[MAXALIASES - 1])
987 *q++ = cp;
988 if ((cp = strpbrk(cp, " \t")) != NULL)
989 *cp++ = '\0';
990 }
991 *q = NULL;
992 h_errno = NETDB_SUCCESS;
993 return &rs->host;
994 }
995
996 /*ARGSUSED*/
997 int
_gethtbyname(void * rv,void * cb_data,va_list ap)998 _gethtbyname(void *rv, void *cb_data, va_list ap)
999 {
1000 struct hostent *hp;
1001 const char *name;
1002 int af;
1003
1004 assert(rv != NULL);
1005
1006 name = va_arg(ap, char *);
1007 /* NOSTRICT skip len */(void)va_arg(ap, int);
1008 af = va_arg(ap, int);
1009
1010 hp = NULL;
1011 #if 0
1012 {
1013 res_state res = __res_get_state();
1014 if (res == NULL)
1015 return NS_NOTFOUND;
1016 if (res->options & RES_USE_INET6)
1017 hp = _gethtbyname2(name, AF_INET6);
1018 if (hp==NULL)
1019 hp = _gethtbyname2(name, AF_INET);
1020 __res_put_state(res);
1021 }
1022 #else
1023 hp = _gethtbyname2(name, af);
1024 #endif
1025 *((struct hostent **)rv) = hp;
1026 if (hp == NULL) {
1027 h_errno = HOST_NOT_FOUND;
1028 return NS_NOTFOUND;
1029 }
1030 return NS_SUCCESS;
1031 }
1032
1033 static struct hostent *
_gethtbyname2(const char * name,int af)1034 _gethtbyname2(const char *name, int af)
1035 {
1036 struct hostent *p;
1037 char *tmpbuf, *ptr, **cp;
1038 int num;
1039 size_t len;
1040 res_static rs = __res_get_static();
1041
1042 assert(name != NULL);
1043
1044 _sethtent(rs->stayopen);
1045 ptr = tmpbuf = NULL;
1046 num = 0;
1047 while ((p = _gethtent()) != NULL && num < MAXADDRS) {
1048 if (p->h_addrtype != af)
1049 continue;
1050 if (strcasecmp(p->h_name, name) != 0) {
1051 for (cp = p->h_aliases; *cp != NULL; cp++)
1052 if (strcasecmp(*cp, name) == 0)
1053 break;
1054 if (*cp == NULL) continue;
1055 }
1056
1057 if (num == 0) {
1058 size_t bufsize;
1059 char *src;
1060
1061 bufsize = strlen(p->h_name) + 2 +
1062 MAXADDRS * p->h_length +
1063 ALIGNBYTES;
1064 for (cp = p->h_aliases; *cp != NULL; cp++)
1065 bufsize += strlen(*cp) + 1;
1066
1067 if ((tmpbuf = malloc(bufsize)) == NULL) {
1068 h_errno = NETDB_INTERNAL;
1069 return NULL;
1070 }
1071
1072 ptr = tmpbuf;
1073 src = p->h_name;
1074 while ((*ptr++ = *src++) != '\0');
1075 for (cp = p->h_aliases; *cp != NULL; cp++) {
1076 src = *cp;
1077 while ((*ptr++ = *src++) != '\0');
1078 }
1079 *ptr++ = '\0';
1080
1081 ptr = (char *)(void *)ALIGN(ptr);
1082 }
1083
1084 (void)memcpy(ptr, p->h_addr_list[0], (size_t)p->h_length);
1085 ptr += p->h_length;
1086 num++;
1087 }
1088 _endhtent();
1089 if (num == 0) return NULL;
1090
1091 len = ptr - tmpbuf;
1092 if (len > (sizeof(rs->hostbuf) - ALIGNBYTES)) {
1093 free(tmpbuf);
1094 errno = ENOSPC;
1095 h_errno = NETDB_INTERNAL;
1096 return NULL;
1097 }
1098 ptr = memcpy((void *)ALIGN(rs->hostbuf), tmpbuf, len);
1099 free(tmpbuf);
1100
1101 rs->host.h_name = ptr;
1102 while (*ptr++);
1103
1104 cp = rs->host_aliases;
1105 while (*ptr) {
1106 *cp++ = ptr;
1107 while (*ptr++);
1108 }
1109 ptr++;
1110 *cp = NULL;
1111
1112 ptr = (char *)(void *)ALIGN(ptr);
1113 cp = rs->h_addr_ptrs;
1114 while (num--) {
1115 *cp++ = ptr;
1116 ptr += rs->host.h_length;
1117 }
1118 *cp = NULL;
1119
1120 return &rs->host;
1121 }
1122
1123 /*ARGSUSED*/
1124 static int
_gethtbyaddr(void * rv,void * cb_data,va_list ap)1125 _gethtbyaddr(void *rv, void *cb_data, va_list ap)
1126 {
1127 struct hostent *p;
1128 const unsigned char *addr;
1129 int len, af;
1130 res_static rs = __res_get_static();
1131
1132 assert(rv != NULL);
1133
1134 addr = va_arg(ap, unsigned char *);
1135 len = va_arg(ap, int);
1136 af = va_arg(ap, int);
1137
1138 rs->host.h_length = len;
1139 rs->host.h_addrtype = af;
1140
1141 _sethtent(rs->stayopen);
1142 while ((p = _gethtent()) != NULL)
1143 if (p->h_addrtype == af && !memcmp(p->h_addr, addr,
1144 (size_t)len))
1145 break;
1146 _endhtent();
1147 *((struct hostent **)rv) = p;
1148 if (p==NULL) {
1149 h_errno = HOST_NOT_FOUND;
1150 return NS_NOTFOUND;
1151 }
1152 return NS_SUCCESS;
1153 }
1154
1155 static void
map_v4v6_address(const char * src,char * dst)1156 map_v4v6_address(const char *src, char *dst)
1157 {
1158 u_char *p = (u_char *)dst;
1159 char tmp[INADDRSZ];
1160 int i;
1161
1162 assert(src != NULL);
1163 assert(dst != NULL);
1164
1165 /* Stash a temporary copy so our caller can update in place. */
1166 (void)memcpy(tmp, src, INADDRSZ);
1167 /* Mark this ipv6 addr as a mapped ipv4. */
1168 for (i = 0; i < 10; i++)
1169 *p++ = 0x00;
1170 *p++ = 0xff;
1171 *p++ = 0xff;
1172 /* Retrieve the saved copy and we're done. */
1173 (void)memcpy((void *)p, tmp, INADDRSZ);
1174 }
1175
1176 static void
map_v4v6_hostent(struct hostent * hp,char ** bpp,char * ep)1177 map_v4v6_hostent(struct hostent *hp, char **bpp, char *ep)
1178 {
1179 char **ap;
1180
1181 assert(hp != NULL);
1182 assert(bpp != NULL);
1183 assert(ep != NULL);
1184
1185 if (hp->h_addrtype != AF_INET || hp->h_length != INADDRSZ)
1186 return;
1187 hp->h_addrtype = AF_INET6;
1188 hp->h_length = IN6ADDRSZ;
1189 for (ap = hp->h_addr_list; *ap; ap++) {
1190 int i = sizeof(align) - (size_t)((u_long)*bpp % sizeof(align));
1191
1192 if (ep - *bpp < (i + IN6ADDRSZ)) {
1193 /* Out of memory. Truncate address list here. XXX */
1194 *ap = NULL;
1195 return;
1196 }
1197 *bpp += i;
1198 map_v4v6_address(*ap, *bpp);
1199 *ap = *bpp;
1200 *bpp += IN6ADDRSZ;
1201 }
1202 }
1203
1204 static void
addrsort(char ** ap,int num,res_state res)1205 addrsort(char **ap, int num, res_state res)
1206 {
1207 int i, j;
1208 char **p;
1209 short aval[MAXADDRS];
1210 int needsort = 0;
1211
1212 assert(ap != NULL);
1213
1214 p = ap;
1215 for (i = 0; i < num; i++, p++) {
1216 for (j = 0 ; (unsigned)j < res->nsort; j++)
1217 if (res->sort_list[j].addr.s_addr ==
1218 (((struct in_addr *)(void *)(*p))->s_addr &
1219 res->sort_list[j].mask))
1220 break;
1221 aval[i] = j;
1222 if (needsort == 0 && i > 0 && j < aval[i-1])
1223 needsort = i;
1224 }
1225 if (!needsort)
1226 return;
1227
1228 while (needsort < num) {
1229 for (j = needsort - 1; j >= 0; j--) {
1230 if (aval[j] > aval[j+1]) {
1231 char *hp;
1232
1233 i = aval[j];
1234 aval[j] = aval[j+1];
1235 aval[j+1] = i;
1236
1237 hp = ap[j];
1238 ap[j] = ap[j+1];
1239 ap[j+1] = hp;
1240 } else
1241 break;
1242 }
1243 needsort++;
1244 }
1245 }
1246
1247 struct hostent *
gethostent(void)1248 gethostent(void)
1249 {
1250 res_static rs = __res_get_static();
1251 rs->host.h_addrtype = 0;
1252 rs->host.h_length = 0;
1253 return _gethtent();
1254 }
1255
1256 /*ARGSUSED*/
1257 static int
_dns_gethtbyname(void * rv,void * cb_data,va_list ap)1258 _dns_gethtbyname(void *rv, void *cb_data, va_list ap)
1259 {
1260 querybuf *buf;
1261 int n, type;
1262 struct hostent *hp;
1263 const char *name;
1264 int af;
1265 res_state res;
1266
1267 assert(rv != NULL);
1268
1269 name = va_arg(ap, char *);
1270 /* NOSTRICT skip len */(void)va_arg(ap, int);
1271 af = va_arg(ap, int);
1272
1273 switch (af) {
1274 case AF_INET:
1275 type = T_A;
1276 break;
1277 case AF_INET6:
1278 type = T_AAAA;
1279 break;
1280 default:
1281 return NS_UNAVAIL;
1282 }
1283 buf = malloc(sizeof(*buf));
1284 if (buf == NULL) {
1285 h_errno = NETDB_INTERNAL;
1286 return NS_NOTFOUND;
1287 }
1288 res = __res_get_state();
1289 if (res == NULL) {
1290 free(buf);
1291 return NS_NOTFOUND;
1292 }
1293 n = res_nsearch(res, name, C_IN, type, buf->buf, sizeof(buf->buf));
1294 if (n < 0) {
1295 free(buf);
1296 dprintf("res_nsearch failed (%d)\n", res, n);
1297 __res_put_state(res);
1298 return NS_NOTFOUND;
1299 }
1300 hp = getanswer(buf, n, name, type, res);
1301 free(buf);
1302 __res_put_state(res);
1303 if (hp == NULL)
1304 switch (h_errno) {
1305 case HOST_NOT_FOUND:
1306 return NS_NOTFOUND;
1307 case TRY_AGAIN:
1308 return NS_TRYAGAIN;
1309 default:
1310 return NS_UNAVAIL;
1311 }
1312 *((struct hostent **)rv) = hp;
1313 return NS_SUCCESS;
1314 }
1315
1316 /*ARGSUSED*/
1317 static int
_dns_gethtbyaddr(void * rv,void * cb_data,va_list ap)1318 _dns_gethtbyaddr(void *rv, void *cb_data, va_list ap)
1319 {
1320 char qbuf[MAXDNAME + 1], *qp, *ep;
1321 int n;
1322 querybuf *buf;
1323 struct hostent *hp;
1324 const unsigned char *uaddr;
1325 int len, af, advance;
1326 res_state res;
1327 unsigned netid, mark;
1328 res_static rs = __res_get_static();
1329
1330 assert(rv != NULL);
1331
1332 uaddr = va_arg(ap, unsigned char *);
1333 len = va_arg(ap, int);
1334 af = va_arg(ap, int);
1335 netid = va_arg(ap, unsigned);
1336 mark = va_arg(ap, unsigned);
1337
1338 switch (af) {
1339 case AF_INET:
1340 (void)snprintf(qbuf, sizeof(qbuf), "%u.%u.%u.%u.in-addr.arpa",
1341 (uaddr[3] & 0xff), (uaddr[2] & 0xff),
1342 (uaddr[1] & 0xff), (uaddr[0] & 0xff));
1343 break;
1344
1345 case AF_INET6:
1346 qp = qbuf;
1347 ep = qbuf + sizeof(qbuf) - 1;
1348 for (n = IN6ADDRSZ - 1; n >= 0; n--) {
1349 advance = snprintf(qp, (size_t)(ep - qp), "%x.%x.",
1350 uaddr[n] & 0xf,
1351 ((unsigned int)uaddr[n] >> 4) & 0xf);
1352 if (advance > 0 && qp + advance < ep)
1353 qp += advance;
1354 else {
1355 h_errno = NETDB_INTERNAL;
1356 return NS_NOTFOUND;
1357 }
1358 }
1359 if (strlcat(qbuf, "ip6.arpa", sizeof(qbuf)) >= sizeof(qbuf)) {
1360 h_errno = NETDB_INTERNAL;
1361 return NS_NOTFOUND;
1362 }
1363 break;
1364 default:
1365 abort();
1366 }
1367
1368 buf = malloc(sizeof(*buf));
1369 if (buf == NULL) {
1370 h_errno = NETDB_INTERNAL;
1371 return NS_NOTFOUND;
1372 }
1373 res = __res_get_state();
1374 if (res == NULL) {
1375 free(buf);
1376 return NS_NOTFOUND;
1377 }
1378 res_setnetid(res, netid);
1379 res_setmark(res, mark);
1380 n = res_nquery(res, qbuf, C_IN, T_PTR, buf->buf, sizeof(buf->buf));
1381 if (n < 0) {
1382 free(buf);
1383 dprintf("res_nquery failed (%d)\n", res, n);
1384 __res_put_state(res);
1385 return NS_NOTFOUND;
1386 }
1387 hp = getanswer(buf, n, qbuf, T_PTR, res);
1388 free(buf);
1389 if (hp == NULL) {
1390 __res_put_state(res);
1391 switch (h_errno) {
1392 case HOST_NOT_FOUND:
1393 return NS_NOTFOUND;
1394 case TRY_AGAIN:
1395 return NS_TRYAGAIN;
1396 default:
1397 return NS_UNAVAIL;
1398 }
1399 }
1400 hp->h_addrtype = af;
1401 hp->h_length = len;
1402 (void)memcpy(rs->host_addr, uaddr, (size_t)len);
1403 rs->h_addr_ptrs[0] = (char *)(void *)rs->host_addr;
1404 rs->h_addr_ptrs[1] = NULL;
1405 if (af == AF_INET && (res->options & RES_USE_INET6)) {
1406 map_v4v6_address((char *)(void *)rs->host_addr,
1407 (char *)(void *)rs->host_addr);
1408 hp->h_addrtype = AF_INET6;
1409 hp->h_length = IN6ADDRSZ;
1410 }
1411
1412 __res_put_state(res);
1413 *((struct hostent **)rv) = hp;
1414 h_errno = NETDB_SUCCESS;
1415 return NS_SUCCESS;
1416 }
1417