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