2 * lib/krb5/os/localaddr.c
4 * Copyright 1990,1991,2000,2001,2002,2004 by the Massachusetts Institute of Technology.
7 * Export of this software from the United States of America may
8 * require a specific license from the United States Government.
9 * It is the responsibility of any person or organization contemplating
10 * export to obtain such a license before exporting.
12 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13 * distribute this software and its documentation for any purpose and
14 * without fee is hereby granted, provided that the above copyright
15 * notice appear in all copies and that both that copyright notice and
16 * this permission notice appear in supporting documentation, and that
17 * the name of M.I.T. not be used in advertising or publicity pertaining
18 * to distribution of the software without specific, written prior
19 * permission. Furthermore if you modify this software you must label
20 * your software as modified software and not distribute it in such a
21 * fashion that it might be confused with the original M.I.T. software.
22 * M.I.T. makes no representations about the suitability of
23 * this software for any purpose. It is provided "as is" without express
24 * or implied warranty.
27 * Return the protocol addresses supported by this host.
28 * Exports from this file:
29 * krb5int_foreach_localaddr (does callbacks)
30 * krb5int_local_addresses (includes krb5.conf extra_addresses)
31 * krb5_os_localaddr (doesn't)
33 * XNS support is untested, but "Should just work". (Hah!)
40 /* needed for solaris, harmless elsewhere... */
42 #include <sys/ioctl.h>
48 #if defined(TEST) || defined(DEBUG)
49 # include "fake-addrinfo.h"
52 #include "foreachaddr.h"
54 /* Note: foreach_localaddr is exported from the library through
55 krb5int_accessor, for the KDC to use.
57 This function iterates over all the addresses it can find for the
58 local system, in one or two passes. In each pass, and between the
59 two, it can invoke callback functions supplied by the caller. The
60 two passes should operate on the same information, though not
61 necessarily in the same order each time. Duplicate and local
62 addresses should be eliminated. Storage passed to callback
63 functions should not be assumed to be valid after foreach_localaddr
66 The int return value is an errno value (XXX or krb5_error_code
67 returned for a socket error) if something internal to
68 foreach_localaddr fails. If one of the callback functions wants to
69 indicate an error, it should store something via the 'data' handle.
70 If any callback function returns a non-zero value,
71 foreach_localaddr will clean up and return immediately.
73 Multiple definitions are provided below, dependent on various
74 system facilities for extracting the necessary information. */
76 /* Now, on to the implementations, and heaps of debugging code. */
79 # define Tprintf(X) printf X
80 # define Tperror(X) perror(X)
82 # define Tprintf(X) (void) X
83 # define Tperror(X) (void)(X)
87 * The SIOCGIF* ioctls require a socket.
88 * It doesn't matter *what* kind of socket they use, but it has to be
91 * Of course, you can't just ask the kernel for a socket of arbitrary
92 * type; you have to ask for one with a valid type.
95 #ifdef HAVE_NETINET_IN_H
96 #include <netinet/in.h>
98 #define USE_AF AF_INET
99 #define USE_TYPE SOCK_DGRAM
105 #include <netns/ns.h>
108 #define USE_TYPE SOCK_DGRAM
109 #define USE_PROTO 0 /* guess */
113 * Add more address families here.
117 #if defined(__linux__) && defined(KRB5_USE_INET6) && !defined(HAVE_IFADDRS_H)
118 #define LINUX_IPV6_HACK
124 * Return all the protocol addresses of this host.
126 * We could kludge up something to return all addresses, assuming that
127 * they're valid kerberos protocol addresses, but we wouldn't know the
128 * real size of the sockaddr or know which part of it was actually the
131 * This uses the SIOCGIFCONF, SIOCGIFFLAGS, and SIOCGIFADDR ioctl's.
135 * BSD 4.4 defines the size of an ifreq to be
136 * max(sizeof(ifreq), sizeof(ifreq.ifr_name)+ifreq.ifr_addr.sa_len
137 * However, under earlier systems, sa_len isn't present, so the size is
138 * just sizeof(struct ifreq).
142 #define max(a,b) ((a) > (b) ? (a) : (b))
144 #define ifreq_size(i) max(sizeof(struct ifreq),\
145 sizeof((i).ifr_name)+(i).ifr_addr.sa_len)
147 #define ifreq_size(i) sizeof(struct ifreq)
148 #endif /* HAVE_SA_LEN*/
150 #if defined(DEBUG) || defined(TEST)
151 #include <netinet/in.h>
154 #include "socket-utils.h"
155 #include "fake-addrinfo.h"
157 void printaddr (struct sockaddr
*);
159 void printaddr (struct sockaddr
*sa
)
160 /*@modifies fileSystem@*/
162 char buf
[NI_MAXHOST
];
165 printf ("%p ", (void *) sa
);
166 err
= getnameinfo (sa
, socklen (sa
), buf
, sizeof (buf
), 0, 0,
169 printf ("<getnameinfo error %d: %s> family=%d",
170 err
, gai_strerror (err
),
177 #ifdef HAVE_IFADDRS_H
181 void printifaddr (struct ifaddrs
*ifp
)
183 printf ("%p={\n", ifp
);
184 /* printf ("\tnext=%p\n", ifp->ifa_next); */
185 printf ("\tname=%s\n", ifp
->ifa_name
);
188 int ch
, flags
= ifp
->ifa_flags
;
189 printf ("%x", flags
);
191 #define X(F) if (flags & IFF_##F) { printf ("%c%s", ch, #F); flags &= ~IFF_##F; ch = ','; }
192 X (UP
); X (BROADCAST
); X (DEBUG
); X (LOOPBACK
); X (POINTOPOINT
);
193 X (NOTRAILERS
); X (RUNNING
); X (NOARP
); X (PROMISC
); X (ALLMULTI
);
205 printf ("\n\taddr="), printaddr (ifp
->ifa_addr
);
206 if (ifp
->ifa_netmask
)
207 printf ("\n\tnetmask="), printaddr (ifp
->ifa_netmask
);
208 if (ifp
->ifa_broadaddr
)
209 printf ("\n\tbroadaddr="), printaddr (ifp
->ifa_broadaddr
);
210 if (ifp
->ifa_dstaddr
)
211 printf ("\n\tdstaddr="), printaddr (ifp
->ifa_dstaddr
);
213 printf ("\n\tdata=%p", ifp
->ifa_data
);
222 addr_eq (const struct sockaddr
*s1
, const struct sockaddr
*s2
)
224 if (s1
->sa_family
!= s2
->sa_family
)
227 if (s1
->sa_len
!= s2
->sa_len
)
229 return !memcmp (s1
, s2
, s1
->sa_len
);
231 #define CMPTYPE(T,F) (!memcmp(&((const T*)s1)->F,&((const T*)s2)->F,sizeof(((const T*)s1)->F)))
232 switch (s1
->sa_family
) {
234 return CMPTYPE (struct sockaddr_in
, sin_addr
);
236 return CMPTYPE (struct sockaddr_in6
, sin6_addr
);
238 /* Err on side of duplicate listings. */
245 #ifndef HAVE_IFADDRS_H
246 /*@-usereleased@*/ /* lclint doesn't understand realloc */
247 static /*@null@*/ void *
248 grow_or_free (/*@only@*/ void *ptr
, size_t newsize
)
252 newptr
= realloc (ptr
, newsize
);
253 if (newptr
== NULL
&& newsize
!= 0) {
254 free (ptr
); /* lclint complains but this is right */
262 get_ifconf (int s
, size_t *lenp
, /*@out@*/ char *buf
)
263 /*@modifies *buf,*lenp@*/
268 /*@+matchanyintegral@*/
270 /*@=matchanyintegral@*/
272 memset(buf
, 0, *lenp
);
274 ret
= ioctl (s
, SIOCGIFCONF
, (char *)&ifc
);
276 /*@+matchanyintegral@*/
278 /*@=matchanyintegral@*/
282 /* Solaris uses SIOCGLIFCONF to return struct lifconf which is just
283 an extended version of struct ifconf.
285 HP-UX 11 also appears to have SIOCGLIFCONF, but uses struct
286 if_laddrconf, and struct if_laddrreq to be used with
288 #if defined(SIOCGLIFCONF) && defined(HAVE_STRUCT_LIFCONF)
290 get_lifconf (int af
, int s
, size_t *lenp
, /*@out@*/ char *buf
)
291 /*@modifies *buf,*lenp@*/
296 lifc
.lifc_family
= af
;
298 /*@+matchanyintegral@*/
299 lifc
.lifc_len
= *lenp
;
300 /*@=matchanyintegral@*/
302 memset(buf
, 0, *lenp
);
304 ret
= ioctl (s
, SIOCGLIFCONF
, (char *)&lifc
);
306 Tperror ("SIOCGLIFCONF");
308 /*@+matchanyintegral@*/
309 *lenp
= lifc
.lifc_len
;
310 /*@=matchanyintegral@*/
314 #if defined(SIOCGLIFCONF) && defined(HAVE_STRUCT_IF_LADDRCONF) && 0
315 /* I'm not sure if this is needed or if net/if.h will pull it in. */
316 /* #include <net/if6.h> */
318 get_if_laddrconf (int af
, int s
, size_t *lenp
, /*@out@*/ char *buf
)
319 /*@modifies *buf,*lenp@*/
322 struct if_laddrconf iflc
;
324 /*@+matchanyintegral@*/
325 iflc
.iflc_len
= *lenp
;
326 /*@=matchanyintegral@*/
328 memset(buf
, 0, *lenp
);
330 ret
= ioctl (s
, SIOCGLIFCONF
, (char *)&iflc
);
332 Tperror ("SIOCGLIFCONF");
334 /*@+matchanyintegral@*/
335 *lenp
= iflc
.iflc_len
;
336 /*@=matchanyintegral@*/
340 #endif /* ! HAVE_IFADDRS_H */
342 #ifdef LINUX_IPV6_HACK
344 /* Read IPv6 addresses out of /proc/net/if_inet6, since there isn't
345 (currently) any ioctl to return them. */
346 struct linux_ipv6_addr_list
{
347 struct sockaddr_in6 addr
;
348 struct linux_ipv6_addr_list
*next
;
350 static struct linux_ipv6_addr_list
*
351 get_linux_ipv6_addrs ()
353 struct linux_ipv6_addr_list
*lst
= 0;
356 /* _PATH_PROCNET_IFINET6 */
357 f
= fopen("/proc/net/if_inet6", "r");
360 unsigned int idx
, pfxlen
, scope
, dadstat
;
362 struct linux_ipv6_addr_list
*nw
;
364 unsigned int addrbyte
[16];
367 "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x"
368 " %2x %2x %2x %2x %20s\n",
369 &addrbyte
[0], &addrbyte
[1], &addrbyte
[2], &addrbyte
[3],
370 &addrbyte
[4], &addrbyte
[5], &addrbyte
[6], &addrbyte
[7],
371 &addrbyte
[8], &addrbyte
[9], &addrbyte
[10], &addrbyte
[11],
372 &addrbyte
[12], &addrbyte
[13], &addrbyte
[14],
374 &idx
, &pfxlen
, &scope
, &dadstat
, ifname
) != EOF
) {
375 for (i
= 0; i
< 16; i
++)
376 a6
.s6_addr
[i
] = addrbyte
[i
];
379 #if 0 /* These symbol names are as used by ifconfig, but none of the
380 system header files export them. Dig up the kernel versions
381 someday and see if they're exported. */
386 case IPV6_ADDR_LINKLOCAL
:
387 case IPV6_ADDR_SITELOCAL
:
388 case IPV6_ADDR_COMPATv4
:
389 case IPV6_ADDR_LOOPBACK
:
393 nw
= malloc (sizeof (struct linux_ipv6_addr_list
));
396 memset (nw
, 0, sizeof (*nw
));
397 nw
->addr
.sin6_addr
= a6
;
398 nw
->addr
.sin6_family
= AF_INET6
;
399 /* Ignore other fields, we don't actually use them here. */
409 /* Return value is errno if internal stuff failed, otherwise zero,
410 even in the case where a called function terminated the iteration.
412 If one of the callback functions wants to pass back an error
413 indication, it should do it via some field pointed to by the DATA
416 #ifdef HAVE_IFADDRS_H
419 foreach_localaddr (/*@null@*/ void *data
,
420 int (*pass1fn
) (/*@null@*/ void *, struct sockaddr
*) /*@*/,
421 /*@null@*/ int (*betweenfn
) (/*@null@*/ void *) /*@*/,
422 /*@null@*/ int (*pass2fn
) (/*@null@*/ void *,
423 struct sockaddr
*) /*@*/)
424 #if defined(DEBUG) || defined(TEST)
425 /*@modifies fileSystem@*/
428 struct ifaddrs
*ifp_head
, *ifp
, *ifp2
;
431 if (getifaddrs (&ifp_head
) < 0)
433 for (ifp
= ifp_head
; ifp
; ifp
= ifp
->ifa_next
) {
437 if ((ifp
->ifa_flags
& IFF_UP
) == 0)
439 if (ifp
->ifa_flags
& IFF_LOOPBACK
) {
440 /* Pretend it's not up, so the second pass will skip
442 ifp
->ifa_flags
&= ~IFF_UP
;
445 if (ifp
->ifa_addr
== NULL
) {
446 /* Can't use an interface without an address. Linux
447 apparently does this sometimes. [RT ticket 1770 from
448 Maurice Massar, also Debian bug 206851, shows the
449 problem with a PPP link on a newer kernel than I'm
452 Pretend it's not up, so the second pass will skip
454 ifp
->ifa_flags
&= ~IFF_UP
;
457 /* If this address is a duplicate, punt. */
459 for (ifp2
= ifp_head
; ifp2
&& ifp2
!= ifp
; ifp2
= ifp2
->ifa_next
) {
460 if ((ifp2
->ifa_flags
& IFF_UP
) == 0)
462 if (ifp2
->ifa_flags
& IFF_LOOPBACK
)
464 if (addr_eq (ifp
->ifa_addr
, ifp2
->ifa_addr
)) {
466 ifp
->ifa_flags
&= ~IFF_UP
;
472 if ((*pass1fn
) (data
, ifp
->ifa_addr
))
475 if (betweenfn
&& (*betweenfn
)(data
))
478 for (ifp
= ifp_head
; ifp
; ifp
= ifp
->ifa_next
) {
479 if (ifp
->ifa_flags
& IFF_UP
)
480 if ((*pass2fn
) (data
, ifp
->ifa_addr
))
484 freeifaddrs (ifp_head
);
488 #elif defined (SIOCGLIFNUM) && defined(HAVE_STRUCT_LIFCONF) /* Solaris 8 and later; Sol 7? */
491 foreach_localaddr (/*@null@*/ void *data
,
492 int (*pass1fn
) (/*@null@*/ void *, struct sockaddr
*) /*@*/,
493 /*@null@*/ int (*betweenfn
) (/*@null@*/ void *) /*@*/,
494 /*@null@*/ int (*pass2fn
) (/*@null@*/ void *,
495 struct sockaddr
*) /*@*/)
496 #if defined(DEBUG) || defined(TEST)
497 /*@modifies fileSystem@*/
500 /* Okay, this is kind of odd. We have to use each of the address
501 families we care about, because with an AF_INET socket, extra
502 interfaces like hme0:1 that have only AF_INET6 addresses will
503 cause errors. Similarly, if hme0 has more AF_INET addresses
504 than AF_INET6 addresses, we won't be able to retrieve all of
505 the AF_INET addresses if we use an AF_INET6 socket. Since
506 neither family is guaranteed to have the greater number of
507 addresses, we should use both.
509 If it weren't for this little quirk, we could use one socket of
510 any type, and ask for addresses of all types. At least, it
511 seems to work that way. */
513 static const int afs
[] = { AF_INET
, AF_NS
, AF_INET6
};
514 #define N_AFS (sizeof (afs) / sizeof (afs[0]))
520 struct lifnum lifnum
;
523 int retval
= 0, afidx
;
524 krb5_error_code sock_err
= 0;
525 struct lifreq
*lifr
, lifreq
, *lifr2
;
527 #define FOREACH_AF() for (afidx = 0; afidx < N_AFS; afidx++)
528 #define P (afp[afidx])
537 /* first pass: get raw data, discard uninteresting addresses, callback */
539 Tprintf (("trying af %d...\n", P
.af
));
540 P
.sock
= socket (P
.af
, USE_TYPE
, USE_PROTO
);
542 sock_err
= SOCKET_ERROR
;
547 P
.lifnum
.lifn_family
= P
.af
;
548 P
.lifnum
.lifn_flags
= 0;
549 P
.lifnum
.lifn_count
= 0;
550 code
= ioctl (P
.sock
, SIOCGLIFNUM
, &P
.lifnum
);
552 Tperror ("ioctl(SIOCGLIFNUM)");
557 P
.buf_size
= P
.lifnum
.lifn_count
* sizeof (struct lifreq
) * 2;
558 P
.buf
= malloc (P
.buf_size
);
564 code
= get_lifconf (P
.af
, P
.sock
, &P
.buf_size
, P
.buf
);
570 for (i
= 0; i
+ sizeof(*lifr
) <= P
.buf_size
; i
+= sizeof (*lifr
)) {
571 lifr
= (struct lifreq
*)((caddr_t
) P
.buf
+i
);
573 strncpy(lifreq
.lifr_name
, lifr
->lifr_name
,
574 sizeof (lifreq
.lifr_name
));
575 Tprintf (("interface %s\n", lifreq
.lifr_name
));
576 /*@-moduncon@*/ /* ioctl unknown to lclint */
577 if (ioctl (P
.sock
, SIOCGLIFFLAGS
, (char *)&lifreq
) < 0) {
578 Tperror ("ioctl(SIOCGLIFFLAGS)");
580 /* mark for next pass */
581 lifr
->lifr_name
[0] = '\0';
587 /* None of the current callers want loopback addresses. */
588 if (lifreq
.lifr_flags
& IFF_LOOPBACK
) {
589 Tprintf ((" loopback\n"));
593 /* Ignore interfaces that are down. */
594 if ((lifreq
.lifr_flags
& IFF_UP
) == 0) {
595 Tprintf ((" down\n"));
599 /* Make sure we didn't process this address already. */
600 for (j
= 0; j
< i
; j
+= sizeof (*lifr2
)) {
601 lifr2
= (struct lifreq
*)((caddr_t
) P
.buf
+j
);
602 if (lifr2
->lifr_name
[0] == '\0')
604 if (lifr2
->lifr_addr
.ss_family
== lifr
->lifr_addr
.ss_family
605 /* Compare address info. If this isn't good enough --
606 i.e., if random padding bytes turn out to differ
607 when the addresses are the same -- then we'll have
608 to do it on a per address family basis. */
609 && !memcmp (&lifr2
->lifr_addr
, &lifr
->lifr_addr
,
611 Tprintf ((" duplicate addr\n"));
617 if ((*pass1fn
) (data
, ss2sa (&lifr
->lifr_addr
)))
623 /* Did we actually get any working sockets? */
626 goto have_working_socket
;
632 if (betweenfn
!= NULL
&& (*betweenfn
)(data
))
639 for (i
= 0; i
+ sizeof (*lifr
) <= P
.buf_size
; i
+= sizeof (*lifr
)) {
640 lifr
= (struct lifreq
*)((caddr_t
) P
.buf
+i
);
642 if (lifr
->lifr_name
[0] == '\0')
643 /* Marked in first pass to be ignored. */
647 if ((*pass2fn
) (data
, ss2sa (&lifr
->lifr_addr
)))
663 #elif defined (SIOCGLIFNUM) && defined(HAVE_STRUCT_IF_LADDRCONF) && 0 /* HP-UX 11 support being debugged */
666 foreach_localaddr (/*@null@*/ void *data
,
667 int (*pass1fn
) (/*@null@*/ void *, struct sockaddr
*) /*@*/,
668 /*@null@*/ int (*betweenfn
) (/*@null@*/ void *) /*@*/,
669 /*@null@*/ int (*pass2fn
) (/*@null@*/ void *,
670 struct sockaddr
*) /*@*/)
671 #if defined(DEBUG) || defined(TEST)
672 /*@modifies fileSystem@*/
675 /* Okay, this is kind of odd. We have to use each of the address
676 families we care about, because with an AF_INET socket, extra
677 interfaces like hme0:1 that have only AF_INET6 addresses will
678 cause errors. Similarly, if hme0 has more AF_INET addresses
679 than AF_INET6 addresses, we won't be able to retrieve all of
680 the AF_INET addresses if we use an AF_INET6 socket. Since
681 neither family is guaranteed to have the greater number of
682 addresses, we should use both.
684 If it weren't for this little quirk, we could use one socket of
685 any type, and ask for addresses of all types. At least, it
686 seems to work that way. */
688 static const int afs
[] = { AF_INET
, AF_NS
, AF_INET6
};
689 #define N_AFS (sizeof (afs) / sizeof (afs[0]))
698 int retval
= 0, afidx
;
699 krb5_error_code sock_err
= 0;
700 struct if_laddrreq
*lifr
, lifreq
, *lifr2
;
702 #define FOREACH_AF() for (afidx = 0; afidx < N_AFS; afidx++)
703 #define P (afp[afidx])
712 /* first pass: get raw data, discard uninteresting addresses, callback */
714 Tprintf (("trying af %d...\n", P
.af
));
715 P
.sock
= socket (P
.af
, USE_TYPE
, USE_PROTO
);
717 sock_err
= SOCKET_ERROR
;
722 code
= ioctl (P
.sock
, SIOCGLIFNUM
, &P
.if_num
);
724 Tperror ("ioctl(SIOCGLIFNUM)");
729 P
.buf_size
= P
.if_num
* sizeof (struct if_laddrreq
) * 2;
730 P
.buf
= malloc (P
.buf_size
);
736 code
= get_if_laddrconf (P
.af
, P
.sock
, &P
.buf_size
, P
.buf
);
742 for (i
= 0; i
+ sizeof(*lifr
) <= P
.buf_size
; i
+= sizeof (*lifr
)) {
743 lifr
= (struct if_laddrreq
*)((caddr_t
) P
.buf
+i
);
745 strncpy(lifreq
.iflr_name
, lifr
->iflr_name
,
746 sizeof (lifreq
.iflr_name
));
747 Tprintf (("interface %s\n", lifreq
.iflr_name
));
748 /*@-moduncon@*/ /* ioctl unknown to lclint */
749 if (ioctl (P
.sock
, SIOCGLIFFLAGS
, (char *)&lifreq
) < 0) {
750 Tperror ("ioctl(SIOCGLIFFLAGS)");
752 /* mark for next pass */
753 lifr
->iflr_name
[0] = '\0';
759 /* None of the current callers want loopback addresses. */
760 if (lifreq
.iflr_flags
& IFF_LOOPBACK
) {
761 Tprintf ((" loopback\n"));
765 /* Ignore interfaces that are down. */
766 if ((lifreq
.iflr_flags
& IFF_UP
) == 0) {
767 Tprintf ((" down\n"));
771 /* Make sure we didn't process this address already. */
772 for (j
= 0; j
< i
; j
+= sizeof (*lifr2
)) {
773 lifr2
= (struct if_laddrreq
*)((caddr_t
) P
.buf
+j
);
774 if (lifr2
->iflr_name
[0] == '\0')
776 if (lifr2
->iflr_addr
.sa_family
== lifr
->iflr_addr
.sa_family
777 /* Compare address info. If this isn't good enough --
778 i.e., if random padding bytes turn out to differ
779 when the addresses are the same -- then we'll have
780 to do it on a per address family basis. */
781 && !memcmp (&lifr2
->iflr_addr
, &lifr
->iflr_addr
,
783 Tprintf ((" duplicate addr\n"));
789 if ((*pass1fn
) (data
, ss2sa (&lifr
->iflr_addr
)))
795 /* Did we actually get any working sockets? */
798 goto have_working_socket
;
804 if (betweenfn
!= NULL
&& (*betweenfn
)(data
))
811 for (i
= 0; i
+ sizeof(*lifr
) <= P
.buf_size
; i
+= sizeof (*lifr
)) {
812 lifr
= (struct if_laddrreq
*)((caddr_t
) P
.buf
+i
);
814 if (lifr
->iflr_name
[0] == '\0')
815 /* Marked in first pass to be ignored. */
819 if ((*pass2fn
) (data
, ss2sa (&lifr
->iflr_addr
)))
835 #else /* not defined (SIOCGLIFNUM) */
837 #define SLOP (sizeof (struct ifreq) + 128)
840 get_ifreq_array(char **bufp
, size_t *np
, int s
)
843 int est_if_count
= 8;
844 size_t est_ifreq_size
;
846 size_t current_buf_size
= 0, size
, n
;
847 #ifdef SIOCGSIZIFCONF
854 /* At least on NetBSD, an ifreq can hold an IPv4 address, but
855 isn't big enough for an IPv6 or ethernet address. So add a
856 little more space. */
857 est_ifreq_size
= sizeof (struct ifreq
) + 8;
858 #ifdef SIOCGSIZIFCONF
859 code
= ioctl (s
, SIOCGSIZIFCONF
, &ifconfsize
);
861 current_buf_size
= ifconfsize
;
862 est_if_count
= ifconfsize
/ est_ifreq_size
;
864 #elif defined (SIOCGIFNUM)
865 code
= ioctl (s
, SIOCGIFNUM
, &numifs
);
866 if (!code
&& numifs
> 0)
867 est_if_count
= numifs
;
869 if (current_buf_size
== 0)
870 current_buf_size
= est_ifreq_size
* est_if_count
+ SLOP
;
871 buf
= malloc (current_buf_size
);
876 size
= current_buf_size
;
877 code
= get_ifconf (s
, &size
, buf
);
883 /* Test that the buffer was big enough that another ifreq could've
884 fit easily, if the OS wanted to provide one. That seems to be
885 the only indication we get, complicated by the fact that the
886 associated address may make the required storage a little
887 bigger than the size of an ifreq. */
888 if (current_buf_size
- size
< SLOP
889 #ifdef SIOCGSIZIFCONF
890 /* Unless we hear SIOCGSIZIFCONF is broken somewhere, let's
891 trust the value it returns. */
893 #elif defined (SIOCGIFNUM)
896 /* And we need *some* sort of bounds. */
897 && current_buf_size
<= 100000
902 new_size
= est_ifreq_size
* est_if_count
+ SLOP
;
903 buf
= grow_or_free (buf
, new_size
);
906 current_buf_size
= new_size
;
911 if (n
> current_buf_size
)
912 n
= current_buf_size
;
920 foreach_localaddr (/*@null@*/ void *data
,
921 int (*pass1fn
) (/*@null@*/ void *, struct sockaddr
*) /*@*/,
922 /*@null@*/ int (*betweenfn
) (/*@null@*/ void *) /*@*/,
923 /*@null@*/ int (*pass2fn
) (/*@null@*/ void *,
924 struct sockaddr
*) /*@*/)
925 #if defined(DEBUG) || defined(TEST)
926 /*@modifies fileSystem@*/
929 struct ifreq
*ifr
, ifreq
, *ifr2
;
932 size_t size
, n
, i
, j
;
934 #ifdef LINUX_IPV6_HACK
935 struct linux_ipv6_addr_list
*linux_ipv6_addrs
= get_linux_ipv6_addrs ();
936 struct linux_ipv6_addr_list
*lx_v6
;
939 s
= socket (USE_AF
, USE_TYPE
, USE_PROTO
);
943 retval
= get_ifreq_array(&buf
, &n
, s
);
945 /*@-moduncon@*/ /* close() unknown to lclint */
951 /* Note: Apparently some systems put the size (used or wanted?)
952 into the start of the buffer, just none that I'm actually
953 using. Fix this when there's such a test system available.
954 The Samba mailing list archives mention that NTP looks for the
955 size on these systems: *-fujitsu-uxp* *-ncr-sysv4*
957 for (i
= 0; i
+ sizeof(struct ifreq
) <= n
; i
+= ifreq_size(*ifr
) ) {
958 ifr
= (struct ifreq
*)((caddr_t
) buf
+i
);
959 /* In case ifreq_size is more than sizeof(). */
960 if (i
+ ifreq_size(*ifr
) > n
)
963 strncpy(ifreq
.ifr_name
, ifr
->ifr_name
, sizeof (ifreq
.ifr_name
));
964 Tprintf (("interface %s\n", ifreq
.ifr_name
));
965 /*@-moduncon@*/ /* ioctl unknown to lclint */
966 if (ioctl (s
, SIOCGIFFLAGS
, (char *)&ifreq
) < 0) {
968 /* mark for next pass */
969 ifr
->ifr_name
[0] = '\0';
975 /* None of the current callers want loopback addresses. */
976 if (ifreq
.ifr_flags
& IFF_LOOPBACK
) {
977 Tprintf ((" loopback\n"));
981 /* Ignore interfaces that are down. */
982 if ((ifreq
.ifr_flags
& IFF_UP
) == 0) {
983 Tprintf ((" down\n"));
987 /* Make sure we didn't process this address already. */
988 for (j
= 0; j
< i
; j
+= ifreq_size(*ifr2
)) {
989 ifr2
= (struct ifreq
*)((caddr_t
) buf
+j
);
990 if (ifr2
->ifr_name
[0] == '\0')
992 if (ifr2
->ifr_addr
.sa_family
== ifr
->ifr_addr
.sa_family
993 && ifreq_size (*ifr
) == ifreq_size (*ifr2
)
994 /* Compare address info. If this isn't good enough --
995 i.e., if random padding bytes turn out to differ
996 when the addresses are the same -- then we'll have
997 to do it on a per address family basis. */
998 && !memcmp (&ifr2
->ifr_addr
.sa_data
, &ifr
->ifr_addr
.sa_data
,
1000 - offsetof (struct ifreq
, ifr_addr
.sa_data
)))) {
1001 Tprintf ((" duplicate addr\n"));
1007 if ((*pass1fn
) (data
, &ifr
->ifr_addr
))
1012 #ifdef LINUX_IPV6_HACK
1013 for (lx_v6
= linux_ipv6_addrs
; lx_v6
; lx_v6
= lx_v6
->next
)
1014 if ((*pass1fn
) (data
, (struct sockaddr
*) &lx_v6
->addr
))
1019 if (betweenfn
!= NULL
&& (*betweenfn
)(data
))
1024 for (i
= 0; i
+ sizeof(struct ifreq
) <= n
; i
+= ifreq_size(*ifr
) ) {
1025 ifr
= (struct ifreq
*)((caddr_t
) buf
+i
);
1027 if (ifr
->ifr_name
[0] == '\0')
1028 /* Marked in first pass to be ignored. */
1032 if ((*pass2fn
) (data
, &ifr
->ifr_addr
))
1036 #ifdef LINUX_IPV6_HACK
1037 for (lx_v6
= linux_ipv6_addrs
; lx_v6
; lx_v6
= lx_v6
->next
)
1038 if ((*pass2fn
) (data
, (struct sockaddr
*) &lx_v6
->addr
))
1047 #ifdef LINUX_IPV6_HACK
1048 while (linux_ipv6_addrs
) {
1049 lx_v6
= linux_ipv6_addrs
->next
;
1050 free (linux_ipv6_addrs
);
1051 linux_ipv6_addrs
= lx_v6
;
1058 #endif /* not HAVE_IFADDRS_H and not SIOCGLIFNUM */
1060 static krb5_error_code
1061 get_localaddrs (krb5_context context
, krb5_address
***addr
, int use_profile
);
1065 static int print_addr (/*@unused@*/ void *dataptr
, struct sockaddr
*sa
)
1066 /*@modifies fileSystem@*/
1068 char hostbuf
[NI_MAXHOST
];
1072 printf (" --> family %2d ", sa
->sa_family
);
1074 err
= getnameinfo (sa
, len
, hostbuf
, (socklen_t
) sizeof (hostbuf
),
1075 (char *) NULL
, 0, NI_NUMERICHOST
);
1078 printf ("<getnameinfo error %d: %s>\n", err
, gai_strerror (err
));
1079 if (err
== EAI_SYSTEM
)
1080 printf ("\t\t<errno is %d: %s>\n", e
, strerror(e
));
1082 printf ("addr %s\n", hostbuf
);
1090 (void) setvbuf (stdout
, (char *)NULL
, _IONBF
, 0);
1091 r
= foreach_localaddr (0, print_addr
, NULL
, NULL
);
1092 printf ("return value = %d\n", r
);
1096 #else /* not TESTing */
1098 struct localaddr_data
{
1099 int count
, mem_err
, cur_idx
, cur_size
;
1100 krb5_address
**addr_temp
;
1104 count_addrs (void *P_data
, struct sockaddr
*a
)
1107 struct localaddr_data
*data
= P_data
;
1108 switch (a
->sa_family
) {
1110 #ifdef KRB5_USE_INET6
1125 allocate (void *P_data
)
1128 struct localaddr_data
*data
= P_data
;
1132 n
= realloc (data
->addr_temp
,
1133 (1 + data
->count
+ data
->cur_idx
) * sizeof (krb5_address
*));
1138 data
->addr_temp
= n
;
1139 data
->cur_size
= 1 + data
->count
+ data
->cur_idx
;
1140 for (i
= data
->cur_idx
; i
<= data
->count
+ data
->cur_idx
; i
++)
1141 data
->addr_temp
[i
] = 0;
1145 static /*@null@*/ krb5_address
*
1146 make_addr (int type
, size_t length
, const void *contents
)
1152 data
= malloc (length
);
1155 a
= malloc (sizeof (krb5_address
));
1160 memcpy (data
, contents
, length
);
1161 a
->magic
= KV5M_ADDRESS
;
1169 add_addr (void *P_data
, struct sockaddr
*a
)
1170 /*@modifies *P_data@*/
1172 struct localaddr_data
*data
= P_data
;
1173 /*@null@*/ krb5_address
*address
= 0;
1175 switch (a
->sa_family
) {
1176 #ifdef HAVE_NETINET_IN_H
1178 address
= make_addr (ADDRTYPE_INET
, sizeof (struct in_addr
),
1179 &((const struct sockaddr_in
*) a
)->sin_addr
);
1180 if (address
== NULL
)
1184 #ifdef KRB5_USE_INET6
1187 const struct sockaddr_in6
*in
= (const struct sockaddr_in6
*) a
;
1189 if (IN6_IS_ADDR_LINKLOCAL (&in
->sin6_addr
))
1192 address
= make_addr (ADDRTYPE_INET6
, sizeof (struct in6_addr
),
1194 if (address
== NULL
)
1198 #endif /* KRB5_USE_INET6 */
1199 #endif /* netinet/in.h */
1203 address
= make_addr (ADDRTYPE_XNS
, sizeof (struct ns_addr
),
1204 &((const struct sockaddr_ns
*)a
)->sns_addr
);
1205 if (address
== NULL
)
1211 /* Some BSD-based systems (e.g. NetBSD 1.5) and AIX will
1212 include the ethernet address, but we don't want that, at
1218 * Add more address families here..
1224 /* Redundant but unconditional store un-confuses lclint. */
1225 data
->addr_temp
[data
->cur_idx
] = address
;
1228 data
->addr_temp
[data
->cur_idx
++] = address
;
1231 return data
->mem_err
;
1234 static krb5_error_code
1235 krb5_os_localaddr_profile (krb5_context context
, struct localaddr_data
*datap
)
1237 krb5_error_code err
;
1238 static const char *const profile_name
[] = {
1239 "libdefaults", "extra_addresses", 0
1243 krb5_address
**newaddrs
;
1246 fprintf (stderr
, "looking up extra_addresses foo\n");
1249 err
= profile_get_values (context
->profile
, profile_name
, &values
);
1250 /* Ignore all errors for now? */
1254 for (iter
= values
; *iter
; iter
++) {
1255 char *cp
= *iter
, *next
, *current
;
1259 fprintf (stderr
, " found line: '%s'\n", cp
);
1262 for (cp
= *iter
, next
= 0; *cp
; cp
= next
) {
1263 while (isspace ((int) *cp
) || *cp
== ',')
1267 /* Start of an address. */
1269 fprintf (stderr
, " addr found in '%s'\n", cp
);
1272 while (*cp
!= 0 && !isspace((int) *cp
) && *cp
!= ',')
1279 /* Got a single address, process it. */
1281 fprintf (stderr
, " processing '%s'\n", current
);
1284 err
= krb5_os_hostaddr (context
, current
, &newaddrs
);
1287 for (i
= 0; newaddrs
[i
]; i
++) {
1289 fprintf (stderr
, " %d: family %d", i
,
1290 newaddrs
[i
]->addrtype
);
1291 fprintf (stderr
, "\n");
1296 fprintf (stderr
, " %d addresses\n", count
);
1298 if (datap
->cur_idx
+ count
>= datap
->cur_size
) {
1299 krb5_address
**bigger
;
1300 bigger
= realloc (datap
->addr_temp
,
1301 sizeof (krb5_address
*) * (datap
->cur_idx
+ count
));
1303 datap
->addr_temp
= bigger
;
1304 datap
->cur_size
= datap
->cur_idx
+ count
;
1307 for (i
= 0; i
< count
; i
++) {
1308 if (datap
->cur_idx
< datap
->cur_size
)
1309 datap
->addr_temp
[datap
->cur_idx
++] = newaddrs
[i
];
1311 free (newaddrs
[i
]->contents
), free (newaddrs
[i
]);
1319 krb5_error_code KRB5_CALLCONV
1320 krb5_os_localaddr(krb5_context context
, krb5_address
***addr
)
1322 return get_localaddrs(context
, addr
, 1);
1326 krb5int_local_addresses(krb5_context context
, krb5_address
***addr
)
1328 return get_localaddrs(context
, addr
, 0);
1331 static krb5_error_code
1332 get_localaddrs (krb5_context context
, krb5_address
***addr
, int use_profile
)
1334 struct localaddr_data data
= { 0 };
1336 krb5_error_code err
;
1339 err
= krb5_os_localaddr_profile (context
, &data
);
1340 /* ignore err for now */
1343 r
= foreach_localaddr (&data
, count_addrs
, allocate
, add_addr
);
1346 if (data
.addr_temp
) {
1347 for (i
= 0; i
< data
.count
; i
++)
1348 krb5_xfree (data
.addr_temp
[i
]);
1349 free (data
.addr_temp
);
1357 data
.cur_idx
++; /* null termination */
1360 else if (data
.cur_idx
== data
.count
)
1361 *addr
= data
.addr_temp
;
1363 /* This can easily happen if we have IPv6 link-local
1364 addresses. Just shorten the array. */
1365 *addr
= (krb5_address
**) realloc (data
.addr_temp
,
1366 (sizeof (krb5_address
*)
1369 /* Okay, shortening failed, but the original should still
1371 *addr
= data
.addr_temp
;
1377 fprintf (stderr
, "addresses:\n");
1378 for (j
= 0; addr
[0][j
]; j
++) {
1379 struct sockaddr_storage ss
;
1381 char namebuf
[NI_MAXHOST
];
1384 fprintf (stderr
, "%2d: ", j
);
1385 fprintf (stderr
, "addrtype %2d, length %2d", addr
[0][j
]->addrtype
,
1386 addr
[0][j
]->length
);
1387 memset (&ss
, 0, sizeof (ss
));
1388 switch (addr
[0][j
]->addrtype
) {
1391 struct sockaddr_in
*sinp
= ss2sin (&ss
);
1392 sinp
->sin_family
= AF_INET
;
1393 addrp
= &sinp
->sin_addr
;
1395 sinp
->sin_len
= sizeof (struct sockaddr_in
);
1399 #ifdef KRB5_USE_INET6
1400 case ADDRTYPE_INET6
:
1402 struct sockaddr_in6
*sin6p
= ss2sin6 (&ss
);
1403 sin6p
->sin6_family
= AF_INET6
;
1404 addrp
= &sin6p
->sin6_addr
;
1406 sin6p
->sin6_len
= sizeof (struct sockaddr_in6
);
1412 ss2sa(&ss
)->sa_family
= 0;
1416 memcpy (addrp
, addr
[0][j
]->contents
, addr
[0][j
]->length
);
1417 err2
= getnameinfo (ss2sa(&ss
), socklen (ss2sa (&ss
)),
1418 namebuf
, sizeof (namebuf
), 0, 0,
1421 fprintf (stderr
, ": addr %s\n", namebuf
);
1423 fprintf (stderr
, ": getnameinfo error %d\n", err2
);
1431 #endif /* not TESTing */
1433 #else /* Windows/Mac version */
1436 * Hold on to your lunch! Backup kludge method of obtaining your
1437 * local IP address, courtesy of Windows Socket Network Programming,
1441 static struct hostent
*local_addr_fallback_kludge()
1443 static struct hostent host
;
1444 static SOCKADDR_IN addr
;
1445 static char * ip_ptrs
[2];
1447 int size
= sizeof(SOCKADDR
);
1450 sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
1451 if (sock
== INVALID_SOCKET
)
1454 /* connect to arbitrary port and address (NOT loopback) */
1455 addr
.sin_family
= AF_INET
;
1456 addr
.sin_port
= htons(IPPORT_ECHO
);
1457 addr
.sin_addr
.s_addr
= inet_addr("204.137.220.51");
1459 err
= connect(sock
, (LPSOCKADDR
) &addr
, sizeof(SOCKADDR
));
1460 if (err
== SOCKET_ERROR
)
1463 err
= getsockname(sock
, (LPSOCKADDR
) &addr
, (int *) size
);
1464 if (err
== SOCKET_ERROR
)
1471 host
.h_addrtype
= AF_INET
;
1473 host
.h_addr_list
= ip_ptrs
;
1474 ip_ptrs
[0] = (char *) &addr
.sin_addr
.s_addr
;
1481 /* No ioctls in winsock so we just assume there is only one networking
1482 * card per machine, so gethostent is good enough.
1484 krb5_error_code KRB5_CALLCONV
1485 krb5_os_localaddr (krb5_context context
, krb5_address
***addr
) {
1486 char host
[64]; /* Name of local machine */
1487 struct hostent
*hostrec
;
1489 krb5_address
** paddr
;
1495 if (gethostname (host
, sizeof(host
))) {
1500 hostrec
= gethostbyname (host
);
1501 if (hostrec
== NULL
) {
1507 hostrec
= local_addr_fallback_kludge();
1511 err
= 0; /* otherwise we will die at cleanup */
1514 for (count
= 0; hostrec
->h_addr_list
[count
]; count
++);
1517 paddr
= (krb5_address
**)malloc(sizeof(krb5_address
*) * (count
+1));
1523 memset(paddr
, 0, sizeof(krb5_address
*) * (count
+1));
1525 for (i
= 0; i
< count
; i
++)
1527 paddr
[i
] = (krb5_address
*)malloc(sizeof(krb5_address
));
1528 if (paddr
[i
] == NULL
) {
1533 paddr
[i
]->magic
= KV5M_ADDRESS
;
1534 paddr
[i
]->addrtype
= hostrec
->h_addrtype
;
1535 paddr
[i
]->length
= hostrec
->h_length
;
1536 paddr
[i
]->contents
= (unsigned char *)malloc(paddr
[i
]->length
);
1537 if (!paddr
[i
]->contents
) {
1541 memcpy(paddr
[i
]->contents
,
1542 hostrec
->h_addr_list
[i
],
1549 for (i
= 0; i
< count
; i
++)
1552 if (paddr
[i
]->contents
)
1553 free(paddr
[i
]->contents
);