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