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 #include "ruby/config.h"
00038 #ifdef RUBY_EXTCONF_H
00039 #include RUBY_EXTCONF_H
00040 #endif
00041 #include <stdio.h>
00042 #include <sys/types.h>
00043 #ifndef _WIN32
00044 #if defined(__BEOS__) && !defined(__HAIKU__) && !defined(BONE)
00045 # include <net/socket.h>
00046 #else
00047 # include <sys/socket.h>
00048 #endif
00049 #include <netinet/in.h>
00050 #if defined(HAVE_ARPA_INET_H)
00051 #include <arpa/inet.h>
00052 #endif
00053 #if defined(HAVE_ARPA_NAMESER_H)
00054 #include <arpa/nameser.h>
00055 #endif
00056 #include <netdb.h>
00057 #if defined(HAVE_RESOLV_H)
00058 #include <resolv.h>
00059 #endif
00060 #endif
00061 #ifdef _WIN32
00062 #include <winsock2.h>
00063 #include <ws2tcpip.h>
00064 #define snprintf _snprintf
00065 #endif
00066
00067 #include <string.h>
00068 #include <stddef.h>
00069
00070 #ifdef SOCKS5
00071 #include <socks.h>
00072 #endif
00073
00074 #ifndef HAVE_TYPE_SOCKLEN_T
00075 typedef int socklen_t;
00076 #endif
00077
00078 #include "addrinfo.h"
00079 #include "sockport.h"
00080
00081 #define SUCCESS 0
00082 #define ANY 0
00083 #define YES 1
00084 #define NO 0
00085
00086 struct sockinet {
00087 u_char si_len;
00088 u_char si_family;
00089 u_short si_port;
00090 };
00091
00092 static struct afd {
00093 int a_af;
00094 int a_addrlen;
00095 int a_socklen;
00096 int a_off;
00097 } afdl [] = {
00098 #ifdef INET6
00099 #define N_INET6 0
00100 {PF_INET6, sizeof(struct in6_addr),
00101 sizeof(struct sockaddr_in6),
00102 offsetof(struct sockaddr_in6, sin6_addr)},
00103 #define N_INET 1
00104 #else
00105 #define N_INET 0
00106 #endif
00107 {PF_INET, sizeof(struct in_addr),
00108 sizeof(struct sockaddr_in),
00109 offsetof(struct sockaddr_in, sin_addr)},
00110 {0, 0, 0, 0},
00111 };
00112
00113 #define ENI_NOSOCKET 0
00114 #define ENI_NOSERVNAME 1
00115 #define ENI_NOHOSTNAME 2
00116 #define ENI_MEMORY 3
00117 #define ENI_SYSTEM 4
00118 #define ENI_FAMILY 5
00119 #define ENI_SALEN 6
00120
00121 #ifndef HAVE_INET_NTOP
00122 static const char *
00123 inet_ntop(int af, const void *addr, char *numaddr, size_t numaddr_len)
00124 {
00125 #ifdef HAVE_INET_NTOA
00126 struct in_addr in;
00127 memcpy(&in.s_addr, addr, sizeof(in.s_addr));
00128 snprintf(numaddr, numaddr_len, "%s", inet_ntoa(in));
00129 #else
00130 unsigned long x = ntohl(*(unsigned long*)addr);
00131 snprintf(numaddr, numaddr_len, "%d.%d.%d.%d",
00132 (int) (x>>24) & 0xff, (int) (x>>16) & 0xff,
00133 (int) (x>> 8) & 0xff, (int) (x>> 0) & 0xff);
00134 #endif
00135 return numaddr;
00136 }
00137 #endif
00138
00139 int
00140 getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, socklen_t hostlen, char *serv, socklen_t servlen, int flags)
00141 {
00142 struct afd *afd;
00143 struct hostent *hp;
00144 u_short port;
00145 int family, len, i;
00146 char *addr, *p;
00147 u_long v4a;
00148 #ifdef INET6
00149 u_char pfx;
00150 #endif
00151 int h_error;
00152 char numserv[512];
00153 char numaddr[512];
00154
00155 if (sa == NULL)
00156 return ENI_NOSOCKET;
00157
00158 if (!VALIDATE_SOCKLEN(sa, salen)) return ENI_SALEN;
00159 len = salen;
00160
00161 family = sa->sa_family;
00162 for (i = 0; afdl[i].a_af; i++)
00163 if (afdl[i].a_af == family) {
00164 afd = &afdl[i];
00165 goto found;
00166 }
00167 return ENI_FAMILY;
00168
00169 found:
00170 if (len != afd->a_socklen) return ENI_SALEN;
00171
00172 port = ((struct sockinet *)sa)->si_port;
00173 addr = (char *)sa + afd->a_off;
00174
00175 if (serv == NULL || servlen == 0) {
00176
00177 } else if (flags & NI_NUMERICSERV) {
00178 snprintf(numserv, sizeof(numserv), "%d", ntohs(port));
00179 if (strlen(numserv) + 1 > servlen)
00180 return ENI_MEMORY;
00181 strcpy(serv, numserv);
00182 } else {
00183 #if defined(HAVE_GETSERVBYPORT)
00184 struct servent *sp = getservbyport(port, (flags & NI_DGRAM) ? "udp" : "tcp");
00185 if (sp) {
00186 if (strlen(sp->s_name) + 1 > servlen)
00187 return ENI_MEMORY;
00188 strcpy(serv, sp->s_name);
00189 } else
00190 return ENI_NOSERVNAME;
00191 #else
00192 return ENI_NOSERVNAME;
00193 #endif
00194 }
00195
00196 switch (sa->sa_family) {
00197 case AF_INET:
00198 v4a = ntohl(((struct sockaddr_in *)sa)->sin_addr.s_addr);
00199 if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a))
00200 flags |= NI_NUMERICHOST;
00201 v4a >>= IN_CLASSA_NSHIFT;
00202 if (v4a == 0)
00203 flags |= NI_NUMERICHOST;
00204 break;
00205 #ifdef INET6
00206 case AF_INET6:
00207 #ifdef HAVE_ADDR8
00208 pfx = ((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr8[0];
00209 #else
00210 pfx = ((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr[0];
00211 #endif
00212 if (pfx == 0 || pfx == 0xfe || pfx == 0xff)
00213 flags |= NI_NUMERICHOST;
00214 break;
00215 #endif
00216 }
00217 if (host == NULL || hostlen == 0) {
00218
00219 } else if (flags & NI_NUMERICHOST) {
00220 if (inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr))
00221 == NULL)
00222 return ENI_SYSTEM;
00223 if (strlen(numaddr) > hostlen)
00224 return ENI_MEMORY;
00225 strcpy(host, numaddr);
00226 } else {
00227 #ifdef INET6
00228 hp = getipnodebyaddr(addr, afd->a_addrlen, afd->a_af, &h_error);
00229 #else
00230 hp = gethostbyaddr(addr, afd->a_addrlen, afd->a_af);
00231 h_error = h_errno;
00232 #endif
00233
00234 if (hp) {
00235 if (flags & NI_NOFQDN) {
00236 p = strchr(hp->h_name, '.');
00237 if (p) *p = '\0';
00238 }
00239 if (strlen(hp->h_name) + 1 > hostlen) {
00240 #ifdef INET6
00241 freehostent(hp);
00242 #endif
00243 return ENI_MEMORY;
00244 }
00245 strcpy(host, hp->h_name);
00246 #ifdef INET6
00247 freehostent(hp);
00248 #endif
00249 } else {
00250 if (flags & NI_NAMEREQD)
00251 return ENI_NOHOSTNAME;
00252 if (inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr))
00253 == NULL)
00254 return ENI_NOHOSTNAME;
00255 if (strlen(numaddr) > hostlen)
00256 return ENI_MEMORY;
00257 strcpy(host, numaddr);
00258 }
00259 }
00260 return SUCCESS;
00261 }
00262