siocgifconf-check-structure-length-field [plain text]
Index: samba/source/configure.in
===================================================================
--- samba/source/configure.in.orig
+++ samba/source/configure.in
@@ -2852,6 +2852,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,8 +99,10 @@ 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)
AC_CHECK_HEADERS(stropts.h)
+
dnl we need to check that net/if.h really can be used, to cope with hpux
dnl where including it always fails
AC_CACHE_CHECK([for usable net/if.h],libreplace_cv_USABLE_NET_IF_H,[
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