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 } 724