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