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