1 /**************************************************
2 OpengateM - a MAC address authentication system
3 module for Controlling ipfw
5 Copyright (C) 2011 Opengate Project Team
6 Written by Yoshiaki Watanabe
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.
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.
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.
22 Email: watanaby@is.saga-u.ac.jp
23 **************************************************/
24 #include "opengatemd.h"
26 static void sigFunc(int signo);
28 /******************************************************************
29 open gate for clientAddr
31 return=ruleNumber. if overlapped ip return=(-1)*ruleNumber
32 ******************************************************************/
33 int openClientGate(char *macAddress, char* userId, char* extraId)
39 int lockFileExist=TRUE;
40 char userIdLong[WORDMAXLN];
41 char clientAddr[WORDMAXLN]="?";
42 char ruleNumber[WORDMAXLN];
44 Sigfunc *defaultSigFunc;
46 /* prepare userid-long as [userid@extraid] */
47 strncpy(userIdLong, userId, WORDMAXLN);
49 strncat(userIdLong, "@", WORDMAXLN);
50 strncat(userIdLong, extraId, WORDMAXLN);
53 /* exclusive exec of ipfw to avoid overlapped rule number */
55 /* if not found lock is ignored */
56 lockFile=GetConfValue("LockFile");
57 if(stat(lockFile, &st)!=0) lockFileExist=FALSE;
58 else lockFileExist=TRUE;
60 /* if lock file exists, exec lock */
63 fd=open(lockFile, O_RDWR, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
65 err_msg("ERR at %s#%d: lockfile open error",__FILE__,__LINE__);
70 if((defaultSigFunc=signal(SIGALRM, sigFunc))==SIG_ERR){
71 err_msg("ERR at %s#%d: set sig alarm error",__FILE__,__LINE__);
75 alarm(atoi(GetConfValue("LockTimeout")));
79 err_msg("ERR at %s#%d: lock error/timeout",__FILE__,__LINE__);
85 signal(SIGALRM, defaultSigFunc);
89 /**** read rules ****/
90 if((retNum=GetRuleNumber(macAddress))<0){
91 /* fail then unlock */
96 return retNum; /* perhaps aleady registered addr is -retNum */
100 snprintf(ruleNumber, WORDMAXLN, "%d", retNum);
102 /**** write rules ****/
103 /* branch by perl script control flag */
104 if(atoi(GetConfValue("IpfwScript/Enable"))){
105 /********** use perl script to control firewall ************/
107 if(Systeml(1, GetConfValue("IpfwScript/Path"),GetConfValue("IpfwPath"),
108 ruleNumber,clientAddr,userIdLong,macAddress,"-",
109 GetConfValue("IpfwTagNumber"),GetConfValue("Pcap/Device"),
111 err_msg("ERR at %s#%d: exec script error",__FILE__,__LINE__);
112 retNum=1; /* abnormal */
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 */
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 */
148 /******************************************************************
149 close gate for clientAddr for the rule number
150 ******************************************************************/
151 void closeClientGate(int ruleNumber)
154 char ruleNumberStr[WORDMAXLN];
156 snprintf(ruleNumberStr, WORDMAXLN, "%d", ruleNumber); /* to string */
159 count=CountRuleNumber(ruleNumber);
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__);
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)
181 int num,newNum,readinNum;
189 enum status {NORMAL, ABNORMAL, FOUND, NOTFOUND, DUP};
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__);
196 /* search unused rule number in the list read from pipe */
197 /* check duplication of clientAddr to existing rules */
204 /* get rule range from config */
205 ipfwmin=atoi(GetConfValue("IpfwRule/Min"));
206 ipfwmax=atoi(GetConfValue("IpfwRule/Max"));
207 ipfwinterval=atoi(GetConfValue("IpfwRule/Interval"));
209 /* each port is checked whether it can be used for new rule or not */
210 for(num=ipfwmin;num<=ipfwmax;num+=ipfwinterval){
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;
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 */
227 if(fileStatus==ABNORMAL){
228 /* abnormal file proc, exit external loop */
233 /* EOF before reading a rule that is larger or equal to num */
234 /* it means that num can be used for new client */
240 /* at this point, readinNum is larger or equal to num */
241 /* check number duplication */
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)
248 && !isalnum(*(p+strlen(macAddress)))){
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__);
283 /*******************************
284 get packet count from ipfw
285 *******************************/
286 int getPacketCount(int ruleNumber)
291 int packets,packetsSum;
292 char ruleNumberStr[WORDMAXLN];
294 snprintf(ruleNumberStr, WORDMAXLN, "%d", ruleNumber); /* to string */
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__);
301 /* search unused number in the list read from pipe */
304 while(fgets(buf, BUFFMAXLN, fpipe)!=NULL){
305 sscanf(buf, "%d %d", &rule, &packets); /* get packet count */
315 /**********************************************
316 get rule count registed to a rule number
317 **********************************************/
318 int countRuleNumber(int ruleNumber)
323 char ruleNumberStr[WORDMAXLN];
325 snprintf(ruleNumberStr, WORDMAXLN, "%d", ruleNumber); /* to string */
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__);
332 /* count line read from pipe */
334 while(fgets(buf, BUFFMAXLN, fpipe)!=0) ruleCount++;
342 /**********************************************
343 function called by signal int
344 **********************************************/
345 static void sigFunc(int signo)
351 /**********************************************
352 get rule numbers table from ipfw rule set
353 **********************************************/
354 int getRuleTableFromIpfw(DB* ruleTable){
361 char macAddress[ADDRMAXLN];
366 int resultFlag=FALSE;
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__);
373 /* get rule range from config */
374 ipfwmin=atoi(GetConfValue("IpfwRule/Min"));
375 ipfwmax=atoi(GetConfValue("IpfwRule/Max"));
376 ipfwinterval=atoi(GetConfValue("IpfwRule/Interval"));
378 /* get ipfw rule line from pipe */
379 while(fgets(buf, BUFFMAXLN, fpipe)!=NULL){
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;
386 /* check the rule number range */
387 if(ruleNumber < ipfwmin)continue;
388 if(ruleNumber > ipfwmax)break;
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;
395 /* put to the hash table */
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__);
413 /**********************************************
414 is the macAddress found in ipfw rules
415 **********************************************/
416 int isMacAddressFoundInIpfw(char* macAddress){
421 char macAddressInRule[ADDRMAXLN];
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__);
433 /* get rule range from config */
434 ipfwmin=atoi(GetConfValue("IpfwRule/Min"));
435 ipfwmax=atoi(GetConfValue("IpfwRule/Max"));
436 ipfwinterval=atoi(GetConfValue("IpfwRule/Interval"));
438 /* get ipfw rule line from pipe */
439 while(fgets(buf, BUFFMAXLN, fpipe)!=NULL){
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;
446 /* check the rule number range */
447 if(ruleNumber < ipfwmin)continue;
448 if(ruleNumber > ipfwmax)break;
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;
455 /* compare the address with the argument */
456 /* if matched, exit loop */
457 if(strncmp(macAddress, macAddressInRule, ADDRMAXLN)==0){
470 /*********************************************
471 routines for debugging output
472 **********************************************/
473 int GetRuleNumber(char *macAddress)
477 if(debug>1) err_msg("DEBUG:=>getRuleNumber(%s)",macAddress);
478 ret=getRuleNumber(macAddress);
479 if(debug>1) err_msg("DEBUG:(%d)<=getRuleNumber( )",ret);
484 int OpenClientGate(char *macAddress, char* userId, char* extraId)
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);
495 void CloseClientGate(int ruleNumber)
497 if(debug>1) err_msg("DEBUG:=>closeClientGate(%d)",ruleNumber);
498 closeClientGate(ruleNumber);
499 if(debug>1) err_msg("DEBUG:<=closeClientGate( )");
503 int GetPacketCount(int ruleNumber)
507 if(debug>1) err_msg("DEBUG:=>getPacketCount(%d)",ruleNumber);
508 ret=getPacketCount(ruleNumber);
509 if(debug>1) err_msg("DEBUG:(%d)<=getPacketCount( )",ret);
514 int CountRuleNumber(int ruleNumber)
518 if(debug>1) err_msg("DEBUG:=>countRuleNumber(%d)", ruleNumber);
519 ret=countRuleNumber(ruleNumber);
520 if(debug>1) err_msg("DEBUG:(%d)<=countRuleNumber( )",ret);
525 int GetRuleTableFromIpfw(DB* ruleTable){
527 if(debug>1) err_msg("DEBUG:=>getRuleTableFromIpfw()");
528 ret=getRuleTableFromIpfw(ruleTable);
529 if(debug>1) err_msg("DEBUG:(%d)<=getRuleTableFromIpfw( )", ret);
533 int IsMacAddressFoundInIpfw(char* macAddress){
535 if(debug>1) err_msg("DEBUG:=>isMacAddressFoundInIpfw(%s)", macAddress);
536 ret=isMacAddressFoundInIpfw(macAddress);
537 if(debug>1) err_msg("DEBUG:(%d)<=isMacAddressFoundInIpfw( )", ret);