diff options
author | Jeremy Allison <jra@samba.org> | 2007-10-02 19:27:25 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 12:31:06 -0500 |
commit | 3fbd1ae54ced2eb889a8fe0a6ea32dfd8175f941 (patch) | |
tree | a39948ec0633b6bed73df92ddc0c94dc4c607f12 /source3/lib | |
parent | 5c5acae0eee9fb113ac6817eb8a164551a1cb117 (diff) | |
download | samba-3fbd1ae54ced2eb889a8fe0a6ea32dfd8175f941.tar.gz samba-3fbd1ae54ced2eb889a8fe0a6ea32dfd8175f941.tar.bz2 samba-3fbd1ae54ced2eb889a8fe0a6ea32dfd8175f941.zip |
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)
Diffstat (limited to 'source3/lib')
-rw-r--r-- | source3/lib/interface.c | 27 | ||||
-rw-r--r-- | source3/lib/interfaces.c | 173 | ||||
-rw-r--r-- | source3/lib/replace/replace.h | 12 | ||||
-rw-r--r-- | source3/lib/replace/system/network.h | 12 | ||||
-rw-r--r-- | source3/lib/util.c | 26 |
5 files changed, 183 insertions, 67 deletions
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<total_probed;i++) { if (gen_fnmatch(token, probed_ifaces[i].name) == 0) { - add_interface(probed_ifaces[i].ip, - probed_ifaces[i].netmask); + add_interface(probed_ifaces[i].iface_addr.ip, + probed_ifaces[i].iface_netmask.netmask); added = 1; } } @@ -119,10 +119,11 @@ static void interpret_interface(char *token) if (!p) { ip = *interpret_addr2(token); for (i=0;i<total_probed;i++) { - if (ip.s_addr == probed_ifaces[i].ip.s_addr && - !ip_equal(allones_ip, probed_ifaces[i].netmask)) { - add_interface(probed_ifaces[i].ip, - probed_ifaces[i].netmask); + if (ip.s_addr == probed_ifaces[i].iface_addr.ip.s_addr && + !ip_equal(allones_ip, + probed_ifaces[i].iface_netmask.netmask)) { + add_interface(probed_ifaces[i].iface_addr.ip, + probed_ifaces[i].iface_netmask.netmask); return; } } @@ -145,8 +146,8 @@ static void interpret_interface(char *token) if (ip.s_addr == MKBCADDR(ip.s_addr, nmask.s_addr) || ip.s_addr == MKNETADDR(ip.s_addr, nmask.s_addr)) { for (i=0;i<total_probed;i++) { - if (same_net(ip, probed_ifaces[i].ip, nmask)) { - add_interface(probed_ifaces[i].ip, nmask); + if (same_net(ip, probed_ifaces[i].iface_addr.ip, nmask)) { + add_interface(probed_ifaces[i].iface_addr.ip, nmask); return; } } @@ -203,11 +204,11 @@ void load_interfaces(void) for (i=0;i<total_probed;i++) { if ( #if !defined(__s390__) - probed_ifaces[i].netmask.s_addr != allones_ip.s_addr && + probed_ifaces[i].iface_netmask.netmask.s_addr != allones_ip.s_addr && #endif - probed_ifaces[i].ip.s_addr != loopback_ip.s_addr) { - add_interface(probed_ifaces[i].ip, - probed_ifaces[i].netmask); + probed_ifaces[i].iface_addr.ip.s_addr != loopback_ip.s_addr) { + add_interface(probed_ifaces[i].iface_addr.ip, + probed_ifaces[i].iface_netmask.netmask); } } return; diff --git a/source3/lib/interfaces.c b/source3/lib/interfaces.c index 2a232226b8..07abf4b1c6 100644 --- a/source3/lib/interfaces.c +++ b/source3/lib/interfaces.c @@ -1,18 +1,19 @@ -/* +/* Unix SMB/CIFS implementation. return a list of network interfaces Copyright (C) Andrew Tridgell 1998 - + Copyright (C) Jeremy Allison 2007 + 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 the Free Software Foundation; either version 3 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ @@ -45,6 +46,10 @@ #include <netinet/in.h> #include <arpa/inet.h> +#ifdef HAVE_IFADDRS_H +#include <ifaddrs.h> +#endif + #ifdef HAVE_SYS_TIME_H #include <sys/time.h> #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; i<n && total < max_interfaces; i++) { ifreq = ifr[i]; - + strioctl.ic_cmd = SIOCGIFFLAGS; strioctl.ic_dp = (char *)&ifreq; strioctl.ic_len = sizeof(struct ifreq); if (ioctl(fd, I_STR, &strioctl) != 0) { continue; } - + if (!(ifreq.ifr_flags & IFF_UP)) { continue; } @@ -239,8 +301,9 @@ static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces) 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++; } @@ -255,8 +318,9 @@ static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces) #ifdef HAVE_IFACE_AIX /**************************************************************************** -this one is for AIX (tested on 4.2) + This one is for AIX (tested on 4.2). ****************************************************************************/ + static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces) { char buff[8192]; @@ -314,8 +378,9 @@ static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces) 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++; @@ -334,7 +399,6 @@ static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces) ifr = (struct ifreq*) (((char*) ifr) + inc); i -= inc; } - close(fd); return total; @@ -354,10 +418,40 @@ static int iface_comp(struct iface_struct *i1, struct iface_struct *i2) { int r; r = strcmp(i1->name, 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;i<total;i++) { + char addr[INET6_ADDRSTRLEN]; printf("%-10s ", ifaces[i].name); - printf("IP=%s ", inet_ntoa(ifaces[i].ip)); - printf("NETMASK=%s\n", inet_ntoa(ifaces[i].netmask)); + printf("IP=%s ", inet_ntop(ifaces[i].sa_family, + (const void *)&ifaces[i].iface_addr.ip, + addr, + sizeof(addr))); + printf("NETMASK=%s\n", inet_ntop(ifaces[i].sa_family, + (const void *)&ifaces[i].iface_netmask.netmask, + addr, + sizeof(addr))); } return 0; } diff --git a/source3/lib/replace/replace.h b/source3/lib/replace/replace.h index 907d9b0086..27265e35c4 100644 --- a/source3/lib/replace/replace.h +++ b/source3/lib/replace/replace.h @@ -330,18 +330,18 @@ ssize_t rep_pread(int __fd, void *__buf, size_t __nbytes, off_t __offset); ssize_t rep_pwrite(int __fd, const void *__buf, size_t __nbytes, off_t __offset); #endif +#if !defined(HAVE_INET_PTON) || !defined(HAVE_INET_NTOP) +#include "system/network.h" +#endif + #ifndef HAVE_INET_PTON -#define inet_pton rep_inet_pton int rep_inet_pton(int af, const char *src, void *dst); +#define inet_pton rep_inet_pton #endif #ifndef HAVE_INET_NTOP -#define inet_ntop rep_inet_ntop const char *rep_inet_ntop(int af, const void *src, char *dst, socklen_t size); -#endif - -#ifndef EAFNOSUPPORT -#define EAFNOSUPPORT EINVAL +#define inet_ntop rep_inet_ntop #endif #ifdef HAVE_LIMITS_H diff --git a/source3/lib/replace/system/network.h b/source3/lib/replace/system/network.h index 7469040b28..70c3ec711c 100644 --- a/source3/lib/replace/system/network.h +++ b/source3/lib/replace/system/network.h @@ -106,4 +106,16 @@ char *rep_inet_ntoa(struct in_addr ip); #define INADDR_NONE 0xffffffff #endif +#ifndef EAFNOSUPPORT +#define EAFNOSUPPORT EINVAL +#endif + +#ifndef INET_ADDRSTRLEN +#define INET_ADDRSTRLEN 16 +#endif + +#ifndef INET6_ADDRSTRLEN +#define INET6_ADDRSTRLEN 46 +#endif + #endif diff --git a/source3/lib/util.c b/source3/lib/util.c index 67c5f8d38f..6c86376e57 100644 --- a/source3/lib/util.c +++ b/source3/lib/util.c @@ -2138,7 +2138,7 @@ BOOL is_myname_or_ipaddr(const char *s) /* optimize for the common case */ - if (strequal(servername, global_myname())) + if (strequal(servername, global_myname())) return True; /* check for an alias */ @@ -2148,10 +2148,10 @@ BOOL is_myname_or_ipaddr(const char *s) /* check for loopback */ - if (strequal(servername, "127.0.0.1")) + if (strequal(servername, "127.0.0.1")) return True; - if (strequal(servername, "localhost")) + if (strequal(servername, "localhost")) return True; /* maybe it's my dns name */ @@ -2159,7 +2159,7 @@ BOOL is_myname_or_ipaddr(const char *s) if ( get_mydnsfullname( dnsname ) ) if ( strequal( servername, dnsname ) ) return True; - + /* handle possible CNAME records */ if ( !is_ipaddress( servername ) ) { @@ -2171,25 +2171,25 @@ BOOL is_myname_or_ipaddr(const char *s) putip( (char*)&return_ip, (char*)hp->h_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<n; i++) { - if (ip == nics[i].ip.s_addr) + if (ip == nics[i].iface_addr.ip.s_addr) return True; } - } + } /* no match */ return False; @@ -2217,14 +2217,14 @@ BOOL is_myworkgroup(const char *s) WinXP => "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 ) |