OSDN Git Service

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