1 /**************************************************
2 opengate Mac addr auth program
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.
8 As checking packet is time consuming procedure,
9 the recently checked addresses are cached and skiped.
10 Implemented with HashTable and Queue.
12 Key= comcatenation of MAC and IP Addresses
14 If address pair is included in table and time is new, skip checking.
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.
20 Copyright (C) 2011 Opengate Project Team
21 Written by Yoshiaki Watanabe
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.
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.
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.
37 Email: watanaby@is.saga-u.ac.jp
38 **************************************************/
39 #include "opengatemd.h"
41 #define CACHESIZE 1000000 /* mac&ip cache size */
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);
49 /* Queue to store MacAndIpAddress */
52 unsigned char addrRaw[MACADDRLN+IPV6ADDRLN];
53 struct queueNode *next;
55 static struct queueNode* queueTail=NULL;
56 static struct queueNode* queueHead=NULL;
58 /* HashTable to store MacAndIpAddress and Time */
61 /* Cache Timeout(seconds) : packet checking interval */
62 static int cacheTimeout;
64 static int cacheItemCount=0;
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 ***********************************/
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){
81 unsigned char storedAddrRaw[MACADDRLN+IPV6ADDRLN];
88 /* get present time */
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);
97 /* getting from hash is successed */
100 /* pick up the pointer to the value */
101 pTime=(int*)(hashVal.data);
103 /* if data is null, return NO */
104 if(pTime==NULL) return FALSE;
106 /* if ignoring addresses(exceptional setting), return YES */
107 if(*pTime==0) return TRUE;
109 /* if recently checked data, return YES */
110 if( (timeNow-*pTime) < cacheTimeout ) return TRUE;
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;
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__);
135 /* if getting from hash is failed, insert address and return NO */
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__);
146 /* insert to queue */
147 EnQueueForCache(macAndIpAddressRaw, addrLen);
148 /*************** end adding item to Cache ***/
150 /* if cache size is over, remove oldest one */
151 if(cacheItemCount>CACHESIZE) DelOldestCacheItem();
155 /* else error exit */
156 err_msg("ERR at %s#%d: fail to get hash table item",__FILE__,__LINE__);
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) {
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__);
177 /* set timeout parameter */
178 cacheTimeout=atoi(GetConfValue("CacheTimeout"));
181 /****************************************
182 memory free for Mac&IpAddress Cache
183 ****************************************/
184 void freeCache(void) {
186 hashDb->close(hashDb);
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) {
200 unsigned char addrRaw[MACADDRLN+IPV6ADDRLN];
201 unsigned char* pRawMac;
202 struct queueNode *temp;
203 struct queueNode *prev;
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);
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;
225 if(inet_pton(AF_INET, ipAddress, addrRaw+MACADDRLN) > 0) inIpv4=TRUE;
229 /*** set start point and length for comparing string */
230 if(inMac && !inIpv6 && !inIpv4){ /* only mac is indivcated */
234 else if(!inMac && inIpv6){ /* only ipv6 is indicated */
238 else if(!inMac && inIpv4){ /* only ipv4 is indicated */
242 else if(inMac && inIpv6){ /* mac and ipv6 is indicated */
244 length=MACADDRLN+IPV6ADDRLN;
246 else if(inMac && inIpv4){ /* mac and ipv4 is indicated */
248 length=MACADDRLN+IPV4ADDRLN;
250 else{ /* no one is indicated */
254 /*** scan queue to find matched address */
255 /* set search point to the head of mac-ip cache */
256 if(queueHead==NULL) return FALSE;
258 temp=queueHead->next;
260 /* scan from queue head to tail */
261 while(temp->next!=NULL){
263 /* compare indicated value and queue value */
264 if(memcmp(addrRaw+shift, (temp->addrRaw)+shift, length)==0){
269 /* delete the item from Hash Table */
270 hashKey.data = temp->addrRaw;
271 hashKey.size = temp->addrLen;
272 hashDb->del(hashDb, &hashKey, 0);
274 /* delete the item from Queue */
275 prev->next=temp->next;
280 /* move to next item */
287 /****************************************
288 delete oldest item from MacAndIp cache
289 ****************************************/
290 int delOldestCacheItem(void) {
292 unsigned char addrRaw[MACADDRLN+IPV6ADDRLN];
295 /* delete oldest item(=head) from queue */
296 if(DeQueueForCache(addrRaw, &addrLen)){
298 /* delete the item from Hash Table */
299 hashKey.data = addrRaw;
300 hashKey.size = addrLen;
301 hashDb->del(hashDb, &hashKey, 0);
309 /*********************************************
310 initialize MacAndIpAddress Queue
312 HeadNode - DataNode - DataNode - TailNode
314 ^queueHead ^queueTail
315 *********************************************/
316 int initQueueForCache(void){
318 unsigned char addrRaw[MACADDRLN+IPV6ADDRLN];
321 /* if not exist, prepare head and tail */
323 queueHead=(struct queueNode*)malloc(sizeof(struct queueNode));
325 err_msg("ERR at %s#%d: fail to malloc",__FILE__,__LINE__);
328 queueTail=(struct queueNode*)malloc(sizeof(struct queueNode));
330 err_msg("ERR at %s#%d: fail to malloc",__FILE__,__LINE__);
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;
341 /* if exist, reset all */
343 while(DeQueueForCache(addrRaw,&addrLen))
347 /* reset item count */
353 /****************************************
354 Add data to the tail of MacAndIP Queue
356 ****************************************/
357 int enQueueForCache(unsigned char* addrRaw, int addrLen){
358 struct queueNode *newNode;
360 /* if not prepared, error */
362 err_msg("ERR at %s#%d: queue not init",__FILE__,__LINE__);
366 /* add item after the tail and set it as new tail*/
367 newNode=(struct queueNode*)malloc(sizeof(struct queueNode));
369 err_msg("ERR at %s#%d: fail to malloc",__FILE__,__LINE__);
372 memcpy(queueTail->addrRaw, addrRaw, addrLen);
373 queueTail->addrLen=addrLen;
374 queueTail->next=newNode;
376 bzero(queueTail->addrRaw,MACADDRLN+IPV6ADDRLN);
377 queueTail->addrLen=0;
378 queueTail->next=NULL;
380 /* increment item count */
386 /****************************************
387 Get and remove address data from the head of MacAndIP Queue
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){
394 /* set null string as default */
395 bzero(addrRaw, MACADDRLN+IPV6ADDRLN);
397 /* if not prepared, error */
399 err_msg("ERR at %s#%d: queue not init",__FILE__,__LINE__);
402 else if(queueHead->next==NULL){
403 err_msg("ERR at %s#%d: queue not init",__FILE__,__LINE__);
407 /* if no data, return false */
408 else if(queueHead->next==queueTail){
412 /* get item from the head */
414 struct queueNode *temp;
415 temp=queueHead->next;
416 queueHead->next=temp->next;
417 memcpy(addrRaw, temp->addrRaw, temp->addrLen);
418 *pAddrLen=temp->addrLen;
421 /* decrement item count */
428 /****************************************
429 Listing MacAndIpAddress Queue (for debugging)
430 ****************************************/
431 int listQueueForCache(void){
433 struct queueNode *temp;
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]);
450 /****************************************
451 memory free for MacAndIpAddress Queue
452 ****************************************/
453 void freeQueueForCache(void){
454 unsigned char addrRaw[MACADDRLN+IPV6ADDRLN];
456 while(DeQueueForCache(addrRaw,&addrLen));
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)
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);
478 /****************************************************
479 routines for debugging putput
480 ***************************************************/
482 void InitCache(void) {
483 if(debug>1) err_msg("DEBUG:=>initCache( )");
485 if(debug>1) err_msg("DEBUG:<=initCache( )");
488 void FreeCache(void) {
489 if(debug>1) err_msg("DEBUG:=>freeCache()");
491 if(debug>1) err_msg("DEBUG:<=freeCache()");
494 int IsRecentlyCheckedAddress(unsigned char* macAndIpAddressRaw, int addrLen){
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);
502 int DelCacheItem(char* macAddress, char* ipAddress) {
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);
510 int DelOldestCacheItem(void) {
512 if(debug>1) err_msg("DEBUG:=>delOldestCacheItem( )");
513 ret = delOldestCacheItem();
514 if(debug>1) err_msg("DEBUG:(%d)<=delOldestCacheItem( )",ret);
518 int InitQueueForCache(void){
520 if(debug>1) err_msg("DEBUG:=>initQueueForCache( )");
521 ret = initQueueForCache();
522 if(debug>1) err_msg("DEBUG:(%d)<=initQueueForCache( )",ret);
526 int EnQueueForCache(unsigned char* addrRaw, int addrLen){
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);
534 int DeQueueForCache(unsigned char* addrRaw, int* pAddrLen){
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);
542 int ListQueueForCache(void){
544 if(debug>1) err_msg("DEBUG:=>listQueueForCache( )");
545 ret = listQueueForCache();
546 if(debug>1) err_msg("DEBUG:(%d)<=listQueueForCache( )",ret);
551 void FreeQueueForCache(void){
552 if(debug>1) err_msg("DEBUG:=>freeQueueForCache()");
554 if(debug>1) err_msg("DEBUG:<=freequeueForCache()");
558 int ReFormatMacAddr(char* macAddr){
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);