1 /* $OpenBSD: gethostnamadr_async.c,v 1.12 2012/12/17 21:13: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 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 } 196 else 197 async_set_state(as, ASR_STATE_NEXT_DOMAIN); 198 } 199 else 200 async_set_state(as, ASR_STATE_NEXT_DB); 201 break; 202 203 case ASR_STATE_NEXT_DOMAIN: 204 205 r = asr_iter_domain(as, as->as.hostnamadr.name, dname, 206 sizeof(dname)); 207 if (r == -1) { 208 async_set_state(as, ASR_STATE_NOT_FOUND); 209 break; 210 } 211 212 if (as->as.hostnamadr.dname) 213 free(as->as.hostnamadr.dname); 214 if ((as->as.hostnamadr.dname = strdup(dname)) == NULL) { 215 ar->ar_h_errno = NETDB_INTERNAL; 216 ar->ar_errno = errno; 217 async_set_state(as, ASR_STATE_HALT); 218 } 219 220 as->as_db_idx = 0; 221 async_set_state(as, ASR_STATE_NEXT_DB); 222 break; 223 224 case ASR_STATE_NEXT_DB: 225 226 if (asr_iter_db(as) == -1) { 227 if (as->as_type == ASR_GETHOSTBYNAME) 228 async_set_state(as, ASR_STATE_NEXT_DOMAIN); 229 else 230 async_set_state(as, ASR_STATE_NOT_FOUND); 231 break; 232 } 233 234 switch (AS_DB(as)) { 235 236 case ASR_DB_DNS: 237 238 /* Create a subquery to do the DNS lookup */ 239 240 if (as->as_type == ASR_GETHOSTBYNAME) { 241 type = (as->as.hostnamadr.family == AF_INET) ? 242 T_A : T_AAAA; 243 as->as.hostnamadr.subq = res_query_async_ctx( 244 as->as.hostnamadr.dname, 245 C_IN, type, NULL, 0, as->as_ctx); 246 } else { 247 addr_as_fqdn(as->as.hostnamadr.addr, 248 as->as.hostnamadr.family, 249 dname, sizeof(dname)); 250 as->as.hostnamadr.subq = res_query_async_ctx( 251 dname, C_IN, T_PTR, NULL, 0, as->as_ctx); 252 } 253 254 if (as->as.hostnamadr.subq == NULL) { 255 ar->ar_errno = errno; 256 ar->ar_h_errno = NETDB_INTERNAL; 257 async_set_state(as, ASR_STATE_HALT); 258 break; 259 } 260 261 async_set_state(as, ASR_STATE_SUBQUERY); 262 break; 263 264 case ASR_DB_FILE: 265 266 /* Try to find a match in the host file */ 267 268 if ((f = fopen(as->as_ctx->ac_hostfile, "r")) == NULL) 269 break; 270 271 if (as->as_type == ASR_GETHOSTBYNAME) 272 data = as->as.hostnamadr.dname; 273 else 274 data = as->as.hostnamadr.addr; 275 276 h = hostent_file_match(f, as->as_type, 277 as->as.hostnamadr.family, data, 278 as->as.hostnamadr.addrlen); 279 saved_errno = errno; 280 fclose(f); 281 errno = saved_errno; 282 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 #ifdef YP 297 case ASR_DB_YP: 298 /* IPv4 only */ 299 if (as->as.hostnamadr.family != AF_INET) 300 break; 301 if (as->as_type == ASR_GETHOSTBYNAME) 302 data = as->as.hostnamadr.dname; 303 else 304 data = as->as.hostnamadr.addr; 305 h = _yp_gethostnamadr(as->as_type, data); 306 if (h == NULL) { 307 if (errno) { 308 ar->ar_errno = errno; 309 ar->ar_h_errno = NETDB_INTERNAL; 310 async_set_state(as, ASR_STATE_HALT); 311 } 312 /* otherwise not found */ 313 break; 314 } 315 ar->ar_hostent = &h->h; 316 ar->ar_h_errno = NETDB_SUCCESS; 317 async_set_state(as, ASR_STATE_HALT); 318 break; 319 #endif 320 } 321 break; 322 323 case ASR_STATE_SUBQUERY: 324 325 /* Run the DNS subquery. */ 326 327 if ((r = async_run(as->as.hostnamadr.subq, ar)) == ASYNC_COND) 328 return (ASYNC_COND); 329 330 /* Done. */ 331 as->as.hostnamadr.subq = NULL; 332 333 if (ar->ar_datalen == -1) { 334 async_set_state(as, ASR_STATE_NEXT_DB); 335 break; 336 } 337 338 /* If we got a packet but no anwser, use the next DB. */ 339 if (ar->ar_count == 0) { 340 free(ar->ar_data); 341 async_set_state(as, ASR_STATE_NEXT_DB); 342 break; 343 } 344 345 /* Read the hostent from the packet. */ 346 347 h = hostent_from_packet(as->as_type, 348 as->as.hostnamadr.family, ar->ar_data, ar->ar_datalen); 349 free(ar->ar_data); 350 if (h == NULL) { 351 ar->ar_errno = errno; 352 ar->ar_h_errno = NETDB_INTERNAL; 353 async_set_state(as, ASR_STATE_HALT); 354 break; 355 } 356 357 if (as->as_type == ASR_GETHOSTBYADDR) { 358 if (hostent_add_addr(h, as->as.hostnamadr.addr, 359 as->as.hostnamadr.addrlen) == -1) { 360 free(h); 361 ar->ar_errno = errno; 362 ar->ar_h_errno = NETDB_INTERNAL; 363 async_set_state(as, ASR_STATE_HALT); 364 break; 365 } 366 } 367 368 /* 369 * No address found in the dns packet. The blocking version 370 * reports this as an error. 371 */ 372 if (as->as_type == ASR_GETHOSTBYNAME && 373 h->h.h_addr_list[0] == NULL) { 374 free(h); 375 async_set_state(as, ASR_STATE_NEXT_DB); 376 break; 377 } 378 379 ar->ar_hostent = &h->h; 380 ar->ar_h_errno = NETDB_SUCCESS; 381 async_set_state(as, ASR_STATE_HALT); 382 break; 383 384 case ASR_STATE_NOT_FOUND: 385 ar->ar_errno = 0; 386 ar->ar_h_errno = HOST_NOT_FOUND; 387 async_set_state(as, ASR_STATE_HALT); 388 break; 389 390 case ASR_STATE_HALT: 391 if (ar->ar_h_errno) 392 ar->ar_hostent = NULL; 393 else 394 ar->ar_errno = 0; 395 return (ASYNC_DONE); 396 397 default: 398 ar->ar_errno = EOPNOTSUPP; 399 ar->ar_h_errno = NETDB_INTERNAL; 400 ar->ar_gai_errno = EAI_SYSTEM; 401 async_set_state(as, ASR_STATE_HALT); 402 break; 403 } 404 goto next; 405 } 406 407 /* 408 * Create a hostent from a numeric address string. 409 */ 410 static struct hostent_ext * 411 hostent_from_addr(int family, const char *name, const char *addr) 412 { 413 struct hostent_ext *h; 414 415 if ((h = hostent_alloc(family)) == NULL) 416 return (NULL); 417 if (hostent_set_cname(h, name, 0) == -1) 418 goto fail; 419 if (hostent_add_addr(h, addr, h->h.h_length) == -1) 420 goto fail; 421 return (h); 422 fail: 423 free(h); 424 return (NULL); 425 } 426 427 /* 428 * Lookup the first matching entry in the hostfile, either by address or by 429 * name depending on reqtype, and build a hostent from the line. 430 */ 431 static struct hostent_ext * 432 hostent_file_match(FILE *f, int reqtype, int family, const char *data, 433 int datalen) 434 { 435 char *tokens[MAXTOKEN], addr[16]; 436 struct hostent_ext *h; 437 int n, i; 438 439 for (;;) { 440 n = asr_parse_namedb_line(f, tokens, MAXTOKEN); 441 if (n == -1) { 442 errno = 0; /* ignore errors reading the file */ 443 return (NULL); 444 } 445 446 if (reqtype == ASR_GETHOSTBYNAME) { 447 for (i = 1; i < n; i++) { 448 if (strcasecmp(data, tokens[i])) 449 continue; 450 if (inet_pton(family, tokens[0], addr) == 1) 451 goto found; 452 } 453 } else { 454 if (inet_pton(family, tokens[0], addr) == 1 && 455 memcmp(addr, data, datalen) == 0) 456 goto found; 457 } 458 } 459 460 found: 461 if ((h = hostent_alloc(family)) == NULL) 462 return (NULL); 463 if (hostent_set_cname(h, tokens[1], 0) == -1) 464 goto fail; 465 for (i = 2; i < n; i ++) 466 if (hostent_add_alias(h, tokens[i], 0) == -1) 467 goto fail; 468 if (hostent_add_addr(h, addr, h->h.h_length) == -1) 469 goto fail; 470 return (h); 471 fail: 472 free(h); 473 return (NULL); 474 } 475 476 /* 477 * Fill the hostent from the given DNS packet. 478 */ 479 static struct hostent_ext * 480 hostent_from_packet(int reqtype, int family, char *pkt, size_t pktlen) 481 { 482 struct hostent_ext *h; 483 struct unpack p; 484 struct header hdr; 485 struct query q; 486 struct rr rr; 487 488 if ((h = hostent_alloc(family)) == NULL) 489 return (NULL); 490 491 unpack_init(&p, pkt, pktlen); 492 unpack_header(&p, &hdr); 493 for (; hdr.qdcount; hdr.qdcount--) 494 unpack_query(&p, &q); 495 for (; hdr.ancount; hdr.ancount--) { 496 unpack_rr(&p, &rr); 497 if (rr.rr_class != C_IN) 498 continue; 499 switch (rr.rr_type) { 500 501 case T_CNAME: 502 if (reqtype == ASR_GETHOSTBYNAME) { 503 if (hostent_add_alias(h, rr.rr_dname, 1) == -1) 504 goto fail; 505 } else { 506 if (hostent_set_cname(h, rr.rr_dname, 1) == -1) 507 goto fail; 508 } 509 break; 510 511 case T_PTR: 512 if (reqtype != ASR_GETHOSTBYADDR) 513 break; 514 if (hostent_set_cname(h, rr.rr.ptr.ptrname, 1) == -1) 515 goto fail; 516 /* XXX See if we need MULTI_PTRS_ARE_ALIASES */ 517 break; 518 519 case T_A: 520 if (reqtype != ASR_GETHOSTBYNAME) 521 break; 522 if (family != AF_INET) 523 break; 524 if (hostent_set_cname(h, rr.rr_dname, 1) == -1) 525 goto fail; 526 if (hostent_add_addr(h, &rr.rr.in_a.addr, 4) == -1) 527 goto fail; 528 break; 529 530 case T_AAAA: 531 if (reqtype != ASR_GETHOSTBYNAME) 532 break; 533 if (family != AF_INET6) 534 break; 535 if (hostent_set_cname(h, rr.rr_dname, 1) == -1) 536 goto fail; 537 if (hostent_add_addr(h, &rr.rr.in_aaaa.addr6, 16) == -1) 538 goto fail; 539 break; 540 } 541 } 542 543 return (h); 544 fail: 545 free(h); 546 return (NULL); 547 } 548 549 static struct hostent_ext * 550 hostent_alloc(int family) 551 { 552 struct hostent_ext *h; 553 size_t alloc; 554 555 alloc = sizeof(*h) + 1024; 556 if ((h = calloc(1, alloc)) == NULL) 557 return (NULL); 558 559 h->h.h_addrtype = family; 560 h->h.h_length = (family == AF_INET) ? 4 : 16; 561 h->h.h_aliases = h->aliases; 562 h->h.h_addr_list = h->addrs; 563 h->pos = (char*)(h) + sizeof(*h); 564 h->end = h->pos + 1024; 565 566 return (h); 567 } 568 569 static int 570 hostent_set_cname(struct hostent_ext *h, const char *name, int isdname) 571 { 572 char buf[MAXDNAME]; 573 size_t n; 574 575 if (h->h.h_name) 576 return (-1); 577 578 if (isdname) { 579 asr_strdname(name, buf, sizeof buf); 580 buf[strlen(buf) - 1] = '\0'; 581 name = buf; 582 } 583 584 n = strlen(name) + 1; 585 if (h->pos + n >= h->end) 586 return (-1); 587 588 h->h.h_name = h->pos; 589 memmove(h->pos, name, n); 590 h->pos += n; 591 return (0); 592 } 593 594 static int 595 hostent_add_alias(struct hostent_ext *h, const char *name, int isdname) 596 { 597 char buf[MAXDNAME]; 598 size_t i, n; 599 600 for (i = 0; i < MAXALIASES; i++) 601 if (h->aliases[i] == NULL) 602 break; 603 if (i == MAXALIASES) 604 return (-1); 605 606 if (isdname) { 607 asr_strdname(name, buf, sizeof buf); 608 buf[strlen(buf)-1] = '\0'; 609 name = buf; 610 } 611 612 n = strlen(name) + 1; 613 if (h->pos + n >= h->end) 614 return (-1); 615 616 h->aliases[i] = h->pos; 617 memmove(h->pos, name, n); 618 h->pos += n; 619 return (0); 620 } 621 622 static int 623 hostent_add_addr(struct hostent_ext *h, const void *addr, size_t size) 624 { 625 int i; 626 627 for (i = 0; i < MAXADDRS; i++) 628 if (h->addrs[i] == NULL) 629 break; 630 if (i == MAXADDRS) 631 return (-1); 632 633 if (h->pos + size >= h->end) 634 return (-1); 635 636 h->addrs[i] = h->pos; 637 memmove(h->pos, addr, size); 638 h->pos += size; 639 return (0); 640 } 641 642 ssize_t 643 addr_as_fqdn(const char *addr, int family, char *dst, size_t max) 644 { 645 const struct in6_addr *in6_addr; 646 in_addr_t in_addr; 647 648 switch (family) { 649 case AF_INET: 650 in_addr = ntohl(*((const in_addr_t *)addr)); 651 snprintf(dst, max, 652 "%d.%d.%d.%d.in-addr.arpa.", 653 in_addr & 0xff, 654 (in_addr >> 8) & 0xff, 655 (in_addr >> 16) & 0xff, 656 (in_addr >> 24) & 0xff); 657 break; 658 case AF_INET6: 659 in6_addr = (const struct in6_addr *)addr; 660 snprintf(dst, max, 661 "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x." 662 "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x." 663 "ip6.arpa.", 664 in6_addr->s6_addr[15] & 0xf, 665 (in6_addr->s6_addr[15] >> 4) & 0xf, 666 in6_addr->s6_addr[14] & 0xf, 667 (in6_addr->s6_addr[14] >> 4) & 0xf, 668 in6_addr->s6_addr[13] & 0xf, 669 (in6_addr->s6_addr[13] >> 4) & 0xf, 670 in6_addr->s6_addr[12] & 0xf, 671 (in6_addr->s6_addr[12] >> 4) & 0xf, 672 in6_addr->s6_addr[11] & 0xf, 673 (in6_addr->s6_addr[11] >> 4) & 0xf, 674 in6_addr->s6_addr[10] & 0xf, 675 (in6_addr->s6_addr[10] >> 4) & 0xf, 676 in6_addr->s6_addr[9] & 0xf, 677 (in6_addr->s6_addr[9] >> 4) & 0xf, 678 in6_addr->s6_addr[8] & 0xf, 679 (in6_addr->s6_addr[8] >> 4) & 0xf, 680 in6_addr->s6_addr[7] & 0xf, 681 (in6_addr->s6_addr[7] >> 4) & 0xf, 682 in6_addr->s6_addr[6] & 0xf, 683 (in6_addr->s6_addr[6] >> 4) & 0xf, 684 in6_addr->s6_addr[5] & 0xf, 685 (in6_addr->s6_addr[5] >> 4) & 0xf, 686 in6_addr->s6_addr[4] & 0xf, 687 (in6_addr->s6_addr[4] >> 4) & 0xf, 688 in6_addr->s6_addr[3] & 0xf, 689 (in6_addr->s6_addr[3] >> 4) & 0xf, 690 in6_addr->s6_addr[2] & 0xf, 691 (in6_addr->s6_addr[2] >> 4) & 0xf, 692 in6_addr->s6_addr[1] & 0xf, 693 (in6_addr->s6_addr[1] >> 4) & 0xf, 694 in6_addr->s6_addr[0] & 0xf, 695 (in6_addr->s6_addr[0] >> 4) & 0xf); 696 break; 697 default: 698 return (-1); 699 } 700 return (0); 701 } 702 703 #ifdef YP 704 static struct hostent_ext * 705 _yp_gethostnamadr(int type, const void *data) 706 { 707 static char *domain = NULL; 708 struct hostent_ext *h = NULL; 709 const char *name; 710 char buf[MAXHOSTNAMELEN]; 711 char *res = NULL; 712 int r, len; 713 714 if (!domain && _yp_check(&domain) == 0) { 715 errno = 0; /* ignore yp_bind errors */ 716 return (NULL); 717 } 718 719 if (type == ASR_GETHOSTBYNAME) { 720 name = data; 721 len = strlen(name); 722 r = yp_match(domain, "hosts.byname", name, len, &res, &len); 723 } 724 else { 725 if (inet_ntop(AF_INET, data, buf, sizeof buf) == NULL) 726 return (NULL); 727 len = strlen(buf); 728 r = yp_match(domain, "hosts.byaddr", buf, len, &res, &len); 729 } 730 if (r == 0) { 731 h = hostent_from_yp(AF_INET, res); 732 } else { 733 errno = 0; /* ignore error if not found */ 734 } 735 if (res) 736 free(res); 737 return (h); 738 } 739 740 static int 741 strsplit(char *line, char **tokens, int ntokens) 742 { 743 int ntok; 744 char *cp, **tp; 745 746 for (cp = line, tp = tokens, ntok = 0; 747 ntok < ntokens && (*tp = strsep(&cp, " \t")) != NULL; ) 748 if (**tp != '\0') { 749 tp++; 750 ntok++; 751 } 752 753 return (ntok); 754 } 755 756 static struct hostent_ext * 757 hostent_from_yp(int family, char *line) 758 { 759 struct hostent_ext *h; 760 char *next, *tokens[10], addr[IN6ADDRSZ]; 761 int i, ntok; 762 763 if ((h = hostent_alloc(family)) == NULL) 764 return (NULL); 765 766 for (next = line; line; line = next) { 767 if ((next = strchr(line, '\n'))) { 768 *next = '\0'; 769 next += 1; 770 } 771 ntok = strsplit(line, tokens, 10); 772 if (ntok < 2) 773 continue; 774 if (inet_pton(family, tokens[0], addr) == 1) 775 hostent_add_addr(h, addr, family == AF_INET ? 776 INADDRSZ : IN6ADDRSZ); 777 i = 2; 778 if (h->h.h_name == NULL) 779 hostent_set_cname(h, tokens[1], 0); 780 else if (strcmp(h->h.h_name, tokens[1])) 781 i = 1; 782 for (; i < ntok; i++) 783 hostent_add_alias(h, tokens[i], 0); 784 } 785 786 if (h->h.h_name == NULL) { 787 free(h); 788 return (NULL); 789 } 790 791 return (h); 792 } 793 #endif 794