Watt-32 tcp/ip  2.2 dev-rel.10
get_ni.c
Go to the documentation of this file.
1 
5 /* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  * notice, this list of conditions and the following disclaimer in the
15  * documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the project nor the names of its contributors
17  * may be used to endorse or promote products derived from this software
18  * without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32 
33 /*
34  * Issues to be discussed:
35  * - Thread safe-ness must be checked
36  * - Return values. There seems to be no standard for return value (RFC2553)
37  * but INRIA implementation returns EAI_xxx defined for getaddrinfo().
38  * - RFC2553 says that we should raise error on short buffer. X/Open says
39  * we need to truncate the result. We obey RFC2553 (and X/Open should be
40  * modified).
41  *
42  * Adapted for Watt-32 tcp/ip stack by G. Vanem <gvanem@yahoo.no>, Aug 2002.
43  */
44 
45 #if 0
46 static const char rcsid[] = "@(#) $Header: /tcpdump/master/tcpdump/missing/"
47  "getnameinfo.c,v 1.8 2000/10/24 00:56:53 fenner Exp $";
48 #endif
49 
50 #include "socket.h"
51 
52 #if defined(USE_BSD_API)
53 
54 #define NI_SUCCESS 0
55 #define ANY 0
56 #define YES 1
57 #define NO 0
58 
59 #define ENI_NOSOCKET EINVAL
60 #define ENI_NOHOSTNAME EINVAL
61 #define ENI_MEMORY ENOMEM
62 #define ENI_SALEN EINVAL
63 #define ENI_FAMILY EAFNOSUPPORT
64 #define ENI_SYSTEM -1
65 
66 #define GI_RESULT(err) gi_result (err, #err, __LINE__)
67 
68 static struct afd {
69  int a_af;
70  int a_addrlen;
71  int a_socklen;
72  int a_off;
73  } afd_list [3];
74 
75 struct sockinet {
76  BYTE si_len;
77  BYTE si_family;
78  WORD si_port;
79  };
80 
81 /*
82  * Initialise afd_list[] with IPv6 protocol at highest priority.
83  */
84 static void afd_list_init (BOOL ip6_prio)
85 {
86  int i = (ip6_prio ? 0 : 1);
87 
88  memset (&afd_list, 0, sizeof(afd_list));
89  afd_list[i].a_af = AF_INET6;
90  afd_list[i].a_addrlen = sizeof (struct in6_addr);
91  afd_list[i].a_socklen = sizeof (struct sockaddr_in6);
92  afd_list[i].a_off = offsetof (struct sockaddr_in6, sin6_addr);
93 
94  i ^= 1;
95  afd_list[i].a_af = AF_INET;
96  afd_list[i].a_addrlen = sizeof (struct in_addr);
97  afd_list[i].a_socklen = sizeof (struct sockaddr_in);
98  afd_list[i].a_off = offsetof (struct sockaddr_in, sin_addr);
99 }
100 
101 static int gi_result (int err, const char *str, unsigned line)
102 {
103  SOCK_LEAVE_SCOPE();
104  if (err)
105  {
106  SOCK_DEBUGF ((", %s (%d) at line %u", str, err, line));
107  if (err > 0)
108  SOCK_ERRNO (err);
109  }
110  else
111  SOCK_DEBUGF ((", okay"));
112 
113  ARGSUSED (str);
114  ARGSUSED (line);
115  return (err);
116 }
117 
118 int W32_CALL getnameinfo (const struct sockaddr *sa, int salen,
119  char *host, int hostlen,
120  char *serv, int servlen, int flags)
121 {
122  static BOOL init = FALSE;
123  struct afd *afd;
124  int i, family = -1;
125  DWORD v4a;
126  WORD port;
127  char numserv[512];
128  char numaddr[512];
129  char *addr, *p;
130 
131  const struct servent *sp;
132  const struct hostent *hp;
133  const struct sockaddr_in *a4 = (const struct sockaddr_in *) sa;
134  const struct sockaddr_in6 *a6 = (const struct sockaddr_in6*) sa;
135 
136  if (!init)
137  afd_list_init (TRUE);
138  init = TRUE;
139 
140  SOCK_DEBUGF (("\ngetnameinfo: "));
141 
142  if (!sa)
143  return GI_RESULT (ENI_NOSOCKET);
144 
145  family = sa->sa_family;
146 
147  SOCK_DEBUGF (("name %s, serv %.10s, flags %04X",
148  family == AF_INET ? inet_ntoa(a4->sin_addr) :
149  family == AF_INET6 ? _inet6_ntoa(&a6->sin6_addr) : "??",
150  ((flags & NI_NUMERICSERV) || flags == 0) ? "<get>" : serv,
151  flags));
152 
153  for (i = 0; afd_list[i].a_af; i++)
154  if (afd_list[i].a_af == family)
155  {
156  afd = &afd_list[i];
157  goto found;
158  }
159  return GI_RESULT (ENI_FAMILY);
160 
161 found:
162  if (salen != afd->a_socklen)
163  return GI_RESULT (ENI_SALEN);
164 
165  port = ((struct sockinet*)sa)->si_port; /* network byte order */
166  addr = (char*) sa + afd->a_off;
167 
168  SOCK_ENTER_SCOPE();
169 
170  if (!serv || servlen == 0)
171  {
172  /* do nothing in this case.
173  * in case you are wondering if "&&" is more correct than
174  * "||" here: RFC2553 says that serv == NULL OR servlen == 0
175  * means that the caller does not want the result.
176  */
177  }
178  else
179  {
180  if (flags & NI_NUMERICSERV)
181  sp = NULL;
182  else sp = getservbyport (port, (flags & NI_DGRAM) ? "udp" : "tcp");
183  if (sp)
184  {
185  if ((int)strlen(sp->s_name) + 1 > servlen)
186  return GI_RESULT (ENI_MEMORY);
187  strcpy (serv, sp->s_name);
188  }
189  else
190  {
191  itoa (ntohs(port), numserv, 10);
192  if ((int)strlen(numserv) + 1 > servlen)
193  return GI_RESULT (ENI_MEMORY);
194  strcpy (serv, numserv);
195  }
196  }
197 
198  switch (sa->sa_family)
199  {
200  case AF_INET:
201  v4a = ntohl (((struct sockaddr_in*)sa)->sin_addr.s_addr);
202  if (IN_MULTICAST (v4a) || IN_EXPERIMENTAL (v4a))
203  flags |= NI_NUMERICHOST;
204  v4a >>= IN_CLASSA_NSHIFT;
205  if (v4a == 0)
206  flags |= NI_NUMERICHOST;
207  break;
208 
209  case AF_INET6:
210  switch (a6->sin6_addr.s6_addr[0])
211  {
212  case 0x00:
213  if (IN6_IS_ADDR_V4MAPPED(&a6->sin6_addr))
214  ;
215  else if (IN6_IS_ADDR_LOOPBACK(&a6->sin6_addr))
216  ;
217  else
218  flags |= NI_NUMERICHOST;
219  break;
220  default:
221  if (IN6_IS_ADDR_LINKLOCAL(&a6->sin6_addr))
222  flags |= NI_NUMERICHOST;
223  else if (IN6_IS_ADDR_MULTICAST(&a6->sin6_addr))
224  flags |= NI_NUMERICHOST;
225  break;
226  }
227  break;
228  }
229  if (!host || hostlen == 0)
230  {
231  /* do nothing in this case.
232  * in case you are wondering if "&&" is more correct than
233  * "||" here: RFC2553 says that host == NULL OR hostlen == 0
234  * means that the caller does not want the result.
235  */
236  }
237  else if (flags & NI_NUMERICHOST)
238  {
239  /* NUMERICHOST and NAMEREQD conflicts with each other
240  */
241  if (flags & NI_NAMEREQD)
242  return GI_RESULT (ENI_NOHOSTNAME);
243 
244  if (inet_ntop (afd->a_af, addr, numaddr, sizeof(numaddr)) == NULL)
245  return GI_RESULT (ENI_SYSTEM);
246 
247  if ((int)strlen(numaddr) + 1 > hostlen)
248  return GI_RESULT (ENI_MEMORY);
249 
250  strcpy (host, numaddr);
251 
252  if (afd->a_af == AF_INET6 &&
253  (IN6_IS_ADDR_LINKLOCAL(addr) ||
254  IN6_IS_ADDR_MULTICAST(addr)) &&
255  ((struct sockaddr_in6*)sa)->sin6_scope_id)
256  {
257 #if !defined(ALWAYS_WITHSCOPE)
258  if (flags & NI_WITHSCOPEID)
259 #endif
260  {
261  char *ep = strchr (host, '\0');
262  int id = ((struct sockaddr_in6*)sa)->sin6_scope_id;
263  int scope = __scope_id_to_ascii (id); /* '1' ... N */
264 
265  *ep++ = SCOPE_DELIMITER;
266  *ep++ = scope ? scope : '?';
267  *ep = '\0';
268  }
269  }
270  }
271  else
272  {
273  hp = gethostbyaddr (addr, afd->a_addrlen, afd->a_af);
274  if (hp)
275  {
276  if (flags & NI_NOFQDN)
277  {
278  p = strchr (hp->h_name, '.');
279  if (p)
280  *p = '\0';
281  }
282  if ((int)strlen(hp->h_name) + 1 > hostlen)
283  return GI_RESULT (ENI_MEMORY);
284  strcpy (host, hp->h_name);
285  }
286  else
287  {
288  if (flags & NI_NAMEREQD)
289  return GI_RESULT (ENI_NOHOSTNAME);
290 
291  if (inet_ntop (afd->a_af, addr, numaddr, sizeof(numaddr)) == NULL)
292  return GI_RESULT (ENI_NOHOSTNAME);
293 
294  if ((int)strlen(numaddr) + 1 > hostlen)
295  return GI_RESULT (ENI_MEMORY);
296 
297  strcpy (host, numaddr);
298  }
299  }
300  ARGSUSED (a4);
301  return GI_RESULT (NI_SUCCESS);
302 }
303 
304 
305 #if defined(TEST_PROG)
306 
307 #undef ni_flags /* <netinet/icmp6.> */
308 
309 static int ni_flags = NI_NAMEREQD; // NI_NUMERICHOST
310 
311 static int ip4_resolve (const char *name)
312 {
313  struct sockaddr_in a4;
314  char buf[40];
315  int rc;
316 
317  printf ("getnameinfo(): ");
318  fflush (stdout);
319 
320  a4.sin_family = AF_INET;
321  inet_pton (AF_INET, "203.178.141.194", &a4.sin_addr);
322  rc = getnameinfo ((const struct sockaddr*)&a4, sizeof(a4),
323  buf, sizeof(buf), NULL, 0, ni_flags);
324  if (rc)
325  perror (NULL);
326  else puts (buf);
327  return (rc);
328 }
329 
330 static int ip6_resolve (const char *name)
331 {
332  struct sockaddr_in6 a6;
333  char buf[40];
334  int rc;
335 
336  printf ("getnameinfo(): ");
337  fflush (stdout);
338 
339  a6.sin6_family = AF_INET6; /* www.kame.net */
340  inet_pton (AF_INET6, "2001:200:DFF:FFF1:216:3EFF:FEB1:44D7", &a6.sin6_addr);
341  rc = getnameinfo ((const struct sockaddr*)&a6, sizeof(a6),
342  buf, sizeof(buf), NULL, 0, ni_flags);
343  if (rc)
344  puts (hstrerror(h_errno));
345  else puts (buf);
346  return (rc);
347 }
348 
349 int main (int argc, char **argv)
350 {
351  int af = -1;
352 
353  if (argc < 2)
354  goto usage;
355 
356  dbug_init();
357  sock_init();
358 
359  if (!stricmp(argv[1],"AF_INET"))
360  af = AF_INET;
361 
362  else if (!stricmp(argv[1],"AF_INET6"))
363  af = AF_INET6;
364 
365  if (af == AF_INET6)
366  return ip6_resolve ("www.kame.net");
367 
368  if (af == AF_INET)
369  return ip4_resolve ("www.kame.net");
370 
371 usage:
372  printf ("Usage: <AF_INET | AF_INET6>");
373  return (1);
374 }
375 #endif /* TEST_PROG */
376 #endif /* USE_BSD_API && USE_IP6 */
377 
Definition: netdb.h:122
const char *W32_CALL inet_ntop(int af, const void *src, char *dst, size_t size)
Convert a network format address to presentation format.
Definition: presaddr.c:40
Definition: netdb.h:102
static void afd_list_init(BOOL ip6_prio)
Initialise afd_list[].
Definition: get_ai.c:273
Definition: in.h:153
Definition: in.h:146
int W32_CALL inet_pton(int af, const char *src, void *dst)
Convert from presentation format (which usually means ASCII printable) to network format (which is us...
Definition: presaddr.c:66
Definition: get_ai.c:67
const char * _inet6_ntoa(const void *ip)
Convert an IPv6-address 'ip' into a string.
Definition: netaddr.c:401
int main(int argc, char **argv)
Definition: echo.c:223