1/* $NetBSD: getaddrinfo.c,v 1.5 2007/07/22 05:19:01 lukem Exp $ */ 2/* from ? */ 3 4/* 5 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the project nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33/* 34 * Issues to be discussed: 35 * - Thread safe-ness must be checked. 36 * - Return values. There are nonstandard return values defined and used 37 * in the source code. This is because RFC2553 is silent about which error 38 * code must be returned for which situation. 39 * - IPv4 classful (shortened) form. RFC2553 is silent about it. XNET 5.2 40 * says to use inet_aton() to convert IPv4 numeric to binary (alows 41 * classful form as a result). 42 * current code - disallow classful form for IPv4 (due to use of inet_pton). 43 * - freeaddrinfo(NULL). RFC2553 is silent about it. XNET 5.2 says it is 44 * invalid. 45 * current code - SEGV on freeaddrinfo(NULL) 46 * Note: 47 * - We use getipnodebyname() just for thread-safeness. There's no intent 48 * to let it do PF_UNSPEC (actually we never pass PF_UNSPEC to 49 * getipnodebyname(). 50 * - The code filters out AFs that are not supported by the kernel, 51 * when globbing NULL hostname (to loopback, or wildcard). Is it the right 52 * thing to do? What is the relationship with post-RFC2553 AI_ADDRCONFIG 53 * in ai_flags? 54 * - (post-2553) semantics of AI_ADDRCONFIG itself is too vague. 55 * (1) what should we do against numeric hostname (2) what should we do 56 * against NULL hostname (3) what is AI_ADDRCONFIG itself. AF not ready? 57 * non-loopback address configured? global address configured? 58 * - The code makes use of following calls when asked to resolver with 59 * ai_family = PF_UNSPEC: 60 * getipnodebyname(host, AF_INET6); 61 * getipnodebyname(host, AF_INET); 62 * This will result in the following queries if the node is configure to 63 * prefer /etc/hosts than DNS: 64 * lookup /etc/hosts for IPv6 address 65 * lookup DNS for IPv6 address 66 * lookup /etc/hosts for IPv4 address 67 * lookup DNS for IPv4 address 68 * which may not meet people's requirement. 69 * The right thing to happen is to have underlying layer which does 70 * PF_UNSPEC lookup (lookup both) and return chain of addrinfos. 71 * This would result in a bit of code duplicate with _dns_ghbyname() and 72 * friends. 73 */ 74 75#include "tnftp.h" 76 77#define SUCCESS 0 78#define ANY 0 79#define YES 1 80#define NO 0 81 82static const char in_addrany[] = { 0, 0, 0, 0 }; 83static const char in_loopback[] = { 127, 0, 0, 1 }; 84#ifdef INET6 85static const char in6_addrany[] = { 86 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 87}; 88static const char in6_loopback[] = { 89 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 90}; 91#endif 92 93static const struct afd { 94 int a_af; 95 int a_addrlen; 96 int a_socklen; 97 int a_off; 98 const char *a_addrany; 99 const char *a_loopback; 100 int a_scoped; 101} afdl [] = { 102#ifdef INET6 103 {PF_INET6, sizeof(struct in6_addr), 104 sizeof(struct sockaddr_in6), 105 offsetof(struct sockaddr_in6, sin6_addr), 106 in6_addrany, in6_loopback, 1}, 107#endif 108 {PF_INET, sizeof(struct in_addr), 109 sizeof(struct sockaddr_in), 110 offsetof(struct sockaddr_in, sin_addr), 111 in_addrany, in_loopback, 0}, 112 {0, 0, 0, 0, NULL, NULL, 0}, 113}; 114 115struct explore { 116 int e_af; 117 int e_socktype; 118 int e_protocol; 119 const char *e_protostr; 120 int e_wild; 121#define WILD_AF(ex) ((ex)->e_wild & 0x01) 122#define WILD_SOCKTYPE(ex) ((ex)->e_wild & 0x02) 123#define WILD_PROTOCOL(ex) ((ex)->e_wild & 0x04) 124}; 125 126static const struct explore explore[] = { 127#if 0 128 { PF_LOCAL, 0, ANY, ANY, NULL, 0x01 }, 129#endif 130#ifdef INET6 131 { PF_INET6, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 }, 132 { PF_INET6, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 }, 133 { PF_INET6, SOCK_RAW, ANY, NULL, 0x05 }, 134#endif 135 { PF_INET, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 }, 136 { PF_INET, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 }, 137 { PF_INET, SOCK_RAW, ANY, NULL, 0x05 }, 138 { -1, 0, 0, NULL, 0 }, 139}; 140 141#ifdef INET6 142#define PTON_MAX 16 143#else 144#define PTON_MAX 4 145#endif 146 147 148static int str_isnumber(const char *); 149static int explore_fqdn(const struct addrinfo *, const char *, 150 const char *, struct addrinfo **); 151static int explore_null(const struct addrinfo *, 152 const char *, struct addrinfo **); 153static int explore_numeric(const struct addrinfo *, const char *, 154 const char *, struct addrinfo **); 155static int explore_numeric_scope(const struct addrinfo *, const char *, 156 const char *, struct addrinfo **); 157static int get_canonname(const struct addrinfo *, 158 struct addrinfo *, const char *); 159static struct addrinfo *get_ai(const struct addrinfo *, 160 const struct afd *, const char *); 161static int get_portmatch(const struct addrinfo *, const char *); 162static int get_port(struct addrinfo *, const char *, int); 163static const struct afd *find_afd(int); 164static int addrconfig(const struct addrinfo *); 165#ifdef INET6 166static int ip6_str2scopeid(char *, struct sockaddr_in6 *); 167#endif 168 169static char *ai_errlist[] = { 170 "Success", 171 "Address family for hostname not supported", /* EAI_ADDRFAMILY */ 172 "Temporary failure in name resolution", /* EAI_AGAIN */ 173 "Invalid value for ai_flags", /* EAI_BADFLAGS */ 174 "Non-recoverable failure in name resolution", /* EAI_FAIL */ 175 "ai_family not supported", /* EAI_FAMILY */ 176 "Memory allocation failure", /* EAI_MEMORY */ 177 "No address associated with hostname", /* EAI_NODATA */ 178 "hostname nor servname provided, or not known", /* EAI_NONAME */ 179 "servname not supported for ai_socktype", /* EAI_SERVICE */ 180 "ai_socktype not supported", /* EAI_SOCKTYPE */ 181 "System error returned in errno", /* EAI_SYSTEM */ 182 "Invalid value for hints", /* EAI_BADHINTS */ 183 "Resolved protocol is unknown", /* EAI_PROTOCOL */ 184 "Unknown error", /* EAI_MAX */ 185}; 186 187/* XXX macros that make external reference is BAD. */ 188 189#define GET_AI(ai, afd, addr) \ 190do { \ 191 /* external reference: pai, error, and label free */ \ 192 (ai) = get_ai(pai, (afd), (addr)); \ 193 if ((ai) == NULL) { \ 194 error = EAI_MEMORY; \ 195 goto free; \ 196 } \ 197} while (/*CONSTCOND*/0) 198 199#define GET_PORT(ai, serv) \ 200do { \ 201 /* external reference: error and label free */ \ 202 error = get_port((ai), (serv), 0); \ 203 if (error != 0) \ 204 goto free; \ 205} while (/*CONSTCOND*/0) 206 207#define GET_CANONNAME(ai, str) \ 208do { \ 209 /* external reference: pai, error and label free */ \ 210 error = get_canonname(pai, (ai), (str)); \ 211 if (error != 0) \ 212 goto free; \ 213} while (/*CONSTCOND*/0) 214 215#define ERR(err) \ 216do { \ 217 /* external reference: error, and label bad */ \ 218 error = (err); \ 219 goto bad; \ 220 /*NOTREACHED*/ \ 221} while (/*CONSTCOND*/0) 222 223#define MATCH_FAMILY(x, y, w) \ 224 ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == PF_UNSPEC || (y) == PF_UNSPEC))) 225#define MATCH(x, y, w) \ 226 ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == ANY || (y) == ANY))) 227 228const char * 229gai_strerror(int ecode) 230{ 231 if (ecode < 0 || ecode > EAI_MAX) 232 ecode = EAI_MAX; 233 return ai_errlist[ecode]; 234} 235 236void 237freeaddrinfo(struct addrinfo *ai) 238{ 239 struct addrinfo *next; 240 241 do { 242 next = ai->ai_next; 243 if (ai->ai_canonname) 244 free(ai->ai_canonname); 245 /* no need to free(ai->ai_addr) */ 246 free(ai); 247 ai = next; 248 } while (ai); 249} 250 251static int 252str_isnumber(const char *p) 253{ 254 char *ep; 255 long l; 256 257 if (*p == '\0') 258 return NO; 259 ep = NULL; 260 l = strtol(p, &ep, 10); 261 if (ep && *ep == '\0' && l >= 0) 262 return YES; 263 else 264 return NO; 265} 266 267int 268getaddrinfo(const char *hostname, const char *servname, 269 const struct addrinfo *hints, struct addrinfo **res) 270{ 271 struct addrinfo sentinel; 272 struct addrinfo *cur; 273 int error = 0; 274 struct addrinfo ai; 275 struct addrinfo ai0; 276 struct addrinfo *pai; 277 const struct afd *afd; 278 const struct explore *ex; 279 280 memset(&sentinel, 0, sizeof(sentinel)); 281 cur = &sentinel; 282 pai = &ai; 283 pai->ai_flags = 0; 284 pai->ai_family = PF_UNSPEC; 285 pai->ai_socktype = ANY; 286 pai->ai_protocol = ANY; 287 pai->ai_addrlen = 0; 288 pai->ai_canonname = NULL; 289 pai->ai_addr = NULL; 290 pai->ai_next = NULL; 291 292 if (hostname == NULL && servname == NULL) 293 return EAI_NONAME; 294 if (hints) { 295 /* error check for hints */ 296 if (hints->ai_addrlen || hints->ai_canonname || 297 hints->ai_addr || hints->ai_next) 298 ERR(EAI_BADHINTS); /* xxx */ 299 if (hints->ai_flags & ~AI_MASK) 300 ERR(EAI_BADFLAGS); 301 switch (hints->ai_family) { 302 case PF_UNSPEC: 303 case PF_INET: 304#ifdef INET6 305 case PF_INET6: 306#endif 307 break; 308 default: 309 ERR(EAI_FAMILY); 310 } 311 memcpy(pai, hints, sizeof(*pai)); 312 313 /* 314 * if both socktype/protocol are specified, check if they 315 * are meaningful combination. 316 */ 317 if (pai->ai_socktype != ANY && pai->ai_protocol != ANY) { 318 for (ex = explore; ex->e_af >= 0; ex++) { 319 if (pai->ai_family != ex->e_af) 320 continue; 321 if (ex->e_socktype == ANY) 322 continue; 323 if (ex->e_protocol == ANY) 324 continue; 325 if (pai->ai_socktype == ex->e_socktype 326 && pai->ai_protocol != ex->e_protocol) { 327 ERR(EAI_BADHINTS); 328 } 329 } 330 } 331 } 332 333 /* 334 * post-2553: AI_ALL and AI_V4MAPPED are effective only against 335 * AF_INET6 query. They needs to be ignored if specified in other 336 * occassions. 337 */ 338 switch (pai->ai_flags & (AI_ALL | AI_V4MAPPED)) { 339 case AI_V4MAPPED: 340 case AI_ALL | AI_V4MAPPED: 341#ifdef INET6 /* XXXLUKEM */ 342 if (pai->ai_family != AF_INET6) 343 pai->ai_flags &= ~(AI_ALL | AI_V4MAPPED); 344 break; 345#endif 346 case AI_ALL: 347#if 1 348 /* illegal */ 349 ERR(EAI_BADFLAGS); 350#else 351 pai->ai_flags &= ~(AI_ALL | AI_V4MAPPED); 352#endif 353 break; 354 } 355 356 /* 357 * check for special cases. (1) numeric servname is disallowed if 358 * socktype/protocol are left unspecified. (2) servname is disallowed 359 * for raw and other inet{,6} sockets. 360 */ 361 if (MATCH_FAMILY(pai->ai_family, PF_INET, 1) 362#ifdef PF_INET6 363 || MATCH_FAMILY(pai->ai_family, PF_INET6, 1) 364#endif 365 ) { 366 ai0 = *pai; /* backup *pai */ 367 368 if (pai->ai_family == PF_UNSPEC) { 369#ifdef PF_INET6 370 pai->ai_family = PF_INET6; 371#else 372 pai->ai_family = PF_INET; 373#endif 374 } 375 error = get_portmatch(pai, servname); 376 if (error) 377 ERR(error); 378 379 *pai = ai0; 380 } 381 382 ai0 = *pai; 383 384 /* NULL hostname, or numeric hostname */ 385 for (ex = explore; ex->e_af >= 0; ex++) { 386 *pai = ai0; 387 388 if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex))) 389 continue; 390 if (!MATCH(pai->ai_socktype, ex->e_socktype, WILD_SOCKTYPE(ex))) 391 continue; 392 if (!MATCH(pai->ai_protocol, ex->e_protocol, WILD_PROTOCOL(ex))) 393 continue; 394 395 if (pai->ai_family == PF_UNSPEC) 396 pai->ai_family = ex->e_af; 397 if (pai->ai_socktype == ANY && ex->e_socktype != ANY) 398 pai->ai_socktype = ex->e_socktype; 399 if (pai->ai_protocol == ANY && ex->e_protocol != ANY) 400 pai->ai_protocol = ex->e_protocol; 401 402 if (hostname == NULL) 403 error = explore_null(pai, servname, &cur->ai_next); 404 else 405 error = explore_numeric_scope(pai, hostname, servname, &cur->ai_next); 406 407 if (error) 408 goto free; 409 410 while (cur && cur->ai_next) 411 cur = cur->ai_next; 412 } 413 414 /* 415 * XXX 416 * If numreic representation of AF1 can be interpreted as FQDN 417 * representation of AF2, we need to think again about the code below. 418 */ 419 if (sentinel.ai_next) 420 goto good; 421 422 if (pai->ai_flags & AI_NUMERICHOST) 423 ERR(EAI_NODATA); 424 if (hostname == NULL) 425 ERR(EAI_NODATA); 426 427 /* 428 * hostname as alphabetical name. 429 * we would like to prefer AF_INET6 than AF_INET, so we'll make a 430 * outer loop by AFs. 431 */ 432 for (afd = afdl; afd->a_af; afd++) { 433 *pai = ai0; 434 435 if (!MATCH_FAMILY(pai->ai_family, afd->a_af, 1)) 436 continue; 437 438 for (ex = explore; ex->e_af >= 0; ex++) { 439 *pai = ai0; 440 441 if (pai->ai_family == PF_UNSPEC) 442 pai->ai_family = afd->a_af; 443 444 if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex))) 445 continue; 446 if (!MATCH(pai->ai_socktype, ex->e_socktype, 447 WILD_SOCKTYPE(ex))) { 448 continue; 449 } 450 if (!MATCH(pai->ai_protocol, ex->e_protocol, 451 WILD_PROTOCOL(ex))) { 452 continue; 453 } 454 455 if (pai->ai_family == PF_UNSPEC) 456 pai->ai_family = ex->e_af; 457 if (pai->ai_socktype == ANY && ex->e_socktype != ANY) 458 pai->ai_socktype = ex->e_socktype; 459 if (pai->ai_protocol == ANY && ex->e_protocol != ANY) 460 pai->ai_protocol = ex->e_protocol; 461 462 error = explore_fqdn(pai, hostname, servname, 463 &cur->ai_next); 464 465 while (cur && cur->ai_next) 466 cur = cur->ai_next; 467 } 468 } 469 470 /* XXX */ 471 if (sentinel.ai_next) 472 error = 0; 473 474 if (error) 475 goto free; 476 if (error == 0) { 477 if (sentinel.ai_next) { 478 good: 479 *res = sentinel.ai_next; 480 return SUCCESS; 481 } else 482 error = EAI_FAIL; 483 } 484 free: 485 bad: 486 if (sentinel.ai_next) 487 freeaddrinfo(sentinel.ai_next); 488 *res = NULL; 489 return error; 490} 491 492/* 493 * FQDN hostname, DNS lookup 494 */ 495static int 496explore_fqdn(const struct addrinfo *pai, const char *hostname, 497 const char *servname, struct addrinfo **res) 498{ 499 struct hostent *hp; 500 int h_error; 501 int af; 502 char **aplist = NULL, *apbuf = NULL; 503 char *ap; 504 struct addrinfo sentinel, *cur; 505 int i; 506#ifndef USE_GETIPNODEBY 507 int naddrs; 508#endif 509 const struct afd *afd; 510 int error = 0; 511#if 0 512 struct addrinfo pai4; 513#ifdef INET6 514 struct addrinfo pai6; 515#endif 516#endif 517 518 *res = NULL; 519 sentinel.ai_next = NULL; 520 cur = &sentinel; 521 522 /* 523 * If AI_ADDRCONFIG is specified, check if we are expected to 524 * return the address family or not. 525 * assumes PF_UNSPEC = PF_INET + PF_INET6. 526 * 527 * NOTE: PF_UNSPEC case is for future use. 528 */ 529 if ((pai->ai_flags & AI_ADDRCONFIG) != 0) { 530 switch (pai->ai_family) { 531#if 0 532 case PF_UNSPEC: 533 pai4 = pai6 = *pai; 534 pai4.ai_family = PF_INET; 535#ifndef INET6 536 if (!addrconfig(&pai4)) 537 return 0; 538#else 539 pai6.ai_family = PF_INET6; 540 if (!addrconfig(&pai4)) { 541 if (!addrconfig(&pai6)) 542 return 0; 543 pai = &pai6; 544 } else { 545 if (!addrconfig(&pai6)) 546 pai = &pai4; 547 else 548 ; /* as is */ 549 } 550#endif 551 break; 552#endif 553 default: 554 if (!addrconfig(pai)) 555 return 0; 556 break; 557 } 558 } 559 560 /* 561 * if the servname does not match socktype/protocol, ignore it. 562 */ 563 if (get_portmatch(pai, servname) != 0) 564 return 0; 565 566 afd = find_afd(pai->ai_family); 567 if (afd == NULL) 568 return 0; 569 570#ifdef USE_GETIPNODEBY 571 hp = getipnodebyname(hostname, pai->ai_family, 572 pai->ai_flags & AI_ADDRCONFIG, &h_error); 573#else 574#if defined(HAVE_GETHOSTBYNAME2) 575 hp = gethostbyname2(hostname, pai->ai_family); 576#else 577 if (pai->ai_family != AF_INET) 578 return 0; 579 hp = gethostbyname(hostname); 580#endif /* defined(HAVE_GETHOSTBYNAME2) */ 581#if defined(HAVE_H_ERRNO) 582 h_error = h_errno; 583#else 584 h_error = EINVAL; 585#endif 586#endif /*USE_GETIPNODEBY*/ 587 588 if (hp == NULL) { 589 switch (h_error) { 590 case HOST_NOT_FOUND: 591 case NO_DATA: 592 error = EAI_NODATA; 593 break; 594 case TRY_AGAIN: 595 error = EAI_AGAIN; 596 break; 597 case NO_RECOVERY: 598#ifdef NETDB_INTERNAL 599 case NETDB_INTERNAL: 600#endif 601 default: 602 error = EAI_FAIL; 603 break; 604 } 605 } else if ((hp->h_name == NULL) || (hp->h_name[0] == 0) 606 || (hp->h_addr_list[0] == NULL)) { 607#ifdef USE_GETIPNODEBY 608 freehostent(hp); 609#endif 610 hp = NULL; 611 error = EAI_FAIL; 612 } 613 614 if (hp == NULL) 615 goto free; 616 617#ifdef USE_GETIPNODEBY 618 aplist = hp->h_addr_list; 619#else 620 /* 621 * hp will be overwritten if we use gethostbyname2(). 622 * always deep copy for simplification. 623 */ 624 for (naddrs = 0; hp->h_addr_list[naddrs] != NULL; naddrs++) 625 ; 626 naddrs++; 627 aplist = (char **)malloc(sizeof(aplist[0]) * naddrs); 628 apbuf = (char *)malloc((size_t)hp->h_length * naddrs); 629 if (aplist == NULL || apbuf == NULL) { 630 error = EAI_MEMORY; 631 goto free; 632 } 633 memset(aplist, 0, sizeof(aplist[0]) * naddrs); 634 for (i = 0; i < naddrs; i++) { 635 if (hp->h_addr_list[i] == NULL) { 636 aplist[i] = NULL; 637 continue; 638 } 639 memcpy(&apbuf[i * hp->h_length], hp->h_addr_list[i], 640 (size_t)hp->h_length); 641 aplist[i] = &apbuf[i * hp->h_length]; 642 } 643#endif 644 645 for (i = 0; aplist[i] != NULL; i++) { 646 af = hp->h_addrtype; 647 ap = aplist[i]; 648#ifdef INET6 649 if (af == AF_INET6 650 && IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ap)) { 651 af = AF_INET; 652 ap = ap + sizeof(struct in6_addr) 653 - sizeof(struct in_addr); 654 } 655#endif 656 657 if (af != pai->ai_family) 658 continue; 659 660 GET_AI(cur->ai_next, afd, ap); 661 GET_PORT(cur->ai_next, servname); 662 if ((pai->ai_flags & AI_CANONNAME) != 0) { 663 /* 664 * RFC2553 says that ai_canonname will be set only for 665 * the first element. we do it for all the elements, 666 * just for convenience. 667 */ 668 GET_CANONNAME(cur->ai_next, hp->h_name); 669 } 670 671 while (cur && cur->ai_next) 672 cur = cur->ai_next; 673 } 674 675 *res = sentinel.ai_next; 676 return 0; 677 678free: 679#ifdef USE_GETIPNODEBY 680 if (hp) 681 freehostent(hp); 682#endif 683 if (aplist) 684 free(aplist); 685 if (apbuf) 686 free(apbuf); 687 if (sentinel.ai_next) 688 freeaddrinfo(sentinel.ai_next); 689 return error; 690} 691 692/* 693 * hostname == NULL. 694 * passive socket -> anyaddr (0.0.0.0 or ::) 695 * non-passive socket -> localhost (127.0.0.1 or ::1) 696 */ 697static int 698explore_null(const struct addrinfo *pai, const char *servname, 699 struct addrinfo **res) 700{ 701 const struct afd *afd; 702 struct addrinfo *cur; 703 struct addrinfo sentinel; 704 int error; 705 706 *res = NULL; 707 sentinel.ai_next = NULL; 708 cur = &sentinel; 709 710 /* 711 * filter out AFs that are not supported by the kernel 712 * XXX errno? 713 */ 714 if (!addrconfig(pai)) 715 return 0; 716 717 /* 718 * if the servname does not match socktype/protocol, ignore it. 719 */ 720 if (get_portmatch(pai, servname) != 0) 721 return 0; 722 723 afd = find_afd(pai->ai_family); 724 if (afd == NULL) 725 return 0; 726 727 if (pai->ai_flags & AI_PASSIVE) { 728 GET_AI(cur->ai_next, afd, afd->a_addrany); 729 /* xxx meaningless? 730 * GET_CANONNAME(cur->ai_next, "anyaddr"); 731 */ 732 GET_PORT(cur->ai_next, servname); 733 } else { 734 GET_AI(cur->ai_next, afd, afd->a_loopback); 735 /* xxx meaningless? 736 * GET_CANONNAME(cur->ai_next, "localhost"); 737 */ 738 GET_PORT(cur->ai_next, servname); 739 } 740 cur = cur->ai_next; 741 742 *res = sentinel.ai_next; 743 return 0; 744 745free: 746 if (sentinel.ai_next) 747 freeaddrinfo(sentinel.ai_next); 748 return error; 749} 750 751/* 752 * numeric hostname 753 */ 754static int 755explore_numeric(const struct addrinfo *pai, const char *hostname, 756 const char *servname, struct addrinfo **res) 757{ 758 const struct afd *afd; 759 struct addrinfo *cur; 760 struct addrinfo sentinel; 761 int error; 762 char pton[PTON_MAX]; 763 764 *res = NULL; 765 sentinel.ai_next = NULL; 766 cur = &sentinel; 767 768 /* 769 * if the servname does not match socktype/protocol, ignore it. 770 */ 771 if (get_portmatch(pai, servname) != 0) 772 return 0; 773 774 afd = find_afd(pai->ai_family); 775 if (afd == NULL) 776 return 0; 777 778 switch (afd->a_af) { 779#if 0 /*X/Open spec*/ 780 case AF_INET: 781 if (inet_aton(hostname, (struct in_addr *)pton) == 1) { 782 if (pai->ai_family == afd->a_af || 783 pai->ai_family == PF_UNSPEC /*?*/) { 784 GET_AI(cur->ai_next, afd, pton); 785 GET_PORT(cur->ai_next, servname); 786 while (cur && cur->ai_next) 787 cur = cur->ai_next; 788 } else 789 ERR(EAI_FAMILY); /*xxx*/ 790 } 791 break; 792#endif 793 default: 794 if (inet_pton(afd->a_af, hostname, pton) == 1) { 795 if (pai->ai_family == afd->a_af || 796 pai->ai_family == PF_UNSPEC /*?*/) { 797 GET_AI(cur->ai_next, afd, pton); 798 GET_PORT(cur->ai_next, servname); 799 while (cur && cur->ai_next) 800 cur = cur->ai_next; 801 } else 802 ERR(EAI_FAMILY); /*xxx*/ 803 } 804 break; 805 } 806 807 *res = sentinel.ai_next; 808 return 0; 809 810free: 811bad: 812 if (sentinel.ai_next) 813 freeaddrinfo(sentinel.ai_next); 814 return error; 815} 816 817/* 818 * numeric hostname with scope 819 */ 820static int 821explore_numeric_scope(const struct addrinfo *pai, const char *hostname, 822 const char *servname, struct addrinfo **res) 823{ 824#if !defined(SCOPE_DELIMITER) || !defined(INET6) 825 return explore_numeric(pai, hostname, servname, res); 826#else 827 const struct afd *afd; 828 struct addrinfo *cur; 829 int error; 830 char *cp, *hostname2 = NULL, *scope, *addr; 831 struct sockaddr_in6 *sin6; 832 833 /* 834 * if the servname does not match socktype/protocol, ignore it. 835 */ 836 if (get_portmatch(pai, servname) != 0) 837 return 0; 838 839 afd = find_afd(pai->ai_family); 840 if (afd == NULL) 841 return 0; 842 843 if (!afd->a_scoped) 844 return explore_numeric(pai, hostname, servname, res); 845 846 cp = strchr(hostname, SCOPE_DELIMITER); 847 if (cp == NULL) 848 return explore_numeric(pai, hostname, servname, res); 849 850#if 0 851 /* 852 * Handle special case of <scope id><delimiter><scoped_address> 853 */ 854 hostname2 = strdup(hostname); 855 if (hostname2 == NULL) 856 return EAI_MEMORY; 857 /* terminate at the delimiter */ 858 hostname2[cp - hostname] = '\0'; 859 scope = hostname2; 860 addr = cp + 1; 861#else 862 /* 863 * Handle special case of <scoped_address><delimiter><scope id> 864 */ 865 hostname2 = strdup(hostname); 866 if (hostname2 == NULL) 867 return EAI_MEMORY; 868 /* terminate at the delimiter */ 869 hostname2[cp - hostname] = '\0'; 870 addr = hostname2; 871 scope = cp + 1; 872#endif 873 874 error = explore_numeric(pai, addr, servname, res); 875 if (error == 0) { 876 int scopeid; 877 878 for (cur = *res; cur; cur = cur->ai_next) { 879 if (cur->ai_family != AF_INET6) 880 continue; 881 sin6 = (struct sockaddr_in6 *)(void *)cur->ai_addr; 882 if ((scopeid = ip6_str2scopeid(scope, sin6)) == -1) { 883 free(hostname2); 884 return(EAI_NODATA); /* XXX: is return OK? */ 885 } 886 sin6->sin6_scope_id = scopeid; 887 } 888 } 889 890 free(hostname2); 891 892 return error; 893#endif 894} 895 896static int 897get_canonname(const struct addrinfo *pai, struct addrinfo *ai, const char *str) 898{ 899 if ((pai->ai_flags & AI_CANONNAME) != 0) { 900 ai->ai_canonname = (char *)malloc(strlen(str) + 1); 901 if (ai->ai_canonname == NULL) 902 return EAI_MEMORY; 903 strcpy(ai->ai_canonname, str); 904 } 905 return 0; 906} 907 908static struct addrinfo * 909get_ai(const struct addrinfo *pai, const struct afd *afd, const char *addr) 910{ 911 char *p; 912 struct addrinfo *ai; 913 914 ai = (struct addrinfo *)malloc(sizeof(struct addrinfo) 915 + (afd->a_socklen)); 916 if (ai == NULL) 917 return NULL; 918 919 memcpy(ai, pai, sizeof(struct addrinfo)); 920 ai->ai_addr = (struct sockaddr *)(void *)(ai + 1); 921 memset(ai->ai_addr, 0, (size_t)afd->a_socklen); 922#if defined(HAVE_STRUCT_SOCKADDR_SA_LEN) 923 ai->ai_addr->sa_len = afd->a_socklen; 924#endif 925 ai->ai_addrlen = afd->a_socklen; 926 ai->ai_addr->sa_family = ai->ai_family = afd->a_af; 927 p = (char *)(void *)(ai->ai_addr); 928 memcpy(p + afd->a_off, addr, (size_t)afd->a_addrlen); 929 return ai; 930} 931 932static int 933get_portmatch(const struct addrinfo *ai, const char *servname) 934{ 935 936 /* get_port does not touch first argument. when matchonly == 1. */ 937 /* LINTED const cast */ 938 return get_port((struct addrinfo *)ai, servname, 1); 939} 940 941static int 942get_port(struct addrinfo *ai, const char *servname, int matchonly) 943{ 944 const char *proto; 945 struct servent *sp; 946 int port; 947 int allownumeric; 948 949 if (servname == NULL) 950 return 0; 951 switch (ai->ai_family) { 952 case AF_INET: 953#ifdef AF_INET6 954 case AF_INET6: 955#endif 956 break; 957 default: 958 return 0; 959 } 960 961 switch (ai->ai_socktype) { 962 case SOCK_RAW: 963 return EAI_SERVICE; 964 case SOCK_DGRAM: 965 case SOCK_STREAM: 966 allownumeric = 1; 967 break; 968 case ANY: 969 allownumeric = 0; 970 break; 971 default: 972 return EAI_SOCKTYPE; 973 } 974 975 if (str_isnumber(servname)) { 976 if (!allownumeric) 977 return EAI_SERVICE; 978 port = htons(atoi(servname)); 979 if (port < 0 || port > 65535) 980 return EAI_SERVICE; 981 } else { 982 switch (ai->ai_socktype) { 983 case SOCK_DGRAM: 984 proto = "udp"; 985 break; 986 case SOCK_STREAM: 987 proto = "tcp"; 988 break; 989 default: 990 proto = NULL; 991 break; 992 } 993 994 if ((sp = getservbyname(servname, proto)) == NULL) 995 return EAI_SERVICE; 996 port = sp->s_port; 997 } 998 999 if (!matchonly) { 1000 switch (ai->ai_family) { 1001 case AF_INET: 1002 ((struct sockaddr_in *)(void *) 1003 ai->ai_addr)->sin_port = port; 1004 break; 1005#ifdef INET6 1006 case AF_INET6: 1007 ((struct sockaddr_in6 *)(void *) 1008 ai->ai_addr)->sin6_port = port; 1009 break; 1010#endif 1011 } 1012 } 1013 1014 return 0; 1015} 1016 1017static const struct afd * 1018find_afd(int af) 1019{ 1020 const struct afd *afd; 1021 1022 if (af == PF_UNSPEC) 1023 return NULL; 1024 for (afd = afdl; afd->a_af; afd++) { 1025 if (afd->a_af == af) 1026 return afd; 1027 } 1028 return NULL; 1029} 1030 1031/* 1032 * post-2553: AI_ADDRCONFIG check. if we use getipnodeby* as backend, backend 1033 * will take care of it. 1034 * the semantics of AI_ADDRCONFIG is not defined well. we are not sure 1035 * if the code is right or not. 1036 */ 1037static int 1038addrconfig(const struct addrinfo *pai) 1039{ 1040#ifdef USE_GETIPNODEBY 1041 return 1; 1042#else 1043 int s; 1044 1045 /* XXX errno */ 1046 s = socket(pai->ai_family, SOCK_DGRAM, 0); 1047 if (s < 0) { 1048 if (errno != EMFILE) 1049 return 0; 1050 } else 1051 close(s); 1052 return 1; 1053#endif 1054} 1055 1056#ifdef INET6 1057/* convert a string to a scope identifier. XXX: IPv6 specific */ 1058static int 1059ip6_str2scopeid(char *scope, struct sockaddr_in6 *sin6) 1060{ 1061 int scopeid; 1062 struct in6_addr *a6 = &sin6->sin6_addr; 1063 char *ep; 1064 1065 /* empty scopeid portion is invalid */ 1066 if (*scope == '\0') 1067 return -1; 1068 1069 if (IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6)) { 1070 /* 1071 * We currently assume a one-to-one mapping between links 1072 * and interfaces, so we simply use interface indices for 1073 * like-local scopes. 1074 */ 1075 scopeid = if_nametoindex(scope); 1076 if (scopeid == 0) 1077 goto trynumeric; 1078 return(scopeid); 1079 } 1080 1081 /* still unclear about literal, allow numeric only - placeholder */ 1082 if (IN6_IS_ADDR_SITELOCAL(a6) || IN6_IS_ADDR_MC_SITELOCAL(a6)) 1083 goto trynumeric; 1084 if (IN6_IS_ADDR_MC_ORGLOCAL(a6)) 1085 goto trynumeric; 1086 else 1087 goto trynumeric; /* global */ 1088 1089 /* try to convert to a numeric id as a last resort */ 1090 trynumeric: 1091 scopeid = (int)strtoul(scope, &ep, 10); 1092 if (*ep == '\0') 1093 return scopeid; 1094 else 1095 return -1; 1096} 1097#endif 1098