Ruby  2.1.10p492(2016-04-01revision54464)
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 #ifndef HAVE_TYPE_SOCKLEN_T
75 typedef int socklen_t;
76 #endif
77 
78 #include "addrinfo.h"
79 #include "sockport.h"
80 
81 #define SUCCESS 0
82 #define ANY 0
83 #define YES 1
84 #define NO 0
85 
86 struct sockinet {
87  u_char si_len;
88  u_char si_family;
90 };
91 
92 static struct afd {
93  int a_af;
94  int a_addrlen;
95  int a_socklen;
96  int a_off;
97 } afdl [] = {
98 #ifdef INET6
99 #define N_INET6 0
100  {PF_INET6, sizeof(struct in6_addr),
101  sizeof(struct sockaddr_in6),
102  offsetof(struct sockaddr_in6, sin6_addr)},
103 #define N_INET 1
104 #else
105 #define N_INET 0
106 #endif
107  {PF_INET, sizeof(struct in_addr),
108  sizeof(struct sockaddr_in),
109  offsetof(struct sockaddr_in, sin_addr)},
110  {0, 0, 0, 0},
111 };
112 
113 #define ENI_NOSOCKET 0
114 #define ENI_NOSERVNAME 1
115 #define ENI_NOHOSTNAME 2
116 #define ENI_MEMORY 3
117 #define ENI_SYSTEM 4
118 #define ENI_FAMILY 5
119 #define ENI_SALEN 6
120 
121 #ifndef HAVE_INET_NTOP
122 static const char *
123 inet_ntop(int af, const void *addr, char *numaddr, size_t numaddr_len)
124 {
125 #ifdef HAVE_INET_NTOA
126  struct in_addr in;
127  memcpy(&in.s_addr, addr, sizeof(in.s_addr));
128  snprintf(numaddr, numaddr_len, "%s", inet_ntoa(in));
129 #else
130  unsigned long x = ntohl(*(unsigned long*)addr);
131  snprintf(numaddr, numaddr_len, "%d.%d.%d.%d",
132  (int) (x>>24) & 0xff, (int) (x>>16) & 0xff,
133  (int) (x>> 8) & 0xff, (int) (x>> 0) & 0xff);
134 #endif
135  return numaddr;
136 }
137 #endif
138 
139 int
140 getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, socklen_t hostlen, char *serv, socklen_t servlen, int flags)
141 {
142  struct afd *afd;
143  struct hostent *hp;
144  u_short port;
145  int family, len, i;
146  char *addr, *p;
147  u_long v4a;
148 #ifdef INET6
149  u_char pfx;
150 #endif
151  int h_error;
152  char numserv[512];
153  char numaddr[512];
154 
155  if (sa == NULL)
156  return ENI_NOSOCKET;
157 
158  if (!VALIDATE_SOCKLEN(sa, salen)) return ENI_SALEN;
159  len = salen;
160 
161  family = sa->sa_family;
162  for (i = 0; afdl[i].a_af; i++)
163  if (afdl[i].a_af == family) {
164  afd = &afdl[i];
165  goto found;
166  }
167  return ENI_FAMILY;
168 
169  found:
170  if (len != afd->a_socklen) return ENI_SALEN;
171 
172  port = ((struct sockinet *)sa)->si_port; /* network byte order */
173  addr = (char *)sa + afd->a_off;
174 
175  if (serv == NULL || servlen == 0) {
176  /* what we should do? */
177  } else if (flags & NI_NUMERICSERV) {
178  snprintf(numserv, sizeof(numserv), "%d", ntohs(port));
179  if (strlen(numserv) + 1 > servlen)
180  return ENI_MEMORY;
181  strcpy(serv, numserv);
182  } else {
183 #if defined(HAVE_GETSERVBYPORT)
184  struct servent *sp = getservbyport(port, (flags & NI_DGRAM) ? "udp" : "tcp");
185  if (sp) {
186  if (strlen(sp->s_name) + 1 > servlen)
187  return ENI_MEMORY;
188  strcpy(serv, sp->s_name);
189  } else
190  return ENI_NOSERVNAME;
191 #else
192  return ENI_NOSERVNAME;
193 #endif
194  }
195 
196  switch (sa->sa_family) {
197  case AF_INET:
198  v4a = ntohl(((struct sockaddr_in *)sa)->sin_addr.s_addr);
199  if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a))
200  flags |= NI_NUMERICHOST;
201  v4a >>= IN_CLASSA_NSHIFT;
202  if (v4a == 0)
203  flags |= NI_NUMERICHOST;
204  break;
205 #ifdef INET6
206  case AF_INET6:
207 #ifdef HAVE_ADDR8
208  pfx = ((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr8[0];
209 #else
210  pfx = ((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr[0];
211 #endif
212  if (pfx == 0 || pfx == 0xfe || pfx == 0xff)
213  flags |= NI_NUMERICHOST;
214  break;
215 #endif
216  }
217  if (host == NULL || hostlen == 0) {
218  /* what should we do? */
219  } else if (flags & NI_NUMERICHOST) {
220  if (inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr))
221  == NULL)
222  return ENI_SYSTEM;
223  if (strlen(numaddr) > hostlen)
224  return ENI_MEMORY;
225  strcpy(host, numaddr);
226  } else {
227 #ifdef INET6
228  hp = getipnodebyaddr(addr, afd->a_addrlen, afd->a_af, &h_error);
229 #else
230  hp = gethostbyaddr(addr, afd->a_addrlen, afd->a_af);
231  h_error = h_errno;
232 #endif
233 
234  if (hp) {
235  if (flags & NI_NOFQDN) {
236  p = strchr(hp->h_name, '.');
237  if (p) *p = '\0';
238  }
239  if (strlen(hp->h_name) + 1 > hostlen) {
240 #ifdef INET6
241  freehostent(hp);
242 #endif
243  return ENI_MEMORY;
244  }
245  strcpy(host, hp->h_name);
246 #ifdef INET6
247  freehostent(hp);
248 #endif
249  } else {
250  if (flags & NI_NAMEREQD)
251  return ENI_NOHOSTNAME;
252  if (inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr))
253  == NULL)
254  return ENI_NOHOSTNAME;
255  if (strlen(numaddr) > hostlen)
256  return ENI_MEMORY;
257  strcpy(host, numaddr);
258  }
259  }
260  return SUCCESS;
261 }
int a_af
Definition: getaddrinfo.c:116
#define SUCCESS
Definition: getnameinfo.c:81
#define VALIDATE_SOCKLEN(addr, len)
Definition: sockport.h:16
size_t strlen(const char *)
#define PF_INET
Definition: sockport.h:109
u_char si_family
Definition: getaddrinfo.c:111
#define NI_DGRAM
Definition: addrinfo.h:128
int a_socklen
Definition: getaddrinfo.c:118
#define freehostent
Definition: addrinfo.h:153
if(args--[1]==0)
Definition: array.c:3187
#define ENI_MEMORY
Definition: getnameinfo.c:116
i
Definition: enum.c:446
strcpy(cmd2, cmd)
static struct afd afdl[]
int flags
Definition: tcltklib.c:3015
#define NI_NUMERICSERV
Definition: addrinfo.h:127
#define offsetof(p_type, field)
Definition: addrinfo.h:186
static const char * inet_ntop(int af, const void *addr, char *numaddr, size_t numaddr_len)
Definition: getnameinfo.c:123
#define IN_CLASSA_NSHIFT
Definition: sockport.h:93
#define u_short
Definition: vsnprintf.c:65
int len
Definition: enumerator.c:1332
else
Definition: enum.c:452
memcpy(buf+1, str, len)
int socklen_t
Definition: getaddrinfo.c:84
#define NI_NUMERICHOST
Definition: addrinfo.h:125
char * strchr(char *, char)
#define ENI_NOSOCKET
Definition: getnameinfo.c:113
#define ENI_SALEN
Definition: getnameinfo.c:119
#define ENI_SYSTEM
Definition: getnameinfo.c:117
#define ENI_FAMILY
Definition: getnameinfo.c:118
int a_off
Definition: getaddrinfo.c:119
#define sizeof(x)
Definition: zlib.c:58
u_char si_len
Definition: getaddrinfo.c:110
#define NI_NOFQDN
Definition: addrinfo.h:124
#define IN_EXPERIMENTAL(i)
Definition: sockport.h:89
int getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, socklen_t hostlen, char *serv, socklen_t servlen, int flags)
Definition: getnameinfo.c:140
#define ENI_NOSERVNAME
Definition: getnameinfo.c:114
register C_block * p
Definition: crypt.c:309
#define u_long
Definition: vsnprintf.c:64
u_short si_port
Definition: getaddrinfo.c:112
#define NI_NAMEREQD
Definition: addrinfo.h:126
#define N_INET
#define snprintf
int a_addrlen
Definition: getaddrinfo.c:117
#define NULL
Definition: _sdbm.c:102
#define IN_MULTICAST(i)
Definition: sockport.h:85
#define ENI_NOHOSTNAME
Definition: getnameinfo.c:115