1 /* $NetBSD: getaddrinfo.c,v 1.42 2000/04/27 05:30:22 itojun Exp $ */ 2 /* $KAME: getaddrinfo.c,v 1.15 2000/04/27 03:36:25 itojun Exp $ */ 3 4 /* 5 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the project nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 /* 34 * Issues to be discussed: 35 * - Thread safe-ness must be checked. 36 * - Return values. There are nonstandard return values defined and used 37 * in the source code. This is because RFC2553 is silent about which error 38 * code must be returned for which situation. 39 * - IPv4 classful (shortened) form. RFC2553 is silent about it. XNET 5.2 40 * says to use inet_aton() to convert IPv4 numeric to binary (alows 41 * classful form as a result). 42 * current code - disallow classful form for IPv4 (due to use of inet_pton). 43 * - freeaddrinfo(NULL). RFC2553 is silent about it. XNET 5.2 says it is 44 * invalid. 45 * current code - SEGV on freeaddrinfo(NULL) 46 * Note: 47 * - We use getipnodebyname() just for thread-safeness. There's no intent 48 * to let it do PF_UNSPEC (actually we never pass PF_UNSPEC to 49 * getipnodebyname(). 50 * - The code filters out AFs that are not supported by the kernel, 51 * when globbing NULL hostname (to loopback, or wildcard). Is it the right 52 * thing to do? What is the relationship with post-RFC2553 AI_ADDRCONFIG 53 * in ai_flags? 54 * - (post-2553) semantics of AI_ADDRCONFIG itself is too vague. 55 * (1) what should we do against numeric hostname (2) what should we do 56 * against NULL hostname (3) what is AI_ADDRCONFIG itself. AF not ready? 57 * non-loopback address configured? global address configured? 58 * - To avoid search order issue, we have a big amount of code duplicate 59 * from gethnamaddr.c and some other places. The issues that there's no 60 * lower layer function to lookup "IPv4 or IPv6" record. Calling 61 * gethostbyname2 from getaddrinfo will end up in wrong search order, as 62 * follows: 63 * - The code makes use of following calls when asked to resolver with 64 * ai_family = PF_UNSPEC: 65 * getipnodebyname(host, AF_INET6); 66 * getipnodebyname(host, AF_INET); 67 * This will result in the following queries if the node is configure to 68 * prefer /etc/hosts than DNS: 69 * lookup /etc/hosts for IPv6 address 70 * lookup DNS for IPv6 address 71 * lookup /etc/hosts for IPv4 address 72 * lookup DNS for IPv4 address 73 * which may not meet people's requirement. 74 * The right thing to happen is to have underlying layer which does 75 * PF_UNSPEC lookup (lookup both) and return chain of addrinfos. 76 * This would result in a bit of code duplicate with _dns_ghbyname() and 77 * friends. 78 */ 79 80 #include <sys/cdefs.h> 81 #if defined(LIBC_SCCS) && !defined(lint) 82 __RCSID("$NetBSD: getaddrinfo.c,v 1.42 2000/04/27 05:30:22 itojun Exp $"); 83 #endif /* LIBC_SCCS and not lint */ 84 85 #include "namespace.h" 86 #include <sys/types.h> 87 #include <sys/param.h> 88 #include <sys/socket.h> 89 #include <net/if.h> 90 #include <netinet/in.h> 91 #include <arpa/inet.h> 92 #include <arpa/nameser.h> 93 #include <netdb.h> 94 #include <resolv.h> 95 #include <string.h> 96 #include <stdlib.h> 97 #include <stddef.h> 98 #include <ctype.h> 99 #include <unistd.h> 100 #include <stdio.h> 101 #include <errno.h> 102 103 #include <syslog.h> 104 #include <stdarg.h> 105 #include <nsswitch.h> 106 107 #ifdef YP 108 #include <rpc/rpc.h> 109 #include <rpcsvc/yp_prot.h> 110 #include <rpcsvc/ypclnt.h> 111 #endif 112 113 #ifdef __weak_alias 114 __weak_alias(getaddrinfo,_getaddrinfo) 115 __weak_alias(freeaddrinfo,_freeaddrinfo) 116 __weak_alias(gai_strerror,_gai_strerror) 117 #endif 118 119 #define SUCCESS 0 120 #define ANY 0 121 #define YES 1 122 #define NO 0 123 124 static const char in_addrany[] = { 0, 0, 0, 0 }; 125 static const char in6_addrany[] = { 126 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 127 }; 128 static const char in_loopback[] = { 127, 0, 0, 1 }; 129 static const char in6_loopback[] = { 130 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 131 }; 132 133 static const struct afd { 134 int a_af; 135 int a_addrlen; 136 int a_socklen; 137 int a_off; 138 const char *a_addrany; 139 const char *a_loopback; 140 int a_scoped; 141 } afdl [] = { 142 #ifdef INET6 143 {PF_INET6, sizeof(struct in6_addr), 144 sizeof(struct sockaddr_in6), 145 offsetof(struct sockaddr_in6, sin6_addr), 146 in6_addrany, in6_loopback, 1}, 147 #endif 148 {PF_INET, sizeof(struct in_addr), 149 sizeof(struct sockaddr_in), 150 offsetof(struct sockaddr_in, sin_addr), 151 in_addrany, in_loopback, 0}, 152 {0, 0, 0, 0, NULL, NULL, 0}, 153 }; 154 155 struct explore { 156 int e_af; 157 int e_socktype; 158 int e_protocol; 159 const char *e_protostr; 160 int e_wild; 161 #define WILD_AF(ex) ((ex)->e_wild & 0x01) 162 #define WILD_SOCKTYPE(ex) ((ex)->e_wild & 0x02) 163 #define WILD_PROTOCOL(ex) ((ex)->e_wild & 0x04) 164 }; 165 166 static const struct explore explore[] = { 167 #if 0 168 { PF_LOCAL, 0, ANY, ANY, NULL, 0x01 }, 169 #endif 170 #ifdef INET6 171 { PF_INET6, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 }, 172 { PF_INET6, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 }, 173 { PF_INET6, SOCK_RAW, ANY, NULL, 0x05 }, 174 #endif 175 { PF_INET, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 }, 176 { PF_INET, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 }, 177 { PF_INET, SOCK_RAW, ANY, NULL, 0x05 }, 178 { PF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 }, 179 { PF_UNSPEC, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 }, 180 { PF_UNSPEC, SOCK_RAW, ANY, NULL, 0x05 }, 181 { -1, 0, 0, NULL, 0 }, 182 }; 183 184 #ifdef INET6 185 #define PTON_MAX 16 186 #else 187 #define PTON_MAX 4 188 #endif 189 190 static const ns_src default_dns_files[] = { 191 { NSSRC_FILES, NS_SUCCESS }, 192 { NSSRC_DNS, NS_SUCCESS }, 193 { 0 } 194 }; 195 196 #if PACKETSZ > 1024 197 #define MAXPACKET PACKETSZ 198 #else 199 #define MAXPACKET 1024 200 #endif 201 202 typedef union { 203 HEADER hdr; 204 u_char buf[MAXPACKET]; 205 } querybuf; 206 207 struct res_target { 208 struct res_target *next; 209 const char *name; /* domain name */ 210 int class, type; /* class and type of query */ 211 u_char *answer; /* buffer to put answer */ 212 int anslen; /* size of answer buffer */ 213 int n; /* result length */ 214 }; 215 216 static int str_isnumber __P((const char *)); 217 static int explore_fqdn __P((const struct addrinfo *, const char *, 218 const char *, struct addrinfo **)); 219 static int explore_null __P((const struct addrinfo *, 220 const char *, struct addrinfo **)); 221 static int explore_numeric __P((const struct addrinfo *, const char *, 222 const char *, struct addrinfo **)); 223 static int explore_numeric_scope __P((const struct addrinfo *, const char *, 224 const char *, struct addrinfo **)); 225 static int get_canonname __P((const struct addrinfo *, 226 struct addrinfo *, const char *)); 227 static struct addrinfo *get_ai __P((const struct addrinfo *, 228 const struct afd *, const char *)); 229 static int get_portmatch __P((const struct addrinfo *, const char *)); 230 static int get_port __P((struct addrinfo *, const char *, int)); 231 static const struct afd *find_afd __P((int)); 232 #if 0 233 static int addrconfig __P((const struct addrinfo *)); 234 #endif 235 #ifdef INET6 236 static int ip6_str2scopeid __P((char *, struct sockaddr_in6 *)); 237 #endif 238 239 static struct addrinfo *getanswer __P((const querybuf *, int, const char *, int, 240 const struct addrinfo *)); 241 static int _dns_getaddrinfo __P((void *, void *, va_list)); 242 static void _sethtent __P((void)); 243 static void _endhtent __P((void)); 244 static struct addrinfo *_gethtent __P((const char *, const struct addrinfo *)); 245 static int _files_getaddrinfo __P((void *, void *, va_list)); 246 #ifdef YP 247 static struct addrinfo *_yphostent __P((char *, const struct addrinfo *)); 248 static int _yp_getaddrinfo __P((void *, void *, va_list)); 249 #endif 250 251 static int res_queryN __P((const char *, struct res_target *)); 252 static int res_searchN __P((const char *, struct res_target *)); 253 static int res_querydomainN __P((const char *, const char *, 254 struct res_target *)); 255 256 static char *ai_errlist[] = { 257 "Success", 258 "Address family for hostname not supported", /* EAI_ADDRFAMILY */ 259 "Temporary failure in name resolution", /* EAI_AGAIN */ 260 "Invalid value for ai_flags", /* EAI_BADFLAGS */ 261 "Non-recoverable failure in name resolution", /* EAI_FAIL */ 262 "ai_family not supported", /* EAI_FAMILY */ 263 "Memory allocation failure", /* EAI_MEMORY */ 264 "No address associated with hostname", /* EAI_NODATA */ 265 "hostname nor servname provided, or not known", /* EAI_NONAME */ 266 "servname not supported for ai_socktype", /* EAI_SERVICE */ 267 "ai_socktype not supported", /* EAI_SOCKTYPE */ 268 "System error returned in errno", /* EAI_SYSTEM */ 269 "Invalid value for hints", /* EAI_BADHINTS */ 270 "Resolved protocol is unknown", /* EAI_PROTOCOL */ 271 "Unknown error", /* EAI_MAX */ 272 }; 273 274 /* XXX macros that make external reference is BAD. */ 275 276 #define GET_AI(ai, afd, addr) \ 277 do { \ 278 /* external reference: pai, error, and label free */ \ 279 (ai) = get_ai(pai, (afd), (addr)); \ 280 if ((ai) == NULL) { \ 281 error = EAI_MEMORY; \ 282 goto free; \ 283 } \ 284 } while (/*CONSTCOND*/0) 285 286 #define GET_PORT(ai, serv) \ 287 do { \ 288 /* external reference: error and label free */ \ 289 error = get_port((ai), (serv), 0); \ 290 if (error != 0) \ 291 goto free; \ 292 } while (/*CONSTCOND*/0) 293 294 #define GET_CANONNAME(ai, str) \ 295 do { \ 296 /* external reference: pai, error and label free */ \ 297 error = get_canonname(pai, (ai), (str)); \ 298 if (error != 0) \ 299 goto free; \ 300 } while (/*CONSTCOND*/0) 301 302 #define ERR(err) \ 303 do { \ 304 /* external reference: error, and label bad */ \ 305 error = (err); \ 306 goto bad; \ 307 /*NOTREACHED*/ \ 308 } while (/*CONSTCOND*/0) 309 310 #define MATCH_FAMILY(x, y, w) \ 311 ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == PF_UNSPEC || (y) == PF_UNSPEC))) 312 #define MATCH(x, y, w) \ 313 ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == ANY || (y) == ANY))) 314 315 char * 316 gai_strerror(ecode) 317 int ecode; 318 { 319 if (ecode < 0 || ecode > EAI_MAX) 320 ecode = EAI_MAX; 321 return ai_errlist[ecode]; 322 } 323 324 void 325 freeaddrinfo(ai) 326 struct addrinfo *ai; 327 { 328 struct addrinfo *next; 329 330 do { 331 next = ai->ai_next; 332 if (ai->ai_canonname) 333 free(ai->ai_canonname); 334 /* no need to free(ai->ai_addr) */ 335 free(ai); 336 ai = next; 337 } while (ai); 338 } 339 340 static int 341 str_isnumber(p) 342 const char *p; 343 { 344 const char *q = (const char *)p; 345 while (*q) { 346 if (!isdigit(*q)) 347 return NO; 348 q++; 349 } 350 return YES; 351 } 352 353 int 354 getaddrinfo(hostname, servname, hints, res) 355 const char *hostname, *servname; 356 const struct addrinfo *hints; 357 struct addrinfo **res; 358 { 359 struct addrinfo sentinel; 360 struct addrinfo *cur; 361 int error = 0; 362 struct addrinfo ai; 363 struct addrinfo ai0; 364 struct addrinfo *pai; 365 const struct explore *ex; 366 367 memset(&sentinel, 0, sizeof(sentinel)); 368 cur = &sentinel; 369 pai = &ai; 370 pai->ai_flags = 0; 371 pai->ai_family = PF_UNSPEC; 372 pai->ai_socktype = ANY; 373 pai->ai_protocol = ANY; 374 pai->ai_addrlen = 0; 375 pai->ai_canonname = NULL; 376 pai->ai_addr = NULL; 377 pai->ai_next = NULL; 378 379 if (hostname == NULL && servname == NULL) 380 return EAI_NONAME; 381 if (hints) { 382 /* error check for hints */ 383 if (hints->ai_addrlen || hints->ai_canonname || 384 hints->ai_addr || hints->ai_next) 385 ERR(EAI_BADHINTS); /* xxx */ 386 if (hints->ai_flags & ~AI_MASK) 387 ERR(EAI_BADFLAGS); 388 switch (hints->ai_family) { 389 case PF_UNSPEC: 390 case PF_INET: 391 #ifdef INET6 392 case PF_INET6: 393 #endif 394 break; 395 default: 396 ERR(EAI_FAMILY); 397 } 398 memcpy(pai, hints, sizeof(*pai)); 399 400 /* 401 * if both socktype/protocol are specified, check if they 402 * are meaningful combination. 403 */ 404 if (pai->ai_socktype != ANY && pai->ai_protocol != ANY) { 405 for (ex = explore; ex->e_af >= 0; ex++) { 406 if (pai->ai_family != ex->e_af) 407 continue; 408 if (ex->e_socktype == ANY) 409 continue; 410 if (ex->e_protocol == ANY) 411 continue; 412 if (pai->ai_socktype == ex->e_socktype 413 && pai->ai_protocol != ex->e_protocol) { 414 ERR(EAI_BADHINTS); 415 } 416 } 417 } 418 } 419 420 /* 421 * check for special cases. (1) numeric servname is disallowed if 422 * socktype/protocol are left unspecified. (2) servname is disallowed 423 * for raw and other inet{,6} sockets. 424 */ 425 if (MATCH_FAMILY(pai->ai_family, PF_INET, 1) 426 #ifdef PF_INET6 427 || MATCH_FAMILY(pai->ai_family, PF_INET6, 1) 428 #endif 429 ) { 430 ai0 = *pai; /* backup *pai */ 431 432 if (pai->ai_family == PF_UNSPEC) { 433 #ifdef PF_INET6 434 pai->ai_family = PF_INET6; 435 #else 436 pai->ai_family = PF_INET; 437 #endif 438 } 439 error = get_portmatch(pai, servname); 440 if (error) 441 ERR(error); 442 443 *pai = ai0; 444 } 445 446 ai0 = *pai; 447 448 /* NULL hostname, or numeric hostname */ 449 for (ex = explore; ex->e_af >= 0; ex++) { 450 *pai = ai0; 451 452 /* PF_UNSPEC entries are prepared for DNS queries only */ 453 if (ex->e_af == PF_UNSPEC) 454 continue; 455 456 if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex))) 457 continue; 458 if (!MATCH(pai->ai_socktype, ex->e_socktype, WILD_SOCKTYPE(ex))) 459 continue; 460 if (!MATCH(pai->ai_protocol, ex->e_protocol, WILD_PROTOCOL(ex))) 461 continue; 462 463 if (pai->ai_family == PF_UNSPEC) 464 pai->ai_family = ex->e_af; 465 if (pai->ai_socktype == ANY && ex->e_socktype != ANY) 466 pai->ai_socktype = ex->e_socktype; 467 if (pai->ai_protocol == ANY && ex->e_protocol != ANY) 468 pai->ai_protocol = ex->e_protocol; 469 470 if (hostname == NULL) 471 error = explore_null(pai, servname, &cur->ai_next); 472 else 473 error = explore_numeric_scope(pai, hostname, servname, &cur->ai_next); 474 475 if (error) 476 goto free; 477 478 while (cur && cur->ai_next) 479 cur = cur->ai_next; 480 } 481 482 /* 483 * XXX 484 * If numreic representation of AF1 can be interpreted as FQDN 485 * representation of AF2, we need to think again about the code below. 486 */ 487 if (sentinel.ai_next) 488 goto good; 489 490 if (pai->ai_flags & AI_NUMERICHOST) 491 ERR(EAI_NONAME); 492 if (hostname == NULL) 493 ERR(EAI_NONAME); 494 495 /* 496 * hostname as alphabetical name. 497 * we would like to prefer AF_INET6 than AF_INET, so we'll make a 498 * outer loop by AFs. 499 */ 500 for (ex = explore; ex->e_af >= 0; ex++) { 501 *pai = ai0; 502 503 /* require exact match for family field */ 504 if (pai->ai_family != ex->e_af) 505 continue; 506 507 if (!MATCH(pai->ai_socktype, ex->e_socktype, 508 WILD_SOCKTYPE(ex))) { 509 continue; 510 } 511 if (!MATCH(pai->ai_protocol, ex->e_protocol, 512 WILD_PROTOCOL(ex))) { 513 continue; 514 } 515 516 if (pai->ai_socktype == ANY && ex->e_socktype != ANY) 517 pai->ai_socktype = ex->e_socktype; 518 if (pai->ai_protocol == ANY && ex->e_protocol != ANY) 519 pai->ai_protocol = ex->e_protocol; 520 521 error = explore_fqdn(pai, hostname, servname, 522 &cur->ai_next); 523 524 while (cur && cur->ai_next) 525 cur = cur->ai_next; 526 } 527 528 /* XXX */ 529 if (sentinel.ai_next) 530 error = 0; 531 532 if (error) 533 goto free; 534 if (error == 0) { 535 if (sentinel.ai_next) { 536 good: 537 *res = sentinel.ai_next; 538 return SUCCESS; 539 } else 540 error = EAI_FAIL; 541 } 542 free: 543 bad: 544 if (sentinel.ai_next) 545 freeaddrinfo(sentinel.ai_next); 546 *res = NULL; 547 return error; 548 } 549 550 /* 551 * FQDN hostname, DNS lookup 552 */ 553 static int 554 explore_fqdn(pai, hostname, servname, res) 555 const struct addrinfo *pai; 556 const char *hostname; 557 const char *servname; 558 struct addrinfo **res; 559 { 560 struct addrinfo *result; 561 struct addrinfo *cur; 562 int error = 0; 563 static const ns_dtab dtab[] = { 564 NS_FILES_CB(_files_getaddrinfo, NULL) 565 { NSSRC_DNS, _dns_getaddrinfo, NULL }, /* force -DHESIOD */ 566 NS_NIS_CB(_yp_getaddrinfo, NULL) 567 { 0 } 568 }; 569 570 result = NULL; 571 572 #if 0 573 /* 574 * If AI_ADDRCONFIG is specified, check if we are expected to 575 * return the address family or not. 576 * XXX does not handle PF_UNSPEC - should filter out result from 577 * nsdispatch() 578 */ 579 if ((pai->ai_flags & AI_ADDRCONFIG) != 0 && !addrconfig(pai)) 580 return 0; 581 #endif 582 583 /* 584 * if the servname does not match socktype/protocol, ignore it. 585 */ 586 if (get_portmatch(pai, servname) != 0) 587 return 0; 588 589 switch (nsdispatch(&result, dtab, NSDB_HOSTS, "getaddrinfo", 590 default_dns_files, hostname, pai)) { 591 case NS_TRYAGAIN: 592 error = EAI_AGAIN; 593 goto free; 594 case NS_UNAVAIL: 595 error = EAI_FAIL; 596 goto free; 597 case NS_NOTFOUND: 598 error = EAI_NODATA; 599 goto free; 600 case NS_SUCCESS: 601 error = 0; 602 for (cur = result; cur; cur = cur->ai_next) { 603 GET_PORT(cur, servname); 604 /* canonname should be filled already */ 605 } 606 break; 607 } 608 609 *res = result; 610 611 return 0; 612 613 free: 614 if (result) 615 freeaddrinfo(result); 616 return error; 617 } 618 619 /* 620 * hostname == NULL. 621 * passive socket -> anyaddr (0.0.0.0 or ::) 622 * non-passive socket -> localhost (127.0.0.1 or ::1) 623 */ 624 static int 625 explore_null(pai, servname, res) 626 const struct addrinfo *pai; 627 const char *servname; 628 struct addrinfo **res; 629 { 630 int s; 631 const struct afd *afd; 632 struct addrinfo *cur; 633 struct addrinfo sentinel; 634 int error; 635 636 *res = NULL; 637 sentinel.ai_next = NULL; 638 cur = &sentinel; 639 640 /* 641 * filter out AFs that are not supported by the kernel 642 * XXX errno? 643 */ 644 s = socket(pai->ai_family, SOCK_DGRAM, 0); 645 if (s < 0) { 646 if (errno != EMFILE) 647 return 0; 648 } else 649 close(s); 650 651 /* 652 * if the servname does not match socktype/protocol, ignore it. 653 */ 654 if (get_portmatch(pai, servname) != 0) 655 return 0; 656 657 afd = find_afd(pai->ai_family); 658 if (afd == NULL) 659 return 0; 660 661 if (pai->ai_flags & AI_PASSIVE) { 662 GET_AI(cur->ai_next, afd, afd->a_addrany); 663 /* xxx meaningless? 664 * GET_CANONNAME(cur->ai_next, "anyaddr"); 665 */ 666 GET_PORT(cur->ai_next, servname); 667 } else { 668 GET_AI(cur->ai_next, afd, afd->a_loopback); 669 /* xxx meaningless? 670 * GET_CANONNAME(cur->ai_next, "localhost"); 671 */ 672 GET_PORT(cur->ai_next, servname); 673 } 674 cur = cur->ai_next; 675 676 *res = sentinel.ai_next; 677 return 0; 678 679 free: 680 if (sentinel.ai_next) 681 freeaddrinfo(sentinel.ai_next); 682 return error; 683 } 684 685 /* 686 * numeric hostname 687 */ 688 static int 689 explore_numeric(pai, hostname, servname, res) 690 const struct addrinfo *pai; 691 const char *hostname; 692 const char *servname; 693 struct addrinfo **res; 694 { 695 const struct afd *afd; 696 struct addrinfo *cur; 697 struct addrinfo sentinel; 698 int error; 699 char pton[PTON_MAX]; 700 701 *res = NULL; 702 sentinel.ai_next = NULL; 703 cur = &sentinel; 704 705 /* 706 * if the servname does not match socktype/protocol, ignore it. 707 */ 708 if (get_portmatch(pai, servname) != 0) 709 return 0; 710 711 afd = find_afd(pai->ai_family); 712 if (afd == NULL) 713 return 0; 714 715 switch (afd->a_af) { 716 #if 0 /*X/Open spec*/ 717 case AF_INET: 718 if (inet_aton(hostname, (struct in_addr *)pton) == 1) { 719 if (pai->ai_family == afd->a_af || 720 pai->ai_family == PF_UNSPEC /*?*/) { 721 GET_AI(cur->ai_next, afd, pton); 722 GET_PORT(cur->ai_next, servname); 723 while (cur && cur->ai_next) 724 cur = cur->ai_next; 725 } else 726 ERR(EAI_FAMILY); /*xxx*/ 727 } 728 break; 729 #endif 730 default: 731 if (inet_pton(afd->a_af, hostname, pton) == 1) { 732 if (pai->ai_family == afd->a_af || 733 pai->ai_family == PF_UNSPEC /*?*/) { 734 GET_AI(cur->ai_next, afd, pton); 735 GET_PORT(cur->ai_next, servname); 736 while (cur && cur->ai_next) 737 cur = cur->ai_next; 738 } else 739 ERR(EAI_FAMILY); /*xxx*/ 740 } 741 break; 742 } 743 744 *res = sentinel.ai_next; 745 return 0; 746 747 free: 748 bad: 749 if (sentinel.ai_next) 750 freeaddrinfo(sentinel.ai_next); 751 return error; 752 } 753 754 /* 755 * numeric hostname with scope 756 */ 757 static int 758 explore_numeric_scope(pai, hostname, servname, res) 759 const struct addrinfo *pai; 760 const char *hostname; 761 const char *servname; 762 struct addrinfo **res; 763 { 764 #if !defined(SCOPE_DELIMITER) || !defined(INET6) 765 return explore_numeric(pai, hostname, servname, res); 766 #else 767 const struct afd *afd; 768 struct addrinfo *cur; 769 int error; 770 char *cp, *hostname2 = NULL, *scope, *addr; 771 struct sockaddr_in6 *sin6; 772 773 /* 774 * if the servname does not match socktype/protocol, ignore it. 775 */ 776 if (get_portmatch(pai, servname) != 0) 777 return 0; 778 779 afd = find_afd(pai->ai_family); 780 if (afd == NULL) 781 return 0; 782 783 if (!afd->a_scoped) 784 return explore_numeric(pai, hostname, servname, res); 785 786 cp = strchr(hostname, SCOPE_DELIMITER); 787 if (cp == NULL) 788 return explore_numeric(pai, hostname, servname, res); 789 790 #if 0 791 /* 792 * Handle special case of <scope id><delimiter><scoped_address> 793 */ 794 hostname2 = strdup(hostname); 795 if (hostname2 == NULL) 796 return EAI_MEMORY; 797 /* terminate at the delimiter */ 798 hostname2[cp - hostname] = '\0'; 799 scope = hostname2; 800 addr = cp + 1; 801 #else 802 /* 803 * Handle special case of <scoped_address><delimiter><scope id> 804 */ 805 hostname2 = strdup(hostname); 806 if (hostname2 == NULL) 807 return EAI_MEMORY; 808 /* terminate at the delimiter */ 809 hostname2[cp - hostname] = '\0'; 810 addr = hostname2; 811 scope = cp + 1; 812 #endif 813 814 error = explore_numeric(pai, addr, servname, res); 815 if (error == 0) { 816 int scopeid; 817 818 for (cur = *res; cur; cur = cur->ai_next) { 819 if (cur->ai_family != AF_INET6) 820 continue; 821 sin6 = (struct sockaddr_in6 *)(void *)cur->ai_addr; 822 if ((scopeid = ip6_str2scopeid(scope, sin6)) == -1) { 823 free(hostname2); 824 return(EAI_NONAME); /* XXX: is return OK? */ 825 } 826 sin6->sin6_scope_id = scopeid; 827 } 828 } 829 830 free(hostname2); 831 832 return error; 833 #endif 834 } 835 836 static int 837 get_canonname(pai, ai, str) 838 const struct addrinfo *pai; 839 struct addrinfo *ai; 840 const char *str; 841 { 842 if ((pai->ai_flags & AI_CANONNAME) != 0) { 843 ai->ai_canonname = (char *)malloc(strlen(str) + 1); 844 if (ai->ai_canonname == NULL) 845 return EAI_MEMORY; 846 strcpy(ai->ai_canonname, str); 847 } 848 return 0; 849 } 850 851 static struct addrinfo * 852 get_ai(pai, afd, addr) 853 const struct addrinfo *pai; 854 const struct afd *afd; 855 const char *addr; 856 { 857 char *p; 858 struct addrinfo *ai; 859 860 ai = (struct addrinfo *)malloc(sizeof(struct addrinfo) 861 + (afd->a_socklen)); 862 if (ai == NULL) 863 return NULL; 864 865 memcpy(ai, pai, sizeof(struct addrinfo)); 866 ai->ai_addr = (struct sockaddr *)(void *)(ai + 1); 867 memset(ai->ai_addr, 0, (size_t)afd->a_socklen); 868 ai->ai_addr->sa_len = afd->a_socklen; 869 ai->ai_addrlen = afd->a_socklen; 870 ai->ai_addr->sa_family = ai->ai_family = afd->a_af; 871 p = (char *)(void *)(ai->ai_addr); 872 memcpy(p + afd->a_off, addr, (size_t)afd->a_addrlen); 873 return ai; 874 } 875 876 static int 877 get_portmatch(ai, servname) 878 const struct addrinfo *ai; 879 const char *servname; 880 { 881 882 /* get_port does not touch first argument. when matchonly == 1. */ 883 /* LINTED const cast */ 884 return get_port((struct addrinfo *)ai, servname, 1); 885 } 886 887 static int 888 get_port(ai, servname, matchonly) 889 struct addrinfo *ai; 890 const char *servname; 891 int matchonly; 892 { 893 const char *proto; 894 struct servent *sp; 895 int port; 896 int allownumeric; 897 898 if (servname == NULL) 899 return 0; 900 switch (ai->ai_family) { 901 case AF_INET: 902 #ifdef AF_INET6 903 case AF_INET6: 904 #endif 905 break; 906 default: 907 return 0; 908 } 909 910 switch (ai->ai_socktype) { 911 case SOCK_RAW: 912 return EAI_SERVICE; 913 case SOCK_DGRAM: 914 case SOCK_STREAM: 915 allownumeric = 1; 916 break; 917 case ANY: 918 allownumeric = 0; 919 break; 920 default: 921 return EAI_SOCKTYPE; 922 } 923 924 if (str_isnumber(servname)) { 925 if (!allownumeric) 926 return EAI_SERVICE; 927 port = htons(atoi(servname)); 928 if (port < 0 || port > 65535) 929 return EAI_SERVICE; 930 } else { 931 switch (ai->ai_socktype) { 932 case SOCK_DGRAM: 933 proto = "udp"; 934 break; 935 case SOCK_STREAM: 936 proto = "tcp"; 937 break; 938 default: 939 proto = NULL; 940 break; 941 } 942 943 if ((sp = getservbyname(servname, proto)) == NULL) 944 return EAI_SERVICE; 945 port = sp->s_port; 946 } 947 948 if (!matchonly) { 949 switch (ai->ai_family) { 950 case AF_INET: 951 ((struct sockaddr_in *)(void *) 952 ai->ai_addr)->sin_port = port; 953 break; 954 #ifdef INET6 955 case AF_INET6: 956 ((struct sockaddr_in6 *)(void *) 957 ai->ai_addr)->sin6_port = port; 958 break; 959 #endif 960 } 961 } 962 963 return 0; 964 } 965 966 static const struct afd * 967 find_afd(af) 968 int af; 969 { 970 const struct afd *afd; 971 972 if (af == PF_UNSPEC) 973 return NULL; 974 for (afd = afdl; afd->a_af; afd++) { 975 if (afd->a_af == af) 976 return afd; 977 } 978 return NULL; 979 } 980 981 #if 0 982 /* 983 * post-2553: AI_ADDRCONFIG check. if we use getipnodeby* as backend, backend 984 * will take care of it. 985 * the semantics of AI_ADDRCONFIG is not defined well. we are not sure 986 * if the code is right or not. 987 */ 988 static int 989 addrconfig(pai) 990 const struct addrinfo *pai; 991 { 992 int s; 993 994 /* XXX errno */ 995 s = socket(pai->ai_family, SOCK_DGRAM, 0); 996 if (s < 0) 997 return 0; 998 close(s); 999 return 1; 1000 } 1001 #endif 1002 1003 #ifdef INET6 1004 /* convert a string to a scope identifier. XXX: IPv6 specific */ 1005 static int 1006 ip6_str2scopeid(scope, sin6) 1007 char *scope; 1008 struct sockaddr_in6 *sin6; 1009 { 1010 int scopeid; 1011 struct in6_addr *a6 = &sin6->sin6_addr; 1012 char *ep; 1013 1014 if (IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6)) { 1015 /* 1016 * We currently assume a one-to-one mapping between links 1017 * and interfaces, so we simply use interface indices for 1018 * like-local scopes. 1019 */ 1020 scopeid = if_nametoindex(scope); 1021 if (scopeid == 0) 1022 goto trynumeric; 1023 return(scopeid); 1024 } 1025 1026 /* still unclear about literal, allow numeric only - placeholder */ 1027 if (IN6_IS_ADDR_SITELOCAL(a6) || IN6_IS_ADDR_MC_SITELOCAL(a6)) 1028 goto trynumeric; 1029 if (IN6_IS_ADDR_MC_ORGLOCAL(a6)) 1030 goto trynumeric; 1031 else 1032 goto trynumeric; /* global */ 1033 1034 /* try to convert to a numeric id as a last resort */ 1035 trynumeric: 1036 scopeid = (int)strtoul(scope, &ep, 10); 1037 if (*ep == '\0') 1038 return scopeid; 1039 else 1040 return -1; 1041 } 1042 #endif 1043 1044 /* code duplicate with gethnamaddr.c */ 1045 1046 static const char AskedForGot[] = 1047 "gethostby*.getanswer: asked for \"%s\", got \"%s\""; 1048 static FILE *hostf = NULL; 1049 1050 static struct addrinfo * 1051 getanswer(answer, anslen, qname, qtype, pai) 1052 const querybuf *answer; 1053 int anslen; 1054 const char *qname; 1055 int qtype; 1056 const struct addrinfo *pai; 1057 { 1058 struct addrinfo sentinel, *cur; 1059 struct addrinfo ai; 1060 const struct afd *afd; 1061 char *canonname; 1062 const HEADER *hp; 1063 const u_char *cp; 1064 int n; 1065 const u_char *eom; 1066 char *bp; 1067 int type, class, buflen, ancount, qdcount; 1068 int haveanswer, had_error; 1069 char tbuf[MAXDNAME]; 1070 int (*name_ok) __P((const char *)); 1071 char hostbuf[8*1024]; 1072 1073 memset(&sentinel, 0, sizeof(sentinel)); 1074 cur = &sentinel; 1075 1076 canonname = NULL; 1077 eom = answer->buf + anslen; 1078 switch (qtype) { 1079 case T_A: 1080 case T_AAAA: 1081 case T_ANY: /*use T_ANY only for T_A/T_AAAA lookup*/ 1082 name_ok = res_hnok; 1083 break; 1084 default: 1085 return (NULL); /* XXX should be abort(); */ 1086 } 1087 /* 1088 * find first satisfactory answer 1089 */ 1090 hp = &answer->hdr; 1091 ancount = ntohs(hp->ancount); 1092 qdcount = ntohs(hp->qdcount); 1093 bp = hostbuf; 1094 buflen = sizeof hostbuf; 1095 cp = answer->buf + HFIXEDSZ; 1096 if (qdcount != 1) { 1097 h_errno = NO_RECOVERY; 1098 return (NULL); 1099 } 1100 n = dn_expand(answer->buf, eom, cp, bp, buflen); 1101 if ((n < 0) || !(*name_ok)(bp)) { 1102 h_errno = NO_RECOVERY; 1103 return (NULL); 1104 } 1105 cp += n + QFIXEDSZ; 1106 if (qtype == T_A || qtype == T_AAAA || qtype == T_ANY) { 1107 /* res_send() has already verified that the query name is the 1108 * same as the one we sent; this just gets the expanded name 1109 * (i.e., with the succeeding search-domain tacked on). 1110 */ 1111 n = strlen(bp) + 1; /* for the \0 */ 1112 if (n >= MAXHOSTNAMELEN) { 1113 h_errno = NO_RECOVERY; 1114 return (NULL); 1115 } 1116 canonname = bp; 1117 bp += n; 1118 buflen -= n; 1119 /* The qname can be abbreviated, but h_name is now absolute. */ 1120 qname = canonname; 1121 } 1122 haveanswer = 0; 1123 had_error = 0; 1124 while (ancount-- > 0 && cp < eom && !had_error) { 1125 n = dn_expand(answer->buf, eom, cp, bp, buflen); 1126 if ((n < 0) || !(*name_ok)(bp)) { 1127 had_error++; 1128 continue; 1129 } 1130 cp += n; /* name */ 1131 type = _getshort(cp); 1132 cp += INT16SZ; /* type */ 1133 class = _getshort(cp); 1134 cp += INT16SZ + INT32SZ; /* class, TTL */ 1135 n = _getshort(cp); 1136 cp += INT16SZ; /* len */ 1137 if (class != C_IN) { 1138 /* XXX - debug? syslog? */ 1139 cp += n; 1140 continue; /* XXX - had_error++ ? */ 1141 } 1142 if ((qtype == T_A || qtype == T_AAAA || qtype == T_ANY) && 1143 type == T_CNAME) { 1144 n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf); 1145 if ((n < 0) || !(*name_ok)(tbuf)) { 1146 had_error++; 1147 continue; 1148 } 1149 cp += n; 1150 /* Get canonical name. */ 1151 n = strlen(tbuf) + 1; /* for the \0 */ 1152 if (n > buflen || n >= MAXHOSTNAMELEN) { 1153 had_error++; 1154 continue; 1155 } 1156 strcpy(bp, tbuf); 1157 canonname = bp; 1158 bp += n; 1159 buflen -= n; 1160 continue; 1161 } 1162 if (qtype == T_ANY) { 1163 if (!(type == T_A || type == T_AAAA)) { 1164 cp += n; 1165 continue; 1166 } 1167 } else if (type != qtype) { 1168 if (type != T_KEY && type != T_SIG) 1169 syslog(LOG_NOTICE|LOG_AUTH, 1170 "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"", 1171 qname, p_class(C_IN), p_type(qtype), 1172 p_type(type)); 1173 cp += n; 1174 continue; /* XXX - had_error++ ? */ 1175 } 1176 switch (type) { 1177 case T_A: 1178 case T_AAAA: 1179 if (strcasecmp(canonname, bp) != 0) { 1180 syslog(LOG_NOTICE|LOG_AUTH, 1181 AskedForGot, canonname, bp); 1182 cp += n; 1183 continue; /* XXX - had_error++ ? */ 1184 } 1185 if (type == T_A && n != INADDRSZ) { 1186 cp += n; 1187 continue; 1188 } 1189 if (type == T_AAAA && n != IN6ADDRSZ) { 1190 cp += n; 1191 continue; 1192 } 1193 if (!haveanswer) { 1194 int nn; 1195 1196 canonname = bp; 1197 nn = strlen(bp) + 1; /* for the \0 */ 1198 bp += nn; 1199 buflen -= nn; 1200 } 1201 1202 /* don't overwrite pai */ 1203 ai = *pai; 1204 ai.ai_family = (type == T_A) ? AF_INET : AF_INET6; 1205 afd = find_afd(ai.ai_family); 1206 if (afd == NULL) { 1207 cp += n; 1208 continue; 1209 } 1210 cur->ai_next = get_ai(&ai, afd, (const char *)cp); 1211 if (cur->ai_next == NULL) 1212 had_error++; 1213 while (cur && cur->ai_next) 1214 cur = cur->ai_next; 1215 cp += n; 1216 break; 1217 default: 1218 abort(); 1219 } 1220 if (!had_error) 1221 haveanswer++; 1222 } 1223 if (haveanswer) { 1224 if (!canonname) 1225 (void)get_canonname(pai, sentinel.ai_next, qname); 1226 else 1227 (void)get_canonname(pai, sentinel.ai_next, canonname); 1228 h_errno = NETDB_SUCCESS; 1229 return sentinel.ai_next; 1230 } 1231 1232 h_errno = NO_RECOVERY; 1233 return NULL; 1234 } 1235 1236 /*ARGSUSED*/ 1237 static int 1238 _dns_getaddrinfo(rv, cb_data, ap) 1239 void *rv; 1240 void *cb_data; 1241 va_list ap; 1242 { 1243 struct addrinfo *ai; 1244 querybuf buf, buf2; 1245 const char *name; 1246 const struct addrinfo *pai; 1247 struct addrinfo sentinel, *cur; 1248 struct res_target q, q2; 1249 1250 name = va_arg(ap, char *); 1251 pai = va_arg(ap, const struct addrinfo *); 1252 1253 memset(&q, 0, sizeof(q2)); 1254 memset(&q2, 0, sizeof(q2)); 1255 memset(&sentinel, 0, sizeof(sentinel)); 1256 cur = &sentinel; 1257 1258 switch (pai->ai_family) { 1259 case AF_UNSPEC: 1260 /* prefer IPv6 */ 1261 q.class = C_IN; 1262 q.type = T_AAAA; 1263 q.answer = buf.buf; 1264 q.anslen = sizeof(buf); 1265 q.next = &q2; 1266 q2.class = C_IN; 1267 q2.type = T_A; 1268 q2.answer = buf2.buf; 1269 q2.anslen = sizeof(buf2); 1270 break; 1271 case AF_INET: 1272 q.class = C_IN; 1273 q.type = T_A; 1274 q.answer = buf.buf; 1275 q.anslen = sizeof(buf); 1276 break; 1277 case AF_INET6: 1278 q.class = C_IN; 1279 q.type = T_AAAA; 1280 q.answer = buf.buf; 1281 q.anslen = sizeof(buf); 1282 break; 1283 default: 1284 return NS_UNAVAIL; 1285 } 1286 if (res_searchN(name, &q) < 0) 1287 return NS_NOTFOUND; 1288 ai = getanswer(&buf, q.n, q.name, q.type, pai); 1289 if (ai) { 1290 cur->ai_next = ai; 1291 while (cur && cur->ai_next) 1292 cur = cur->ai_next; 1293 } 1294 if (q.next) { 1295 ai = getanswer(&buf2, q2.n, q2.name, q2.type, pai); 1296 if (ai) 1297 cur->ai_next = ai; 1298 } 1299 if (sentinel.ai_next == NULL) 1300 switch (h_errno) { 1301 case HOST_NOT_FOUND: 1302 return NS_NOTFOUND; 1303 case TRY_AGAIN: 1304 return NS_TRYAGAIN; 1305 default: 1306 return NS_UNAVAIL; 1307 } 1308 *((struct addrinfo **)rv) = sentinel.ai_next; 1309 return NS_SUCCESS; 1310 } 1311 1312 static void 1313 _sethtent() 1314 { 1315 if (!hostf) 1316 hostf = fopen(_PATH_HOSTS, "r" ); 1317 else 1318 rewind(hostf); 1319 } 1320 1321 static void 1322 _endhtent() 1323 { 1324 if (hostf) { 1325 (void) fclose(hostf); 1326 hostf = NULL; 1327 } 1328 } 1329 1330 static struct addrinfo * 1331 _gethtent(name, pai) 1332 const char *name; 1333 const struct addrinfo *pai; 1334 { 1335 char *p; 1336 char *cp, *tname; 1337 struct addrinfo hints, *res0, *res; 1338 int error; 1339 const char *addr; 1340 char hostbuf[8*1024]; 1341 1342 if (!hostf && !(hostf = fopen(_PATH_HOSTS, "r" ))) 1343 return (NULL); 1344 again: 1345 if (!(p = fgets(hostbuf, sizeof hostbuf, hostf))) 1346 return (NULL); 1347 if (*p == '#') 1348 goto again; 1349 if (!(cp = strpbrk(p, "#\n"))) 1350 goto again; 1351 *cp = '\0'; 1352 if (!(cp = strpbrk(p, " \t"))) 1353 goto again; 1354 *cp++ = '\0'; 1355 addr = p; 1356 /* if this is not something we're looking for, skip it. */ 1357 while (cp && *cp) { 1358 if (*cp == ' ' || *cp == '\t') { 1359 cp++; 1360 continue; 1361 } 1362 tname = cp; 1363 if ((cp = strpbrk(cp, " \t")) != NULL) 1364 *cp++ = '\0'; 1365 if (strcasecmp(name, tname) == 0) 1366 goto found; 1367 } 1368 goto again; 1369 1370 found: 1371 hints = *pai; 1372 hints.ai_flags = AI_NUMERICHOST; 1373 error = getaddrinfo(addr, NULL, &hints, &res0); 1374 if (error) 1375 goto again; 1376 for (res = res0; res; res = res->ai_next) { 1377 /* cover it up */ 1378 res->ai_flags = pai->ai_flags; 1379 1380 if (pai->ai_flags & AI_CANONNAME) { 1381 if (get_canonname(pai, res, name) != 0) { 1382 freeaddrinfo(res0); 1383 goto again; 1384 } 1385 } 1386 } 1387 return res0; 1388 } 1389 1390 /*ARGSUSED*/ 1391 static int 1392 _files_getaddrinfo(rv, cb_data, ap) 1393 void *rv; 1394 void *cb_data; 1395 va_list ap; 1396 { 1397 const char *name; 1398 const struct addrinfo *pai; 1399 struct addrinfo sentinel, *cur; 1400 struct addrinfo *p; 1401 1402 name = va_arg(ap, char *); 1403 pai = va_arg(ap, struct addrinfo *); 1404 1405 memset(&sentinel, 0, sizeof(sentinel)); 1406 cur = &sentinel; 1407 1408 _sethtent(); 1409 while ((p = _gethtent(name, pai)) != NULL) { 1410 cur->ai_next = p; 1411 while (cur && cur->ai_next) 1412 cur = cur->ai_next; 1413 } 1414 _endhtent(); 1415 1416 *((struct addrinfo **)rv) = sentinel.ai_next; 1417 if (sentinel.ai_next == NULL) 1418 return NS_NOTFOUND; 1419 return NS_SUCCESS; 1420 } 1421 1422 #ifdef YP 1423 static char *__ypdomain; 1424 1425 /*ARGSUSED*/ 1426 static struct addrinfo * 1427 _yphostent(line, pai) 1428 char *line; 1429 const struct addrinfo *pai; 1430 { 1431 struct addrinfo sentinel, *cur; 1432 struct addrinfo hints, *res, *res0; 1433 int error; 1434 char *p = line; 1435 const char *addr, *canonname; 1436 char *nextline; 1437 char *cp; 1438 1439 addr = canonname = NULL; 1440 1441 memset(&sentinel, 0, sizeof(sentinel)); 1442 cur = &sentinel; 1443 1444 nextline: 1445 /* terminate line */ 1446 cp = strchr(p, '\n'); 1447 if (cp) { 1448 *cp++ = '\0'; 1449 nextline = cp; 1450 } else 1451 nextline = NULL; 1452 1453 cp = strpbrk(p, " \t"); 1454 if (cp == NULL) { 1455 if (canonname == NULL) 1456 return (NULL); 1457 else 1458 goto done; 1459 } 1460 *cp++ = '\0'; 1461 1462 addr = p; 1463 1464 while (cp && *cp) { 1465 if (*cp == ' ' || *cp == '\t') { 1466 cp++; 1467 continue; 1468 } 1469 if (!canonname) 1470 canonname = cp; 1471 if ((cp = strpbrk(cp, " \t")) != NULL) 1472 *cp++ = '\0'; 1473 } 1474 1475 hints = *pai; 1476 hints.ai_flags = AI_NUMERICHOST; 1477 error = getaddrinfo(addr, NULL, &hints, &res0); 1478 if (error == 0) { 1479 for (res = res0; res; res = res->ai_next) { 1480 /* cover it up */ 1481 res->ai_flags = pai->ai_flags; 1482 1483 if (pai->ai_flags & AI_CANONNAME) 1484 (void)get_canonname(pai, res, canonname); 1485 } 1486 } else 1487 res0 = NULL; 1488 if (res0) { 1489 cur->ai_next = res0; 1490 while (cur && cur->ai_next) 1491 cur = cur->ai_next; 1492 } 1493 1494 if (nextline) { 1495 p = nextline; 1496 goto nextline; 1497 } 1498 1499 done: 1500 return sentinel.ai_next; 1501 } 1502 1503 /*ARGSUSED*/ 1504 static int 1505 _yp_getaddrinfo(rv, cb_data, ap) 1506 void *rv; 1507 void *cb_data; 1508 va_list ap; 1509 { 1510 struct addrinfo sentinel, *cur; 1511 struct addrinfo *ai = NULL; 1512 static char *__ypcurrent; 1513 int __ypcurrentlen, r; 1514 const char *name; 1515 const struct addrinfo *pai; 1516 1517 name = va_arg(ap, char *); 1518 pai = va_arg(ap, const struct addrinfo *); 1519 1520 memset(&sentinel, 0, sizeof(sentinel)); 1521 cur = &sentinel; 1522 1523 if (!__ypdomain) { 1524 if (_yp_check(&__ypdomain) == 0) 1525 return NS_UNAVAIL; 1526 } 1527 if (__ypcurrent) 1528 free(__ypcurrent); 1529 __ypcurrent = NULL; 1530 1531 /* hosts.byname is only for IPv4 (Solaris8) */ 1532 if (pai->ai_family == PF_UNSPEC || pai->ai_family == PF_INET) { 1533 r = yp_match(__ypdomain, "hosts.byname", name, 1534 (int)strlen(name), &__ypcurrent, &__ypcurrentlen); 1535 if (r == 0) { 1536 struct addrinfo ai4; 1537 1538 ai4 = *pai; 1539 ai4.ai_family = AF_INET; 1540 ai = _yphostent(__ypcurrent, &ai4); 1541 if (ai) { 1542 cur->ai_next = ai; 1543 while (cur && cur->ai_next) 1544 cur = cur->ai_next; 1545 } 1546 } 1547 } 1548 1549 /* ipnodes.byname can hold both IPv4/v6 */ 1550 r = yp_match(__ypdomain, "ipnodes.byname", name, 1551 (int)strlen(name), &__ypcurrent, &__ypcurrentlen); 1552 if (r == 0) { 1553 ai = _yphostent(__ypcurrent, pai); 1554 if (ai) { 1555 cur->ai_next = ai; 1556 while (cur && cur->ai_next) 1557 cur = cur->ai_next; 1558 } 1559 } 1560 1561 if (sentinel.ai_next == NULL) { 1562 h_errno = HOST_NOT_FOUND; 1563 return NS_NOTFOUND; 1564 } 1565 *((struct addrinfo **)rv) = sentinel.ai_next; 1566 return NS_SUCCESS; 1567 } 1568 #endif 1569 1570 /* resolver logic */ 1571 1572 extern const char *__hostalias __P((const char *)); 1573 extern int h_errno; 1574 1575 /* 1576 * Formulate a normal query, send, and await answer. 1577 * Returned answer is placed in supplied buffer "answer". 1578 * Perform preliminary check of answer, returning success only 1579 * if no error is indicated and the answer count is nonzero. 1580 * Return the size of the response on success, -1 on error. 1581 * Error number is left in h_errno. 1582 * 1583 * Caller must parse answer and determine whether it answers the question. 1584 */ 1585 static int 1586 res_queryN(name, target) 1587 const char *name; /* domain name */ 1588 struct res_target *target; 1589 { 1590 u_char buf[MAXPACKET]; 1591 HEADER *hp; 1592 int n; 1593 struct res_target *t; 1594 int rcode; 1595 int ancount; 1596 1597 rcode = NOERROR; 1598 ancount = 0; 1599 1600 if ((_res.options & RES_INIT) == 0 && res_init() == -1) { 1601 h_errno = NETDB_INTERNAL; 1602 return (-1); 1603 } 1604 1605 for (t = target; t; t = t->next) { 1606 int class, type; 1607 u_char *answer; 1608 int anslen; 1609 1610 hp = (HEADER *)(void *)t->answer; 1611 hp->rcode = NOERROR; /* default */ 1612 1613 /* make it easier... */ 1614 class = t->class; 1615 type = t->type; 1616 answer = t->answer; 1617 anslen = t->anslen; 1618 #ifdef DEBUG 1619 if (_res.options & RES_DEBUG) 1620 printf(";; res_query(%s, %d, %d)\n", name, class, type); 1621 #endif 1622 1623 n = res_mkquery(QUERY, name, class, type, NULL, 0, NULL, 1624 buf, sizeof(buf)); 1625 if (n <= 0) { 1626 #ifdef DEBUG 1627 if (_res.options & RES_DEBUG) 1628 printf(";; res_query: mkquery failed\n"); 1629 #endif 1630 h_errno = NO_RECOVERY; 1631 return (n); 1632 } 1633 n = res_send(buf, n, answer, anslen); 1634 #if 0 1635 if (n < 0) { 1636 #ifdef DEBUG 1637 if (_res.options & RES_DEBUG) 1638 printf(";; res_query: send error\n"); 1639 #endif 1640 h_errno = TRY_AGAIN; 1641 return (n); 1642 } 1643 #endif 1644 1645 if (n < 0 || hp->rcode != NOERROR || ntohs(hp->ancount) == 0) { 1646 rcode = hp->rcode; /* record most recent error */ 1647 #ifdef DEBUG 1648 if (_res.options & RES_DEBUG) 1649 printf(";; rcode = %d, ancount=%d\n", hp->rcode, 1650 ntohs(hp->ancount)); 1651 #endif 1652 continue; 1653 } 1654 1655 ancount += ntohs(hp->ancount); 1656 1657 t->n = n; 1658 } 1659 1660 if (ancount == 0) { 1661 switch (rcode) { 1662 case NXDOMAIN: 1663 h_errno = HOST_NOT_FOUND; 1664 break; 1665 case SERVFAIL: 1666 h_errno = TRY_AGAIN; 1667 break; 1668 case NOERROR: 1669 h_errno = NO_DATA; 1670 break; 1671 case FORMERR: 1672 case NOTIMP: 1673 case REFUSED: 1674 default: 1675 h_errno = NO_RECOVERY; 1676 break; 1677 } 1678 return (-1); 1679 } 1680 return (ancount); 1681 } 1682 1683 /* 1684 * Formulate a normal query, send, and retrieve answer in supplied buffer. 1685 * Return the size of the response on success, -1 on error. 1686 * If enabled, implement search rules until answer or unrecoverable failure 1687 * is detected. Error code, if any, is left in h_errno. 1688 */ 1689 static int 1690 res_searchN(name, target) 1691 const char *name; /* domain name */ 1692 struct res_target *target; 1693 { 1694 const char *cp, * const *domain; 1695 HEADER *hp = (HEADER *)(void *)target->answer; /*XXX*/ 1696 u_int dots; 1697 int trailing_dot, ret, saved_herrno; 1698 int got_nodata = 0, got_servfail = 0, tried_as_is = 0; 1699 1700 if ((_res.options & RES_INIT) == 0 && res_init() == -1) { 1701 h_errno = NETDB_INTERNAL; 1702 return (-1); 1703 } 1704 1705 errno = 0; 1706 h_errno = HOST_NOT_FOUND; /* default, if we never query */ 1707 dots = 0; 1708 for (cp = name; *cp; cp++) 1709 dots += (*cp == '.'); 1710 trailing_dot = 0; 1711 if (cp > name && *--cp == '.') 1712 trailing_dot++; 1713 1714 /* 1715 * if there aren't any dots, it could be a user-level alias 1716 */ 1717 if (!dots && (cp = __hostalias(name)) != NULL) 1718 return (res_queryN(cp, target)); 1719 1720 /* 1721 * If there are dots in the name already, let's just give it a try 1722 * 'as is'. The threshold can be set with the "ndots" option. 1723 */ 1724 saved_herrno = -1; 1725 if (dots >= _res.ndots) { 1726 ret = res_querydomainN(name, NULL, target); 1727 if (ret > 0) 1728 return (ret); 1729 saved_herrno = h_errno; 1730 tried_as_is++; 1731 } 1732 1733 /* 1734 * We do at least one level of search if 1735 * - there is no dot and RES_DEFNAME is set, or 1736 * - there is at least one dot, there is no trailing dot, 1737 * and RES_DNSRCH is set. 1738 */ 1739 if ((!dots && (_res.options & RES_DEFNAMES)) || 1740 (dots && !trailing_dot && (_res.options & RES_DNSRCH))) { 1741 int done = 0; 1742 1743 for (domain = (const char * const *)_res.dnsrch; 1744 *domain && !done; 1745 domain++) { 1746 1747 ret = res_querydomainN(name, *domain, target); 1748 if (ret > 0) 1749 return (ret); 1750 1751 /* 1752 * If no server present, give up. 1753 * If name isn't found in this domain, 1754 * keep trying higher domains in the search list 1755 * (if that's enabled). 1756 * On a NO_DATA error, keep trying, otherwise 1757 * a wildcard entry of another type could keep us 1758 * from finding this entry higher in the domain. 1759 * If we get some other error (negative answer or 1760 * server failure), then stop searching up, 1761 * but try the input name below in case it's 1762 * fully-qualified. 1763 */ 1764 if (errno == ECONNREFUSED) { 1765 h_errno = TRY_AGAIN; 1766 return (-1); 1767 } 1768 1769 switch (h_errno) { 1770 case NO_DATA: 1771 got_nodata++; 1772 /* FALLTHROUGH */ 1773 case HOST_NOT_FOUND: 1774 /* keep trying */ 1775 break; 1776 case TRY_AGAIN: 1777 if (hp->rcode == SERVFAIL) { 1778 /* try next search element, if any */ 1779 got_servfail++; 1780 break; 1781 } 1782 /* FALLTHROUGH */ 1783 default: 1784 /* anything else implies that we're done */ 1785 done++; 1786 } 1787 /* 1788 * if we got here for some reason other than DNSRCH, 1789 * we only wanted one iteration of the loop, so stop. 1790 */ 1791 if (!(_res.options & RES_DNSRCH)) 1792 done++; 1793 } 1794 } 1795 1796 /* 1797 * if we have not already tried the name "as is", do that now. 1798 * note that we do this regardless of how many dots were in the 1799 * name or whether it ends with a dot. 1800 */ 1801 if (!tried_as_is) { 1802 ret = res_querydomainN(name, NULL, target); 1803 if (ret > 0) 1804 return (ret); 1805 } 1806 1807 /* 1808 * if we got here, we didn't satisfy the search. 1809 * if we did an initial full query, return that query's h_errno 1810 * (note that we wouldn't be here if that query had succeeded). 1811 * else if we ever got a nodata, send that back as the reason. 1812 * else send back meaningless h_errno, that being the one from 1813 * the last DNSRCH we did. 1814 */ 1815 if (saved_herrno != -1) 1816 h_errno = saved_herrno; 1817 else if (got_nodata) 1818 h_errno = NO_DATA; 1819 else if (got_servfail) 1820 h_errno = TRY_AGAIN; 1821 return (-1); 1822 } 1823 1824 /* 1825 * Perform a call on res_query on the concatenation of name and domain, 1826 * removing a trailing dot from name if domain is NULL. 1827 */ 1828 static int 1829 res_querydomainN(name, domain, target) 1830 const char *name, *domain; 1831 struct res_target *target; 1832 { 1833 char nbuf[MAXDNAME]; 1834 const char *longname = nbuf; 1835 size_t n, d; 1836 1837 if ((_res.options & RES_INIT) == 0 && res_init() == -1) { 1838 h_errno = NETDB_INTERNAL; 1839 return (-1); 1840 } 1841 #ifdef DEBUG 1842 if (_res.options & RES_DEBUG) 1843 printf(";; res_querydomain(%s, %s)\n", 1844 name, domain?domain:"<Nil>"); 1845 #endif 1846 if (domain == NULL) { 1847 /* 1848 * Check for trailing '.'; 1849 * copy without '.' if present. 1850 */ 1851 n = strlen(name); 1852 if (n >= MAXDNAME) { 1853 h_errno = NO_RECOVERY; 1854 return (-1); 1855 } 1856 if (n > 0 && name[--n] == '.') { 1857 strncpy(nbuf, name, n); 1858 nbuf[n] = '\0'; 1859 } else 1860 longname = name; 1861 } else { 1862 n = strlen(name); 1863 d = strlen(domain); 1864 if (n + d + 1 >= MAXDNAME) { 1865 h_errno = NO_RECOVERY; 1866 return (-1); 1867 } 1868 sprintf(nbuf, "%s.%s", name, domain); 1869 } 1870 return (res_queryN(longname, target)); 1871 } 1872