OSDN Git Service

1d5bf63efed79161ea72c0fbf54e34d25a049ac2
[opengatem/opengatem.git] / mdsrc / packetcache.c
1 /**************************************************
2 opengate Mac addr auth program
3
4  module to control cache of mac and ip address pair
5   to skip checking every packets.
6   All detected address pair (allowable or not) are cached.
7
8   As checking packet is time consuming procedure,
9   the recently checked addresses are cached and skiped.
10   Implemented with HashTable and Queue.
11   HashTable:
12     Key= comcatenation of MAC and IP Addresses
13     Val= checked time
14     If address pair is included in table and time is new, skip checking.
15   Queue:
16     Address pair odrered by checked time.
17     If an old item is found in table, elder items are removed from table.
18     The queue controls the remove sequence.
19
20 Copyright (C) 2011 Opengate Project Team
21 Written by Yoshiaki Watanabe
22
23 This program is free software; you can redistribute it and/or
24 modify it under the terms of the GNU General Public License
25 as published by the Free Software Foundation; either version 2
26 of the License, or (at your option) any later version.
27
28 This program is distributed in the hope that it will be useful,
29 but WITHOUT ANY WARRANTY; without even the implied warranty of
30 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
31 GNU General Public License for more details.
32
33 You should have received a copy of the GNU General Public License
34 along with this program; if not, write to the Free Software
35 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
36
37 Email: watanaby@is.saga-u.ac.jp
38 **************************************************/
39 #include "opengatemd.h"
40
41 #define CACHESIZE 1000000 /* mac&ip cache size */
42
43 int InitQueueForCache(void);
44 int EnQueueForCache(unsigned char* addrRaw, int addrLen);
45 int DeQueueForCache(unsigned char* addrRaw, int* pAddrLen);
46 int ListQueueForCache(void);
47 void FreeQueueForCache(void);
48
49 /* Queue to store MacAndIpAddress */
50 struct queueNode{
51   int addrLen;
52   unsigned char addrRaw[MACADDRLN+IPV6ADDRLN];
53   struct queueNode *next;
54 };
55 static struct queueNode* queueTail=NULL;
56 static struct queueNode* queueHead=NULL;
57
58 /* HashTable to store MacAndIpAddress and Time */
59 static DB* hashDb;
60
61 /* Cache Timeout(seconds) : packet checking interval */
62 static int cacheTimeout;
63
64 static int cacheItemCount=0;
65
66 /**********************************
67 This cache is made from HashTable and Queue.
68 HashTabel for quick access, and Queue for ordering.
69 Same data are stored in the two data structures.
70 If you add/delete items in cache, treat both structures.
71 Don't add/delete items from one structure only. 
72 ***********************************/
73
74 /****************************************
75 Is the IpAddress checked recently or not
76  input=ipAddress return TRUE if checked recently
77 ****************************************/
78 int isRecentlyCheckedAddress(unsigned char* macAndIpAddressRaw, int addrLen){
79
80   int timeNow;
81   unsigned char storedAddrRaw[MACADDRLN+IPV6ADDRLN];
82   int storedAddrLen;
83   int ret;
84   int* pTime;
85   DBT hashKey;
86   DBT hashVal;
87
88   /* get present time */
89   timeNow=time(NULL);
90
91   /***** get item matched to the mac&ip from hash table */
92   hashKey.data = macAndIpAddressRaw;
93   hashKey.size = addrLen;
94   memset(&hashVal, 0, sizeof(DBT));
95   ret=hashDb->get(hashDb, &hashKey, &hashVal, 0);
96
97   /* getting from hash is successed */
98   if(ret==0){
99
100     /* pick up the pointer to the value */
101     pTime=(int*)(hashVal.data);
102
103     /* if data is null, return NO */
104     if(pTime==NULL) return FALSE;
105
106     /* if ignoring addresses(exceptional setting), return YES */
107     if(*pTime==0) return TRUE;
108
109     /* if recently checked data, return YES */
110     if( (timeNow-*pTime) < cacheTimeout ) return TRUE;
111
112     /***** if timeover, elder items are removed from queue and hashTable */
113     /* dequeue data from queue head and inspect the address */
114     /* until present address is found. */
115     while(DeQueueForCache(storedAddrRaw, &storedAddrLen)){
116       hashKey.data=storedAddrRaw;
117       hashKey.size = storedAddrLen;
118       hashDb->del(hashDb, &hashKey, 0);
119       if(memcmp(macAndIpAddressRaw,storedAddrRaw,storedAddrLen)==0)break;
120     }
121
122     /* insert update item to queue and hashTable */
123     EnQueueForCache(storedAddrRaw, storedAddrLen);
124     hashVal.data = &timeNow;
125     hashVal.size = sizeof(int);    
126     if(hashDb->put(hashDb, &hashKey, &hashVal, 0) == -1) {
127       err_msg("ERR at %s#%d: fail to put into hash table",__FILE__,__LINE__);
128       terminateProg(0);
129     }
130
131     /* and return NO */
132     return FALSE;
133   }
134
135   /* if getting from hash is failed, insert address and return NO */
136   if(ret==1){
137
138     /*************** begin adding item to Cache ***/
139     /* insert to hash table */
140     hashVal.data = &timeNow;
141     hashVal.size = sizeof(int);    
142     if(hashDb->put(hashDb, &hashKey, &hashVal, 0) == -1) {
143       err_msg("ERR at %s#%d: fail to put into hash table",__FILE__,__LINE__);
144       terminateProg(0);
145     }
146     /* insert to queue */
147     EnQueueForCache(macAndIpAddressRaw, addrLen);
148     /*************** end adding item to Cache ***/
149
150     /* if cache size is over, remove oldest one */
151     if(cacheItemCount>CACHESIZE) DelOldestCacheItem();
152     return FALSE;
153   }
154
155   /* else error exit */
156   err_msg("ERR at %s#%d: fail to get hash table item",__FILE__,__LINE__);
157   return FALSE;
158 }
159
160 /****************************************
161 initialize Mac&IpAddress Cache
162  Mac&Ip Cache is formed with in HashTable and Queue
163  HashTable=to search an item quickly
164  Queue    =to list items in FIFO order
165 ****************************************/
166 void initCache(void) {
167
168   /* prepare hash table */
169   if((hashDb = dbopen(NULL, O_CREAT | O_RDWR, 0644, DB_HASH, NULL)) == NULL) {
170     err_msg("ERR at %s#%d: fail to open hash table",__FILE__,__LINE__);
171     terminateProg(0);
172   }
173
174   /* prepare queue */
175   InitQueueForCache();
176
177   /* set timeout parameter */
178   cacheTimeout=atoi(GetConfValue("CacheTimeout"));
179 }
180
181 /****************************************
182 memory free for Mac&IpAddress Cache
183 ****************************************/
184 void freeCache(void) {
185
186   hashDb->close(hashDb);
187   FreeQueueForCache();
188 }
189
190
191 /****************************************
192 delete item from MacAndIp cache matched to the mac or/and ip address
193 set arguments for mac and/or ip to detele
194 set argument as "", if the address is not known 
195  eg: to delete item for an ipv4 and unknown mac, ("", "192.168.0.100")
196 ****************************************/
197 int delCacheItem(char* macAddress, char* ipAddress) {
198   int found=FALSE;
199   DBT hashKey;
200   unsigned char addrRaw[MACADDRLN+IPV6ADDRLN];
201   unsigned char* pRawMac;
202   struct queueNode *temp;
203   struct queueNode *prev;
204   int inMac=FALSE;
205   int inIpv4=FALSE;
206   int inIpv6=FALSE;
207   int shift=0;
208   int length=0;
209
210   /*** set the raw values */
211   /* if mac is not null, set the mac raw value */
212   if(!isNull(macAddress)) {
213     if((pRawMac=(unsigned char*)ether_aton(macAddress)) != NULL){
214       memcpy(addrRaw, pRawMac, MACADDRLN);
215       inMac=TRUE;
216     }
217   }
218
219   /* if ip is not null, set the ipv6/ipv4 raw value */
220   if(!isNull(ipAddress)) {
221     if(strchr(ipAddress, ':') != NULL) {
222       if(inet_pton(AF_INET6, ipAddress, addrRaw+MACADDRLN) > 0) inIpv6=TRUE;
223     }
224     else{
225       if(inet_pton(AF_INET, ipAddress, addrRaw+MACADDRLN) > 0) inIpv4=TRUE;
226     }
227   }
228   
229   /*** set start point and length for comparing string */
230   if(inMac && !inIpv6 && !inIpv4){ /* only mac is indivcated */
231     shift=0;
232     length=MACADDRLN;
233   }
234   else if(!inMac && inIpv6){ /* only ipv6 is indicated */
235    shift=MACADDRLN;
236    length=IPV6ADDRLN;
237   }
238   else if(!inMac && inIpv4){ /* only ipv4 is indicated */
239     shift=MACADDRLN;
240     length=IPV4ADDRLN;
241   }
242   else if(inMac && inIpv6){ /* mac and ipv6 is indicated */
243     shift=0;
244     length=MACADDRLN+IPV6ADDRLN;
245   }
246   else if(inMac && inIpv4){ /* mac and ipv4 is indicated */
247     shift=0;
248     length=MACADDRLN+IPV4ADDRLN;
249   }
250   else{ /* no one is indicated */
251     return FALSE;
252   }
253
254   /*** scan queue to find matched address */
255   /* set search point to the head of mac-ip cache */
256   if(queueHead==NULL) return FALSE;
257   prev=queueHead;
258   temp=queueHead->next;
259
260   /* scan from queue head to tail */
261   while(temp->next!=NULL){
262
263     /* compare indicated value and queue value */
264     if(memcmp(addrRaw+shift, (temp->addrRaw)+shift, length)==0){
265
266       /* set found flag */
267       found=TRUE;
268
269       /* delete the item from Hash Table */
270       hashKey.data = temp->addrRaw;
271       hashKey.size = temp->addrLen;
272       hashDb->del(hashDb, &hashKey, 0);
273
274       /* delete the item from Queue */
275       prev->next=temp->next;
276       free(temp);
277       temp=prev;
278     }
279
280     /* move to next item */
281     prev=temp;
282     temp=temp->next;
283   }
284   return found;
285 }
286
287 /****************************************
288 delete oldest item from MacAndIp cache 
289 ****************************************/
290 int delOldestCacheItem(void) {
291   DBT hashKey;
292   unsigned char addrRaw[MACADDRLN+IPV6ADDRLN];
293   int addrLen=0;
294   
295   /* delete oldest item(=head) from queue */
296   if(DeQueueForCache(addrRaw, &addrLen)){
297
298     /* delete the item from Hash Table */
299     hashKey.data = addrRaw;
300     hashKey.size = addrLen;
301     hashDb->del(hashDb, &hashKey, 0);
302     
303     return TRUE;
304   }
305
306   return FALSE;
307 }
308
309 /*********************************************
310 initialize MacAndIpAddress Queue
311  Queue
312  HeadNode - DataNode - DataNode - TailNode
313  (dummy)                           (dummy)
314   ^queueHead                        ^queueTail
315 *********************************************/
316 int initQueueForCache(void){
317
318   unsigned char addrRaw[MACADDRLN+IPV6ADDRLN];
319   int addrLen;
320
321   /* if not exist, prepare head and tail */
322   if(queueHead==NULL){
323     queueHead=(struct queueNode*)malloc(sizeof(struct queueNode));
324     if(queueHead==NULL){
325       err_msg("ERR at %s#%d: fail to malloc",__FILE__,__LINE__);
326       terminateProg(0);
327     }
328     queueTail=(struct queueNode*)malloc(sizeof(struct queueNode));
329     if(queueTail==NULL){
330       err_msg("ERR at %s#%d: fail to malloc",__FILE__,__LINE__);
331       terminateProg(0);
332     }
333     bzero(queueHead->addrRaw, MACADDRLN+IPV6ADDRLN);
334     queueHead->addrLen=0;
335     bzero(queueTail->addrRaw, MACADDRLN+IPV6ADDRLN);
336     queueTail->addrLen=0;
337     queueHead->next=queueTail;
338     queueTail->next=NULL;
339   }
340   
341   /* if exist, reset all */
342   else{
343     while(DeQueueForCache(addrRaw,&addrLen))
344       ;
345   }
346
347   /* reset item count */
348   cacheItemCount=0;
349
350   return TRUE;
351 }
352
353 /****************************************
354 Add data to the tail of MacAndIP Queue
355  input=addr
356 ****************************************/
357 int enQueueForCache(unsigned char* addrRaw, int addrLen){
358   struct queueNode *newNode;
359
360   /* if not prepared, error */
361   if(queueHead==NULL){
362     err_msg("ERR at %s#%d: queue not init",__FILE__,__LINE__);
363     return FALSE;
364   }
365
366   /* add item after the tail and set it as new tail*/
367   newNode=(struct queueNode*)malloc(sizeof(struct queueNode));
368   if(newNode==NULL){
369     err_msg("ERR at %s#%d: fail to malloc",__FILE__,__LINE__);
370     terminateProg(0);
371   }
372   memcpy(queueTail->addrRaw, addrRaw, addrLen);
373   queueTail->addrLen=addrLen;
374   queueTail->next=newNode;
375   queueTail=newNode;
376   bzero(queueTail->addrRaw,MACADDRLN+IPV6ADDRLN);
377   queueTail->addrLen=0;
378   queueTail->next=NULL;
379
380   /* increment item count */
381   cacheItemCount++;
382
383   return TRUE;
384 }
385
386 /****************************************
387 Get and remove address data from the head of MacAndIP Queue
388 output
389  addrRaw:binary string of Mac&Ip (length=MACADDRLN+IPV6ADDRLN)
390  pAddrLen: pointer to the aquired string length 
391 ****************************************/
392 int deQueueForCache(unsigned char* addrRaw, int* pAddrLen){
393
394   /* set null string as default */
395   bzero(addrRaw, MACADDRLN+IPV6ADDRLN);
396
397   /* if not prepared, error */
398   if(queueHead==NULL){
399     err_msg("ERR at %s#%d: queue not init",__FILE__,__LINE__);
400     return FALSE;
401   }
402   else if(queueHead->next==NULL){
403     err_msg("ERR at %s#%d: queue not init",__FILE__,__LINE__);
404     return FALSE;  
405   }
406
407   /* if no data, return false */
408   else if(queueHead->next==queueTail){
409     return FALSE;
410   }
411
412   /* get item from the head */
413   else {
414     struct queueNode *temp;
415     temp=queueHead->next;
416     queueHead->next=temp->next;
417     memcpy(addrRaw, temp->addrRaw, temp->addrLen);
418     *pAddrLen=temp->addrLen;
419     free(temp);
420
421     /* decrement item count */
422     cacheItemCount--;
423   }
424
425   return TRUE;
426 }
427
428 /****************************************
429 Listing MacAndIpAddress Queue (for debugging)
430 ****************************************/
431 int listQueueForCache(void){
432
433   struct queueNode *temp;
434   int i;
435
436   printf("Queue items\n");
437   if(queueHead==NULL) return FALSE;
438   temp=queueHead->next;
439   while(temp->next!=NULL){
440     for(i=0;i<temp->addrLen;i++){
441       printf("%x ", temp->addrRaw[i]);
442     }
443     printf("\n");
444     temp=temp->next;
445   }
446   printf("---\n");
447   return TRUE;
448 }
449
450 /****************************************
451 memory free for MacAndIpAddress Queue
452 ****************************************/
453 void freeQueueForCache(void){
454   unsigned char addrRaw[MACADDRLN+IPV6ADDRLN];
455   int addrLen;
456   while(DeQueueForCache(addrRaw,&addrLen));
457   free(queueHead);
458   free(queueTail);
459 }
460
461 /************************************/
462 /* arp form is reformed to ndp form */ 
463 /* format macAddr for ndp or arp    */
464 /* match the form of two program    */
465 /* mac addr by arp 00:01:12:0b:..   */
466 /* mac addr by ndp 0:1:12:b:..      */
467 /* DO NOT CALL IT WITH CONST STRING */
468 /************************************/
469 int reFormatMacAddr(char* macAddr)
470 {
471   int m1,m2,m3,m4,m5,m6;
472   if(sscanf(macAddr, "%x:%x:%x:%x:%x:%x", &m1,&m2,&m3,&m4,&m5,&m6)!=6) return FALSE;
473   snprintf(macAddr, ADDRMAXLN,"%02x:%02x:%02x:%02x:%02x:%02x", m1,m2,m3,m4,m5,m6);
474   return TRUE;
475 }
476
477
478 /****************************************************
479  routines for debugging putput
480  ***************************************************/
481
482 void InitCache(void) {
483   if(debug>1) err_msg("DEBUG:=>initCache( )");
484   initCache();
485   if(debug>1) err_msg("DEBUG:<=initCache( )");
486 }
487
488 void FreeCache(void) {
489   if(debug>1) err_msg("DEBUG:=>freeCache()");
490   freeCache();
491   if(debug>1) err_msg("DEBUG:<=freeCache()");
492 }
493
494 int IsRecentlyCheckedAddress(unsigned char* macAndIpAddressRaw, int addrLen){
495   int ret;
496   if(debug>1) err_msg("DEBUG:=>isRecentlyCheckedAddress(%x,%d)", macAndIpAddressRaw[0],addrLen);
497   ret = isRecentlyCheckedAddress(macAndIpAddressRaw, addrLen);
498   if(debug>1) err_msg("DEBUG:(%d)<=isRecentlyCheckedAddress( )",ret);
499   return ret;
500 }
501
502 int DelCacheItem(char* macAddress, char* ipAddress) {
503   int ret;
504   if(debug>1) err_msg("DEBUG:=>delCacheItem(%s,5s)", macAddress,ipAddress);
505   ret = delCacheItem(macAddress,ipAddress);
506   if(debug>1) err_msg("DEBUG:(%d)<=delCacheItem( )",ret);
507   return ret;
508 }
509
510 int DelOldestCacheItem(void) {
511   int ret;
512   if(debug>1) err_msg("DEBUG:=>delOldestCacheItem( )");
513   ret = delOldestCacheItem();
514   if(debug>1) err_msg("DEBUG:(%d)<=delOldestCacheItem( )",ret);
515   return ret;
516 }
517
518 int InitQueueForCache(void){
519   int ret;
520   if(debug>1) err_msg("DEBUG:=>initQueueForCache( )");
521   ret = initQueueForCache();
522   if(debug>1) err_msg("DEBUG:(%d)<=initQueueForCache( )",ret);
523   return ret;
524 }
525
526 int EnQueueForCache(unsigned char* addrRaw, int addrLen){
527   int ret;
528   if(debug>1) err_msg("DEBUG:=>enQueueForCache(%x,%d)", addrRaw[0],addrLen);
529   ret = enQueueForCache(addrRaw,addrLen);
530   if(debug>1) err_msg("DEBUG:(%d)<=enQueueForCache( )",ret);
531   return ret;
532 }
533
534 int DeQueueForCache(unsigned char* addrRaw, int* pAddrLen){
535   int ret;
536   if(debug>1) err_msg("DEBUG:=>deQueueForCache( )");
537   ret = deQueueForCache(addrRaw,pAddrLen);
538   if(debug>1) err_msg("DEBUG:(%d)<=deQuqueForCache(%x,%d)",ret, addrRaw[0],*pAddrLen);
539   return ret;
540
541 }
542 int ListQueueForCache(void){
543   int ret;
544   if(debug>1) err_msg("DEBUG:=>listQueueForCache( )");
545   ret = listQueueForCache();
546   if(debug>1) err_msg("DEBUG:(%d)<=listQueueForCache( )",ret);
547   return ret;
548
549 }
550
551 void FreeQueueForCache(void){
552   if(debug>1) err_msg("DEBUG:=>freeQueueForCache()");
553   freeQueueForCache();
554   if(debug>1) err_msg("DEBUG:<=freequeueForCache()");
555
556 }
557
558 int ReFormatMacAddr(char* macAddr){
559   int ret;
560   if(debug>1) err_msg("DEBUG:=>reFormatMacAddr(%s)", macAddr);
561   ret=reFormatMacAddr(macAddr);
562   if(debug>1) err_msg("DEBUG:(%d)<=reFormatMacAddr(%s)", ret, macAddr);
563   return ret;
564 }