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