1 /* $NetBSD: getaddrinfo.c,v 1.13 1999/09/20 04:39:11 lukem Exp $ */ 2 3 /* 4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the project nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 /* 33 * "#ifdef FAITH" part is local hack for supporting IPv4-v6 translator. 34 * 35 * Issues to be discussed: 36 * - Thread safe-ness must be checked. 37 * - Return values. There are nonstandard return values defined and used 38 * in the source code. This is because RFC2133 is silent about which error 39 * code must be returned for which situation. 40 * - PF_UNSPEC case would be handled in getipnodebyname() with the AI_ALL flag. 41 */ 42 43 #include "namespace.h" 44 #include <sys/param.h> 45 #include <sys/sysctl.h> 46 #include <sys/socket.h> 47 48 #include <netinet/in.h> 49 #include <arpa/inet.h> 50 #include <arpa/nameser.h> 51 52 #include <assert.h> 53 #include <ctype.h> 54 #include <errno.h> 55 #include <netdb.h> 56 #include <resolv.h> 57 #include <stddef.h> 58 #include <stdlib.h> 59 #include <string.h> 60 #include <unistd.h> 61 62 #if 0 /*quickhack*/ 63 #if defined(__KAME__) && defined(INET6) 64 # define FAITH 65 #endif 66 #endif 67 68 #define SUCCESS 0 69 #define ANY 0 70 #define YES 1 71 #define NO 0 72 73 #ifdef FAITH 74 static int translate = NO; 75 static struct in6_addr faith_prefix = IN6ADDR_ANY_INIT; 76 #endif 77 78 static const char in_addrany[] = { 0, 0, 0, 0 }; 79 static const char in6_addrany[] = { 80 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 81 }; 82 static const char in_loopback[] = { 127, 0, 0, 1 }; 83 static const char in6_loopback[] = { 84 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 85 }; 86 87 struct sockinet { 88 u_char si_len; 89 u_char si_family; 90 u_short si_port; 91 }; 92 93 static 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 } afdl [] = { 101 #ifdef INET6 102 #define N_INET6 0 103 {PF_INET6, sizeof(struct in6_addr), 104 sizeof(struct sockaddr_in6), 105 offsetof(struct sockaddr_in6, sin6_addr), 106 in6_addrany, in6_loopback}, 107 #define N_INET 1 108 #else 109 #define N_INET 0 110 #endif 111 {PF_INET, sizeof(struct in_addr), 112 sizeof(struct sockaddr_in), 113 offsetof(struct sockaddr_in, sin_addr), 114 in_addrany, in_loopback}, 115 {0, 0, 0, 0, NULL, NULL}, 116 }; 117 118 #ifdef INET6 119 #define PTON_MAX 16 120 #else 121 #define PTON_MAX 4 122 #endif 123 124 125 static int get_name __P((const char *, struct afd *, 126 struct addrinfo **, char *, struct addrinfo *, 127 int)); 128 static int get_addr __P((const char *, int, struct addrinfo **, 129 struct addrinfo *, int)); 130 static int get_addr0 __P((const char *, int, struct addrinfo **, 131 struct addrinfo *, int)); 132 static int str_isnumber __P((const char *)); 133 134 static char *ai_errlist[] = { 135 "Success", 136 "Address family for hostname not supported", /* EAI_ADDRFAMILY */ 137 "Temporary failure in name resolution", /* EAI_AGAIN */ 138 "Invalid value for ai_flags", /* EAI_BADFLAGS */ 139 "Non-recoverable failure in name resolution", /* EAI_FAIL */ 140 "ai_family not supported", /* EAI_FAMILY */ 141 "Memory allocation failure", /* EAI_MEMORY */ 142 "No address associated with hostname", /* EAI_NODATA */ 143 "hostname nor servname provided, or not known",/* EAI_NONAME */ 144 "servname not supported for ai_socktype", /* EAI_SERVICE */ 145 "ai_socktype not supported", /* EAI_SOCKTYPE */ 146 "System error returned in errno", /* EAI_SYSTEM */ 147 "Invalid value for hints", /* EAI_BADHINTS */ 148 "Resolved protocol is unknown", /* EAI_PROTOCOL */ 149 "Unknown error", /* EAI_MAX */ 150 }; 151 152 #define GET_CANONNAME(ai, str) \ 153 if (pai->ai_flags & AI_CANONNAME) {\ 154 if (((ai)->ai_canonname = (char *)malloc(strlen(str) + 1)) != NULL) {\ 155 strcpy((ai)->ai_canonname, (str));\ 156 } else {\ 157 error = EAI_MEMORY;\ 158 goto free;\ 159 }\ 160 } 161 162 #define GET_AI(ai, afd, addr, port) {\ 163 char *p;\ 164 if (((ai) = (struct addrinfo *)malloc(sizeof(struct addrinfo) +\ 165 ((afd)->a_socklen)))\ 166 == NULL) {\ 167 error = EAI_MEMORY;\ 168 goto free;\ 169 }\ 170 memcpy(ai, pai, sizeof(struct addrinfo));\ 171 (ai)->ai_addr = (struct sockaddr *)((ai) + 1);\ 172 memset((ai)->ai_addr, 0, (afd)->a_socklen);\ 173 (ai)->ai_addr->sa_len = (ai)->ai_addrlen = (afd)->a_socklen;\ 174 (ai)->ai_addr->sa_family = (ai)->ai_family = (afd)->a_af;\ 175 ((struct sockinet *)(ai)->ai_addr)->si_port = port;\ 176 p = (char *)((ai)->ai_addr);\ 177 memcpy(p + (afd)->a_off, (addr), (afd)->a_addrlen);\ 178 } 179 180 #define ERR(err) { error = (err); goto bad; } 181 182 char * 183 gai_strerror(ecode) 184 int ecode; 185 { 186 if (ecode < 0 || ecode > EAI_MAX) 187 ecode = EAI_MAX; 188 return ai_errlist[ecode]; 189 } 190 191 void 192 freeaddrinfo(ai) 193 struct addrinfo *ai; 194 { 195 struct addrinfo *next; 196 197 _DIAGASSERT(ai != NULL); 198 199 do { 200 next = ai->ai_next; 201 if (ai->ai_canonname) 202 free(ai->ai_canonname); 203 /* no need to free(ai->ai_addr) */ 204 free(ai); 205 } while ((ai = next) != NULL); 206 } 207 208 static int 209 str_isnumber(p) 210 const char *p; 211 { 212 char *q = (char *)p; 213 214 _DIAGASSERT(p != NULL); 215 216 while (*q) { 217 if (! isdigit(*q)) 218 return NO; 219 q++; 220 } 221 return YES; 222 } 223 224 int 225 getaddrinfo(hostname, servname, hints, res) 226 const char *hostname, *servname; 227 const struct addrinfo *hints; 228 struct addrinfo **res; 229 { 230 struct addrinfo sentinel; 231 struct addrinfo *top = NULL; 232 struct addrinfo *cur; 233 int i, error = 0; 234 char pton[PTON_MAX]; 235 struct addrinfo ai; 236 struct addrinfo *pai; 237 u_short port; 238 239 #ifdef FAITH 240 static int firsttime = 1; 241 242 if (firsttime) { 243 /* translator hack */ 244 { 245 char *q = getenv("GAI"); 246 if (q && inet_pton(AF_INET6, q, &faith_prefix) == 1) 247 translate = YES; 248 } 249 firsttime = 0; 250 } 251 #endif 252 253 /* hostname may be NULL */ 254 /* servname may be NULL */ 255 /* hints may be NULL */ 256 _DIAGASSERT(res != NULL); 257 258 /* initialize file static vars */ 259 sentinel.ai_next = NULL; 260 cur = &sentinel; 261 pai = &ai; 262 pai->ai_flags = 0; 263 pai->ai_family = PF_UNSPEC; 264 pai->ai_socktype = ANY; 265 pai->ai_protocol = ANY; 266 pai->ai_addrlen = 0; 267 pai->ai_canonname = NULL; 268 pai->ai_addr = NULL; 269 pai->ai_next = NULL; 270 port = ANY; 271 272 if (hostname == NULL && servname == NULL) 273 return EAI_NONAME; 274 if (hints) { 275 /* error check for hints */ 276 if (hints->ai_addrlen || hints->ai_canonname || 277 hints->ai_addr || hints->ai_next) 278 ERR(EAI_BADHINTS); /* xxx */ 279 if (hints->ai_flags & ~AI_MASK) 280 ERR(EAI_BADFLAGS); 281 switch (hints->ai_family) { 282 case PF_UNSPEC: 283 case PF_INET: 284 #ifdef INET6 285 case PF_INET6: 286 #endif 287 break; 288 default: 289 ERR(EAI_FAMILY); 290 } 291 memcpy(pai, hints, sizeof(*pai)); 292 switch (pai->ai_socktype) { 293 case ANY: 294 switch (pai->ai_protocol) { 295 case ANY: 296 break; 297 case IPPROTO_UDP: 298 pai->ai_socktype = SOCK_DGRAM; 299 break; 300 case IPPROTO_TCP: 301 pai->ai_socktype = SOCK_STREAM; 302 break; 303 default: 304 pai->ai_socktype = SOCK_RAW; 305 break; 306 } 307 break; 308 case SOCK_RAW: 309 break; 310 case SOCK_DGRAM: 311 if (pai->ai_protocol != IPPROTO_UDP && 312 pai->ai_protocol != ANY) 313 ERR(EAI_BADHINTS); /*xxx*/ 314 pai->ai_protocol = IPPROTO_UDP; 315 break; 316 case SOCK_STREAM: 317 if (pai->ai_protocol != IPPROTO_TCP && 318 pai->ai_protocol != ANY) 319 ERR(EAI_BADHINTS); /*xxx*/ 320 pai->ai_protocol = IPPROTO_TCP; 321 break; 322 default: 323 ERR(EAI_SOCKTYPE); 324 break; 325 } 326 } 327 328 /* 329 * service port 330 */ 331 if (servname) { 332 if (str_isnumber(servname)) { 333 if (pai->ai_socktype == ANY) { 334 /* caller accept *ANY* socktype */ 335 pai->ai_socktype = SOCK_DGRAM; 336 pai->ai_protocol = IPPROTO_UDP; 337 } 338 port = htons(atoi(servname)); 339 } else { 340 struct servent *sp; 341 char *proto; 342 343 proto = NULL; 344 switch (pai->ai_socktype) { 345 case ANY: 346 proto = NULL; 347 break; 348 case SOCK_DGRAM: 349 proto = "udp"; 350 break; 351 case SOCK_STREAM: 352 proto = "tcp"; 353 break; 354 default: 355 fprintf(stderr, "panic!\n"); 356 break; 357 } 358 if ((sp = getservbyname(servname, proto)) == NULL) 359 ERR(EAI_SERVICE); 360 port = sp->s_port; 361 if (pai->ai_socktype == ANY) { 362 if (strcmp(sp->s_proto, "udp") == 0) { 363 pai->ai_socktype = SOCK_DGRAM; 364 pai->ai_protocol = IPPROTO_UDP; 365 } else if (strcmp(sp->s_proto, "tcp") == 0) { 366 pai->ai_socktype = SOCK_STREAM; 367 pai->ai_protocol = IPPROTO_TCP; 368 } else 369 ERR(EAI_PROTOCOL); /*xxx*/ 370 } 371 } 372 } 373 374 /* 375 * hostname == NULL. 376 * passive socket -> anyaddr (0.0.0.0 or ::) 377 * non-passive socket -> localhost (127.0.0.1 or ::1) 378 */ 379 if (hostname == NULL) { 380 struct afd *afd; 381 int s; 382 383 for (afd = &afdl[0]; afd->a_af; afd++) { 384 if (!(pai->ai_family == PF_UNSPEC 385 || pai->ai_family == afd->a_af)) { 386 continue; 387 } 388 389 /* 390 * filter out AFs that are not supported by the kernel 391 * XXX errno? 392 */ 393 s = socket(afd->a_af, SOCK_DGRAM, 0); 394 if (s < 0) 395 continue; 396 close(s); 397 398 if (pai->ai_flags & AI_PASSIVE) { 399 GET_AI(cur->ai_next, afd, afd->a_addrany, port); 400 /* xxx meaningless? 401 * GET_CANONNAME(cur->ai_next, "anyaddr"); 402 */ 403 } else { 404 GET_AI(cur->ai_next, afd, afd->a_loopback, 405 port); 406 /* xxx meaningless? 407 * GET_CANONNAME(cur->ai_next, "localhost"); 408 */ 409 } 410 cur = cur->ai_next; 411 } 412 top = sentinel.ai_next; 413 if (top) 414 goto good; 415 else 416 ERR(EAI_FAMILY); 417 } 418 419 /* hostname as numeric name */ 420 for (i = 0; afdl[i].a_af; i++) { 421 if (inet_pton(afdl[i].a_af, hostname, pton)) { 422 u_long v4a; 423 u_char pfx; 424 425 switch (afdl[i].a_af) { 426 case AF_INET: 427 v4a = ntohl(((struct in_addr *)pton)->s_addr); 428 if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a)) 429 pai->ai_flags &= ~AI_CANONNAME; 430 v4a >>= IN_CLASSA_NSHIFT; 431 if (v4a == 0 || v4a == IN_LOOPBACKNET) 432 pai->ai_flags &= ~AI_CANONNAME; 433 break; 434 #ifdef INET6 435 case AF_INET6: 436 pfx = ((struct in6_addr *)pton)->s6_addr8[0]; 437 if (pfx == 0 || pfx == 0xfe || pfx == 0xff) 438 pai->ai_flags &= ~AI_CANONNAME; 439 break; 440 #endif 441 } 442 443 if (pai->ai_family == afdl[i].a_af || 444 pai->ai_family == PF_UNSPEC) { 445 if (! (pai->ai_flags & AI_CANONNAME)) { 446 GET_AI(top, &afdl[i], pton, port); 447 goto good; 448 } 449 /* 450 * if AI_CANONNAME and if reverse lookup 451 * fail, return ai anyway to pacify 452 * calling application. 453 * 454 * XXX getaddrinfo() is a name->address 455 * translation function, and it looks strange 456 * that we do addr->name translation here. 457 */ 458 get_name(pton, &afdl[i], &top, pton, pai, port); 459 goto good; 460 } else 461 ERR(EAI_FAMILY); /*xxx*/ 462 } 463 } 464 465 if (pai->ai_flags & AI_NUMERICHOST) 466 ERR(EAI_NONAME); 467 468 /* hostname as alphabetical name */ 469 error = get_addr(hostname, pai->ai_family, &top, pai, port); 470 if (error == 0) { 471 if (top) { 472 good: 473 *res = top; 474 return SUCCESS; 475 } else 476 error = EAI_FAIL; 477 } 478 free: 479 if (top) 480 freeaddrinfo(top); 481 bad: 482 *res = NULL; 483 return error; 484 } 485 486 static int 487 get_name(addr, afd, res, numaddr, pai, port0) 488 const char *addr; 489 struct afd *afd; 490 struct addrinfo **res; 491 char *numaddr; 492 struct addrinfo *pai; 493 int port0; 494 { 495 u_short port = port0 & 0xffff; 496 struct hostent *hp; 497 struct addrinfo *cur; 498 int error = 0; 499 #ifdef USE_GETIPNODEBY 500 int h_error; 501 #endif 502 503 _DIAGASSERT(addr != NULL); 504 _DIAGASSERT(afd != NULL); 505 _DIAGASSERT(res != NULL); 506 _DIAGASSERT(numaddr != NULL); 507 _DIAGASSERT(pai != NULL); 508 509 #ifdef USE_GETIPNODEBY 510 hp = getipnodebyaddr(addr, afd->a_addrlen, afd->a_af, &h_error); 511 #else 512 hp = gethostbyaddr(addr, afd->a_addrlen, afd->a_af); 513 #endif 514 if (hp && hp->h_name && hp->h_name[0] && hp->h_addr_list[0]) { 515 GET_AI(cur, afd, hp->h_addr_list[0], port); 516 GET_CANONNAME(cur, hp->h_name); 517 } else 518 GET_AI(cur, afd, numaddr, port); 519 520 #ifdef USE_GETIPNODEBY 521 if (hp) 522 freehostent(hp); 523 #endif 524 *res = cur; 525 return SUCCESS; 526 free: 527 if (cur) 528 freeaddrinfo(cur); 529 #ifdef USE_GETIPNODEBY 530 if (hp) 531 freehostent(hp); 532 #endif 533 /* bad: */ 534 *res = NULL; 535 return error; 536 } 537 538 static int 539 get_addr(hostname, af, res0, pai, port0) 540 const char *hostname; 541 int af; 542 struct addrinfo **res0; 543 struct addrinfo *pai; 544 int port0; 545 { 546 #ifndef USE_GETIPNODEBY 547 int i, error, ekeep; 548 struct addrinfo *cur; 549 struct addrinfo **res; 550 int retry; 551 int s; 552 #endif 553 554 _DIAGASSERT(hostname != NULL); 555 _DIAGASSERT(res != NULL); 556 _DIAGASSERT(pai != NULL); 557 558 #ifdef USE_GETIPNODEBY 559 return get_addr0(hostname, af, res0, pai, port0); 560 #else 561 res = res0; 562 ekeep = 0; 563 error = 0; 564 for (i = 0; afdl[i].a_af; i++) { 565 retry = 0; 566 if (af == AF_UNSPEC) { 567 /* 568 * filter out AFs that are not supported by the kernel 569 * XXX errno? 570 */ 571 s = socket(afdl[i].a_af, SOCK_DGRAM, 0); 572 if (s < 0) 573 continue; 574 close(s); 575 } else { 576 if (af != afdl[i].a_af) 577 continue; 578 } 579 /* It is WRONG, we need getipnodebyname(). */ 580 again: 581 error = get_addr0(hostname, afdl[i].a_af, res, pai, port0); 582 switch (error) { 583 case EAI_AGAIN: 584 if (++retry < 3) 585 goto again; 586 /* FALL THROUGH*/ 587 default: 588 if (ekeep == 0) 589 ekeep = error; 590 break; 591 } 592 if (*res) { 593 /* make chain of addrs */ 594 for (cur = *res; 595 cur && cur->ai_next; 596 cur = cur->ai_next) 597 ; 598 if (!cur) 599 return EAI_FAIL; 600 res = &cur->ai_next; 601 } 602 } 603 604 /* if we got something, it's okay */ 605 if (*res0) 606 return 0; 607 608 return error ? error : ekeep; 609 #endif 610 } 611 612 static int 613 get_addr0(hostname, af, res, pai, port0) 614 const char *hostname; 615 int af; 616 struct addrinfo **res; 617 struct addrinfo *pai; 618 int port0; 619 { 620 u_short port = port0 & 0xffff; 621 struct addrinfo sentinel; 622 struct hostent *hp; 623 struct addrinfo *top, *cur; 624 struct afd *afd; 625 int i, error = 0, h_error; 626 char *ap; 627 #ifndef USE_GETIPNODEBY 628 extern int h_errno; 629 #endif 630 631 _DIAGASSERT(hostname != NULL); 632 _DIAGASSERT(res != NULL); 633 _DIAGASSERT(pai != NULL); 634 635 top = NULL; 636 sentinel.ai_next = NULL; 637 cur = &sentinel; 638 #ifdef USE_GETIPNODEBY 639 if (af == AF_UNSPEC) { 640 hp = getipnodebyname(hostname, AF_INET6, 641 AI_ADDRCONFIG|AI_ALL|AI_V4MAPPED, &h_error); 642 } else 643 hp = getipnodebyname(hostname, af, AI_ADDRCONFIG, &h_error); 644 #else 645 if (af == AF_UNSPEC) { 646 error = EAI_FAIL; 647 goto bad; 648 } 649 hp = gethostbyname2(hostname, af); 650 h_error = h_errno; 651 #endif 652 if (hp == NULL) { 653 switch (h_error) { 654 case HOST_NOT_FOUND: 655 case NO_DATA: 656 error = EAI_NODATA; 657 break; 658 case TRY_AGAIN: 659 error = EAI_AGAIN; 660 break; 661 case NO_RECOVERY: 662 case NETDB_INTERNAL: 663 default: 664 error = EAI_FAIL; 665 break; 666 } 667 goto bad; 668 } 669 670 if ((hp->h_name == NULL) || (hp->h_name[0] == 0) || 671 (hp->h_addr_list[0] == NULL)) 672 ERR(EAI_FAIL); 673 674 for (i = 0; (ap = hp->h_addr_list[i]) != NULL; i++) { 675 switch (af) { 676 #ifdef INET6 677 case AF_INET6: 678 afd = &afdl[N_INET6]; 679 break; 680 #endif 681 #ifndef INET6 682 default: /* AF_UNSPEC */ 683 #endif 684 case AF_INET: 685 afd = &afdl[N_INET]; 686 break; 687 #ifdef INET6 688 default: /* AF_UNSPEC */ 689 if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ap)) { 690 ap += sizeof(struct in6_addr) - 691 sizeof(struct in_addr); 692 afd = &afdl[N_INET]; 693 } else 694 afd = &afdl[N_INET6]; 695 break; 696 #endif 697 } 698 #ifdef FAITH 699 if (translate && afd->a_af == AF_INET) { 700 struct in6_addr *in6; 701 702 GET_AI(cur->ai_next, &afdl[N_INET6], ap, port); 703 in6 = &((struct sockaddr_in6 *)cur->ai_next->ai_addr)->sin6_addr; 704 memcpy(&in6->s6_addr32[0], &faith_prefix, 705 sizeof(struct in6_addr) - sizeof(struct in_addr)); 706 memcpy(&in6->s6_addr32[3], ap, sizeof(struct in_addr)); 707 } else 708 #endif /* FAITH */ 709 GET_AI(cur->ai_next, afd, ap, port); 710 if (cur == &sentinel) { 711 top = cur->ai_next; 712 GET_CANONNAME(top, hp->h_name); 713 } 714 cur = cur->ai_next; 715 } 716 #ifdef USE_GETIPNODEBY 717 freehostent(hp); 718 #endif 719 *res = top; 720 return SUCCESS; 721 free: 722 if (top) 723 freeaddrinfo(top); 724 #ifdef USE_GETIPNODEBY 725 if (hp) 726 freehostent(hp); 727 #endif 728 bad: 729 *res = NULL; 730 return error; 731 } 732