1 /* $OpenBSD: gethostnamadr_async.c,v 1.17 2013/04/03 21:13:50 eric Exp $ */ 2 /* 3 * Copyright (c) 2012 Eric Faurot <eric@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/types.h> 19 #include <sys/socket.h> 20 #include <netinet/in.h> 21 #include <arpa/inet.h> 22 #include <arpa/nameser.h> 23 #ifdef YP 24 #include <rpc/rpc.h> 25 #include <rpcsvc/yp.h> 26 #include <rpcsvc/ypclnt.h> 27 #include "ypinternal.h" 28 #endif 29 30 #include <ctype.h> 31 #include <err.h> 32 #include <errno.h> 33 #include <stdlib.h> 34 #include <string.h> 35 #include <unistd.h> 36 37 #include "asr.h" 38 #include "asr_private.h" 39 40 #define MAXALIASES 16 41 #define MAXADDRS 16 42 43 struct hostent_ext { 44 struct hostent h; 45 char *aliases[MAXALIASES + 1]; 46 char *addrs[MAXADDRS + 1]; 47 char *end; 48 char *pos; 49 }; 50 51 ssize_t addr_as_fqdn(const char *, int, char *, size_t); 52 53 static int gethostnamadr_async_run(struct async *, struct async_res *); 54 static struct hostent_ext *hostent_alloc(int); 55 static int hostent_set_cname(struct hostent_ext *, const char *, int); 56 static int hostent_add_alias(struct hostent_ext *, const char *, int); 57 static int hostent_add_addr(struct hostent_ext *, const void *, size_t); 58 static struct hostent_ext *hostent_from_addr(int, const char *, const char *); 59 static struct hostent_ext *hostent_file_match(FILE *, int, int, const char *, 60 int); 61 static struct hostent_ext *hostent_from_packet(int, int, char *, size_t); 62 #ifdef YP 63 static struct hostent_ext *_yp_gethostnamadr(int, const void *); 64 static struct hostent_ext *hostent_from_yp(int, char *); 65 #endif 66 67 struct async * 68 gethostbyname_async(const char *name, struct asr *asr) 69 { 70 return gethostbyname2_async(name, AF_INET, asr); 71 } 72 73 struct async * 74 gethostbyname2_async(const char *name, int af, struct asr *asr) 75 { 76 struct asr_ctx *ac; 77 struct async *as; 78 79 /* the original segfaults */ 80 if (name == NULL) { 81 errno = EINVAL; 82 return (NULL); 83 } 84 85 ac = asr_use_resolver(asr); 86 if ((as = async_new(ac, ASR_GETHOSTBYNAME)) == NULL) 87 goto abort; /* errno set */ 88 as->as_run = gethostnamadr_async_run; 89 90 as->as.hostnamadr.family = af; 91 if (af == AF_INET) 92 as->as.hostnamadr.addrlen = INADDRSZ; 93 else if (af == AF_INET6) 94 as->as.hostnamadr.addrlen = IN6ADDRSZ; 95 as->as.hostnamadr.name = strdup(name); 96 if (as->as.hostnamadr.name == NULL) 97 goto abort; /* errno set */ 98 99 asr_ctx_unref(ac); 100 return (as); 101 102 abort: 103 if (as) 104 async_free(as); 105 asr_ctx_unref(ac); 106 return (NULL); 107 } 108 109 struct async * 110 gethostbyaddr_async(const void *addr, socklen_t len, int af, struct asr *asr) 111 { 112 struct asr_ctx *ac; 113 struct async *as; 114 115 ac = asr_use_resolver(asr); 116 as = gethostbyaddr_async_ctx(addr, len, af, ac); 117 asr_ctx_unref(ac); 118 119 return (as); 120 } 121 122 struct async * 123 gethostbyaddr_async_ctx(const void *addr, socklen_t len, int af, 124 struct asr_ctx *ac) 125 { 126 struct async *as; 127 128 if ((as = async_new(ac, ASR_GETHOSTBYADDR)) == NULL) 129 goto abort; /* errno set */ 130 as->as_run = gethostnamadr_async_run; 131 132 as->as.hostnamadr.family = af; 133 as->as.hostnamadr.addrlen = len; 134 if (len > 0) 135 memmove(as->as.hostnamadr.addr, addr, (len > 16) ? 16 : len); 136 137 return (as); 138 139 abort: 140 if (as) 141 async_free(as); 142 return (NULL); 143 } 144 145 static int 146 gethostnamadr_async_run(struct async *as, struct async_res *ar) 147 { 148 struct hostent_ext *h; 149 int r, type, saved_errno; 150 FILE *f; 151 char dname[MAXDNAME], *data, addr[16], *c; 152 153 next: 154 switch (as->as_state) { 155 156 case ASR_STATE_INIT: 157 158 if (as->as.hostnamadr.family != AF_INET && 159 as->as.hostnamadr.family != AF_INET6) { 160 ar->ar_h_errno = NETDB_INTERNAL; 161 ar->ar_errno = EAFNOSUPPORT; 162 async_set_state(as, ASR_STATE_HALT); 163 break; 164 } 165 166 if ((as->as.hostnamadr.family == AF_INET && 167 as->as.hostnamadr.addrlen != INADDRSZ) || 168 (as->as.hostnamadr.family == AF_INET6 && 169 as->as.hostnamadr.addrlen != IN6ADDRSZ)) { 170 ar->ar_h_errno = NETDB_INTERNAL; 171 ar->ar_errno = EINVAL; 172 async_set_state(as, ASR_STATE_HALT); 173 break; 174 } 175 176 /* Name might be an IP address string */ 177 if (as->as_type == ASR_GETHOSTBYNAME) { 178 for (c = as->as.hostnamadr.name; *c; c++) 179 if (!isdigit(*c) && *c != '.' && *c != ':') 180 break; 181 if (*c == 0 && 182 inet_pton(as->as.hostnamadr.family, 183 as->as.hostnamadr.name, addr) == 1) { 184 h = hostent_from_addr(as->as.hostnamadr.family, 185 as->as.hostnamadr.name, addr); 186 if (h == NULL) { 187 ar->ar_errno = errno; 188 ar->ar_h_errno = NETDB_INTERNAL; 189 } 190 else { 191 ar->ar_hostent = &h->h; 192 ar->ar_h_errno = NETDB_SUCCESS; 193 } 194 async_set_state(as, ASR_STATE_HALT); 195 break; 196 } 197 } 198 async_set_state(as, ASR_STATE_NEXT_DB); 199 break; 200 201 case ASR_STATE_NEXT_DB: 202 203 if (asr_iter_db(as) == -1) { 204 async_set_state(as, ASR_STATE_NOT_FOUND); 205 break; 206 } 207 208 switch (AS_DB(as)) { 209 210 case ASR_DB_DNS: 211 212 /* Create a subquery to do the DNS lookup */ 213 214 if (as->as_type == ASR_GETHOSTBYNAME) { 215 type = (as->as.hostnamadr.family == AF_INET) ? 216 T_A : T_AAAA; 217 as->as.hostnamadr.subq = res_search_async_ctx( 218 as->as.hostnamadr.name, 219 C_IN, type, NULL, 0, as->as_ctx); 220 } else { 221 addr_as_fqdn(as->as.hostnamadr.addr, 222 as->as.hostnamadr.family, 223 dname, sizeof(dname)); 224 as->as.hostnamadr.subq = res_query_async_ctx( 225 dname, C_IN, T_PTR, NULL, 0, as->as_ctx); 226 } 227 228 if (as->as.hostnamadr.subq == NULL) { 229 ar->ar_errno = errno; 230 ar->ar_h_errno = NETDB_INTERNAL; 231 async_set_state(as, ASR_STATE_HALT); 232 break; 233 } 234 235 async_set_state(as, ASR_STATE_SUBQUERY); 236 break; 237 238 case ASR_DB_FILE: 239 240 /* Try to find a match in the host file */ 241 242 if ((f = fopen(as->as_ctx->ac_hostfile, "r")) == NULL) 243 break; 244 245 if (as->as_type == ASR_GETHOSTBYNAME) 246 data = as->as.hostnamadr.name; 247 else 248 data = as->as.hostnamadr.addr; 249 250 h = hostent_file_match(f, as->as_type, 251 as->as.hostnamadr.family, data, 252 as->as.hostnamadr.addrlen); 253 saved_errno = errno; 254 fclose(f); 255 errno = saved_errno; 256 257 if (h == NULL) { 258 if (errno) { 259 ar->ar_errno = errno; 260 ar->ar_h_errno = NETDB_INTERNAL; 261 async_set_state(as, ASR_STATE_HALT); 262 } 263 /* otherwise not found */ 264 break; 265 } 266 ar->ar_hostent = &h->h; 267 ar->ar_h_errno = NETDB_SUCCESS; 268 async_set_state(as, ASR_STATE_HALT); 269 break; 270 #ifdef YP 271 case ASR_DB_YP: 272 /* IPv4 only */ 273 if (as->as.hostnamadr.family != AF_INET) 274 break; 275 if (as->as_type == ASR_GETHOSTBYNAME) 276 data = as->as.hostnamadr.name; 277 else 278 data = as->as.hostnamadr.addr; 279 h = _yp_gethostnamadr(as->as_type, data); 280 if (h == NULL) { 281 if (errno) { 282 ar->ar_errno = errno; 283 ar->ar_h_errno = NETDB_INTERNAL; 284 async_set_state(as, ASR_STATE_HALT); 285 } 286 /* otherwise not found */ 287 break; 288 } 289 ar->ar_hostent = &h->h; 290 ar->ar_h_errno = NETDB_SUCCESS; 291 async_set_state(as, ASR_STATE_HALT); 292 break; 293 #endif 294 } 295 break; 296 297 case ASR_STATE_SUBQUERY: 298 299 /* Run the DNS subquery. */ 300 301 if ((r = async_run(as->as.hostnamadr.subq, ar)) == ASYNC_COND) 302 return (ASYNC_COND); 303 304 /* Done. */ 305 as->as.hostnamadr.subq = NULL; 306 307 if (ar->ar_datalen == -1) { 308 async_set_state(as, ASR_STATE_NEXT_DB); 309 break; 310 } 311 312 /* If we got a packet but no anwser, use the next DB. */ 313 if (ar->ar_count == 0) { 314 free(ar->ar_data); 315 as->as.hostnamadr.subq_h_errno = ar->ar_h_errno; 316 async_set_state(as, ASR_STATE_NEXT_DB); 317 break; 318 } 319 320 /* Read the hostent from the packet. */ 321 322 h = hostent_from_packet(as->as_type, 323 as->as.hostnamadr.family, ar->ar_data, ar->ar_datalen); 324 free(ar->ar_data); 325 if (h == NULL) { 326 ar->ar_errno = errno; 327 ar->ar_h_errno = NETDB_INTERNAL; 328 async_set_state(as, ASR_STATE_HALT); 329 break; 330 } 331 332 if (as->as_type == ASR_GETHOSTBYADDR) { 333 if (hostent_add_addr(h, as->as.hostnamadr.addr, 334 as->as.hostnamadr.addrlen) == -1) { 335 free(h); 336 ar->ar_errno = errno; 337 ar->ar_h_errno = NETDB_INTERNAL; 338 async_set_state(as, ASR_STATE_HALT); 339 break; 340 } 341 } 342 343 /* 344 * No address found in the dns packet. The blocking version 345 * reports this as an error. 346 */ 347 if ((as->as_type == ASR_GETHOSTBYNAME && 348 h->h.h_addr_list[0] == NULL) || 349 (as->as_type == ASR_GETHOSTBYADDR && 350 h->h.h_name == NULL)) { 351 free(h); 352 async_set_state(as, ASR_STATE_NEXT_DB); 353 break; 354 } 355 356 ar->ar_hostent = &h->h; 357 ar->ar_h_errno = NETDB_SUCCESS; 358 async_set_state(as, ASR_STATE_HALT); 359 break; 360 361 case ASR_STATE_NOT_FOUND: 362 ar->ar_errno = 0; 363 if (as->as.hostnamadr.subq_h_errno) 364 ar->ar_h_errno = as->as.hostnamadr.subq_h_errno; 365 else 366 ar->ar_h_errno = HOST_NOT_FOUND; 367 async_set_state(as, ASR_STATE_HALT); 368 break; 369 370 case ASR_STATE_HALT: 371 if (ar->ar_h_errno) 372 ar->ar_hostent = NULL; 373 else 374 ar->ar_errno = 0; 375 return (ASYNC_DONE); 376 377 default: 378 ar->ar_errno = EOPNOTSUPP; 379 ar->ar_h_errno = NETDB_INTERNAL; 380 ar->ar_gai_errno = EAI_SYSTEM; 381 async_set_state(as, ASR_STATE_HALT); 382 break; 383 } 384 goto next; 385 } 386 387 /* 388 * Create a hostent from a numeric address string. 389 */ 390 static struct hostent_ext * 391 hostent_from_addr(int family, const char *name, const char *addr) 392 { 393 struct hostent_ext *h; 394 395 if ((h = hostent_alloc(family)) == NULL) 396 return (NULL); 397 if (hostent_set_cname(h, name, 0) == -1) 398 goto fail; 399 if (hostent_add_addr(h, addr, h->h.h_length) == -1) 400 goto fail; 401 return (h); 402 fail: 403 free(h); 404 return (NULL); 405 } 406 407 /* 408 * Lookup the first matching entry in the hostfile, either by address or by 409 * name depending on reqtype, and build a hostent from the line. 410 */ 411 static struct hostent_ext * 412 hostent_file_match(FILE *f, int reqtype, int family, const char *data, 413 int datalen) 414 { 415 char *tokens[MAXTOKEN], addr[16]; 416 struct hostent_ext *h; 417 int n, i; 418 419 for (;;) { 420 n = asr_parse_namedb_line(f, tokens, MAXTOKEN); 421 if (n == -1) { 422 errno = 0; /* ignore errors reading the file */ 423 return (NULL); 424 } 425 426 if (reqtype == ASR_GETHOSTBYNAME) { 427 for (i = 1; i < n; i++) { 428 if (strcasecmp(data, tokens[i])) 429 continue; 430 if (inet_pton(family, tokens[0], addr) == 1) 431 goto found; 432 } 433 } else { 434 if (inet_pton(family, tokens[0], addr) == 1 && 435 memcmp(addr, data, datalen) == 0) 436 goto found; 437 } 438 } 439 440 found: 441 if ((h = hostent_alloc(family)) == NULL) 442 return (NULL); 443 if (hostent_set_cname(h, tokens[1], 0) == -1) 444 goto fail; 445 for (i = 2; i < n; i ++) 446 if (hostent_add_alias(h, tokens[i], 0) == -1) 447 goto fail; 448 if (hostent_add_addr(h, addr, h->h.h_length) == -1) 449 goto fail; 450 return (h); 451 fail: 452 free(h); 453 return (NULL); 454 } 455 456 /* 457 * Fill the hostent from the given DNS packet. 458 */ 459 static struct hostent_ext * 460 hostent_from_packet(int reqtype, int family, char *pkt, size_t pktlen) 461 { 462 struct hostent_ext *h; 463 struct unpack p; 464 struct header hdr; 465 struct query q; 466 struct rr rr; 467 char dname[MAXDNAME]; 468 469 if ((h = hostent_alloc(family)) == NULL) 470 return (NULL); 471 472 unpack_init(&p, pkt, pktlen); 473 unpack_header(&p, &hdr); 474 for (; hdr.qdcount; hdr.qdcount--) 475 unpack_query(&p, &q); 476 strlcpy(dname, q.q_dname, sizeof(dname)); 477 478 for (; hdr.ancount; hdr.ancount--) { 479 unpack_rr(&p, &rr); 480 if (rr.rr_class != C_IN) 481 continue; 482 switch (rr.rr_type) { 483 484 case T_CNAME: 485 if (reqtype == ASR_GETHOSTBYNAME) { 486 if (hostent_add_alias(h, rr.rr_dname, 1) == -1) 487 goto fail; 488 } else { 489 if (strcasecmp(rr.rr_dname, dname) == 0) 490 strlcpy(dname, rr.rr.cname.cname, 491 sizeof(dname)); 492 } 493 break; 494 495 case T_PTR: 496 if (reqtype != ASR_GETHOSTBYADDR) 497 break; 498 if (strcasecmp(rr.rr_dname, dname) != 0) 499 continue; 500 if (hostent_set_cname(h, rr.rr.ptr.ptrname, 1) == -1) 501 goto fail; 502 /* XXX See if we need MULTI_PTRS_ARE_ALIASES */ 503 break; 504 505 case T_A: 506 if (reqtype != ASR_GETHOSTBYNAME) 507 break; 508 if (family != AF_INET) 509 break; 510 if (hostent_set_cname(h, rr.rr_dname, 1) == -1) 511 ; 512 if (hostent_add_addr(h, &rr.rr.in_a.addr, 4) == -1) 513 goto fail; 514 break; 515 516 case T_AAAA: 517 if (reqtype != ASR_GETHOSTBYNAME) 518 break; 519 if (family != AF_INET6) 520 break; 521 if (hostent_set_cname(h, rr.rr_dname, 1) == -1) 522 ; 523 if (hostent_add_addr(h, &rr.rr.in_aaaa.addr6, 16) == -1) 524 goto fail; 525 break; 526 } 527 } 528 529 return (h); 530 fail: 531 free(h); 532 return (NULL); 533 } 534 535 static struct hostent_ext * 536 hostent_alloc(int family) 537 { 538 struct hostent_ext *h; 539 size_t alloc; 540 541 alloc = sizeof(*h) + 1024; 542 if ((h = calloc(1, alloc)) == NULL) 543 return (NULL); 544 545 h->h.h_addrtype = family; 546 h->h.h_length = (family == AF_INET) ? 4 : 16; 547 h->h.h_aliases = h->aliases; 548 h->h.h_addr_list = h->addrs; 549 h->pos = (char *)(h) + sizeof(*h); 550 h->end = h->pos + 1024; 551 552 return (h); 553 } 554 555 static int 556 hostent_set_cname(struct hostent_ext *h, const char *name, int isdname) 557 { 558 char buf[MAXDNAME]; 559 size_t n; 560 561 if (h->h.h_name) 562 return (-1); 563 564 if (isdname) { 565 asr_strdname(name, buf, sizeof buf); 566 buf[strlen(buf) - 1] = '\0'; 567 name = buf; 568 } 569 570 n = strlen(name) + 1; 571 if (h->pos + n >= h->end) 572 return (-1); 573 574 h->h.h_name = h->pos; 575 memmove(h->pos, name, n); 576 h->pos += n; 577 return (0); 578 } 579 580 static int 581 hostent_add_alias(struct hostent_ext *h, const char *name, int isdname) 582 { 583 char buf[MAXDNAME]; 584 size_t i, n; 585 586 for (i = 0; i < MAXALIASES; i++) 587 if (h->aliases[i] == NULL) 588 break; 589 if (i == MAXALIASES) 590 return (-1); 591 592 if (isdname) { 593 asr_strdname(name, buf, sizeof buf); 594 buf[strlen(buf)-1] = '\0'; 595 name = buf; 596 } 597 598 n = strlen(name) + 1; 599 if (h->pos + n >= h->end) 600 return (-1); 601 602 h->aliases[i] = h->pos; 603 memmove(h->pos, name, n); 604 h->pos += n; 605 return (0); 606 } 607 608 static int 609 hostent_add_addr(struct hostent_ext *h, const void *addr, size_t size) 610 { 611 int i; 612 613 for (i = 0; i < MAXADDRS; i++) 614 if (h->addrs[i] == NULL) 615 break; 616 if (i == MAXADDRS) 617 return (-1); 618 619 if (h->pos + size >= h->end) 620 return (-1); 621 622 h->addrs[i] = h->pos; 623 memmove(h->pos, addr, size); 624 h->pos += size; 625 return (0); 626 } 627 628 ssize_t 629 addr_as_fqdn(const char *addr, int family, char *dst, size_t max) 630 { 631 const struct in6_addr *in6_addr; 632 in_addr_t in_addr; 633 634 switch (family) { 635 case AF_INET: 636 in_addr = ntohl(*((const in_addr_t *)addr)); 637 snprintf(dst, max, 638 "%d.%d.%d.%d.in-addr.arpa.", 639 in_addr & 0xff, 640 (in_addr >> 8) & 0xff, 641 (in_addr >> 16) & 0xff, 642 (in_addr >> 24) & 0xff); 643 break; 644 case AF_INET6: 645 in6_addr = (const struct in6_addr *)addr; 646 snprintf(dst, max, 647 "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x." 648 "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x." 649 "ip6.arpa.", 650 in6_addr->s6_addr[15] & 0xf, 651 (in6_addr->s6_addr[15] >> 4) & 0xf, 652 in6_addr->s6_addr[14] & 0xf, 653 (in6_addr->s6_addr[14] >> 4) & 0xf, 654 in6_addr->s6_addr[13] & 0xf, 655 (in6_addr->s6_addr[13] >> 4) & 0xf, 656 in6_addr->s6_addr[12] & 0xf, 657 (in6_addr->s6_addr[12] >> 4) & 0xf, 658 in6_addr->s6_addr[11] & 0xf, 659 (in6_addr->s6_addr[11] >> 4) & 0xf, 660 in6_addr->s6_addr[10] & 0xf, 661 (in6_addr->s6_addr[10] >> 4) & 0xf, 662 in6_addr->s6_addr[9] & 0xf, 663 (in6_addr->s6_addr[9] >> 4) & 0xf, 664 in6_addr->s6_addr[8] & 0xf, 665 (in6_addr->s6_addr[8] >> 4) & 0xf, 666 in6_addr->s6_addr[7] & 0xf, 667 (in6_addr->s6_addr[7] >> 4) & 0xf, 668 in6_addr->s6_addr[6] & 0xf, 669 (in6_addr->s6_addr[6] >> 4) & 0xf, 670 in6_addr->s6_addr[5] & 0xf, 671 (in6_addr->s6_addr[5] >> 4) & 0xf, 672 in6_addr->s6_addr[4] & 0xf, 673 (in6_addr->s6_addr[4] >> 4) & 0xf, 674 in6_addr->s6_addr[3] & 0xf, 675 (in6_addr->s6_addr[3] >> 4) & 0xf, 676 in6_addr->s6_addr[2] & 0xf, 677 (in6_addr->s6_addr[2] >> 4) & 0xf, 678 in6_addr->s6_addr[1] & 0xf, 679 (in6_addr->s6_addr[1] >> 4) & 0xf, 680 in6_addr->s6_addr[0] & 0xf, 681 (in6_addr->s6_addr[0] >> 4) & 0xf); 682 break; 683 default: 684 return (-1); 685 } 686 return (0); 687 } 688 689 #ifdef YP 690 static struct hostent_ext * 691 _yp_gethostnamadr(int type, const void *data) 692 { 693 static char *domain = NULL; 694 struct hostent_ext *h = NULL; 695 const char *name; 696 char buf[MAXHOSTNAMELEN]; 697 char *res = NULL; 698 int r, len; 699 700 if (!domain && _yp_check(&domain) == 0) { 701 errno = 0; /* ignore yp_bind errors */ 702 return (NULL); 703 } 704 705 if (type == ASR_GETHOSTBYNAME) { 706 name = data; 707 len = strlen(name); 708 r = yp_match(domain, "hosts.byname", name, len, &res, &len); 709 } 710 else { 711 if (inet_ntop(AF_INET, data, buf, sizeof buf) == NULL) 712 return (NULL); 713 len = strlen(buf); 714 r = yp_match(domain, "hosts.byaddr", buf, len, &res, &len); 715 } 716 if (r == 0) { 717 h = hostent_from_yp(AF_INET, res); 718 } else { 719 errno = 0; /* ignore error if not found */ 720 } 721 if (res) 722 free(res); 723 return (h); 724 } 725 726 static int 727 strsplit(char *line, char **tokens, int ntokens) 728 { 729 int ntok; 730 char *cp, **tp; 731 732 for (cp = line, tp = tokens, ntok = 0; 733 ntok < ntokens && (*tp = strsep(&cp, " \t")) != NULL; ) 734 if (**tp != '\0') { 735 tp++; 736 ntok++; 737 } 738 739 return (ntok); 740 } 741 742 static struct hostent_ext * 743 hostent_from_yp(int family, char *line) 744 { 745 struct hostent_ext *h; 746 char *next, *tokens[10], addr[IN6ADDRSZ]; 747 int i, ntok; 748 749 if ((h = hostent_alloc(family)) == NULL) 750 return (NULL); 751 752 for (next = line; line; line = next) { 753 if ((next = strchr(line, '\n'))) { 754 *next = '\0'; 755 next += 1; 756 } 757 ntok = strsplit(line, tokens, 10); 758 if (ntok < 2) 759 continue; 760 if (inet_pton(family, tokens[0], addr) == 1) 761 hostent_add_addr(h, addr, family == AF_INET ? 762 INADDRSZ : IN6ADDRSZ); 763 i = 2; 764 if (h->h.h_name == NULL) 765 hostent_set_cname(h, tokens[1], 0); 766 else if (strcmp(h->h.h_name, tokens[1])) 767 i = 1; 768 for (; i < ntok; i++) 769 hostent_add_alias(h, tokens[i], 0); 770 } 771 772 if (h->h.h_name == NULL) { 773 free(h); 774 return (NULL); 775 } 776 777 return (h); 778 } 779 #endif 780