Ruby  1.9.3p484(2013-11-22revision43786)
getnameinfo.c
Go to the documentation of this file.
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  * Issues to be discussed:
32  * - Thread safe-ness must be checked
33  * - Return values. There seems to be no standard for return value (RFC2133)
34  * but INRIA implementation returns EAI_xxx defined for getaddrinfo().
35  */
36 
37 #include "ruby/config.h"
38 #ifdef RUBY_EXTCONF_H
39 #include RUBY_EXTCONF_H
40 #endif
41 #include <stdio.h>
42 #include <sys/types.h>
43 #ifndef _WIN32
44 #if defined(__BEOS__) && !defined(__HAIKU__) && !defined(BONE)
45 # include <net/socket.h>
46 #else
47 # include <sys/socket.h>
48 #endif
49 #include <netinet/in.h>
50 #if defined(HAVE_ARPA_INET_H)
51 #include <arpa/inet.h>
52 #endif
53 #if defined(HAVE_ARPA_NAMESER_H)
54 #include <arpa/nameser.h>
55 #endif
56 #include <netdb.h>
57 #if defined(HAVE_RESOLV_H)
58 #include <resolv.h>
59 #endif
60 #endif
61 #ifdef _WIN32
62 #include <winsock2.h>
63 #include <ws2tcpip.h>
64 #define snprintf _snprintf
65 #endif
66 
67 #include <string.h>
68 #include <stddef.h>
69 
70 #ifdef SOCKS5
71 #include <socks.h>
72 #endif
73 
74 #include "addrinfo.h"
75 #include "sockport.h"
76 
77 #define SUCCESS 0
78 #define ANY 0
79 #define YES 1
80 #define NO 0
81 
82 struct sockinet {
83  u_char si_len;
84  u_char si_family;
86 };
87 
88 static struct afd {
89  int a_af;
90  int a_addrlen;
91  int a_socklen;
92  int a_off;
93 } afdl [] = {
94 #ifdef INET6
95 #define N_INET6 0
96  {PF_INET6, sizeof(struct in6_addr),
97  sizeof(struct sockaddr_in6),
98  offsetof(struct sockaddr_in6, sin6_addr)},
99 #define N_INET 1
100 #else
101 #define N_INET 0
102 #endif
103  {PF_INET, sizeof(struct in_addr),
104  sizeof(struct sockaddr_in),
105  offsetof(struct sockaddr_in, sin_addr)},
106  {0, 0, 0, 0},
107 };
108 
109 #define ENI_NOSOCKET 0
110 #define ENI_NOSERVNAME 1
111 #define ENI_NOHOSTNAME 2
112 #define ENI_MEMORY 3
113 #define ENI_SYSTEM 4
114 #define ENI_FAMILY 5
115 #define ENI_SALEN 6
116 
117 #ifndef HAVE_INET_NTOP
118 static const char *
119 inet_ntop(int af, const void *addr, char *numaddr, size_t numaddr_len)
120 {
121 #ifdef HAVE_INET_NTOA
122  struct in_addr in;
123  memcpy(&in.s_addr, addr, sizeof(in.s_addr));
124  snprintf(numaddr, numaddr_len, "%s", inet_ntoa(in));
125 #else
126  unsigned long x = ntohl(*(unsigned long*)addr);
127  snprintf(numaddr, numaddr_len, "%d.%d.%d.%d",
128  (int) (x>>24) & 0xff, (int) (x>>16) & 0xff,
129  (int) (x>> 8) & 0xff, (int) (x>> 0) & 0xff);
130 #endif
131  return numaddr;
132 }
133 #endif
134 
135 int
136 getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, socklen_t hostlen, char *serv, socklen_t servlen, int flags)
137 {
138  struct afd *afd;
139  struct hostent *hp;
140  u_short port;
141  int family, len, i;
142  char *addr, *p;
143  u_long v4a;
144 #ifdef INET6
145  u_char pfx;
146 #endif
147  int h_error;
148  char numserv[512];
149  char numaddr[512];
150 
151  if (sa == NULL)
152  return ENI_NOSOCKET;
153 
154  len = SA_LEN(sa);
155  if (len != salen) return ENI_SALEN;
156 
157  family = sa->sa_family;
158  for (i = 0; afdl[i].a_af; i++)
159  if (afdl[i].a_af == family) {
160  afd = &afdl[i];
161  goto found;
162  }
163  return ENI_FAMILY;
164 
165  found:
166  if (len != afd->a_socklen) return ENI_SALEN;
167 
168  port = ((struct sockinet *)sa)->si_port; /* network byte order */
169  addr = (char *)sa + afd->a_off;
170 
171  if (serv == NULL || servlen == 0) {
172  /* what we should do? */
173  } else if (flags & NI_NUMERICSERV) {
174  snprintf(numserv, sizeof(numserv), "%d", ntohs(port));
175  if (strlen(numserv) + 1 > servlen)
176  return ENI_MEMORY;
177  strcpy(serv, numserv);
178  } else {
179 #if defined(HAVE_GETSERVBYPORT)
180  struct servent *sp = getservbyport(port, (flags & NI_DGRAM) ? "udp" : "tcp");
181  if (sp) {
182  if (strlen(sp->s_name) + 1 > servlen)
183  return ENI_MEMORY;
184  strcpy(serv, sp->s_name);
185  } else
186  return ENI_NOSERVNAME;
187 #else
188  return ENI_NOSERVNAME;
189 #endif
190  }
191 
192  switch (sa->sa_family) {
193  case AF_INET:
194  v4a = ntohl(((struct sockaddr_in *)sa)->sin_addr.s_addr);
195  if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a))
196  flags |= NI_NUMERICHOST;
197  v4a >>= IN_CLASSA_NSHIFT;
198  if (v4a == 0)
199  flags |= NI_NUMERICHOST;
200  break;
201 #ifdef INET6
202  case AF_INET6:
203 #ifdef HAVE_ADDR8
204  pfx = ((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr8[0];
205 #else
206  pfx = ((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr[0];
207 #endif
208  if (pfx == 0 || pfx == 0xfe || pfx == 0xff)
209  flags |= NI_NUMERICHOST;
210  break;
211 #endif
212  }
213  if (host == NULL || hostlen == 0) {
214  /* what should we do? */
215  } else if (flags & NI_NUMERICHOST) {
216  if (inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr))
217  == NULL)
218  return ENI_SYSTEM;
219  if (strlen(numaddr) > hostlen)
220  return ENI_MEMORY;
221  strcpy(host, numaddr);
222  } else {
223 #ifdef INET6
224  hp = getipnodebyaddr(addr, afd->a_addrlen, afd->a_af, &h_error);
225 #else
226  hp = gethostbyaddr(addr, afd->a_addrlen, afd->a_af);
227  h_error = h_errno;
228 #endif
229 
230  if (hp) {
231  if (flags & NI_NOFQDN) {
232  p = strchr(hp->h_name, '.');
233  if (p) *p = '\0';
234  }
235  if (strlen(hp->h_name) + 1 > hostlen) {
236 #ifdef INET6
237  freehostent(hp);
238 #endif
239  return ENI_MEMORY;
240  }
241  strcpy(host, hp->h_name);
242 #ifdef INET6
243  freehostent(hp);
244 #endif
245  } else {
246  if (flags & NI_NAMEREQD)
247  return ENI_NOHOSTNAME;
248  if (inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr))
249  == NULL)
250  return ENI_NOHOSTNAME;
251  if (strlen(numaddr) > hostlen)
252  return ENI_MEMORY;
253  strcpy(host, numaddr);
254  }
255  }
256  return SUCCESS;
257 }
258