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