lib/interfaces.c

説明を見る。
00001 /* 
00002    Unix SMB/CIFS implementation.
00003    return a list of network interfaces
00004    Copyright (C) Andrew Tridgell 1998
00005    
00006    This program is free software; you can redistribute it and/or modify
00007    it under the terms of the GNU General Public License as published by
00008    the Free Software Foundation; either version 2 of the License, or
00009    (at your option) any later version.
00010    
00011    This program is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014    GNU General Public License for more details.
00015    
00016    You should have received a copy of the GNU General Public License
00017    along with this program; if not, write to the Free Software
00018    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00019 */
00020 
00021 
00022 /* working out the interfaces for a OS is an incredibly non-portable
00023    thing. We have several possible implementations below, and autoconf
00024    tries each of them to see what works
00025 
00026    Note that this file does _not_ include includes.h. That is so this code
00027    can be called directly from the autoconf tests. That also means
00028    this code cannot use any of the normal Samba debug stuff or defines.
00029    This is standalone code.
00030 
00031 */
00032 
00033 #ifndef AUTOCONF_TEST
00034 #include "config.h"
00035 #endif
00036 
00037 #include <unistd.h>
00038 #include <stdio.h>
00039 #include <sys/types.h>
00040 #include <netdb.h>
00041 #include <sys/ioctl.h>
00042 #include <netdb.h>
00043 #include <sys/ioctl.h>
00044 #include <sys/time.h>
00045 #include <sys/socket.h>
00046 #include <netinet/in.h>
00047 #include <arpa/inet.h>
00048 
00049 #ifdef HAVE_SYS_TIME_H
00050 #include <sys/time.h>
00051 #endif
00052 
00053 #ifndef SIOCGIFCONF
00054 #ifdef HAVE_SYS_SOCKIO_H
00055 #include <sys/sockio.h>
00056 #endif
00057 #endif
00058 
00059 #ifdef HAVE_STDLIB_H
00060 #include <stdlib.h>
00061 #endif
00062 
00063 #ifdef HAVE_STRING_H
00064 #include <string.h>
00065 #endif
00066 
00067 #ifdef HAVE_STRINGS_H
00068 #include <strings.h>
00069 #endif
00070 
00071 #ifdef __COMPAR_FN_T
00072 #define QSORT_CAST (__compar_fn_t)
00073 #endif
00074 
00075 #ifndef QSORT_CAST
00076 #define QSORT_CAST (int (*)(const void *, const void *))
00077 #endif
00078 
00079 #ifdef HAVE_NET_IF_H
00080 #include <net/if.h>
00081 #endif
00082 
00083 #include "interfaces.h"
00084 
00085 #if HAVE_IFACE_IFCONF
00086 
00087 /* this works for Linux 2.2, Solaris 2.5, SunOS4, HPUX 10.20, OSF1
00088    V4.0, Ultrix 4.4, SCO Unix 3.2, IRIX 6.4 and FreeBSD 3.2.
00089 
00090    It probably also works on any BSD style system.  */
00091 
00092 /****************************************************************************
00093   get the netmask address for a local interface
00094 ****************************************************************************/
00095 static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
00096 {  
00097         struct ifconf ifc;
00098         char buff[8192];
00099         int fd, i, n;
00100         struct ifreq *ifr=NULL;
00101         int total = 0;
00102         struct in_addr ipaddr;
00103         struct in_addr nmask;
00104         char *iname;
00105 
00106         if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
00107                 return -1;
00108         }
00109   
00110         ifc.ifc_len = sizeof(buff);
00111         ifc.ifc_buf = buff;
00112 
00113         if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
00114                 close(fd);
00115                 return -1;
00116         } 
00117 
00118         ifr = ifc.ifc_req;
00119   
00120         n = ifc.ifc_len / sizeof(struct ifreq);
00121 
00122         /* Loop through interfaces, looking for given IP address */
00123         for (i=n-1;i>=0 && total < max_interfaces;i--) {
00124                 if (ioctl(fd, SIOCGIFADDR, &ifr[i]) != 0) {
00125                         continue;
00126                 }
00127 
00128                 iname = ifr[i].ifr_name;
00129                 ipaddr = (*(struct sockaddr_in *)&ifr[i].ifr_addr).sin_addr;
00130 
00131                 if (ioctl(fd, SIOCGIFFLAGS, &ifr[i]) != 0) {
00132                         continue;
00133                 }  
00134 
00135                 if (!(ifr[i].ifr_flags & IFF_UP)) {
00136                         continue;
00137                 }
00138 
00139                 if (ioctl(fd, SIOCGIFNETMASK, &ifr[i]) != 0) {
00140                         continue;
00141                 }  
00142 
00143                 nmask = ((struct sockaddr_in *)&ifr[i].ifr_addr)->sin_addr;
00144 
00145                 strncpy(ifaces[total].name, iname, sizeof(ifaces[total].name)-1);
00146                 ifaces[total].name[sizeof(ifaces[total].name)-1] = 0;
00147                 ifaces[total].ip = ipaddr;
00148                 ifaces[total].netmask = nmask;
00149                 total++;
00150         }
00151 
00152         close(fd);
00153 
00154         return total;
00155 }  
00156 
00157 #define _FOUND_IFACE_ANY
00158 #endif /* HAVE_IFACE_IFCONF */
00159 #ifdef HAVE_IFACE_IFREQ
00160 
00161 #ifndef I_STR
00162 #include <sys/stropts.h>
00163 #endif
00164 
00165 /****************************************************************************
00166 this should cover most of the streams based systems
00167 Thanks to Andrej.Borsenkow@mow.siemens.ru for several ideas in this code
00168 ****************************************************************************/
00169 static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
00170 {
00171         struct ifreq ifreq;
00172         struct strioctl strioctl;
00173         char buff[8192];
00174         int fd, i, n;
00175         struct ifreq *ifr=NULL;
00176         int total = 0;
00177         struct in_addr ipaddr;
00178         struct in_addr nmask;
00179         char *iname;
00180 
00181         if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
00182                 return -1;
00183         }
00184   
00185         strioctl.ic_cmd = SIOCGIFCONF;
00186         strioctl.ic_dp  = buff;
00187         strioctl.ic_len = sizeof(buff);
00188         if (ioctl(fd, I_STR, &strioctl) < 0) {
00189                 close(fd);
00190                 return -1;
00191         } 
00192 
00193         /* we can ignore the possible sizeof(int) here as the resulting
00194            number of interface structures won't change */
00195         n = strioctl.ic_len / sizeof(struct ifreq);
00196 
00197         /* we will assume that the kernel returns the length as an int
00198            at the start of the buffer if the offered size is a
00199            multiple of the structure size plus an int */
00200         if (n*sizeof(struct ifreq) + sizeof(int) == strioctl.ic_len) {
00201                 ifr = (struct ifreq *)(buff + sizeof(int));  
00202         } else {
00203                 ifr = (struct ifreq *)buff;  
00204         }
00205 
00206         /* Loop through interfaces */
00207 
00208         for (i = 0; i<n && total < max_interfaces; i++) {
00209                 ifreq = ifr[i];
00210   
00211                 strioctl.ic_cmd = SIOCGIFFLAGS;
00212                 strioctl.ic_dp  = (char *)&ifreq;
00213                 strioctl.ic_len = sizeof(struct ifreq);
00214                 if (ioctl(fd, I_STR, &strioctl) != 0) {
00215                         continue;
00216                 }
00217                 
00218                 if (!(ifreq.ifr_flags & IFF_UP)) {
00219                         continue;
00220                 }
00221 
00222                 strioctl.ic_cmd = SIOCGIFADDR;
00223                 strioctl.ic_dp  = (char *)&ifreq;
00224                 strioctl.ic_len = sizeof(struct ifreq);
00225                 if (ioctl(fd, I_STR, &strioctl) != 0) {
00226                         continue;
00227                 }
00228 
00229                 ipaddr = (*(struct sockaddr_in *) &ifreq.ifr_addr).sin_addr;
00230                 iname = ifreq.ifr_name;
00231 
00232                 strioctl.ic_cmd = SIOCGIFNETMASK;
00233                 strioctl.ic_dp  = (char *)&ifreq;
00234                 strioctl.ic_len = sizeof(struct ifreq);
00235                 if (ioctl(fd, I_STR, &strioctl) != 0) {
00236                         continue;
00237                 }
00238 
00239                 nmask = ((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr;
00240 
00241                 strncpy(ifaces[total].name, iname, sizeof(ifaces[total].name)-1);
00242                 ifaces[total].name[sizeof(ifaces[total].name)-1] = 0;
00243                 ifaces[total].ip = ipaddr;
00244                 ifaces[total].netmask = nmask;
00245 
00246                 total++;
00247         }
00248 
00249         close(fd);
00250 
00251         return total;
00252 }
00253 
00254 #define _FOUND_IFACE_ANY
00255 #endif /* HAVE_IFACE_IFREQ */
00256 #ifdef HAVE_IFACE_AIX
00257 
00258 /****************************************************************************
00259 this one is for AIX (tested on 4.2)
00260 ****************************************************************************/
00261 static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
00262 {
00263         char buff[8192];
00264         int fd, i;
00265         struct ifconf ifc;
00266         struct ifreq *ifr=NULL;
00267         struct in_addr ipaddr;
00268         struct in_addr nmask;
00269         char *iname;
00270         int total = 0;
00271 
00272         if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
00273                 return -1;
00274         }
00275 
00276 
00277         ifc.ifc_len = sizeof(buff);
00278         ifc.ifc_buf = buff;
00279 
00280         if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
00281                 close(fd);
00282                 return -1;
00283         }
00284 
00285         ifr = ifc.ifc_req;
00286 
00287         /* Loop through interfaces */
00288         i = ifc.ifc_len;
00289 
00290         while (i > 0 && total < max_interfaces) {
00291                 uint_t inc;
00292 
00293                 inc = ifr->ifr_addr.sa_len;
00294 
00295                 if (ioctl(fd, SIOCGIFADDR, ifr) != 0) {
00296                         goto next;
00297                 }
00298 
00299                 ipaddr = (*(struct sockaddr_in *) &ifr->ifr_addr).sin_addr;
00300                 iname = ifr->ifr_name;
00301 
00302                 if (ioctl(fd, SIOCGIFFLAGS, ifr) != 0) {
00303                         goto next;
00304                 }
00305 
00306                 if (!(ifr->ifr_flags & IFF_UP)) {
00307                         goto next;
00308                 }
00309 
00310                 if (ioctl(fd, SIOCGIFNETMASK, ifr) != 0) {
00311                         goto next;
00312                 }
00313 
00314                 nmask = ((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr;
00315 
00316                 strncpy(ifaces[total].name, iname, sizeof(ifaces[total].name)-1);
00317                 ifaces[total].name[sizeof(ifaces[total].name)-1] = 0;
00318                 ifaces[total].ip = ipaddr;
00319                 ifaces[total].netmask = nmask;
00320 
00321                 total++;
00322 
00323         next:
00324                 /*
00325                  * Patch from Archie Cobbs (archie@whistle.com).  The
00326                  * addresses in the SIOCGIFCONF interface list have a
00327                  * minimum size. Usually this doesn't matter, but if
00328                  * your machine has tunnel interfaces, etc. that have
00329                  * a zero length "link address", this does matter.  */
00330 
00331                 if (inc < sizeof(ifr->ifr_addr))
00332                         inc = sizeof(ifr->ifr_addr);
00333                 inc += IFNAMSIZ;
00334 
00335                 ifr = (struct ifreq*) (((char*) ifr) + inc);
00336                 i -= inc;
00337         }
00338   
00339 
00340         close(fd);
00341         return total;
00342 }
00343 
00344 #define _FOUND_IFACE_ANY
00345 #endif /* HAVE_IFACE_AIX */
00346 #ifndef _FOUND_IFACE_ANY
00347 static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
00348 {
00349         return -1;
00350 }
00351 #endif
00352 
00353 
00354 static int iface_comp(struct iface_struct *i1, struct iface_struct *i2)
00355 {
00356         int r;
00357         r = strcmp(i1->name, i2->name);
00358         if (r) return r;
00359         r = ntohl(i1->ip.s_addr) - ntohl(i2->ip.s_addr);
00360         if (r) return r;
00361         r = ntohl(i1->netmask.s_addr) - ntohl(i2->netmask.s_addr);
00362         return r;
00363 }
00364 
00365 int get_interfaces(struct iface_struct *ifaces, int max_interfaces);
00366 /* this wrapper is used to remove duplicates from the interface list generated
00367    above */
00368 int get_interfaces(struct iface_struct *ifaces, int max_interfaces)
00369 {
00370         int total, i, j;
00371 
00372         total = _get_interfaces(ifaces, max_interfaces);
00373         if (total <= 0) return total;
00374 
00375         /* now we need to remove duplicates */
00376         qsort(ifaces, total, sizeof(ifaces[0]), QSORT_CAST iface_comp);
00377 
00378         for (i=1;i<total;) {
00379                 if (iface_comp(&ifaces[i-1], &ifaces[i]) == 0) {
00380                         for (j=i-1;j<total-1;j++) {
00381                                 ifaces[j] = ifaces[j+1];
00382                         }
00383                         total--;
00384                 } else {
00385                         i++;
00386                 }
00387         }
00388 
00389         return total;
00390 }
00391 
00392 
00393 #ifdef AUTOCONF_TEST
00394 /* this is the autoconf driver to test get_interfaces() */
00395 
00396  int main()
00397 {
00398         struct iface_struct ifaces[MAX_INTERFACES];
00399         int total = get_interfaces(ifaces, MAX_INTERFACES);
00400         int i;
00401 
00402         printf("got %d interfaces:\n", total);
00403         if (total <= 0) exit(1);
00404 
00405         for (i=0;i<total;i++) {
00406                 printf("%-10s ", ifaces[i].name);
00407                 printf("IP=%s ", inet_ntoa(ifaces[i].ip));
00408                 printf("NETMASK=%s\n", inet_ntoa(ifaces[i].netmask));
00409         }
00410         return 0;
00411 }
00412 #endif

Sambaに対してSat Aug 29 21:22:58 2009に生成されました。  doxygen 1.4.7