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