libdevstat - Limit sscanf field, fix redundant condition
[dragonfly.git] / lib / libc / net / gethostnamadr.c
1 /*-
2  * Copyright (c) 1994, Garrett Wollman
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  *
25  * $FreeBSD: src/lib/libc/net/gethostnamadr.c,v 1.33 2006/05/21 11:27:28 ume Exp $
26  */
27
28 #include "namespace.h"
29 #include "reentrant.h"
30 #include <sys/param.h>
31 #include <sys/socket.h>
32 #include <netinet/in.h>
33 #include <arpa/inet.h>
34 #include <netdb.h>
35 #include <stdio.h>
36 #include <ctype.h>
37 #include <errno.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <stdarg.h>
41 #include <nsswitch.h>
42 #include <arpa/nameser.h>               /* XXX hack for _res */
43 #include <resolv.h>                     /* XXX hack for _res */
44 #include "un-namespace.h"
45 #include "netdb_private.h"
46 #ifdef NS_CACHING
47 #include "nscache.h"
48 #endif
49
50 extern int _ht_gethostbyname(void *, void *, va_list);
51 extern int _dns_gethostbyname(void *, void *, va_list);
52 extern int _nis_gethostbyname(void *, void *, va_list);
53 extern int _ht_gethostbyaddr(void *, void *, va_list);
54 extern int _dns_gethostbyaddr(void *, void *, va_list);
55 extern int _nis_gethostbyaddr(void *, void *, va_list);
56
57 static int gethostbyname_internal(const char *, int, struct hostent *, char *,
58     size_t, struct hostent **, int *, res_state);
59
60 /* Host lookup order if nsswitch.conf is broken or nonexistant */
61 static const ns_src default_src[] = {
62         { NSSRC_FILES, NS_SUCCESS },
63         { NSSRC_DNS, NS_SUCCESS },
64         { 0 }
65 };
66 #ifdef NS_CACHING
67 static int host_id_func(char *, size_t *, va_list, void *);
68 static int host_marshal_func(char *, size_t *, void *, va_list, void *);
69 static int host_unmarshal_func(char *, size_t, void *, va_list, void *);
70 #endif
71
72 NETDB_THREAD_ALLOC(hostent)
73 NETDB_THREAD_ALLOC(hostent_data)
74 NETDB_THREAD_ALLOC(hostdata)
75
76 static void
77 hostent_free(void *ptr)
78 {
79         free(ptr);
80 }
81
82 static void
83 hostent_data_free(void *ptr)
84 {
85         struct hostent_data *hed = ptr;
86
87         if (hed == NULL)
88                 return;
89         hed->stayopen = 0;
90         _endhosthtent(hed);
91         free(hed);
92 }
93
94 static void
95 hostdata_free(void *ptr)
96 {
97         free(ptr);
98 }
99
100 int
101 __copy_hostent(struct hostent *he, struct hostent *hptr, char *buf,
102                size_t buflen)
103 {
104         char *cp;
105         char **ptr;
106         int i, n;
107         int nptr, len;
108
109         /* Find out the amount of space required to store the answer. */
110         nptr = 2; /* NULL ptrs */
111         len = (char *)ALIGN(buf) - buf;
112         for (i = 0; he->h_addr_list[i]; i++, nptr++) {
113                 len += he->h_length;
114         }
115         for (i = 0; he->h_aliases[i]; i++, nptr++) {
116                 len += strlen(he->h_aliases[i]) + 1;
117         }
118         len += strlen(he->h_name) + 1;
119         len += nptr * sizeof(char*);
120
121         if (len > buflen) {
122                 errno = ERANGE;
123                 return (-1);
124         }
125
126         /* copy address size and type */
127         hptr->h_addrtype = he->h_addrtype;
128         n = hptr->h_length = he->h_length;
129
130         ptr = (char **)ALIGN(buf);
131         cp = (char *)ALIGN(buf) + nptr * sizeof(char *);
132
133         /* copy address list */
134         hptr->h_addr_list = ptr;
135         for (i = 0; he->h_addr_list[i]; i++ , ptr++) {
136                 memcpy(cp, he->h_addr_list[i], n);
137                 hptr->h_addr_list[i] = cp;
138                 cp += n;
139         }
140         hptr->h_addr_list[i] = NULL;
141         ptr++;
142
143         /* copy official name */
144         n = strlen(he->h_name) + 1;
145         strcpy(cp, he->h_name);
146         hptr->h_name = cp;
147         cp += n;
148
149         /* copy aliases */
150         hptr->h_aliases = ptr;
151         for (i = 0 ; he->h_aliases[i]; i++) {
152                 n = strlen(he->h_aliases[i]) + 1;
153                 strcpy(cp, he->h_aliases[i]);
154                 hptr->h_aliases[i] = cp;
155                 cp += n;
156         }
157         hptr->h_aliases[i] = NULL;
158
159         return (0);
160 }
161
162 #ifdef NS_CACHING
163 static int
164 host_id_func(char *buffer, size_t *buffer_size, va_list ap, void *cache_mdata)
165 {
166         res_state statp;
167         u_long res_options;
168
169         const int op_id = 1;
170         char *str;
171         void *addr;
172         socklen_t len;
173         int type;
174
175         size_t desired_size, size;
176         enum nss_lookup_type lookup_type;
177         char *p;
178         int res = NS_UNAVAIL;
179
180         statp = __res_state();
181         res_options = statp->options & (RES_RECURSE | RES_DEFNAMES |
182             RES_DNSRCH | RES_NOALIASES | RES_USE_INET6);
183
184         lookup_type = (enum nss_lookup_type)cache_mdata;
185         switch (lookup_type) {
186         case nss_lt_name:
187                 str = va_arg(ap, char *);
188                 type = va_arg(ap, int);
189
190                 size = strlen(str);
191                 desired_size = sizeof(res_options) + sizeof(int) +
192                     sizeof(enum nss_lookup_type) + sizeof(int) + size + 1;
193
194                 if (desired_size > *buffer_size) {
195                         res = NS_RETURN;
196                         goto fin;
197                 }
198
199                 p = buffer;
200
201                 memcpy(p, &res_options, sizeof(res_options));
202                 p += sizeof(res_options);
203
204                 memcpy(p, &op_id, sizeof(int));
205                 p += sizeof(int);
206
207                 memcpy(p, &lookup_type, sizeof(enum nss_lookup_type));
208                 p += sizeof(int);
209
210                 memcpy(p, &type, sizeof(int));
211                 p += sizeof(int);
212
213                 memcpy(p, str, size + 1);
214
215                 res = NS_SUCCESS;
216                 break;
217         case nss_lt_id:
218                 addr = va_arg(ap, void *);
219                 len = va_arg(ap, socklen_t);
220                 type = va_arg(ap, int);
221
222                 desired_size = sizeof(res_options) + sizeof(int) +
223                     sizeof(enum nss_lookup_type) + sizeof(int) +
224                     sizeof(socklen_t) + len;
225
226                 if (desired_size > *buffer_size) {
227                         res = NS_RETURN;
228                         goto fin;
229                 }
230
231                 p = buffer;
232                 memcpy(p, &res_options, sizeof(res_options));
233                 p += sizeof(res_options);
234
235                 memcpy(p, &op_id, sizeof(int));
236                 p += sizeof(int);
237
238                 memcpy(p, &lookup_type, sizeof(enum nss_lookup_type));
239                 p += sizeof(int);
240
241                 memcpy(p, &type, sizeof(int));
242                 p += sizeof(int);
243
244                 memcpy(p, &len, sizeof(socklen_t));
245                 p += sizeof(socklen_t);
246
247                 memcpy(p, addr, len);
248
249                 res = NS_SUCCESS;
250                 break;
251         default:
252                 /* should be unreachable */
253                 return (NS_UNAVAIL);
254         }
255
256 fin:
257         *buffer_size = desired_size;
258         return (res);
259 }
260
261 static int
262 host_marshal_func(char *buffer, size_t *buffer_size, void *retval __unused,
263                   va_list ap, void *cache_mdata)
264 {
265         char *str __unused;
266         void *addr __unused;
267         socklen_t len __unused;
268         int type __unused;
269         struct hostent *ht;
270
271         struct hostent new_ht;
272         size_t desired_size, aliases_size, addr_size, size;
273         char *p, **iter;
274
275         switch ((enum nss_lookup_type)cache_mdata) {
276         case nss_lt_name:
277                 str = va_arg(ap, char *);
278                 type = va_arg(ap, int);
279                 break;
280         case nss_lt_id:
281                 addr = va_arg(ap, void *);
282                 len = va_arg(ap, socklen_t);
283                 type = va_arg(ap, int);
284                 break;
285         default:
286                 /* should be unreachable */
287                 return (NS_UNAVAIL);
288         }
289         ht = va_arg(ap, struct hostent *);
290
291         desired_size = _ALIGNBYTES + sizeof(struct hostent) + sizeof(char *);
292         if (ht->h_name != NULL)
293                 desired_size += strlen(ht->h_name) + 1;
294
295         if (ht->h_aliases != NULL) {
296                 aliases_size = 0;
297                 for (iter = ht->h_aliases; *iter; ++iter) {
298                         desired_size += strlen(*iter) + 1;
299                         ++aliases_size;
300                 }
301
302                 desired_size += _ALIGNBYTES +
303                     (aliases_size + 1) * sizeof(char *);
304         }
305
306         if (ht->h_addr_list != NULL) {
307                 addr_size = 0;
308                 for (iter = ht->h_addr_list; *iter; ++iter)
309                         ++addr_size;
310
311                 desired_size += addr_size * _ALIGN(ht->h_length);
312                 desired_size += _ALIGNBYTES + (addr_size + 1) * sizeof(char *);
313         }
314
315         if (desired_size > *buffer_size) {
316                 /* this assignment is here for future use */
317                 *buffer_size = desired_size;
318                 return (NS_RETURN);
319         }
320
321         memcpy(&new_ht, ht, sizeof(struct hostent));
322         memset(buffer, 0, desired_size);
323
324         *buffer_size = desired_size;
325         p = buffer + sizeof(struct hostent) + sizeof(char *);
326         memcpy(buffer + sizeof(struct hostent), &p, sizeof(char *));
327         p = (char *)_ALIGN(p);
328
329         if (new_ht.h_name != NULL) {
330                 size = strlen(new_ht.h_name);
331                 memcpy(p, new_ht.h_name, size);
332                 new_ht.h_name = p;
333                 p += size + 1;
334         }
335
336         if (new_ht.h_aliases != NULL) {
337                 p = (char *)_ALIGN(p);
338                 memcpy(p, new_ht.h_aliases, sizeof(char *) * aliases_size);
339                 new_ht.h_aliases = (char **)p;
340                 p += sizeof(char *) * (aliases_size + 1);
341
342                 for (iter = new_ht.h_aliases; *iter; ++iter) {
343                         size = strlen(*iter);
344                         memcpy(p, *iter, size);
345                         *iter = p;
346                         p += size + 1;
347                 }
348         }
349
350         if (new_ht.h_addr_list != NULL) {
351                 p = (char *)_ALIGN(p);
352                 memcpy(p, new_ht.h_addr_list, sizeof(char *) * addr_size);
353                 new_ht.h_addr_list = (char **)p;
354                 p += sizeof(char *) * (addr_size + 1);
355
356                 size = _ALIGN(new_ht.h_length);
357                 for (iter = new_ht.h_addr_list; *iter; ++iter) {
358                         memcpy(p, *iter, size);
359                         *iter = p;
360                         p += size + 1;
361                 }
362         }
363         memcpy(buffer, &new_ht, sizeof(struct hostent));
364         return (NS_SUCCESS);
365 }
366
367 static int
368 host_unmarshal_func(char *buffer, size_t buffer_size, void *retval, va_list ap,
369                     void *cache_mdata)
370 {
371         char *str __unused;
372         void *addr __unused;
373         socklen_t len __unused;
374         int type __unused;
375         struct hostent *ht;
376
377         char *p;
378         char **iter;
379         char *orig_buf;
380         size_t orig_buf_size;
381
382         switch ((enum nss_lookup_type)cache_mdata) {
383         case nss_lt_name:
384                 str = va_arg(ap, char *);
385                 type = va_arg(ap, int);
386                 break;
387         case nss_lt_id:
388                 addr = va_arg(ap, void *);
389                 len = va_arg(ap, socklen_t);
390                 type = va_arg(ap, int);
391                 break;
392         default:
393                 /* should be unreachable */
394                 return (NS_UNAVAIL);
395         }
396
397         ht = va_arg(ap, struct hostent *);
398         orig_buf = va_arg(ap, char *);
399         orig_buf_size = va_arg(ap, size_t);
400
401         if (orig_buf_size <
402             buffer_size - sizeof(struct hostent) - sizeof(char *)) {
403                 errno = ERANGE;
404                 return (NS_RETURN);
405         }
406
407         memcpy(ht, buffer, sizeof(struct hostent));
408         memcpy(&p, buffer + sizeof(struct hostent), sizeof(char *));
409
410         orig_buf = (char *)_ALIGN(orig_buf);
411         memcpy(orig_buf, buffer + sizeof(struct hostent) + sizeof(char *) +
412             _ALIGN(p) - (size_t)p,
413             buffer_size - sizeof(struct hostent) - sizeof(char *) -
414             _ALIGN(p) + (size_t)p);
415         p = (char *)_ALIGN(p);
416
417         NS_APPLY_OFFSET(ht->h_name, orig_buf, p, char *);
418         if (ht->h_aliases != NULL) {
419                 NS_APPLY_OFFSET(ht->h_aliases, orig_buf, p, char **);
420
421                 for (iter = ht->h_aliases; *iter; ++iter)
422                         NS_APPLY_OFFSET(*iter, orig_buf, p, char *);
423         }
424
425         if (ht->h_addr_list != NULL) {
426                 NS_APPLY_OFFSET(ht->h_addr_list, orig_buf, p, char **);
427
428                 for (iter = ht->h_addr_list; *iter; ++iter)
429                         NS_APPLY_OFFSET(*iter, orig_buf, p, char *);
430         }
431
432         *((struct hostent **)retval) = ht;
433         return (NS_SUCCESS);
434 }
435 #endif /* NS_CACHING */
436
437 static int
438 fakeaddr(const char *name, int af, struct hostent *hp, char *buf,
439          size_t buflen, res_state statp)
440 {
441         struct hostent_data *hed;
442         struct hostent he;
443
444         if ((hed = __hostent_data_init()) == NULL) {
445                 errno = ENOMEM;
446                 RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
447                 return (-1);
448         }
449
450         if ((af != AF_INET ||
451             inet_aton(name, (struct in_addr *)hed->host_addr) != 1) &&
452             inet_pton(af, name, hed->host_addr) != 1) {
453                 RES_SET_H_ERRNO(statp, HOST_NOT_FOUND);
454                 return (-1);
455         }
456         strncpy(hed->hostbuf, name, MAXDNAME);
457         hed->hostbuf[MAXDNAME] = '\0';
458         if (af == AF_INET && (statp->options & RES_USE_INET6) != 0U) {
459                 _map_v4v6_address((char *)hed->host_addr,
460                     (char *)hed->host_addr);
461                 af = AF_INET6;
462         }
463         he.h_addrtype = af;
464         switch(af) {
465         case AF_INET:
466                 he.h_length = NS_INADDRSZ;
467                 break;
468         case AF_INET6:
469                 he.h_length = NS_IN6ADDRSZ;
470                 break;
471         default:
472                 errno = EAFNOSUPPORT;
473                 RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
474                 return (-1);
475         }
476         he.h_name = hed->hostbuf;
477         he.h_aliases = hed->host_aliases;
478         hed->host_aliases[0] = NULL;
479         hed->h_addr_ptrs[0] = (char *)hed->host_addr;
480         hed->h_addr_ptrs[1] = NULL;
481         he.h_addr_list = hed->h_addr_ptrs;
482         RES_SET_H_ERRNO(statp, NETDB_SUCCESS);
483         return (__copy_hostent(&he, hp, buf, buflen));
484 }
485
486 int
487 gethostbyname_r(const char *name, struct hostent *he, char *buffer,
488                 size_t buflen, struct hostent **result, int *h_errnop)
489 {
490         res_state statp;
491
492         statp = __res_state();
493         if ((statp->options & RES_INIT) == 0 && res_ninit(statp) == -1) {
494                 RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
495                 return (-1);
496         }
497         if (statp->options & RES_USE_INET6) {
498                 if (fakeaddr(name, AF_INET, he, buffer, buflen, statp) == 0) {
499                         *result = he;
500                         return (0);
501                 }
502                 if (gethostbyname_internal(name, AF_INET6, he, buffer, buflen,
503                     result, h_errnop, statp) == 0)
504                         return (0);
505         }
506         return (gethostbyname_internal(name, AF_INET, he, buffer, buflen,
507             result, h_errnop, statp));
508 }
509
510 int
511 gethostbyname2_r(const char *name, int af, struct hostent *he, char *buffer,
512                  size_t buflen, struct hostent **result, int *h_errnop)
513 {
514         res_state statp;
515
516         statp = __res_state();
517         if ((statp->options & RES_INIT) == 0 && res_ninit(statp) == -1) {
518                 RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
519                 return (-1);
520         }
521         return (gethostbyname_internal(name, af, he, buffer, buflen, result,
522             h_errnop, statp));
523 }
524
525 static int
526 gethostbyname_internal(const char *name, int af, struct hostent *hp, char *buf,
527                        size_t buflen, struct hostent **result, int *h_errnop,
528                        res_state statp)
529 {
530         const char *cp;
531         int rval, ret_errno;
532         char abuf[MAXDNAME];
533
534 #ifdef NS_CACHING
535         static const nss_cache_info cache_info =
536                 NS_COMMON_CACHE_INFO_INITIALIZER(
537                 hosts, (void *)nss_lt_name,
538                 host_id_func, host_marshal_func, host_unmarshal_func);
539 #endif
540         static const ns_dtab dtab[] = {
541                 NS_FILES_CB(_ht_gethostbyname, NULL)
542                 { NSSRC_DNS, _dns_gethostbyname, NULL },
543                 NS_NIS_CB(_nis_gethostbyname, NULL) /* force -DHESIOD */
544 #ifdef NS_CACHING
545                 NS_CACHE_CB(&cache_info)
546 #endif
547                 { 0 }
548         };
549
550         switch (af) {
551         case AF_INET:
552         case AF_INET6:
553                 break;
554         default:
555                 RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
556                 *h_errnop = statp->res_h_errno;
557                 errno = EAFNOSUPPORT;
558                 return (-1);
559         }
560
561         /*
562          * if there aren't any dots, it could be a user-level alias.
563          * this is also done in res_query() since we are not the only
564          * function that looks up host names.
565          */
566         if (!strchr(name, '.') &&
567             (cp = res_hostalias(statp, name, abuf, sizeof abuf)))
568                 name = cp;
569
570         if (fakeaddr(name, af, hp, buf, buflen, statp) == 0) {
571                 *result = hp;
572                 return (0);
573         }
574
575         rval = _nsdispatch((void *)result, dtab, NSDB_HOSTS,
576             "gethostbyname2_r", default_src, name, af, hp, buf, buflen,
577             &ret_errno, h_errnop);
578
579         return ((rval == NS_SUCCESS) ? 0 : -1);
580 }
581
582 int
583 gethostbyaddr_r(const void *addr, socklen_t len, int af, struct hostent *hp,
584                 char *buf, size_t buflen, struct hostent **result,
585                 int *h_errnop)
586 {
587         const u_char *uaddr = (const u_char *)addr;
588         const struct in6_addr *addr6;
589         socklen_t size;
590         int rval, ret_errno;
591         res_state statp;
592
593 #ifdef NS_CACHING
594         static const nss_cache_info cache_info =
595                 NS_COMMON_CACHE_INFO_INITIALIZER(
596                 hosts, (void *)nss_lt_id,
597                 host_id_func, host_marshal_func, host_unmarshal_func);
598 #endif
599         static const ns_dtab dtab[] = {
600                 NS_FILES_CB(_ht_gethostbyaddr, NULL)
601                 { NSSRC_DNS, _dns_gethostbyaddr, NULL },
602                 NS_NIS_CB(_nis_gethostbyaddr, NULL) /* force -DHESIOD */
603 #ifdef NS_CACHING
604                 NS_CACHE_CB(&cache_info)
605 #endif
606                 { 0 }
607         };
608
609         statp = __res_state();
610         if ((statp->options & RES_INIT) == 0 && res_ninit(statp) == -1) {
611                 RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
612                 *h_errnop = statp->res_h_errno;
613                 return (-1);
614         }
615
616         if (af == AF_INET6 && len == NS_IN6ADDRSZ) {
617                 addr6 = (const struct in6_addr *)addr;
618                 if (IN6_IS_ADDR_LINKLOCAL(addr6)) {
619                         RES_SET_H_ERRNO(statp, HOST_NOT_FOUND);
620                         *h_errnop = statp->res_h_errno;
621                         return (-1);
622                 }
623                 if (IN6_IS_ADDR_V4MAPPED(addr6) ||
624                     IN6_IS_ADDR_V4COMPAT(addr6)) {
625                         /* Unmap. */
626                         uaddr += NS_IN6ADDRSZ - NS_INADDRSZ;
627                         af = AF_INET;
628                         len = NS_INADDRSZ;
629                 }
630         }
631         switch (af) {
632         case AF_INET:
633                 size = NS_INADDRSZ;
634                 break;
635         case AF_INET6:
636                 size = NS_IN6ADDRSZ;
637                 break;
638         default:
639                 errno = EAFNOSUPPORT;
640                 RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
641                 *h_errnop = statp->res_h_errno;
642                 return (-1);
643         }
644         if (size != len) {
645                 errno = EINVAL;
646                 RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
647                 *h_errnop = statp->res_h_errno;
648                 return (-1);
649         }
650
651         rval = _nsdispatch((void *)result, dtab, NSDB_HOSTS,
652             "gethostbyaddr_r", default_src, uaddr, len, af, hp, buf, buflen,
653             &ret_errno, h_errnop);
654
655         return ((rval == NS_SUCCESS) ? 0 : -1);
656 }
657
658 struct hostent *
659 gethostbyname(const char *name)
660 {
661         struct hostdata *hd;
662         struct hostent *rval;
663         int ret_h_errno;
664
665         if ((hd = __hostdata_init()) == NULL)
666                 return (NULL);
667         if (gethostbyname_r(name, &hd->host, hd->data, sizeof(hd->data), &rval,
668             &ret_h_errno) != 0)
669                 return (NULL);
670         return (rval);
671 }
672
673 struct hostent *
674 gethostbyname2(const char *name, int af)
675 {
676         struct hostdata *hd;
677         struct hostent *rval;
678         int ret_h_errno;
679
680         if ((hd = __hostdata_init()) == NULL)
681                 return (NULL);
682         if (gethostbyname2_r(name, af, &hd->host, hd->data, sizeof(hd->data),
683             &rval, &ret_h_errno) != 0)
684                 return (NULL);
685         return (rval);
686 }
687
688 struct hostent *
689 gethostbyaddr(const void *addr, socklen_t len, int af)
690 {
691         struct hostdata *hd;
692         struct hostent *rval;
693         int ret_h_errno;
694
695         if ((hd = __hostdata_init()) == NULL)
696                 return (NULL);
697         if (gethostbyaddr_r(addr, len, af, &hd->host, hd->data,
698             sizeof(hd->data), &rval, &ret_h_errno) != 0)
699                 return (NULL);
700         return (rval);
701 }
702
703 void
704 sethostent(int stayopen)
705 {
706         struct hostent_data *hed;
707
708         if ((hed = __hostent_data_init()) == NULL)
709                 return;
710         _sethosthtent(stayopen, hed);
711         _sethostdnsent(stayopen);
712 }
713
714 void
715 endhostent(void)
716 {
717         struct hostent_data *hed;
718
719         if ((hed = __hostent_data_init()) == NULL)
720                 return;
721         _endhosthtent(hed);
722         _endhostdnsent();
723 }