]>
git.ipfire.org Git - people/ms/strongswan.git/blob - lib/liblwres/getipnode.c
2 * Copyright (C) 1999-2001 Internet Software Consortium.
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
9 * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
10 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
11 * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
13 * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
14 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
15 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 /* $Id: getipnode.c,v 1.1 2004/03/15 20:35:25 as Exp $ */
26 #include <lwres/lwres.h>
27 #include <lwres/net.h>
28 #include <lwres/netdb.h> /* XXX #include <netdb.h> */
39 #ifdef LWRES_PLATFORM_NEEDIN6ADDRANY
40 LIBLWRES_EXTERNAL_DATA
const struct in6_addr in6addr_any
= IN6ADDR_ANY_INIT
;
43 #ifndef IN6_IS_ADDR_V4COMPAT
44 static const unsigned char in6addr_compat
[12] = {
45 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
47 #define IN6_IS_ADDR_V4COMPAT(x) (!memcmp((x)->s6_addr, in6addr_compat, 12) && \
48 ((x)->s6_addr[12] != 0 || \
49 (x)->s6_addr[13] != 0 || \
50 (x)->s6_addr[14] != 0 || \
51 ((x)->s6_addr[15] != 0 && \
52 (x)->s6_addr[15] != 1)))
54 #ifndef IN6_IS_ADDR_V4MAPPED
55 #define IN6_IS_ADDR_V4MAPPED(x) (!memcmp((x)->s6_addr, in6addr_mapped, 12))
58 static const unsigned char in6addr_mapped
[12] = {
59 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff
63 *** Forward declarations.
67 scan_interfaces(int *, int *);
69 static struct hostent
*
70 copyandmerge(struct hostent
*, struct hostent
*, int, int *);
72 static struct hostent
*
73 hostfromaddr(lwres_gnbaresponse_t
*addr
, int af
, const void *src
);
75 static struct hostent
*
76 hostfromname(lwres_gabnresponse_t
*name
, int af
);
83 * AI_V4MAPPED + AF_INET6
84 * If no IPv6 address then a query for IPv4 and map returned values.
86 * AI_ALL + AI_V4MAPPED + AF_INET6
87 * Return IPv6 and IPv4 mapped.
90 * Only return IPv6 / IPv4 address if there is an interface of that
95 lwres_getipnodebyname(const char *name
, int af
, int flags
, int *error_num
) {
96 int have_v4
= 1, have_v6
= 1;
99 struct hostent he
, *he1
= NULL
, *he2
= NULL
, *he3
= NULL
;
102 lwres_context_t
*lwrctx
= NULL
;
103 lwres_gabnresponse_t
*by
= NULL
;
107 * If we care about active interfaces then check.
109 if ((flags
& AI_ADDRCONFIG
) != 0)
110 if (scan_interfaces(&have_v4
, &have_v6
) == -1) {
111 *error_num
= NO_RECOVERY
;
115 /* Check for literal address. */
116 if ((v4
= lwres_net_pton(AF_INET
, name
, &in4
)) != 1)
117 v6
= lwres_net_pton(AF_INET6
, name
, &in6
);
120 * Impossible combination?
122 if ((af
== AF_INET6
&& (flags
& AI_V4MAPPED
) == 0 && v4
== 1) ||
123 (af
== AF_INET
&& v6
== 1) ||
124 (have_v4
== 0 && v4
== 1) ||
125 (have_v6
== 0 && v6
== 1) ||
126 (have_v4
== 0 && af
== AF_INET
) ||
127 (have_v6
== 0 && af
== AF_INET6
&&
128 (((flags
& AI_V4MAPPED
) != 0 && have_v4
) ||
129 (flags
& AI_V4MAPPED
) == 0))) {
130 *error_num
= HOST_NOT_FOUND
;
137 if (v4
== 1 || v6
== 1) {
141 const char *const_name
;
146 he
.h_name
= u
.deconst_name
;
147 he
.h_addr_list
= addr_list
;
148 he
.h_addr_list
[0] = (v4
== 1) ? (char *)&in4
: (char *)&in6
;
149 he
.h_addr_list
[1] = NULL
;
150 he
.h_aliases
= aliases
;
151 he
.h_aliases
[0] = NULL
;
152 he
.h_length
= (v4
== 1) ? INADDRSZ
: IN6ADDRSZ
;
153 he
.h_addrtype
= (v4
== 1) ? AF_INET
: AF_INET6
;
154 return (copyandmerge(&he
, NULL
, af
, error_num
));
157 n
= lwres_context_create(&lwrctx
, NULL
, NULL
, NULL
, 0);
159 *error_num
= NO_RECOVERY
;
162 (void) lwres_conf_parse(lwrctx
, lwres_resolv_conf
);
163 tmp_err
= NO_RECOVERY
;
164 if (have_v6
&& af
== AF_INET6
) {
166 n
= lwres_getaddrsbyname(lwrctx
, name
, LWRES_ADDRTYPE_V6
, &by
);
168 he1
= hostfromname(by
, AF_INET6
);
169 lwres_gabnresponse_free(lwrctx
, &by
);
171 *error_num
= NO_RECOVERY
;
175 tmp_err
= HOST_NOT_FOUND
;
181 (af
== AF_INET6
&& (flags
& AI_V4MAPPED
) != 0 &&
182 (he1
== NULL
|| (flags
& AI_ALL
) != 0)))) {
183 n
= lwres_getaddrsbyname(lwrctx
, name
, LWRES_ADDRTYPE_V4
, &by
);
185 he2
= hostfromname(by
, AF_INET
);
186 lwres_gabnresponse_free(lwrctx
, &by
);
188 *error_num
= NO_RECOVERY
;
191 } else if (he1
== NULL
) {
192 if (n
== LWRES_R_NOTFOUND
)
193 *error_num
= HOST_NOT_FOUND
;
195 *error_num
= NO_RECOVERY
;
199 *error_num
= tmp_err
;
201 he3
= copyandmerge(he1
, he2
, af
, error_num
);
205 lwres_freehostent(he1
);
207 lwres_freehostent(he2
);
208 if (lwrctx
!= NULL
) {
209 lwres_conf_clear(lwrctx
);
210 lwres_context_destroy(&lwrctx
);
216 lwres_getipnodebyaddr(const void *src
, size_t len
, int af
, int *error_num
) {
217 struct hostent
*he1
, *he2
;
218 lwres_context_t
*lwrctx
= NULL
;
219 lwres_gnbaresponse_t
*by
= NULL
;
223 struct in6_addr
*in6
;
230 *error_num
= NO_RECOVERY
;
236 if (len
!= INADDRSZ
) {
237 *error_num
= NO_RECOVERY
;
242 if (len
!= IN6ADDRSZ
) {
243 *error_num
= NO_RECOVERY
;
248 *error_num
= NO_RECOVERY
;
253 * The de-"const"-ing game is done because at least one
254 * vendor's system (RedHat 6.0) defines the IN6_IS_ADDR_*
255 * macros in such a way that they discard the const with
256 * internal casting, and gcc ends up complaining. Rather
257 * than replacing their own (possibly optimized) definitions
258 * with our own, cleanly discarding the const is the easiest
264 * Look up IPv4 and IPv4 mapped/compatible addresses.
266 if ((af
== AF_INET6
&& IN6_IS_ADDR_V4COMPAT(u
.in6
)) ||
267 (af
== AF_INET6
&& IN6_IS_ADDR_V4MAPPED(u
.in6
)) ||
269 const unsigned char *cp
= src
;
273 n
= lwres_context_create(&lwrctx
, NULL
, NULL
, NULL
, 0);
274 if (n
== LWRES_R_SUCCESS
)
275 (void) lwres_conf_parse(lwrctx
, lwres_resolv_conf
);
276 if (n
== LWRES_R_SUCCESS
)
277 n
= lwres_getnamebyaddr(lwrctx
, LWRES_ADDRTYPE_V4
,
279 if (n
!= LWRES_R_SUCCESS
) {
280 lwres_conf_clear(lwrctx
);
281 lwres_context_destroy(&lwrctx
);
282 if (n
== LWRES_R_NOTFOUND
)
283 *error_num
= HOST_NOT_FOUND
;
285 *error_num
= NO_RECOVERY
;
288 he1
= hostfromaddr(by
, AF_INET
, cp
);
289 lwres_gnbaresponse_free(lwrctx
, &by
);
290 lwres_conf_clear(lwrctx
);
291 lwres_context_destroy(&lwrctx
);
296 * Convert from AF_INET to AF_INET6.
298 he2
= copyandmerge(he1
, NULL
, af
, error_num
);
299 lwres_freehostent(he1
);
303 * Restore original address.
305 memcpy(he2
->h_addr
, src
, len
);
310 * Lookup IPv6 address.
312 if (memcmp(src
, &in6addr_any
, IN6ADDRSZ
) == 0) {
313 *error_num
= HOST_NOT_FOUND
;
317 n
= lwres_context_create(&lwrctx
, NULL
, NULL
, NULL
, 0);
318 if (n
== LWRES_R_SUCCESS
)
319 (void) lwres_conf_parse(lwrctx
, lwres_resolv_conf
);
320 if (n
== LWRES_R_SUCCESS
)
321 n
= lwres_getnamebyaddr(lwrctx
, LWRES_ADDRTYPE_V6
, IN6ADDRSZ
,
324 *error_num
= HOST_NOT_FOUND
;
327 he1
= hostfromaddr(by
, AF_INET6
, src
);
328 lwres_gnbaresponse_free(lwrctx
, &by
);
330 *error_num
= NO_RECOVERY
;
331 lwres_context_destroy(&lwrctx
);
336 lwres_freehostent(struct hostent
*he
) {
343 cpp
= he
->h_addr_list
;
344 while (*cpp
!= NULL
) {
352 while (*cpp
!= NULL
) {
359 free(he
->h_addr_list
);
368 * Scan the interface table and set have_v4 and have_v6 depending
369 * upon whether there are IPv4 and IPv6 interface addresses.
377 scan_interfaces(int *have_v4
, int *have_v6
) {
379 *have_v4
= *have_v6
= 1;
386 char *buf
= NULL
, *cp
, *cplim
;
387 static int bufsiz
= 4095;
391 * Set to zero. Used as loop terminators below.
393 *have_v4
= *have_v6
= 0;
396 * Get interface list from system.
398 if ((s
= socket(AF_INET
, SOCK_DGRAM
, 0)) == -1)
402 * Grow buffer until large enough to contain all interface
406 buf
= malloc(bufsiz
);
409 ifc
.ifc_len
= bufsiz
;
411 #ifdef IRIX_EMUL_IOCTL_SIOCGIFCONF
413 * This is a fix for IRIX OS in which the call to ioctl with
414 * the flag SIOCGIFCONF may not return an entry for all the
415 * interfaces like most flavors of Unix.
417 if (emul_ioctl(&ifc
) >= 0)
420 if ((n
= ioctl(s
, SIOCGIFCONF
, (char *)&ifc
)) != -1) {
422 * Some OS's just return what will fit rather
423 * than set EINVAL if the buffer is too small
424 * to fit all the interfaces in. If
425 * ifc.ifc_len is too near to the end of the
426 * buffer we will grow it just in case and
429 if (ifc
.ifc_len
+ 2 * sizeof(ifreq
) < bufsiz
)
433 if ((n
== -1) && errno
!= EINVAL
)
436 if (bufsiz
> 1000000)
444 * Parse system's interface list.
446 cplim
= buf
+ ifc
.ifc_len
; /* skip over if's with big ifr_addr's */
448 (*have_v4
== 0 || *have_v6
== 0) && cp
< cplim
;
450 memcpy(&ifreq
, cp
, sizeof ifreq
);
451 #ifdef LWRES_PLATFORM_HAVESALEN
452 #ifdef FIX_ZERO_SA_LEN
453 if (ifreq
.ifr_addr
.sa_len
== 0)
454 ifreq
.ifr_addr
.sa_len
= IN6ADDRSZ
;
456 #ifdef HAVE_MINIMUM_IFREQ
457 cpsize
= sizeof ifreq
;
458 if (ifreq
.ifr_addr
.sa_len
> sizeof (struct sockaddr
))
459 cpsize
+= (int)ifreq
.ifr_addr
.sa_len
-
460 (int)(sizeof(struct sockaddr
));
462 cpsize
= sizeof ifreq
.ifr_name
+ ifreq
.ifr_addr
.sa_len
;
463 #endif /* HAVE_MINIMUM_IFREQ */
464 #elif defined SIOCGIFCONF_ADDR
465 cpsize
= sizeof ifreq
;
467 cpsize
= sizeof ifreq
.ifr_name
;
468 /* XXX maybe this should be a hard error? */
469 if (ioctl(s
, SIOCGIFADDR
, (char *)&ifreq
) < 0)
471 #endif /* LWRES_PLATFORM_HAVESALEN */
472 switch (ifreq
.ifr_addr
.sa_family
) {
476 &((struct sockaddr_in
*)
477 &ifreq
.ifr_addr
)->sin_addr
,
479 if (in4
.s_addr
== INADDR_ANY
)
481 n
= ioctl(s
, SIOCGIFFLAGS
, (char *)&ifreq
);
484 if ((ifreq
.ifr_flags
& IFF_UP
) == 0)
492 &((struct sockaddr_in6
*)
493 &ifreq
.ifr_addr
)->sin6_addr
,
495 if (memcmp(&in6
, &in6addr_any
,
498 n
= ioctl(s
, SIOCGIFFLAGS
, (char *)&ifreq
);
501 if ((ifreq
.ifr_flags
& IFF_UP
) == 0)
521 static struct hostent
*
522 copyandmerge(struct hostent
*he1
, struct hostent
*he2
, int af
, int *error_num
)
524 struct hostent
*he
= NULL
;
525 int addresses
= 1; /* NULL terminator */
526 int names
= 1; /* NULL terminator */
531 * Work out array sizes.
534 cpp
= he1
->h_addr_list
;
535 while (*cpp
!= NULL
) {
539 cpp
= he1
->h_aliases
;
540 while (*cpp
!= NULL
) {
547 cpp
= he2
->h_addr_list
;
548 while (*cpp
!= NULL
) {
553 cpp
= he2
->h_aliases
;
554 while (*cpp
!= NULL
) {
561 if (addresses
== 1) {
562 *error_num
= NO_ADDRESS
;
566 he
= malloc(sizeof *he
);
570 he
->h_addr_list
= malloc(sizeof(char *) * (addresses
));
571 if (he
->h_addr_list
== NULL
)
573 memset(he
->h_addr_list
, 0, sizeof(char *) * (addresses
));
578 npp
= he
->h_addr_list
;
580 cpp
= he1
->h_addr_list
;
581 while (*cpp
!= NULL
) {
582 *npp
= malloc((af
== AF_INET
) ? INADDRSZ
: IN6ADDRSZ
);
586 * Convert to mapped if required.
588 if (af
== AF_INET6
&& he1
->h_addrtype
== AF_INET
) {
589 memcpy(*npp
, in6addr_mapped
,
590 sizeof in6addr_mapped
);
591 memcpy(*npp
+ sizeof in6addr_mapped
, *cpp
,
595 (af
== AF_INET
) ? INADDRSZ
: IN6ADDRSZ
);
603 cpp
= he2
->h_addr_list
;
604 while (*cpp
!= NULL
) {
605 *npp
= malloc((af
== AF_INET
) ? INADDRSZ
: IN6ADDRSZ
);
609 * Convert to mapped if required.
611 if (af
== AF_INET6
&& he2
->h_addrtype
== AF_INET
) {
612 memcpy(*npp
, in6addr_mapped
,
613 sizeof in6addr_mapped
);
614 memcpy(*npp
+ sizeof in6addr_mapped
, *cpp
,
618 (af
== AF_INET
) ? INADDRSZ
: IN6ADDRSZ
);
625 he
->h_aliases
= malloc(sizeof(char *) * (names
));
626 if (he
->h_aliases
== NULL
)
628 memset(he
->h_aliases
, 0, sizeof(char *) * (names
));
634 cpp
= (he1
!= NULL
) ? he1
->h_aliases
: he2
->h_aliases
;
635 while (*cpp
!= NULL
) {
636 len
= strlen (*cpp
) + 1;
648 he
->h_name
= malloc(strlen((he1
!= NULL
) ?
649 he1
->h_name
: he2
->h_name
) + 1);
650 if (he
->h_name
== NULL
)
652 strcpy(he
->h_name
, (he1
!= NULL
) ? he1
->h_name
: he2
->h_name
);
655 * Set address type and length.
658 he
->h_length
= (af
== AF_INET
) ? INADDRSZ
: IN6ADDRSZ
;
663 while (*cpp
!= NULL
) {
670 cpp
= he
->h_addr_list
;
671 while (*cpp
!= NULL
) {
676 free(he
->h_addr_list
);
682 *error_num
= NO_RECOVERY
;
686 static struct hostent
*
687 hostfromaddr(lwres_gnbaresponse_t
*addr
, int af
, const void *src
) {
691 he
= malloc(sizeof *he
);
694 memset(he
, 0, sizeof(*he
));
697 * Set family and length.
702 he
->h_length
= INADDRSZ
;
705 he
->h_length
= IN6ADDRSZ
;
714 he
->h_name
= strdup(addr
->realname
);
715 if (he
->h_name
== NULL
)
721 he
->h_aliases
= malloc(sizeof(char *) * (addr
->naliases
+ 1));
722 if (he
->h_aliases
== NULL
)
724 for (i
= 0 ; i
< addr
->naliases
; i
++) {
725 he
->h_aliases
[i
] = strdup(addr
->aliases
[i
]);
726 if (he
->h_aliases
[i
] == NULL
)
729 he
->h_aliases
[i
] = NULL
;
734 he
->h_addr_list
= malloc(sizeof(char *) * 2);
735 if (he
->h_addr_list
== NULL
)
737 he
->h_addr_list
[0] = malloc(he
->h_length
);
738 if (he
->h_addr_list
[0] == NULL
)
740 memcpy(he
->h_addr_list
[0], src
, he
->h_length
);
741 he
->h_addr_list
[1] = NULL
;
745 if (he
!= NULL
&& he
->h_addr_list
!= NULL
) {
746 for (i
= 0; he
->h_addr_list
[i
] != NULL
; i
++)
747 free(he
->h_addr_list
[i
]);
748 free(he
->h_addr_list
);
750 if (he
!= NULL
&& he
->h_aliases
!= NULL
) {
751 for (i
= 0; he
->h_aliases
[i
] != NULL
; i
++)
752 free(he
->h_aliases
[i
]);
755 if (he
!= NULL
&& he
->h_name
!= NULL
)
762 static struct hostent
*
763 hostfromname(lwres_gabnresponse_t
*name
, int af
) {
768 he
= malloc(sizeof *he
);
771 memset(he
, 0, sizeof(*he
));
774 * Set family and length.
779 he
->h_length
= INADDRSZ
;
782 he
->h_length
= IN6ADDRSZ
;
791 he
->h_name
= strdup(name
->realname
);
792 if (he
->h_name
== NULL
)
798 he
->h_aliases
= malloc(sizeof(char *) * (name
->naliases
+ 1));
799 for (i
= 0 ; i
< name
->naliases
; i
++) {
800 he
->h_aliases
[i
] = strdup(name
->aliases
[i
]);
801 if (he
->h_aliases
[i
] == NULL
)
804 he
->h_aliases
[i
] = NULL
;
809 he
->h_addr_list
= malloc(sizeof(char *) * (name
->naddrs
+ 1));
810 addr
= LWRES_LIST_HEAD(name
->addrs
);
812 while (addr
!= NULL
) {
813 he
->h_addr_list
[i
] = malloc(he
->h_length
);
814 if (he
->h_addr_list
[i
] == NULL
)
816 memcpy(he
->h_addr_list
[i
], addr
->address
, he
->h_length
);
817 addr
= LWRES_LIST_NEXT(addr
, link
);
820 he
->h_addr_list
[i
] = NULL
;
824 if (he
!= NULL
&& he
->h_addr_list
!= NULL
) {
825 for (i
= 0; he
->h_addr_list
[i
] != NULL
; i
++)
826 free(he
->h_addr_list
[i
]);
827 free(he
->h_addr_list
);
829 if (he
!= NULL
&& he
->h_aliases
!= NULL
) {
830 for (i
= 0; he
->h_aliases
[i
] != NULL
; i
++)
831 free(he
->h_aliases
[i
]);
834 if (he
!= NULL
&& he
->h_name
!= NULL
)