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