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