Watt-32 tcp/ip  2.2 dev-rel.10
get_ip.c
Go to the documentation of this file.
1 
6 /*
7  * Copyright (C) 1999-2001 Internet Software Consortium.
8  *
9  * Permission to use, copy, modify, and distribute this software for any
10  * purpose with or without fee is hereby granted, provided that the above
11  * copyright notice and this permission notice appear in all copies.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
14  * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
16  * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
17  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
18  * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
19  * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
20  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21  */
22 
23 /* $Id: getipnode.c,v 1.30 2001/07/18 02:37:08 mayer Exp $ */
24 
25 /* Originally from ISC's BIND 9.21; lightweigth resolver library (lwres).
26  * Rewritten an simplified for Watt-32 by <gvanem@yahoo.no> Nov-2003.
27  */
28 
29 #include "socket.h"
30 #include "get_xby.h"
31 #include "pcdns.h"
32 
33 #if defined(USE_BSD_API)
34 
35 static struct hostent *copyandmerge (const struct hostent *he1,
36  const struct hostent *he2,
37  int af, int *err);
38 
39 static __inline void scan_interface (BOOL *have_v4, BOOL *have_v6)
40 {
41  if (have_v4)
42  *have_v4 = TRUE;
43 
44  if (have_v6)
45 #if defined(USE_IPV6)
46  *have_v6 = dns_do_ipv6;
47 #else
48  *have_v6 = FALSE;
49 #endif
50 }
51 
52 /*
53  * AI_V4MAPPED + AF_INET6
54  * If no IPv6 address then a query for IPv4 and map returned values.
55  *
56  * AI_ALL + AI_V4MAPPED + AF_INET6
57  * Return IPv6 and IPv4 mapped.
58  *
59  * AI_ADDRCONFIG
60  * Only return IPv6 / IPv4 address if there is an interface of that
61  * type active.
62  */
63 struct hostent * W32_CALL
64 getipnodebyname (const char *name, int af, int flags, int *error)
65 {
66  struct hostent *he1 = NULL;
67  struct hostent *he2 = NULL;
68  struct in_addr in4;
69  struct in6_addr in6;
70  BOOL have_v4 = TRUE, have_v6 = TRUE;
71  BOOL v4 = FALSE, v6 = FALSE;
72  int tmp_err;
73 
74  SOCK_DEBUGF (("\ngetipnodebyname: %s ", name));
75 
76 #if !defined(USE_IPV6)
77  if (af == AF_INET6)
78  {
79  *error = HOST_NOT_FOUND;
80  return (NULL);
81  }
82 #endif
83 
84  /* If we care about active interfaces then check.
85  */
86  if (flags & AI_ADDRCONFIG)
87  scan_interface (&have_v4, &have_v6);
88 
89  /* Check for literal address.
90  */
91  v4 = inet_pton (AF_INET, name, &in4);
92  if (!v4)
93  v6 = inet_pton (AF_INET6, name, &in6);
94 
95  /* Impossible combination?
96  */
97  if ((af == AF_INET6 && !(flags & AI_V4MAPPED) && v4) ||
98  (af == AF_INET && v6) ||
99  (!have_v4 && v4) ||
100  (!have_v6 && v6) ||
101  (!have_v4 && af == AF_INET) ||
102  ((!have_v6 && af == AF_INET6) && ((flags & AI_V4MAPPED) && have_v4)) ||
103  !(flags & AI_V4MAPPED))
104  {
105  *error = HOST_NOT_FOUND;
106  return (NULL);
107  }
108 
109  /* Literal address?
110  */
111  if (v4 || v6)
112  {
113  struct hostent he;
114  char *addr_list[2];
115  char *aliases[1];
116 
117  he.h_name = (char*) name;
118  he.h_addr_list = addr_list;
119  he.h_addr_list[0] = (v4 ? (char*)&in4 : (char*)&in6);
120  he.h_addr_list[1] = NULL;
121  he.h_aliases = aliases;
122  he.h_aliases[0] = NULL;
123  he.h_length = (v4 ? INADDRSZ : IN6ADDRSZ);
124  he.h_addrtype = (v4 ? AF_INET : AF_INET6);
125  return copyandmerge (&he, NULL, af, error);
126  }
127 
128  tmp_err = NO_RECOVERY;
129  if (have_v6 && af == AF_INET6)
130  {
131 #if defined(USE_IPV6)
132  he1 = gethostbyname6 (name);
133 #else
134  he1 = NULL;
135 #endif
136  if (!he1)
137  tmp_err = HOST_NOT_FOUND;
138  }
139 
140  if (have_v4 &&
141  (af == AF_INET ||
142  (af == AF_INET6 &&
143  (flags & AI_V4MAPPED) && (!he1 || (flags & AI_ALL)))))
144  {
145  SOCK_ENTER_SCOPE();
146  he2 = gethostbyname (name);
147  SOCK_LEAVE_SCOPE();
148  if (!he2 || !he1)
149  {
150  *error = HOST_NOT_FOUND;
151  return (NULL);
152  }
153  }
154  else
155  *error = tmp_err;
156 
157  return copyandmerge (he1, he2, af, error);
158 }
159 
160 struct hostent * W32_CALL
161 getipnodebyaddr (const void *src, size_t len, int af, int *error)
162 {
163  struct hostent *he1, *he2 = NULL;
164  const BYTE *cp = (const BYTE*) src;
165 
166  SOCK_DEBUGF (("\ngetipnodebyaddr: "));
167 
168  if (!src)
169  {
170  *error = NO_RECOVERY;
171  return (NULL);
172  }
173 
174  switch (af)
175  {
176  case AF_INET:
177  if (len < INADDRSZ)
178  {
179  *error = NO_RECOVERY;
180  return (NULL);
181  }
182  break;
183 #if defined(USE_IPV6)
184  case AF_INET6:
185  if (len < IN6ADDRSZ)
186  {
187  *error = NO_RECOVERY;
188  return (NULL);
189  }
190  break;
191 #endif
192  default:
193  *error = NO_RECOVERY;
194  return (NULL);
195  }
196 
197  /* Look up IPv4 and IPv4 mapped/compatible addresses.
198  */
199  if ((af == AF_INET6 && IN6_IS_ADDR_V4COMPAT(cp)) ||
200  (af == AF_INET6 && IN6_IS_ADDR_V4MAPPED(cp)) ||
201  (af == AF_INET))
202  {
203  if (af == AF_INET6)
204  cp += 12;
205 
206  SOCK_ENTER_SCOPE();
207  he1 = gethostbyaddr ((const char*)cp, 4, AF_INET);
208  SOCK_LEAVE_SCOPE();
209 
210  if (af == AF_INET)
211  goto ret_copy;
212 
213 #if defined(USE_IPV6)
214  /* Convert from AF_INET to AF_INET6.
215  */
216  he2 = copyandmerge (he1, NULL, af, error);
217  if (he2)
218  {
219  memcpy (he2->h_addr, src, len); /* Restore original address */
220  SOCK_DEBUGF (("%s", af == AF_INET ?
221  inet_ntoa(*(struct in_addr*)&he2->h_addr) :
222  _inet6_ntoa(he2->h_addr)));
223  }
224 #endif
225  return (he2);
226  }
227 
228  he1 = gethostbyaddr (src, len, AF_INET6); /* Lookup IPv6 address */
229 
230 ret_copy:
231  if (!he1)
232  {
233  *error = HOST_NOT_FOUND;
234  return (NULL);
235  }
236  return copyandmerge (he1, NULL, af, error);
237 }
238 
239 void W32_CALL freehostent (struct hostent *he)
240 {
241  char *p;
242 
243  SOCK_DEBUGF (("\nfreehostent: %s ", he->h_name));
244 
245  if (!he->h_name) /* possible double freeing */
246  return;
247 
248  free (he->h_name);
249  he->h_name = NULL;
250 
251  for (p = he->h_addr_list[0]; p; p++)
252  free (p);
253 
254  for (p = he->h_aliases[0]; p; p++)
255  free (p);
256 
257  free (he->h_aliases);
258  free (he->h_addr_list);
259  free (he);
260 }
261 
262 static struct hostent *copyandmerge (const struct hostent *he1,
263  const struct hostent *he2,
264  int af, int *error)
265 {
266  struct hostent *he = NULL;
267  int addresses = 1; /* NULL terminator */
268  int names = 1; /* NULL terminator */
269  char **cpp, **npp;
270 
271 #if !defined(USE_IPV6)
272  BYTE in6addr_mapped[12];
273 
274  WATT_ASSERT (af != AF_INET6);
275 #endif
276 
277  /* Work out array sizes.
278  */
279  if (he1)
280  {
281  cpp = he1->h_addr_list;
282  while (*cpp)
283  {
284  addresses++;
285  cpp++;
286  }
287  cpp = he1->h_aliases;
288  while (*cpp)
289  {
290  names++;
291  cpp++;
292  }
293  }
294 
295  if (he2)
296  {
297  cpp = he2->h_addr_list;
298  while (*cpp)
299  {
300  addresses++;
301  cpp++;
302  }
303  if (!he1)
304  {
305  cpp = he2->h_aliases;
306  while (*cpp)
307  {
308  names++;
309  cpp++;
310  }
311  }
312  }
313 
314  if (addresses == 1)
315  {
316  *error = NO_ADDRESS;
317  return (NULL);
318  }
319 
320  he = malloc (sizeof(*he));
321  if (!he)
322  {
323  *error = NO_RECOVERY;
324  return (NULL);
325  }
326 
327  he->h_addr_list = calloc (addresses * sizeof(char*), 1);
328  if (!he->h_addr_list)
329  goto cleanup0;
330 
331  /* Copy addresses.
332  */
333  npp = he->h_addr_list;
334  if (he1)
335  {
336  cpp = he1->h_addr_list;
337  while (*cpp)
338  {
339  *npp = malloc (af == AF_INET ? INADDRSZ : IN6ADDRSZ);
340  if (!*npp)
341  goto cleanup1;
342 
343  /* Convert to mapped if required.
344  */
345  if (af == AF_INET6 && he1->h_addrtype == AF_INET)
346  {
347  memcpy (*npp, in6addr_mapped, sizeof(in6addr_mapped));
348  memcpy (*npp + sizeof(in6addr_mapped), *cpp, INADDRSZ);
349  }
350  else
351  memcpy (*npp, *cpp, af == AF_INET ? INADDRSZ : IN6ADDRSZ);
352  cpp++;
353  npp++;
354  }
355  }
356 
357  if (he2)
358  {
359  cpp = he2->h_addr_list;
360  while (*cpp)
361  {
362  *npp = malloc (af == AF_INET ? INADDRSZ : IN6ADDRSZ);
363  if (!*npp)
364  goto cleanup1;
365 
366  /* Convert to mapped if required.
367  */
368  if (af == AF_INET6 && he2->h_addrtype == AF_INET)
369  {
370  memcpy (*npp, in6addr_mapped, sizeof(in6addr_mapped));
371  memcpy (*npp + sizeof(in6addr_mapped), *cpp, INADDRSZ);
372  }
373  else
374  memcpy (*npp, *cpp, af == AF_INET ? INADDRSZ : IN6ADDRSZ);
375  cpp++;
376  npp++;
377  }
378  }
379 
380  he->h_aliases = calloc (names * sizeof(char*), 1);
381  if (!he->h_aliases)
382  goto cleanup1;
383 
384  /* Copy aliases.
385  */
386  npp = he->h_aliases;
387  cpp = (he1 ? he1->h_aliases : he2->h_aliases);
388  while (*cpp)
389  {
390  *npp = strdup (*cpp);
391  if (!*npp)
392  goto cleanup2;
393  npp++;
394  cpp++;
395  }
396 
397  /* Copy hostname.
398  */
399  if (he1)
400  he->h_name = strdup (he1->h_name);
401  else he->h_name = strdup (he2->h_name);
402 
403  if (!he->h_name)
404  goto cleanup2;
405 
406  he->h_addrtype = af;
407  he->h_length = (af == AF_INET ? INADDRSZ : IN6ADDRSZ);
408  return (he);
409 
410 cleanup2:
411  for (cpp = he->h_aliases; *cpp; *cpp++ = NULL)
412  free (*cpp);
413  free (he->h_aliases);
414 
415 cleanup1:
416  for (cpp = he->h_addr_list; *cpp; *cpp++ = NULL)
417  free (*cpp);
418  free (he->h_addr_list);
419 
420 cleanup0:
421  free (he);
422  *error = NO_RECOVERY;
423  return (NULL);
424 }
425 #endif /* USE_BSD_API */
Definition: netdb.h:102
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
const char * _inet6_ntoa(const void *ip)
Convert an IPv6-address 'ip' into a string.
Definition: netaddr.c:401