]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libc/net/gethostnamadr.c
Fix multiple denial of service in ntpd.
[FreeBSD/FreeBSD.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
26 #include <sys/cdefs.h>
27 __FBSDID("$FreeBSD$");
28
29 #include "namespace.h"
30 #include "reentrant.h"
31 #include <sys/param.h>
32 #include <sys/socket.h>
33 #include <netinet/in.h>
34 #include <arpa/inet.h>
35 #include <netdb.h>
36 #include <stdio.h>
37 #include <ctype.h>
38 #include <errno.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <stdarg.h>
42 #include <nsswitch.h>
43 #include <arpa/nameser.h>               /* XXX hack for _res */
44 #include <resolv.h>                     /* XXX hack for _res */
45 #include "un-namespace.h"
46 #include "netdb_private.h"
47 #ifdef NS_CACHING
48 #include "nscache.h"
49 #endif
50
51 static int gethostbyname_internal(const char *, int, struct hostent *, char *,
52     size_t, struct hostent **, int *, res_state);
53
54 /* Host lookup order if nsswitch.conf is broken or nonexistent */
55 static const ns_src default_src[] = {
56         { NSSRC_FILES, NS_SUCCESS },
57         { NSSRC_DNS, NS_SUCCESS },
58         { 0 }
59 };
60 #ifdef NS_CACHING
61 static int host_id_func(char *, size_t *, va_list, void *);
62 static int host_marshal_func(char *, size_t *, void *, va_list, void *);
63 static int host_unmarshal_func(char *, size_t, void *, va_list, void *);
64 #endif
65
66 NETDB_THREAD_ALLOC(hostent)
67 NETDB_THREAD_ALLOC(hostent_data)
68 NETDB_THREAD_ALLOC(hostdata)
69
70 static void
71 hostent_free(void *ptr)
72 {
73         free(ptr);
74 }
75
76 static void
77 hostent_data_free(void *ptr)
78 {
79         struct hostent_data *hed = ptr;
80
81         if (hed == NULL)
82                 return;
83         hed->stayopen = 0;
84         _endhosthtent(hed);
85         free(hed);
86 }
87
88 static void
89 hostdata_free(void *ptr)
90 {
91         free(ptr);
92 }
93
94 int
95 __copy_hostent(struct hostent *he, struct hostent *hptr, char *buf,
96     size_t buflen)
97 {
98         char *cp;
99         char **ptr;
100         int i, n;
101         int nptr, len;
102
103         /* Find out the amount of space required to store the answer. */
104         nptr = 2; /* NULL ptrs */
105         len = (char *)ALIGN(buf) - buf;
106         for (i = 0; he->h_addr_list[i]; i++, nptr++) {
107                 len += he->h_length;
108         }
109         for (i = 0; he->h_aliases[i]; i++, nptr++) {
110                 len += strlen(he->h_aliases[i]) + 1;
111         }
112         len += strlen(he->h_name) + 1;
113         len += nptr * sizeof(char*);
114
115         if (len > buflen) {
116                 errno = ERANGE;
117                 return (-1);
118         }
119
120         /* copy address size and type */
121         hptr->h_addrtype = he->h_addrtype;
122         n = hptr->h_length = he->h_length;
123
124         ptr = (char **)ALIGN(buf);
125         cp = (char *)ALIGN(buf) + nptr * sizeof(char *);
126
127         /* copy address list */
128         hptr->h_addr_list = ptr;
129         for (i = 0; he->h_addr_list[i]; i++ , ptr++) {
130                 memcpy(cp, he->h_addr_list[i], n);
131                 hptr->h_addr_list[i] = cp;
132                 cp += n;
133         }
134         hptr->h_addr_list[i] = NULL;
135         ptr++;
136
137         /* copy official name */
138         n = strlen(he->h_name) + 1;
139         strcpy(cp, he->h_name);
140         hptr->h_name = cp;
141         cp += n;
142
143         /* copy aliases */
144         hptr->h_aliases = ptr;
145         for (i = 0 ; he->h_aliases[i]; i++) {
146                 n = strlen(he->h_aliases[i]) + 1;
147                 strcpy(cp, he->h_aliases[i]);
148                 hptr->h_aliases[i] = cp;
149                 cp += n;
150         }
151         hptr->h_aliases[i] = NULL;
152
153         return (0);
154 }
155
156 #ifdef NS_CACHING
157 static int
158 host_id_func(char *buffer, size_t *buffer_size, va_list ap, void *cache_mdata)
159 {
160         res_state statp;
161         u_long res_options;
162
163         const int op_id = 1;
164         char *str;
165         void *addr;
166         socklen_t len;
167         int type;
168
169         size_t desired_size, size;
170         enum nss_lookup_type lookup_type;
171         char *p;
172         int res = NS_UNAVAIL;
173
174         statp = __res_state();
175         res_options = statp->options & (RES_RECURSE | RES_DEFNAMES |
176             RES_DNSRCH | RES_NOALIASES | RES_USE_INET6);
177
178         lookup_type = (enum nss_lookup_type)cache_mdata;
179         switch (lookup_type) {
180         case nss_lt_name:
181                 str = va_arg(ap, char *);
182                 type = va_arg(ap, int);
183
184                 size = strlen(str);
185                 desired_size = sizeof(res_options) + sizeof(int) +
186                     sizeof(enum nss_lookup_type) + sizeof(int) + size + 1;
187
188                 if (desired_size > *buffer_size) {
189                         res = NS_RETURN;
190                         goto fin;
191                 }
192
193                 p = buffer;
194
195                 memcpy(p, &res_options, sizeof(res_options));
196                 p += sizeof(res_options);
197
198                 memcpy(p, &op_id, sizeof(int));
199                 p += sizeof(int);
200
201                 memcpy(p, &lookup_type, sizeof(enum nss_lookup_type));
202                 p += sizeof(int);
203
204                 memcpy(p, &type, sizeof(int));
205                 p += sizeof(int);
206
207                 memcpy(p, str, size + 1);
208
209                 res = NS_SUCCESS;
210                 break;
211         case nss_lt_id:
212                 addr = va_arg(ap, void *);
213                 len = va_arg(ap, socklen_t);
214                 type = va_arg(ap, int);
215
216                 desired_size = sizeof(res_options) + sizeof(int) +
217                     sizeof(enum nss_lookup_type) + sizeof(int) +
218                     sizeof(socklen_t) + len;
219
220                 if (desired_size > *buffer_size) {
221                         res = NS_RETURN;
222                         goto fin;
223                 }
224
225                 p = buffer;
226                 memcpy(p, &res_options, sizeof(res_options));
227                 p += sizeof(res_options);
228
229                 memcpy(p, &op_id, sizeof(int));
230                 p += sizeof(int);
231
232                 memcpy(p, &lookup_type, sizeof(enum nss_lookup_type));
233                 p += sizeof(int);
234
235                 memcpy(p, &type, sizeof(int));
236                 p += sizeof(int);
237
238                 memcpy(p, &len, sizeof(socklen_t));
239                 p += sizeof(socklen_t);
240
241                 memcpy(p, addr, len);
242
243                 res = NS_SUCCESS;
244                 break;
245         default:
246                 /* should be unreachable */
247                 return (NS_UNAVAIL);
248         }
249
250 fin:
251         *buffer_size = desired_size;
252         return (res);
253 }
254
255 static int
256 host_marshal_func(char *buffer, size_t *buffer_size, void *retval, va_list ap,
257     void *cache_mdata)
258 {
259         char *str;
260         void *addr;
261         socklen_t len;
262         int type;
263         struct hostent *ht;
264
265         struct hostent new_ht;
266         size_t desired_size, aliases_size, addr_size, size;
267         char *p, **iter;
268
269         switch ((enum nss_lookup_type)cache_mdata) {
270         case nss_lt_name:
271                 str = va_arg(ap, char *);
272                 type = va_arg(ap, int);
273                 break;
274         case nss_lt_id:
275                 addr = va_arg(ap, void *);
276                 len = va_arg(ap, socklen_t);
277                 type = va_arg(ap, int);
278                 break;
279         default:
280                 /* should be unreachable */
281                 return (NS_UNAVAIL);
282         }
283         ht = va_arg(ap, struct hostent *);
284
285         desired_size = _ALIGNBYTES + sizeof(struct hostent) + sizeof(char *);
286         if (ht->h_name != NULL)
287                 desired_size += strlen(ht->h_name) + 1;
288
289         if (ht->h_aliases != NULL) {
290                 aliases_size = 0;
291                 for (iter = ht->h_aliases; *iter; ++iter) {
292                         desired_size += strlen(*iter) + 1;
293                         ++aliases_size;
294                 }
295
296                 desired_size += _ALIGNBYTES +
297                     (aliases_size + 1) * sizeof(char *);
298         }
299
300         if (ht->h_addr_list != NULL) {
301                 addr_size = 0;
302                 for (iter = ht->h_addr_list; *iter; ++iter)
303                         ++addr_size;
304
305                 desired_size += addr_size * _ALIGN(ht->h_length);
306                 desired_size += _ALIGNBYTES + (addr_size + 1) * sizeof(char *);
307         }
308
309         if (desired_size > *buffer_size) {
310                 /* this assignment is here for future use */
311                 *buffer_size = desired_size;
312                 return (NS_RETURN);
313         }
314
315         memcpy(&new_ht, ht, sizeof(struct hostent));
316         memset(buffer, 0, desired_size);
317
318         *buffer_size = desired_size;
319         p = buffer + sizeof(struct hostent) + sizeof(char *);
320         memcpy(buffer + sizeof(struct hostent), &p, sizeof(char *));
321         p = (char *)_ALIGN(p);
322
323         if (new_ht.h_name != NULL) {
324                 size = strlen(new_ht.h_name);
325                 memcpy(p, new_ht.h_name, size);
326                 new_ht.h_name = p;
327                 p += size + 1;
328         }
329
330         if (new_ht.h_aliases != NULL) {
331                 p = (char *)_ALIGN(p);
332                 memcpy(p, new_ht.h_aliases, sizeof(char *) * aliases_size);
333                 new_ht.h_aliases = (char **)p;
334                 p += sizeof(char *) * (aliases_size + 1);
335
336                 for (iter = new_ht.h_aliases; *iter; ++iter) {
337                         size = strlen(*iter);
338                         memcpy(p, *iter, size);
339                         *iter = p;
340                         p += size + 1;
341                 }
342         }
343
344         if (new_ht.h_addr_list != NULL) {
345                 p = (char *)_ALIGN(p);
346                 memcpy(p, new_ht.h_addr_list, sizeof(char *) * addr_size);
347                 new_ht.h_addr_list = (char **)p;
348                 p += sizeof(char *) * (addr_size + 1);
349
350                 size = _ALIGN(new_ht.h_length);
351                 for (iter = new_ht.h_addr_list; *iter; ++iter) {
352                         memcpy(p, *iter, size);
353                         *iter = p;
354                         p += size + 1;
355                 }
356         }
357         memcpy(buffer, &new_ht, sizeof(struct hostent));
358         return (NS_SUCCESS);
359 }
360
361 static int
362 host_unmarshal_func(char *buffer, size_t buffer_size, void *retval, va_list ap,
363     void *cache_mdata)
364 {
365         char *str;
366         void *addr;
367         socklen_t len;
368         int type;
369         struct hostent *ht;
370
371         char *p;
372         char **iter;
373         char *orig_buf;
374         size_t orig_buf_size;
375
376         switch ((enum nss_lookup_type)cache_mdata) {
377         case nss_lt_name:
378                 str = va_arg(ap, char *);
379                 type = va_arg(ap, int);
380                 break;
381         case nss_lt_id:
382                 addr = va_arg(ap, void *);
383                 len = va_arg(ap, socklen_t);
384                 type = va_arg(ap, int);
385                 break;
386         default:
387                 /* should be unreachable */
388                 return (NS_UNAVAIL);
389         }
390
391         ht = va_arg(ap, struct hostent *);
392         orig_buf = va_arg(ap, char *);
393         orig_buf_size = va_arg(ap, size_t);
394
395         if (orig_buf_size <
396             buffer_size - sizeof(struct hostent) - sizeof(char *)) {
397                 errno = ERANGE;
398                 return (NS_RETURN);
399         }
400
401         memcpy(ht, buffer, sizeof(struct hostent));
402         memcpy(&p, buffer + sizeof(struct hostent), sizeof(char *));
403
404         orig_buf = (char *)_ALIGN(orig_buf);
405         memcpy(orig_buf, buffer + sizeof(struct hostent) + sizeof(char *) +
406             _ALIGN(p) - (size_t)p,
407             buffer_size - sizeof(struct hostent) - sizeof(char *) -
408             _ALIGN(p) + (size_t)p);
409         p = (char *)_ALIGN(p);
410
411         NS_APPLY_OFFSET(ht->h_name, orig_buf, p, char *);
412         if (ht->h_aliases != NULL) {
413                 NS_APPLY_OFFSET(ht->h_aliases, orig_buf, p, char **);
414
415                 for (iter = ht->h_aliases; *iter; ++iter)
416                         NS_APPLY_OFFSET(*iter, orig_buf, p, char *);
417         }
418
419         if (ht->h_addr_list != NULL) {
420                 NS_APPLY_OFFSET(ht->h_addr_list, orig_buf, p, char **);
421
422                 for (iter = ht->h_addr_list; *iter; ++iter)
423                         NS_APPLY_OFFSET(*iter, orig_buf, p, char *);
424         }
425
426         *((struct hostent **)retval) = ht;
427         return (NS_SUCCESS);
428 }
429 #endif /* NS_CACHING */
430
431 static int
432 fakeaddr(const char *name, int af, struct hostent *hp, char *buf,
433     size_t buflen, res_state statp)
434 {
435         struct hostent_data *hed;
436         struct hostent he;
437
438         if ((hed = __hostent_data_init()) == NULL) {
439                 errno = ENOMEM;
440                 RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
441                 return (-1);
442         }
443
444         if ((af != AF_INET ||
445             inet_aton(name, (struct in_addr *)hed->host_addr) != 1) &&
446             inet_pton(af, name, hed->host_addr) != 1) {
447                 RES_SET_H_ERRNO(statp, HOST_NOT_FOUND);
448                 return (-1);
449         }
450         strncpy(hed->hostbuf, name, MAXDNAME);
451         hed->hostbuf[MAXDNAME] = '\0';
452         if (af == AF_INET && (statp->options & RES_USE_INET6) != 0U) {
453                 _map_v4v6_address((char *)hed->host_addr,
454                     (char *)hed->host_addr);
455                 af = AF_INET6;
456         }
457         he.h_addrtype = af;
458         switch(af) {
459         case AF_INET:
460                 he.h_length = NS_INADDRSZ;
461                 break;
462         case AF_INET6:
463                 he.h_length = NS_IN6ADDRSZ;
464                 break;
465         default:
466                 errno = EAFNOSUPPORT;
467                 RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
468                 return (-1);
469         }
470         he.h_name = hed->hostbuf;
471         he.h_aliases = hed->host_aliases;
472         hed->host_aliases[0] = NULL;
473         hed->h_addr_ptrs[0] = (char *)hed->host_addr;
474         hed->h_addr_ptrs[1] = NULL;
475         he.h_addr_list = hed->h_addr_ptrs;
476         if (__copy_hostent(&he, hp, buf, buflen) != 0) {
477                 RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
478                 return (-1);
479         }
480         RES_SET_H_ERRNO(statp, NETDB_SUCCESS);
481         return (0);
482 }
483
484 int
485 gethostbyname_r(const char *name, struct hostent *he, char *buffer,
486     size_t buflen, struct hostent **result, int *h_errnop)
487 {
488         res_state statp;
489
490         statp = __res_state();
491         if ((statp->options & RES_INIT) == 0 && res_ninit(statp) == -1) {
492                 RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
493                 return (-1);
494         }
495         if (statp->options & RES_USE_INET6) {
496                 if (fakeaddr(name, AF_INET, he, buffer, buflen, statp) == 0) {
497                         *result = he;
498                         return (0);
499                 }
500                 if (gethostbyname_internal(name, AF_INET6, he, buffer, buflen,
501                     result, h_errnop, statp) == 0)
502                         return (0);
503         }
504         return (gethostbyname_internal(name, AF_INET, he, buffer, buflen,
505             result, h_errnop, statp));
506 }
507
508 int
509 gethostbyname2_r(const char *name, int af, struct hostent *he, char *buffer,
510     size_t buflen, struct hostent **result, int *h_errnop)
511 {
512         res_state statp;
513
514         statp = __res_state();
515         if ((statp->options & RES_INIT) == 0 && res_ninit(statp) == -1) {
516                 RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
517                 return (-1);
518         }
519         return (gethostbyname_internal(name, af, he, buffer, buflen, result,
520             h_errnop, statp));
521 }
522
523 int
524 gethostbyname_internal(const char *name, int af, struct hostent *hp, char *buf,
525     size_t buflen, struct hostent **result, int *h_errnop, res_state statp)
526 {
527         const char *cp;
528         int rval, ret_errno = 0;
529         char abuf[MAXDNAME];
530
531 #ifdef NS_CACHING
532         static const nss_cache_info cache_info =
533                 NS_COMMON_CACHE_INFO_INITIALIZER(
534                 hosts, (void *)nss_lt_name,
535                 host_id_func, host_marshal_func, host_unmarshal_func);
536 #endif
537         static const ns_dtab dtab[] = {
538                 NS_FILES_CB(_ht_gethostbyname, NULL)
539                 { NSSRC_DNS, _dns_gethostbyname, NULL },
540                 NS_NIS_CB(_nis_gethostbyname, NULL) /* force -DHESIOD */
541 #ifdef NS_CACHING
542                 NS_CACHE_CB(&cache_info)
543 #endif
544                 { 0 }
545         };
546
547         switch (af) {
548         case AF_INET:
549         case AF_INET6:
550                 break;
551         default:
552                 RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
553                 *h_errnop = statp->res_h_errno;
554                 errno = EAFNOSUPPORT;
555                 return (-1);
556         }
557
558         /*
559          * if there aren't any dots, it could be a user-level alias.
560          * this is also done in res_query() since we are not the only
561          * function that looks up host names.
562          */
563         if (!strchr(name, '.') &&
564             (cp = res_hostalias(statp, name, abuf, sizeof abuf)))
565                 name = cp;
566
567         if (fakeaddr(name, af, hp, buf, buflen, statp) == 0) {
568                 *result = hp;
569                 return (0);
570         }
571
572         rval = _nsdispatch((void *)result, dtab, NSDB_HOSTS,
573             "gethostbyname2_r", default_src, name, af, hp, buf, buflen,
574             &ret_errno, h_errnop);
575
576         if (rval != NS_SUCCESS) {
577                 errno = ret_errno;
578                 return ((ret_errno != 0) ? ret_errno : -1);
579         }
580         return (0);
581 }
582
583 int
584 gethostbyaddr_r(const void *addr, socklen_t len, int af, struct hostent *hp,
585     char *buf, size_t buflen, struct hostent **result, 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 = 0;
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         if (rval != NS_SUCCESS) {
656                 errno = ret_errno;
657                 return ((ret_errno != 0) ? ret_errno : -1);
658         }
659         return (0);
660 }
661
662 struct hostent *
663 gethostbyname(const char *name)
664 {
665         struct hostdata *hd;
666         struct hostent *rval;
667         int ret_h_errno;
668
669         if ((hd = __hostdata_init()) == NULL)
670                 return (NULL);
671         if (gethostbyname_r(name, &hd->host, hd->data, sizeof(hd->data), &rval,
672             &ret_h_errno) != 0)
673                 return (NULL);
674         return (rval);
675 }
676
677 struct hostent *
678 gethostbyname2(const char *name, int af)
679 {
680         struct hostdata *hd;
681         struct hostent *rval;
682         int ret_h_errno;
683
684         if ((hd = __hostdata_init()) == NULL)
685                 return (NULL);
686         if (gethostbyname2_r(name, af, &hd->host, hd->data, sizeof(hd->data),
687             &rval, &ret_h_errno) != 0)
688                 return (NULL);
689         return (rval);
690 }
691
692 struct hostent *
693 gethostbyaddr(const void *addr, socklen_t len, int af)
694 {
695         struct hostdata *hd;
696         struct hostent *rval;
697         int ret_h_errno;
698
699         if ((hd = __hostdata_init()) == NULL)
700                 return (NULL);
701         if (gethostbyaddr_r(addr, len, af, &hd->host, hd->data,
702             sizeof(hd->data), &rval, &ret_h_errno) != 0)
703                 return (NULL);
704         return (rval);
705 }
706
707 void
708 sethostent(int stayopen)
709 {
710         struct hostent_data *hed;
711
712         if ((hed = __hostent_data_init()) == NULL)
713                 return;
714         _sethosthtent(stayopen, hed);
715         _sethostdnsent(stayopen);
716 }
717
718 void
719 endhostent(void)
720 {
721         struct hostent_data *hed;
722
723         if ((hed = __hostent_data_init()) == NULL)
724                 return;
725         _endhosthtent(hed);
726         _endhostdnsent();
727 }