OSDN Git Service

Ver.0.8.1
[opengatem/opengatem.git] / mdsrc / ipfw.c
1 /**************************************************
2 OpengateM - a MAC address authentication system
3  module for Controlling ipfw 
4
5 Copyright (C) 2011 Opengate Project Team
6 Written by Yoshiaki Watanabe
7
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2
11 of the License, or (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21
22 Email: watanaby@is.saga-u.ac.jp
23 **************************************************/
24 #include "opengatemd.h"
25
26 static void sigFunc(int signo);
27
28 /******************************************************************
29  open gate for clientAddr
30      return=-2..+2: error
31      return=ruleNumber. if overlapped ip return=(-1)*ruleNumber
32 ******************************************************************/
33 int openClientGate(char *macAddress, char* userId, char* extraId)
34 {
35   int fd=0;
36   int retNum=-1;
37   struct stat st;
38   char* lockFile;
39   int lockFileExist=TRUE;
40   char userIdLong[WORDMAXLN];
41   char clientAddr[WORDMAXLN]="?";
42   char ruleNumber[WORDMAXLN];
43
44   Sigfunc *defaultSigFunc;
45
46   /* prepare userid-long as [userid@extraid] */
47   strncpy(userIdLong, userId, WORDMAXLN);
48   if(!isNull(extraId)){
49     strncat(userIdLong, "@", WORDMAXLN);
50     strncat(userIdLong, extraId, WORDMAXLN);
51   }
52
53   /* exclusive exec of ipfw to avoid overlapped rule number */
54   /**** prepare ****/
55   /* if not found lock is ignored */
56   lockFile=GetConfValue("LockFile");
57   if(stat(lockFile, &st)!=0) lockFileExist=FALSE;
58   else lockFileExist=TRUE;
59
60   /* if lock file exists, exec lock */
61   if(lockFileExist){
62     /* open lockfile */
63     fd=open(lockFile, O_RDWR, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
64     if(fd==-1){
65       err_msg("ERR at %s#%d: lockfile open error",__FILE__,__LINE__);
66       return -1;
67     } 
68
69     /* set timeout */
70     if((defaultSigFunc=signal(SIGALRM, sigFunc))==SIG_ERR){
71       err_msg("ERR at %s#%d: set sig alarm error",__FILE__,__LINE__);
72       Close(fd);
73       return 1;
74     }
75     alarm(atoi(GetConfValue("LockTimeout")));
76     
77     /* lock */
78     if(Lock(fd)<0){
79       err_msg("ERR at %s#%d: lock error/timeout",__FILE__,__LINE__);
80       Close(fd);
81       return -1;
82     }
83
84     /* reset timeout */
85     signal(SIGALRM, defaultSigFunc);
86     alarm(0);
87   }
88
89   /**** read rules ****/
90   if((retNum=GetRuleNumber(macAddress))<0){
91     /* fail then unlock */
92     if(lockFileExist){
93       Unlock(fd);
94       Close(fd);
95     }
96     return retNum; /* perhaps aleady registered addr is -retNum */
97   }
98
99   /* to string */
100   snprintf(ruleNumber, WORDMAXLN, "%d", retNum);
101
102   /**** write rules ****/
103   /* branch by perl script control flag */
104   if(atoi(GetConfValue("IpfwScript/Enable"))){
105     /********** use perl script to control firewall ************/
106
107     if(Systeml(1, GetConfValue("IpfwScript/Path"),GetConfValue("IpfwPath"),
108                ruleNumber,clientAddr,userIdLong,macAddress,"-",
109                GetConfValue("IpfwTagNumber"),GetConfValue("Pcap/Device"),
110                (char *)0) != 0){
111       err_msg("ERR at %s#%d: exec script error",__FILE__,__LINE__);
112       retNum=1;  /* abnormal */
113     }
114   }
115
116   else{
117     /********** direct control of firewall **********************/
118     /********** add outgoing ipfw rule for the client *************/
119     if(Systeml(1, GetConfValue("IpfwPath"),"-q","add",ruleNumber,
120                "count","tag",GetConfValue("IpfwTagNumber"),
121                "ip","from","any","to","any","MAC","any",macAddress,
122                "via",GetConfValue("Pcap/Device"),"keep-state",
123                "//", userIdLong, (char *)0) != 0){
124       err_msg("ERR at %s#%d: exec ipfw add error",__FILE__,__LINE__);
125       retNum=1;  /* abnormal */
126     }
127     
128     if(Systeml(1, GetConfValue("IpfwPath"),"-q","add",ruleNumber,
129                "count","tag",GetConfValue("IpfwTagNumber"),
130                "ip","from","any","to","any","MAC",macAddress,"any",
131                "via",GetConfValue("Pcap/Device"),"keep-state",
132                "//", userIdLong, (char *)0) != 0){
133       err_msg("ERR at %s#%d: exec ipfw add error",__FILE__,__LINE__);
134       retNum=1; /* abnormal */
135     }
136   }
137
138   /* unlock */
139   if(lockFileExist){
140     Unlock(fd);
141     Close(fd);
142   }
143   
144   return retNum;
145 }
146
147
148 /******************************************************************
149  close gate for clientAddr for the rule number                  
150 ******************************************************************/
151 void closeClientGate(int ruleNumber)
152 {
153   int count;
154   char ruleNumberStr[WORDMAXLN];
155
156   snprintf(ruleNumberStr, WORDMAXLN, "%d", ruleNumber); /* to string */
157
158   /* count rule */
159   count=CountRuleNumber(ruleNumber);
160
161   if(count>0){
162     /* exec ipfw del */
163     /* [ipfw del rule] deletes all rule of the rule number at one call */
164     if(Systeml(1, GetConfValue("IpfwPath"),"delete",ruleNumberStr,(char *)0) != 0){
165       err_msg("ERR at %s#%d: exec ipfw del error",__FILE__,__LINE__);
166     }
167   }
168 }
169
170 /**************************************
171  get unused ipfw rule number       
172  return value ret>0: acquired rule number that can be used 
173               ret=-1: no rule number available 
174               ret=-2: some system error occured 
175               ret=-num: the mac address is already registered in rule 'num' 
176 **************************************/
177 int getRuleNumber(char *macAddress)
178 {
179   FILE *fpipe;
180   char buf[BUFFMAXLN];
181   int num,newNum,readinNum;
182   int ipfwmin;
183   int ipfwmax;
184   int ipfwinterval;
185   int portStatus;
186   int fileStatus;
187   char* p;
188
189   enum status {NORMAL, ABNORMAL, FOUND, NOTFOUND, DUP};
190
191   /* exec ipfw list and open pipe */
192   if((fpipe=Popenl(1, "r", GetConfValue("IpfwPath"),"list",(char *)0)) == NULL){ 
193       err_msg("ERR at %s#%d: exec ipfw list error",__FILE__,__LINE__);
194   }
195   
196   /* search unused rule number in the list read from pipe */
197   /* check duplication of clientAddr to existing rules */
198
199   newNum=-1;
200   readinNum=0;
201   portStatus=NOTFOUND;
202   fileStatus=NORMAL;
203
204   /* get rule range from config */
205   ipfwmin=atoi(GetConfValue("IpfwRule/Min"));
206   ipfwmax=atoi(GetConfValue("IpfwRule/Max"));
207   ipfwinterval=atoi(GetConfValue("IpfwRule/Interval"));
208
209   /* each port is checked whether it can be used for new rule or not */
210   for(num=ipfwmin;num<=ipfwmax;num+=ipfwinterval){
211
212     /* skip rules smaller than num */
213     while(readinNum<num){
214       if(fgets(buf, BUFFMAXLN, fpipe)==NULL){
215         if(feof(fpipe)==1) fileStatus=EOF; 
216         else fileStatus=ABNORMAL;
217         break;
218       }
219       if( sscanf(buf, "%d", &readinNum) !=1 ){
220         err_msg("ERR at %s#%d: abnormal ipfw response[ %s ]",
221                 __FILE__,__LINE__, buf);
222         fileStatus=ABNORMAL; /* abnormal responsem exit internal loop */
223         break;
224       }
225     }
226
227     if(fileStatus==ABNORMAL){
228       /* abnormal file proc, exit external loop */ 
229       break;
230     }
231
232     if(fileStatus==EOF){
233       /* EOF before reading a rule that is larger or equal to num */
234       /* it means that num can be used for new client */
235       portStatus=FOUND;
236       newNum=num;
237       break;
238     }
239
240     /* at this point, readinNum is larger or equal to num */
241     /* check number duplication */
242     if(readinNum==num){
243
244       /* if macAddress is found in the rule, then exit, else check next rule */
245       /* following code checks the existence of "space+macAddress+space|etc" */
246       if(((p=(char*)strstr(buf+1,macAddress))!=NULL)
247          && isspace(*(p-1))
248          && !isalnum(*(p+strlen(macAddress)))){
249         newNum=num;
250         portStatus=DUP;
251         break;
252       }else{
253         continue;
254       }
255     }
256  
257     /* at this point, readNum is larger than num */
258     /* it means that num can be used for new client */
259     newNum=num;
260     portStatus=FOUND;
261
262     break;
263   }
264   
265   /* close pipe */
266   Pclose(fpipe);
267     
268   if(fileStatus==ABNORMAL){
269     err_msg("ERR at %s#%d: abnormal ipfw response ",__FILE__,__LINE__);
270     return -2;
271   }
272   if(portStatus==NOTFOUND){
273     err_msg("ERR at %s#%d: cannot get unused ipfw number",__FILE__,__LINE__);
274     return -1;
275   }
276   if(portStatus==DUP){
277     return -newNum;
278   }
279
280   return newNum;
281 }
282
283 /*******************************
284  get packet count from ipfw  
285 *******************************/
286 int getPacketCount(int ruleNumber)
287 {
288   FILE *fpipe;
289   char buf[BUFFMAXLN];
290   int rule;
291   int packets,packetsSum;
292   char ruleNumberStr[WORDMAXLN];
293
294   snprintf(ruleNumberStr, WORDMAXLN, "%d", ruleNumber); /* to string */
295
296   /* exec proc */
297   if((fpipe=Popenl(1, "r", GetConfValue("IpfwPath"),"-a","list",ruleNumberStr,(char *)0)) == NULL){ 
298     err_msg("ERR at %s#%d: exec ipfw -a list error",__FILE__,__LINE__);
299   }
300
301   /* search unused number in the list read from pipe */
302   packetsSum=0;
303     
304   while(fgets(buf, BUFFMAXLN, fpipe)!=NULL){
305     sscanf(buf, "%d %d", &rule, &packets);   /* get packet count */
306     packetsSum+=packets;
307   }
308
309   /* close pipe */
310   Pclose(fpipe);
311
312   return packetsSum;
313 }
314
315 /**********************************************
316  get rule count registed to a rule number   
317 **********************************************/
318 int countRuleNumber(int ruleNumber)
319 {
320   FILE *fpipe;
321   char buf[BUFFMAXLN];
322   int ruleCount;
323   char ruleNumberStr[WORDMAXLN];
324
325   snprintf(ruleNumberStr, WORDMAXLN, "%d", ruleNumber); /* to string */
326
327   /* exec proc */
328   if((fpipe=Popenl(1, "r", GetConfValue("IpfwPath"),"list",ruleNumberStr,(char *)0)) == NULL){ 
329     err_msg("ERR at %s#%d: exec ipfw list error",__FILE__,__LINE__);
330   }
331   
332   /* count line read from pipe */
333   ruleCount = 0;
334   while(fgets(buf, BUFFMAXLN, fpipe)!=0) ruleCount++;
335
336   /* close pipe */
337   Pclose(fpipe);
338
339   return ruleCount;
340 }
341
342 /**********************************************
343  function called by signal int              
344 **********************************************/
345 static void sigFunc(int signo)
346 {
347   return;
348 }
349
350
351 /**********************************************
352 get rule numbers table from ipfw rule set
353 **********************************************/
354 int getRuleTableFromIpfw(DB* ruleTable){
355
356   DBT hashKey;
357   DBT hashVal;
358   FILE *fpipe;
359   char buf[BUFFMAXLN];
360   int ruleNumber;
361   char macAddress[ADDRMAXLN];
362   char *p;
363   int ipfwmin;
364   int ipfwmax;
365   int ipfwinterval;
366   int resultFlag=FALSE;
367   
368   /* exec ipfw list and open pipe */
369   if((fpipe=Popenl(1, "r", GetConfValue("IpfwPath"),"list",(char *)0)) == NULL){ 
370     err_msg("ERR at %s#%d: exec ipfw list error",__FILE__,__LINE__);
371   }
372   
373   /* get rule range from config */
374   ipfwmin=atoi(GetConfValue("IpfwRule/Min"));
375   ipfwmax=atoi(GetConfValue("IpfwRule/Max"));
376   ipfwinterval=atoi(GetConfValue("IpfwRule/Interval"));
377   
378   /* get ipfw rule line from pipe */
379   while(fgets(buf, BUFFMAXLN, fpipe)!=NULL){
380
381     /* get ruleNumber(=leftmost number) */
382     /* 10000 count tag 123 ip from any to any MAC 11:22:33:44:55:66 any .... */
383     /* 10000 count tag 123 ip from any to any MAC any 11:22:33:44:55:66 .... */
384     if( sscanf(buf, "%d", &ruleNumber) !=1 ) continue;
385
386     /* check the rule number range */
387     if(ruleNumber < ipfwmin)continue;
388     if(ruleNumber > ipfwmax)break;
389
390     /* get macAddress(=after [MAC]) in the line */
391     if((p=(char*)strstr(buf, "MAC"))==NULL) continue;
392     if( sscanf((p+3), "%s", macAddress) != 1 ) continue;
393     if( (strchr(macAddress,':')==NULL) )continue;
394       
395     /* put to the hash table */
396     resultFlag=TRUE;
397     hashVal.data = &ruleNumber;
398     hashVal.size = sizeof(int);    
399     hashKey.data = macAddress;
400     hashKey.size = strlen(macAddress)+1;
401     if(ruleTable->put(ruleTable, &hashKey, &hashVal, 0) == -1) {
402       err_msg("ERR at %s#%d: fail to put into hash table",__FILE__,__LINE__);
403     }
404   }
405
406   /* close pipe */
407   Pclose(fpipe);
408
409   return resultFlag;
410 }
411
412
413 /**********************************************
414 is the macAddress found in ipfw rules
415 **********************************************/
416 int isMacAddressFoundInIpfw(char* macAddress){
417
418   FILE *fpipe;
419   char buf[BUFFMAXLN];
420   int ruleNumber;
421   char macAddressInRule[ADDRMAXLN];
422   char *p;
423   int ipfwmin;
424   int ipfwmax;
425   int ipfwinterval;
426   int found=FALSE;
427   
428   /* exec ipfw list and open pipe */
429   if((fpipe=Popenl(1, "r", GetConfValue("IpfwPath"),"list",(char *)0)) == NULL){ 
430     err_msg("ERR at %s#%d: exec ipfw list error",__FILE__,__LINE__);
431   }
432   
433   /* get rule range from config */
434   ipfwmin=atoi(GetConfValue("IpfwRule/Min"));
435   ipfwmax=atoi(GetConfValue("IpfwRule/Max"));
436   ipfwinterval=atoi(GetConfValue("IpfwRule/Interval"));
437   
438   /* get ipfw rule line from pipe */
439   while(fgets(buf, BUFFMAXLN, fpipe)!=NULL){
440
441     /* get ruleNumber(=leftmost number) */
442     /* 10000 count tag 123 ip from any to any MAC 11:22:33:44:55:66 any .... */
443     /* 10000 count tag 123 ip from any to any MAC any 11:22:33:44:55:66 .... */
444     if( sscanf(buf, "%d", &ruleNumber) !=1 ) continue;
445
446     /* check the rule number range */
447     if(ruleNumber < ipfwmin)continue;
448     if(ruleNumber > ipfwmax)break;
449
450     /* get macAddress(=after [MAC]) in the line */
451     if((p=(char*)strstr(buf, "MAC"))==NULL) continue;
452     if( sscanf((p+3), "%s", macAddressInRule) != 1 ) continue;
453     if( (strchr(macAddressInRule,':')==NULL) )continue;
454
455     /* compare the address with the argument */
456     /* if matched, exit loop */
457     if(strncmp(macAddress, macAddressInRule, ADDRMAXLN)==0){
458       found=TRUE;
459       break;
460     }
461   }
462
463   /* close pipe */
464   Pclose(fpipe);
465
466   return found;
467 }
468
469
470 /*********************************************
471  routines for debugging output
472 **********************************************/
473 int GetRuleNumber(char *macAddress)
474 {
475   int ret;
476
477   if(debug>1) err_msg("DEBUG:=>getRuleNumber(%s)",macAddress);
478   ret=getRuleNumber(macAddress);
479   if(debug>1) err_msg("DEBUG:(%d)<=getRuleNumber( )",ret);
480
481   return ret;
482 }
483
484 int OpenClientGate(char *macAddress, char* userId, char* extraId)
485 {
486   int ret;
487
488   if(debug>1) err_msg("DEBUG:=>openClientGate(%s,%s,%s)",macAddress,userId,extraId);
489   ret=openClientGate(macAddress,userId,extraId);
490   if(debug>1) err_msg("DEBUG:(%d)<=openClientGate( )",ret);
491
492   return ret;
493 }
494
495 void CloseClientGate(int ruleNumber)
496 {
497   if(debug>1) err_msg("DEBUG:=>closeClientGate(%d)",ruleNumber);
498   closeClientGate(ruleNumber);
499   if(debug>1) err_msg("DEBUG:<=closeClientGate( )");
500 }
501
502
503 int GetPacketCount(int ruleNumber)
504 {
505   int ret;
506
507   if(debug>1) err_msg("DEBUG:=>getPacketCount(%d)",ruleNumber);
508   ret=getPacketCount(ruleNumber);
509   if(debug>1) err_msg("DEBUG:(%d)<=getPacketCount( )",ret);
510
511   return ret;
512 }
513
514 int CountRuleNumber(int ruleNumber)
515 {
516   int ret;
517   
518   if(debug>1) err_msg("DEBUG:=>countRuleNumber(%d)", ruleNumber);
519   ret=countRuleNumber(ruleNumber);
520   if(debug>1) err_msg("DEBUG:(%d)<=countRuleNumber( )",ret);
521   
522   return ret;
523 }
524
525 int GetRuleTableFromIpfw(DB* ruleTable){
526   int ret;
527   if(debug>1) err_msg("DEBUG:=>getRuleTableFromIpfw()");
528   ret=getRuleTableFromIpfw(ruleTable);
529   if(debug>1) err_msg("DEBUG:(%d)<=getRuleTableFromIpfw( )", ret);
530   return ret;
531 }
532
533 int IsMacAddressFoundInIpfw(char* macAddress){
534   int ret;
535   if(debug>1) err_msg("DEBUG:=>isMacAddressFoundInIpfw(%s)", macAddress);
536   ret=isMacAddressFoundInIpfw(macAddress);
537   if(debug>1) err_msg("DEBUG:(%d)<=isMacAddressFoundInIpfw( )", ret);
538   return ret;
539 }