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