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