From: Jeremy Allison Date: Tue, 2 Oct 2007 19:27:25 +0000 (+0000) Subject: r25472: Fix the interfaces code to detect IPv6 interfaces, using the X-Git-Url: http://git.samba.org/samba.git/?a=commitdiff_plain;h=3fbd1ae54ced2eb889a8fe0a6ea32dfd8175f941;p=kai%2Fsamba.git r25472: Fix the interfaces code to detect IPv6 interfaces, using the new standard getifaddrs() and freeifaddrs() interfaces. Currently we only return IPv4 af_families. Needs fixing for binds to IPv6 but this has to be careful work. Jeremy. (This used to be commit 327875182c9219aeba687e10aaea93546d9a70ea) --- diff --git a/source3/configure.in b/source3/configure.in index 561d4c6e0e4..919cfc93dc3 100644 --- a/source3/configure.in +++ b/source3/configure.in @@ -995,7 +995,7 @@ AC_CHECK_HEADERS(limits.h float.h pthread.h) AC_CHECK_HEADERS(rpc/rpc.h rpcsvc/nis.h rpcsvc/ypclnt.h) AC_CHECK_HEADERS(sys/param.h ctype.h sys/wait.h sys/resource.h sys/ioctl.h sys/ipc.h sys/prctl.h) AC_CHECK_HEADERS(sys/mman.h sys/filio.h sys/priv.h sys/shm.h string.h strings.h stdlib.h sys/socket.h) -AC_CHECK_HEADERS(sys/un.h) +AC_CHECK_HEADERS(sys/un.h ifaddrs.h) AC_CHECK_HEADERS(sys/mount.h sys/vfs.h sys/fs/s5param.h sys/filsys.h termios.h termio.h) AC_CHECK_HEADERS(sys/termio.h sys/statfs.h sys/dustat.h sys/statvfs.h stdarg.h sys/sockio.h) AC_CHECK_HEADERS(sys/sysmacros.h) @@ -1082,6 +1082,7 @@ AC_CHECK_TYPE(loff_t,off_t) AC_CHECK_TYPE(offset_t,loff_t) AC_CHECK_TYPE(ssize_t, int) AC_CHECK_TYPE(wchar_t, unsigned short) +AC_CHECK_TYPE(socklen_t, int) AC_CHECK_TYPE(comparison_fn_t, [AC_DEFINE(HAVE_COMPARISON_FN_T, 1,[Whether or not we have comparison_fn_t])]) @@ -3038,6 +3039,42 @@ SMB_CHECK_SYSCONF(_SC_NPROCESSORS_ONLN) SMB_CHECK_SYSCONF(_SC_PAGESIZE) AC_CHECK_FUNCS(getpagesize) +dnl test for sa_family_t +AC_CACHE_CHECK([for sa_family_t],samba_cv_HAVE_SA_FAMILY_T,[ +AC_TRY_COMPILE([ +#include +#include +#include +#include +], +[ +sa_family_t foo; +], +samba_cv_HAVE_SA_FAMILY_T=yes,samba_cv_HAVE_SA_FAMILY_T=no)]) +if test x"$samba_cv_HAVE_SA_FAMILY_T" = x"yes"; then + AC_DEFINE(HAVE_SA_FAMILY_T,1,[Whether the system has sa_family_t]) +fi + +dnl test for getifaddrs and freeifaddrs +AC_CACHE_CHECK([for getifaddrs and freeifaddrs],samba_cv_HAVE_GETIFADDRS,[ +AC_TRY_COMPILE([ +#include +#include +#include +#include +#include +#include ], +[ +struct ifaddrs *ifp = NULL; +int ret = getifaddrs (&ifp); +freeifaddrs(ifp); +], +samba_cv_HAVE_GETIFADDRS=yes,samba_cv_HAVE_GETIFADDRS=no)]) +if test x"$samba_cv_HAVE_GETIFADDRS" = x"yes"; then + AC_DEFINE(HAVE_GETIFADDRS,1,[Whether the system has getifaddrs]) + AC_DEFINE(HAVE_FREEIFADDRS,1,[Whether the system has freeifaddrs]) +fi + ################## # look for a method of finding the list of network interfaces iface=no; @@ -3055,6 +3092,21 @@ if test x"$samba_cv_HAVE_IFACE_AIX" = x"yes"; then iface=yes;AC_DEFINE(HAVE_IFACE_AIX,1,[Whether iface AIX is available]) fi +if test $iface = no; then +AC_CACHE_CHECK([for iface getifaddrs],samba_cv_HAVE_GETIFADDRS,[ +SAVE_CPPFLAGS="$CPPFLAGS" +CPPFLAGS="$CPPFLAGS ${SAMBA_CONFIGURE_CPPFLAGS}" +AC_TRY_RUN([ +#define HAVE_IFACE_GETIFADDRS 1 +#define AUTOCONF_TEST 1 +#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 ifconf is available]) +fi +fi + if test $iface = no; then AC_CACHE_CHECK([for iface ifconf],samba_cv_HAVE_IFACE_IFCONF,[ SAVE_CPPFLAGS="$CPPFLAGS" diff --git a/source3/include/includes.h b/source3/include/includes.h index 4f11e7a0932..b084eed40cd 100644 --- a/source3/include/includes.h +++ b/source3/include/includes.h @@ -1262,4 +1262,8 @@ void exit_server_fault(void) NORETURN_ATTRIBUTE ; #include "libnscd.h" #endif +#ifndef HAVE_SA_FAMILY_T +typedef unsigned short int sa_family_t; +#endif + #endif /* _INCLUDES_H */ diff --git a/source3/include/interfaces.h b/source3/include/interfaces.h index 3b786f1ebcb..371f64292f6 100644 --- a/source3/include/interfaces.h +++ b/source3/include/interfaces.h @@ -7,6 +7,17 @@ struct iface_struct { char name[16]; - struct in_addr ip; - struct in_addr netmask; + sa_family_t sa_family; + union { + struct in_addr ip; +#ifdef AF_INET6 + struct in6_addr ip6; +#endif + } iface_addr; + union { + struct in_addr netmask; +#ifdef AF_INET6 + struct in6_addr netmask6; +#endif + } iface_netmask; }; diff --git a/source3/lib/interface.c b/source3/lib/interface.c index 29ed15a0c26..c1875839239 100644 --- a/source3/lib/interface.c +++ b/source3/lib/interface.c @@ -103,12 +103,12 @@ static void interpret_interface(char *token) zero_ip(&ip); zero_ip(&nmask); - + /* first check if it is an interface name */ for (i=0;i. */ @@ -45,6 +46,10 @@ #include #include +#ifdef HAVE_IFADDRS_H +#include +#endif + #ifdef HAVE_SYS_TIME_H #include #endif @@ -81,6 +86,60 @@ #include "interfaces.h" +/**************************************************************************** + Try the "standard" getifaddrs/freeifaddrs interfaces. + Also gets IPv6 interfaces. +****************************************************************************/ + +#if HAVE_IFACE_GETIFADDRS +/**************************************************************************** + Get the netmask address for a local interface. +****************************************************************************/ + +static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces) +{ + struct ifaddrs *iflist = NULL; + struct ifaddrs *ifptr = NULL; + int total = 0; + + if (getifaddrs(&ifp) < 0) { + return -1; + } + + /* Loop through interfaces, looking for given IP address */ + for (ifptr = iflist, total = 0; + ifptr != NULL && total < max_interfaces; + ifptr = ifptr->ifa_next) { + + /* Skip ipv6 for now. */ + if (ifptr->ifa_addr->sa_family != AF_INET) { + continue; + } + if (!(ifptr->ifa_flags & IFF_UP)) { + continue; + } + + ifaces[total].sa_family = ifptr->ifa_addr->sa_family; + + ifaces[total].iface_addr.ip = + ((struct sockaddr_in *)ifptr->ifa_addr).sin_addr; + + ifaces[total].iface_netmask.netmask = + ((struct sockaddr_in *)ifptr->ifa_addr)->sin_addr; + + strncpy(ifaces[total].name, ifptr->ifa_name, + sizeof(ifaces[total].name)-1); + ifaces[total].name[sizeof(ifaces[total].name)-1] = 0; + total++; + } + + freeifaddrs(iflist); + + return total; +} + +#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 @@ -89,10 +148,11 @@ It probably also works on any BSD style system. */ /**************************************************************************** - get the netmask address for a local interface + Get the netmask address for a local interface. ****************************************************************************/ + static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces) -{ +{ struct ifconf ifc; char buff[8192]; int fd, i, n; @@ -105,17 +165,17 @@ static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces) if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { return -1; } - + ifc.ifc_len = sizeof(buff); ifc.ifc_buf = buff; if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) { close(fd); return -1; - } + } ifr = ifc.ifc_req; - + n = ifc.ifc_len / sizeof(struct ifreq); /* Loop through interfaces, looking for given IP address */ @@ -129,7 +189,7 @@ static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces) if (ioctl(fd, SIOCGIFFLAGS, &ifr[i]) != 0) { continue; - } + } if (!(ifr[i].ifr_flags & IFF_UP)) { continue; @@ -137,21 +197,22 @@ static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces) if (ioctl(fd, SIOCGIFNETMASK, &ifr[i]) != 0) { continue; - } + } nmask = ((struct sockaddr_in *)&ifr[i].ifr_addr)->sin_addr; strncpy(ifaces[total].name, iname, sizeof(ifaces[total].name)-1); ifaces[total].name[sizeof(ifaces[total].name)-1] = 0; - ifaces[total].ip = ipaddr; - ifaces[total].netmask = nmask; + ifaces[total].sa_family = AF_INET; + ifaces[total].iface_addr.ip = ipaddr; + ifaces[total].iface_netmask.netmask = nmask; total++; } close(fd); return total; -} +} #define _FOUND_IFACE_ANY #endif /* HAVE_IFACE_IFCONF */ @@ -162,9 +223,10 @@ static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces) #endif /**************************************************************************** -this should cover most of the streams based systems -Thanks to Andrej.Borsenkow@mow.siemens.ru for several ideas in this code + This should cover most of the streams based systems. + Thanks to Andrej.Borsenkow@mow.siemens.ru for several ideas in this code. ****************************************************************************/ + static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces) { struct ifreq ifreq; @@ -180,14 +242,14 @@ static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces) if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { return -1; } - + strioctl.ic_cmd = SIOCGIFCONF; strioctl.ic_dp = buff; strioctl.ic_len = sizeof(buff); if (ioctl(fd, I_STR, &strioctl) < 0) { close(fd); return -1; - } + } /* we can ignore the possible sizeof(int) here as the resulting number of interface structures won't change */ @@ -197,23 +259,23 @@ static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces) at the start of the buffer if the offered size is a multiple of the structure size plus an int */ if (n*sizeof(struct ifreq) + sizeof(int) == strioctl.ic_len) { - ifr = (struct ifreq *)(buff + sizeof(int)); + ifr = (struct ifreq *)(buff + sizeof(int)); } else { - ifr = (struct ifreq *)buff; + ifr = (struct ifreq *)buff; } /* Loop through interfaces */ for (i = 0; iname, i2->name); - if (r) return r; - r = ntohl(i1->ip.s_addr) - ntohl(i2->ip.s_addr); - if (r) return r; - r = ntohl(i1->netmask.s_addr) - ntohl(i2->netmask.s_addr); + if (r) { + return r; + } + r = i1->sa_family - i2->sa_family; + if (r) { + return r; + } + +#ifdef AF_INET6 + if (i1->sa_family == AF_INET6) { + r = memcmp(&i1->iface_addr.ip6, + &i2->iface_addr.ip6, + sizeof(struct in6_addr)); + if (r) { + return r; + } + r = memcmp(&i1->iface_netmask.netmask6, + &i1->iface_netmask.netmask6, + sizeof(struct in6_addr)); + if (r) { + return r; + } + } +#endif + + if (i1->sa_family == AF_INET) { + r = ntohl(i1->iface_addr.ip.s_addr) - + ntohl(i2->iface_addr.ip.s_addr); + if (r) { + return r; + } + r = ntohl(i1->iface_netmask.netmask.s_addr) - + ntohl(i2->iface_netmask.netmask.s_addr); + } return r; } @@ -399,12 +493,21 @@ int get_interfaces(struct iface_struct *ifaces, int max_interfaces) int i; printf("got %d interfaces:\n", total); - if (total <= 0) exit(1); + if (total <= 0) { + exit(1); + } for (i=0;ih_addr ); fstrcpy( name, inet_ntoa( return_ip ) ); servername = name; - } + } } - + /* maybe its an IP address? */ if (is_ipaddress(servername)) { struct iface_struct nics[MAX_INTERFACES]; int i, n; uint32 ip; - + ip = interpret_addr(servername); if ((ip==0) || (ip==0xffffffff)) return False; - + n = get_interfaces(nics, MAX_INTERFACES); for (i=0; i "Windows 2002 5.1" WinXP 64bit => "Windows XP 5.2" Win2k => "Windows 2000 5.0" - NT4 => "Windows NT 4.0" + NT4 => "Windows NT 4.0" Win9x => "Windows 4.0" - Windows 2003 doesn't set the native lan manager string but + Windows 2003 doesn't set the native lan manager string but they do set the domain to "Windows 2003 5.2" (probably a bug). ********************************************************************/ void ra_lanman_string( const char *native_lanman ) -{ +{ if ( strcmp( native_lanman, "Windows 2002 5.1" ) == 0 ) set_remote_arch( RA_WINXP ); else if ( strcmp( native_lanman, "Windows XP 5.2" ) == 0 ) diff --git a/source3/utils/net_dns.c b/source3/utils/net_dns.c index 6163f53c6e5..e1993488f5b 100644 --- a/source3/utils/net_dns.c +++ b/source3/utils/net_dns.c @@ -158,8 +158,8 @@ int get_my_ip_address( struct in_addr **ips ) } for ( i=0; i