ifls.c

00001 /* $Id$
00002  *
00003  *
00004  * test programs, list all interfaces and their ip address
00005  *
00006  * Copyright (C) 2001-2003 FhG Fokus
00007  *
00008  * This file is part of ser, a free SIP server.
00009  *
00010  * ser is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2 of the License, or
00013  * (at your option) any later version
00014  *
00015  * For a license to use the ser software under conditions
00016  * other than those described here, or to purchase support for this
00017  * software, please contact iptel.org by e-mail at the following addresses:
00018  *    info@iptel.org
00019  *
00020  * ser is distributed in the hope that it will be useful,
00021  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00022  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00023  * GNU General Public License for more details.
00024  *
00025  * You should have received a copy of the GNU General Public License 
00026  * along with this program; if not, write to the Free Software 
00027  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00028  */
00029  /*
00030   * History:
00031   * --------
00032   *  2002-09-09  created by andrei
00033   */
00034 
00035 
00036 
00037 #include <sys/types.h>
00038 #include <sys/socket.h>
00039 #include <netinet/in.h>
00040 #include <sys/ioctl.h>
00041 #include <net/if.h>
00042 #ifdef __sun__
00043 #include <sys/sockio.h>
00044 #endif
00045 
00046 #include <stdio.h>
00047 #include <stdlib.h>
00048 #include <ctype.h>
00049 #include <string.h>
00050 #include <unistd.h>
00051 #include <errno.h>
00052 
00053 #define FLAGS 1
00054 #define IF_DOWN 2
00055 #define IF_UP   4
00056 
00057 
00058 static char* version="ifls 0.1";
00059 static char* id="$Id$";
00060 static char* help_msg="\
00061 Usage: ifls [-6hV} [interface...]\n\
00062 (if no interface name is specified it will list all the interfaces)\n\
00063 Options:\n\
00064     -a      list both ipv4 and ipv6 interfaces (default)\n\
00065     -4      list only ipv4 interfaces\n\
00066     -6      list only ipv6 interfaces\n\
00067     -f      show also the interface flags\n\
00068     -U      brings all the matching interfaces up\n\
00069     -D      brings all the matching interfaces down\n\
00070     -V      version number\n\
00071     -h      this help message\n\
00072 ";
00073 
00074 
00075 #define MAX(a,b) ( ((a)>(b))?(a):(b))
00076 
00077 
00078 
00079 void print_sockaddr(struct sockaddr* sa)
00080 {
00081         unsigned char* buf;
00082         int r;
00083         
00084         switch(sa->sa_family){
00085         case AF_INET:
00086                 buf=(char*)&(((struct sockaddr_in*)sa)->sin_addr).s_addr;
00087                 printf("%d.%d.%d.%d\n", buf[0], buf[1], buf[2], buf[3]);
00088                 break;
00089         case AF_INET6:
00090                 buf=(((struct sockaddr_in6*)sa)->sin6_addr).s6_addr;
00091                 for(r=0; r<16; r++) 
00092                         printf("%02x%s", buf[r], ((r%2)&&(r!=15))?":":"" );
00093                 printf("\n");
00094                 break;
00095         default:
00096                 printf("unknown af %d\n", sa->sa_family);
00097 #ifdef __FreeBSD__
00098                 for (r=0; r<sa->sa_len; r++) 
00099                         printf("%02x ", ((unsigned char*)sa)[r]);
00100                 printf("\n");
00101 #endif
00102         }
00103 }
00104 
00105 
00106 
00107 int ls_ifflags(char* name, int family , int options)
00108 {
00109         struct ifreq ifr;
00110         int s;
00111         
00112         memset(&ifr, 0, sizeof(ifr)); /* init to 0 (check if filled)*/
00113         s=socket(family, SOCK_DGRAM, 0);
00114         strncpy(ifr.ifr_name, name, IFNAMSIZ);
00115 #if 0   
00116         if (ioctl(s, SIOCGIFADDR, &ifr)==-1){
00117                 if(errno==EBADF) return 0; /* invalid descriptor => no address*/
00118                 fprintf(stderr, "ls_if: ioctl for %s failed: %s\n", name, 
00119                                         strerror(errno));
00120                 goto error;
00121         };
00122         
00123         printf("%s:\n", ifr.ifr_name);
00124         printf("        dbg: family=%d", ifr.ifr_addr.sa_family);
00125 #ifdef __FreeBSD__
00126         printf(", len=%d\n", ifr.ifr_addr.sa_len);
00127 #else
00128         printf("\n");
00129 #endif
00130         if (ifr.ifr_addr.sa_family==0){
00131                 printf("ls_if: OS BUG: SIOCGIFADDR doesn't work!\n");
00132                 goto error;
00133         }
00134         
00135         printf("        ");
00136         print_sockaddr(&ifr.ifr_addr);
00137 
00138         if (ifr.ifr_addr.sa_family!=family){
00139                 printf("ls_if: strange family %d\n", ifr.ifr_addr.sa_family);
00140                 /*goto error;*/
00141         }
00142 #endif
00143         if (options & (FLAGS|IF_DOWN|IF_UP)){
00144                 if (ioctl(s, SIOCGIFFLAGS, &ifr)==-1){
00145                         fprintf(stderr, "ls_if: flags ioctl for %s  failed: %s\n",
00146                                         name, strerror(errno));
00147                         goto error;
00148                 }
00149                 if (ifr.ifr_flags & IFF_UP) printf ("UP ");
00150                 if (ifr.ifr_flags & IFF_BROADCAST) printf ("BROADCAST ");
00151                 if (ifr.ifr_flags & IFF_DEBUG) printf ("DEBUG ");
00152                 if (ifr.ifr_flags & IFF_LOOPBACK) printf ("LOOPBACK ");
00153                 if (ifr.ifr_flags & IFF_POINTOPOINT) printf ("POINTOPOINT ");
00154                 if (ifr.ifr_flags & IFF_RUNNING) printf ("RUNNING ");
00155                 if (ifr.ifr_flags & IFF_NOARP) printf ("NOARP ");
00156                 if (ifr.ifr_flags & IFF_PROMISC) printf ("PROMISC ");
00157                 /*if (ifr.ifr_flags & IFF_NOTRAILERS) printf ("NOTRAILERS ");*/
00158                 if (ifr.ifr_flags & IFF_ALLMULTI) printf ("ALLMULTI ");
00159                 /*if (ifr.ifr_flags & IFF_MASTER) printf ("MASTER ");*/
00160                 /*if (ifr.ifr_flags & IFF_SLAVE) printf ("SLAVE ");*/
00161                 if (ifr.ifr_flags & IFF_MULTICAST) printf ("MULTICAST ");
00162                 /*if (ifr.ifr_flags & IFF_PORTSEL) printf ("PORTSEL ");*/
00163                 /*if (ifr.ifr_flags & IFF_AUTOMEDIA) printf ("AUTOMEDIA ");*/
00164                 /*if (ifr.ifr_flags & IFF_DYNAMIC ) printf ("DYNAMIC ");*/
00165                 printf ("\n");
00166                 if (options & IF_DOWN){
00167                         ifr.ifr_flags &= ~IFF_UP;
00168                 }
00169                 if (options & IF_UP){
00170                         ifr.ifr_flags |= IFF_UP;
00171                 }
00172                 if (options & (IF_UP|IF_DOWN)){
00173                         if (ioctl(s, SIOCSIFFLAGS, &ifr)==-1){
00174                                 fprintf(stderr, "ls_if: set flags ioctl for %s  failed: %s\n",
00175                                                 name, strerror(errno));
00176                                 goto error;
00177                         }
00178                 }
00179         };
00180                 
00181         close(s);
00182         return 0;
00183 error:
00184         close(s);
00185         return -1;
00186 }
00187 
00188 
00189 
00190 int ls_ifs(char* name, int family, int options)
00191 {
00192         struct ifconf ifc;
00193         struct ifreq* ifr;
00194         char*  last;
00195         int size;
00196         int lastlen;
00197         int s;
00198         
00199         /* ipv4 or ipv6 only*/
00200         s=socket(family, SOCK_DGRAM, 0);
00201         lastlen=0;
00202         for (size=2; ; size*=2){
00203                 ifc.ifc_len=size*sizeof(struct ifreq);
00204                 ifc.ifc_req=(struct ifreq*) malloc(size*sizeof(struct ifreq));
00205                 if (ifc.ifc_req==0){
00206                         fprintf(stderr, "memory allocation failure\n");
00207                         goto error;
00208                 }
00209                 if (ioctl(s, SIOCGIFCONF, &ifc)==-1){
00210                         if(errno==EBADF) return 0; /* invalid descriptor => no such ifs*/
00211                         fprintf(stderr, "ioctl failed: %s\n", strerror(errno));
00212                         goto error;
00213                 }
00214                 if  ((lastlen) && (ifc.ifc_len==lastlen)) break; /*success,
00215                                                                                                                    len not changed*/
00216                 lastlen=ifc.ifc_len;
00217                 /* try a bigger array*/
00218                 free(ifc.ifc_req);
00219         }
00220         
00221         last=(char*)ifc.ifc_req+ifc.ifc_len;
00222         for(ifr=ifc.ifc_req; (char*)ifr<last;
00223                         ifr=(struct ifreq*)((char*)ifr+sizeof(ifr->ifr_name)+
00224                         #ifdef  __FreeBSD__
00225                                 MAX(ifr->ifr_addr.sa_len, sizeof(struct sockaddr))
00226                         #else
00227                                 ( (ifr->ifr_addr.sa_family==AF_INET)?
00228                                         sizeof(struct sockaddr_in):
00229                                         ((ifr->ifr_addr.sa_family==AF_INET6)?
00230                                                 sizeof(struct sockaddr_in6):sizeof(struct sockaddr)) )
00231                         #endif
00232                                 )
00233                 )
00234         {
00235 /*
00236                 printf("\nls_all dbg: %s family=%d", ifr->ifr_name,
00237                                                                                 ifr->ifr_addr.sa_family);
00238 #ifdef __FreeBSD__
00239                 printf(", len=%d\n", ifr->ifr_addr.sa_len);
00240 #else
00241                 printf("\n");
00242 #endif
00243 */
00244                 if (ifr->ifr_addr.sa_family!=family){
00245                         /*printf("strange family %d skipping...\n",
00246                                         ifr->ifr_addr.sa_family);*/
00247                         continue;
00248                 }
00249                 if ((name==0)||
00250                         (strncmp(name, ifr->ifr_name, sizeof(ifr->ifr_name))==0)){
00251                         printf("%s:\n", ifr->ifr_name);
00252                         printf("        ");
00253                         print_sockaddr(&(ifr->ifr_addr));
00254                         printf("        ");
00255                         ls_ifflags(ifr->ifr_name, family, options);
00256                         printf("\n");
00257                 }
00258         }
00259         free(ifc.ifc_req); /*clean up*/
00260         close(s);
00261         return  0;
00262 error:
00263         close(s);
00264         return -1;
00265 }
00266 
00267 
00268 int main(int argc, char**argv)
00269 {
00270         char** name;
00271         int no;
00272         int options;
00273         int ipv6, ipv4;
00274         int r;
00275         char c;
00276         
00277         
00278         options=0;
00279         ipv6=ipv4=1;
00280         name=0;
00281         no=0;
00282         opterr=0;
00283         while((c=getopt(argc, argv, "a46fhVUD"))!=-1){
00284                 switch(c){
00285                         case 'a':
00286                                 ipv6=ipv4=1;
00287                                 break;
00288                         case '4':
00289                                 ipv6=0;
00290                                 ipv4=1;
00291                                 break;
00292                         case '6':
00293                                 ipv4=0;
00294                                 ipv6=1;
00295                                 break;
00296                         case 'f':
00297                                 options|=FLAGS;
00298                                 break;
00299                         case 'V':
00300                                 printf("version: %s\n", version);
00301                                 printf("%s\n", id);
00302                                 exit(0);
00303                                 break;
00304                         case 'D':
00305                                 options|=IF_DOWN;
00306                                 break;
00307                         case 'U':
00308                                 options|=IF_UP;
00309                                 break;
00310                         case 'h':
00311                                 printf("version: %s\n", version);
00312                                 printf("%s", help_msg);
00313                                 exit(0);
00314                                 break;
00315                         case '?':
00316                                 if (isprint(optopt))
00317                                         fprintf(stderr, "Unknown option `-%c´\n", optopt);
00318                                 else
00319                                         fprintf(stderr, "Unknown character `\\x%x´\n", optopt);
00320                                 goto error;
00321                         case ':':
00322                                 fprintf(stderr, "Option `-%c´ requires an argument\n",
00323                                                 optopt);
00324                                 goto error;
00325                         default:
00326                                 abort();
00327                 };
00328         };
00329         /* check if we have non-options */
00330         if( optind < argc){
00331                 no=argc-optind;
00332                 name=&argv[optind];
00333         }
00334         
00335         if (no==0){
00336                 /* list all interfaces */
00337                 if (ipv4) ls_ifs(0, AF_INET, options);
00338                 if (ipv6) ls_ifs(0, AF_INET6, options);
00339         }else{
00340                 for(r=0; r<no; r++){
00341                         if (ipv4) ls_ifs(name[r], AF_INET, options);
00342                         if (ipv6) ls_ifs(name[r], AF_INET6, options);
00343                 }
00344         };
00345         
00346         
00347         exit(0);
00348 error:
00349         exit(-1);
00350 };