[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 |
Splash - DocumentationSNMP Plus a Lightweight API for SNAP Handlingsnap_svc/snap_svc_if.cGo 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 |