build: commit all the waf build files in the tree
[nivanova/samba-autobuild/.git] / source4 / lib / socket / netif.c
index 1595b0dfd5334231935a71c0d9d5c336df976f57..e36f268bde1edb70be65effa2c7ac0a8c02673c9 100644 (file)
@@ -2,10 +2,12 @@
    Unix SMB/CIFS implementation.
    return a list of network interfaces
    Copyright (C) Andrew Tridgell 1998
+   Copyright (C) Jeremy Allison 2007
+   Copyright (C) Jelmer Vernooij 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 2 of the License, or
+   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,
@@ -14,8 +16,7 @@
    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.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 
 
 */
 
-#ifndef AUTOCONF_TEST
 #include "includes.h"
-#endif
-
-#include <unistd.h>
-#include <stdio.h>
-#include <sys/types.h>
-#include <netdb.h>
-#include <sys/ioctl.h>
-#include <netdb.h>
-#include <sys/ioctl.h>
-#include <sys/time.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-
-#ifdef HAVE_SYS_TIME_H
-#include <sys/time.h>
-#endif
-
-#ifndef SIOCGIFCONF
-#ifdef HAVE_SYS_SOCKIO_H
-#include <sys/sockio.h>
-#endif
-#endif
-
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
-
-#ifdef HAVE_STRINGS_H
-#include <strings.h>
-#endif
-
-#ifdef __COMPAR_FN_T
-#define QSORT_CAST (__compar_fn_t)
-#endif
-
-#ifndef QSORT_CAST
-#define QSORT_CAST (int (*)(const void *, const void *))
-#endif
-
-#ifdef HAVE_NET_IF_H
-#include <net/if.h>
-#endif
-
+#include "system/network.h"
 #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.  */
+#include "lib/util/tsort.h"
 
 /****************************************************************************
-  get the netmask address for a local interface
+ Try the "standard" getifaddrs/freeifaddrs interfaces.
+ Also gets IPv6 interfaces.
 ****************************************************************************/
-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;
-}  
-
-#define _FOUND_IFACE_ANY
-#endif /* HAVE_IFACE_IFCONF */
-#ifdef HAVE_IFACE_IFREQ
-
-#ifndef I_STR
-#include <sys/stropts.h>
-#endif
 
 /****************************************************************************
-this should cover most of the streams based systems
-Thanks to Andrej.Borsenkow@mow.siemens.ru for several ideas in this code
+ Get the netmask address for a local interface.
 ****************************************************************************/
+
 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;
+       struct ifaddrs *iflist = NULL;
+       struct ifaddrs *ifptr = NULL;
        int total = 0;
-       struct in_addr ipaddr;
-       struct in_addr nmask;
-       char *iname;
 
-       if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
+       if (getifaddrs(&iflist) < 0) {
                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, looking for given IP address */
+       for (ifptr = iflist, total = 0;
+                       ifptr != NULL && total < max_interfaces;
+                       ifptr = ifptr->ifa_next) {
 
-       /* Loop through interfaces */
+               memset(&ifaces[total], '\0', sizeof(ifaces[total]));
 
-       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)) {
+               if (!ifptr->ifa_addr || !ifptr->ifa_netmask) {
                        continue;
                }
 
-               strioctl.ic_cmd = SIOCGIFADDR;
-               strioctl.ic_dp  = (char *)&ifreq;
-               strioctl.ic_len = sizeof(struct ifreq);
-               if (ioctl(fd, I_STR, &strioctl) != 0) {
+               /* Check the interface is up. */
+               if (!(ifptr->ifa_flags & IFF_UP)) {
                        continue;
                }
 
-               ipaddr = (*(struct sockaddr_in *) &ifreq.ifr_addr).sin_addr;
-               iname = ifreq.ifr_name;
-
-               strioctl.ic_cmd = SIOCGIFNETMASK;
-               strioctl.ic_dp  = (char *)&ifreq;
-               strioctl.ic_len = sizeof(struct ifreq);
-               if (ioctl(fd, I_STR, &strioctl) != 0) {
+               /* We don't support IPv6 *yet* */
+               if (ifptr->ifa_addr->sa_family != AF_INET) {
                        continue;
                }
 
-               nmask = ((struct sockaddr_in *)&ifreq.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].ip = ((struct sockaddr_in *)ifptr->ifa_addr)->sin_addr;
+               ifaces[total].netmask = ((struct sockaddr_in *)ifptr->ifa_netmask)->sin_addr;
 
+               strlcpy(ifaces[total].name, ifptr->ifa_name,
+                       sizeof(ifaces[total].name));
                total++;
        }
 
-       close(fd);
+       freeifaddrs(iflist);
 
        return total;
 }
 
-#define _FOUND_IFACE_ANY
-#endif /* HAVE_IFACE_IFREQ */
-#ifdef 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;
-}
-
-#define _FOUND_IFACE_ANY
-#endif /* HAVE_IFACE_AIX */
-#ifndef _FOUND_IFACE_ANY
-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;
@@ -372,7 +110,7 @@ int get_interfaces(struct iface_struct *ifaces, int max_interfaces)
        if (total <= 0) return total;
 
        /* now we need to remove duplicates */
-       qsort(ifaces, total, sizeof(ifaces[0]), QSORT_CAST iface_comp);
+       TYPESAFE_QSORT(ifaces, total, iface_comp);
 
        for (i=1;i<total;) {
                if (iface_comp(&ifaces[i-1], &ifaces[i]) == 0) {
@@ -387,25 +125,3 @@ int get_interfaces(struct iface_struct *ifaces, int max_interfaces)
 
        return total;
 }
-
-
-#ifdef AUTOCONF_TEST
-/* this is the autoconf driver to test get_interfaces() */
-
- int main()
-{
-       struct iface_struct ifaces[MAX_INTERFACES];
-       int total = get_interfaces(ifaces, MAX_INTERFACES);
-       int i;
-
-       printf("got %d interfaces:\n", total);
-       if (total <= 0) exit(1);
-
-       for (i=0;i<total;i++) {
-               printf("%-10s ", ifaces[i].name);
-               printf("IP=%s ", inet_ntoa(ifaces[i].ip));
-               printf("NETMASK=%s\n", inet_ntoa(ifaces[i].netmask));
-       }
-       return 0;
-}
-#endif