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