From 3fbd1ae54ced2eb889a8fe0a6ea32dfd8175f941 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 2 Oct 2007 19:27:25 +0000 Subject: 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) --- source3/lib/interface.c | 27 +++--- source3/lib/interfaces.c | 173 ++++++++++++++++++++++++++++------- source3/lib/replace/replace.h | 12 +-- source3/lib/replace/system/network.h | 12 +++ source3/lib/util.c | 26 +++--- 5 files changed, 183 insertions(+), 67 deletions(-) (limited to 'source3/lib') diff --git a/source3/lib/interface.c b/source3/lib/interface.c index 29ed15a0c2..c187583923 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 ) -- cgit