1 /**************************************************
2 OpengateM - MAC address authentication system
4 module for Controling ipfw
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. if overlapped ip return=(-1)*ruleNumber
35 ******************************************************************/
36 int openClientGate(char *clientAddr, int forced, char* userId, char* extraId, char* macAddress)
42 int lockFileExist=TRUE;
43 char userIdLong[WORDMAXLN];
45 Sigfunc *defaultSigFunc;
47 /* prepare userid-long as [userid@extraid] */
48 strlcpy(userIdLong, userId, WORDMAXLN);
50 strlcat(userIdLong, "@", WORDMAXLN);
51 strlcat(userIdLong, extraId, WORDMAXLN);
54 /* exclusive exec of ipfw to avoid overlapped rule number */
56 /* if not found lock is ignored */
57 lockFile=GetConfValue("LockFile");
58 if(stat(lockFile, &st)!=0) lockFileExist=FALSE;
59 else lockFileExist=TRUE;
61 /* if lock file exists, exec lock */
64 fd=open(lockFile, O_RDWR, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
66 err_msg("ERR at %s#%d: lockfile open error",__FILE__,__LINE__);
71 if((defaultSigFunc=signal(SIGALRM, sigFunc))==SIG_ERR){
72 err_msg("ERR at %s#%d: set sig alarm error",__FILE__,__LINE__);
76 alarm(atoi(GetConfValue("LockTimeout")));
80 err_msg("ERR at %s#%d: lock error",__FILE__,__LINE__);
86 signal(SIGALRM, defaultSigFunc);
90 /**** read rules ****/
91 if((retNum=GetRuleNumber(clientAddr, forced))<0){
92 /* fail then unlock */
97 return retNum; /* perhaps aleady registered addr is -retNum */
100 /**** write rules ****/
101 /* branch by perl script control flag */
102 if(atoi(GetConfValue("IpfwScript/Enable"))){
103 /********** use perl script to control firewall ************/
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 */
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 */
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 */
143 /******************************************************************
144 close gate for clientAddr for the rule number
145 ******************************************************************/
146 void closeClientGate(int ruleNumber)
149 char ruleNumberStr[WORDMAXLN];
151 snprintf(ruleNumberStr, WORDMAXLN, "%d", ruleNumber); /* to string */
154 count=CountRuleNumber(ruleNumber);
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__);
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)
178 int num,newNum,readinNum;
186 enum status {NORMAL, ABNORMAL, FOUND, NOTFOUND, DUP};
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__);
193 /* search unused rule number in the list read from pipe */
194 /* check duplication of clientAddr to existing rules */
201 /* get rule range from config */
202 ipfwmin=atoi(GetConfValue("IpfwRule/Min"));
203 ipfwmax=atoi(GetConfValue("IpfwRule/Max"));
204 ipfwinterval=atoi(GetConfValue("IpfwRule/Interval"));
206 /* each port is checked whether it can be used for new rule or not */
207 for(num=ipfwmin;num<=ipfwmax;num+=ipfwinterval){
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;
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 */
224 if(fileStatus==ABNORMAL){
225 /* abnormal file proc, exit external loop */
230 /* EOF before reading a rule that is larger or equal to num */
231 /* it means that num can be used for new client */
237 /* at this point, readinNum is larger or equal to num */
238 /* check number duplication */
241 /* if clientAddr found in the existing rule, then duplicate err exit */
242 /* if in forced mode, ignore the checking */
244 if(((p=(char*)strstr(buf+1,clientAddr))!=NULL)
246 && !isalnum(*(p+strlen(clientAddr)))){
257 /* at this point, readNum is larger than num */
258 /* it means that num can be used for new client */
268 if(fileStatus==ABNORMAL){
269 err_msg("ERR at %s#%d: abnormal ipfw response ",__FILE__,__LINE__);
272 if(portStatus==NOTFOUND){
273 err_msg("ERR at %s#%d: cannot get unused ipfw number",__FILE__,__LINE__);
277 snprintf(ruleNumber, WORDMAXLN, "%d", newNum); /* to string */
281 snprintf(ruleNumber, WORDMAXLN, "%d", newNum); /* to string */
285 /*******************************
286 get packet count from ipfw
287 *******************************/
288 int getPacketCount(int ruleNumber)
293 int packets,packetsSum;
294 char ruleNumberStr[WORDMAXLN];
296 snprintf(ruleNumberStr, WORDMAXLN, "%d", ruleNumber); /* to string */
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__);
303 /* search unused number in the list read from pipe */
306 while(fgets(buf, BUFFMAXLN, fpipe)!=NULL){
307 sscanf(buf, "%d %d", &rule, &packets); /* get packet count */
317 /**********************************************
318 get rule count registed to a rule number
319 **********************************************/
320 int countRuleNumber(int ruleNumber)
325 char ruleNumberStr[WORDMAXLN];
327 snprintf(ruleNumberStr, WORDMAXLN, "%d", ruleNumber); /* to string */
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__);
334 /* count line read from pipe */
336 while(fgets(buf, BUFFMAXLN, fpipe)!=0) ruleCount++;
344 /**********************************************
345 function called by signal int
346 **********************************************/
347 static void sigFunc(int signo)
353 /**********************************************
354 get rule numbers table from ipfw rule set
355 **********************************************/
356 int getRuleTableFromIpfw(DB* ruleTable){
363 char clientAddr[ADDRMAXLN];
368 int resultFlag=FALSE;
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__);
375 /* get rule range from config */
376 ipfwmin=atoi(GetConfValue("IpfwRule/Min"));
377 ipfwmax=atoi(GetConfValue("IpfwRule/Max"));
378 ipfwinterval=atoi(GetConfValue("IpfwRule/Interval"));
380 /* get ipfw rule line from pipe */
381 while(fgets(buf, BUFFMAXLN, fpipe)!=NULL){
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;
388 /* check the rule number range */
389 if(ruleNumber < ipfwmin)continue;
390 if(ruleNumber > ipfwmax)break;
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;
397 /* put to the hash table */
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__);
415 /*********************************************
416 routines for debugging output
417 **********************************************/
418 int GetRuleNumber(char *clientAddr, int forced)
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);
429 int OpenClientGate(char *clientAddr, int forced, char* userId, char* extraId,char* macAddress)
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);
440 void CloseClientGate(int ruleNumber)
442 if(debug>1) err_msg("DEBUG:=>closeClientGate(%d)",ruleNumber);
443 closeClientGate(ruleNumber);
444 if(debug>1) err_msg("DEBUG:<=closeClientGate( )");
448 int GetPacketCount(int ruleNumber)
452 if(debug>1) err_msg("DEBUG:=>getPacketCount(%d)",ruleNumber);
453 ret=getPacketCount(ruleNumber);
454 if(debug>1) err_msg("DEBUG:(%d)<=getPacketCount( )",ret);
459 int CountRuleNumber(int ruleNumber)
463 if(debug>1) err_msg("DEBUG:=>countRuleNumber(%d)", ruleNumber);
464 ret=countRuleNumber(ruleNumber);
465 if(debug>1) err_msg("DEBUG:(%d)<=countRuleNumber( )",ret);
470 int GetRuleTableFromIpfw(DB* ruleTable){
472 if(debug>1) err_msg("DEBUG:=>getRuleTableFromIpfw()");
473 ret=getRuleTableFromIpfw(ruleTable);
474 if(debug>1) err_msg("DEBUG:<=getRuleTableFromIpfw( )", ret);