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 RFC2133 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#if 0 42#include <sys/types.h> 43#include <sys/param.h> 44#include <sys/sysctl.h> 45#include <sys/socket.h> 46#include <netinet/in.h> 47#include <arpa/inet.h> 48#include <arpa/nameser.h> 49#include <netdb.h> 50#include <resolv.h> 51#include <string.h> 52#include <stdlib.h> 53#include <stddef.h> 54#include <ctype.h> 55#include <unistd.h> 56 57#include "addrinfo.h" 58#endif 59 60#if defined(__KAME__) && defined(ENABLE_IPV6) 61# define FAITH 62#endif 63 64#ifdef HAVE_NETDB_H 65#define HAVE_GETADDRINFO 1 66 67#define SUCCESS 0 68#define GAI_ANY 0 69#define YES 1 70#define NO 0 71 72#ifdef FAITH 73static int translate = NO; 74static struct in6_addr faith_prefix = IN6ADDR_GAI_ANY_INIT; 75#endif 76 77static const char in_addrany[] = { 0, 0, 0, 0 }; 78static const char in6_addrany[] = { 79 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 80}; 81static const char in_loopback[] = { 127, 0, 0, 1 }; 82static const char in6_loopback[] = { 83 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 84}; 85 86struct sockinet { 87 u_char si_len; 88 u_char si_family; 89 u_short si_port; 90}; 91 92static struct gai_afd { 93 int a_af; 94 int a_addrlen; 95 int a_socklen; 96 int a_off; 97 const char *a_addrany; 98 const char *a_loopback; 99} gai_afdl [] = { 100#ifdef ENABLE_IPV6 101#define N_INET6 0 102 {PF_INET6, sizeof(struct in6_addr), 103 sizeof(struct sockaddr_in6), 104 offsetof(struct sockaddr_in6, sin6_addr), 105 in6_addrany, in6_loopback}, 106#define N_INET 1 107#else 108#define N_INET 0 109#endif 110 {PF_INET, sizeof(struct in_addr), 111 sizeof(struct sockaddr_in), 112 offsetof(struct sockaddr_in, sin_addr), 113 in_addrany, in_loopback}, 114 {0, 0, 0, 0, NULL, NULL}, 115}; 116 117#ifdef ENABLE_IPV6 118#define PTON_MAX 16 119#else 120#define PTON_MAX 4 121#endif 122 123#ifndef IN_MULTICAST 124#define IN_MULTICAST(i) (((i) & 0xf0000000U) == 0xe0000000U) 125#endif 126 127#ifndef IN_EXPERIMENTAL 128#define IN_EXPERIMENTAL(i) (((i) & 0xe0000000U) == 0xe0000000U) 129#endif 130 131#ifndef IN_LOOPBACKNET 132#define IN_LOOPBACKNET 127 133#endif 134 135static int get_name(const char *, struct gai_afd *, 136 struct addrinfo **, char *, struct addrinfo *, 137 int); 138static int get_addr(const char *, int, struct addrinfo **, 139 struct addrinfo *, int); 140static int str_isnumber(const char *); 141 142static const char * const ai_errlist[] = { 143 "success.", 144 "address family for hostname not supported.", /* EAI_ADDRFAMILY */ 145 "temporary failure in name resolution.", /* EAI_AGAIN */ 146 "invalid value for ai_flags.", /* EAI_BADFLAGS */ 147 "non-recoverable failure in name resolution.", /* EAI_FAIL */ 148 "ai_family not supported.", /* EAI_FAMILY */ 149 "memory allocation failure.", /* EAI_MEMORY */ 150 "no address associated with hostname.", /* EAI_NODATA */ 151 "hostname nor servname provided, or not known.",/* EAI_NONAME */ 152 "servname not supported for ai_socktype.", /* EAI_SERVICE */ 153 "ai_socktype not supported.", /* EAI_SOCKTYPE */ 154 "system error returned in errno.", /* EAI_SYSTEM */ 155 "invalid value for hints.", /* EAI_BADHINTS */ 156 "resolved protocol is unknown.", /* EAI_PROTOCOL */ 157 "unknown error.", /* EAI_MAX */ 158}; 159 160#define GET_CANONNAME(ai, str) \ 161if (pai->ai_flags & AI_CANONNAME) {\ 162 if (((ai)->ai_canonname = (char *)malloc(strlen(str) + 1)) != NULL) {\ 163 strcpy((ai)->ai_canonname, (str));\ 164 } else {\ 165 error = EAI_MEMORY;\ 166 goto free;\ 167 }\ 168} 169 170#ifdef HAVE_SOCKADDR_SA_LEN 171#define GET_AI(ai, gai_afd, addr, port) {\ 172 char *p;\ 173 if (((ai) = (struct addrinfo *)malloc(sizeof(struct addrinfo) +\ 174 ((gai_afd)->a_socklen)))\ 175 == NULL) goto free;\ 176 memcpy(ai, pai, sizeof(struct addrinfo));\ 177 (ai)->ai_addr = (struct sockaddr *)((ai) + 1);\ 178 memset((ai)->ai_addr, 0, (gai_afd)->a_socklen);\ 179 (ai)->ai_addr->sa_len = (ai)->ai_addrlen = (gai_afd)->a_socklen;\ 180 (ai)->ai_addr->sa_family = (ai)->ai_family = (gai_afd)->a_af;\ 181 ((struct sockinet *)(ai)->ai_addr)->si_port = port;\ 182 p = (char *)((ai)->ai_addr);\ 183 memcpy(p + (gai_afd)->a_off, (addr), (gai_afd)->a_addrlen);\ 184} 185#else 186#define GET_AI(ai, gai_afd, addr, port) {\ 187 char *p;\ 188 if (((ai) = (struct addrinfo *)malloc(sizeof(struct addrinfo) +\ 189 ((gai_afd)->a_socklen)))\ 190 == NULL) goto free;\ 191 memcpy(ai, pai, sizeof(struct addrinfo));\ 192 (ai)->ai_addr = (struct sockaddr *)((ai) + 1);\ 193 memset((ai)->ai_addr, 0, (gai_afd)->a_socklen);\ 194 (ai)->ai_addrlen = (gai_afd)->a_socklen;\ 195 (ai)->ai_addr->sa_family = (ai)->ai_family = (gai_afd)->a_af;\ 196 ((struct sockinet *)(ai)->ai_addr)->si_port = port;\ 197 p = (char *)((ai)->ai_addr);\ 198 memcpy(p + (gai_afd)->a_off, (addr), (gai_afd)->a_addrlen);\ 199} 200#endif 201 202#define ERR(err) { error = (err); goto bad; } 203 204const char * 205gai_strerror(int ecode) 206{ 207 if (ecode < 0 || ecode > EAI_MAX) 208 ecode = EAI_MAX; 209 return ai_errlist[ecode]; 210} 211 212void 213freeaddrinfo(struct addrinfo *ai) 214{ 215 struct addrinfo *next; 216 217 do { 218 next = ai->ai_next; 219 if (ai->ai_canonname) 220 free(ai->ai_canonname); 221 /* no need to free(ai->ai_addr) */ 222 free(ai); 223 } while ((ai = next) != NULL); 224} 225 226static int 227str_isnumber(const char *p) 228{ 229 unsigned char *q = (unsigned char *)p; 230 while (*q) { 231 if (! isdigit(*q)) 232 return NO; 233 q++; 234 } 235 return YES; 236} 237 238int 239getaddrinfo(const char*hostname, const char*servname, 240 const struct addrinfo *hints, struct addrinfo **res) 241{ 242 struct addrinfo sentinel; 243 struct addrinfo *top = NULL; 244 struct addrinfo *cur; 245 int i, error = 0; 246 char pton[PTON_MAX]; 247 struct addrinfo ai; 248 struct addrinfo *pai; 249 u_short port; 250 251#ifdef FAITH 252 static int firsttime = 1; 253 254 if (firsttime) { 255 /* translator hack */ 256 { 257 const char *q = getenv("GAI"); 258 if (q && inet_pton(AF_INET6, q, &faith_prefix) == 1) 259 translate = YES; 260 } 261 firsttime = 0; 262 } 263#endif 264 265 /* initialize file static vars */ 266 sentinel.ai_next = NULL; 267 cur = &sentinel; 268 pai = &ai; 269 pai->ai_flags = 0; 270 pai->ai_family = PF_UNSPEC; 271 pai->ai_socktype = GAI_ANY; 272 pai->ai_protocol = GAI_ANY; 273 pai->ai_addrlen = 0; 274 pai->ai_canonname = NULL; 275 pai->ai_addr = NULL; 276 pai->ai_next = NULL; 277 port = GAI_ANY; 278 279 if (hostname == NULL && servname == NULL) 280 return EAI_NONAME; 281 if (hints) { 282 /* error check for hints */ 283 if (hints->ai_addrlen || hints->ai_canonname || 284 hints->ai_addr || hints->ai_next) 285 ERR(EAI_BADHINTS); /* xxx */ 286 if (hints->ai_flags & ~AI_MASK) 287 ERR(EAI_BADFLAGS); 288 switch (hints->ai_family) { 289 case PF_UNSPEC: 290 case PF_INET: 291#ifdef ENABLE_IPV6 292 case PF_INET6: 293#endif 294 break; 295 default: 296 ERR(EAI_FAMILY); 297 } 298 memcpy(pai, hints, sizeof(*pai)); 299 switch (pai->ai_socktype) { 300 case GAI_ANY: 301 switch (pai->ai_protocol) { 302 case GAI_ANY: 303 break; 304 case IPPROTO_UDP: 305 pai->ai_socktype = SOCK_DGRAM; 306 break; 307 case IPPROTO_TCP: 308 pai->ai_socktype = SOCK_STREAM; 309 break; 310 default: 311 pai->ai_socktype = SOCK_RAW; 312 break; 313 } 314 break; 315 case SOCK_RAW: 316 break; 317 case SOCK_DGRAM: 318 if (pai->ai_protocol != IPPROTO_UDP && 319 pai->ai_protocol != GAI_ANY) 320 ERR(EAI_BADHINTS); /*xxx*/ 321 pai->ai_protocol = IPPROTO_UDP; 322 break; 323 case SOCK_STREAM: 324 if (pai->ai_protocol != IPPROTO_TCP && 325 pai->ai_protocol != GAI_ANY) 326 ERR(EAI_BADHINTS); /*xxx*/ 327 pai->ai_protocol = IPPROTO_TCP; 328 break; 329 default: 330 ERR(EAI_SOCKTYPE); 331 /* unreachable */ 332 } 333 } 334 335 /* 336 * service port 337 */ 338 if (servname) { 339 if (str_isnumber(servname)) { 340 if (pai->ai_socktype == GAI_ANY) { 341 /* caller accept *GAI_ANY* socktype */ 342 pai->ai_socktype = SOCK_DGRAM; 343 pai->ai_protocol = IPPROTO_UDP; 344 } 345 port = htons((u_short)atoi(servname)); 346 } else { 347 struct servent *sp; 348 const char *proto; 349 350 proto = NULL; 351 switch (pai->ai_socktype) { 352 case GAI_ANY: 353 proto = NULL; 354 break; 355 case SOCK_DGRAM: 356 proto = "udp"; 357 break; 358 case SOCK_STREAM: 359 proto = "tcp"; 360 break; 361 default: 362 fprintf(stderr, "panic!\n"); 363 break; 364 } 365 if ((sp = getservbyname(servname, proto)) == NULL) 366 ERR(EAI_SERVICE); 367 port = sp->s_port; 368 if (pai->ai_socktype == GAI_ANY) { 369 if (strcmp(sp->s_proto, "udp") == 0) { 370 pai->ai_socktype = SOCK_DGRAM; 371 pai->ai_protocol = IPPROTO_UDP; 372 } else if (strcmp(sp->s_proto, "tcp") == 0) { 373 pai->ai_socktype = SOCK_STREAM; 374 pai->ai_protocol = IPPROTO_TCP; 375 } else 376 ERR(EAI_PROTOCOL); /*xxx*/ 377 } 378 } 379 } 380 381 /* 382 * hostname == NULL. 383 * passive socket -> anyaddr (0.0.0.0 or ::) 384 * non-passive socket -> localhost (127.0.0.1 or ::1) 385 */ 386 if (hostname == NULL) { 387 struct gai_afd *gai_afd; 388 389 for (gai_afd = &gai_afdl[0]; gai_afd->a_af; gai_afd++) { 390 if (!(pai->ai_family == PF_UNSPEC 391 || pai->ai_family == gai_afd->a_af)) { 392 continue; 393 } 394 395 if (pai->ai_flags & AI_PASSIVE) { 396 GET_AI(cur->ai_next, gai_afd, gai_afd->a_addrany, port); 397 /* xxx meaningless? 398 * GET_CANONNAME(cur->ai_next, "anyaddr"); 399 */ 400 } else { 401 GET_AI(cur->ai_next, gai_afd, gai_afd->a_loopback, 402 port); 403 /* xxx meaningless? 404 * GET_CANONNAME(cur->ai_next, "localhost"); 405 */ 406 } 407 cur = cur->ai_next; 408 } 409 top = sentinel.ai_next; 410 if (top) 411 goto good; 412 else 413 ERR(EAI_FAMILY); 414 } 415 416 /* hostname as numeric name */ 417 for (i = 0; gai_afdl[i].a_af; i++) { 418 if (inet_pton(gai_afdl[i].a_af, hostname, pton)) { 419 u_long v4a; 420#ifdef ENABLE_IPV6 421 u_char pfx; 422#endif 423 424 switch (gai_afdl[i].a_af) { 425 case AF_INET: 426 v4a = ((struct in_addr *)pton)->s_addr; 427 v4a = ntohl(v4a); 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 ENABLE_IPV6 435 case AF_INET6: 436 pfx = ((struct in6_addr *)pton)->s6_addr[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 == gai_afdl[i].a_af || 444 pai->ai_family == PF_UNSPEC) { 445 if (! (pai->ai_flags & AI_CANONNAME)) { 446 GET_AI(top, &gai_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, &gai_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 486static int 487get_name(addr, gai_afd, res, numaddr, pai, port0) 488 const char *addr; 489 struct gai_afd *gai_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 ENABLE_IPV6 500 int h_error; 501#endif 502 503#ifdef ENABLE_IPV6 504 hp = getipnodebyaddr(addr, gai_afd->a_addrlen, gai_afd->a_af, &h_error); 505#else 506 hp = gethostbyaddr(addr, gai_afd->a_addrlen, AF_INET); 507#endif 508 if (hp && hp->h_name && hp->h_name[0] && hp->h_addr_list[0]) { 509 GET_AI(cur, gai_afd, hp->h_addr_list[0], port); 510 GET_CANONNAME(cur, hp->h_name); 511 } else 512 GET_AI(cur, gai_afd, numaddr, port); 513 514#ifdef ENABLE_IPV6 515 if (hp) 516 freehostent(hp); 517#endif 518 *res = cur; 519 return SUCCESS; 520 free: 521 if (cur) 522 freeaddrinfo(cur); 523#ifdef ENABLE_IPV6 524 if (hp) 525 freehostent(hp); 526#endif 527 /* bad: */ 528 *res = NULL; 529 return error; 530} 531 532static int 533get_addr(hostname, af, res, pai, port0) 534 const char *hostname; 535 int af; 536 struct addrinfo **res; 537 struct addrinfo *pai; 538 int port0; 539{ 540 u_short port = port0 & 0xffff; 541 struct addrinfo sentinel; 542 struct hostent *hp; 543 struct addrinfo *top, *cur; 544 struct gai_afd *gai_afd; 545 int i, error = 0, h_error; 546 char *ap; 547 548 top = NULL; 549 sentinel.ai_next = NULL; 550 cur = &sentinel; 551#ifdef ENABLE_IPV6 552 if (af == AF_UNSPEC) { 553 hp = getipnodebyname(hostname, AF_INET6, 554 AI_ADDRCONFIG|AI_ALL|AI_V4MAPPED, &h_error); 555 } else 556 hp = getipnodebyname(hostname, af, AI_ADDRCONFIG, &h_error); 557#else 558 hp = gethostbyname(hostname); 559 h_error = h_errno; 560#endif 561 if (hp == NULL) { 562 switch (h_error) { 563 case HOST_NOT_FOUND: 564 case NO_DATA: 565 error = EAI_NODATA; 566 break; 567 case TRY_AGAIN: 568 error = EAI_AGAIN; 569 break; 570 case NO_RECOVERY: 571 default: 572 error = EAI_FAIL; 573 break; 574 } 575 goto free; 576 } 577 578 if ((hp->h_name == NULL) || (hp->h_name[0] == 0) || 579 (hp->h_addr_list[0] == NULL)) { 580 error = EAI_FAIL; 581 goto free; 582 } 583 584 for (i = 0; (ap = hp->h_addr_list[i]) != NULL; i++) { 585 switch (af) { 586#ifdef ENABLE_IPV6 587 case AF_INET6: 588 gai_afd = &gai_afdl[N_INET6]; 589 break; 590#endif 591#ifndef ENABLE_IPV6 592 default: /* AF_UNSPEC */ 593#endif 594 case AF_INET: 595 gai_afd = &gai_afdl[N_INET]; 596 break; 597#ifdef ENABLE_IPV6 598 default: /* AF_UNSPEC */ 599 if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ap)) { 600 ap += sizeof(struct in6_addr) - 601 sizeof(struct in_addr); 602 gai_afd = &gai_afdl[N_INET]; 603 } else 604 gai_afd = &gai_afdl[N_INET6]; 605 break; 606#endif 607 } 608#ifdef FAITH 609 if (translate && gai_afd->a_af == AF_INET) { 610 struct in6_addr *in6; 611 612 GET_AI(cur->ai_next, &gai_afdl[N_INET6], ap, port); 613 in6 = &((struct sockaddr_in6 *)cur->ai_next->ai_addr)->sin6_addr; 614 memcpy(&in6->s6_addr32[0], &faith_prefix, 615 sizeof(struct in6_addr) - sizeof(struct in_addr)); 616 memcpy(&in6->s6_addr32[3], ap, sizeof(struct in_addr)); 617 } else 618#endif /* FAITH */ 619 GET_AI(cur->ai_next, gai_afd, ap, port); 620 if (cur == &sentinel) { 621 top = cur->ai_next; 622 GET_CANONNAME(top, hp->h_name); 623 } 624 cur = cur->ai_next; 625 } 626#ifdef ENABLE_IPV6 627 freehostent(hp); 628#endif 629 *res = top; 630 return SUCCESS; 631 free: 632 if (top) 633 freeaddrinfo(top); 634#ifdef ENABLE_IPV6 635 if (hp) 636 freehostent(hp); 637#endif 638/* bad: */ 639 *res = NULL; 640 return error; 641} 642 643#endif // HAVE_NETDB_H 644