2 * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1999-2003 Internet Software Consortium.
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
18 /* $Id: getipnode.c,v 1.30.2.6 2004/03/09 06:12:33 marka 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) {
140 char mappedname
[sizeof("::ffff:123.123.123.123")];
142 const char *const_name
;
147 if (v4
== 1 && af
== AF_INET6
) {
148 strcpy(mappedname
, "::ffff:");
149 lwres_net_ntop(AF_INET
, (char *)&in4
,
150 mappedname
+ sizeof("::ffff:") - 1,
151 sizeof(mappedname
) - sizeof("::ffff:")
153 he
.h_name
= mappedname
;
155 he
.h_name
= u
.deconst_name
;
156 he
.h_addr_list
= addr_list
;
157 he
.h_addr_list
[0] = (v4
== 1) ? (char *)&in4
: (char *)&in6
;
158 he
.h_addr_list
[1] = NULL
;
159 he
.h_aliases
= aliases
;
160 he
.h_aliases
[0] = NULL
;
161 he
.h_length
= (v4
== 1) ? INADDRSZ
: IN6ADDRSZ
;
162 he
.h_addrtype
= (v4
== 1) ? AF_INET
: AF_INET6
;
163 return (copyandmerge(&he
, NULL
, af
, error_num
));
166 n
= lwres_context_create(&lwrctx
, NULL
, NULL
, NULL
, 0);
168 *error_num
= NO_RECOVERY
;
171 (void) lwres_conf_parse(lwrctx
, lwres_resolv_conf
);
172 tmp_err
= NO_RECOVERY
;
173 if (have_v6
&& af
== AF_INET6
) {
175 n
= lwres_getaddrsbyname(lwrctx
, name
, LWRES_ADDRTYPE_V6
, &by
);
177 he1
= hostfromname(by
, AF_INET6
);
178 lwres_gabnresponse_free(lwrctx
, &by
);
180 *error_num
= NO_RECOVERY
;
184 tmp_err
= HOST_NOT_FOUND
;
190 (af
== AF_INET6
&& (flags
& AI_V4MAPPED
) != 0 &&
191 (he1
== NULL
|| (flags
& AI_ALL
) != 0)))) {
192 n
= lwres_getaddrsbyname(lwrctx
, name
, LWRES_ADDRTYPE_V4
, &by
);
194 he2
= hostfromname(by
, AF_INET
);
195 lwres_gabnresponse_free(lwrctx
, &by
);
197 *error_num
= NO_RECOVERY
;
200 } else if (he1
== NULL
) {
201 if (n
== LWRES_R_NOTFOUND
)
202 *error_num
= HOST_NOT_FOUND
;
204 *error_num
= NO_RECOVERY
;
208 *error_num
= tmp_err
;
210 he3
= copyandmerge(he1
, he2
, af
, error_num
);
214 lwres_freehostent(he1
);
216 lwres_freehostent(he2
);
217 if (lwrctx
!= NULL
) {
218 lwres_conf_clear(lwrctx
);
219 lwres_context_destroy(&lwrctx
);
225 lwres_getipnodebyaddr(const void *src
, size_t len
, int af
, int *error_num
) {
226 struct hostent
*he1
, *he2
;
227 lwres_context_t
*lwrctx
= NULL
;
228 lwres_gnbaresponse_t
*by
= NULL
;
232 struct in6_addr
*in6
;
239 *error_num
= NO_RECOVERY
;
245 if (len
!= (unsigned int)INADDRSZ
) {
246 *error_num
= NO_RECOVERY
;
251 if (len
!= (unsigned int)IN6ADDRSZ
) {
252 *error_num
= NO_RECOVERY
;
257 *error_num
= NO_RECOVERY
;
262 * The de-"const"-ing game is done because at least one
263 * vendor's system (RedHat 6.0) defines the IN6_IS_ADDR_*
264 * macros in such a way that they discard the const with
265 * internal casting, and gcc ends up complaining. Rather
266 * than replacing their own (possibly optimized) definitions
267 * with our own, cleanly discarding the const is the easiest
273 * Look up IPv4 and IPv4 mapped/compatible addresses.
275 if ((af
== AF_INET6
&& IN6_IS_ADDR_V4COMPAT(u
.in6
)) ||
276 (af
== AF_INET6
&& IN6_IS_ADDR_V4MAPPED(u
.in6
)) ||
278 const unsigned char *cp
= src
;
282 n
= lwres_context_create(&lwrctx
, NULL
, NULL
, NULL
, 0);
283 if (n
== LWRES_R_SUCCESS
)
284 (void) lwres_conf_parse(lwrctx
, lwres_resolv_conf
);
285 if (n
== LWRES_R_SUCCESS
)
286 n
= lwres_getnamebyaddr(lwrctx
, LWRES_ADDRTYPE_V4
,
288 if (n
!= LWRES_R_SUCCESS
) {
289 lwres_conf_clear(lwrctx
);
290 lwres_context_destroy(&lwrctx
);
291 if (n
== LWRES_R_NOTFOUND
)
292 *error_num
= HOST_NOT_FOUND
;
294 *error_num
= NO_RECOVERY
;
297 he1
= hostfromaddr(by
, AF_INET
, cp
);
298 lwres_gnbaresponse_free(lwrctx
, &by
);
299 lwres_conf_clear(lwrctx
);
300 lwres_context_destroy(&lwrctx
);
305 * Convert from AF_INET to AF_INET6.
307 he2
= copyandmerge(he1
, NULL
, af
, error_num
);
308 lwres_freehostent(he1
);
312 * Restore original address.
314 memcpy(he2
->h_addr
, src
, len
);
319 * Lookup IPv6 address.
321 if (memcmp(src
, &in6addr_any
, IN6ADDRSZ
) == 0) {
322 *error_num
= HOST_NOT_FOUND
;
326 n
= lwres_context_create(&lwrctx
, NULL
, NULL
, NULL
, 0);
327 if (n
== LWRES_R_SUCCESS
)
328 (void) lwres_conf_parse(lwrctx
, lwres_resolv_conf
);
329 if (n
== LWRES_R_SUCCESS
)
330 n
= lwres_getnamebyaddr(lwrctx
, LWRES_ADDRTYPE_V6
, IN6ADDRSZ
,
333 *error_num
= HOST_NOT_FOUND
;
336 he1
= hostfromaddr(by
, AF_INET6
, src
);
337 lwres_gnbaresponse_free(lwrctx
, &by
);
339 *error_num
= NO_RECOVERY
;
340 lwres_context_destroy(&lwrctx
);
345 lwres_freehostent(struct hostent
*he
) {
352 cpp
= he
->h_addr_list
;
353 while (*cpp
!= NULL
) {
361 while (*cpp
!= NULL
) {
368 free(he
->h_addr_list
);
377 * Scan the interface table and set have_v4 and have_v6 depending
378 * upon whether there are IPv4 and IPv6 interface addresses.
386 scan_interfaces(int *have_v4
, int *have_v6
) {
388 *have_v4
= *have_v6
= 1;
395 char *buf
= NULL
, *cp
, *cplim
;
396 static int bufsiz
= 4095;
400 * Set to zero. Used as loop terminators below.
402 *have_v4
= *have_v6
= 0;
405 * Get interface list from system.
407 if ((s
= socket(AF_INET
, SOCK_DGRAM
, 0)) == -1)
411 * Grow buffer until large enough to contain all interface
415 buf
= malloc(bufsiz
);
418 ifc
.ifc_len
= bufsiz
;
420 #ifdef IRIX_EMUL_IOCTL_SIOCGIFCONF
422 * This is a fix for IRIX OS in which the call to ioctl with
423 * the flag SIOCGIFCONF may not return an entry for all the
424 * interfaces like most flavors of Unix.
426 if (emul_ioctl(&ifc
) >= 0)
429 if ((n
= ioctl(s
, SIOCGIFCONF
, (char *)&ifc
)) != -1) {
431 * Some OS's just return what will fit rather
432 * than set EINVAL if the buffer is too small
433 * to fit all the interfaces in. If
434 * ifc.ifc_len is too near to the end of the
435 * buffer we will grow it just in case and
438 if (ifc
.ifc_len
+ 2 * sizeof(ifreq
) < bufsiz
)
442 if ((n
== -1) && errno
!= EINVAL
)
445 if (bufsiz
> 1000000)
453 * Parse system's interface list.
455 cplim
= buf
+ ifc
.ifc_len
; /* skip over if's with big ifr_addr's */
457 (*have_v4
== 0 || *have_v6
== 0) && cp
< cplim
;
459 memcpy(&ifreq
, cp
, sizeof ifreq
);
460 #ifdef LWRES_PLATFORM_HAVESALEN
461 #ifdef FIX_ZERO_SA_LEN
462 if (ifreq
.ifr_addr
.sa_len
== 0)
463 ifreq
.ifr_addr
.sa_len
= IN6ADDRSZ
;
465 #ifdef HAVE_MINIMUM_IFREQ
466 cpsize
= sizeof ifreq
;
467 if (ifreq
.ifr_addr
.sa_len
> sizeof (struct sockaddr
))
468 cpsize
+= (int)ifreq
.ifr_addr
.sa_len
-
469 (int)(sizeof(struct sockaddr
));
471 cpsize
= sizeof ifreq
.ifr_name
+ ifreq
.ifr_addr
.sa_len
;
472 #endif /* HAVE_MINIMUM_IFREQ */
473 #elif defined SIOCGIFCONF_ADDR
474 cpsize
= sizeof ifreq
;
476 cpsize
= sizeof ifreq
.ifr_name
;
477 /* XXX maybe this should be a hard error? */
478 if (ioctl(s
, SIOCGIFADDR
, (char *)&ifreq
) < 0)
480 #endif /* LWRES_PLATFORM_HAVESALEN */
481 switch (ifreq
.ifr_addr
.sa_family
) {
485 &((struct sockaddr_in
*)
486 &ifreq
.ifr_addr
)->sin_addr
,
488 if (in4
.s_addr
== INADDR_ANY
)
490 n
= ioctl(s
, SIOCGIFFLAGS
, (char *)&ifreq
);
493 if ((ifreq
.ifr_flags
& IFF_UP
) == 0)
501 &((struct sockaddr_in6
*)
502 &ifreq
.ifr_addr
)->sin6_addr
,
504 if (memcmp(&in6
, &in6addr_any
,
507 n
= ioctl(s
, SIOCGIFFLAGS
, (char *)&ifreq
);
510 if ((ifreq
.ifr_flags
& IFF_UP
) == 0)
530 static struct hostent
*
531 copyandmerge(struct hostent
*he1
, struct hostent
*he2
, int af
, int *error_num
)
533 struct hostent
*he
= NULL
;
534 int addresses
= 1; /* NULL terminator */
535 int names
= 1; /* NULL terminator */
540 * Work out array sizes.
543 cpp
= he1
->h_addr_list
;
544 while (*cpp
!= NULL
) {
548 cpp
= he1
->h_aliases
;
549 while (*cpp
!= NULL
) {
556 cpp
= he2
->h_addr_list
;
557 while (*cpp
!= NULL
) {
562 cpp
= he2
->h_aliases
;
563 while (*cpp
!= NULL
) {
570 if (addresses
== 1) {
571 *error_num
= NO_ADDRESS
;
575 he
= malloc(sizeof *he
);
579 he
->h_addr_list
= malloc(sizeof(char *) * (addresses
));
580 if (he
->h_addr_list
== NULL
)
582 memset(he
->h_addr_list
, 0, sizeof(char *) * (addresses
));
587 npp
= he
->h_addr_list
;
589 cpp
= he1
->h_addr_list
;
590 while (*cpp
!= NULL
) {
591 *npp
= malloc((af
== AF_INET
) ? INADDRSZ
: IN6ADDRSZ
);
595 * Convert to mapped if required.
597 if (af
== AF_INET6
&& he1
->h_addrtype
== AF_INET
) {
598 memcpy(*npp
, in6addr_mapped
,
599 sizeof in6addr_mapped
);
600 memcpy(*npp
+ sizeof in6addr_mapped
, *cpp
,
604 (af
== AF_INET
) ? INADDRSZ
: IN6ADDRSZ
);
612 cpp
= he2
->h_addr_list
;
613 while (*cpp
!= NULL
) {
614 *npp
= malloc((af
== AF_INET
) ? INADDRSZ
: IN6ADDRSZ
);
618 * Convert to mapped if required.
620 if (af
== AF_INET6
&& he2
->h_addrtype
== AF_INET
) {
621 memcpy(*npp
, in6addr_mapped
,
622 sizeof in6addr_mapped
);
623 memcpy(*npp
+ sizeof in6addr_mapped
, *cpp
,
627 (af
== AF_INET
) ? INADDRSZ
: IN6ADDRSZ
);
634 he
->h_aliases
= malloc(sizeof(char *) * (names
));
635 if (he
->h_aliases
== NULL
)
637 memset(he
->h_aliases
, 0, sizeof(char *) * (names
));
643 cpp
= (he1
!= NULL
) ? he1
->h_aliases
: he2
->h_aliases
;
644 while (*cpp
!= NULL
) {
645 len
= strlen (*cpp
) + 1;
657 he
->h_name
= malloc(strlen((he1
!= NULL
) ?
658 he1
->h_name
: he2
->h_name
) + 1);
659 if (he
->h_name
== NULL
)
661 strcpy(he
->h_name
, (he1
!= NULL
) ? he1
->h_name
: he2
->h_name
);
664 * Set address type and length.
667 he
->h_length
= (af
== AF_INET
) ? INADDRSZ
: IN6ADDRSZ
;
672 while (*cpp
!= NULL
) {
679 cpp
= he
->h_addr_list
;
680 while (*cpp
!= NULL
) {
685 free(he
->h_addr_list
);
691 *error_num
= NO_RECOVERY
;
695 static struct hostent
*
696 hostfromaddr(lwres_gnbaresponse_t
*addr
, int af
, const void *src
) {
700 he
= malloc(sizeof *he
);
703 memset(he
, 0, sizeof(*he
));
706 * Set family and length.
711 he
->h_length
= INADDRSZ
;
714 he
->h_length
= IN6ADDRSZ
;
723 he
->h_name
= strdup(addr
->realname
);
724 if (he
->h_name
== NULL
)
730 he
->h_aliases
= malloc(sizeof(char *) * (addr
->naliases
+ 1));
731 if (he
->h_aliases
== NULL
)
733 for (i
= 0 ; i
< addr
->naliases
; i
++) {
734 he
->h_aliases
[i
] = strdup(addr
->aliases
[i
]);
735 if (he
->h_aliases
[i
] == NULL
)
738 he
->h_aliases
[i
] = NULL
;
743 he
->h_addr_list
= malloc(sizeof(char *) * 2);
744 if (he
->h_addr_list
== NULL
)
746 he
->h_addr_list
[0] = malloc(he
->h_length
);
747 if (he
->h_addr_list
[0] == NULL
)
749 memcpy(he
->h_addr_list
[0], src
, he
->h_length
);
750 he
->h_addr_list
[1] = NULL
;
754 if (he
!= NULL
&& he
->h_addr_list
!= NULL
) {
755 for (i
= 0; he
->h_addr_list
[i
] != NULL
; i
++)
756 free(he
->h_addr_list
[i
]);
757 free(he
->h_addr_list
);
759 if (he
!= NULL
&& he
->h_aliases
!= NULL
) {
760 for (i
= 0; he
->h_aliases
[i
] != NULL
; i
++)
761 free(he
->h_aliases
[i
]);
764 if (he
!= NULL
&& he
->h_name
!= NULL
)
771 static struct hostent
*
772 hostfromname(lwres_gabnresponse_t
*name
, int af
) {
777 he
= malloc(sizeof *he
);
780 memset(he
, 0, sizeof(*he
));
783 * Set family and length.
788 he
->h_length
= INADDRSZ
;
791 he
->h_length
= IN6ADDRSZ
;
800 he
->h_name
= strdup(name
->realname
);
801 if (he
->h_name
== NULL
)
807 he
->h_aliases
= malloc(sizeof(char *) * (name
->naliases
+ 1));
808 for (i
= 0 ; i
< name
->naliases
; i
++) {
809 he
->h_aliases
[i
] = strdup(name
->aliases
[i
]);
810 if (he
->h_aliases
[i
] == NULL
)
813 he
->h_aliases
[i
] = NULL
;
818 he
->h_addr_list
= malloc(sizeof(char *) * (name
->naddrs
+ 1));
819 addr
= LWRES_LIST_HEAD(name
->addrs
);
821 while (addr
!= NULL
) {
822 he
->h_addr_list
[i
] = malloc(he
->h_length
);
823 if (he
->h_addr_list
[i
] == NULL
)
825 memcpy(he
->h_addr_list
[i
], addr
->address
, he
->h_length
);
826 addr
= LWRES_LIST_NEXT(addr
, link
);
829 he
->h_addr_list
[i
] = NULL
;
833 if (he
!= NULL
&& he
->h_addr_list
!= NULL
) {
834 for (i
= 0; he
->h_addr_list
[i
] != NULL
; i
++)
835 free(he
->h_addr_list
[i
]);
836 free(he
->h_addr_list
);
838 if (he
!= NULL
&& he
->h_aliases
!= NULL
) {
839 for (i
= 0; he
->h_aliases
[i
] != NULL
; i
++)
840 free(he
->h_aliases
[i
]);
843 if (he
!= NULL
&& he
->h_name
!= NULL
)