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