Support gethostbyname_r_ERANGE.
[android-sdk/platform-bionic.git] / libc / dns / gethnamaddr.c
1 /*      $NetBSD: gethnamaddr.c,v 1.91 2014/06/19 15:08:18 christos Exp $        */
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  */
54 #include <sys/cdefs.h>
55 #include <sys/types.h>
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 <stdbool.h>
73 #include <stdio.h>
74 #include <strings.h>
75 #include <syslog.h>
76 #include <unistd.h>
78 #define ALIGNBYTES (sizeof(uintptr_t) - 1)
79 #define ALIGN(p) (((uintptr_t)(p) + ALIGNBYTES) &~ ALIGNBYTES)
81 #ifndef LOG_AUTH
82 # define LOG_AUTH 0
83 #endif
85 #define MULTI_PTRS_ARE_ALIASES 1        /* XXX - experimental */
87 #include "nsswitch.h"
88 #include <stdlib.h>
89 #include <string.h>
91 #include "hostent.h"
93 #define maybe_ok(res, nm, ok) (((res)->options & RES_NOCHECKNAME) != 0U || \
94                                (ok)(nm) != 0)
95 #define maybe_hnok(res, hn) maybe_ok((res), (hn), res_hnok)
96 #define maybe_dnok(res, dn) maybe_ok((res), (dn), res_dnok)
98 #define addalias(d, s, arr, siz) do {                   \
99         if (d >= &arr[siz]) {                           \
100                 char **xptr = realloc(arr, (siz + 10) * sizeof(*arr)); \
101                 if (xptr == NULL)                       \
102                         goto nospc;                     \
103                 d = xptr + (d - arr);                   \
104                 arr = xptr;                             \
105                 siz += 10;                              \
106         }                                               \
107         *d++ = s;                                       \
108 } while (/*CONSTCOND*/0)
110 #define setup(arr, siz) do {                            \
111         arr = malloc((siz = 10) * sizeof(*arr));        \
112         if (arr == NULL)                                \
113                 goto nospc;                             \
114 } while (/*CONSTCOND*/0)
116 // This should be synchronized to ResponseCode.h
117 static const int DnsProxyQueryResult = 222;
119 static const char AskedForGot[] =
120                           "gethostby*.getanswer: asked for \"%s\", got \"%s\"";
122 #define MAXPACKET       (64*1024)
124 typedef union {
125     HEADER hdr;
126     u_char buf[MAXPACKET];
127 } querybuf;
129 typedef union {
130     int32_t al;
131     char ac;
132 } align;
134 #ifdef DEBUG
135 static void debugprintf(const char *, res_state, ...)
136         __attribute__((__format__(__printf__, 1, 3)));
137 #endif
138 static struct hostent *getanswer(const querybuf *, int, const char *, int,
139     res_state, struct hostent *, char *, size_t, int *);
140 static void map_v4v6_address(const char *, char *);
141 static void map_v4v6_hostent(struct hostent *, char **, char *);
142 static void addrsort(char **, int, res_state);
144 void ht_sethostent(int);
145 void ht_endhostent(void);
146 struct hostent *ht_gethostbyname(char *);
147 struct hostent *ht_gethostbyaddr(const char *, int, int);
148 void dns_service(void);
149 #undef dn_skipname
150 int dn_skipname(const u_char *, const u_char *);
151 static int _dns_gethtbyaddr(void *, void *, va_list);
152 static int _dns_gethtbyname(void *, void *, va_list);
154 static struct hostent *gethostbyname_internal(const char *, int, res_state,
155     struct hostent *, char *, size_t, int *, unsigned, unsigned);
156 static struct hostent* android_gethostbyaddrfornet_proxy_internal(const void*, socklen_t,
157     int, struct hostent *, char *, size_t, int *, unsigned, unsigned);
159 static const ns_src default_dns_files[] = {
160         { NSSRC_FILES,  NS_SUCCESS },
161         { NSSRC_DNS,    NS_SUCCESS },
162         { 0, 0 }
163 };
166 #ifdef DEBUG
167 static void
168 debugprintf(const char *msg, res_state res, ...)
170         _DIAGASSERT(msg != NULL);
172         if (res->options & RES_DEBUG) {
173                 int save = errno;
174                 va_list ap;
176                 va_start (ap, res);
177                 vprintf(msg, ap);
178                 va_end (ap);
180                 errno = save;
181         }
183 #else
184 # define debugprintf(msg, res, num) /*nada*/
185 #endif
187 #define BOUNDED_INCR(x) \
188         do { \
189                 cp += (x); \
190                 if (cp > eom) \
191                         goto no_recovery; \
192         } while (/*CONSTCOND*/0)
194 #define BOUNDS_CHECK(ptr, count) \
195         do { \
196                 if ((ptr) + (count) > eom) \
197                         goto no_recovery; \
198         } while (/*CONSTCOND*/0)
200 static struct hostent *
201 getanswer(const querybuf *answer, int anslen, const char *qname, int qtype,
202     res_state res, struct hostent *hent, char *buf, size_t buflen, int *he)
204         const HEADER *hp;
205         const u_char *cp;
206         int n;
207         size_t qlen;
208         const u_char *eom, *erdata;
209         char *bp, **ap, **hap, *ep;
210         int type, class, ancount, qdcount;
211         int haveanswer, had_error;
212         int toobig = 0;
213         char tbuf[MAXDNAME];
214         char **aliases;
215         size_t maxaliases;
216         char *addr_ptrs[MAXADDRS];
217         const char *tname;
218         int (*name_ok)(const char *);
220         _DIAGASSERT(answer != NULL);
221         _DIAGASSERT(qname != NULL);
223         tname = qname;
224         hent->h_name = NULL;
225         eom = answer->buf + anslen;
226         switch (qtype) {
227         case T_A:
228         case T_AAAA:
229                 name_ok = res_hnok;
230                 break;
231         case T_PTR:
232                 name_ok = res_dnok;
233                 break;
234         default:
235           *he = NO_RECOVERY;
236                 return NULL;    /* XXX should be abort(); */
237         }
239         setup(aliases, maxaliases);
240         /*
241          * find first satisfactory answer
242          */
243         hp = &answer->hdr;
244         ancount = ntohs(hp->ancount);
245         qdcount = ntohs(hp->qdcount);
246         bp = buf;
247         ep = buf + buflen;
248         cp = answer->buf;
249         BOUNDED_INCR(HFIXEDSZ);
250         if (qdcount != 1)
251                 goto no_recovery;
253         n = dn_expand(answer->buf, eom, cp, bp, (int)(ep - bp));
254         if ((n < 0) || !maybe_ok(res, bp, name_ok))
255                 goto no_recovery;
257         BOUNDED_INCR(n + QFIXEDSZ);
258         if (qtype == T_A || qtype == T_AAAA) {
259                 /* res_send() has already verified that the query name is the
260                  * same as the one we sent; this just gets the expanded name
261                  * (i.e., with the succeeding search-domain tacked on).
262                  */
263                 n = (int)strlen(bp) + 1;                /* for the \0 */
264                 if (n >= MAXHOSTNAMELEN)
265                         goto no_recovery;
266                 hent->h_name = bp;
267                 bp += n;
268                 /* The qname can be abbreviated, but h_name is now absolute. */
269                 qname = hent->h_name;
270         }
271         hent->h_aliases = ap = aliases;
272         hent->h_addr_list = hap = addr_ptrs;
273         *ap = NULL;
274         *hap = NULL;
275         haveanswer = 0;
276         had_error = 0;
277         while (ancount-- > 0 && cp < eom && !had_error) {
278                 n = dn_expand(answer->buf, eom, cp, bp, (int)(ep - bp));
279                 if ((n < 0) || !maybe_ok(res, bp, name_ok)) {
280                         had_error++;
281                         continue;
282                 }
283                 cp += n;                        /* name */
284                 BOUNDS_CHECK(cp, 3 * INT16SZ + INT32SZ);
285                 type = _getshort(cp);
286                 cp += INT16SZ;                  /* type */
287                 class = _getshort(cp);
288                 cp += INT16SZ + INT32SZ;        /* class, TTL */
289                 n = _getshort(cp);
290                 cp += INT16SZ;                  /* len */
291                 BOUNDS_CHECK(cp, n);
292                 erdata = cp + n;
293                 if (class != C_IN) {
294                         /* XXX - debug? syslog? */
295                         cp += n;
296                         continue;               /* XXX - had_error++ ? */
297                 }
298                 if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME) {
299                         n = dn_expand(answer->buf, eom, cp, tbuf,
300                             (int)sizeof tbuf);
301                         if ((n < 0) || !maybe_ok(res, tbuf, name_ok)) {
302                                 had_error++;
303                                 continue;
304                         }
305                         cp += n;
306                         if (cp != erdata)
307                                 goto no_recovery;
308                         /* Store alias. */
309                         addalias(ap, bp, aliases, maxaliases);
310                         n = (int)strlen(bp) + 1;        /* for the \0 */
311                         if (n >= MAXHOSTNAMELEN) {
312                                 had_error++;
313                                 continue;
314                         }
315                         bp += n;
316                         /* Get canonical name. */
317                         n = (int)strlen(tbuf) + 1;      /* for the \0 */
318                         if (n > ep - bp || n >= MAXHOSTNAMELEN) {
319                                 had_error++;
320                                 continue;
321                         }
322                         strlcpy(bp, tbuf, (size_t)(ep - bp));
323                         hent->h_name = bp;
324                         bp += n;
325                         continue;
326                 }
327                 if (qtype == T_PTR && type == T_CNAME) {
328                         n = dn_expand(answer->buf, eom, cp, tbuf,
329                             (int)sizeof tbuf);
330                         if (n < 0 || !maybe_dnok(res, tbuf)) {
331                                 had_error++;
332                                 continue;
333                         }
334                         cp += n;
335                         if (cp != erdata)
336                                 goto no_recovery;
337                         /* Get canonical name. */
338                         n = (int)strlen(tbuf) + 1;      /* for the \0 */
339                         if (n > ep - bp || n >= MAXHOSTNAMELEN) {
340                                 had_error++;
341                                 continue;
342                         }
343                         strlcpy(bp, tbuf, (size_t)(ep - bp));
344                         tname = bp;
345                         bp += n;
346                         continue;
347                 }
348                 if (type != qtype) {
349                         if (type != T_KEY && type != T_SIG)
350                                 syslog(LOG_NOTICE|LOG_AUTH,
351                "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"",
352                                        qname, p_class(C_IN), p_type(qtype),
353                                        p_type(type));
354                         cp += n;
355                         continue;               /* XXX - had_error++ ? */
356                 }
357                 switch (type) {
358                 case T_PTR:
359                         if (strcasecmp(tname, bp) != 0) {
360                                 syslog(LOG_NOTICE|LOG_AUTH,
361                                        AskedForGot, qname, bp);
362                                 cp += n;
363                                 continue;       /* XXX - had_error++ ? */
364                         }
365                         n = dn_expand(answer->buf, eom, cp, bp, (int)(ep - bp));
366                         if ((n < 0) || !maybe_hnok(res, bp)) {
367                                 had_error++;
368                                 break;
369                         }
370 #if MULTI_PTRS_ARE_ALIASES
371                         cp += n;
372                         if (cp != erdata)
373                                 goto no_recovery;
374                         if (!haveanswer)
375                                 hent->h_name = bp;
376                         else
377                                 addalias(ap, bp, aliases, maxaliases);
378                         if (n != -1) {
379                                 n = (int)strlen(bp) + 1;        /* for the \0 */
380                                 if (n >= MAXHOSTNAMELEN) {
381                                         had_error++;
382                                         break;
383                                 }
384                                 bp += n;
385                         }
386                         break;
387 #else
388                         hent->h_name = bp;
389                         if (res->options & RES_USE_INET6) {
390                                 n = strlen(bp) + 1;     /* for the \0 */
391                                 if (n >= MAXHOSTNAMELEN) {
392                                         had_error++;
393                                         break;
394                                 }
395                                 bp += n;
396                                 map_v4v6_hostent(hent, &bp, ep);
397                         }
398                         goto success;
399 #endif
400                 case T_A:
401                 case T_AAAA:
402                         if (strcasecmp(hent->h_name, bp) != 0) {
403                                 syslog(LOG_NOTICE|LOG_AUTH,
404                                        AskedForGot, hent->h_name, bp);
405                                 cp += n;
406                                 continue;       /* XXX - had_error++ ? */
407                         }
408                         if (n != hent->h_length) {
409                                 cp += n;
410                                 continue;
411                         }
412                         if (type == T_AAAA) {
413                                 struct in6_addr in6;
414                                 memcpy(&in6, cp, NS_IN6ADDRSZ);
415                                 if (IN6_IS_ADDR_V4MAPPED(&in6)) {
416                                         cp += n;
417                                         continue;
418                                 }
419                         }
420                         if (!haveanswer) {
421                                 int nn;
423                                 hent->h_name = bp;
424                                 nn = (int)strlen(bp) + 1;       /* for the \0 */
425                                 bp += nn;
426                         }
428                         bp += sizeof(align) -
429                             (size_t)((u_long)bp % sizeof(align));
431                         if (bp + n >= ep) {
432                                 debugprintf("size (%d) too big\n", res, n);
433                                 had_error++;
434                                 continue;
435                         }
436                         if (hap >= &addr_ptrs[MAXADDRS - 1]) {
437                                 if (!toobig++) {
438                                         debugprintf("Too many addresses (%d)\n",
439                                                 res, MAXADDRS);
440                                 }
441                                 cp += n;
442                                 continue;
443                         }
444                         (void)memcpy(*hap++ = bp, cp, (size_t)n);
445                         bp += n;
446                         cp += n;
447                         if (cp != erdata)
448                                 goto no_recovery;
449                         break;
450                 default:
451                         abort();
452                 }
453                 if (!had_error)
454                         haveanswer++;
455         }
456         if (haveanswer) {
457                 *ap = NULL;
458                 *hap = NULL;
459                 /*
460                  * Note: we sort even if host can take only one address
461                  * in its return structures - should give it the "best"
462                  * address in that case, not some random one
463                  */
464                 if (res->nsort && haveanswer > 1 && qtype == T_A)
465                         addrsort(addr_ptrs, haveanswer, res);
466                 if (!hent->h_name) {
467                         n = (int)strlen(qname) + 1;     /* for the \0 */
468                         if (n > ep - bp || n >= MAXHOSTNAMELEN)
469                                 goto no_recovery;
470                         strlcpy(bp, qname, (size_t)(ep - bp));
471                         hent->h_name = bp;
472                         bp += n;
473                 }
474                 if (res->options & RES_USE_INET6)
475                         map_v4v6_hostent(hent, &bp, ep);
476           goto success;
477         }
478 no_recovery:
479         free(aliases);
480         *he = NO_RECOVERY;
481         return NULL;
482 success:
483         bp = (char *)ALIGN(bp);
484         n = (int)(ap - aliases);
485         qlen = (n + 1) * sizeof(*hent->h_aliases);
486         if ((size_t)(ep - bp) < qlen)
487                 goto nospc;
488         hent->h_aliases = (void *)bp;
489         memcpy(bp, aliases, qlen);
490         free(aliases);
491         aliases = NULL;
493         bp += qlen;
494         n = (int)(hap - addr_ptrs);
495         qlen = (n + 1) * sizeof(*hent->h_addr_list);
496         if ((size_t)(ep - bp) < qlen)
497                 goto nospc;
498         hent->h_addr_list = (void *)bp;
499         memcpy(bp, addr_ptrs, qlen);
500         *he = NETDB_SUCCESS;
501         return hent;
502 nospc:
503         free(aliases);
504         errno = ENOSPC;
505         *he = NETDB_INTERNAL;
506         return NULL;
509 /* The prototype of gethostbyname_r is from glibc, not that in netbsd. */
510 int
511 gethostbyname_r(const char *name, struct hostent *hp, char *buf, size_t buflen,
512     struct hostent **result, int *errorp)
514         res_state res = __res_get_state();
516         if (res == NULL) {
517           *result = NULL;
518                 *errorp = NETDB_INTERNAL;
519                 return -1;
520         }
522         _DIAGASSERT(name != NULL);
524         if (res->options & RES_USE_INET6) {
525                 *result = gethostbyname_internal(name, AF_INET6, res, hp, buf, buflen, errorp, NETID_UNSET,
526                                                  MARK_UNSET);
527                 if (*result) {
528                         __res_put_state(res);
529                         return 0;
530                 }
531         }
532         *result = gethostbyname_internal(name, AF_INET, res, hp, buf, buflen, errorp, NETID_UNSET,
533                                          MARK_UNSET);
534         __res_put_state(res);
535         if (!*result && errno == ENOSPC) {
536           errno = ERANGE;
537           return ERANGE; /* Return error as in linux manual page. */
538         }
539         return (*result) ? 0 : -1;
542 /* The prototype of gethostbyname2_r is from glibc, not that in netbsd. */
543 int
544 gethostbyname2_r(const char *name, int af, struct hostent *hp, char *buf,
545     size_t buflen, struct hostent **result, int *errorp)
547         res_state res = __res_get_state();
549         if (res == NULL) {
550                 *result = NULL;
551                 *errorp = NETDB_INTERNAL;
552                 return -1;
553         }
554         *result = gethostbyname_internal(name, af, res, hp, buf, buflen, errorp, NETID_UNSET,
555                                          MARK_UNSET);
556         __res_put_state(res);
557         if (!*result && errno == ENOSPC) {
558                 errno = ERANGE;
559                 return ERANGE;
560         }
561         return (*result) ? 0 : -1;
564 __LIBC_HIDDEN__ FILE* android_open_proxy() {
565         const char* cache_mode = getenv("ANDROID_DNS_MODE");
566         bool use_proxy = (cache_mode == NULL || strcmp(cache_mode, "local") != 0);
567         if (!use_proxy) {
568                 return NULL;
569         }
571         int s = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
572         if (s == -1) {
573                 return NULL;
574         }
576         const int one = 1;
577         setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
579         struct sockaddr_un proxy_addr;
580         memset(&proxy_addr, 0, sizeof(proxy_addr));
581         proxy_addr.sun_family = AF_UNIX;
582         strlcpy(proxy_addr.sun_path, "/dev/socket/dnsproxyd", sizeof(proxy_addr.sun_path));
584         if (TEMP_FAILURE_RETRY(connect(s, (const struct sockaddr*) &proxy_addr, sizeof(proxy_addr))) != 0) {
585                 close(s);
586                 return NULL;
587         }
589         return fdopen(s, "r+");
592 static struct hostent *
593 android_read_hostent(FILE* proxy, struct hostent* hp, char* hbuf, size_t hbuflen, int *he)
595         uint32_t size;
596         char buf[4];
597         if (fread(buf, 1, sizeof(buf), proxy) != sizeof(buf)) return NULL;
599         // This is reading serialized data from system/netd/server/DnsProxyListener.cpp
600         // and changes here need to be matched there.
601         int result_code = strtol(buf, NULL, 10);
602         if (result_code != DnsProxyQueryResult) {
603                 fread(&size, 1, sizeof(size), proxy);
604                 *he = HOST_NOT_FOUND;
605                 return NULL;
606         }
608         if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return NULL;
609         size = ntohl(size);
611         memset(hp, 0, sizeof(*hp));
612         char *ptr = hbuf;
613         char *hbuf_end = hbuf + hbuflen;
615         if (ptr + size > hbuf_end) {
616                 goto nospc;
617         }
618         if (fread(ptr, 1, size, proxy) != size) return NULL;
619         hp->h_name = ptr;
620         ptr += size;
622         char *aliases_ptrs[MAXALIASES];
623         char **aliases = &aliases_ptrs[0];
625         while (1) {
626                 if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return NULL;
627                 size = ntohl(size);
629                 if (size == 0) {
630                         *aliases = NULL;
631                         break;
632                 }
633                 if (ptr + size > hbuf_end) {
634                   goto nospc;
635                 }
636                 if (fread(ptr, 1, size, proxy) != size) return NULL;
637                 if (aliases < &aliases_ptrs[MAXALIASES - 1]) {
638                   *aliases++ = ptr;
639                 }
640                 ptr += size;
641         }
643         int aliases_len = ((int)(aliases - aliases_ptrs) + 1) * sizeof(*hp->h_aliases);
644         if (ptr + aliases_len > hbuf_end) {
645                 goto nospc;
646         }
647         hp->h_aliases = (void*)ptr;
648         memcpy(ptr, aliases_ptrs, aliases_len);
649         ptr += aliases_len;
651         if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return NULL;
652         hp->h_addrtype = ntohl(size);
654         if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return NULL;
655         hp->h_length = ntohl(size);
657         char *addr_ptrs[MAXADDRS];
658         char **addr_p = &addr_ptrs[0];
660         while (1) {
661                 if (fread(&size, 1, sizeof(size), proxy) != sizeof(size)) return NULL;
662                 size = ntohl(size);
663                 if (size == 0) {
664                         *addr_p = NULL;
665                         break;
666                 }
667                 if (ptr + size > hbuf_end) {
668                   goto nospc;
669                 }
670                 if (fread(ptr, 1, size, proxy) != size) return NULL;
671                 if (addr_p < &addr_ptrs[MAXADDRS - 1]) {
672                   *addr_p++ = ptr;
673                 }
674                 ptr += size;
675         }
677         int addrs_len = ((int)(addr_p - addr_ptrs) + 1) * sizeof(*hp->h_addr_list);
678         if (ptr + addrs_len > hbuf_end) {
679                 goto nospc;
680         }
681         hp->h_addr_list = (void*)ptr;
682         memcpy(ptr, addr_ptrs, addrs_len);
683         *he = NETDB_SUCCESS;
684         return hp;
686 nospc:
687         *he = NETDB_INTERNAL;
688         errno = ENOSPC;
689         return NULL;
692 static struct hostent *
693 gethostbyname_internal_real(const char *name, int af, res_state res, struct hostent *hp, char *buf,
694                             size_t buflen, int *he)
696         const char *cp;
697         struct getnamaddr info;
698         char hbuf[MAXHOSTNAMELEN];
699         size_t size;
700         static const ns_dtab dtab[] = {
701                 NS_FILES_CB(_hf_gethtbyname, NULL)
702                 { NSSRC_DNS, _dns_gethtbyname, NULL },  /* force -DHESIOD */
703                 NS_NIS_CB(_yp_gethtbyname, NULL)
704                 NS_NULL_CB
705         };
707         _DIAGASSERT(name != NULL);
709         switch (af) {
710         case AF_INET:
711                 size = NS_INADDRSZ;
712                 break;
713         case AF_INET6:
714                 size = NS_IN6ADDRSZ;
715                 break;
716         default:
717                 *he = NETDB_INTERNAL;
718                 errno = EAFNOSUPPORT;
719                 return NULL;
720         }
721         if (buflen < size)
722                 goto nospc;
724         hp->h_addrtype = af;
725         hp->h_length = (int)size;
727         /*
728          * if there aren't any dots, it could be a user-level alias.
729          * this is also done in res_nquery() since we are not the only
730          * function that looks up host names.
731          */
732         if (!strchr(name, '.') && (cp = res_hostalias(res, name,
733             hbuf, sizeof(hbuf))))
734                 name = cp;
736         /*
737          * disallow names consisting only of digits/dots, unless
738          * they end in a dot.
739          */
740         if (isdigit((u_char) name[0]))
741                 for (cp = name;; ++cp) {
742                         if (!*cp) {
743                                 if (*--cp == '.')
744                                         break;
745                                 /*
746                                  * All-numeric, no dot at the end.
747                                  * Fake up a hostent as if we'd actually
748                                  * done a lookup.
749                                  */
750                                 goto fake;
751                         }
752                         if (!isdigit((u_char) *cp) && *cp != '.')
753                                 break;
754                 }
755         if ((isxdigit((u_char) name[0]) && strchr(name, ':') != NULL) ||
756             name[0] == ':')
757                 for (cp = name;; ++cp) {
758                         if (!*cp) {
759                                 if (*--cp == '.')
760                                         break;
761                                 /*
762                                  * All-IPv6-legal, no dot at the end.
763                                  * Fake up a hostent as if we'd actually
764                                  * done a lookup.
765                                  */
766                                 goto fake;
767                         }
768                         if (!isxdigit((u_char) *cp) && *cp != ':' && *cp != '.')
769                                 break;
770                 }
772         *he = NETDB_INTERNAL;
773         info.hp = hp;
774         info.buf = buf;
775         info.buflen = buflen;
776         info.he = he;
777         if (nsdispatch(&info, dtab, NSDB_HOSTS, "gethostbyname",
778             default_dns_files, name, strlen(name), af) != NS_SUCCESS)
779                 return NULL;
780         *he = NETDB_SUCCESS;
781         return hp;
782 nospc:
783         *he = NETDB_INTERNAL;
784         errno = ENOSPC;
785         return NULL;
786 fake:
787         HENT_ARRAY(hp->h_addr_list, 1, buf, buflen);
788         HENT_ARRAY(hp->h_aliases, 0, buf, buflen);
790         hp->h_aliases[0] = NULL;
791         if (size > buflen)
792                 goto nospc;
794         if (inet_pton(af, name, buf) <= 0) {
795                 *he = HOST_NOT_FOUND;
796                 return NULL;
797         }
798         hp->h_addr_list[0] = buf;
799         hp->h_addr_list[1] = NULL;
800         buf += size;
801         buflen -= size;
802         HENT_SCOPY(hp->h_name, name, buf, buflen);
803         if (res->options & RES_USE_INET6)
804                 map_v4v6_hostent(hp, &buf, buf + buflen);
805         *he = NETDB_SUCCESS;
806         return hp;
809 // very similar in proxy-ness to android_getaddrinfo_proxy
810 static struct hostent *
811 gethostbyname_internal(const char *name, int af, res_state res, struct hostent *hp, char *hbuf,
812                        size_t hbuflen, int *errorp, unsigned netid, unsigned mark)
814         FILE* proxy = android_open_proxy();
815         if (proxy == NULL) {
816                 // Either we're not supposed to be using the proxy or the proxy is unavailable.
817                 res_setnetid(res, netid);
818                 res_setmark(res, mark);
819                 return gethostbyname_internal_real(name, af, res, hp, hbuf, hbuflen, errorp);
820         }
822         netid = __netdClientDispatch.netIdForResolv(netid);
824         // This is writing to system/netd/server/DnsProxyListener.cpp and changes
825         // here need to be matched there.
826         if (fprintf(proxy, "gethostbyname %u %s %d",
827                         netid,
828                         name == NULL ? "^" : name,
829                         af) < 0) {
830                 fclose(proxy);
831                 return NULL;
832         }
834         if (fputc(0, proxy) == EOF || fflush(proxy) != 0) {
835                 fclose(proxy);
836                 return NULL;
837         }
839         struct hostent* result = android_read_hostent(proxy, hp, hbuf, hbuflen, errorp);
840         fclose(proxy);
841         return result;
844 /* The prototype of gethostbyaddr_r is from glibc, not that in netbsd. */
845 int gethostbyaddr_r(const void *addr, socklen_t len, int af, struct hostent *hp, char *buf,
846                     size_t buflen, struct hostent **result, int *h_errnop)
848         *result = android_gethostbyaddrfornet_proxy_internal(addr, len, af, hp, buf, buflen, h_errnop,
849                                                        NETID_UNSET, MARK_UNSET);
850         if (!*result && errno == ENOSPC) {
851                 errno = ERANGE;
852                 return ERANGE;
853         }
854         return (*result) ? 0 : -1;
857 static struct hostent *
858 android_gethostbyaddrfornet_real(const void *addr, socklen_t len, int af, struct hostent *hp,
859                                  char *buf, size_t buflen, int *he, unsigned netid, unsigned mark)
861         const u_char *uaddr = (const u_char *)addr;
862         socklen_t size;
863         struct getnamaddr info;
864         static const ns_dtab dtab[] = {
865                 NS_FILES_CB(_hf_gethtbyaddr, NULL)
866                 { NSSRC_DNS, _dns_gethtbyaddr, NULL },  /* force -DHESIOD */
867                 NS_NIS_CB(_yp_gethtbyaddr, NULL)
868                 NS_NULL_CB
869         };
871         _DIAGASSERT(addr != NULL);
873         if (af == AF_INET6 && len == NS_IN6ADDRSZ &&
874             (IN6_IS_ADDR_LINKLOCAL((const struct in6_addr *)addr) ||
875              IN6_IS_ADDR_SITELOCAL((const struct in6_addr *)addr))) {
876                 *he = HOST_NOT_FOUND;
877                 return NULL;
878         }
879         if (af == AF_INET6 && len == NS_IN6ADDRSZ &&
880             (IN6_IS_ADDR_V4MAPPED((const struct in6_addr *)addr) ||
881              IN6_IS_ADDR_V4COMPAT((const struct in6_addr *)addr))) {
882                 /* Unmap. */
883                 uaddr += NS_IN6ADDRSZ - NS_INADDRSZ;
884                 addr = uaddr;
885                 af = AF_INET;
886                 len = NS_INADDRSZ;
887         }
888         switch (af) {
889         case AF_INET:
890                 size = NS_INADDRSZ;
891                 break;
892         case AF_INET6:
893                 size = NS_IN6ADDRSZ;
894                 break;
895         default:
896                 errno = EAFNOSUPPORT;
897                 *he = NETDB_INTERNAL;
898                 return NULL;
899         }
900         if (size != len) {
901                 errno = EINVAL;
902                 *he = NETDB_INTERNAL;
903                 return NULL;
904         }
905         info.hp = hp;
906         info.buf = buf;
907         info.buflen = buflen;
908         info.he = he;
909         *he = NETDB_INTERNAL;
910         if (nsdispatch(&info, dtab, NSDB_HOSTS, "gethostbyaddr",
911             default_dns_files, uaddr, len, af, netid, mark) != NS_SUCCESS)
912                 return NULL;
913         *he = NETDB_SUCCESS;
914         return hp;
917 static struct hostent*
918 android_gethostbyaddrfornet_proxy_internal(const void* addr, socklen_t len, int af,
919                              struct hostent *hp, char *hbuf, size_t hbuflen, int *he,
920                              unsigned netid, unsigned mark)
922         FILE* proxy = android_open_proxy();
923         if (proxy == NULL) {
924                 // Either we're not supposed to be using the proxy or the proxy is unavailable.
925                 return android_gethostbyaddrfornet_real(addr,len, af, hp, hbuf, hbuflen, he, netid, mark);
926         }
928         char buf[INET6_ADDRSTRLEN];  //big enough for IPv4 and IPv6
929         const char * addrStr = inet_ntop(af, addr, buf, sizeof(buf));
930         if (addrStr == NULL) {
931                 fclose(proxy);
932                 return NULL;
933         }
935         netid = __netdClientDispatch.netIdForResolv(netid);
937         if (fprintf(proxy, "gethostbyaddr %s %d %d %u",
938                         addrStr, len, af, netid) < 0) {
939                 fclose(proxy);
940                 return NULL;
941         }
943         if (fputc(0, proxy) == EOF || fflush(proxy) != 0) {
944                 fclose(proxy);
945                 return NULL;
946         }
948         struct hostent *result = android_read_hostent(proxy, hp, hbuf, hbuflen, he);
949         fclose(proxy);
950         return result;
953 struct hostent*
954 netbsd_gethostent_r(FILE *hf, struct hostent *hent, char *buf, size_t buflen, int *he)
956         char *p, *name;
957         char *cp, **q;
958         int af, len;
959         size_t anum;
960         char **aliases;
961         size_t maxaliases;
962         struct in6_addr host_addr;
964         if (hf == NULL) {
965                 *he = NETDB_INTERNAL;
966                 errno = EINVAL;
967                 return NULL;
968         }
969         p = NULL;
970         setup(aliases, maxaliases);
972         /* Allocate a new space to read file lines like upstream does.
973          * To keep reentrancy we cannot use __res_get_static()->hostbuf here,
974          * as the buffer may be used to store content for a previous hostent
975          * returned by non-reentrant functions like gethostbyname().
976          */
977         const size_t line_buf_size = sizeof(__res_get_static()->hostbuf);
978         if ((p = malloc(line_buf_size)) == NULL) {
979           goto nospc;
980         }
981         for (;;) {
982                 if (!fgets(p, line_buf_size, hf)) {
983                         free(p);
984                         free(aliases);
985                         *he = HOST_NOT_FOUND;
986                         return NULL;
987                 }
988                 if (*p == '#') {
989                         continue;
990                 }
991                 if (!(cp = strpbrk(p, "#\n"))) {
992                         continue;
993                 }
994                 *cp = '\0';
995                 if (!(cp = strpbrk(p, " \t")))
996                         continue;
997                 *cp++ = '\0';
998                 if (inet_pton(AF_INET6, p, &host_addr) > 0) {
999                         af = AF_INET6;
1000                         len = NS_IN6ADDRSZ;
1001                 } else {
1002                         if (inet_pton(AF_INET, p, &host_addr) <= 0)
1003                                 continue;
1005                         res_state res = __res_get_state();
1006                         if (res == NULL)
1007                                 goto nospc;
1008                         if (res->options & RES_USE_INET6) {
1009                                 map_v4v6_address(buf, buf);
1010                                 af = AF_INET6;
1011                                 len = NS_IN6ADDRSZ;
1012                         } else {
1013                                 af = AF_INET;
1014                                 len = NS_INADDRSZ;
1015                         }
1016                         __res_put_state(res);
1017                 }
1019                 /* if this is not something we're looking for, skip it. */
1020                 if (hent->h_addrtype != 0 && hent->h_addrtype != af)
1021                         continue;
1022                 if (hent->h_length != 0 && hent->h_length != len)
1023                         continue;
1025                 while (*cp == ' ' || *cp == '\t')
1026                         cp++;
1027                 if ((cp = strpbrk(name = cp, " \t")) != NULL)
1028                         *cp++ = '\0';
1029                 q = aliases;
1030                 while (cp && *cp) {
1031                         if (*cp == ' ' || *cp == '\t') {
1032                                 cp++;
1033                                 continue;
1034                         }
1035                         addalias(q, cp, aliases, maxaliases);
1036                         if ((cp = strpbrk(cp, " \t")) != NULL)
1037                                 *cp++ = '\0';
1038                 }
1039                 break;
1040         }
1041         hent->h_length = len;
1042         hent->h_addrtype = af;
1043         HENT_ARRAY(hent->h_addr_list, 1, buf, buflen);
1044         anum = (size_t)(q - aliases);
1045         HENT_ARRAY(hent->h_aliases, anum, buf, buflen);
1046         HENT_COPY(hent->h_addr_list[0], &host_addr, hent->h_length, buf,
1047             buflen);
1048         hent->h_addr_list[1] = NULL;
1050         HENT_SCOPY(hent->h_name, name, buf, buflen);
1051         for (size_t i = 0; i < anum; i++)
1052                 HENT_SCOPY(hent->h_aliases[i], aliases[i], buf, buflen);
1053         hent->h_aliases[anum] = NULL;
1055         *he = NETDB_SUCCESS;
1056         free(p);
1057         free(aliases);
1058         return hent;
1059 nospc:
1060         free(p);
1061         free(aliases);
1062         errno = ENOSPC;
1063         *he = NETDB_INTERNAL;
1064         return NULL;
1067 static void
1068 map_v4v6_address(const char *src, char *dst)
1070         u_char *p = (u_char *)dst;
1071         char tmp[NS_INADDRSZ];
1072         int i;
1074         _DIAGASSERT(src != NULL);
1075         _DIAGASSERT(dst != NULL);
1077         /* Stash a temporary copy so our caller can update in place. */
1078         (void)memcpy(tmp, src, NS_INADDRSZ);
1079         /* Mark this ipv6 addr as a mapped ipv4. */
1080         for (i = 0; i < 10; i++)
1081                 *p++ = 0x00;
1082         *p++ = 0xff;
1083         *p++ = 0xff;
1084         /* Retrieve the saved copy and we're done. */
1085         (void)memcpy(p, tmp, NS_INADDRSZ);
1088 static void
1089 map_v4v6_hostent(struct hostent *hp, char **bpp, char *ep)
1091         char **ap;
1093         _DIAGASSERT(hp != NULL);
1094         _DIAGASSERT(bpp != NULL);
1095         _DIAGASSERT(ep != NULL);
1097         if (hp->h_addrtype != AF_INET || hp->h_length != NS_INADDRSZ)
1098                 return;
1099         hp->h_addrtype = AF_INET6;
1100         hp->h_length = NS_IN6ADDRSZ;
1101         for (ap = hp->h_addr_list; *ap; ap++) {
1102                 int i = (int)(sizeof(align) -
1103                     (size_t)((u_long)*bpp % sizeof(align)));
1105                 if (ep - *bpp < (i + NS_IN6ADDRSZ)) {
1106                         /* Out of memory.  Truncate address list here.  XXX */
1107                         *ap = NULL;
1108                         return;
1109                 }
1110                 *bpp += i;
1111                 map_v4v6_address(*ap, *bpp);
1112                 *ap = *bpp;
1113                 *bpp += NS_IN6ADDRSZ;
1114         }
1117 static void
1118 addrsort(char **ap, int num, res_state res)
1120         int i, j;
1121         char **p;
1122         short aval[MAXADDRS];
1123         int needsort = 0;
1125         _DIAGASSERT(ap != NULL);
1127         p = ap;
1128         for (i = 0; i < num; i++, p++) {
1129             for (j = 0 ; (unsigned)j < res->nsort; j++)
1130                 if (res->sort_list[j].addr.s_addr ==
1131                     (((struct in_addr *)(void *)(*p))->s_addr &
1132                     res->sort_list[j].mask))
1133                         break;
1134             aval[i] = j;
1135             if (needsort == 0 && i > 0 && j < aval[i-1])
1136                 needsort = i;
1137         }
1138         if (!needsort)
1139             return;
1141         while (needsort < num) {
1142             for (j = needsort - 1; j >= 0; j--) {
1143                 if (aval[j] > aval[j+1]) {
1144                     char *hp;
1146                     i = aval[j];
1147                     aval[j] = aval[j+1];
1148                     aval[j+1] = i;
1150                     hp = ap[j];
1151                     ap[j] = ap[j+1];
1152                     ap[j+1] = hp;
1153                 } else
1154                     break;
1155             }
1156             needsort++;
1157         }
1160 /*ARGSUSED*/
1161 static int
1162 _dns_gethtbyname(void *rv, void *cb_data, va_list ap)
1164         querybuf *buf;
1165         int n, type;
1166         struct hostent *hp;
1167         const char *name;
1168         res_state res;
1169         struct getnamaddr *info = rv;
1171         _DIAGASSERT(rv != NULL);
1173         name = va_arg(ap, char *);
1174         /* NOSTRICT skip string len */(void)va_arg(ap, int);
1175         info->hp->h_addrtype = va_arg(ap, int);
1177         switch (info->hp->h_addrtype) {
1178         case AF_INET:
1179                 info->hp->h_length = NS_INADDRSZ;
1180                 type = T_A;
1181                 break;
1182         case AF_INET6:
1183                 info->hp->h_length = NS_IN6ADDRSZ;
1184                 type = T_AAAA;
1185                 break;
1186         default:
1187                 return NS_UNAVAIL;
1188         }
1189         buf = malloc(sizeof(*buf));
1190         if (buf == NULL) {
1191                 *info->he = NETDB_INTERNAL;
1192                 return NS_NOTFOUND;
1193         }
1194         res = __res_get_state();
1195         if (res == NULL) {
1196                 free(buf);
1197                 return NS_NOTFOUND;
1198         }
1199         n = res_nsearch(res, name, C_IN, type, buf->buf, (int)sizeof(buf->buf));
1200         if (n < 0) {
1201                 free(buf);
1202                 debugprintf("res_nsearch failed (%d)\n", res, n);
1203                 __res_put_state(res);
1204                 return NS_NOTFOUND;
1205         }
1206         hp = getanswer(buf, n, name, type, res, info->hp, info->buf,
1207             info->buflen, info->he);
1208         free(buf);
1209         __res_put_state(res);
1210         if (hp == NULL)
1211                 switch (*info->he) {
1212                 case HOST_NOT_FOUND:
1213                         return NS_NOTFOUND;
1214                 case TRY_AGAIN:
1215                         return NS_TRYAGAIN;
1216                 default:
1217                         return NS_UNAVAIL;
1218                 }
1219         return NS_SUCCESS;
1222 /*ARGSUSED*/
1223 static int
1224 _dns_gethtbyaddr(void *rv, void *cb_data, va_list ap)
1226         char qbuf[MAXDNAME + 1], *qp, *ep;
1227         int n;
1228         querybuf *buf;
1229         struct hostent *hp;
1230         const unsigned char *uaddr;
1231         int advance;
1232         res_state res;
1233         char *bf;
1234         size_t blen;
1235         struct getnamaddr *info = rv;
1236         unsigned netid, mark;
1238         _DIAGASSERT(rv != NULL);
1240         uaddr = va_arg(ap, unsigned char *);
1241         info->hp->h_length = va_arg(ap, int);
1242         info->hp->h_addrtype = va_arg(ap, int);
1243         netid = va_arg(ap, unsigned);
1244         mark = va_arg(ap, unsigned);
1246         switch (info->hp->h_addrtype) {
1247         case AF_INET:
1248                 (void)snprintf(qbuf, sizeof(qbuf), "%u.%u.%u.%u.in-addr.arpa",
1249                     (uaddr[3] & 0xff), (uaddr[2] & 0xff),
1250                     (uaddr[1] & 0xff), (uaddr[0] & 0xff));
1251                 break;
1253         case AF_INET6:
1254                 qp = qbuf;
1255                 ep = qbuf + sizeof(qbuf) - 1;
1256                 for (n = NS_IN6ADDRSZ - 1; n >= 0; n--) {
1257                         advance = snprintf(qp, (size_t)(ep - qp), "%x.%x.",
1258                             uaddr[n] & 0xf,
1259                             ((unsigned int)uaddr[n] >> 4) & 0xf);
1260                         if (advance > 0 && qp + advance < ep)
1261                                 qp += advance;
1262                         else {
1263                                 *info->he = NETDB_INTERNAL;
1264                                 return NS_NOTFOUND;
1265                         }
1266                 }
1267                 if (strlcat(qbuf, "ip6.arpa", sizeof(qbuf)) >= sizeof(qbuf)) {
1268                         *info->he = NETDB_INTERNAL;
1269                         return NS_NOTFOUND;
1270                 }
1271                 break;
1272         default:
1273                 return NS_UNAVAIL;
1274         }
1276         buf = malloc(sizeof(*buf));
1277         if (buf == NULL) {
1278                 *info->he = NETDB_INTERNAL;
1279                 return NS_NOTFOUND;
1280         }
1281         res = __res_get_state();
1282         if (res == NULL) {
1283                 free(buf);
1284                 return NS_NOTFOUND;
1285         }
1286         res_setnetid(res, netid);
1287         res_setmark(res, mark);
1288         n = res_nquery(res, qbuf, C_IN, T_PTR, buf->buf, (int)sizeof(buf->buf));
1289         if (n < 0) {
1290                 free(buf);
1291                 debugprintf("res_nquery failed (%d)\n", res, n);
1292                 __res_put_state(res);
1293                 return NS_NOTFOUND;
1294         }
1295         hp = getanswer(buf, n, qbuf, T_PTR, res, info->hp, info->buf,
1296             info->buflen, info->he);
1297         free(buf);
1298         if (hp == NULL) {
1299                 __res_put_state(res);
1300                 switch (*info->he) {
1301                 case HOST_NOT_FOUND:
1302                         return NS_NOTFOUND;
1303                 case TRY_AGAIN:
1304                         return NS_TRYAGAIN;
1305                 default:
1306                         return NS_UNAVAIL;
1307                 }
1308         }
1310         bf = (void *)(hp->h_addr_list + 2);
1311         blen = (size_t)(bf - info->buf);
1312         if (blen + info->hp->h_length > info->buflen)
1313                 goto nospc;
1314         hp->h_addr_list[0] = bf;
1315         hp->h_addr_list[1] = NULL;
1316         (void)memcpy(bf, uaddr, (size_t)info->hp->h_length);
1317         if (info->hp->h_addrtype == AF_INET && (res->options & RES_USE_INET6)) {
1318                 if (blen + NS_IN6ADDRSZ > info->buflen)
1319                         goto nospc;
1320                 map_v4v6_address(bf, bf);
1321                 hp->h_addrtype = AF_INET6;
1322                 hp->h_length = NS_IN6ADDRSZ;
1323         }
1325         __res_put_state(res);
1326         *info->he = NETDB_SUCCESS;
1327         return NS_SUCCESS;
1328 nospc:
1329         errno = ENOSPC;
1330         *info->he = NETDB_INTERNAL;
1331         return NS_UNAVAIL;
1334 #ifdef YP
1335 /*ARGSUSED*/
1336 static struct hostent *
1337 _yp_hostent(char *line, int af, struct getnamaddr *info)
1339         struct in6_addr host_addrs[MAXADDRS];
1340         char **aliases;
1341         size_t maxaliases;
1342         char *p = line;
1343         char *cp, **q, *ptr;
1344         size_t len, anum, i;
1345         int addrok;
1346         int more;
1347         size_t naddrs;
1348         struct hostent *hp = info->hp;
1350         _DIAGASSERT(line != NULL);
1352         hp->h_name = NULL;
1353         hp->h_addrtype = af;
1354         switch (af) {
1355         case AF_INET:
1356                 hp->h_length = NS_INADDRSZ;
1357                 break;
1358         case AF_INET6:
1359                 hp->h_length = NS_IN6ADDRSZ;
1360                 break;
1361         default:
1362                 return NULL;
1363         }
1364         setup(aliases, maxaliases);
1365         naddrs = 0;
1366         q = aliases;
1368 nextline:
1369         /* check for host_addrs overflow */
1370         if (naddrs >= __arraycount(host_addrs))
1371                 goto done;
1373         more = 0;
1374         cp = strpbrk(p, " \t");
1375         if (cp == NULL)
1376                 goto done;
1377         *cp++ = '\0';
1379         /* p has should have an address */
1380         addrok = inet_pton(af, p, &host_addrs[naddrs]);
1381         if (addrok != 1) {
1382                 /* skip to the next line */
1383                 while (cp && *cp) {
1384                         if (*cp == '\n') {
1385                                 cp++;
1386                                 goto nextline;
1387                         }
1388                         cp++;
1389                 }
1390                 goto done;
1391         }
1392         naddrs++;
1394         while (*cp == ' ' || *cp == '\t')
1395                 cp++;
1396         p = cp;
1397         cp = strpbrk(p, " \t\n");
1398         if (cp != NULL) {
1399                 if (*cp == '\n')
1400                         more = 1;
1401                 *cp++ = '\0';
1402         }
1403         if (!hp->h_name)
1404                 hp->h_name = p;
1405         else if (strcmp(hp->h_name, p) == 0)
1406                 ;
1407         else
1408                 addalias(q, p, aliases, maxaliases);
1409         p = cp;
1410         if (more)
1411                 goto nextline;
1413         while (cp && *cp) {
1414                 if (*cp == ' ' || *cp == '\t') {
1415                         cp++;
1416                         continue;
1417                 }
1418                 if (*cp == '\n') {
1419                         cp++;
1420                         goto nextline;
1421                 }
1422                 addalias(q, cp, aliases, maxaliases);
1423                 cp = strpbrk(cp, " \t");
1424                 if (cp != NULL)
1425                         *cp++ = '\0';
1426         }
1428 done:
1429         if (hp->h_name == NULL) {
1430                 free(aliases);
1431                 return NULL;
1432         }
1434         ptr = info->buf;
1435         len = info->buflen;
1437         anum = (size_t)(q - aliases);
1438         HENT_ARRAY(hp->h_addr_list, naddrs, ptr, len);
1439         HENT_ARRAY(hp->h_aliases, anum, ptr, len);
1441         for (i = 0; i < naddrs; i++)
1442                 HENT_COPY(hp->h_addr_list[i], &host_addrs[i], hp->h_length,
1443                     ptr, len);
1444         hp->h_addr_list[naddrs] = NULL;
1446         HENT_SCOPY(hp->h_name, hp->h_name, ptr, len);
1448         for (i = 0; i < anum; i++)
1449                 HENT_SCOPY(hp->h_aliases[i], aliases[i], ptr, len);
1450         hp->h_aliases[anum] = NULL;
1451         free(aliases);
1453         return hp;
1454 nospc:
1455         free(aliases);
1456         *info->he = NETDB_INTERNAL;
1457         errno = ENOSPC;
1458         return NULL;
1461 /*ARGSUSED*/
1462 int
1463 _yp_gethtbyaddr(void *rv, void *cb_data, va_list ap)
1465         struct hostent *hp = NULL;
1466         char *ypcurrent;
1467         int ypcurrentlen, r;
1468         char name[INET6_ADDRSTRLEN];    /* XXX enough? */
1469         const unsigned char *uaddr;
1470         int af;
1471         const char *map;
1472         struct getnamaddr *info = rv;
1474         _DIAGASSERT(rv != NULL);
1476         uaddr = va_arg(ap, unsigned char *);
1477         /* NOSTRICT skip len */(void)va_arg(ap, int);
1478         af = va_arg(ap, int);
1480         if (!__ypdomain) {
1481                 if (_yp_check(&__ypdomain) == 0)
1482                         return NS_UNAVAIL;
1483         }
1484         /*
1485          * XXX unfortunately, we cannot support IPv6 extended scoped address
1486          * notation here.  gethostbyaddr() is not scope-aware.  too bad.
1487          */
1488         if (inet_ntop(af, uaddr, name, (socklen_t)sizeof(name)) == NULL)
1489                 return NS_UNAVAIL;
1490         switch (af) {
1491         case AF_INET:
1492                 map = "hosts.byaddr";
1493                 break;
1494         default:
1495                 map = "ipnodes.byaddr";
1496                 break;
1497         }
1498         ypcurrent = NULL;
1499         r = yp_match(__ypdomain, map, name,
1500                 (int)strlen(name), &ypcurrent, &ypcurrentlen);
1501         if (r == 0)
1502                 hp = _yp_hostent(ypcurrent, af, info);
1503         else
1504                 hp = NULL;
1505         free(ypcurrent);
1506         if (hp == NULL) {
1507                 *info->he = HOST_NOT_FOUND;
1508                 return NS_NOTFOUND;
1509         }
1510         return NS_SUCCESS;
1513 /*ARGSUSED*/
1514 int
1515 _yp_gethtbyname(void *rv, void *cb_data, va_list ap)
1517         struct hostent *hp;
1518         char *ypcurrent;
1519         int ypcurrentlen, r;
1520         const char *name;
1521         int af;
1522         const char *map;
1523         struct getnamaddr *info = rv;
1525         _DIAGASSERT(rv != NULL);
1527         name = va_arg(ap, char *);
1528         /* NOSTRICT skip string len */(void)va_arg(ap, int);
1529         af = va_arg(ap, int);
1531         if (!__ypdomain) {
1532                 if (_yp_check(&__ypdomain) == 0)
1533                         return NS_UNAVAIL;
1534         }
1535         switch (af) {
1536         case AF_INET:
1537                 map = "hosts.byname";
1538                 break;
1539         default:
1540                 map = "ipnodes.byname";
1541                 break;
1542         }
1543         ypcurrent = NULL;
1544         r = yp_match(__ypdomain, map, name,
1545                 (int)strlen(name), &ypcurrent, &ypcurrentlen);
1546         if (r == 0)
1547                 hp = _yp_hostent(ypcurrent, af, info);
1548         else
1549                 hp = NULL;
1550         free(ypcurrent);
1551         if (hp == NULL) {
1552                 *info->he = HOST_NOT_FOUND;
1553                 return NS_NOTFOUND;
1554         }
1555         return NS_SUCCESS;
1557 #endif
1559 /*
1560  * Non-reentrant versions.
1561  */
1563 struct hostent *
1564 gethostbyname(const char *name)
1566         struct hostent *result = NULL;
1567         res_static rs = __res_get_static(); /* Use res_static to provide thread-safety. */
1569         gethostbyname_r(name, &rs->host, rs->hostbuf, sizeof(rs->hostbuf), &result, &h_errno);
1570         return result;
1573 struct hostent *
1574 gethostbyname2(const char *name, int af)
1576         struct hostent *result = NULL;
1577         res_static rs = __res_get_static(); /* Use res_static to provide thread-safety. */
1579         gethostbyname2_r(name, af, &rs->host, rs->hostbuf, sizeof(rs->hostbuf), &result, &h_errno);
1580         return result;
1583 struct hostent *
1584 android_gethostbynamefornet(const char *name, int af, unsigned netid, unsigned mark)
1586         struct hostent *hp;
1587         res_state res = __res_get_state();
1588         if (res == NULL)
1589                 return NULL;
1590         res_static rs = __res_get_static(); /* Use res_static to provide thread-safety. */
1591         hp = gethostbyname_internal(name, af, res, &rs->host, rs->hostbuf, sizeof(rs->hostbuf),
1592                                     &h_errno, netid, mark);
1593         __res_put_state(res);
1594         return hp;
1597 struct hostent *
1598 gethostbyaddr(const void *addr, socklen_t len, int af)
1600         return android_gethostbyaddrfornet_proxy(addr, len, af, NETID_UNSET, MARK_UNSET);
1603 struct hostent *
1604 android_gethostbyaddrfornet(const void *addr, socklen_t len, int af, unsigned netid, unsigned mark)
1606         return android_gethostbyaddrfornet_proxy(addr, len, af, netid, mark);
1609 __LIBC_HIDDEN__ struct hostent*
1610 android_gethostbyaddrfornet_proxy(const void* addr, socklen_t len, int af,
1611                                   unsigned netid, unsigned mark)
1613         res_static rs = __res_get_static(); /* Use res_static to provide thread-safety. */
1614         return android_gethostbyaddrfornet_proxy_internal(addr, len, af, &rs->host, rs->hostbuf,
1615                                                     sizeof(rs->hostbuf), &h_errno, netid, mark);
1618 struct hostent *
1619 gethostent(void)
1621   res_static  rs = __res_get_static();
1622         if (!rs->hostf) {
1623           sethostent_r(&rs->hostf);
1624           if (!rs->hostf) {
1625             h_errno = NETDB_INTERNAL;
1626             return NULL;
1627           }
1628         }
1629         memset(&rs->host, 0, sizeof(rs->host));
1630         return netbsd_gethostent_r(rs->hostf, &rs->host, rs->hostbuf, sizeof(rs->hostbuf), &h_errno);