siocgifconf-check-structure-length-field   [plain text]


Index: samba/source/configure.in
===================================================================
--- samba/source/configure.in.orig
+++ samba/source/configure.in
@@ -2833,6 +2833,25 @@ AC_CHECK_FUNCS(getpagesize)
 ##################
 # look for a method of finding the list of network interfaces
 iface=no;
+
+AC_CACHE_CHECK([for iface getifaddrs],samba_cv_HAVE_IFACE_GETIFADDRS,[
+SAVE_CPPFLAGS="$CPPFLAGS"
+CPPFLAGS="$CPPFLAGS ${SAMBA_CONFIGURE_CPPFLAGS}"
+AC_TRY_RUN([
+#define HAVE_IFACE_GETIFADDRS 1
+#define AUTOCONF_TEST 1
+#undef _XOPEN_SOURCE_EXTENDED
+#include "${srcdir-.}/lib/interfaces.c"],
+           samba_cv_HAVE_IFACE_GETIFADDRS=yes,
+	   samba_cv_HAVE_IFACE_GETIFADDRS=no,
+	   samba_cv_HAVE_IFACE_GETIFADDRS=cross)])
+CPPFLAGS="$SAVE_CPPFLAGS"
+if test x"$samba_cv_HAVE_IFACE_GETIFADDRS" = x"yes"; then
+    iface=yes
+    AC_DEFINE(HAVE_IFACE_GETIFADDRS, 1,
+	    [Whether iface getifaddrs is available])
+fi
+
 AC_CACHE_CHECK([for iface AIX],samba_cv_HAVE_IFACE_AIX,[
 SAVE_CPPFLAGS="$CPPFLAGS"
 CPPFLAGS="$CPPFLAGS ${SAMBA_CONFIGURE_CPPFLAGS}"
Index: samba/source/lib/interfaces.c
===================================================================
--- samba/source/lib/interfaces.c.orig
+++ samba/source/lib/interfaces.c
@@ -2,6 +2,7 @@
    Unix SMB/CIFS implementation.
    return a list of network interfaces
    Copyright (C) Andrew Tridgell 1998
+   Copyright (C) 2007 Apple Inc. All rights reserved.
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -82,6 +83,62 @@
 
 #include "interfaces.h"
 
+#ifdef HAVE_IFACE_GETIFADDRS
+
+#ifdef HAVE_IFADDRS_H
+#include <ifaddrs.h>
+#endif
+
+/* This works for modern BSD systems, including Mac OS X. */
+static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
+{
+	struct ifaddrs *addrlist;
+	struct ifaddrs *addr;
+	int count = 0;
+
+	if (getifaddrs(&addrlist) == -1) {
+		return -1;
+	}
+
+	for (addr = addrlist; addr; addr = addr->ifa_next) {
+
+		if (addr->ifa_addr == NULL ||
+		    addr->ifa_netmask == NULL) {
+			continue;
+		}
+
+		if (addr->ifa_addr->sa_family != AF_INET) {
+			continue;
+		}
+
+		if (!(addr->ifa_flags & IFF_UP)) {
+			continue;
+		}
+
+#define SOCKADDR_TO_INADDR(sa) (((struct sockaddr_in *)sa)->sin_addr)
+
+		ifaces[count].ip = SOCKADDR_TO_INADDR(addr->ifa_addr);
+		ifaces[count].netmask = SOCKADDR_TO_INADDR(addr->ifa_netmask);
+
+#undef SOCKADDR_TO_INADDR(sa)
+
+		strncpy(ifaces[count].name, addr->ifa_name,
+			sizeof(ifaces[count].name) - 1);
+		ifaces[count].name[sizeof(ifaces[count].name) - 1] = 0;
+
+		if (++count >= max_interfaces) {
+			break;
+		}
+	}
+
+	freeifaddrs(addrlist);
+	return count;
+}
+
+#define _FOUND_IFACE_ANY
+#endif /* HAVE_IFACE_GETIFADDRS */
+
+
 #if HAVE_IFACE_IFCONF
 
 /* this works for Linux 2.2, Solaris 2.5, SunOS4, HPUX 10.20, OSF1
@@ -96,8 +153,8 @@ static int _get_interfaces(struct iface_
 {  
 	struct ifconf ifc;
 	char buff[8192];
-	int fd, i, n;
-	struct ifreq *ifr=NULL;
+	char current;
+	int fd;
 	int total = 0;
 	struct in_addr ipaddr;
 	struct in_addr nmask;
@@ -114,33 +171,52 @@ static int _get_interfaces(struct iface_
 		close(fd);
 		return -1;
 	} 
-
-	ifr = ifc.ifc_req;
   
-	n = ifc.ifc_len / sizeof(struct ifreq);
-
 	/* Loop through interfaces, looking for given IP address */
-	for (i=n-1;i>=0 && total < max_interfaces;i--) {
-		if (ioctl(fd, SIOCGIFADDR, &ifr[i]) != 0) {
+	for (current = buf;
+	     current < ifc.ifc_len && total < max_interfaces;) {
+		struct ifreq *ifr = (struct ifref *)current;
+
+		/* Point current to the next ifreq. The ifreq list is not
+		 * actually an array. The structures are packed in the buffer
+		 * and their size varies depending on the type of address, so
+		 * we have to look as the sockaddr length to figure it out.
+		 */
+#ifdef _SIZEOF_ADDR_IFREQ(ifr)
+		/* 4.4 BSD introduced sockaddr.sa_len which lets us figure out
+		 * the real size.
+		 */
+		current += _SIZEOF_ADDR_IFREQ(ifr);
+#else
+		/* Earlier systems should have a fixed size sockaddr. */
+		current += sizeof(struct ifreq);
+#endif
+
+		/* We only support IPv4. */
+		if (ifr->ifr_addr.sa_family != AF_INET) {
 			continue;
 		}
 
-		iname = ifr[i].ifr_name;
-		ipaddr = (*(struct sockaddr_in *)&ifr[i].ifr_addr).sin_addr;
+		if (ioctl(fd, SIOCGIFADDR, ifr) != 0) {
+			continue;
+		}
+
+		iname = ifr->ifr_name;
+		ipaddr = (*(struct sockaddr_in *)ifr->ifr_addr).sin_addr;
 
-		if (ioctl(fd, SIOCGIFFLAGS, &ifr[i]) != 0) {
+		if (ioctl(fd, SIOCGIFFLAGS, ifr) != 0) {
 			continue;
 		}  
 
-		if (!(ifr[i].ifr_flags & IFF_UP)) {
+		if (!(ifr->fr_flags & IFF_UP)) {
 			continue;
 		}
 
-		if (ioctl(fd, SIOCGIFNETMASK, &ifr[i]) != 0) {
+		if (ioctl(fd, SIOCGIFNETMASK, ifr) != 0) {
 			continue;
 		}  
 
-		nmask = ((struct sockaddr_in *)&ifr[i].ifr_addr)->sin_addr;
+		nmask = ((struct sockaddr_in *)ifr->fr_addr)->sin_addr;
 
 		strncpy(ifaces[total].name, iname, sizeof(ifaces[total].name)-1);
 		ifaces[total].name[sizeof(ifaces[total].name)-1] = 0;
Index: samba/source/lib/replace/libreplace.m4
===================================================================
--- samba/source/lib/replace/libreplace.m4.orig
+++ samba/source/lib/replace/libreplace.m4
@@ -99,6 +99,7 @@ AC_CHECK_HEADERS(stdarg.h vararg.h)
 AC_CHECK_HEADERS(sys/socket.h netinet/in.h netdb.h arpa/inet.h)
 AC_CHECK_HEADERS(netinet/ip.h netinet/tcp.h netinet/in_systm.h netinet/in_ip.h)
 AC_CHECK_HEADERS(sys/sockio.h sys/un.h)
+AC_CHECK_HEADERS(ifaddrs.h)
 
 
 dnl we need to check that net/if.h really can be used, to cope with hpux
Index: samba/source/tests/summary.c
===================================================================
--- samba/source/tests/summary.c.orig
+++ samba/source/tests/summary.c
@@ -7,7 +7,7 @@ main()
 	exit(1);
 #endif
 
-#if !(defined(HAVE_IFACE_IFCONF) || defined(HAVE_IFACE_IFREQ) || defined(HAVE_IFACE_AIX))
+#if !(defined(HAVE_IFACE_IFCONF) || defined(HAVE_IFACE_IFREQ) || defined(HAVE_IFACE_AIX) || defined(HAVE_IFACE_GETIFADDRS))
 	printf("WARNING: No automated network interface determination\n");
 #endif