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
, 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
= reallocarray(data
->addr_temp
, (1 + data
->count
+ data
->cur_idx
),
1133 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
= reallocarray(datap
->addr_temp
,
1301 (datap
->cur_idx
+ count
),
1302 sizeof(krb5_address
*));
1304 datap
->addr_temp
= bigger
;
1305 datap
->cur_size
= datap
->cur_idx
+ count
;
1308 for (i
= 0; i
< count
; i
++) {
1309 if (datap
->cur_idx
< datap
->cur_size
)
1310 datap
->addr_temp
[datap
->cur_idx
++] = newaddrs
[i
];
1312 free (newaddrs
[i
]->contents
), free (newaddrs
[i
]);
1320 krb5_error_code KRB5_CALLCONV
1321 krb5_os_localaddr(krb5_context context
, krb5_address
***addr
)
1323 return get_localaddrs(context
, addr
, 1);
1327 krb5int_local_addresses(krb5_context context
, krb5_address
***addr
)
1329 return get_localaddrs(context
, addr
, 0);
1332 static krb5_error_code
1333 get_localaddrs (krb5_context context
, krb5_address
***addr
, int use_profile
)
1335 struct localaddr_data data
= { 0 };
1337 krb5_error_code err
;
1340 err
= krb5_os_localaddr_profile (context
, &data
);
1341 /* ignore err for now */
1344 r
= foreach_localaddr (&data
, count_addrs
, allocate
, add_addr
);
1347 if (data
.addr_temp
) {
1348 for (i
= 0; i
< data
.count
; i
++)
1349 krb5_xfree (data
.addr_temp
[i
]);
1350 free (data
.addr_temp
);
1358 data
.cur_idx
++; /* null termination */
1361 else if (data
.cur_idx
== data
.count
)
1362 *addr
= data
.addr_temp
;
1364 /* This can easily happen if we have IPv6 link-local
1365 addresses. Just shorten the array. */
1366 *addr
= (krb5_address
**) realloc (data
.addr_temp
,
1367 (sizeof (krb5_address
*)
1370 /* Okay, shortening failed, but the original should still
1372 *addr
= data
.addr_temp
;
1378 fprintf (stderr
, "addresses:\n");
1379 for (j
= 0; addr
[0][j
]; j
++) {
1380 struct sockaddr_storage ss
;
1382 char namebuf
[NI_MAXHOST
];
1385 fprintf (stderr
, "%2d: ", j
);
1386 fprintf (stderr
, "addrtype %2d, length %2d", addr
[0][j
]->addrtype
,
1387 addr
[0][j
]->length
);
1388 memset (&ss
, 0, sizeof (ss
));
1389 switch (addr
[0][j
]->addrtype
) {
1392 struct sockaddr_in
*sinp
= ss2sin (&ss
);
1393 sinp
->sin_family
= AF_INET
;
1394 addrp
= &sinp
->sin_addr
;
1396 sinp
->sin_len
= sizeof (struct sockaddr_in
);
1400 #ifdef KRB5_USE_INET6
1401 case ADDRTYPE_INET6
:
1403 struct sockaddr_in6
*sin6p
= ss2sin6 (&ss
);
1404 sin6p
->sin6_family
= AF_INET6
;
1405 addrp
= &sin6p
->sin6_addr
;
1407 sin6p
->sin6_len
= sizeof (struct sockaddr_in6
);
1413 ss2sa(&ss
)->sa_family
= 0;
1417 memcpy (addrp
, addr
[0][j
]->contents
, addr
[0][j
]->length
);
1418 err2
= getnameinfo (ss2sa(&ss
), socklen (ss2sa (&ss
)),
1419 namebuf
, sizeof (namebuf
), 0, 0,
1422 fprintf (stderr
, ": addr %s\n", namebuf
);
1424 fprintf (stderr
, ": getnameinfo error %d\n", err2
);
1432 #endif /* not TESTing */
1434 #else /* Windows/Mac version */
1437 * Hold on to your lunch! Backup kludge method of obtaining your
1438 * local IP address, courtesy of Windows Socket Network Programming,
1442 static struct hostent
*local_addr_fallback_kludge()
1444 static struct hostent host
;
1445 static SOCKADDR_IN addr
;
1446 static char * ip_ptrs
[2];
1448 int size
= sizeof(SOCKADDR
);
1451 sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
1452 if (sock
== INVALID_SOCKET
)
1455 /* connect to arbitrary port and address (NOT loopback) */
1456 addr
.sin_family
= AF_INET
;
1457 addr
.sin_port
= htons(IPPORT_ECHO
);
1458 addr
.sin_addr
.s_addr
= inet_addr("204.137.220.51");
1460 err
= connect(sock
, (LPSOCKADDR
) &addr
, sizeof(SOCKADDR
));
1461 if (err
== SOCKET_ERROR
)
1464 err
= getsockname(sock
, (LPSOCKADDR
) &addr
, (int *) size
);
1465 if (err
== SOCKET_ERROR
)
1472 host
.h_addrtype
= AF_INET
;
1474 host
.h_addr_list
= ip_ptrs
;
1475 ip_ptrs
[0] = (char *) &addr
.sin_addr
.s_addr
;
1482 /* No ioctls in winsock so we just assume there is only one networking
1483 * card per machine, so gethostent is good enough.
1485 krb5_error_code KRB5_CALLCONV
1486 krb5_os_localaddr (krb5_context context
, krb5_address
***addr
) {
1487 char host
[64]; /* Name of local machine */
1488 struct hostent
*hostrec
;
1490 krb5_address
** paddr
;
1496 if (gethostname (host
, sizeof(host
))) {
1501 hostrec
= gethostbyname (host
);
1502 if (hostrec
== NULL
) {
1508 hostrec
= local_addr_fallback_kludge();
1512 err
= 0; /* otherwise we will die at cleanup */
1515 for (count
= 0; hostrec
->h_addr_list
[count
]; count
++);
1518 paddr
= (krb5_address
**)malloc(sizeof(krb5_address
*) * (count
+1));
1524 memset(paddr
, 0, sizeof(krb5_address
*) * (count
+1));
1526 for (i
= 0; i
< count
; i
++)
1528 paddr
[i
] = (krb5_address
*)malloc(sizeof(krb5_address
));
1529 if (paddr
[i
] == NULL
) {
1534 paddr
[i
]->magic
= KV5M_ADDRESS
;
1535 paddr
[i
]->addrtype
= hostrec
->h_addrtype
;
1536 paddr
[i
]->length
= hostrec
->h_length
;
1537 paddr
[i
]->contents
= (unsigned char *)malloc(paddr
[i
]->length
);
1538 if (!paddr
[i
]->contents
) {
1542 memcpy(paddr
[i
]->contents
,
1543 hostrec
->h_addr_list
[i
],
1550 for (i
= 0; i
< count
; i
++)
1553 free(paddr
[i
]->contents
);