1 /* $OpenBSD: gethostnamadr_async.c,v 1.14 2013/03/29 20:04:17 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.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 free(h); 350 async_set_state(as, ASR_STATE_NEXT_DB); 351 break; 352 } 353 354 ar->ar_hostent = &h->h; 355 ar->ar_h_errno = NETDB_SUCCESS; 356 async_set_state(as, ASR_STATE_HALT); 357 break; 358 359 case ASR_STATE_NOT_FOUND: 360 ar->ar_errno = 0; 361 if (as->as.hostnamadr.h_errno) 362 ar->ar_h_errno = as->as.hostnamadr.h_errno; 363 else 364 ar->ar_h_errno = HOST_NOT_FOUND; 365 async_set_state(as, ASR_STATE_HALT); 366 break; 367 368 case ASR_STATE_HALT: 369 if (ar->ar_h_errno) 370 ar->ar_hostent = NULL; 371 else 372 ar->ar_errno = 0; 373 return (ASYNC_DONE); 374 375 default: 376 ar->ar_errno = EOPNOTSUPP; 377 ar->ar_h_errno = NETDB_INTERNAL; 378 ar->ar_gai_errno = EAI_SYSTEM; 379 async_set_state(as, ASR_STATE_HALT); 380 break; 381 } 382 goto next; 383 } 384 385 /* 386 * Create a hostent from a numeric address string. 387 */ 388 static struct hostent_ext * 389 hostent_from_addr(int family, const char *name, const char *addr) 390 { 391 struct hostent_ext *h; 392 393 if ((h = hostent_alloc(family)) == NULL) 394 return (NULL); 395 if (hostent_set_cname(h, name, 0) == -1) 396 goto fail; 397 if (hostent_add_addr(h, addr, h->h.h_length) == -1) 398 goto fail; 399 return (h); 400 fail: 401 free(h); 402 return (NULL); 403 } 404 405 /* 406 * Lookup the first matching entry in the hostfile, either by address or by 407 * name depending on reqtype, and build a hostent from the line. 408 */ 409 static struct hostent_ext * 410 hostent_file_match(FILE *f, int reqtype, int family, const char *data, 411 int datalen) 412 { 413 char *tokens[MAXTOKEN], addr[16]; 414 struct hostent_ext *h; 415 int n, i; 416 417 for (;;) { 418 n = asr_parse_namedb_line(f, tokens, MAXTOKEN); 419 if (n == -1) { 420 errno = 0; /* ignore errors reading the file */ 421 return (NULL); 422 } 423 424 if (reqtype == ASR_GETHOSTBYNAME) { 425 for (i = 1; i < n; i++) { 426 if (strcasecmp(data, tokens[i])) 427 continue; 428 if (inet_pton(family, tokens[0], addr) == 1) 429 goto found; 430 } 431 } else { 432 if (inet_pton(family, tokens[0], addr) == 1 && 433 memcmp(addr, data, datalen) == 0) 434 goto found; 435 } 436 } 437 438 found: 439 if ((h = hostent_alloc(family)) == NULL) 440 return (NULL); 441 if (hostent_set_cname(h, tokens[1], 0) == -1) 442 goto fail; 443 for (i = 2; i < n; i ++) 444 if (hostent_add_alias(h, tokens[i], 0) == -1) 445 goto fail; 446 if (hostent_add_addr(h, addr, h->h.h_length) == -1) 447 goto fail; 448 return (h); 449 fail: 450 free(h); 451 return (NULL); 452 } 453 454 /* 455 * Fill the hostent from the given DNS packet. 456 */ 457 static struct hostent_ext * 458 hostent_from_packet(int reqtype, int family, char *pkt, size_t pktlen) 459 { 460 struct hostent_ext *h; 461 struct unpack p; 462 struct header hdr; 463 struct query q; 464 struct rr rr; 465 466 if ((h = hostent_alloc(family)) == NULL) 467 return (NULL); 468 469 unpack_init(&p, pkt, pktlen); 470 unpack_header(&p, &hdr); 471 for (; hdr.qdcount; hdr.qdcount--) 472 unpack_query(&p, &q); 473 for (; hdr.ancount; hdr.ancount--) { 474 unpack_rr(&p, &rr); 475 if (rr.rr_class != C_IN) 476 continue; 477 switch (rr.rr_type) { 478 479 case T_CNAME: 480 if (reqtype == ASR_GETHOSTBYNAME) { 481 if (hostent_add_alias(h, rr.rr_dname, 1) == -1) 482 goto fail; 483 } else { 484 if (hostent_set_cname(h, rr.rr_dname, 1) == -1) 485 goto fail; 486 } 487 break; 488 489 case T_PTR: 490 if (reqtype != ASR_GETHOSTBYADDR) 491 break; 492 if (hostent_set_cname(h, rr.rr.ptr.ptrname, 1) == -1) 493 goto fail; 494 /* XXX See if we need MULTI_PTRS_ARE_ALIASES */ 495 break; 496 497 case T_A: 498 if (reqtype != ASR_GETHOSTBYNAME) 499 break; 500 if (family != AF_INET) 501 break; 502 if (hostent_set_cname(h, rr.rr_dname, 1) == -1) 503 ; 504 if (hostent_add_addr(h, &rr.rr.in_a.addr, 4) == -1) 505 goto fail; 506 break; 507 508 case T_AAAA: 509 if (reqtype != ASR_GETHOSTBYNAME) 510 break; 511 if (family != AF_INET6) 512 break; 513 if (hostent_set_cname(h, rr.rr_dname, 1) == -1) 514 ; 515 if (hostent_add_addr(h, &rr.rr.in_aaaa.addr6, 16) == -1) 516 goto fail; 517 break; 518 } 519 } 520 521 return (h); 522 fail: 523 free(h); 524 return (NULL); 525 } 526 527 static struct hostent_ext * 528 hostent_alloc(int family) 529 { 530 struct hostent_ext *h; 531 size_t alloc; 532 533 alloc = sizeof(*h) + 1024; 534 if ((h = calloc(1, alloc)) == NULL) 535 return (NULL); 536 537 h->h.h_addrtype = family; 538 h->h.h_length = (family == AF_INET) ? 4 : 16; 539 h->h.h_aliases = h->aliases; 540 h->h.h_addr_list = h->addrs; 541 h->pos = (char*)(h) + sizeof(*h); 542 h->end = h->pos + 1024; 543 544 return (h); 545 } 546 547 static int 548 hostent_set_cname(struct hostent_ext *h, const char *name, int isdname) 549 { 550 char buf[MAXDNAME]; 551 size_t n; 552 553 if (h->h.h_name) 554 return (-1); 555 556 if (isdname) { 557 asr_strdname(name, buf, sizeof buf); 558 buf[strlen(buf) - 1] = '\0'; 559 name = buf; 560 } 561 562 n = strlen(name) + 1; 563 if (h->pos + n >= h->end) 564 return (-1); 565 566 h->h.h_name = h->pos; 567 memmove(h->pos, name, n); 568 h->pos += n; 569 return (0); 570 } 571 572 static int 573 hostent_add_alias(struct hostent_ext *h, const char *name, int isdname) 574 { 575 char buf[MAXDNAME]; 576 size_t i, n; 577 578 for (i = 0; i < MAXALIASES; i++) 579 if (h->aliases[i] == NULL) 580 break; 581 if (i == MAXALIASES) 582 return (-1); 583 584 if (isdname) { 585 asr_strdname(name, buf, sizeof buf); 586 buf[strlen(buf)-1] = '\0'; 587 name = buf; 588 } 589 590 n = strlen(name) + 1; 591 if (h->pos + n >= h->end) 592 return (-1); 593 594 h->aliases[i] = h->pos; 595 memmove(h->pos, name, n); 596 h->pos += n; 597 return (0); 598 } 599 600 static int 601 hostent_add_addr(struct hostent_ext *h, const void *addr, size_t size) 602 { 603 int i; 604 605 for (i = 0; i < MAXADDRS; i++) 606 if (h->addrs[i] == NULL) 607 break; 608 if (i == MAXADDRS) 609 return (-1); 610 611 if (h->pos + size >= h->end) 612 return (-1); 613 614 h->addrs[i] = h->pos; 615 memmove(h->pos, addr, size); 616 h->pos += size; 617 return (0); 618 } 619 620 ssize_t 621 addr_as_fqdn(const char *addr, int family, char *dst, size_t max) 622 { 623 const struct in6_addr *in6_addr; 624 in_addr_t in_addr; 625 626 switch (family) { 627 case AF_INET: 628 in_addr = ntohl(*((const in_addr_t *)addr)); 629 snprintf(dst, max, 630 "%d.%d.%d.%d.in-addr.arpa.", 631 in_addr & 0xff, 632 (in_addr >> 8) & 0xff, 633 (in_addr >> 16) & 0xff, 634 (in_addr >> 24) & 0xff); 635 break; 636 case AF_INET6: 637 in6_addr = (const struct in6_addr *)addr; 638 snprintf(dst, max, 639 "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x." 640 "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x." 641 "ip6.arpa.", 642 in6_addr->s6_addr[15] & 0xf, 643 (in6_addr->s6_addr[15] >> 4) & 0xf, 644 in6_addr->s6_addr[14] & 0xf, 645 (in6_addr->s6_addr[14] >> 4) & 0xf, 646 in6_addr->s6_addr[13] & 0xf, 647 (in6_addr->s6_addr[13] >> 4) & 0xf, 648 in6_addr->s6_addr[12] & 0xf, 649 (in6_addr->s6_addr[12] >> 4) & 0xf, 650 in6_addr->s6_addr[11] & 0xf, 651 (in6_addr->s6_addr[11] >> 4) & 0xf, 652 in6_addr->s6_addr[10] & 0xf, 653 (in6_addr->s6_addr[10] >> 4) & 0xf, 654 in6_addr->s6_addr[9] & 0xf, 655 (in6_addr->s6_addr[9] >> 4) & 0xf, 656 in6_addr->s6_addr[8] & 0xf, 657 (in6_addr->s6_addr[8] >> 4) & 0xf, 658 in6_addr->s6_addr[7] & 0xf, 659 (in6_addr->s6_addr[7] >> 4) & 0xf, 660 in6_addr->s6_addr[6] & 0xf, 661 (in6_addr->s6_addr[6] >> 4) & 0xf, 662 in6_addr->s6_addr[5] & 0xf, 663 (in6_addr->s6_addr[5] >> 4) & 0xf, 664 in6_addr->s6_addr[4] & 0xf, 665 (in6_addr->s6_addr[4] >> 4) & 0xf, 666 in6_addr->s6_addr[3] & 0xf, 667 (in6_addr->s6_addr[3] >> 4) & 0xf, 668 in6_addr->s6_addr[2] & 0xf, 669 (in6_addr->s6_addr[2] >> 4) & 0xf, 670 in6_addr->s6_addr[1] & 0xf, 671 (in6_addr->s6_addr[1] >> 4) & 0xf, 672 in6_addr->s6_addr[0] & 0xf, 673 (in6_addr->s6_addr[0] >> 4) & 0xf); 674 break; 675 default: 676 return (-1); 677 } 678 return (0); 679 } 680 681 #ifdef YP 682 static struct hostent_ext * 683 _yp_gethostnamadr(int type, const void *data) 684 { 685 static char *domain = NULL; 686 struct hostent_ext *h = NULL; 687 const char *name; 688 char buf[MAXHOSTNAMELEN]; 689 char *res = NULL; 690 int r, len; 691 692 if (!domain && _yp_check(&domain) == 0) { 693 errno = 0; /* ignore yp_bind errors */ 694 return (NULL); 695 } 696 697 if (type == ASR_GETHOSTBYNAME) { 698 name = data; 699 len = strlen(name); 700 r = yp_match(domain, "hosts.byname", name, len, &res, &len); 701 } 702 else { 703 if (inet_ntop(AF_INET, data, buf, sizeof buf) == NULL) 704 return (NULL); 705 len = strlen(buf); 706 r = yp_match(domain, "hosts.byaddr", buf, len, &res, &len); 707 } 708 if (r == 0) { 709 h = hostent_from_yp(AF_INET, res); 710 } else { 711 errno = 0; /* ignore error if not found */ 712 } 713 if (res) 714 free(res); 715 return (h); 716 } 717 718 static int 719 strsplit(char *line, char **tokens, int ntokens) 720 { 721 int ntok; 722 char *cp, **tp; 723 724 for (cp = line, tp = tokens, ntok = 0; 725 ntok < ntokens && (*tp = strsep(&cp, " \t")) != NULL; ) 726 if (**tp != '\0') { 727 tp++; 728 ntok++; 729 } 730 731 return (ntok); 732 } 733 734 static struct hostent_ext * 735 hostent_from_yp(int family, char *line) 736 { 737 struct hostent_ext *h; 738 char *next, *tokens[10], addr[IN6ADDRSZ]; 739 int i, ntok; 740 741 if ((h = hostent_alloc(family)) == NULL) 742 return (NULL); 743 744 for (next = line; line; line = next) { 745 if ((next = strchr(line, '\n'))) { 746 *next = '\0'; 747 next += 1; 748 } 749 ntok = strsplit(line, tokens, 10); 750 if (ntok < 2) 751 continue; 752 if (inet_pton(family, tokens[0], addr) == 1) 753 hostent_add_addr(h, addr, family == AF_INET ? 754 INADDRSZ : IN6ADDRSZ); 755 i = 2; 756 if (h->h.h_name == NULL) 757 hostent_set_cname(h, tokens[1], 0); 758 else if (strcmp(h->h.h_name, tokens[1])) 759 i = 1; 760 for (; i < ntok; i++) 761 hostent_add_alias(h, tokens[i], 0); 762 } 763 764 if (h->h.h_name == NULL) { 765 free(h); 766 return (NULL); 767 } 768 769 return (h); 770 } 771 #endif 772