OSDN Git Service

Ver.1.4.9: Change hello timing control from client side to server side.
[opengate/opengate.git] / opengate / opengatesrv / comm-ipfw.c
1 /**************************************************
2 opengate server
3  module for Controling ipfw 
4
5 Copyright (C) 1999 Opengate Project Team
6 Written by Yoshiaki Watanabe
7 Modified Katsuhiko Eguchi, 2005 
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
26 #include "opengatesrv.h"
27
28 char ruleNumber4[WORDMAXLN];  /* ipfw rule number in string form */
29
30 int getRuleNumber4(char *clientAddr4);
31 int GetRuleNumber4(char *clientAddr4);
32
33 static void sigFunc(int signo);
34
35 /******************************************************************/
36 /* open gate for clientAddr4 (nnn.nnn.nnn.nnn)                     */
37 /******************************************************************/
38 int openClientGate4(char *clientAddr4, char *userid, char *macAddr4, char *userProperty)
39 {
40   int fd;
41   int ret=0;
42   int retNum;
43
44   Sigfunc *defaultSigFunc;
45
46   /* exclusive exec of ipfw to avoid overlapped rule number */
47   /**** prepare ****/
48   /* open lockfile */
49   fd=open(GetConfValue("LockFile"), O_RDWR|O_CREAT, 
50           S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
51   if(fd==-1){
52     err_msg("ERR at %s#%d: lockfile open error",__FILE__,__LINE__);
53     return 1;
54   } 
55
56   /* set timeout */
57   if((defaultSigFunc=Signal(SIGALRM, sigFunc))==SIG_ERR) return 1;
58   alarm(atoi(GetConfValue("LockTimeout")));
59
60   /* lock */
61   if(Lock(fd)<0){
62     err_msg("ERR at %s#%d: lock error",__FILE__,__LINE__);
63     return 1;
64   }
65
66   /* reset timeout */
67   Signal(SIGALRM, defaultSigFunc);
68   alarm(0);
69
70   /**** read rules ****/
71   if((retNum=GetRuleNumber4(clientAddr4))<0){
72     /* fail then unlock */
73     Unlock(fd);
74     Close(fd);
75     return retNum;
76   }
77
78   /**** write rules ****/
79
80   if(atoi(GetConfValue("IpfwScript/Enable"))){
81     /********** use perl script to control firewall ************/
82
83     if(Systeml(GetConfValue("IpfwScript/Path"),GetConfValue("IpfwPath"),
84                ruleNumber4,clientAddr4,
85                userid,macAddr4,userProperty,(char *)0) != 0){
86       err_msg("ERR at %s#%d: exec script error",__FILE__,__LINE__);
87       ret=1;  /* abnormal */
88     }
89     
90     /* lock is not necessary in following exec */
91     Unlock(fd);
92     Close(fd);    /* because reserved number is used */
93
94   }else{
95     /********** direct control of firewall **********************/
96     /********** add outgoing ipfw rule for the client *************/
97     if(Systeml(GetConfValue("IpfwPath"),"-q","add",ruleNumber4,"allow","ip",
98                "from",clientAddr4,"to","any",(char *)0) != 0){
99       err_msg("ERR at %s#%d: exec ipfw add error",__FILE__,__LINE__);
100       ret=1;  /* abnormal */
101     }
102
103     /* lock is not necessary in following exec */
104     Unlock(fd);
105     Close(fd);    /* because reserved number is used */
106     
107     if(Systeml(GetConfValue("IpfwPath"),"-q","add",ruleNumber4,"allow","ip",
108                "from","any","to",clientAddr4,(char *)0) != 0){
109       err_msg("ERR at %s#%d: exec ipfw add error",__FILE__,__LINE__);
110       ret=1; /* abnormal */
111     }
112   }
113   return ret;
114 }
115
116
117 /******************************************************************/
118 /* close gate for clientAddr (nnn.nnn.nnn.nnn)                    */
119 /******************************************************************/
120 void closeClientGate4(struct clientAddr *pClientAddr, char *userid, char *macAddr4)
121 {
122   double time_l;
123   int hour, min, sec;
124   time_t timeOut;
125
126   /********** del ipfw rule for the client *************/
127   DelIpfwRule(pClientAddr->ruleNumber);
128
129   timeOut = time(NULL);
130   time_l=difftime(timeOut,pClientAddr->timeIn);
131   hour=time_l/60/60;
132   min=(time_l-hour*60*60)/60;
133   sec=(time_l-hour*60*60-min*60);
134   err_msg("CLOS: user %s from %s at %s ( %02d:%02d:%02d )",
135           userid, pClientAddr->ipAddr, macAddr4, hour,min,sec);
136
137   return;
138 }
139
140 /***********************************************/
141 /* delete ipfw rule                            */
142 /***********************************************/
143 void delIpfwRule(char *ruleNumber){
144   int count;
145
146   /* count rule */
147   count=CountRuleNumber4(ruleNumber);
148
149   if(count>0){
150     /* exec ipfw del */
151     /* [ipfw del rule] deletes all rule of the rule number at one call */
152     if(Systeml(GetConfValue("IpfwPath"),"del",ruleNumber,(char *)0) != 0){
153       err_msg("ERR at %s#%d: exec ipfw del error",__FILE__,__LINE__);
154     }
155   }
156 }
157
158 /**************************************/
159 /* get unused ipfw rule number        */
160 /* error if addr is already in rules */ 
161 /* return value ret>0: acquired rule number that can be used */
162 /*              ret=-1: no rule number available */
163 /*              ret=-2: some system error occured */
164 /*              ret=-num: the ip address is already registered in rule 'num' */
165 /**************************************/
166 int getRuleNumber4(char *clientAddr4)
167 {
168   FILE *fpipe;
169   char buf[BUFFMAXLN];
170   int num,newNum,readinNum;
171   char *p;
172   int ipfwmin;
173   int ipfwmax;
174   int ipfwinterval;
175   int portStatus;
176   int fileStatus;
177   enum status {NORMAL, ABNORMAL, FOUND, NOTFOUND, DUPLICATED};
178
179   /* exec ipfw list and open pipe */
180   if((fpipe=Popenl("r", GetConfValue("IpfwPath"),"list",(char *)0)) == NULL){ 
181       err_msg("ERR at %s#%d: exec ipfw list error",__FILE__,__LINE__);
182   }
183   
184   /* search unused rule number in the list read from pipe */
185   /* check duplication of clientAddr to existing rules */
186
187   newNum=-1;
188   readinNum=0;
189   portStatus=NOTFOUND;
190   fileStatus=NORMAL;
191
192   /* get rule range from config */
193   ipfwmin=atoi(GetConfValue("IpfwRule/Min"));
194   ipfwmax=atoi(GetConfValue("IpfwRule/Max"));
195   ipfwinterval=atoi(GetConfValue("IpfwRule/Interval"));
196
197   /* each port is checked whether it can be used for new rule or not */
198   for(num=ipfwmin;num<=ipfwmax;num+=ipfwinterval){
199
200     /* skip rules smaller than num */
201     while(readinNum<num){
202       if(fgets(buf, BUFFMAXLN, fpipe)==NULL){
203         if(feof(fpipe)==1) fileStatus=EOF; 
204         else fileStatus=ABNORMAL;
205         break;
206       }
207       if( sscanf(buf, "%d", &readinNum) !=1 ){
208         err_msg("ERR at %s#%d: abnormal ipfw response[ %s ]",
209                 __FILE__,__LINE__, buf);
210         fileStatus=ABNORMAL; /* abnormal responsem exit internal loop */
211         break;
212       }
213     }
214     
215     if(fileStatus==ABNORMAL){
216       /* abnormal file proc, exit external loop */ 
217       break;
218     }
219
220     if(fileStatus==EOF){
221       /* EOF before reading a rule that is larger or equal to num */
222       /* it means that num can be used for new client */
223       portStatus=FOUND;
224       newNum=num;
225       break;
226     }
227
228     /* at this point, readinNum is larger or equal to num */
229     /* check number duplication */
230     if(readinNum==num){
231
232       /* if clientAddr is found in the existing rule, then err exit. */
233       if(((p=(char*)strstr(buf+1,clientAddr4))!=NULL)
234         && isspace(*(p-1))
235         && !isalnum(*(p+strlen(clientAddr4)))){
236         err_msg("ERR at %s#%d: overlapped request from %s",
237                 __FILE__,__LINE__, clientAddr4);
238         newNum=num;
239         portStatus=DUPLICATED;
240         break;
241       }
242       /* the num is used for other client */
243       /* go to checking of next num */
244       else{
245         continue;
246       }
247     }
248     
249     /* at this point, readNum is larger than num */
250     /* it means that num can be used for new client */
251     newNum=num;
252     portStatus=FOUND;
253     break;
254   }
255   
256   /* close pipe */
257   Pclose(fpipe);
258     
259   if(fileStatus==ABNORMAL){
260     err_msg("ERR at %s#%d: abnormal ipfw response ",__FILE__,__LINE__);
261     return -2;
262   }
263   if(portStatus==NOTFOUND){
264     err_msg("ERR at %s#%d: cannot get unused ipfw number",__FILE__,__LINE__);
265     return -1;
266   }
267   if(portStatus==DUPLICATED){
268     return -newNum;
269   }
270
271   snprintf(ruleNumber4, WORDMAXLN, "%d", newNum); /* to string */
272
273   return newNum;
274 }
275
276 /*******************************/
277 /* get packet count from ipfw  */
278 /*******************************/
279 int getPacketCount4(char *ruleNumber)
280 {
281   FILE *fpipe;
282   char buf[BUFFMAXLN];
283   int rule;
284   int packets,packetsSum;
285
286   /* exec proc */
287   if((fpipe=Popenl("r", GetConfValue("IpfwPath"),"-a","list",ruleNumber,(char *)0)) == NULL){ 
288     err_msg("ERR at %s#%d: exec ipfw -a list error",__FILE__,__LINE__);
289   }
290
291   /* search unused number in the list read from pipe */
292   packetsSum=0;
293     
294   while(fgets(buf, BUFFMAXLN, fpipe)!=NULL){
295     sscanf(buf, "%d %d", &rule, &packets);   /* get packet count */
296     packetsSum+=packets;
297   }
298
299   /* close pipe */
300   Pclose(fpipe);
301
302   return packetsSum;
303 }
304
305 /**********************************************/
306 /* get rule count registed to a rule number   */
307 /**********************************************/
308 int countRuleNumber4(char *ruleNumber)
309 {
310   FILE *fpipe;
311   char buf[BUFFMAXLN];
312   int ruleCount;
313
314   /* exec proc */
315   if((fpipe=Popenl("r", GetConfValue("IpfwPath"),"list",ruleNumber,(char *)0)) == NULL){ 
316     err_msg("ERR at %s#%d: exec ipfw list error",__FILE__,__LINE__);
317   }
318   
319   /* count line read from pipe */
320   ruleCount = 0;
321   while(fgets(buf, BUFFMAXLN, fpipe)!=0) ruleCount++;
322
323   /* close pipe */
324   Pclose(fpipe);
325
326   return ruleCount;
327 }
328
329 /**********************************************/
330 /* function called by signal int              */
331 /**********************************************/
332 static void sigFunc(int signo)
333 {
334   return;
335 }
336
337 /**********************************************/
338 /**********************************************/
339 int GetRuleNumber4(char *clientAddr4)
340 {
341   int ret;
342
343   if(debug>1) err_msg("DEBUG:=>getRuleNumber4(%s)",clientAddr4);
344   ret=getRuleNumber4(clientAddr4);
345   if(debug>1) err_msg("DEBUG:(%d)<=getRuleNumber4( )",ret);
346
347   return ret;
348 }
349
350 int OpenClientGate4(char *clientAddr4, char *userid, char *macAddr4, char *userProperty)
351 {
352   int ret;
353
354   if(debug>1) err_msg("DEBUG:=>openClientGate4(%s,%s,%s,%s)",clientAddr4,userid,macAddr4,userProperty);
355   ret=openClientGate4(clientAddr4, userid, macAddr4, userProperty);
356   if(debug>1) err_msg("DEBUG:(%d)<=openClientGate4( )",ret);
357
358   return ret;
359 }
360
361 void CloseClientGate4(struct clientAddr *pClientAddr, char *userid, char *macAddr4)
362 {
363   if(debug>1) err_msg("DEBUG:=>closeClientGate4(%p,%s,%s)",pClientAddr,userid,macAddr4);
364   closeClientGate4(pClientAddr,userid,macAddr4);
365   if(debug>1) err_msg("DEBUG:<=closeClientGate4( )");
366 }
367
368
369 int GetPacketCount4(char *ruleNumber)
370 {
371   int ret;
372
373   if(debug>1) err_msg("DEBUG:=>getPacketCount4(%s)",ruleNumber);
374   ret=getPacketCount4(ruleNumber);
375   if(debug>1) err_msg("DEBUG:(%d)<=getPacketCount4( )",ret);
376
377   return ret;
378 }
379
380 void DelIpfwRule(char *ruleNumber){
381  if(debug>1) err_msg("DEBUG:=>delIpfwRule(%s)",ruleNumber);
382   delIpfwRule(ruleNumber);
383   if(debug>1) err_msg("DEBUG:<=delIpfwRule( )");
384 }
385
386 int CountRuleNumber4(char *ruleNumber)
387 {
388   int ret;
389   
390   if(debug>1) err_msg("DEBUG:=>countRuleNumber4(%s)", ruleNumber);
391   ret=countRuleNumber4(ruleNumber);
392   if(debug>1) err_msg("DEBUG:(%d)<=countRuleNumber4( )",ret);
393   
394   return ret;
395 }