00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041 #include "ruby/config.h"
00042 #ifdef RUBY_EXTCONF_H
00043 #include RUBY_EXTCONF_H
00044 #endif
00045 #include <sys/types.h>
00046 #ifndef _WIN32
00047 #include <sys/param.h>
00048 #if defined(__BEOS__) && !defined(__HAIKU__) && !defined(BONE)
00049 # include <net/socket.h>
00050 #else
00051 # include <sys/socket.h>
00052 #endif
00053 #include <netinet/in.h>
00054 #if defined(HAVE_ARPA_INET_H)
00055 #include <arpa/inet.h>
00056 #endif
00057 #if defined(HAVE_ARPA_NAMESER_H)
00058 #include <arpa/nameser.h>
00059 #endif
00060 #include <netdb.h>
00061 #if defined(HAVE_RESOLV_H)
00062 #ifdef _SX
00063 #include <stdio.h>
00064 #endif
00065 #include <resolv.h>
00066 #endif
00067 #include <unistd.h>
00068 #else
00069 #include <winsock2.h>
00070 #include <ws2tcpip.h>
00071 #include <io.h>
00072 #endif
00073 #include <string.h>
00074 #include <stdio.h>
00075 #include <stdlib.h>
00076 #include <stddef.h>
00077 #include <ctype.h>
00078
00079 #ifdef SOCKS5
00080 #include <socks.h>
00081 #endif
00082
00083 #include "addrinfo.h"
00084 #include "sockport.h"
00085
00086 #define SUCCESS 0
00087 #define ANY 0
00088 #define YES 1
00089 #define NO 0
00090
00091 #ifdef FAITH
00092 static int translate = NO;
00093 static struct in6_addr faith_prefix = IN6ADDR_ANY_INIT;
00094 #endif
00095
00096 static const char in_addrany[] = { 0, 0, 0, 0 };
00097 static const char in6_addrany[] = {
00098 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
00099 };
00100 static const char in_loopback[] = { 127, 0, 0, 1 };
00101 static const char in6_loopback[] = {
00102 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
00103 };
00104
00105 struct sockinet {
00106 u_char si_len;
00107 u_char si_family;
00108 u_short si_port;
00109 };
00110
00111 static const struct afd {
00112 int a_af;
00113 int a_addrlen;
00114 int a_socklen;
00115 int a_off;
00116 const char *a_addrany;
00117 const char *a_loopback;
00118 } afdl [] = {
00119 #ifdef INET6
00120 #define N_INET6 0
00121 {PF_INET6, sizeof(struct in6_addr),
00122 sizeof(struct sockaddr_in6),
00123 offsetof(struct sockaddr_in6, sin6_addr),
00124 in6_addrany, in6_loopback},
00125 #define N_INET 1
00126 #else
00127 #define N_INET 0
00128 #endif
00129 {PF_INET, sizeof(struct in_addr),
00130 sizeof(struct sockaddr_in),
00131 offsetof(struct sockaddr_in, sin_addr),
00132 in_addrany, in_loopback},
00133 {0, 0, 0, 0, NULL, NULL},
00134 };
00135
00136 #ifdef INET6
00137 #define PTON_MAX 16
00138 #else
00139 #define PTON_MAX 4
00140 #endif
00141
00142 static int get_name __P((const char *, const struct afd *,
00143 struct addrinfo **, char *, struct addrinfo *,
00144 int));
00145 static int get_addr __P((const char *, int, struct addrinfo **,
00146 struct addrinfo *, int));
00147 static int str_isnumber __P((const char *));
00148
00149 static const char *const ai_errlist[] = {
00150 "success.",
00151 "address family for hostname not supported.",
00152 "temporary failure in name resolution.",
00153 "invalid value for ai_flags.",
00154 "non-recoverable failure in name resolution.",
00155 "ai_family not supported.",
00156 "memory allocation failure.",
00157 "no address associated with hostname.",
00158 "hostname nor servname provided, or not known.",
00159 "servname not supported for ai_socktype.",
00160 "ai_socktype not supported.",
00161 "system error returned in errno.",
00162 "invalid value for hints.",
00163 "resolved protocol is unknown.",
00164 "unknown error.",
00165 };
00166
00167 #define GET_CANONNAME(ai, str) \
00168 if (pai->ai_flags & AI_CANONNAME) {\
00169 if (((ai)->ai_canonname = (char *)malloc(strlen(str) + 1)) != NULL) {\
00170 strcpy((ai)->ai_canonname, (str));\
00171 } else {\
00172 error = EAI_MEMORY;\
00173 goto free;\
00174 }\
00175 }
00176
00177 #define GET_AI(ai, afd, addr, port) {\
00178 char *p;\
00179 if (((ai) = (struct addrinfo *)malloc(sizeof(struct addrinfo) +\
00180 ((afd)->a_socklen)))\
00181 == NULL) {\
00182 error = EAI_MEMORY;\
00183 goto free;\
00184 }\
00185 memcpy(ai, pai, sizeof(struct addrinfo));\
00186 (ai)->ai_addr = (struct sockaddr *)((ai) + 1);\
00187 memset((ai)->ai_addr, 0, (afd)->a_socklen);\
00188 SET_SA_LEN((ai)->ai_addr, (ai)->ai_addrlen = (afd)->a_socklen);\
00189 (ai)->ai_addr->sa_family = (ai)->ai_family = (afd)->a_af;\
00190 ((struct sockinet *)(ai)->ai_addr)->si_port = port;\
00191 p = (char *)((ai)->ai_addr);\
00192 memcpy(p + (afd)->a_off, (addr), (afd)->a_addrlen);\
00193 }
00194
00195 #define ERR(err) { error = (err); goto bad; }
00196
00197 #ifndef HAVE_GAI_STRERROR
00198 #ifdef GAI_STRERROR_CONST
00199 const
00200 #endif
00201 char *
00202 gai_strerror(int ecode)
00203 {
00204 if (ecode < 0 || ecode > EAI_MAX)
00205 ecode = EAI_MAX;
00206 return (char *)ai_errlist[ecode];
00207 }
00208 #endif
00209
00210 void
00211 freeaddrinfo(struct addrinfo *ai)
00212 {
00213 struct addrinfo *next;
00214
00215 do {
00216 next = ai->ai_next;
00217 if (ai->ai_canonname)
00218 free(ai->ai_canonname);
00219
00220 free(ai);
00221 } while ((ai = next) != NULL);
00222 }
00223
00224 static int
00225 str_isnumber(const char *p)
00226 {
00227 char *q = (char *)p;
00228 while (*q) {
00229 if (! isdigit(*q))
00230 return NO;
00231 q++;
00232 }
00233 return YES;
00234 }
00235
00236 #ifndef HAVE_INET_PTON
00237
00238 static int
00239 inet_pton(int af, const char *hostname, void *pton)
00240 {
00241 struct in_addr in;
00242
00243 #ifdef HAVE_INET_ATON
00244 if (!inet_aton(hostname, &in))
00245 return 0;
00246 #else
00247 int d1, d2, d3, d4;
00248 char ch;
00249
00250 if (sscanf(hostname, "%d.%d.%d.%d%c", &d1, &d2, &d3, &d4, &ch) == 4 &&
00251 0 <= d1 && d1 <= 255 && 0 <= d2 && d2 <= 255 &&
00252 0 <= d3 && d3 <= 255 && 0 <= d4 && d4 <= 255) {
00253 in.s_addr = htonl(
00254 ((long) d1 << 24) | ((long) d2 << 16) |
00255 ((long) d3 << 8) | ((long) d4 << 0));
00256 }
00257 else {
00258 return 0;
00259 }
00260 #endif
00261 memcpy(pton, &in, sizeof(in));
00262 return 1;
00263 }
00264 #endif
00265
00266 int
00267 getaddrinfo(const char *hostname, const char *servname, const struct addrinfo *hints, struct addrinfo **res)
00268 {
00269 struct addrinfo sentinel;
00270 struct addrinfo *top = NULL;
00271 struct addrinfo *cur;
00272 int i, error = 0;
00273 char pton[PTON_MAX];
00274 struct addrinfo ai;
00275 struct addrinfo *pai;
00276 u_short port;
00277
00278 #ifdef FAITH
00279 static int firsttime = 1;
00280
00281 if (firsttime) {
00282
00283 {
00284 char *q = getenv("GAI");
00285 if (q && inet_pton(AF_INET6, q, &faith_prefix) == 1)
00286 translate = YES;
00287 }
00288 firsttime = 0;
00289 }
00290 #endif
00291
00292
00293 sentinel.ai_next = NULL;
00294 cur = &sentinel;
00295 pai = &ai;
00296 pai->ai_flags = 0;
00297 pai->ai_family = PF_UNSPEC;
00298 pai->ai_socktype = ANY;
00299 pai->ai_protocol = ANY;
00300 pai->ai_addrlen = 0;
00301 pai->ai_canonname = NULL;
00302 pai->ai_addr = NULL;
00303 pai->ai_next = NULL;
00304 port = ANY;
00305
00306 if (hostname == NULL && servname == NULL)
00307 return EAI_NONAME;
00308 if (hints) {
00309
00310 if (hints->ai_addrlen || hints->ai_canonname ||
00311 hints->ai_addr || hints->ai_next)
00312 ERR(EAI_BADHINTS);
00313 if (hints->ai_flags & ~AI_MASK)
00314 ERR(EAI_BADFLAGS);
00315 switch (hints->ai_family) {
00316 case PF_UNSPEC:
00317 case PF_INET:
00318 #ifdef INET6
00319 case PF_INET6:
00320 #endif
00321 break;
00322 default:
00323 ERR(EAI_FAMILY);
00324 }
00325 memcpy(pai, hints, sizeof(*pai));
00326 switch (pai->ai_socktype) {
00327 case ANY:
00328 switch (pai->ai_protocol) {
00329 case ANY:
00330 break;
00331 case IPPROTO_UDP:
00332 pai->ai_socktype = SOCK_DGRAM;
00333 break;
00334 case IPPROTO_TCP:
00335 pai->ai_socktype = SOCK_STREAM;
00336 break;
00337 default:
00338 #if defined(SOCK_RAW)
00339 pai->ai_socktype = SOCK_RAW;
00340 #endif
00341 break;
00342 }
00343 break;
00344 #if defined(SOCK_RAW)
00345 case SOCK_RAW:
00346 break;
00347 #endif
00348 case SOCK_DGRAM:
00349 if (pai->ai_protocol != IPPROTO_UDP &&
00350 pai->ai_protocol != ANY)
00351 ERR(EAI_BADHINTS);
00352 pai->ai_protocol = IPPROTO_UDP;
00353 break;
00354 case SOCK_STREAM:
00355 if (pai->ai_protocol != IPPROTO_TCP &&
00356 pai->ai_protocol != ANY)
00357 ERR(EAI_BADHINTS);
00358 pai->ai_protocol = IPPROTO_TCP;
00359 break;
00360 default:
00361 ERR(EAI_SOCKTYPE);
00362 break;
00363 }
00364 }
00365
00366
00367
00368
00369 if (servname) {
00370 if (str_isnumber(servname)) {
00371 if (pai->ai_socktype == ANY) {
00372
00373 pai->ai_socktype = SOCK_DGRAM;
00374 pai->ai_protocol = IPPROTO_UDP;
00375 }
00376 port = htons((unsigned short)atoi(servname));
00377 } else if (pai->ai_flags & AI_NUMERICSERV) {
00378 ERR(EAI_NONAME);
00379 } else {
00380 struct servent *sp;
00381 const char *proto;
00382
00383 proto = NULL;
00384 switch (pai->ai_socktype) {
00385 case ANY:
00386 proto = NULL;
00387 break;
00388 case SOCK_DGRAM:
00389 proto = "udp";
00390 break;
00391 case SOCK_STREAM:
00392 proto = "tcp";
00393 break;
00394 default:
00395 fprintf(stderr, "panic!\n");
00396 break;
00397 }
00398 if ((sp = getservbyname((char*)servname, proto)) == NULL)
00399 ERR(EAI_SERVICE);
00400 port = sp->s_port;
00401 if (pai->ai_socktype == ANY)
00402 if (strcmp(sp->s_proto, "udp") == 0) {
00403 pai->ai_socktype = SOCK_DGRAM;
00404 pai->ai_protocol = IPPROTO_UDP;
00405 } else if (strcmp(sp->s_proto, "tcp") == 0) {
00406 pai->ai_socktype = SOCK_STREAM;
00407 pai->ai_protocol = IPPROTO_TCP;
00408 } else
00409 ERR(EAI_PROTOCOL);
00410 }
00411 }
00412
00413
00414
00415
00416
00417
00418 if (hostname == NULL) {
00419 const struct afd *afd;
00420 int s;
00421
00422 for (afd = &afdl[0]; afd->a_af; afd++) {
00423 if (!(pai->ai_family == PF_UNSPEC
00424 || pai->ai_family == afd->a_af)) {
00425 continue;
00426 }
00427
00428
00429
00430
00431
00432 s = socket(afd->a_af, SOCK_DGRAM, 0);
00433 if (s < 0)
00434 continue;
00435 #if defined(__BEOS__)
00436 closesocket(s);
00437 #else
00438 close(s);
00439 #endif
00440
00441 if (pai->ai_flags & AI_PASSIVE) {
00442 GET_AI(cur->ai_next, afd, afd->a_addrany, port);
00443
00444
00445
00446 } else {
00447 GET_AI(cur->ai_next, afd, afd->a_loopback,
00448 port);
00449
00450
00451
00452 }
00453 cur = cur->ai_next;
00454 }
00455 top = sentinel.ai_next;
00456 if (top)
00457 goto good;
00458 else
00459 ERR(EAI_FAMILY);
00460 }
00461
00462
00463 for (i = 0; afdl[i].a_af; i++) {
00464 if (inet_pton(afdl[i].a_af, hostname, pton)) {
00465 u_long v4a;
00466 #ifdef INET6
00467 u_char pfx;
00468 #endif
00469
00470 switch (afdl[i].a_af) {
00471 case AF_INET:
00472 v4a = ((struct in_addr *)pton)->s_addr;
00473 if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a))
00474 pai->ai_flags &= ~AI_CANONNAME;
00475 v4a >>= IN_CLASSA_NSHIFT;
00476 if (v4a == 0 || v4a == IN_LOOPBACKNET)
00477 pai->ai_flags &= ~AI_CANONNAME;
00478 break;
00479 #ifdef INET6
00480 case AF_INET6:
00481 pfx = ((struct in6_addr *)pton)->s6_addr[0];
00482 if (pfx == 0 || pfx == 0xfe || pfx == 0xff)
00483 pai->ai_flags &= ~AI_CANONNAME;
00484 break;
00485 #endif
00486 }
00487
00488 if (pai->ai_family == afdl[i].a_af ||
00489 pai->ai_family == PF_UNSPEC) {
00490 if (! (pai->ai_flags & AI_CANONNAME)) {
00491 GET_AI(top, &afdl[i], pton, port);
00492 goto good;
00493 }
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503 get_name(pton, &afdl[i], &top, pton, pai, port);
00504 goto good;
00505 } else
00506 ERR(EAI_FAMILY);
00507 }
00508 }
00509
00510 if (pai->ai_flags & AI_NUMERICHOST)
00511 ERR(EAI_NONAME);
00512
00513
00514 error = get_addr(hostname, pai->ai_family, &top, pai, port);
00515 if (error == 0) {
00516 if (top) {
00517 good:
00518 *res = top;
00519 return SUCCESS;
00520 } else
00521 error = EAI_FAIL;
00522 }
00523 free:
00524 if (top)
00525 freeaddrinfo(top);
00526 bad:
00527 *res = NULL;
00528 return error;
00529 }
00530
00531 static int
00532 get_name(const char *addr, const struct afd *afd, struct addrinfo **res, char *numaddr, struct addrinfo *pai, int port0)
00533 {
00534 u_short port = port0 & 0xffff;
00535 struct hostent *hp;
00536 struct addrinfo *cur;
00537 int error = 0;
00538 #ifdef INET6
00539 int h_error;
00540 #endif
00541
00542 #ifdef INET6
00543 hp = getipnodebyaddr(addr, afd->a_addrlen, afd->a_af, &h_error);
00544 #else
00545 hp = gethostbyaddr((char*)addr, afd->a_addrlen, AF_INET);
00546 #endif
00547 if (hp && hp->h_name && hp->h_name[0] && hp->h_addr_list[0]) {
00548 GET_AI(cur, afd, hp->h_addr_list[0], port);
00549 GET_CANONNAME(cur, hp->h_name);
00550 } else
00551 GET_AI(cur, afd, numaddr, port);
00552
00553 #ifdef INET6
00554 if (hp)
00555 freehostent(hp);
00556 #endif
00557 *res = cur;
00558 return SUCCESS;
00559 free:
00560 if (cur)
00561 freeaddrinfo(cur);
00562 #ifdef INET6
00563 if (hp)
00564 freehostent(hp);
00565 #endif
00566
00567 *res = NULL;
00568 return error;
00569 }
00570
00571 static int
00572 get_addr(const char *hostname, int af, struct addrinfo **res, struct addrinfo *pai, int port0)
00573 {
00574 u_short port = port0 & 0xffff;
00575 struct addrinfo sentinel;
00576 struct hostent *hp;
00577 struct addrinfo *top, *cur;
00578 const struct afd *afd;
00579 int i, error = 0, h_error;
00580 char *ap;
00581
00582 top = NULL;
00583 sentinel.ai_next = NULL;
00584 cur = &sentinel;
00585 #ifdef INET6
00586 if (af == AF_UNSPEC) {
00587 hp = getipnodebyname(hostname, AF_INET6,
00588 AI_ADDRCONFIG|AI_ALL|AI_V4MAPPED, &h_error);
00589 } else
00590 hp = getipnodebyname(hostname, af, AI_ADDRCONFIG, &h_error);
00591 #else
00592 hp = gethostbyname((char*)hostname);
00593 h_error = h_errno;
00594 #endif
00595 if (hp == NULL) {
00596 switch (h_error) {
00597 case HOST_NOT_FOUND:
00598 case NO_DATA:
00599 error = EAI_NODATA;
00600 break;
00601 case TRY_AGAIN:
00602 error = EAI_AGAIN;
00603 break;
00604 case NO_RECOVERY:
00605 default:
00606 error = EAI_FAIL;
00607 break;
00608 }
00609 goto bad;
00610 }
00611
00612 if ((hp->h_name == NULL) || (hp->h_name[0] == 0) ||
00613 (hp->h_addr_list[0] == NULL))
00614 ERR(EAI_FAIL);
00615
00616 for (i = 0; (ap = hp->h_addr_list[i]) != NULL; i++) {
00617 switch (af) {
00618 #ifdef INET6
00619 case AF_INET6:
00620 afd = &afdl[N_INET6];
00621 break;
00622 #endif
00623 #ifndef INET6
00624 default:
00625 #endif
00626 case AF_INET:
00627 afd = &afdl[N_INET];
00628 break;
00629 #ifdef INET6
00630 default:
00631 if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ap)) {
00632 ap += sizeof(struct in6_addr) -
00633 sizeof(struct in_addr);
00634 afd = &afdl[N_INET];
00635 } else
00636 afd = &afdl[N_INET6];
00637 break;
00638 #endif
00639 }
00640 #ifdef FAITH
00641 if (translate && afd->a_af == AF_INET) {
00642 struct in6_addr *in6;
00643
00644 GET_AI(cur->ai_next, &afdl[N_INET6], ap, port);
00645 in6 = &((struct sockaddr_in6 *)cur->ai_next->ai_addr)->sin6_addr;
00646 memcpy(&in6->s6_addr, &faith_prefix,
00647 sizeof(struct in6_addr) - sizeof(struct in_addr));
00648 memcpy(&in6->s6_addr + sizeof(struct in_addr), ap,
00649 sizeof(struct in_addr));
00650 } else
00651 #endif
00652 GET_AI(cur->ai_next, afd, ap, port);
00653 if (cur == &sentinel) {
00654 top = cur->ai_next;
00655 GET_CANONNAME(top, hp->h_name);
00656 }
00657 cur = cur->ai_next;
00658 }
00659 #ifdef INET6
00660 freehostent(hp);
00661 #endif
00662 *res = top;
00663 return SUCCESS;
00664 free:
00665 if (top)
00666 freeaddrinfo(top);
00667 #ifdef INET6
00668 if (hp)
00669 freehostent(hp);
00670 #endif
00671 bad:
00672 *res = NULL;
00673 return error;
00674 }
00675