Ruby  2.5.0dev(2017-10-22revision60238)
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 #include <sys/socket.h>
45 #include <netinet/in.h>
46 #if defined(HAVE_ARPA_INET_H)
47 #include <arpa/inet.h>
48 #endif
49 #if defined(HAVE_ARPA_NAMESER_H)
50 #include <arpa/nameser.h>
51 #endif
52 #include <netdb.h>
53 #if defined(HAVE_RESOLV_H)
54 #include <resolv.h>
55 #endif
56 #endif
57 #ifdef _WIN32
58 #if defined(_MSC_VER) && _MSC_VER <= 1200
59 #include <windows.h>
60 #endif
61 #include <winsock2.h>
62 #include <ws2tcpip.h>
63 #define snprintf _snprintf
64 #endif
65 
66 #include <string.h>
67 #include <stddef.h>
68 
69 #ifdef SOCKS5
70 #include <socks.h>
71 #endif
72 
73 #ifndef HAVE_TYPE_SOCKLEN_T
74 typedef int socklen_t;
75 #endif
76 
77 #include "addrinfo.h"
78 #include "sockport.h"
79 #include "rubysocket.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 int
122 getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, socklen_t hostlen, char *serv, socklen_t servlen, int flags)
123 {
124  struct afd *afd;
125  struct hostent *hp;
126  u_short port;
127  int family, len, i;
128  char *addr, *p;
129  u_long v4a;
130 #ifdef INET6
131  u_char pfx;
132 #endif
133  int h_error;
134  char numserv[512];
135  char numaddr[512];
136 
137  if (sa == NULL)
138  return ENI_NOSOCKET;
139 
140  if (!VALIDATE_SOCKLEN(sa, salen)) return ENI_SALEN;
141  len = salen;
142 
143  family = sa->sa_family;
144  for (i = 0; afdl[i].a_af; i++)
145  if (afdl[i].a_af == family) {
146  afd = &afdl[i];
147  goto found;
148  }
149  return ENI_FAMILY;
150 
151  found:
152  if (len != afd->a_socklen) return ENI_SALEN;
153 
154  port = ((struct sockinet *)sa)->si_port; /* network byte order */
155  addr = (char *)sa + afd->a_off;
156 
157  if (serv == NULL || servlen == 0) {
158  /* what we should do? */
159  } else if (flags & NI_NUMERICSERV) {
160  snprintf(numserv, sizeof(numserv), "%d", ntohs(port));
161  if (strlen(numserv) + 1 > servlen)
162  return ENI_MEMORY;
163  strcpy(serv, numserv);
164  } else {
165 #if defined(HAVE_GETSERVBYPORT)
166  struct servent *sp = getservbyport(port, (flags & NI_DGRAM) ? "udp" : "tcp");
167  if (sp) {
168  if (strlen(sp->s_name) + 1 > servlen)
169  return ENI_MEMORY;
170  strcpy(serv, sp->s_name);
171  } else
172  return ENI_NOSERVNAME;
173 #else
174  return ENI_NOSERVNAME;
175 #endif
176  }
177 
178  switch (sa->sa_family) {
179  case AF_INET:
180  v4a = ntohl(((struct sockaddr_in *)sa)->sin_addr.s_addr);
181  if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a))
182  flags |= NI_NUMERICHOST;
183  v4a >>= IN_CLASSA_NSHIFT;
184  if (v4a == 0)
185  flags |= NI_NUMERICHOST;
186  break;
187 #ifdef INET6
188  case AF_INET6:
189 #ifdef HAVE_ADDR8
190  pfx = ((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr8[0];
191 #else
192  pfx = ((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr[0];
193 #endif
194  if (pfx == 0 || pfx == 0xfe || pfx == 0xff)
195  flags |= NI_NUMERICHOST;
196  break;
197 #endif
198  }
199  if (host == NULL || hostlen == 0) {
200  /* what should we do? */
201  } else if (flags & NI_NUMERICHOST) {
202  if (inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr))
203  == NULL)
204  return ENI_SYSTEM;
205  if (strlen(numaddr) > hostlen)
206  return ENI_MEMORY;
207  strcpy(host, numaddr);
208  } else {
209 #ifdef INET6
210  hp = getipnodebyaddr(addr, afd->a_addrlen, afd->a_af, &h_error);
211 #else
212  hp = gethostbyaddr(addr, afd->a_addrlen, afd->a_af);
213  h_error = h_errno;
214 #endif
215 
216  if (hp) {
217  if (flags & NI_NOFQDN) {
218  p = strchr(hp->h_name, '.');
219  if (p) *p = '\0';
220  }
221  if (strlen(hp->h_name) + 1 > hostlen) {
222 #ifdef INET6
223  freehostent(hp);
224 #endif
225  return ENI_MEMORY;
226  }
227  strcpy(host, hp->h_name);
228 #ifdef INET6
229  freehostent(hp);
230 #endif
231  } else {
232  if (flags & NI_NAMEREQD)
233  return ENI_NOHOSTNAME;
234  if (inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr))
235  == NULL)
236  return ENI_NOHOSTNAME;
237  if (strlen(numaddr) > hostlen)
238  return ENI_MEMORY;
239  strcpy(host, numaddr);
240  }
241  }
242  return SUCCESS;
243 }
#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:110
#define NI_DGRAM
Definition: addrinfo.h:128
if(len<=MAX_WORD_LENGTH &&len >=MIN_WORD_LENGTH)
Definition: zonetab.h:883
int socklen_t
Definition: getnameinfo.c:74
#define freehostent
Definition: addrinfo.h:153
const char * inet_ntop(int af, const void *addr, char *numaddr, size_t numaddr_len)
Definition: option.c:651
#define ENI_MEMORY
Definition: getnameinfo.c:116
#define NI_NUMERICSERV
Definition: addrinfo.h:127
#define snprintf
Definition: subst.h:6
#define IN_CLASSA_NSHIFT
Definition: sockport.h:93
#define u_short
Definition: vsnprintf.c:65
int socklen_t
Definition: getaddrinfo.c:83
#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
register unsigned int len
Definition: zonetab.h:51
#define ENI_SYSTEM
Definition: getnameinfo.c:117
#define ENI_FAMILY
Definition: getnameinfo.c:118
u_char si_len
Definition: getaddrinfo.c:109
#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:122
#define ENI_NOSERVNAME
Definition: getnameinfo.c:114
#define u_long
Definition: vsnprintf.c:64
u_short si_port
Definition: getaddrinfo.c:111
#define NI_NAMEREQD
Definition: addrinfo.h:126
#define NULL
Definition: _sdbm.c:102
#define IN_MULTICAST(i)
Definition: sockport.h:85
#define ENI_NOHOSTNAME
Definition: getnameinfo.c:115