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