1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* lib/krb5/os/localaddr.c */
4 * Copyright 1990,1991,2000,2001,2002,2004,2007,2008 by the Massachusetts
5 * Institute of Technology. All Rights Reserved.
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.
28 * Return the protocol addresses supported by this host.
29 * Exports from this file:
30 * krb5int_foreach_localaddr (does callbacks)
31 * krb5_os_localaddr (doesn't include krb5.conf extra_addresses)
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(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 *);
160 printaddr(struct sockaddr *sa)
161 /*@modifies fileSystem@*/
163 char buf[NI_MAXHOST];
166 printf ("%p ", (void *) sa);
167 err = getnameinfo (sa, socklen (sa), buf, sizeof (buf), 0, 0,
170 printf ("<getnameinfo error %d: %s> family=%d",
171 err, gai_strerror (err),
179 is_loopback_address(struct sockaddr *sa)
181 switch (sa->sa_family) {
183 struct sockaddr_in *s4 = (struct sockaddr_in *)sa;
184 return s4->sin_addr.s_addr == htonl(INADDR_LOOPBACK);
187 struct sockaddr_in6 *s6 = (struct sockaddr_in6 *)sa;
188 return IN6_IS_ADDR_LOOPBACK(&s6->sin6_addr);
195 #ifdef HAVE_IFADDRS_H
200 printifaddr(struct ifaddrs *ifp)
202 printf ("%p={\n", ifp);
203 /* printf ("\tnext=%p\n", ifp->ifa_next); */
204 printf ("\tname=%s\n", ifp->ifa_name);
207 int ch, flags = ifp->ifa_flags;
208 printf ("%x", flags);
210 #define X(F) if (flags & IFF_##F) { printf ("%c%s", ch, #F); flags &= ~IFF_##F; ch = ','; }
211 X (UP); X (BROADCAST); X (DEBUG); X (LOOPBACK); X (POINTOPOINT);
212 X (NOTRAILERS); X (RUNNING); X (NOARP); X (PROMISC); X (ALLMULTI);
224 printf ("\n\taddr="), printaddr (ifp->ifa_addr);
225 if (ifp->ifa_netmask)
226 printf ("\n\tnetmask="), printaddr (ifp->ifa_netmask);
227 if (ifp->ifa_broadaddr)
228 printf ("\n\tbroadaddr="), printaddr (ifp->ifa_broadaddr);
229 if (ifp->ifa_dstaddr)
230 printf ("\n\tdstaddr="), printaddr (ifp->ifa_dstaddr);
232 printf ("\n\tdata=%p", ifp->ifa_data);
241 addr_eq (const struct sockaddr *s1, const struct sockaddr *s2)
243 if (s1->sa_family != s2->sa_family)
246 if (s1->sa_len != s2->sa_len)
248 return !memcmp (s1, s2, s1->sa_len);
250 #define CMPTYPE(T,F) (!memcmp(&((const T*)s1)->F,&((const T*)s2)->F,sizeof(((const T*)s1)->F)))
251 switch (s1->sa_family) {
253 return CMPTYPE (struct sockaddr_in, sin_addr);
255 return CMPTYPE (struct sockaddr_in6, sin6_addr);
257 /* Err on side of duplicate listings. */
264 #ifndef HAVE_IFADDRS_H
265 /*@-usereleased@*/ /* lclint doesn't understand realloc */
266 static /*@null@*/ void *
267 grow_or_free (/*@only@*/ void *ptr, size_t newsize)
271 newptr = realloc (ptr, newsize);
272 if (newptr == NULL && newsize != 0) {
273 free (ptr); /* lclint complains but this is right */
281 get_ifconf (int s, size_t *lenp, /*@out@*/ char *buf)
282 /*@modifies *buf,*lenp@*/
287 /*@+matchanyintegral@*/
289 /*@=matchanyintegral@*/
291 memset(buf, 0, *lenp);
293 ret = ioctl (s, SIOCGIFCONF, (char *)&ifc);
295 /*@+matchanyintegral@*/
297 /*@=matchanyintegral@*/
301 /* Solaris uses SIOCGLIFCONF to return struct lifconf which is just
302 an extended version of struct ifconf.
304 HP-UX 11 also appears to have SIOCGLIFCONF, but uses struct
305 if_laddrconf, and struct if_laddrreq to be used with
307 #if defined(SIOCGLIFCONF) && defined(HAVE_STRUCT_LIFCONF)
309 get_lifconf (int af, int s, size_t *lenp, /*@out@*/ char *buf)
310 /*@modifies *buf,*lenp@*/
315 lifc.lifc_family = af;
317 /*@+matchanyintegral@*/
318 lifc.lifc_len = *lenp;
319 /*@=matchanyintegral@*/
321 memset(buf, 0, *lenp);
323 ret = ioctl (s, SIOCGLIFCONF, (char *)&lifc);
325 Tperror ("SIOCGLIFCONF");
327 /*@+matchanyintegral@*/
328 *lenp = lifc.lifc_len;
329 /*@=matchanyintegral@*/
333 #if defined(SIOCGLIFCONF) && defined(HAVE_STRUCT_IF_LADDRCONF) && 0
334 /* I'm not sure if this is needed or if net/if.h will pull it in. */
335 /* #include <net/if6.h> */
337 get_if_laddrconf (int af, int s, size_t *lenp, /*@out@*/ char *buf)
338 /*@modifies *buf,*lenp@*/
341 struct if_laddrconf iflc;
343 /*@+matchanyintegral@*/
344 iflc.iflc_len = *lenp;
345 /*@=matchanyintegral@*/
347 memset(buf, 0, *lenp);
349 ret = ioctl (s, SIOCGLIFCONF, (char *)&iflc);
351 Tperror ("SIOCGLIFCONF");
353 /*@+matchanyintegral@*/
354 *lenp = iflc.iflc_len;
355 /*@=matchanyintegral@*/
359 #endif /* ! HAVE_IFADDRS_H */
361 #ifdef LINUX_IPV6_HACK
363 /* Read IPv6 addresses out of /proc/net/if_inet6, since there isn't
364 (currently) any ioctl to return them. */
365 struct linux_ipv6_addr_list {
366 struct sockaddr_in6 addr;
367 struct linux_ipv6_addr_list *next;
369 static struct linux_ipv6_addr_list *
370 get_linux_ipv6_addrs ()
372 struct linux_ipv6_addr_list *lst = 0;
375 /* _PATH_PROCNET_IFINET6 */
376 f = fopen("/proc/net/if_inet6", "r");
379 unsigned int idx, pfxlen, scope, dadstat;
381 struct linux_ipv6_addr_list *nw;
383 unsigned int addrbyte[16];
387 "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x"
388 " %2x %2x %2x %2x %20s\n",
389 &addrbyte[0], &addrbyte[1], &addrbyte[2], &addrbyte[3],
390 &addrbyte[4], &addrbyte[5], &addrbyte[6], &addrbyte[7],
391 &addrbyte[8], &addrbyte[9], &addrbyte[10], &addrbyte[11],
392 &addrbyte[12], &addrbyte[13], &addrbyte[14],
394 &idx, &pfxlen, &scope, &dadstat, ifname) != EOF) {
395 for (i = 0; i < 16; i++)
396 a6.s6_addr[i] = addrbyte[i];
399 #if 0 /* These symbol names are as used by ifconfig, but none of the
400 system header files export them. Dig up the kernel versions
401 someday and see if they're exported. */
406 case IPV6_ADDR_LINKLOCAL:
407 case IPV6_ADDR_SITELOCAL:
408 case IPV6_ADDR_COMPATv4:
409 case IPV6_ADDR_LOOPBACK:
413 nw = calloc (1, sizeof (struct linux_ipv6_addr_list));
416 nw->addr.sin6_addr = a6;
417 nw->addr.sin6_family = AF_INET6;
418 /* Ignore other fields, we don't actually use them here. */
428 /* Return value is errno if internal stuff failed, otherwise zero,
429 even in the case where a called function terminated the iteration.
431 If one of the callback functions wants to pass back an error
432 indication, it should do it via some field pointed to by the DATA
435 #ifdef HAVE_IFADDRS_H
438 foreach_localaddr (/*@null@*/ void *data,
439 int (*pass1fn) (/*@null@*/ void *, struct sockaddr *) /*@*/,
440 /*@null@*/ int (*betweenfn) (/*@null@*/ void *) /*@*/,
441 /*@null@*/ int (*pass2fn) (/*@null@*/ void *,
442 struct sockaddr *) /*@*/)
443 #if defined(DEBUG) || defined(TEST)
444 /*@modifies fileSystem@*/
447 struct ifaddrs *ifp_head, *ifp, *ifp2;
450 if (getifaddrs (&ifp_head) < 0)
452 for (ifp = ifp_head; ifp; ifp = ifp->ifa_next) {
456 if ((ifp->ifa_flags & IFF_UP) == 0)
458 if (ifp->ifa_addr == NULL) {
459 /* Can't use an interface without an address. Linux
460 apparently does this sometimes. [RT ticket 1770 from
461 Maurice Massar, also Debian bug 206851, shows the
462 problem with a PPP link on a newer kernel than I'm
465 Pretend it's not up, so the second pass will skip
467 ifp->ifa_flags &= ~IFF_UP;
470 if (is_loopback_address(ifp->ifa_addr)) {
471 /* Pretend it's not up, so the second pass will skip
473 ifp->ifa_flags &= ~IFF_UP;
476 /* If this address is a duplicate, punt. */
478 for (ifp2 = ifp_head; ifp2 && ifp2 != ifp; ifp2 = ifp2->ifa_next) {
479 if ((ifp2->ifa_flags & IFF_UP) == 0)
481 if (addr_eq (ifp->ifa_addr, ifp2->ifa_addr)) {
483 ifp->ifa_flags &= ~IFF_UP;
489 if ((*pass1fn) (data, ifp->ifa_addr))
492 if (betweenfn && (*betweenfn)(data))
495 for (ifp = ifp_head; ifp; ifp = ifp->ifa_next) {
496 if (ifp->ifa_flags & IFF_UP)
497 if ((*pass2fn) (data, ifp->ifa_addr))
501 freeifaddrs (ifp_head);
505 #elif defined (SIOCGLIFNUM) && defined(HAVE_STRUCT_LIFCONF) /* Solaris 8 and later; Sol 7? */
508 foreach_localaddr (/*@null@*/ void *data,
509 int (*pass1fn) (/*@null@*/ void *, struct sockaddr *) /*@*/,
510 /*@null@*/ int (*betweenfn) (/*@null@*/ void *) /*@*/,
511 /*@null@*/ int (*pass2fn) (/*@null@*/ void *,
512 struct sockaddr *) /*@*/)
513 #if defined(DEBUG) || defined(TEST)
514 /*@modifies fileSystem@*/
517 /* Okay, this is kind of odd. We have to use each of the address
518 families we care about, because with an AF_INET socket, extra
519 interfaces like hme0:1 that have only AF_INET6 addresses will
520 cause errors. Similarly, if hme0 has more AF_INET addresses
521 than AF_INET6 addresses, we won't be able to retrieve all of
522 the AF_INET addresses if we use an AF_INET6 socket. Since
523 neither family is guaranteed to have the greater number of
524 addresses, we should use both.
526 If it weren't for this little quirk, we could use one socket of
527 any type, and ask for addresses of all types. At least, it
528 seems to work that way. */
530 static const int afs[] = { AF_INET, AF_NS, AF_INET6 };
531 #define N_AFS (sizeof (afs) / sizeof (afs[0]))
537 struct lifnum lifnum;
540 int retval = 0, afidx;
541 krb5_error_code sock_err = 0;
542 struct lifreq *lifr, lifreq, *lifr2;
544 #define FOREACH_AF() for (afidx = 0; afidx < N_AFS; afidx++)
545 #define P (afp[afidx])
554 /* first pass: get raw data, discard uninteresting addresses, callback */
556 Tprintf (("trying af %d...\n", P.af));
557 P.sock = socket (P.af, USE_TYPE, USE_PROTO);
559 sock_err = SOCKET_ERROR;
563 set_cloexec_fd(P.sock);
565 P.lifnum.lifn_family = P.af;
566 P.lifnum.lifn_flags = 0;
567 P.lifnum.lifn_count = 0;
568 code = ioctl (P.sock, SIOCGLIFNUM, &P.lifnum);
570 Tperror ("ioctl(SIOCGLIFNUM)");
575 P.buf_size = P.lifnum.lifn_count * sizeof (struct lifreq) * 2;
576 P.buf = malloc (P.buf_size);
582 code = get_lifconf (P.af, P.sock, &P.buf_size, P.buf);
588 for (i = 0; i + sizeof(*lifr) <= P.buf_size; i+= sizeof (*lifr)) {
589 lifr = (struct lifreq *)((caddr_t) P.buf+i);
591 strncpy(lifreq.lifr_name, lifr->lifr_name,
592 sizeof (lifreq.lifr_name));
593 Tprintf (("interface %s\n", lifreq.lifr_name));
594 /*@-moduncon@*/ /* ioctl unknown to lclint */
595 if (ioctl (P.sock, SIOCGLIFFLAGS, (char *)&lifreq) < 0) {
596 Tperror ("ioctl(SIOCGLIFFLAGS)");
598 /* mark for next pass */
599 lifr->lifr_name[0] = '\0';
604 /* None of the current callers want loopback addresses. */
605 if (is_loopback_address((struct sockaddr *)&lifr->lifr_addr)) {
606 Tprintf ((" loopback\n"));
609 /* Ignore interfaces that are down. */
610 if ((lifreq.lifr_flags & IFF_UP) == 0) {
611 Tprintf ((" down\n"));
615 /* Make sure we didn't process this address already. */
616 for (j = 0; j < i; j += sizeof (*lifr2)) {
617 lifr2 = (struct lifreq *)((caddr_t) P.buf+j);
618 if (lifr2->lifr_name[0] == '\0')
620 if (lifr2->lifr_addr.ss_family == lifr->lifr_addr.ss_family
621 /* Compare address info. If this isn't good enough --
622 i.e., if random padding bytes turn out to differ
623 when the addresses are the same -- then we'll have
624 to do it on a per address family basis. */
625 && !memcmp (&lifr2->lifr_addr, &lifr->lifr_addr,
627 Tprintf ((" duplicate addr\n"));
633 if ((*pass1fn) (data, ss2sa (&lifr->lifr_addr)))
639 /* Did we actually get any working sockets? */
642 goto have_working_socket;
648 if (betweenfn != NULL && (*betweenfn)(data))
655 for (i = 0; i + sizeof (*lifr) <= P.buf_size; i+= sizeof (*lifr)) {
656 lifr = (struct lifreq *)((caddr_t) P.buf+i);
658 if (lifr->lifr_name[0] == '\0')
659 /* Marked in first pass to be ignored. */
663 if ((*pass2fn) (data, ss2sa (&lifr->lifr_addr)))
679 #elif defined (SIOCGLIFNUM) && defined(HAVE_STRUCT_IF_LADDRCONF) && 0 /* HP-UX 11 support being debugged */
682 foreach_localaddr (/*@null@*/ void *data,
683 int (*pass1fn) (/*@null@*/ void *, struct sockaddr *) /*@*/,
684 /*@null@*/ int (*betweenfn) (/*@null@*/ void *) /*@*/,
685 /*@null@*/ int (*pass2fn) (/*@null@*/ void *,
686 struct sockaddr *) /*@*/)
687 #if defined(DEBUG) || defined(TEST)
688 /*@modifies fileSystem@*/
691 /* Okay, this is kind of odd. We have to use each of the address
692 families we care about, because with an AF_INET socket, extra
693 interfaces like hme0:1 that have only AF_INET6 addresses will
694 cause errors. Similarly, if hme0 has more AF_INET addresses
695 than AF_INET6 addresses, we won't be able to retrieve all of
696 the AF_INET addresses if we use an AF_INET6 socket. Since
697 neither family is guaranteed to have the greater number of
698 addresses, we should use both.
700 If it weren't for this little quirk, we could use one socket of
701 any type, and ask for addresses of all types. At least, it
702 seems to work that way. */
704 static const int afs[] = { AF_INET, AF_NS, AF_INET6 };
705 #define N_AFS (sizeof (afs) / sizeof (afs[0]))
714 int retval = 0, afidx;
715 krb5_error_code sock_err = 0;
716 struct if_laddrreq *lifr, lifreq, *lifr2;
718 #define FOREACH_AF() for (afidx = 0; afidx < N_AFS; afidx++)
719 #define P (afp[afidx])
728 /* first pass: get raw data, discard uninteresting addresses, callback */
730 Tprintf (("trying af %d...\n", P.af));
731 P.sock = socket (P.af, USE_TYPE, USE_PROTO);
733 sock_err = SOCKET_ERROR;
737 set_cloexec_fd(P.sock);
739 code = ioctl (P.sock, SIOCGLIFNUM, &P.if_num);
741 Tperror ("ioctl(SIOCGLIFNUM)");
746 P.buf_size = P.if_num * sizeof (struct if_laddrreq) * 2;
747 P.buf = malloc (P.buf_size);
753 code = get_if_laddrconf (P.af, P.sock, &P.buf_size, P.buf);
759 for (i = 0; i + sizeof(*lifr) <= P.buf_size; i+= sizeof (*lifr)) {
760 lifr = (struct if_laddrreq *)((caddr_t) P.buf+i);
762 strncpy(lifreq.iflr_name, lifr->iflr_name,
763 sizeof (lifreq.iflr_name));
764 Tprintf (("interface %s\n", lifreq.iflr_name));
765 /*@-moduncon@*/ /* ioctl unknown to lclint */
766 if (ioctl (P.sock, SIOCGLIFFLAGS, (char *)&lifreq) < 0) {
767 Tperror ("ioctl(SIOCGLIFFLAGS)");
769 /* mark for next pass */
770 lifr->iflr_name[0] = '\0';
775 /* None of the current callers want loopback addresses. */
776 if (is_loopback_address(&lifr->iflr_addr)) {
777 Tprintf ((" loopback\n"));
780 /* Ignore interfaces that are down. */
781 if ((lifreq.iflr_flags & IFF_UP) == 0) {
782 Tprintf ((" down\n"));
786 /* Make sure we didn't process this address already. */
787 for (j = 0; j < i; j += sizeof (*lifr2)) {
788 lifr2 = (struct if_laddrreq *)((caddr_t) P.buf+j);
789 if (lifr2->iflr_name[0] == '\0')
791 if (lifr2->iflr_addr.sa_family == lifr->iflr_addr.sa_family
792 /* Compare address info. If this isn't good enough --
793 i.e., if random padding bytes turn out to differ
794 when the addresses are the same -- then we'll have
795 to do it on a per address family basis. */
796 && !memcmp (&lifr2->iflr_addr, &lifr->iflr_addr,
798 Tprintf ((" duplicate addr\n"));
804 if ((*pass1fn) (data, ss2sa (&lifr->iflr_addr)))
810 /* Did we actually get any working sockets? */
813 goto have_working_socket;
819 if (betweenfn != NULL && (*betweenfn)(data))
826 for (i = 0; i + sizeof(*lifr) <= P.buf_size; i+= sizeof (*lifr)) {
827 lifr = (struct if_laddrreq *)((caddr_t) P.buf+i);
829 if (lifr->iflr_name[0] == '\0')
830 /* Marked in first pass to be ignored. */
834 if ((*pass2fn) (data, ss2sa (&lifr->iflr_addr)))
850 #else /* not defined (SIOCGLIFNUM) */
852 #define SLOP (sizeof (struct ifreq) + 128)
855 get_ifreq_array(char **bufp, size_t *np, int s)
858 int est_if_count = 8;
859 size_t est_ifreq_size;
861 size_t current_buf_size = 0, size, n;
862 #ifdef SIOCGSIZIFCONF
869 /* At least on NetBSD, an ifreq can hold an IPv4 address, but
870 isn't big enough for an IPv6 or ethernet address. So add a
871 little more space. */
872 est_ifreq_size = sizeof (struct ifreq) + 8;
873 #ifdef SIOCGSIZIFCONF
874 code = ioctl (s, SIOCGSIZIFCONF, &ifconfsize);
876 current_buf_size = ifconfsize;
877 est_if_count = ifconfsize / est_ifreq_size;
879 #elif defined (SIOCGIFNUM)
880 code = ioctl (s, SIOCGIFNUM, &numifs);
881 if (!code && numifs > 0)
882 est_if_count = numifs;
884 if (current_buf_size == 0)
885 current_buf_size = est_ifreq_size * est_if_count + SLOP;
886 buf = malloc (current_buf_size);
891 size = current_buf_size;
892 code = get_ifconf (s, &size, buf);
898 /* Test that the buffer was big enough that another ifreq could've
899 fit easily, if the OS wanted to provide one. That seems to be
900 the only indication we get, complicated by the fact that the
901 associated address may make the required storage a little
902 bigger than the size of an ifreq. */
903 if (current_buf_size - size < SLOP
904 #ifdef SIOCGSIZIFCONF
905 /* Unless we hear SIOCGSIZIFCONF is broken somewhere, let's
906 trust the value it returns. */
908 #elif defined (SIOCGIFNUM)
911 /* And we need *some* sort of bounds. */
912 && current_buf_size <= 100000
917 new_size = est_ifreq_size * est_if_count + SLOP;
918 buf = grow_or_free (buf, new_size);
921 current_buf_size = new_size;
926 if (n > current_buf_size)
927 n = current_buf_size;
935 foreach_localaddr (/*@null@*/ void *data,
936 int (*pass1fn) (/*@null@*/ void *, struct sockaddr *) /*@*/,
937 /*@null@*/ int (*betweenfn) (/*@null@*/ void *) /*@*/,
938 /*@null@*/ int (*pass2fn) (/*@null@*/ void *,
939 struct sockaddr *) /*@*/)
940 #if defined(DEBUG) || defined(TEST)
941 /*@modifies fileSystem@*/
944 struct ifreq *ifr, ifreq, *ifr2;
947 size_t size, n, i, j;
949 #ifdef LINUX_IPV6_HACK
950 struct linux_ipv6_addr_list *linux_ipv6_addrs = get_linux_ipv6_addrs ();
951 struct linux_ipv6_addr_list *lx_v6;
954 s = socket (USE_AF, USE_TYPE, USE_PROTO);
959 retval = get_ifreq_array(&buf, &n, s);
961 /*@-moduncon@*/ /* close() unknown to lclint */
967 /* Note: Apparently some systems put the size (used or wanted?)
968 into the start of the buffer, just none that I'm actually
969 using. Fix this when there's such a test system available.
970 The Samba mailing list archives mention that NTP looks for the
971 size on these systems: *-fujitsu-uxp* *-ncr-sysv4*
973 for (i = 0; i + sizeof(struct ifreq) <= n; i+= ifreq_size(*ifr) ) {
974 ifr = (struct ifreq *)((caddr_t) buf+i);
975 /* In case ifreq_size is more than sizeof(). */
976 if (i + ifreq_size(*ifr) > n)
979 strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof (ifreq.ifr_name));
980 Tprintf (("interface %s\n", ifreq.ifr_name));
981 /*@-moduncon@*/ /* ioctl unknown to lclint */
982 if (ioctl (s, SIOCGIFFLAGS, (char *)&ifreq) < 0) {
984 /* mark for next pass */
985 ifr->ifr_name[0] = '\0';
990 /* None of the current callers want loopback addresses. */
991 if (is_loopback_address(&ifreq.ifr_addr)) {
992 Tprintf ((" loopback\n"));
995 /* Ignore interfaces that are down. */
996 if ((ifreq.ifr_flags & IFF_UP) == 0) {
997 Tprintf ((" down\n"));
1001 /* Make sure we didn't process this address already. */
1002 for (j = 0; j < i; j += ifreq_size(*ifr2)) {
1003 ifr2 = (struct ifreq *)((caddr_t) buf+j);
1004 if (ifr2->ifr_name[0] == '\0')
1006 if (ifr2->ifr_addr.sa_family == ifr->ifr_addr.sa_family
1007 && ifreq_size (*ifr) == ifreq_size (*ifr2)
1008 /* Compare address info. If this isn't good enough --
1009 i.e., if random padding bytes turn out to differ
1010 when the addresses are the same -- then we'll have
1011 to do it on a per address family basis. */
1012 && !memcmp (&ifr2->ifr_addr.sa_data, &ifr->ifr_addr.sa_data,
1014 - offsetof (struct ifreq, ifr_addr.sa_data)))) {
1015 Tprintf ((" duplicate addr\n"));
1021 if ((*pass1fn) (data, &ifr->ifr_addr))
1026 #ifdef LINUX_IPV6_HACK
1027 for (lx_v6 = linux_ipv6_addrs; lx_v6; lx_v6 = lx_v6->next)
1028 if ((*pass1fn) (data, (struct sockaddr *) &lx_v6->addr))
1033 if (betweenfn != NULL && (*betweenfn)(data))
1038 for (i = 0; i + sizeof(struct ifreq) <= n; i+= ifreq_size(*ifr) ) {
1039 ifr = (struct ifreq *)((caddr_t) buf+i);
1041 if (ifr->ifr_name[0] == '\0')
1042 /* Marked in first pass to be ignored. */
1046 if ((*pass2fn) (data, &ifr->ifr_addr))
1050 #ifdef LINUX_IPV6_HACK
1051 for (lx_v6 = linux_ipv6_addrs; lx_v6; lx_v6 = lx_v6->next)
1052 if ((*pass2fn) (data, (struct sockaddr *) &lx_v6->addr))
1061 #ifdef LINUX_IPV6_HACK
1062 while (linux_ipv6_addrs) {
1063 lx_v6 = linux_ipv6_addrs->next;
1064 free (linux_ipv6_addrs);
1065 linux_ipv6_addrs = lx_v6;
1072 #endif /* not HAVE_IFADDRS_H and not SIOCGLIFNUM */
1074 static krb5_error_code
1075 get_localaddrs (krb5_context context, krb5_address ***addr, int use_profile);
1079 static int print_addr (/*@unused@*/ void *dataptr, struct sockaddr *sa)
1080 /*@modifies fileSystem@*/
1082 char hostbuf[NI_MAXHOST];
1086 printf (" --> family %2d ", sa->sa_family);
1088 err = getnameinfo (sa, len, hostbuf, (socklen_t) sizeof (hostbuf),
1089 (char *) NULL, 0, NI_NUMERICHOST);
1092 printf ("<getnameinfo error %d: %s>\n", err, gai_strerror (err));
1093 if (err == EAI_SYSTEM)
1094 printf ("\t\t<errno is %d: %s>\n", e, strerror(e));
1096 printf ("addr %s\n", hostbuf);
1104 (void) setvbuf (stdout, (char *)NULL, _IONBF, 0);
1105 r = foreach_localaddr (0, print_addr, NULL, NULL);
1106 printf ("return value = %d\n", r);
1110 #else /* not TESTing */
1112 struct localaddr_data {
1113 int count, mem_err, cur_idx, cur_size;
1114 krb5_address **addr_temp;
1118 count_addrs (void *P_data, struct sockaddr *a)
1121 struct localaddr_data *data = P_data;
1122 switch (a->sa_family) {
1137 allocate (void *P_data)
1140 struct localaddr_data *data = P_data;
1144 n = realloc (data->addr_temp,
1145 (1 + data->count + data->cur_idx) * sizeof (krb5_address *));
1150 data->addr_temp = n;
1151 data->cur_size = 1 + data->count + data->cur_idx;
1152 for (i = data->cur_idx; i <= data->count + data->cur_idx; i++)
1153 data->addr_temp[i] = 0;
1157 static /*@null@*/ krb5_address *
1158 make_addr (int type, size_t length, const void *contents)
1164 data = malloc (length);
1167 a = malloc (sizeof (krb5_address));
1172 memcpy (data, contents, length);
1173 a->magic = KV5M_ADDRESS;
1181 add_addr (void *P_data, struct sockaddr *a)
1182 /*@modifies *P_data@*/
1184 struct localaddr_data *data = P_data;
1185 /*@null@*/ krb5_address *address = 0;
1187 switch (a->sa_family) {
1188 #ifdef HAVE_NETINET_IN_H
1190 address = make_addr (ADDRTYPE_INET, sizeof (struct in_addr),
1191 &((const struct sockaddr_in *) a)->sin_addr);
1192 if (address == NULL)
1198 const struct sockaddr_in6 *in = (const struct sockaddr_in6 *) a;
1200 if (IN6_IS_ADDR_LINKLOCAL (&in->sin6_addr))
1203 address = make_addr (ADDRTYPE_INET6, sizeof (struct in6_addr),
1205 if (address == NULL)
1209 #endif /* netinet/in.h */
1213 address = make_addr (ADDRTYPE_XNS, sizeof (struct ns_addr),
1214 &((const struct sockaddr_ns *)a)->sns_addr);
1215 if (address == NULL)
1221 /* Some BSD-based systems (e.g. NetBSD 1.5) and AIX will
1222 include the ethernet address, but we don't want that, at
1228 * Add more address families here..
1234 /* Redundant but unconditional store un-confuses lclint. */
1235 data->addr_temp[data->cur_idx] = address;
1238 data->addr_temp[data->cur_idx++] = address;
1241 return data->mem_err;
1244 static krb5_error_code
1245 krb5_os_localaddr_profile (krb5_context context, struct localaddr_data *datap)
1247 krb5_error_code err;
1248 static const char *const profile_name[] = {
1249 KRB5_CONF_LIBDEFAULTS, KRB5_CONF_EXTRA_ADDRESSES, 0
1253 krb5_address **newaddrs;
1256 fprintf (stderr, "looking up extra_addresses foo\n");
1259 err = profile_get_values (context->profile, profile_name, &values);
1260 /* Ignore all errors for now? */
1264 for (iter = values; *iter; iter++) {
1265 char *cp = *iter, *next, *current;
1269 fprintf (stderr, " found line: '%s'\n", cp);
1272 for (cp = *iter, next = 0; *cp; cp = next) {
1273 while (isspace ((int) *cp) || *cp == ',')
1277 /* Start of an address. */
1279 fprintf (stderr, " addr found in '%s'\n", cp);
1282 while (*cp != 0 && !isspace((int) *cp) && *cp != ',')
1289 /* Got a single address, process it. */
1291 fprintf (stderr, " processing '%s'\n", current);
1294 err = krb5_os_hostaddr (context, current, &newaddrs);
1297 for (i = 0; newaddrs[i]; i++) {
1299 fprintf (stderr, " %d: family %d", i,
1300 newaddrs[i]->addrtype);
1301 fprintf (stderr, "\n");
1306 fprintf (stderr, " %d addresses\n", count);
1308 if (datap->cur_idx + count >= datap->cur_size) {
1309 krb5_address **bigger;
1310 bigger = realloc (datap->addr_temp,
1311 sizeof (krb5_address *) * (datap->cur_idx + count));
1313 datap->addr_temp = bigger;
1314 datap->cur_size = datap->cur_idx + count;
1317 for (i = 0; i < count; i++) {
1318 if (datap->cur_idx < datap->cur_size)
1319 datap->addr_temp[datap->cur_idx++] = newaddrs[i];
1321 free (newaddrs[i]->contents), free (newaddrs[i]);
1329 krb5_error_code KRB5_CALLCONV
1330 krb5_os_localaddr(krb5_context context, krb5_address ***addr)
1332 return get_localaddrs(context, addr, 1);
1335 #if 0 /* not actually used anywhere currently */
1337 krb5int_local_addresses(krb5_context context, krb5_address ***addr)
1339 return get_localaddrs(context, addr, 0);
1343 static krb5_error_code
1344 get_localaddrs (krb5_context context, krb5_address ***addr, int use_profile)
1346 struct localaddr_data data = { 0 };
1348 krb5_error_code err;
1351 err = krb5_os_localaddr_profile (context, &data);
1352 /* ignore err for now */
1355 r = foreach_localaddr (&data, count_addrs, allocate, add_addr);
1358 if (data.addr_temp) {
1359 for (i = 0; i < data.count; i++)
1360 free (data.addr_temp[i]);
1361 free (data.addr_temp);
1369 data.cur_idx++; /* null termination */
1372 else if (data.cur_idx == data.count)
1373 *addr = data.addr_temp;
1375 /* This can easily happen if we have IPv6 link-local
1376 addresses. Just shorten the array. */
1377 *addr = (krb5_address **) realloc (data.addr_temp,
1378 (sizeof (krb5_address *)
1381 /* Okay, shortening failed, but the original should still
1383 *addr = data.addr_temp;
1389 fprintf (stderr, "addresses:\n");
1390 for (j = 0; addr[0][j]; j++) {
1391 struct sockaddr_storage ss;
1393 char namebuf[NI_MAXHOST];
1396 fprintf (stderr, "%2d: ", j);
1397 fprintf (stderr, "addrtype %2d, length %2d", addr[0][j]->addrtype,
1398 addr[0][j]->length);
1399 memset (&ss, 0, sizeof (ss));
1400 switch (addr[0][j]->addrtype) {
1403 struct sockaddr_in *sinp = ss2sin (&ss);
1404 sinp->sin_family = AF_INET;
1405 addrp = &sinp->sin_addr;
1407 sinp->sin_len = sizeof (struct sockaddr_in);
1411 case ADDRTYPE_INET6:
1413 struct sockaddr_in6 *sin6p = ss2sin6 (&ss);
1414 sin6p->sin6_family = AF_INET6;
1415 addrp = &sin6p->sin6_addr;
1417 sin6p->sin6_len = sizeof (struct sockaddr_in6);
1422 ss2sa(&ss)->sa_family = 0;
1426 memcpy (addrp, addr[0][j]->contents, addr[0][j]->length);
1427 err2 = getnameinfo (ss2sa(&ss), socklen (ss2sa (&ss)),
1428 namebuf, sizeof (namebuf), 0, 0,
1431 fprintf (stderr, ": addr %s\n", namebuf);
1433 fprintf (stderr, ": getnameinfo error %d\n", err2);
1441 #endif /* not TESTing */
1443 #else /* Windows/Mac version */
1446 * Hold on to your lunch! Backup kludge method of obtaining your
1447 * local IP address, courtesy of Windows Socket Network Programming,
1451 static struct hostent *local_addr_fallback_kludge()
1453 static struct hostent host;
1454 static SOCKADDR_IN addr;
1455 static char * ip_ptrs[2];
1457 int size = sizeof(SOCKADDR);
1460 sock = socket(AF_INET, SOCK_DGRAM, 0);
1461 if (sock == INVALID_SOCKET)
1463 set_cloexec_fd(sock);
1465 /* connect to arbitrary port and address (NOT loopback) */
1466 addr.sin_family = AF_INET;
1467 addr.sin_port = htons(IPPORT_ECHO);
1468 addr.sin_addr.s_addr = inet_addr("204.137.220.51");
1470 err = connect(sock, (LPSOCKADDR) &addr, sizeof(SOCKADDR));
1471 if (err == SOCKET_ERROR)
1474 err = getsockname(sock, (LPSOCKADDR) &addr, (int *) size);
1475 if (err == SOCKET_ERROR)
1482 host.h_addrtype = AF_INET;
1484 host.h_addr_list = ip_ptrs;
1485 ip_ptrs[0] = (char *) &addr.sin_addr.s_addr;
1492 /* No ioctls in winsock so we just assume there is only one networking
1493 * card per machine, so gethostent is good enough.
1495 krb5_error_code KRB5_CALLCONV
1496 krb5_os_localaddr (krb5_context context, krb5_address ***addr) {
1497 char host[64]; /* Name of local machine */
1498 struct hostent *hostrec;
1500 krb5_address ** paddr;
1506 if (gethostname (host, sizeof(host))) {
1511 hostrec = gethostbyname (host);
1512 if (hostrec == NULL) {
1518 hostrec = local_addr_fallback_kludge();
1522 err = 0; /* otherwise we will die at cleanup */
1525 for (count = 0; hostrec->h_addr_list[count]; count++);
1528 paddr = (krb5_address **)calloc(count+1, sizeof(krb5_address *));
1534 for (i = 0; i < count; i++) {
1535 paddr[i] = (krb5_address *)malloc(sizeof(krb5_address));
1536 if (paddr[i] == NULL) {
1541 paddr[i]->magic = KV5M_ADDRESS;
1542 paddr[i]->addrtype = hostrec->h_addrtype;
1543 paddr[i]->length = hostrec->h_length;
1544 paddr[i]->contents = (unsigned char *)malloc(paddr[i]->length);
1545 if (!paddr[i]->contents) {
1549 memcpy(paddr[i]->contents,
1550 hostrec->h_addr_list[i],
1557 for (i = 0; i < count; i++)
1560 if (paddr[i]->contents)
1561 free(paddr[i]->contents);