blob: c59d1f1c8e9bc18915bd9cbd461d1a0639eec950 [file] [log] [blame]
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001/* $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>
Mattias Falkf1464ff2011-08-23 14:34:14 +020059#include <sys/un.h>
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080060#include <netinet/in.h>
61#include <arpa/inet.h>
62#include "arpa_nameser.h"
63#include "resolv_private.h"
64#include "resolv_cache.h"
65#include <assert.h>
66#include <ctype.h>
67#include <errno.h>
68#include <netdb.h>
69#include <stdarg.h>
70#include <stdio.h>
Carl Shapiro2cc2b2b2011-03-21 20:01:03 -070071#include <strings.h>
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080072#include <syslog.h>
Mattias Falkf1464ff2011-08-23 14:34:14 +020073#include <unistd.h>
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080074
75#ifndef LOG_AUTH
76# define LOG_AUTH 0
77#endif
78
79#define MULTI_PTRS_ARE_ALIASES 1 /* XXX - experimental */
80
81#include "nsswitch.h"
82#include <stdlib.h>
83#include <string.h>
84
Mattias Falkf1464ff2011-08-23 14:34:14 +020085// This should be synchronized to ResponseCode.h
86static const int DnsProxyQueryResult = 222;
87
The Android Open Source Project1dc9e472009-03-03 19:28:35 -080088static const char const AskedForGot[] =
89 "gethostby*.getanswer: asked for \"%s\", got \"%s\"";
90
91#define MAXPACKET (64*1024)
92
93typedef union {
94 HEADER hdr;
95 u_char buf[MAXPACKET];
96} querybuf;
97
98typedef union {
99 int32_t al;
100 char ac;
101} align;
102
103#ifdef DEBUG
104static void dprintf(const char *, res_state, ...)
105 __attribute__((__format__(__printf__, 1, 3)));
106#endif
107static struct hostent *getanswer(const querybuf *, int, const char *, int,
108 res_state);
109static void map_v4v6_address(const char *, char *);
110static void map_v4v6_hostent(struct hostent *, char **, char *);
111static void addrsort(char **, int, res_state);
112
Jim Huange5c35e02010-09-27 23:37:10 +0800113static void _sethtent(int);
114static void _endhtent(void);
115static struct hostent *_gethtent(void);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800116void ht_sethostent(int);
117void ht_endhostent(void);
118struct hostent *ht_gethostbyname(char *);
119struct hostent *ht_gethostbyaddr(const char *, int, int);
120void dns_service(void);
121#undef dn_skipname
122int dn_skipname(const u_char *, const u_char *);
Jim Huange5c35e02010-09-27 23:37:10 +0800123static int _gethtbyaddr(void *, void *, va_list);
124static int _gethtbyname(void *, void *, va_list);
125static struct hostent *_gethtbyname2(const char *, int);
126static int _dns_gethtbyaddr(void *, void *, va_list);
127static int _dns_gethtbyname(void *, void *, va_list);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800128
Mattias Falkf1464ff2011-08-23 14:34:14 +0200129static struct hostent *gethostbyname_internal(const char *, int, res_state, const char *);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800130
131static const ns_src default_dns_files[] = {
132 { NSSRC_FILES, NS_SUCCESS },
133 { NSSRC_DNS, NS_SUCCESS },
134 { 0, 0 }
135};
136
137
138#ifdef DEBUG
139static void
140dprintf(const char *msg, res_state res, ...)
141{
142 assert(msg != NULL);
143
144 if (res->options & RES_DEBUG) {
145 int save = errno;
146 va_list ap;
147
148 va_start (ap, res);
149 vprintf(msg, ap);
150 va_end (ap);
151
152 errno = save;
153 }
154}
155#else
156# define dprintf(msg, res, num) ((void)0) /*nada*/
157#endif
158
159#define BOUNDED_INCR(x) \
160 do { \
161 cp += (x); \
162 if (cp > eom) { \
163 h_errno = NO_RECOVERY; \
164 return NULL; \
165 } \
166 } while (/*CONSTCOND*/0)
167
168#define BOUNDS_CHECK(ptr, count) \
169 do { \
170 if ((ptr) + (count) > eom) { \
171 h_errno = NO_RECOVERY; \
172 return NULL; \
173 } \
174 } while (/*CONSTCOND*/0)
175
176static struct hostent *
177getanswer(const querybuf *answer, int anslen, const char *qname, int qtype,
178 res_state res)
179{
180 const HEADER *hp;
181 const u_char *cp;
182 int n;
183 const u_char *eom, *erdata;
184 char *bp, **ap, **hap, *ep;
185 int type, class, ancount, qdcount;
186 int haveanswer, had_error;
187 int toobig = 0;
188 char tbuf[MAXDNAME];
189 const char *tname;
190 int (*name_ok)(const char *);
191 res_static rs = __res_get_static();
192
193 assert(answer != NULL);
194 assert(qname != NULL);
195
196 tname = qname;
197 rs->host.h_name = NULL;
198 eom = answer->buf + anslen;
199 switch (qtype) {
200 case T_A:
201 case T_AAAA:
202 name_ok = res_hnok;
203 break;
204 case T_PTR:
205 name_ok = res_dnok;
206 break;
207 default:
208 return NULL; /* XXX should be abort(); */
209 }
210 /*
211 * find first satisfactory answer
212 */
213 hp = &answer->hdr;
214 ancount = ntohs(hp->ancount);
215 qdcount = ntohs(hp->qdcount);
216 bp = rs->hostbuf;
217 ep = rs->hostbuf + sizeof rs->hostbuf;
218 cp = answer->buf;
219 BOUNDED_INCR(HFIXEDSZ);
220 if (qdcount != 1) {
221 h_errno = NO_RECOVERY;
222 return NULL;
223 }
224 n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
225 if ((n < 0) || !(*name_ok)(bp)) {
226 h_errno = NO_RECOVERY;
227 return NULL;
228 }
229 BOUNDED_INCR(n + QFIXEDSZ);
230 if (qtype == T_A || qtype == T_AAAA) {
231 /* res_send() has already verified that the query name is the
232 * same as the one we sent; this just gets the expanded name
233 * (i.e., with the succeeding search-domain tacked on).
234 */
235 n = strlen(bp) + 1; /* for the \0 */
236 if (n >= MAXHOSTNAMELEN) {
237 h_errno = NO_RECOVERY;
238 return NULL;
239 }
240 rs->host.h_name = bp;
241 bp += n;
242 /* The qname can be abbreviated, but h_name is now absolute. */
243 qname = rs->host.h_name;
244 }
245 ap = rs->host_aliases;
246 *ap = NULL;
247 rs->host.h_aliases = rs->host_aliases;
248 hap = rs->h_addr_ptrs;
249 *hap = NULL;
250 rs->host.h_addr_list = rs->h_addr_ptrs;
251 haveanswer = 0;
252 had_error = 0;
253 while (ancount-- > 0 && cp < eom && !had_error) {
254 n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
255 if ((n < 0) || !(*name_ok)(bp)) {
256 had_error++;
257 continue;
258 }
259 cp += n; /* name */
260 BOUNDS_CHECK(cp, 3 * INT16SZ + INT32SZ);
261 type = _getshort(cp);
262 cp += INT16SZ; /* type */
263 class = _getshort(cp);
264 cp += INT16SZ + INT32SZ; /* class, TTL */
265 n = _getshort(cp);
266 cp += INT16SZ; /* len */
267 BOUNDS_CHECK(cp, n);
268 erdata = cp + n;
269 if (class != C_IN) {
270 /* XXX - debug? syslog? */
271 cp += n;
272 continue; /* XXX - had_error++ ? */
273 }
274 if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME) {
275 if (ap >= &rs->host_aliases[MAXALIASES-1])
276 continue;
277 n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
278 if ((n < 0) || !(*name_ok)(tbuf)) {
279 had_error++;
280 continue;
281 }
282 cp += n;
283 if (cp != erdata) {
284 h_errno = NO_RECOVERY;
285 return NULL;
286 }
287 /* Store alias. */
288 *ap++ = bp;
289 n = strlen(bp) + 1; /* for the \0 */
290 if (n >= MAXHOSTNAMELEN) {
291 had_error++;
292 continue;
293 }
294 bp += n;
295 /* Get canonical name. */
296 n = strlen(tbuf) + 1; /* for the \0 */
297 if (n > ep - bp || n >= MAXHOSTNAMELEN) {
298 had_error++;
299 continue;
300 }
301 strlcpy(bp, tbuf, (size_t)(ep - bp));
302 rs->host.h_name = bp;
303 bp += n;
304 continue;
305 }
306 if (qtype == T_PTR && type == T_CNAME) {
307 n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
308 if (n < 0 || !res_dnok(tbuf)) {
309 had_error++;
310 continue;
311 }
312 cp += n;
313 if (cp != erdata) {
314 h_errno = NO_RECOVERY;
315 return NULL;
316 }
317 /* Get canonical name. */
318 n = strlen(tbuf) + 1; /* for the \0 */
319 if (n > ep - bp || n >= MAXHOSTNAMELEN) {
320 had_error++;
321 continue;
322 }
323 strlcpy(bp, tbuf, (size_t)(ep - bp));
324 tname = bp;
325 bp += n;
326 continue;
327 }
328 if (type != qtype) {
329 if (type != T_KEY && type != T_SIG)
330 syslog(LOG_NOTICE|LOG_AUTH,
331 "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"",
332 qname, p_class(C_IN), p_type(qtype),
333 p_type(type));
334 cp += n;
335 continue; /* XXX - had_error++ ? */
336 }
337 switch (type) {
338 case T_PTR:
339 if (strcasecmp(tname, bp) != 0) {
340 syslog(LOG_NOTICE|LOG_AUTH,
341 AskedForGot, qname, bp);
342 cp += n;
343 continue; /* XXX - had_error++ ? */
344 }
345 n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
346 if ((n < 0) || !res_hnok(bp)) {
347 had_error++;
348 break;
349 }
350#if MULTI_PTRS_ARE_ALIASES
351 cp += n;
352 if (cp != erdata) {
353 h_errno = NO_RECOVERY;
354 return NULL;
355 }
356 if (!haveanswer)
357 rs->host.h_name = bp;
358 else if (ap < &rs->host_aliases[MAXALIASES-1])
359 *ap++ = bp;
360 else
361 n = -1;
362 if (n != -1) {
363 n = strlen(bp) + 1; /* for the \0 */
364 if (n >= MAXHOSTNAMELEN) {
365 had_error++;
366 break;
367 }
368 bp += n;
369 }
370 break;
371#else
372 rs->host.h_name = bp;
373 if (res->options & RES_USE_INET6) {
374 n = strlen(bp) + 1; /* for the \0 */
375 if (n >= MAXHOSTNAMELEN) {
376 had_error++;
377 break;
378 }
379 bp += n;
380 map_v4v6_hostent(&rs->host, &bp, ep);
381 }
382 h_errno = NETDB_SUCCESS;
383 return &rs->host;
384#endif
385 case T_A:
386 case T_AAAA:
387 if (strcasecmp(rs->host.h_name, bp) != 0) {
388 syslog(LOG_NOTICE|LOG_AUTH,
389 AskedForGot, rs->host.h_name, bp);
390 cp += n;
391 continue; /* XXX - had_error++ ? */
392 }
393 if (n != rs->host.h_length) {
394 cp += n;
395 continue;
396 }
397 if (type == T_AAAA) {
398 struct in6_addr in6;
399 memcpy(&in6, cp, IN6ADDRSZ);
400 if (IN6_IS_ADDR_V4MAPPED(&in6)) {
401 cp += n;
402 continue;
403 }
404 }
405 if (!haveanswer) {
406 int nn;
407
408 rs->host.h_name = bp;
409 nn = strlen(bp) + 1; /* for the \0 */
410 bp += nn;
411 }
412
413 bp += sizeof(align) -
414 (size_t)((u_long)bp % sizeof(align));
415
416 if (bp + n >= &rs->hostbuf[sizeof rs->hostbuf]) {
417 dprintf("size (%d) too big\n", res, n);
418 had_error++;
419 continue;
420 }
421 if (hap >= &rs->h_addr_ptrs[MAXADDRS-1]) {
422 if (!toobig++)
423 dprintf("Too many addresses (%d)\n",
424 res, MAXADDRS);
425 cp += n;
426 continue;
427 }
428 (void)memcpy(*hap++ = bp, cp, (size_t)n);
429 bp += n;
430 cp += n;
431 if (cp != erdata) {
432 h_errno = NO_RECOVERY;
433 return NULL;
434 }
435 break;
436 default:
437 abort();
438 }
439 if (!had_error)
440 haveanswer++;
441 }
442 if (haveanswer) {
443 *ap = NULL;
444 *hap = NULL;
445 /*
446 * Note: we sort even if host can take only one address
447 * in its return structures - should give it the "best"
448 * address in that case, not some random one
449 */
450 if (res->nsort && haveanswer > 1 && qtype == T_A)
451 addrsort(rs->h_addr_ptrs, haveanswer, res);
452 if (!rs->host.h_name) {
453 n = strlen(qname) + 1; /* for the \0 */
454 if (n > ep - bp || n >= MAXHOSTNAMELEN)
455 goto no_recovery;
456 strlcpy(bp, qname, (size_t)(ep - bp));
457 rs->host.h_name = bp;
458 bp += n;
459 }
460 if (res->options & RES_USE_INET6)
461 map_v4v6_hostent(&rs->host, &bp, ep);
462 h_errno = NETDB_SUCCESS;
463 return &rs->host;
464 }
465 no_recovery:
466 h_errno = NO_RECOVERY;
467 return NULL;
468}
469
470int
471gethostbyname_r(const char *name, struct hostent *hp, char *buf, size_t buflen,
472 struct hostent**result, int *errorp)
473{
474 struct hostent *res;
475
476 res = gethostbyname(name);
477 *errorp = h_errno;
478 if (res == NULL) {
479 *result = NULL;
480 return -1;
481 }
482 memcpy(hp, res, sizeof *hp);
483 *result = hp;
484 return 0;
485}
486
487struct hostent *
488gethostbyname(const char *name)
489{
490 struct hostent *hp;
491 res_state res = __res_get_state();
492
493 if (res == NULL)
494 return NULL;
495
496 assert(name != NULL);
497
Mattias Falkf1464ff2011-08-23 14:34:14 +0200498 /* try IPv6 first - if that fails do IPv4 */
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800499 if (res->options & RES_USE_INET6) {
Mattias Falkf1464ff2011-08-23 14:34:14 +0200500 hp = gethostbyname_internal(name, AF_INET6, res, NULL);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800501 if (hp) {
502 __res_put_state(res);
503 return hp;
504 }
505 }
Mattias Falkf1464ff2011-08-23 14:34:14 +0200506 hp = gethostbyname_internal(name, AF_INET, res, NULL);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800507 __res_put_state(res);
508 return hp;
509}
510
511struct hostent *
512gethostbyname2(const char *name, int af)
513{
Mattias Falkf1464ff2011-08-23 14:34:14 +0200514 return android_gethostbynameforiface(name, af, NULL);
515}
516
517struct hostent *
518android_gethostbynameforiface(const char *name, int af, const char *iface)
519{
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800520 struct hostent *hp;
521 res_state res = __res_get_state();
522
523 if (res == NULL)
524 return NULL;
Mattias Falkf1464ff2011-08-23 14:34:14 +0200525 hp = gethostbyname_internal(name, af, res, iface);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800526 __res_put_state(res);
527 return hp;
528}
529
Mattias Falkf1464ff2011-08-23 14:34:14 +0200530static struct hostent *gethostbyname_internal_real(const char *name, int af, res_state res);
531
532// very similar in proxy-ness to android_getaddrinfo_proxy
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800533static struct hostent *
Mattias Falkf1464ff2011-08-23 14:34:14 +0200534gethostbyname_internal(const char *name, int af, res_state res, const char *iface)
535{
536 int sock;
537 const int one = 1;
538 struct sockaddr_un proxy_addr;
539 const char *cache_mode = getenv("ANDROID_DNS_MODE");
540 FILE* proxy = NULL;
541
542 if (cache_mode != NULL && strcmp(cache_mode, "local") == 0) {
543 res_setiface(res, iface);
544 return gethostbyname_internal_real(name, af, res);
545 }
546
547 sock = socket(AF_UNIX, SOCK_STREAM, 0);
548 if (sock < 0) {
549 return NULL;
550 }
551
552 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
553 memset(&proxy_addr, 0, sizeof(proxy_addr));
554 proxy_addr.sun_family = AF_UNIX;
555 strlcpy(proxy_addr.sun_path, "/dev/socket/dnsproxyd", sizeof(proxy_addr.sun_path));
556 if (TEMP_FAILURE_RETRY(connect(sock,
557 (const struct sockaddr*) &proxy_addr,
558 sizeof(proxy_addr))) != 0) {
559 close(sock);
560 return NULL;
561 }
562
563 proxy = fdopen(sock, "r+");
564 /* This is writing to system/netd/DnsProxyListener.cpp and changes
565 * here need to be matched there */
566 if (fprintf(proxy, "gethostbyname %d %s %d",
567 getpid(),
568 iface == NULL ? "^" : iface,
569 name == NULL ? "^" : name,
570 af) < 0) {
571 goto exit;
572 }
573
574 if (fputc(0, proxy) == EOF || fflush(proxy) != 0) {
575 goto exit;
576 }
577
578 uint32_t size;
579 char *buf = (char *)&size;
580 if (fread(buf, 1, sizeof(size), proxy) != 1) {
581 goto exit;
582 }
583
584 /* This is reading serialized data from system/netd/DnsProxyListener.cpp
585 * and changes here need to be matched there */
586 int result_code = (int)strtol(buf, NULL, 10);
587 if (result_code != DnsProxyQueryResult) goto exit;
588
589 if (fread(buf, 1, sizeof(size), proxy) != 1) goto exit;
590 size = ntohl(size);
591
592 res_static rs = __res_get_static();
593 memset(&rs->host, 0, sizeof(rs->host));
594 char *ptr = rs->hostbuf;
595
596 if (fread(ptr, 1, size, proxy) != 1) goto exit;
597 ptr += size;
598 rs->host.h_name = rs->hostbuf;
599
600 char **aliases = rs->host_aliases;
601 rs->host.h_aliases = rs->host_aliases;
602 while (1) {
603 if (fread(buf, 1, sizeof(size), proxy) != 1) goto exit;
604 size = ntohl(size);
605 if (fread(ptr, 1, size, proxy) != 1) goto exit;
606 if (size == 1) {
607 *aliases = NULL;
608 break;
609 }
610 *aliases++ = ptr;
611 ptr += size;
612 }
613
614 if (fread(buf, 1, sizeof(size), proxy) != 1) goto exit;
615 rs->host.h_addrtype = ntohl(size);
616
617 if (fread(buf, 1, sizeof(size), proxy) != 1) goto exit;
618 rs->host.h_length = ntohl(size);
619
620 char **addrs = rs->h_addr_ptrs;
621 rs->host.h_addr_list = rs->h_addr_ptrs;
622 while (1) {
623 if (fread(buf, 1, sizeof(size), proxy) != 1) goto exit;
624 size = ntohl(size);
625 if (fread(ptr, 1, size, proxy) != 1) goto exit;
626 if (size == 1) {
627 *addrs = NULL;
628 break;
629 }
630 *addrs++ = ptr;
631 ptr += size;
632 }
633
634 fclose(proxy);
635 return &rs->host;
636
637exit:
638 if (proxy != NULL) {
639 fclose(proxy);
640 }
641 return NULL;
642}
643
644
645static struct hostent *
646gethostbyname_internal_real(const char *name, int af, res_state res)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800647{
648 const char *cp;
649 char *bp, *ep;
650 int size;
651 struct hostent *hp;
Mattias Falkf1464ff2011-08-23 14:34:14 +0200652 res_static rs = __res_get_static();
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800653
654 static const ns_dtab dtab[] = {
655 NS_FILES_CB(_gethtbyname, NULL)
656 { NSSRC_DNS, _dns_gethtbyname, NULL }, /* force -DHESIOD */
657 { 0, 0, 0 }
658 };
659
660 assert(name != NULL);
661
662 switch (af) {
663 case AF_INET:
664 size = INADDRSZ;
665 break;
666 case AF_INET6:
667 size = IN6ADDRSZ;
668 break;
669 default:
670 h_errno = NETDB_INTERNAL;
671 errno = EAFNOSUPPORT;
672 return NULL;
673 }
674
675 rs->host.h_addrtype = af;
676 rs->host.h_length = size;
677
678 /*
679 * if there aren't any dots, it could be a user-level alias.
680 * this is also done in res_nquery() since we are not the only
681 * function that looks up host names.
682 */
683 if (!strchr(name, '.') && (cp = __hostalias(name)))
684 name = cp;
685
686 /*
687 * disallow names consisting only of digits/dots, unless
688 * they end in a dot.
689 */
690 if (isdigit((u_char) name[0]))
691 for (cp = name;; ++cp) {
692 if (!*cp) {
693 if (*--cp == '.')
694 break;
695 /*
696 * All-numeric, no dot at the end.
697 * Fake up a hostent as if we'd actually
698 * done a lookup.
699 */
700 if (inet_pton(af, name,
701 (char *)(void *)rs->host_addr) <= 0) {
702 h_errno = HOST_NOT_FOUND;
703 return NULL;
704 }
705 strncpy(rs->hostbuf, name, MAXDNAME);
706 rs->hostbuf[MAXDNAME] = '\0';
707 bp = rs->hostbuf + MAXDNAME;
708 ep = rs->hostbuf + sizeof rs->hostbuf;
709 rs->host.h_name = rs->hostbuf;
710 rs->host.h_aliases = rs->host_aliases;
711 rs->host_aliases[0] = NULL;
712 rs->h_addr_ptrs[0] = (char *)(void *)rs->host_addr;
713 rs->h_addr_ptrs[1] = NULL;
714 rs->host.h_addr_list = rs->h_addr_ptrs;
715 if (res->options & RES_USE_INET6)
716 map_v4v6_hostent(&rs->host, &bp, ep);
717 h_errno = NETDB_SUCCESS;
718 return &rs->host;
719 }
720 if (!isdigit((u_char) *cp) && *cp != '.')
721 break;
722 }
723 if ((isxdigit((u_char) name[0]) && strchr(name, ':') != NULL) ||
724 name[0] == ':')
725 for (cp = name;; ++cp) {
726 if (!*cp) {
727 if (*--cp == '.')
728 break;
729 /*
730 * All-IPv6-legal, no dot at the end.
731 * Fake up a hostent as if we'd actually
732 * done a lookup.
733 */
734 if (inet_pton(af, name,
735 (char *)(void *)rs->host_addr) <= 0) {
736 h_errno = HOST_NOT_FOUND;
737 return NULL;
738 }
739 strncpy(rs->hostbuf, name, MAXDNAME);
740 rs->hostbuf[MAXDNAME] = '\0';
741 bp = rs->hostbuf + MAXDNAME;
742 ep = rs->hostbuf + sizeof rs->hostbuf;
743 rs->host.h_name = rs->hostbuf;
744 rs->host.h_aliases = rs->host_aliases;
745 rs->host_aliases[0] = NULL;
746 rs->h_addr_ptrs[0] = (char *)(void *)rs->host_addr;
747 rs->h_addr_ptrs[1] = NULL;
748 rs->host.h_addr_list = rs->h_addr_ptrs;
749 h_errno = NETDB_SUCCESS;
750 return &rs->host;
751 }
752 if (!isxdigit((u_char) *cp) && *cp != ':' && *cp != '.')
753 break;
754 }
755
756 hp = NULL;
757 h_errno = NETDB_INTERNAL;
758 if (nsdispatch(&hp, dtab, NSDB_HOSTS, "gethostbyname",
759 default_dns_files, name, strlen(name), af) != NS_SUCCESS) {
760 return NULL;
761 }
762 h_errno = NETDB_SUCCESS;
763 return hp;
764}
765
766struct hostent *
JP Abgrallf8d02d22011-05-18 16:53:23 -0700767gethostbyaddr(const void *addr,
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800768 socklen_t len, int af)
769{
Mattias Falkf1464ff2011-08-23 14:34:14 +0200770 return android_gethostbyaddrforiface(addr, len, af, NULL);
771}
772
773struct hostent *
774android_gethostbyaddrforiface(const void *addr,
775 socklen_t len, int af, const char* iface)
776{
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800777 const u_char *uaddr = (const u_char *)addr;
778 socklen_t size;
779 struct hostent *hp;
780 static const ns_dtab dtab[] = {
781 NS_FILES_CB(_gethtbyaddr, NULL)
782 { NSSRC_DNS, _dns_gethtbyaddr, NULL }, /* force -DHESIOD */
783 { 0, 0, 0 }
784 };
785
786 assert(addr != NULL);
787
788 if (af == AF_INET6 && len == IN6ADDRSZ &&
789 (IN6_IS_ADDR_LINKLOCAL((const struct in6_addr *)(const void *)uaddr) ||
790 IN6_IS_ADDR_SITELOCAL((const struct in6_addr *)(const void *)uaddr))) {
791 h_errno = HOST_NOT_FOUND;
792 return NULL;
793 }
794 if (af == AF_INET6 && len == IN6ADDRSZ &&
795 (IN6_IS_ADDR_V4MAPPED((const struct in6_addr *)(const void *)uaddr) ||
796 IN6_IS_ADDR_V4COMPAT((const struct in6_addr *)(const void *)uaddr))) {
797 /* Unmap. */
798 addr += IN6ADDRSZ - INADDRSZ;
799 uaddr += IN6ADDRSZ - INADDRSZ;
800 af = AF_INET;
801 len = INADDRSZ;
802 }
803 switch (af) {
804 case AF_INET:
805 size = INADDRSZ;
806 break;
807 case AF_INET6:
808 size = IN6ADDRSZ;
809 break;
810 default:
811 errno = EAFNOSUPPORT;
812 h_errno = NETDB_INTERNAL;
813 return NULL;
814 }
815 if (size != len) {
816 errno = EINVAL;
817 h_errno = NETDB_INTERNAL;
818 return NULL;
819 }
820 hp = NULL;
821 h_errno = NETDB_INTERNAL;
822 if (nsdispatch(&hp, dtab, NSDB_HOSTS, "gethostbyaddr",
Mattias Falkf1464ff2011-08-23 14:34:14 +0200823 default_dns_files, uaddr, len, af, iface) != NS_SUCCESS)
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800824 return NULL;
825 h_errno = NETDB_SUCCESS;
826 return hp;
827}
828
Jim Huange5c35e02010-09-27 23:37:10 +0800829static void
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800830_sethtent(int f)
831{
832 res_static rs = __res_get_static();
833 if (rs == NULL) return;
834 if (!rs->hostf)
835 rs->hostf = fopen(_PATH_HOSTS, "r" );
836 else
837 rewind(rs->hostf);
838 rs->stayopen = f;
839}
840
Jim Huange5c35e02010-09-27 23:37:10 +0800841static void
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800842_endhtent(void)
843{
844 res_static rs = __res_get_static();
845 if (rs == NULL) return;
846
847 if (rs->hostf && !rs->stayopen) {
848 (void) fclose(rs->hostf);
849 rs->hostf = NULL;
850 }
851}
852
Jim Huange5c35e02010-09-27 23:37:10 +0800853static struct hostent *
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800854_gethtent(void)
855{
856 char *p;
857 char *cp, **q;
858 int af, len;
859 res_static rs = __res_get_static();
860
861 if (!rs->hostf && !(rs->hostf = fopen(_PATH_HOSTS, "r" ))) {
862 h_errno = NETDB_INTERNAL;
863 return NULL;
864 }
865 again:
866 if (!(p = fgets(rs->hostbuf, sizeof rs->hostbuf, rs->hostf))) {
867 h_errno = HOST_NOT_FOUND;
868 return NULL;
869 }
870 if (*p == '#')
871 goto again;
872 if (!(cp = strpbrk(p, "#\n")))
873 goto again;
874 *cp = '\0';
875 if (!(cp = strpbrk(p, " \t")))
876 goto again;
877 *cp++ = '\0';
878 if (inet_pton(AF_INET6, p, (char *)(void *)rs->host_addr) > 0) {
879 af = AF_INET6;
880 len = IN6ADDRSZ;
881 } else if (inet_pton(AF_INET, p, (char *)(void *)rs->host_addr) > 0) {
882 res_state res = __res_get_state();
883 if (res == NULL)
884 return NULL;
885 if (res->options & RES_USE_INET6) {
886 map_v4v6_address((char *)(void *)rs->host_addr,
887 (char *)(void *)rs->host_addr);
888 af = AF_INET6;
889 len = IN6ADDRSZ;
890 } else {
891 af = AF_INET;
892 len = INADDRSZ;
893 }
894 __res_put_state(res);
895 } else {
896 goto again;
897 }
898 /* if this is not something we're looking for, skip it. */
899 if (rs->host.h_addrtype != 0 && rs->host.h_addrtype != af)
900 goto again;
901 if (rs->host.h_length != 0 && rs->host.h_length != len)
902 goto again;
903 rs->h_addr_ptrs[0] = (char *)(void *)rs->host_addr;
904 rs->h_addr_ptrs[1] = NULL;
905 rs->host.h_addr_list = rs->h_addr_ptrs;
906 rs->host.h_length = len;
907 rs->host.h_addrtype = af;
908 while (*cp == ' ' || *cp == '\t')
909 cp++;
910 rs->host.h_name = cp;
911 q = rs->host.h_aliases = rs->host_aliases;
912 if ((cp = strpbrk(cp, " \t")) != NULL)
913 *cp++ = '\0';
914 while (cp && *cp) {
915 if (*cp == ' ' || *cp == '\t') {
916 cp++;
917 continue;
918 }
919 if (q < &rs->host_aliases[MAXALIASES - 1])
920 *q++ = cp;
921 if ((cp = strpbrk(cp, " \t")) != NULL)
922 *cp++ = '\0';
923 }
924 *q = NULL;
925 h_errno = NETDB_SUCCESS;
926 return &rs->host;
927}
928
929/*ARGSUSED*/
930int
931_gethtbyname(void *rv, void *cb_data, va_list ap)
932{
933 struct hostent *hp;
934 const char *name;
935 int af;
936
937 assert(rv != NULL);
938
939 name = va_arg(ap, char *);
940 /* NOSTRICT skip len */(void)va_arg(ap, int);
941 af = va_arg(ap, int);
942
943 hp = NULL;
944#if 0
945 {
946 res_state res = __res_get_state();
947 if (res == NULL)
948 return NS_NOTFOUND;
949 if (res->options & RES_USE_INET6)
950 hp = _gethtbyname2(name, AF_INET6);
951 if (hp==NULL)
952 hp = _gethtbyname2(name, AF_INET);
953 __res_put_state(res);
954 }
955#else
956 hp = _gethtbyname2(name, af);
957#endif
958 *((struct hostent **)rv) = hp;
959 if (hp == NULL) {
960 h_errno = HOST_NOT_FOUND;
961 return NS_NOTFOUND;
962 }
963 return NS_SUCCESS;
964}
965
Jim Huange5c35e02010-09-27 23:37:10 +0800966static struct hostent *
The Android Open Source Project1dc9e472009-03-03 19:28:35 -0800967_gethtbyname2(const char *name, int af)
968{
969 struct hostent *p;
970 char *tmpbuf, *ptr, **cp;
971 int num;
972 size_t len;
973 res_static rs = __res_get_static();
974
975 assert(name != NULL);
976
977 _sethtent(rs->stayopen);
978 ptr = tmpbuf = NULL;
979 num = 0;
980 while ((p = _gethtent()) != NULL && num < MAXADDRS) {
981 if (p->h_addrtype != af)
982 continue;
983 if (strcasecmp(p->h_name, name) != 0) {
984 for (cp = p->h_aliases; *cp != NULL; cp++)
985 if (strcasecmp(*cp, name) == 0)
986 break;
987 if (*cp == NULL) continue;
988 }
989
990 if (num == 0) {
991 size_t bufsize;
992 char *src;
993
994 bufsize = strlen(p->h_name) + 2 +
995 MAXADDRS * p->h_length +
996 ALIGNBYTES;
997 for (cp = p->h_aliases; *cp != NULL; cp++)
998 bufsize += strlen(*cp) + 1;
999
1000 if ((tmpbuf = malloc(bufsize)) == NULL) {
1001 h_errno = NETDB_INTERNAL;
1002 return NULL;
1003 }
1004
1005 ptr = tmpbuf;
1006 src = p->h_name;
1007 while ((*ptr++ = *src++) != '\0');
1008 for (cp = p->h_aliases; *cp != NULL; cp++) {
1009 src = *cp;
1010 while ((*ptr++ = *src++) != '\0');
1011 }
1012 *ptr++ = '\0';
1013
1014 ptr = (char *)(void *)ALIGN(ptr);
1015 }
1016
1017 (void)memcpy(ptr, p->h_addr_list[0], (size_t)p->h_length);
1018 ptr += p->h_length;
1019 num++;
1020 }
1021 _endhtent();
1022 if (num == 0) return NULL;
1023
1024 len = ptr - tmpbuf;
1025 if (len > (sizeof(rs->hostbuf) - ALIGNBYTES)) {
1026 free(tmpbuf);
1027 errno = ENOSPC;
1028 h_errno = NETDB_INTERNAL;
1029 return NULL;
1030 }
1031 ptr = memcpy((void *)ALIGN(rs->hostbuf), tmpbuf, len);
1032 free(tmpbuf);
1033
1034 rs->host.h_name = ptr;
1035 while (*ptr++);
1036
1037 cp = rs->host_aliases;
1038 while (*ptr) {
1039 *cp++ = ptr;
1040 while (*ptr++);
1041 }
1042 ptr++;
1043 *cp = NULL;
1044
1045 ptr = (char *)(void *)ALIGN(ptr);
1046 cp = rs->h_addr_ptrs;
1047 while (num--) {
1048 *cp++ = ptr;
1049 ptr += rs->host.h_length;
1050 }
1051 *cp = NULL;
1052
1053 return &rs->host;
1054}
1055
1056/*ARGSUSED*/
Jim Huange5c35e02010-09-27 23:37:10 +08001057static int
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001058_gethtbyaddr(void *rv, void *cb_data, va_list ap)
1059{
1060 struct hostent *p;
1061 const unsigned char *addr;
1062 int len, af;
1063 res_static rs = __res_get_static();
1064
1065 assert(rv != NULL);
1066
1067 addr = va_arg(ap, unsigned char *);
1068 len = va_arg(ap, int);
1069 af = va_arg(ap, int);
1070
1071 rs->host.h_length = len;
1072 rs->host.h_addrtype = af;
1073
1074 _sethtent(rs->stayopen);
1075 while ((p = _gethtent()) != NULL)
1076 if (p->h_addrtype == af && !memcmp(p->h_addr, addr,
1077 (size_t)len))
1078 break;
1079 _endhtent();
1080 *((struct hostent **)rv) = p;
1081 if (p==NULL) {
1082 h_errno = HOST_NOT_FOUND;
1083 return NS_NOTFOUND;
1084 }
1085 return NS_SUCCESS;
1086}
1087
1088static void
1089map_v4v6_address(const char *src, char *dst)
1090{
1091 u_char *p = (u_char *)dst;
1092 char tmp[INADDRSZ];
1093 int i;
1094
1095 assert(src != NULL);
1096 assert(dst != NULL);
1097
1098 /* Stash a temporary copy so our caller can update in place. */
1099 (void)memcpy(tmp, src, INADDRSZ);
1100 /* Mark this ipv6 addr as a mapped ipv4. */
1101 for (i = 0; i < 10; i++)
1102 *p++ = 0x00;
1103 *p++ = 0xff;
1104 *p++ = 0xff;
1105 /* Retrieve the saved copy and we're done. */
1106 (void)memcpy((void *)p, tmp, INADDRSZ);
1107}
1108
1109static void
1110map_v4v6_hostent(struct hostent *hp, char **bpp, char *ep)
1111{
1112 char **ap;
1113
1114 assert(hp != NULL);
1115 assert(bpp != NULL);
1116 assert(ep != NULL);
1117
1118 if (hp->h_addrtype != AF_INET || hp->h_length != INADDRSZ)
1119 return;
1120 hp->h_addrtype = AF_INET6;
1121 hp->h_length = IN6ADDRSZ;
1122 for (ap = hp->h_addr_list; *ap; ap++) {
1123 int i = sizeof(align) - (size_t)((u_long)*bpp % sizeof(align));
1124
1125 if (ep - *bpp < (i + IN6ADDRSZ)) {
1126 /* Out of memory. Truncate address list here. XXX */
1127 *ap = NULL;
1128 return;
1129 }
1130 *bpp += i;
1131 map_v4v6_address(*ap, *bpp);
1132 *ap = *bpp;
1133 *bpp += IN6ADDRSZ;
1134 }
1135}
1136
1137static void
1138addrsort(char **ap, int num, res_state res)
1139{
1140 int i, j;
1141 char **p;
1142 short aval[MAXADDRS];
1143 int needsort = 0;
1144
1145 assert(ap != NULL);
1146
1147 p = ap;
1148 for (i = 0; i < num; i++, p++) {
1149 for (j = 0 ; (unsigned)j < res->nsort; j++)
1150 if (res->sort_list[j].addr.s_addr ==
1151 (((struct in_addr *)(void *)(*p))->s_addr &
1152 res->sort_list[j].mask))
1153 break;
1154 aval[i] = j;
1155 if (needsort == 0 && i > 0 && j < aval[i-1])
1156 needsort = i;
1157 }
1158 if (!needsort)
1159 return;
1160
1161 while (needsort < num) {
1162 for (j = needsort - 1; j >= 0; j--) {
1163 if (aval[j] > aval[j+1]) {
1164 char *hp;
1165
1166 i = aval[j];
1167 aval[j] = aval[j+1];
1168 aval[j+1] = i;
1169
1170 hp = ap[j];
1171 ap[j] = ap[j+1];
1172 ap[j+1] = hp;
1173 } else
1174 break;
1175 }
1176 needsort++;
1177 }
1178}
1179
1180struct hostent *
1181gethostent(void)
1182{
1183 res_static rs = __res_get_static();
1184 rs->host.h_addrtype = 0;
1185 rs->host.h_length = 0;
1186 return _gethtent();
1187}
1188
1189/*ARGSUSED*/
Jim Huange5c35e02010-09-27 23:37:10 +08001190static int
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001191_dns_gethtbyname(void *rv, void *cb_data, va_list ap)
1192{
1193 querybuf *buf;
1194 int n, type;
1195 struct hostent *hp;
1196 const char *name;
1197 int af;
1198 res_state res;
1199
1200 assert(rv != NULL);
1201
1202 name = va_arg(ap, char *);
1203 /* NOSTRICT skip len */(void)va_arg(ap, int);
1204 af = va_arg(ap, int);
1205
1206 switch (af) {
1207 case AF_INET:
1208 type = T_A;
1209 break;
1210 case AF_INET6:
1211 type = T_AAAA;
1212 break;
1213 default:
1214 return NS_UNAVAIL;
1215 }
1216 buf = malloc(sizeof(*buf));
1217 if (buf == NULL) {
1218 h_errno = NETDB_INTERNAL;
1219 return NS_NOTFOUND;
1220 }
1221 res = __res_get_state();
1222 if (res == NULL) {
1223 free(buf);
1224 return NS_NOTFOUND;
1225 }
1226 n = res_nsearch(res, name, C_IN, type, buf->buf, sizeof(buf->buf));
1227 if (n < 0) {
1228 free(buf);
1229 dprintf("res_nsearch failed (%d)\n", res, n);
1230 __res_put_state(res);
1231 return NS_NOTFOUND;
1232 }
1233 hp = getanswer(buf, n, name, type, res);
1234 free(buf);
1235 __res_put_state(res);
1236 if (hp == NULL)
1237 switch (h_errno) {
1238 case HOST_NOT_FOUND:
1239 return NS_NOTFOUND;
1240 case TRY_AGAIN:
1241 return NS_TRYAGAIN;
1242 default:
1243 return NS_UNAVAIL;
1244 }
1245 *((struct hostent **)rv) = hp;
1246 return NS_SUCCESS;
1247}
1248
1249/*ARGSUSED*/
Jim Huange5c35e02010-09-27 23:37:10 +08001250static int
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001251_dns_gethtbyaddr(void *rv, void *cb_data, va_list ap)
1252{
1253 char qbuf[MAXDNAME + 1], *qp, *ep;
1254 int n;
1255 querybuf *buf;
1256 struct hostent *hp;
1257 const unsigned char *uaddr;
1258 int len, af, advance;
1259 res_state res;
Mattias Falkf1464ff2011-08-23 14:34:14 +02001260 const char* iface;
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001261 res_static rs = __res_get_static();
1262
1263 assert(rv != NULL);
1264
1265 uaddr = va_arg(ap, unsigned char *);
1266 len = va_arg(ap, int);
1267 af = va_arg(ap, int);
Mattias Falkf1464ff2011-08-23 14:34:14 +02001268 iface = va_arg(ap, char *);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001269
1270 switch (af) {
1271 case AF_INET:
1272 (void)snprintf(qbuf, sizeof(qbuf), "%u.%u.%u.%u.in-addr.arpa",
1273 (uaddr[3] & 0xff), (uaddr[2] & 0xff),
1274 (uaddr[1] & 0xff), (uaddr[0] & 0xff));
1275 break;
1276
1277 case AF_INET6:
1278 qp = qbuf;
1279 ep = qbuf + sizeof(qbuf) - 1;
1280 for (n = IN6ADDRSZ - 1; n >= 0; n--) {
1281 advance = snprintf(qp, (size_t)(ep - qp), "%x.%x.",
1282 uaddr[n] & 0xf,
1283 ((unsigned int)uaddr[n] >> 4) & 0xf);
1284 if (advance > 0 && qp + advance < ep)
1285 qp += advance;
1286 else {
1287 h_errno = NETDB_INTERNAL;
1288 return NS_NOTFOUND;
1289 }
1290 }
1291 if (strlcat(qbuf, "ip6.arpa", sizeof(qbuf)) >= sizeof(qbuf)) {
1292 h_errno = NETDB_INTERNAL;
1293 return NS_NOTFOUND;
1294 }
1295 break;
1296 default:
1297 abort();
1298 }
1299
1300 buf = malloc(sizeof(*buf));
1301 if (buf == NULL) {
1302 h_errno = NETDB_INTERNAL;
1303 return NS_NOTFOUND;
1304 }
1305 res = __res_get_state();
1306 if (res == NULL) {
1307 free(buf);
1308 return NS_NOTFOUND;
1309 }
Mattias Falkf1464ff2011-08-23 14:34:14 +02001310 res_setiface(res, iface);
1311 _resolv_populate_res_for_iface(res);
The Android Open Source Project1dc9e472009-03-03 19:28:35 -08001312 n = res_nquery(res, qbuf, C_IN, T_PTR, buf->buf, sizeof(buf->buf));
1313 if (n < 0) {
1314 free(buf);
1315 dprintf("res_nquery failed (%d)\n", res, n);
1316 __res_put_state(res);
1317 return NS_NOTFOUND;
1318 }
1319 hp = getanswer(buf, n, qbuf, T_PTR, res);
1320 free(buf);
1321 if (hp == NULL) {
1322 __res_put_state(res);
1323 switch (h_errno) {
1324 case HOST_NOT_FOUND:
1325 return NS_NOTFOUND;
1326 case TRY_AGAIN:
1327 return NS_TRYAGAIN;
1328 default:
1329 return NS_UNAVAIL;
1330 }
1331 }
1332 hp->h_addrtype = af;
1333 hp->h_length = len;
1334 (void)memcpy(rs->host_addr, uaddr, (size_t)len);
1335 rs->h_addr_ptrs[0] = (char *)(void *)rs->host_addr;
1336 rs->h_addr_ptrs[1] = NULL;
1337 if (af == AF_INET && (res->options & RES_USE_INET6)) {
1338 map_v4v6_address((char *)(void *)rs->host_addr,
1339 (char *)(void *)rs->host_addr);
1340 hp->h_addrtype = AF_INET6;
1341 hp->h_length = IN6ADDRSZ;
1342 }
1343
1344 __res_put_state(res);
1345 *((struct hostent **)rv) = hp;
1346 h_errno = NETDB_SUCCESS;
1347 return NS_SUCCESS;
1348}