[insert project logo here (125x200px max)]

Navigator

Mailinglists

Please report any errors or ommissions you find to our `Help' mailinglist, or post a message in the Forums.

Copyright and Licensing Information

Snap is (c) Jonathan T. Moore, 1999-2002 and licensed under the GNU General Public License (GPL).

All other parts of Splash are (c) Willem de Bruijn, 2002-2003 and licensed under the BSD Open Source License.

All sourcecode is made publicly available.

Acknowledgement

Splash and the Splash website are hosted by SourceForge.net

SourceForge.net Logo

osi-open source certified logo

Splash - Documentation

SNMP Plus a Lightweight API for SNAP Handling

Main Page   Alphabetical List   Data Structures   File List   Data Fields   Globals  

snap_svc/snap_svc_if.c

Go to the documentation of this file.
00001 /* snap service library                 */
00002 /* (c) Willem de Bruijn, 2002, 2003     */
00003 /* Licensed under the BSD License       */
00004 /* snap_svc_if library sourcefile   */
00005 
00006 /* platform includes (linux) */
00007 #include <sys/ioctl.h>
00008 #include <sys/socket.h>
00009 #include <asm/types.h>
00010 #include <netinet/in.h>
00011 #include <net/if.h>
00012 
00013 /* libc includes */
00014 #include <string.h>
00015 #include <arpa/inet.h>
00016 #include <unistd.h>
00017 #include <stdlib.h>
00018 #include <stdio.h>
00019 
00020 /* local includes */
00021 #include "d_printf.h"
00022 #include "snap_svc.h"
00023 #include "snap_svc_if.h"
00024 
00025 /* global variables */
00026 unsigned int snap_svc_if_count = 0;
00027 unsigned int snap_svc_if_maxidx = 0;
00028 struct snap_svc_ifip_item* iface_list = NULL;
00029 
00030 /* library handling functions */
00031 void snap_external_svclib_init(){
00032 
00033     if (snap_svc_ifip_init())
00034         d_printf(50,"snap_svc_if : initialized\n");
00035     else
00036         d_printf(50,"snap_svc_if : initialized with errors\n");
00037 }
00038 
00039 void snap_external_svclib_done(){
00040     int count;
00041     
00042     if (iface_list){
00043         for(count=0; count == snap_svc_if_maxidx + 1; count++){
00044             if (iface_list[count].if_name)  /* if it exists */
00045                 free (iface_list[count].if_name);
00046         }
00047         free (iface_list);
00048     }
00049     d_printf(50,"snap_svc_if : closed\n");
00050 }
00051 
00052 /* there is where functions inside the library should be listed for registration */
00053 void snap_external_svclib_getnextfunc(char** snapsvc_name, snapsvc_func_proto* snapsvc_func, int* snapsvc_args, int* snapsvc_rets){
00054 
00055     switch (svc_fun_counter){
00056         case 0  :       (*snapsvc_name) = strdup ("if_getifacecount");
00057                         (*snapsvc_func) = (snapsvc_func_proto) &if_get_interface_count;
00058                         (*snapsvc_args) = 0;
00059                         (*snapsvc_rets) = SVC_SNMP_TYPE_INT;
00060                         break;
00061         case 1  :       (*snapsvc_name) = strdup ("if_getifacename");
00062                         (*snapsvc_func) = (snapsvc_func_proto) &if_get_interface_name;
00063                         (*snapsvc_args) = 1;
00064                         (*snapsvc_rets) = SVC_SNMP_TYPE_STRING;
00065                         break;
00066         case 2  :       (*snapsvc_name) = strdup ("if_getiface_flag");
00067                         (*snapsvc_func) = (snapsvc_func_proto) &if_getiface;
00068                         (*snapsvc_args) = 2;
00069                         (*snapsvc_rets) = SVC_SNMP_TYPE_INT;
00070                         break;
00071         case 3  :       (*snapsvc_name) = strdup ("if_getiface_up");
00072                         (*snapsvc_func) = (snapsvc_func_proto) &if_getiface_up;
00073                         (*snapsvc_args) = 1;
00074                         (*snapsvc_rets) = SVC_SNMP_TYPE_INT;
00075                         break;
00076         case 4  :       (*snapsvc_name) = strdup ("if_setiface_flag");
00077                         (*snapsvc_func) = (snapsvc_func_proto) &if_setiface;
00078                         (*snapsvc_args) = 3;
00079                         (*snapsvc_rets) = SVC_SNMP_TYPE_NULL;
00080                         break;
00081         case 5  :       (*snapsvc_name) = strdup ("if_setiface_up");
00082                         (*snapsvc_func) = (snapsvc_func_proto) &if_setiface_up;
00083                         (*snapsvc_args) = 2;
00084                         (*snapsvc_rets) = SVC_SNMP_TYPE_NULL;
00085                         break;
00086         case 6  :       (*snapsvc_name) = strdup ("if_getnexthop");
00087                         (*snapsvc_func) = (snapsvc_func_proto) &if_getnexthop;
00088                         (*snapsvc_args) = 1;
00089                         (*snapsvc_rets) = SVC_SNMP_TYPE_ADDR;
00090                         break;
00091         case 7  :       (*snapsvc_name) = strdup ("if_getallneighbours");
00092                         (*snapsvc_func) = (snapsvc_func_proto) &if_getallneighbours;
00093                         (*snapsvc_args) = 1;
00094                         (*snapsvc_rets) = SVC_SNMP_TYPE_NULL;
00095                         break;
00096         /* unknown handler -> return NULL as end-of-list symbol */
00097         default :   (*snapsvc_name) = NULL;
00098                     (*snapsvc_func) = NULL;
00099                     (*snapsvc_args) = 0;
00100                     (*snapsvc_rets) = 0;
00101     }
00102     svc_fun_counter ++;
00103 }
00104 
00105 /* ADD SERVICES BELOW */
00106 /* declarations of snap service handlers */
00107 
00108 /* initialize the interfaces and read IP addresses (if applicable) */
00109 int snap_svc_ifip_init(){
00110     int sk;
00111     struct if_nameindex *allifs;
00112     struct if_nameindex *currif;
00113     struct ifreq ifr;
00114 
00115     /* setup the socket for ioctl(..) access */
00116     sk = socket(PF_INET, SOCK_DGRAM, 0);
00117 
00118     /* collect IFACE info from glibc functions */
00119     if ((allifs = if_nameindex()) == NULL) {
00120         perror("if_nameindex");
00121     }
00122 
00123     /* calculate number of interfaces and maximum interface index */
00124     for (currif = allifs; (currif->if_index != 0) && (currif->if_name != NULL); currif++) {
00125         if (currif->if_index > snap_svc_if_maxidx) {
00126             snap_svc_if_maxidx = currif->if_index;
00127         }
00128         snap_svc_if_count++;
00129     }
00130     d_printf(40,"snap_svc_if : found %u interfaces, max index is %u\n",snap_svc_if_count, snap_svc_if_maxidx);
00131 
00132     if(snap_svc_if_maxidx <= 0){
00133         d_printf(20,"snap_svc_if : warning : found zero or less interfaces\n");
00134     }
00135 
00136     /* get additional IFACE info from local functions */
00137     if (iface_list){
00138         d_printf(40,"snap_svc_if : warning : reinitializing open iface list\n");
00139         free (iface_list);
00140     }
00141     iface_list = (struct snap_svc_ifip_item*) calloc (snap_svc_if_maxidx + 1, sizeof(struct snap_svc_ifip_item));
00142     for (currif = allifs;(currif->if_index != 0) && (currif->if_name != NULL); currif++) {
00143             /* incorporate data from the if_nameindex(..) call */
00144             iface_list[currif->if_index].if_index = currif->if_index;
00145             iface_list[currif->if_index].if_name = strdup(currif->if_name);
00146             
00147             /* get data from the kernel through ioctl(..) */
00148             strcpy(ifr.ifr_name, currif->if_name);
00149             if (ioctl(sk, SIOCGIFADDR, &ifr) < 0 ){
00150                 d_printf(20,"snap_svc_if : error while executing ioctl()\n");
00151                 iface_list[currif->if_index].addr = 0;
00152             }
00153             else
00154                 iface_list[currif->if_index].addr = (*(struct sockaddr_in *)(&ifr.ifr_addr)).sin_addr.s_addr;
00155             
00156             /* show some debugging info*/
00157             d_printf(100,"snap_svc_if : found interface [id=%u, name=%s, ip=%u.%u.%u.%u]\n",
00158                 iface_list[currif->if_index].if_index,
00159                 iface_list[currif->if_index].if_name,
00160                 iface_list[currif->if_index].addr >> 24,
00161                 iface_list[currif->if_index].addr << 8 >> 24,
00162                 iface_list[currif->if_index].addr << 16 >> 24,
00163                 iface_list[currif->if_index].addr << 24 >> 24);
00164     }
00165 
00166     /* free structure obtained by if_nameindex(..) call */
00167     if_freenameindex (allifs);
00168     close (sk);
00169 
00170     return snap_svc_if_maxidx;
00171 }
00172 
00173 /* returns the number of active interfaces */
00174 int if_get_interface_count(void* useless){
00175     struct ifconf ifc;
00176     struct ifreq ifrs[100];
00177     int sk;
00178     int i;
00179 
00180     sk = socket(PF_INET, SOCK_DGRAM, 0);
00181 
00182     ifc.ifc_len = sizeof(ifrs);
00183     ifc.ifc_req = ifrs;
00184     if (ioctl(sk, SIOCGIFCONF, &ifc) == -1){
00185         d_printf(10,"error >> if_get_interfaces : ioctl failed\n");
00186         return -1;
00187     }
00188 
00189     for (i = 0; i < ifc.ifc_len / sizeof(struct ifreq); i++) {
00190             struct ifreq *ifr = &ifrs[i];
00191             struct sockaddr_in *addr = (struct sockaddr_in *) &ifr->ifr_addr;
00192             d_printf(100,"%2d %-8s %-15s\n", i, ifr->ifr_name, inet_ntoa(addr->sin_addr)); 
00193     }
00194 
00195     close(sk);
00196     
00197     return (ifc.ifc_len / sizeof(struct ifreq));
00198 }
00199  
00200 /* translates an interface no into a name */
00201 char* if_get_interface_name(int dIfNo){
00202     struct ifconf ifc;
00203     struct ifreq ifrs[100];
00204     int sk;
00205     char* strIfName = NULL;
00206     
00207     sk = socket(PF_INET, SOCK_DGRAM, 0);
00208 
00209     ifc.ifc_len = sizeof(ifrs);
00210     ifc.ifc_req = ifrs;
00211     if (ioctl(sk, SIOCGIFCONF, &ifc) == -1){
00212         d_printf(10,"error >> if_get_interfaces : ioctl failed\n");
00213         return NULL;
00214     }
00215     
00216     if (dIfNo < ifc.ifc_len)
00217         strIfName = strdup(( &ifrs[dIfNo])->ifr_name );
00218             
00219     close(sk);
00220     
00221     return (strIfName);
00222 }
00223 
00224 /* test whether a flag is toggled */
00225 int if_getiface(const char* strIfName, int flag){
00226     int fd;
00227     struct ifreq ifr;
00228 
00229     fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
00230     strcpy(ifr.ifr_name, strIfName);
00231     if (ioctl(fd, SIOCGIFFLAGS, &ifr) == -1){
00232         d_printf(10,"error >> if_isup_interface : ioctl failed\n");
00233         return -1;
00234     }
00235     else{
00236         d_printf(100,"%s is %s\n", strIfName, (ifr.ifr_flags & IFF_UP) ? "up" : "down");
00237         return (ifr.ifr_flags & flag) ? 1 : 0;
00238     }
00239 }
00240 
00241 /* test whether an interface is up */
00242 int if_getiface_up(const char* strIfName){
00243     return if_getiface(strIfName, IFF_UP);
00244 }
00245 
00246 /* set an interface flag */
00247 /* flags are defined in linux/if.h */
00248 int if_setiface(const char* strIfName, int flag, int state){
00249     int fd;
00250     struct ifreq ifr;
00251 
00252     fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
00253     strcpy(ifr.ifr_name, strIfName);
00254     if (ioctl(fd, SIOCGIFFLAGS, &ifr) == -1){
00255         d_printf(10,"error >> if_isup_interface : ioctl failed\n");
00256         return -1;
00257     }
00258     if (state)
00259         ifr.ifr_flags |= flag;
00260     else
00261         ifr.ifr_flags ^= flag; /* XOR operator : set bit to zero */
00262     if (ioctl(fd, SIOCSIFFLAGS, &ifr) == -1){
00263         d_printf(10,"error >> if_isup_interface : ioctl failed\n");
00264         return -1;
00265     }
00266     else{
00267         d_printf(100,"%s is %s\n", strIfName, (ifr.ifr_flags & IFF_UP) ? "up" : "down");
00268         return if_getiface_up(strIfName);
00269     }
00270 }
00271 
00272 /* set the interface up/down flag */
00273 int if_setiface_up(const char* strIfName, int state){
00274     return if_setiface(strIfName, IFF_UP, state);
00275 }
00276 
00277 /* 
00278     ADVANCED : get low-level packet routing information
00279     (uses route access through /proc/net/route)
00280 
00281     we use a simple round-robin scheme for stateless network
00282     traversal. Calculate the incoming iface from the ip, find
00283     the next ip interface - forgetting localhost - and return
00284     this as a result.
00285 
00286     second, an oilstain spread of packets has been facilitated
00287     if_getallneighbours(..) resembles the algorithm discussed
00288     above, but extends it by returning all other (non localhost)
00289     devices. For this a single returnvalue cannot suffice, 
00290     therefore we resorted to using the struct svc_returnstruct
00291     defined in snap_svc.h
00292 */
00293 
00294 /* find the next interface by index in iface_table */
00295 unsigned int if_getnextiface(unsigned int iface_idx){
00296     unsigned int iface_nextidx=0;
00297     unsigned short bFound = 0;
00298     
00299     iface_nextidx = iface_idx + 1;      
00300     do {
00301         if (iface_nextidx > snap_svc_if_maxidx)
00302             iface_nextidx = 0;
00303             
00304         /* drop empty items and the local address */
00305         if (iface_list[iface_nextidx].addr != 0 && iface_list[iface_nextidx].addr != htonl((127 << 24) + 1))
00306             bFound = 1; 
00307         
00308         d_printf(200,"snap_sv_if_getoutiface : found addr %u.%u.%u.%u at index %u\n",iface_list[iface_nextidx].addr << 24>>24, iface_list[iface_nextidx].addr << 16 >>24, iface_list[iface_nextidx].addr << 8 >>24, iface_list[iface_nextidx].addr  >>24, iface_nextidx);
00309         
00310         if (!bFound)
00311             iface_nextidx++;
00312     } while (!bFound && iface_nextidx != iface_idx+1);  
00313     /* if nextidx=idx+1 we've searched the entire structure and have to use the previous interface*/
00314     
00315     return iface_nextidx;
00316 }
00317 
00318 /* search the iface list for the incoming ip address */
00319 unsigned int if_getifaceidx(uint32_t ip){
00320     int iface_counter=0;
00321     unsigned int iface_idx = 0;
00322     
00323     do {
00324         d_printf(200,"snap_svc_if_getifaceidx : comparing %u.%u.%u.%u with %u.%u.%u.%u\n",ip << 24 >> 24,ip << 16 >> 24 ,ip << 8 >> 24 ,ip >> 24 ,iface_list[iface_counter].addr << 24 >>24, iface_list[iface_counter].addr << 16 >>24, iface_list[iface_counter].addr << 8 >>24, iface_list[iface_counter].addr >>24);
00325         if (ip == iface_list[iface_counter].addr)
00326             iface_idx = iface_list[iface_counter].if_index;
00327         iface_counter++;
00328     } while (!iface_idx && iface_counter <= snap_svc_if_maxidx);
00329     
00330     return iface_idx;
00331 }
00332 
00333 /* select a new interface based on a given ip */
00334 char* if_getoutiface(uint32_t incoming_ip){
00335     unsigned int iface_idx = 0, iface_nextidx = 0;
00336     char* outgoing_name = NULL;
00337     
00338     /* safety check */
00339     if (!incoming_ip)
00340         snap_svc_ifip_init();
00341         
00342     /* get iface from incoming ip. drop if IP is not one of our local addresses */
00343     iface_idx = if_getifaceidx(incoming_ip);
00344     if (!iface_idx)
00345         return NULL;
00346     
00347     /* get the next interface */
00348     iface_nextidx = if_getnextiface(iface_idx);
00349     outgoing_name = iface_list[iface_nextidx].if_name;
00350     
00351     d_printf(100,"snap_svc_if_getoutiface : found hop with index %u and name %s\n",iface_nextidx,outgoing_name);
00352     return outgoing_name;
00353 }
00354 
00355 /* find an ip that is linked to the given interface */
00356 uint32_t if_gethopfromiface(char* if_outname){
00357     /* 
00358         scan the routetable for an appropriate destination 
00359         if it is a subnet then add a 1 to create a host
00360         this trick works when we use FORW,SEND,etc. *NOT* DFORW,DSEND,etc.
00361     */
00362     char buf[1024];
00363     FILE *f;
00364     uint32_t outgoing_ip=0;
00365     
00366     /* simple test */
00367     if (! if_outname){
00368         d_printf(40,"snap_svc_if_gethopfromiface : didn't receive an iface name... skipping\n");
00369         return 0;
00370     }
00371     
00372     f = fopen("/proc/net/route","r");
00373     if (f == NULL) {
00374         fprintf(stderr,"snap_svc_if_getnexthop : unable to open /proc/net/route\n");
00375         exit(1);
00376     }
00377 
00378     /* count number of routes */
00379     while(! outgoing_ip && fgets(buf,sizeof(buf),f)) {
00380         if (!strncmp(if_outname,buf,strlen(if_outname))){
00381             outgoing_ip = strtol(&buf[strlen(if_outname)], NULL, 16);
00382             if ((outgoing_ip >> 24) == 0)
00383                 outgoing_ip += 0x01000000; /* add .01 if dest is a network address */
00384             d_printf(50,"snap_svc_if_getnexthop : found destination %u.%u.%u.%u over iface %s\n",outgoing_ip << 24 >> 24,outgoing_ip << 16 >> 24,outgoing_ip << 8 >> 24,outgoing_ip >> 24,if_outname);
00385         }
00386     }
00387       
00388     return outgoing_ip;  
00389 }
00390 
00391 /* a wrapper for two previous functions */
00392 uint32_t if_getnexthop(uint32_t incoming_ip){
00393     char* if_outname = if_getoutiface(incoming_ip);
00394     if (!if_outname)
00395         return (1 << 24);   /* send to the standard route + 1 (0,0,0,1) in network byte order */
00396     else
00397         return if_gethopfromiface(if_outname);
00398 }
00399 
00400 /* return all neighbours through the returnstruct mechanism */
00401 void if_getallneighbours(uint32_t incoming_ip){
00402     unsigned int iface_idx=0;
00403     unsigned int iface_saveidx=0;
00404     unsigned int iface_nextidx=0;
00405     uint32_t uAddress;
00406     unsigned int iface_count=0;
00407     
00408     iface_idx=if_getifaceidx(incoming_ip);
00409     iface_saveidx = iface_idx;
00410 
00411     d_printf(100,"snap_svc_getallneighbours : packet entered from interface %u, discarding\n",iface_saveidx);   
00412     /* find all interfaces*/
00413     do {
00414         /* find the next interface */
00415         iface_nextidx = if_getnextiface(iface_idx);
00416 
00417         if (iface_nextidx != iface_idx && iface_list[iface_nextidx].addr){  /* only process interfaces other than the incoming iface */
00418             iface_count++;  
00419             iface_idx = iface_nextidx;  /* move the `current' pointer */
00420         }
00421     } while (iface_nextidx != iface_saveidx);
00422     
00423     d_printf(100,"snap_svc_if_getallneighbours : found %u items\n",iface_count);
00424 
00425     /* initialize the returnstruct */
00426     snap_external_svclib_free_local_returnstruct();
00427     svc_return = (struct svc_returnstruct*) calloc (1,sizeof(struct svc_returnstruct));
00428     svc_return->length = iface_count;
00429     svc_return->list = (struct svc_returnitem*) calloc (iface_count,sizeof(struct svc_returnitem));
00430 
00431     /* find the interfaces again and now place them inside the struct */
00432     iface_saveidx = iface_idx;
00433     do {
00434         /* find the next interface */
00435         iface_nextidx = if_getnextiface(iface_idx);
00436 
00437         if (iface_nextidx != iface_saveidx && iface_list[iface_nextidx].addr){  /* only process interfaces other than the incoming iface */
00438             uAddress=if_gethopfromiface(iface_list[iface_nextidx].if_name);
00439             d_printf(50,"snap_svc_if_getallneighbours : found destination %u.%u.%u.%u over iface %s\n",uAddress << 24 >> 24,uAddress << 16 >> 24,uAddress << 8 >> 24,uAddress >> 24,iface_list[iface_nextidx].if_name);
00440             
00441             /* write the value */
00442             svc_return->list[iface_count-1].type = SVC_SNMP_TYPE_ADDR;
00443             svc_return->list[iface_count-1].data = calloc (1, sizeof(uint32_t));
00444             memmove(svc_return->list[iface_count-1].data,&uAddress,sizeof(uint32_t));
00445             iface_count--;
00446             
00447             iface_idx = iface_nextidx;  /* move the `current' pointer */
00448         }
00449     } while (iface_nextidx != iface_saveidx && iface_count); /*NB second test shouldn't be an issue*/
00450 }
00451