From a2eca9174c7803732658a1e6f7e8ed873c4fb6fd Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 17 Aug 2006 13:37:04 +0000 Subject: r17586: merge lib/netif into lib/socket and use -lnsl -lsocket on the configure check for the interfaces. should fix the build on some old sun boxes metze (This used to be commit f20e251bfd9f1eb7ce5c00739631b1625a2aa467) --- source4/lib/basic.mk | 11 -- source4/lib/netif/config.m4 | 42 ----- source4/lib/netif/interface.c | 354 ------------------------------------ source4/lib/netif/netif.c | 403 ----------------------------------------- source4/lib/netif/netif.h | 33 ---- source4/lib/socket/config.m4 | 51 ++++++ source4/lib/socket/config.mk | 10 + source4/lib/socket/interface.c | 354 ++++++++++++++++++++++++++++++++++++ source4/lib/socket/netif.c | 403 +++++++++++++++++++++++++++++++++++++++++ source4/lib/socket/netif.h | 33 ++++ 10 files changed, 851 insertions(+), 843 deletions(-) delete mode 100644 source4/lib/netif/config.m4 delete mode 100644 source4/lib/netif/interface.c delete mode 100644 source4/lib/netif/netif.c delete mode 100644 source4/lib/netif/netif.h create mode 100644 source4/lib/socket/interface.c create mode 100644 source4/lib/socket/netif.c create mode 100644 source4/lib/socket/netif.h (limited to 'source4/lib') diff --git a/source4/lib/basic.mk b/source4/lib/basic.mk index bce5b85b32..145adfa3f0 100644 --- a/source4/lib/basic.mk +++ b/source4/lib/basic.mk @@ -17,17 +17,6 @@ include stream/config.mk include util/config.mk include tdr/config.mk -############################## -# Start SUBSYSTEM LIBNETIF -[SUBSYSTEM::LIBNETIF] -PRIVATE_PROTO_HEADER = netif/proto.h -OBJ_FILES = \ - netif/interface.o \ - netif/netif.o -PRIVATE_DEPENDENCIES = LIBSAMBA-UTIL EXT_NSL -# End SUBSYSTEM LIBNETIF -############################## - ############################## # Start SUBSYSTEM LIBCRYPTO [SUBSYSTEM::LIBCRYPTO] diff --git a/source4/lib/netif/config.m4 b/source4/lib/netif/config.m4 deleted file mode 100644 index 9880440f21..0000000000 --- a/source4/lib/netif/config.m4 +++ /dev/null @@ -1,42 +0,0 @@ -AC_CHECK_HEADERS(arpa/inet.h net/if.h netdb.h netinet/in.h sys/time.h) -AC_CHECK_HEADERS(netinet/ip.h netinet/tcp.h netinet/in_systm.h netinet/in_ip.h) - -################## -# look for a method of finding the list of network interfaces -iface=no; -AC_CACHE_CHECK([for iface AIX],samba_cv_HAVE_IFACE_AIX,[ -AC_TRY_RUN([ -#define HAVE_IFACE_AIX 1 -#define AUTOCONF_TEST 1 -#include "confdefs.h" -#include "${srcdir-.}/lib/netif/netif.c"], - samba_cv_HAVE_IFACE_AIX=yes,samba_cv_HAVE_IFACE_AIX=no,samba_cv_HAVE_IFACE_AIX=cross)]) -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 ifconf],samba_cv_HAVE_IFACE_IFCONF,[ -AC_TRY_RUN([ -#define HAVE_IFACE_IFCONF 1 -#define AUTOCONF_TEST 1 -#include "confdefs.h" -#include "${srcdir-.}/lib/netif/netif.c"], - samba_cv_HAVE_IFACE_IFCONF=yes,samba_cv_HAVE_IFACE_IFCONF=no,samba_cv_HAVE_IFACE_IFCONF=cross)]) -if test x"$samba_cv_HAVE_IFACE_IFCONF" = x"yes"; then - iface=yes;AC_DEFINE(HAVE_IFACE_IFCONF,1,[Whether iface ifconf is available]) -fi -fi - -if test $iface = no; then -AC_CACHE_CHECK([for iface ifreq],samba_cv_HAVE_IFACE_IFREQ,[ -AC_TRY_RUN([ -#define HAVE_IFACE_IFREQ 1 -#define AUTOCONF_TEST 1 -#include "confdefs.h" -#include "${srcdir-.}/lib/netif/netif.c"], - samba_cv_HAVE_IFACE_IFREQ=yes,samba_cv_HAVE_IFACE_IFREQ=no,samba_cv_HAVE_IFACE_IFREQ=cross)]) -if test x"$samba_cv_HAVE_IFACE_IFREQ" = x"yes"; then - iface=yes;AC_DEFINE(HAVE_IFACE_IFREQ,1,[Whether iface ifreq is available]) -fi -fi diff --git a/source4/lib/netif/interface.c b/source4/lib/netif/interface.c deleted file mode 100644 index 019b05cfbb..0000000000 --- a/source4/lib/netif/interface.c +++ /dev/null @@ -1,354 +0,0 @@ -/* - Unix SMB/CIFS implementation. - - multiple interface handling - - Copyright (C) Andrew Tridgell 1992-2005 - - 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 2 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, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" -#include "system/network.h" -#include "lib/netif/netif.h" -#include "dlinklist.h" - -/** used for network interfaces */ -struct interface { - struct interface *next, *prev; - struct ipv4_addr ip; - struct ipv4_addr nmask; - const char *ip_s; - const char *bcast_s; - const char *nmask_s; -}; - -static struct interface *local_interfaces; - -#define ALLONES ((uint32_t)0xFFFFFFFF) -/* - address construction based on a patch from fred@datalync.com -*/ -#define MKBCADDR(_IP, _NM) ((_IP & _NM) | (_NM ^ ALLONES)) -#define MKNETADDR(_IP, _NM) (_IP & _NM) - -static struct ipv4_addr tov4(struct in_addr in) -{ - struct ipv4_addr in2; - in2.addr = in.s_addr; - return in2; -} - -/**************************************************************************** -Try and find an interface that matches an ip. If we cannot, return NULL - **************************************************************************/ -static struct interface *iface_find(struct in_addr ip, BOOL CheckMask) -{ - struct interface *i; - if (is_zero_ip(tov4(ip))) return local_interfaces; - - for (i=local_interfaces;i;i=i->next) - if (CheckMask) { - if (same_net(i->ip,tov4(ip),i->nmask)) return i; - } else if (i->ip.addr == ip.s_addr) return i; - - return NULL; -} - - -/**************************************************************************** -add an interface to the linked list of interfaces -****************************************************************************/ -static void add_interface(struct in_addr ip, struct in_addr nmask) -{ - struct interface *iface; - struct ipv4_addr bcast; - if (iface_find(ip, False)) { - DEBUG(3,("not adding duplicate interface %s\n",inet_ntoa(ip))); - return; - } - - iface = talloc(local_interfaces, struct interface); - if (!iface) return; - - ZERO_STRUCTPN(iface); - - iface->ip = tov4(ip); - iface->nmask = tov4(nmask); - bcast.addr = MKBCADDR(iface->ip.addr, iface->nmask.addr); - - /* keep string versions too, to avoid people tripping over the implied - static in sys_inet_ntoa() */ - iface->ip_s = talloc_strdup(iface, sys_inet_ntoa(iface->ip)); - iface->nmask_s = talloc_strdup(iface, sys_inet_ntoa(iface->nmask)); - - if (nmask.s_addr != ~0) { - iface->bcast_s = talloc_strdup(iface, sys_inet_ntoa(bcast)); - } - - DLIST_ADD_END(local_interfaces, iface, struct interface *); - - DEBUG(2,("added interface ip=%s nmask=%s\n", iface->ip_s, iface->nmask_s)); -} - - - -/** -interpret a single element from a interfaces= config line - -This handles the following different forms: - -1) wildcard interface name -2) DNS name -3) IP/masklen -4) ip/mask -5) bcast/mask -**/ -static void interpret_interface(const char *token, - struct iface_struct *probed_ifaces, - int total_probed) -{ - struct in_addr ip, nmask; - char *p; - int i, added=0; - - ip.s_addr = 0; - nmask.s_addr = 0; - - /* first check if it is an interface name */ - for (i=0;i 2) { - nmask.s_addr = interpret_addr2(p).addr; - } else { - nmask.s_addr = htonl(((ALLONES >> atoi(p)) ^ ALLONES)); - } - - /* maybe the first component was a broadcast address */ - if (ip.s_addr == MKBCADDR(ip.s_addr, nmask.s_addr) || - ip.s_addr == MKNETADDR(ip.s_addr, nmask.s_addr)) { - for (i=0;inext) - ret++; - return ret; -} - -/** - return IP of the Nth interface - **/ -const char *iface_n_ip(int n) -{ - struct interface *i; - - load_interfaces(); - - for (i=local_interfaces;i && n;i=i->next) - n--; - - if (i) { - return i->ip_s; - } - return NULL; -} - -/** - return bcast of the Nth interface - **/ -const char *iface_n_bcast(int n) -{ - struct interface *i; - - load_interfaces(); - - for (i=local_interfaces;i && n;i=i->next) - n--; - - if (i) { - return i->bcast_s; - } - return NULL; -} - -/** - return netmask of the Nth interface - **/ -const char *iface_n_netmask(int n) -{ - struct interface *i; - - load_interfaces(); - - for (i=local_interfaces;i && n;i=i->next) - n--; - - if (i) { - return i->nmask_s; - } - return NULL; -} - -/** - return the local IP address that best matches a destination IP, or - our first interface if none match -*/ -const char *iface_best_ip(const char *dest) -{ - struct interface *iface; - struct in_addr ip; - - load_interfaces(); - - ip.s_addr = interpret_addr(dest); - iface = iface_find(ip, True); - if (iface) { - return iface->ip_s; - } - return iface_n_ip(0); -} - -/** - return True if an IP is one one of our local networks -*/ -BOOL iface_is_local(const char *dest) -{ - struct in_addr ip; - - load_interfaces(); - - ip.s_addr = interpret_addr(dest); - if (iface_find(ip, True)) { - return True; - } - return False; -} - -/** - return True if a IP matches a IP/netmask pair -*/ -BOOL iface_same_net(const char *ip1, const char *ip2, const char *netmask) -{ - return same_net(interpret_addr2(ip1), - interpret_addr2(ip2), - interpret_addr2(netmask)); -} diff --git a/source4/lib/netif/netif.c b/source4/lib/netif/netif.c deleted file mode 100644 index 0344febf38..0000000000 --- a/source4/lib/netif/netif.c +++ /dev/null @@ -1,403 +0,0 @@ -/* - Unix SMB/CIFS implementation. - return a list of network interfaces - Copyright (C) Andrew Tridgell 1998 - - 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 2 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, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - - -/* working out the interfaces for a OS is an incredibly non-portable - thing. We have several possible implementations below, and autoconf - tries each of them to see what works - - Note that this file does _not_ include includes.h. That is so this code - can be called directly from the autoconf tests. That also means - this code cannot use any of the normal Samba debug stuff or defines. - This is standalone code. - -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifndef AUTOCONF_TEST -#include "config.h" -#endif - -#ifdef HAVE_SYS_TIME_H -#include -#endif - -#ifndef SIOCGIFCONF -#ifdef HAVE_SYS_SOCKIO_H -#include -#endif -#endif - -#ifdef HAVE_STDLIB_H -#include -#endif - -#ifdef HAVE_STRING_H -#include -#endif - -#ifdef HAVE_STRINGS_H -#include -#endif - -#ifdef __COMPAR_FN_T -#define QSORT_CAST (__compar_fn_t) -#endif - -#ifndef QSORT_CAST -#define QSORT_CAST (int (*)(const void *, const void *)) -#endif - -#include -#define BOOL int -#include "netif.h" - -#if HAVE_IFACE_IFCONF - -/* this works for Linux 2.2, Solaris 2.5, SunOS4, HPUX 10.20, OSF1 - V4.0, Ultrix 4.4, SCO Unix 3.2, IRIX 6.4 and FreeBSD 3.2. - - It probably also works on any BSD style system. */ - -/**************************************************************************** - 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; - struct ifreq *ifr=NULL; - int total = 0; - struct in_addr ipaddr; - struct in_addr nmask; - char *iname; - - 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 */ - for (i=n-1;i>=0 && total < max_interfaces;i--) { - if (ioctl(fd, SIOCGIFADDR, &ifr[i]) != 0) { - continue; - } - - iname = ifr[i].ifr_name; - ipaddr = (*(struct sockaddr_in *)&ifr[i].ifr_addr).sin_addr; - - if (ioctl(fd, SIOCGIFFLAGS, &ifr[i]) != 0) { - continue; - } - - if (!(ifr[i].ifr_flags & IFF_UP)) { - continue; - } - - 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; - total++; - } - - close(fd); - - return total; -} - -#elif HAVE_IFACE_IFREQ - -#ifndef I_STR -#include -#endif - -/**************************************************************************** -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; - struct strioctl strioctl; - char buff[8192]; - int fd, i, n; - struct ifreq *ifr=NULL; - int total = 0; - struct in_addr ipaddr; - struct in_addr nmask; - char *iname; - - 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 */ - n = strioctl.ic_len / sizeof(struct ifreq); - - /* we will assume that the kernel returns the length as an int - 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)); - } else { - ifr = (struct ifreq *)buff; - } - - /* Loop through interfaces */ - - for (i = 0; isin_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; - - total++; - } - - close(fd); - - return total; -} - -#elif HAVE_IFACE_AIX - -/**************************************************************************** -this one is for AIX (tested on 4.2) -****************************************************************************/ -static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces) -{ - char buff[8192]; - int fd, i; - struct ifconf ifc; - struct ifreq *ifr=NULL; - struct in_addr ipaddr; - struct in_addr nmask; - char *iname; - int total = 0; - - 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; - - /* Loop through interfaces */ - i = ifc.ifc_len; - - while (i > 0 && total < max_interfaces) { - uint_t inc; - - inc = ifr->ifr_addr.sa_len; - - if (ioctl(fd, SIOCGIFADDR, ifr) != 0) { - goto next; - } - - ipaddr = (*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr; - iname = ifr->ifr_name; - - if (ioctl(fd, SIOCGIFFLAGS, ifr) != 0) { - goto next; - } - - if (!(ifr->ifr_flags & IFF_UP)) { - goto next; - } - - if (ioctl(fd, SIOCGIFNETMASK, ifr) != 0) { - goto next; - } - - nmask = ((struct sockaddr_in *)&ifr->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; - - total++; - - next: - /* - * Patch from Archie Cobbs (archie@whistle.com). The - * addresses in the SIOCGIFCONF interface list have a - * minimum size. Usually this doesn't matter, but if - * your machine has tunnel interfaces, etc. that have - * a zero length "link address", this does matter. */ - - if (inc < sizeof(ifr->ifr_addr)) - inc = sizeof(ifr->ifr_addr); - inc += IFNAMSIZ; - - ifr = (struct ifreq*) (((char*) ifr) + inc); - i -= inc; - } - - - close(fd); - return total; -} - -#else /* a dummy version */ -static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces) -{ - return -1; -} -#endif - - -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); - return r; -} - -/* this wrapper is used to remove duplicates from the interface list generated - above */ -int get_interfaces(struct iface_struct *ifaces, int max_interfaces) -{ - int total, i, j; - - total = _get_interfaces(ifaces, max_interfaces); - if (total <= 0) return total; - - /* now we need to remove duplicates */ - qsort(ifaces, total, sizeof(ifaces[0]), QSORT_CAST iface_comp); - - for (i=1;inext) + if (CheckMask) { + if (same_net(i->ip,tov4(ip),i->nmask)) return i; + } else if (i->ip.addr == ip.s_addr) return i; + + return NULL; +} + + +/**************************************************************************** +add an interface to the linked list of interfaces +****************************************************************************/ +static void add_interface(struct in_addr ip, struct in_addr nmask) +{ + struct interface *iface; + struct ipv4_addr bcast; + if (iface_find(ip, False)) { + DEBUG(3,("not adding duplicate interface %s\n",inet_ntoa(ip))); + return; + } + + iface = talloc(local_interfaces, struct interface); + if (!iface) return; + + ZERO_STRUCTPN(iface); + + iface->ip = tov4(ip); + iface->nmask = tov4(nmask); + bcast.addr = MKBCADDR(iface->ip.addr, iface->nmask.addr); + + /* keep string versions too, to avoid people tripping over the implied + static in sys_inet_ntoa() */ + iface->ip_s = talloc_strdup(iface, sys_inet_ntoa(iface->ip)); + iface->nmask_s = talloc_strdup(iface, sys_inet_ntoa(iface->nmask)); + + if (nmask.s_addr != ~0) { + iface->bcast_s = talloc_strdup(iface, sys_inet_ntoa(bcast)); + } + + DLIST_ADD_END(local_interfaces, iface, struct interface *); + + DEBUG(2,("added interface ip=%s nmask=%s\n", iface->ip_s, iface->nmask_s)); +} + + + +/** +interpret a single element from a interfaces= config line + +This handles the following different forms: + +1) wildcard interface name +2) DNS name +3) IP/masklen +4) ip/mask +5) bcast/mask +**/ +static void interpret_interface(const char *token, + struct iface_struct *probed_ifaces, + int total_probed) +{ + struct in_addr ip, nmask; + char *p; + int i, added=0; + + ip.s_addr = 0; + nmask.s_addr = 0; + + /* first check if it is an interface name */ + for (i=0;i 2) { + nmask.s_addr = interpret_addr2(p).addr; + } else { + nmask.s_addr = htonl(((ALLONES >> atoi(p)) ^ ALLONES)); + } + + /* maybe the first component was a broadcast address */ + if (ip.s_addr == MKBCADDR(ip.s_addr, nmask.s_addr) || + ip.s_addr == MKNETADDR(ip.s_addr, nmask.s_addr)) { + for (i=0;inext) + ret++; + return ret; +} + +/** + return IP of the Nth interface + **/ +const char *iface_n_ip(int n) +{ + struct interface *i; + + load_interfaces(); + + for (i=local_interfaces;i && n;i=i->next) + n--; + + if (i) { + return i->ip_s; + } + return NULL; +} + +/** + return bcast of the Nth interface + **/ +const char *iface_n_bcast(int n) +{ + struct interface *i; + + load_interfaces(); + + for (i=local_interfaces;i && n;i=i->next) + n--; + + if (i) { + return i->bcast_s; + } + return NULL; +} + +/** + return netmask of the Nth interface + **/ +const char *iface_n_netmask(int n) +{ + struct interface *i; + + load_interfaces(); + + for (i=local_interfaces;i && n;i=i->next) + n--; + + if (i) { + return i->nmask_s; + } + return NULL; +} + +/** + return the local IP address that best matches a destination IP, or + our first interface if none match +*/ +const char *iface_best_ip(const char *dest) +{ + struct interface *iface; + struct in_addr ip; + + load_interfaces(); + + ip.s_addr = interpret_addr(dest); + iface = iface_find(ip, True); + if (iface) { + return iface->ip_s; + } + return iface_n_ip(0); +} + +/** + return True if an IP is one one of our local networks +*/ +BOOL iface_is_local(const char *dest) +{ + struct in_addr ip; + + load_interfaces(); + + ip.s_addr = interpret_addr(dest); + if (iface_find(ip, True)) { + return True; + } + return False; +} + +/** + return True if a IP matches a IP/netmask pair +*/ +BOOL iface_same_net(const char *ip1, const char *ip2, const char *netmask) +{ + return same_net(interpret_addr2(ip1), + interpret_addr2(ip2), + interpret_addr2(netmask)); +} diff --git a/source4/lib/socket/netif.c b/source4/lib/socket/netif.c new file mode 100644 index 0000000000..0344febf38 --- /dev/null +++ b/source4/lib/socket/netif.c @@ -0,0 +1,403 @@ +/* + Unix SMB/CIFS implementation. + return a list of network interfaces + Copyright (C) Andrew Tridgell 1998 + + 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 2 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, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +/* working out the interfaces for a OS is an incredibly non-portable + thing. We have several possible implementations below, and autoconf + tries each of them to see what works + + Note that this file does _not_ include includes.h. That is so this code + can be called directly from the autoconf tests. That also means + this code cannot use any of the normal Samba debug stuff or defines. + This is standalone code. + +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef AUTOCONF_TEST +#include "config.h" +#endif + +#ifdef HAVE_SYS_TIME_H +#include +#endif + +#ifndef SIOCGIFCONF +#ifdef HAVE_SYS_SOCKIO_H +#include +#endif +#endif + +#ifdef HAVE_STDLIB_H +#include +#endif + +#ifdef HAVE_STRING_H +#include +#endif + +#ifdef HAVE_STRINGS_H +#include +#endif + +#ifdef __COMPAR_FN_T +#define QSORT_CAST (__compar_fn_t) +#endif + +#ifndef QSORT_CAST +#define QSORT_CAST (int (*)(const void *, const void *)) +#endif + +#include +#define BOOL int +#include "netif.h" + +#if HAVE_IFACE_IFCONF + +/* this works for Linux 2.2, Solaris 2.5, SunOS4, HPUX 10.20, OSF1 + V4.0, Ultrix 4.4, SCO Unix 3.2, IRIX 6.4 and FreeBSD 3.2. + + It probably also works on any BSD style system. */ + +/**************************************************************************** + 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; + struct ifreq *ifr=NULL; + int total = 0; + struct in_addr ipaddr; + struct in_addr nmask; + char *iname; + + 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 */ + for (i=n-1;i>=0 && total < max_interfaces;i--) { + if (ioctl(fd, SIOCGIFADDR, &ifr[i]) != 0) { + continue; + } + + iname = ifr[i].ifr_name; + ipaddr = (*(struct sockaddr_in *)&ifr[i].ifr_addr).sin_addr; + + if (ioctl(fd, SIOCGIFFLAGS, &ifr[i]) != 0) { + continue; + } + + if (!(ifr[i].ifr_flags & IFF_UP)) { + continue; + } + + 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; + total++; + } + + close(fd); + + return total; +} + +#elif HAVE_IFACE_IFREQ + +#ifndef I_STR +#include +#endif + +/**************************************************************************** +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; + struct strioctl strioctl; + char buff[8192]; + int fd, i, n; + struct ifreq *ifr=NULL; + int total = 0; + struct in_addr ipaddr; + struct in_addr nmask; + char *iname; + + 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 */ + n = strioctl.ic_len / sizeof(struct ifreq); + + /* we will assume that the kernel returns the length as an int + 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)); + } else { + ifr = (struct ifreq *)buff; + } + + /* Loop through interfaces */ + + for (i = 0; isin_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; + + total++; + } + + close(fd); + + return total; +} + +#elif HAVE_IFACE_AIX + +/**************************************************************************** +this one is for AIX (tested on 4.2) +****************************************************************************/ +static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces) +{ + char buff[8192]; + int fd, i; + struct ifconf ifc; + struct ifreq *ifr=NULL; + struct in_addr ipaddr; + struct in_addr nmask; + char *iname; + int total = 0; + + 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; + + /* Loop through interfaces */ + i = ifc.ifc_len; + + while (i > 0 && total < max_interfaces) { + uint_t inc; + + inc = ifr->ifr_addr.sa_len; + + if (ioctl(fd, SIOCGIFADDR, ifr) != 0) { + goto next; + } + + ipaddr = (*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr; + iname = ifr->ifr_name; + + if (ioctl(fd, SIOCGIFFLAGS, ifr) != 0) { + goto next; + } + + if (!(ifr->ifr_flags & IFF_UP)) { + goto next; + } + + if (ioctl(fd, SIOCGIFNETMASK, ifr) != 0) { + goto next; + } + + nmask = ((struct sockaddr_in *)&ifr->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; + + total++; + + next: + /* + * Patch from Archie Cobbs (archie@whistle.com). The + * addresses in the SIOCGIFCONF interface list have a + * minimum size. Usually this doesn't matter, but if + * your machine has tunnel interfaces, etc. that have + * a zero length "link address", this does matter. */ + + if (inc < sizeof(ifr->ifr_addr)) + inc = sizeof(ifr->ifr_addr); + inc += IFNAMSIZ; + + ifr = (struct ifreq*) (((char*) ifr) + inc); + i -= inc; + } + + + close(fd); + return total; +} + +#else /* a dummy version */ +static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces) +{ + return -1; +} +#endif + + +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); + return r; +} + +/* this wrapper is used to remove duplicates from the interface list generated + above */ +int get_interfaces(struct iface_struct *ifaces, int max_interfaces) +{ + int total, i, j; + + total = _get_interfaces(ifaces, max_interfaces); + if (total <= 0) return total; + + /* now we need to remove duplicates */ + qsort(ifaces, total, sizeof(ifaces[0]), QSORT_CAST iface_comp); + + for (i=1;i