1 /**************************************************
2 OpengateM - MAC address authentication system
4 module for Controling ipfw (firewall)
6 Copyright (C) 2011 Opengate Project Team
7 Written by Yoshiaki Watanabe
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.
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.
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.
23 Email: watanaby@is.saga-u.ac.jp
24 **************************************************/
25 #include "opengatemmng.h"
27 char ruleNumber[WORDMAXLN]; /* ipfw rule number in string form */
29 static void sigFunc(int signo);
31 /******************************************************************/
32 /* open gate for clientAddr */
33 /* if forced=TRUE, ignore checking for address overlapping */
34 /* return=ruleNumber */
35 /* return=(-1)*ruleNumber: can't open because of overlapping */
36 /******************************************************************/
37 int openClientGate(char *clientAddr, int forced, char* userId, char* extraId, char* macAddress)
43 int lockFileExist=TRUE;
44 char userIdLong[WORDMAXLN];
46 Sigfunc *defaultSigFunc;
48 /* prepare userid-long as [userid@extraid] */
49 strlcpy(userIdLong, userId, WORDMAXLN);
51 strlcat(userIdLong, "@", WORDMAXLN);
52 strlcat(userIdLong, extraId, WORDMAXLN);
55 /* exclusive exec of ipfw to avoid overlapped rule number */
57 /* search lock file */
58 lockFile=GetConfValue("LockFile");
59 if(stat(lockFile, &st)!=0) lockFileExist=FALSE;
60 else lockFileExist=TRUE;
62 /* if lock file exists, exec lock (if not found, lock is ignored) */
66 fd=open(lockFile, O_RDWR, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
68 err_msg("ERR at %s#%d: lockfile open error",__FILE__,__LINE__);
72 /* set lock timeout (at long time locking, lock is canceled by SIGALRM) */
73 if((defaultSigFunc=signal(SIGALRM, sigFunc))==SIG_ERR){
74 err_msg("ERR at %s#%d: set sig alarm error",__FILE__,__LINE__);
78 alarm(atoi(GetConfValue("LockTimeout")));
82 err_msg("ERR at %s#%d: lock error",__FILE__,__LINE__);
87 /* when other process executes here, this process waits in lock() */
88 /* returning from lock() means that exclusive execution is possible */
89 /* then reset timeout signal and go to main processing */
90 signal(SIGALRM, defaultSigFunc);
94 /**** read rules ****/
95 if((retNum=GetRuleNumber(clientAddr, forced))<0){
97 /* if fail, then unlock and return */
102 return retNum; /* perhaps aleady registered addr is -retNum */
105 /**** write rules ****/
106 /**** if perl script control flag is set in conf file, use perl script */
107 /* (not recommended) */
108 if(atoi(GetConfValue("IpfwScript/Enable"))){
109 if(Systeml(1, GetConfValue("IpfwScript/Path"),GetConfValue("IpfwPath"),
110 ruleNumber,clientAddr,userIdLong,macAddress,"-",
111 GetConfValue("IpfwTagNumber"),(char *)0) != 0){
112 err_msg("ERR at %s#%d: exec script error",__FILE__,__LINE__);
113 retNum=1; /* abnormal */
117 /**** else, direct control of firewall (default) ***************/
120 /********** add outgoing ipfw rule for the client (in IP level) *************/
121 /* eg.(ipfw -q add 10000 count tag 123 ip from 192.168.1.10 to any //wata@guest) */
122 if(Systeml(1, GetConfValue("IpfwPath"),"-q","add",ruleNumber,
123 "count","tag",GetConfValue("IpfwTagNumber"),
124 "ip","from",clientAddr,"to","any",
125 "//", userIdLong, (char *)0) != 0){
126 err_msg("ERR at %s#%d: exec ipfw add error",__FILE__,__LINE__);
127 retNum=1; /* abnormal */
130 /********** add incoming ipfw rule for the client *************/
131 /* eg.(ipfw -q add 10000 count tag 123 ip from any to 192.168.1.10 //wata@guest) */
132 if(Systeml(1, GetConfValue("IpfwPath"),"-q","add",ruleNumber,
133 "count","tag",GetConfValue("IpfwTagNumber"),
134 "ip","from","any","to",clientAddr,
135 "//", userIdLong, (char *)0) != 0){
136 err_msg("ERR at %s#%d: exec ipfw add error",__FILE__,__LINE__);
137 retNum=1; /* abnormal */
151 /*****************************************************************/
152 /* close gate for clientAddr for the rule number */
153 /*****************************************************************/
154 void closeClientGate(int ruleNumber)
157 char ruleNumberStr[WORDMAXLN];
159 snprintf(ruleNumberStr, WORDMAXLN, "%d", ruleNumber); /* to string */
162 count=CountRuleNumber(ruleNumber);
166 /* [ipfw del rule] deletes all rule of the rule number at one call */
167 if(Systeml(1, GetConfValue("IpfwPath"),"delete",ruleNumberStr,(char *)0) != 0){
168 err_msg("ERR at %s#%d: exec ipfw del error",__FILE__,__LINE__);
173 /**************************************
174 get unused ipfw rule number
175 error if addr is already in rules
176 if forced=TRUE, ignore checking for address overlapping
177 return value ret>0: acquired rule number that can be used
178 ret=-1: no rule number available
179 ret=-2: some system error occured
180 ret=-num: the ip address is already registered in rule 'num'
181 **************************************/
182 int getRuleNumber(char *clientAddr, int forced)
186 int num,newNum,readinNum;
194 enum status {NORMAL, ABNORMAL, FOUND, NOTFOUND, DUP};
196 /* exec ipfw list and open pipe */
197 if((fpipe=Popenl(1, "r", GetConfValue("IpfwPath"),"list",(char *)0)) == NULL){
198 err_msg("ERR at %s#%d: exec ipfw list error",__FILE__,__LINE__);
201 /* search unused rule number in the list read from pipe */
202 /* check duplication of clientAddr to existing rules */
209 /* get rule range from config */
210 ipfwmin=atoi(GetConfValue("IpfwRule/Min"));
211 ipfwmax=atoi(GetConfValue("IpfwRule/Max"));
212 ipfwinterval=atoi(GetConfValue("IpfwRule/Interval"));
214 /* each port is checked whether it can be used for new rule or not */
215 for(num=ipfwmin;num<=ipfwmax;num+=ipfwinterval){
217 /* skip rules smaller than num */
218 while(readinNum<num){
219 if(fgets(buf, BUFFMAXLN, fpipe)==NULL){
220 if(feof(fpipe)==1) fileStatus=EOF;
221 else fileStatus=ABNORMAL;
224 if( sscanf(buf, "%d", &readinNum) !=1 ){
225 err_msg("ERR at %s#%d: abnormal ipfw response[ %s ]",
226 __FILE__,__LINE__, buf);
227 fileStatus=ABNORMAL; /* abnormal responsem exit internal loop */
232 if(fileStatus==ABNORMAL){
233 /* abnormal file proc, exit external loop */
238 /* EOF before reading a rule that is larger or equal to num */
239 /* it means that num can be used for new client */
245 /* at this point, readinNum is larger or equal to num */
246 /* check number duplication */
249 /* if clientAddr found in the existing rule, then duplicate err exit */
250 /* if in forced mode, ignore the checking */
252 if(((p=(char*)strstr(buf+1,clientAddr))!=NULL)
254 && !isalnum(*(p+strlen(clientAddr)))){
265 /* at this point, readNum is larger than num */
266 /* it means that num can be used for new client */
276 if(fileStatus==ABNORMAL){
277 err_msg("ERR at %s#%d: abnormal ipfw response ",__FILE__,__LINE__);
280 if(portStatus==NOTFOUND){
281 err_msg("ERR at %s#%d: cannot get unused ipfw number",__FILE__,__LINE__);
285 snprintf(ruleNumber, WORDMAXLN, "%d", newNum); /* to string */
289 snprintf(ruleNumber, WORDMAXLN, "%d", newNum); /* to string */
293 /*******************************
294 get packet count from ipfw
295 *******************************/
296 int getPacketCount(int ruleNumber)
301 int packets,packetsSum;
302 char ruleNumberStr[WORDMAXLN];
304 snprintf(ruleNumberStr, WORDMAXLN, "%d", ruleNumber); /* to string */
307 if((fpipe=Popenl(1, "r", GetConfValue("IpfwPath"),"-a","list",ruleNumberStr,(char *)0)) == NULL){
308 err_msg("ERR at %s#%d: exec ipfw -a list error",__FILE__,__LINE__);
311 /* search unused number in the list read from pipe */
314 while(fgets(buf, BUFFMAXLN, fpipe)!=NULL){
315 sscanf(buf, "%d %d", &rule, &packets); /* get packet count */
325 /**********************************************
326 get rule count registed to a rule number
327 **********************************************/
328 int countRuleNumber(int ruleNumber)
333 char ruleNumberStr[WORDMAXLN];
335 snprintf(ruleNumberStr, WORDMAXLN, "%d", ruleNumber); /* to string */
338 if((fpipe=Popenl(1, "r", GetConfValue("IpfwPath"),"list",ruleNumberStr,(char *)0)) == NULL){
339 err_msg("ERR at %s#%d: exec ipfw list error",__FILE__,__LINE__);
342 /* count line read from pipe */
344 while(fgets(buf, BUFFMAXLN, fpipe)!=0) ruleCount++;
352 /**********************************************
353 function called by signal int
354 **********************************************/
355 static void sigFunc(int signo)
361 /**********************************************
362 get rule numbers table from ipfw rule set
363 **********************************************/
364 int getRuleTableFromIpfw(DB* ruleTable){
371 char clientAddr[ADDRMAXLN];
376 int resultFlag=FALSE;
378 /* exec ipfw list and open pipe */
379 if((fpipe=Popenl(1, "r", GetConfValue("IpfwPath"),"list",(char *)0)) == NULL){
380 err_msg("ERR at %s#%d: exec ipfw list error",__FILE__,__LINE__);
383 /* get rule range from config */
384 ipfwmin=atoi(GetConfValue("IpfwRule/Min"));
385 ipfwmax=atoi(GetConfValue("IpfwRule/Max"));
386 ipfwinterval=atoi(GetConfValue("IpfwRule/Interval"));
388 /* get ipfw rule line from pipe */
389 while(fgets(buf, BUFFMAXLN, fpipe)!=NULL){
391 /* get ruleNumber(=leftmost number) */
392 /* 10000 count tag 123 ip from 192.168.0.2 to any .... */
393 /* 10000 count tag 123 ip from any to 192.168.0.2 .... */
394 if( sscanf(buf, "%d", &ruleNumber) !=1 ) continue;
396 /* check the rule number range */
397 if(ruleNumber < ipfwmin)continue;
398 if(ruleNumber > ipfwmax)break;
400 /* get clientAddr(=after [from]) in the line */
401 if((p=(char*)strstr(buf, "from"))==NULL) continue;
402 if( sscanf((p+4), "%s", clientAddr) != 1 ) continue;
403 if( (strchr(clientAddr,'.')==NULL) && (strchr(clientAddr,':')==NULL) )continue;
405 /* put to the hash table */
407 hashVal.data = &ruleNumber;
408 hashVal.size = sizeof(int);
409 hashKey.data = clientAddr;
410 hashKey.size = strlen(clientAddr)+1;
411 if(ruleTable->put(ruleTable, &hashKey, &hashVal, 0) == -1) {
412 err_msg("ERR at %s#%d: fail to put into hash table",__FILE__,__LINE__);
423 /*********************************************
424 routines for debugging output
425 **********************************************/
426 int GetRuleNumber(char *clientAddr, int forced)
430 if(debug>1) err_msg("DEBUG:=>getRuleNumber(%s,%d)",clientAddr,forced);
431 ret=getRuleNumber(clientAddr, forced);
432 if(debug>1) err_msg("DEBUG:(%d)<=getRuleNumber( )",ret);
437 int OpenClientGate(char *clientAddr, int forced, char* userId, char* extraId,char* macAddress)
441 if(debug>1) err_msg("DEBUG:=>openClientGate(%s,%d,%s,%s)",clientAddr,forced,userId,extraId,macAddress);
442 ret=openClientGate(clientAddr,forced,userId,extraId,macAddress);
443 if(debug>1) err_msg("DEBUG:(%d)<=openClientGate( )",ret);
448 void CloseClientGate(int ruleNumber)
450 if(debug>1) err_msg("DEBUG:=>closeClientGate(%d)",ruleNumber);
451 closeClientGate(ruleNumber);
452 if(debug>1) err_msg("DEBUG:<=closeClientGate( )");
456 int GetPacketCount(int ruleNumber)
460 if(debug>1) err_msg("DEBUG:=>getPacketCount(%d)",ruleNumber);
461 ret=getPacketCount(ruleNumber);
462 if(debug>1) err_msg("DEBUG:(%d)<=getPacketCount( )",ret);
467 int CountRuleNumber(int ruleNumber)
471 if(debug>1) err_msg("DEBUG:=>countRuleNumber(%d)", ruleNumber);
472 ret=countRuleNumber(ruleNumber);
473 if(debug>1) err_msg("DEBUG:(%d)<=countRuleNumber( )",ret);
478 int GetRuleTableFromIpfw(DB* ruleTable){
480 if(debug>1) err_msg("DEBUG:=>getRuleTableFromIpfw()");
481 ret=getRuleTableFromIpfw(ruleTable);
482 if(debug>1) err_msg("DEBUG:<=getRuleTableFromIpfw( )", ret);