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