getifaddrs() support
authorKen Raeburn <raeburn@mit.edu>
Tue, 10 Oct 2000 15:24:22 +0000 (15:24 +0000)
committerKen Raeburn <raeburn@mit.edu>
Tue, 10 Oct 2000 15:24:22 +0000 (15:24 +0000)
git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@12751 dc483132-0cff-0310-8789-dd5450dbe970

src/lib/krb5/configure.in
src/lib/krb5/os/ChangeLog
src/lib/krb5/os/Makefile.in
src/lib/krb5/os/localaddr.c

index ce4f84c113c42bcd061f6f8e8982659ea4fd4606..ae8c7f4ff00d78ee938fd40cfcd99e4a8082b001 100644 (file)
@@ -8,8 +8,8 @@ AC_TYPE_UID_T
 AC_TYPE_OFF_T
 HAS_ANSI_VOLATILE
 AC_HEADER_STDARG
-AC_CHECK_HEADERS(unistd.h paths.h regex.h regexp.h regexpr.h fcntl.h memory.h)
-AC_CHECK_FUNCS(flock fchmod chmod strftime strptime geteuid setenv unsetenv getenv setsid gethostbyname2)
+AC_CHECK_HEADERS(unistd.h paths.h regex.h regexp.h regexpr.h fcntl.h memory.h ifaddrs.h)
+AC_CHECK_FUNCS(flock fchmod chmod strftime strptime geteuid setenv unsetenv getenv setsid gethostbyname2 getifaddrs)
 AC_REPLACE_FUNCS(vfprintf vsprintf strdup strcasecmp strerror memmove daemon getuid sscanf syslog)
 KRB5_AC_REGEX_FUNCS
 dnl
index 31cf7e25ee9d441c6f82fdbed91a90a89b25b7b8..6a337cc8f9e6cd077a46641aef57c3ab1bfa2924 100644 (file)
@@ -1,3 +1,17 @@
+2000-10-09  Ken Raeburn  <raeburn@mit.edu>
+
+       Support for getifaddrs() interface added in BSD.
+       * localaddr.c (printaddr, printifaddr) [HAVE_IFADDRS_H && DEBUG]:
+       New functions for debugging new ifaddrs code.
+       (addr_eq) [HAVE_IFADDRS_H]: New function, for comparing addresses
+       found with getifaddrs.
+       (foreach_localaddr) [HAVE_IFADDRS_H]: New implementation, relies
+       on C library function to retrieve data.
+       (foreach_localaddr) [!HAVE_IFADDRS_H && TEST]: Print info about
+       each address and why it might not be used.
+       (print_addr, main) [TEST]: Print out the local addresses.
+       * Makefile.in (t_localaddr): New target.
+
 2000-09-26  Ezra Peisach  <epeisach@mit.edu>
 
        * an_to_ln.c: Unsigned vs signed int fixes.
index 05775c41b02963a03d521a9abecc1e27e6bdb98c..a850474162742a447f39132cc3838d050440eefe 100644 (file)
@@ -166,6 +166,9 @@ t_an_to_ln: $(T_AN_TO_LN_OBJS) $(KRB5_BASE_DEPLIBS)
 t_realm_iter: $(T_REALM_ITER_OBJS) $(KRB5_BASE_DEPLIBS)
        $(CC_LINK) -o t_realm_iter $(T_REALM_ITER_OBJS) $(KRB5_BASE_LIBS)
 
+t_localaddr: localaddr.c
+       $(CC) $(ALL_CFLAGS) -DTEST -o t_localaddr $(srcdir)/localaddr.c
+
 check-unix:: $(TEST_PROGS)
        KRB5_CONFIG=$(srcdir)/td_krb5.conf ; export KRB5_CONFIG ;\
        $(KRB5_RUN_ENV) ./t_std_conf  -d -s NEW.DEFAULT.REALM -d \
index d5b46b664157bcd2b974169003b7a054009cc4d6..170b7f2c2d0304f06d98dd474c8a6065c60e847d 100644 (file)
@@ -249,13 +249,147 @@ add_addr (void *P_data, struct sockaddr *a)
 #define ifreq_size(i) sizeof(struct ifreq)
 #endif /* HAVE_SA_LEN*/
 
+#ifdef HAVE_IFADDRS_H
+#include <ifaddrs.h>
+
+#ifdef DEBUG
+#include <netinet/in.h>
+#include <net/if.h>
+
+void printaddr (struct sockaddr *sa)
+{
+    char buf[50];
+    printf ("%p ", sa);
+    switch (sa->sa_family) {
+    case AF_INET:
+       inet_ntop (AF_INET, &((struct sockaddr_in *)sa)->sin_addr,
+                  buf, sizeof (buf));
+       printf ("inet %s", buf);
+       break;
+    case AF_INET6:
+       inet_ntop (AF_INET6, &((struct sockaddr_in6 *)sa)->sin6_addr,
+                  buf, sizeof (buf));
+       printf ("inet6 %s", buf);
+       break;
+    default:
+       printf ("family=%d", sa->sa_family);
+       break;
+    }
+}
+
+void printifaddr (struct ifaddrs *ifp)
+{
+    printf ("%p={\n", ifp);
+/*  printf ("\tnext=%p\n", ifp->ifa_next); */
+    printf ("\tname=%s\n", ifp->ifa_name);
+    printf ("\tflags=");
+    {
+       int ch, flags = ifp->ifa_flags;
+       printf ("%x", flags);
+       ch = '<';
+#define X(F) if (flags & IFF_##F) { printf ("%c%s", ch, #F); flags &= ~IFF_##F; ch = ','; }
+       X (UP); X (BROADCAST); X (DEBUG); X (LOOPBACK); X (POINTOPOINT);
+       X (NOTRAILERS); X (RUNNING); X (NOARP); X (PROMISC); X (ALLMULTI);
+       X (OACTIVE); X (SIMPLEX); X (MULTICAST);
+       printf (">");
+#undef X
+    }
+    if (ifp->ifa_addr)
+       printf ("\n\taddr="), printaddr (ifp->ifa_addr);
+    if (ifp->ifa_netmask)
+       printf ("\n\tnetmask="), printaddr (ifp->ifa_netmask);
+    if (ifp->ifa_broadaddr)
+       printf ("\n\tbroadaddr="), printaddr (ifp->ifa_broadaddr);
+    if (ifp->ifa_dstaddr)
+       printf ("\n\tdstaddr="), printaddr (ifp->ifa_dstaddr);
+    if (ifp->ifa_data)
+       printf ("\n\tdata=%p", ifp->ifa_data);
+    printf ("\n}\n");
+}
+#endif /* DEBUG */
+
 static int
-foreach_localaddr (data, pass1fn, betweenfn, pass2fn)
-    void *data;
-    int (*pass1fn) (void *, struct sockaddr *);
-    int (*betweenfn) (void *);
-    int (*pass2fn) (void *, struct sockaddr *);
+addr_eq (const struct sockaddr *s1, const struct sockaddr *s2)
 {
+    if (s1->sa_family != s2->sa_family)
+       return 0;
+#ifdef HAVE_SA_LEN
+    if (s1->sa_len != s2->sa_len)
+       return 0;
+    return !memcmp (s1, s2, s1->sa_len);
+#else
+#define CMPTYPE(T,F) (!memcmp(&((T*)s1)->F,&((T*)s2)->F,sizeof(((T*)s1)->F)))
+    switch (s1->sa_family) {
+    case AF_INET:
+       return CMPTYPE (struct sockaddr_in, sin_addr);
+    case AF_INET6:
+       return CMPTYPE (struct sockaddr_in6, sin6_addr);
+    default:
+       /* Err on side of duplicate listings.  */
+       return 0;
+    }
+#endif
+}
+#endif
+
+static int
+foreach_localaddr (void *data,
+                  int (*pass1fn) (void *, struct sockaddr *),
+                  int (*betweenfn) (void *),
+                  int (*pass2fn) (void *, struct sockaddr *))
+{
+#ifdef HAVE_IFADDRS_H
+    struct ifaddrs *ifp_head, *ifp, *ifp2;
+    int match, fail = 0;
+
+    if (getifaddrs (&ifp_head) < 0)
+       return errno;
+    for (ifp = ifp_head; ifp; ifp = ifp->ifa_next) {
+#ifdef DEBUG
+       printifaddr (ifp);
+#endif
+       if ((ifp->ifa_flags & IFF_UP) == 0)
+           continue;
+       if (ifp->ifa_flags & IFF_LOOPBACK) {
+           ifp->ifa_flags &= ~IFF_UP;
+           continue;
+       }
+       /* If this address is a duplicate, punt.  */
+       match = 0;
+       for (ifp2 = ifp_head; ifp2 && ifp2 != ifp; ifp2 = ifp2->ifa_next) {
+           if ((ifp2->ifa_flags & IFF_UP) == 0)
+               continue;
+           if (ifp2->ifa_flags & IFF_LOOPBACK)
+               continue;
+           if (addr_eq (ifp->ifa_addr, ifp2->ifa_addr)) {
+               match = 1;
+               ifp->ifa_flags &= ~IFF_UP;
+               break;
+           }
+       }
+       if (match)
+           continue;
+       if ((*pass1fn) (data, ifp->ifa_addr)) {
+           fail = 1;
+           goto punt;
+       }
+    }
+    if (betweenfn && (*betweenfn)(data)) {
+       fail = 1;
+       goto punt;
+    }
+    if (pass2fn)
+       for (ifp = ifp_head; ifp; ifp = ifp->ifa_next) {
+           if (ifp->ifa_flags & IFF_UP)
+               if ((*pass2fn) (data, ifp->ifa_addr)) {
+                   fail = 1;
+                   goto punt;
+               }
+       }
+ punt:
+    freeifaddrs (ifp_head);
+    return fail;
+#else
     struct ifreq *ifr, ifreq, *ifr2;
     struct ifconf ifc;
     int s, code, n, i, j;
@@ -329,22 +463,32 @@ foreach_localaddr (data, pass1fn, betweenfn, pass2fn)
        ifr = (struct ifreq *)((caddr_t) ifc.ifc_buf+i);
 
        strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof (ifreq.ifr_name));
+#ifdef TEST
+       printf ("interface %s\n", ifreq.ifr_name);
+#endif
        if (ioctl (s, SIOCGIFFLAGS, (char *)&ifreq) < 0) {
        skip:
            /* mark for next pass */
            ifr->ifr_name[0] = 0;
-
            continue;
        }
 
 #ifdef IFF_LOOPBACK
            /* None of the current callers want loopback addresses.  */
-       if (ifreq.ifr_flags & IFF_LOOPBACK)
+       if (ifreq.ifr_flags & IFF_LOOPBACK) {
+#ifdef TEST
+           printf ("loopback\n");
+#endif
            goto skip;
+       }
 #endif
        /* Ignore interfaces that are down.  */
-       if (!(ifreq.ifr_flags & IFF_UP))
+       if (!(ifreq.ifr_flags & IFF_UP)) {
+#ifdef TEST
+           printf ("down\n");
+#endif
            goto skip;
+       }
 
        /* Make sure we didn't process this address already.  */
        for (j = 0; j < i; j += ifreq_size(*ifr2)) {
@@ -359,8 +503,12 @@ foreach_localaddr (data, pass1fn, betweenfn, pass2fn)
                   to do it on a per address family basis.  */
                && !memcmp (&ifr2->ifr_addr.sa_data, &ifr->ifr_addr.sa_data,
                            (ifreq_size (*ifr)
-                            - offsetof (struct ifreq, ifr_addr.sa_data))))
+                            - offsetof (struct ifreq, ifr_addr.sa_data)))) {
+#ifdef TEST
+               printf ("duplicate addr\n");
+#endif
                goto skip;
+           }
        }
 
        if ((*pass1fn) (data, &ifr->ifr_addr)) {
@@ -392,9 +540,48 @@ foreach_localaddr (data, pass1fn, betweenfn, pass2fn)
     free (buf);
 
     return fail;
+#endif /* not HAVE_IFADDRS_H */
 }
 
+#ifdef TEST
 
+int print_addr (void *dataptr, struct sockaddr *sa)
+{
+    char buf[50];
+    printf ("family %d", sa->sa_family);
+    switch (sa->sa_family) {
+    case AF_INET:
+       printf (" addr %s\n",
+               inet_ntoa (((struct sockaddr_in *)sa)->sin_addr));
+       break;
+    case AF_INET6:
+       printf (" addr %s\n",
+               inet_ntop (sa->sa_family,
+                          &((struct sockaddr_in6 *)sa)->sin6_addr,
+                          buf, sizeof (buf)));
+       break;
+#ifdef AF_LINK
+    case AF_LINK:
+       printf (" linkaddr\n");
+       break;
+#endif
+    default:
+       printf (" don't know how to print addr\n");
+       break;
+    }
+    return 0;
+}
+
+int main ()
+{
+    int r;
+
+    r = foreach_localaddr (0, print_addr, 0, 0);
+    printf ("return value = %d\n", r);
+    return 0;
+}
+
+#else /* not TESTing */
 
 KRB5_DLLIMP krb5_error_code KRB5_CALLCONV
 krb5_os_localaddr(context, addr)
@@ -437,6 +624,8 @@ krb5_os_localaddr(context, addr)
     return 0;
 }
 
+#endif /* not TESTing */
+
 #else /* Windows/Mac version */
 
 /*