OSDN Git Service

Ver.1.2.0: add IPv6 support contributed by K. Eguchi
[opengate/opengate.git] / opengate / opengatesrv / comm-ipfw.c
1 /**************************************************
2 opengate server
3  module for Controling ipfw 
4
5 Copyright (C) 1999 Yoshiaki Watanabe
6       Modfied 2005 Katsuhiko Eguchi
7
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.
12
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.
17
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.
21
22 Email: watanaby@is.saga-u.ac.jp
23 **************************************************/
24
25 #include "opengatesrv.h"
26
27 char ruleNumber4[WORDMAXLN];  /* ipfw rule number in string form */
28
29 int getRuleNumber4(char *clientAddr4);
30 int GetRuleNumber4(char *clientAddr4);
31
32 static void sigFunc(int signo);
33
34 /******************************************************************/
35 /* open gate for clientAddr4 (nnn.nnn.nnn.nnn)                     */
36 /******************************************************************/
37 int openClientGate4(char *clientAddr4, char *userid, char *macAddr4, char *userProperty)
38 {
39   int st;
40   int fd;
41   int ret;
42   int retFork;
43   int retNum;
44
45   Sigfunc *defaultSigFunc;
46
47   /* exclusive exec of ipfw to avoid overlapped rule number */
48
49   /**** prepare ****/
50   /* open lockfile */
51   fd=Open(LOCKFILE, O_RDWR|O_CREAT, 
52           S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
53   /* set timeout */
54   defaultSigFunc=Signal(SIGALRM, sigFunc);
55   alarm(LOCKTIMEOUT);
56   /* lock */
57   Lock(fd);
58   /* reset timeout */
59   Signal(SIGALRM, defaultSigFunc);
60   alarm(0);
61
62   /**** read rules ****/
63   if((retNum=GetRuleNumber4(clientAddr4))<0){
64     /* fail then unlock */
65     Unlock(fd);
66     Close(fd);
67     if(retNum==-3) return 1; /* ipfw returns abnormal response */
68     else return -1; /* already opened or rules are full */
69   }
70
71   /**** write rules ****/
72
73   if(GetUseFwScript()==1){
74     /********** use perl script to control firewall ************/
75
76     /* fork */
77     if((retFork=Fork())==0){
78       /* child proc */
79       if(execl(GetFwScriptPath(),GetFwScript(),IPFWPATH,ruleNumber4,clientAddr4,
80                userid,macAddr4,userProperty,(char *)0)==-1){
81               err_quit("ERR in comm-ipfw: execl error no= %d", errno);
82       }
83       exit(1);
84     }
85     
86     /* parent process */
87     if(retFork==-1){
88       err_msg("ERR in comm-ipfw: fork error no= %d", errno);
89     }
90
91     /* wait child end */
92     wait(&st);
93     if(WIFEXITED(st)){
94       ret=WEXITSTATUS(st);
95       if(ret) err_msg("ERR in comm-ipfw: child process returns error %d", ret);
96     } else{
97       ret=1;
98       err_msg("ERR in comm-ipfw: child process does not exited by exit call");
99     }
100
101     Unlock(fd);   /* lock is not necessary in following exec */
102     Close(fd);    /* because reserved number is used */
103
104   }else{
105     /********** direct control of firewall **********************/
106     /********** add outgoing ipfw rule for the client *************/
107     /* fork */
108     if((retFork=Fork())==0){
109       /* child proc */
110       if(execl(IPFWPATH,"ipfw","-q","add",ruleNumber4,"allow","ip",
111                "from",clientAddr4,"to","any",(char *)0)==-1){
112               err_quit("ERR in comm-ipfw: execl error no= %d", errno);
113       }
114       exit(1);
115     }
116
117     /* parent process */
118     if(retFork==-1){
119       err_msg("ERR in comm-ipfw: fork error no= %d", errno);
120     }
121
122     /* wait child end */
123     wait(&st);
124     if(WIFEXITED(st)){
125       ret=WEXITSTATUS(st);
126       if(ret) err_msg("ERR in comm-ipfw: child process returns error %d", ret);
127     } else{
128       ret=1;
129       err_msg("ERR in comm-ipfw: child process does not exited by exit call");
130     }
131
132     Unlock(fd);   /* lock is not necessary in following exec */
133     Close(fd);    /* because reserved number is used */
134     
135     /********** add incoming ipfw rule for the client *************/
136     /* fork */
137     if((retFork=Fork())==0){
138       /* child proc */
139       if(execl(IPFWPATH,"ipfw","-q","add",ruleNumber4,"allow","ip",
140                "from","any","to",clientAddr4,(char *)0)==-1){
141               err_quit("ERR in comm-ipfw: execl error no= %d", errno);
142       }
143       exit(1);
144     }
145
146     /* parent process */
147     if(retFork==-1){
148       err_msg("ERR in comm-ipfw: fork error no= %d", errno);
149     }
150
151     /* wait child end */
152     wait(&st);
153     if(WIFEXITED(st)){
154       ret=WEXITSTATUS(st);
155       if(ret) err_msg("ERR in comm-ipfw: child process returns error %d", ret);
156     } else{
157       ret=1;
158       err_msg("ERR in comm-ipfw: child process does not exited by exit call");
159     }
160
161   }
162   return ret;
163 }
164
165
166 /******************************************************************/
167 /* close gate for clientAddr (nnn.nnn.nnn.nnn)                    */
168 /******************************************************************/
169 void closeClientGate4(struct clientAddr *pClientAddr, char *userid, char *macAddr4)
170 {
171   int st;
172   double time_l;
173   int hour, min, sec;
174   time_t timeOut;
175
176   /********** del ipfw rule for the client *************/
177
178   /* fork */
179   if(Fork()==0){
180     /* child proc */
181     if(execl(IPFWPATH,"ipfw","del",pClientAddr->ruleNumber,(char *)0)==-1){
182       err_quit("ERR in comm-ipfw: execl error no= %d", errno);
183     }
184     exit(1);
185   }
186   /* wait child end */
187   wait(&st);
188
189   timeOut = time(NULL);
190   time_l=difftime(timeOut,pClientAddr->timeIn);
191   hour=time_l/60/60;
192   min=(time_l-hour*60*60)/60;
193   sec=(time_l-hour*60*60-min*60);
194   err_msg("CLOS: user %s from %s at %s ( %02d:%02d:%02d )",
195           userid, pClientAddr->IpAddr, macAddr4, hour,min,sec);
196
197   return;
198 }
199
200
201 /**************************************/
202 /* get unused ipfw rule number        */
203 /* error if addr is already in rules */ 
204 /**************************************/
205 int getRuleNumber4(char *clientAddr4)
206 {
207   int fd[2];
208   int piperead_fd,pipewrite_fd;
209   int stdin_fd=0,stdout_fd=1,stderr_fd=2;
210   char buf[BUFFMAXLN];
211   int st;
212   int num,newNum,readinNum;
213   int eofFound;
214   int abnormalRes;
215   char *p;
216   int ipfwmin;
217   int ipfwmax;
218   int ipfwinterval;
219
220   /* create pipe */
221   if(pipe(fd)!=0){
222     err_msg("ERR in comm-ipfw: Cannot create pipe for ipfw\n");
223     return -1;
224   }
225   piperead_fd=fd[0];
226   pipewrite_fd=fd[1];
227
228   /* fork */
229   if(Fork()==0){
230     /* child proc */
231
232     /* connect pipeout to stdout & strerr */
233     Close(stdout_fd);
234     Close(stderr_fd);
235     dup(pipewrite_fd);
236     dup(pipewrite_fd);
237
238     /* close other IO */
239     Close(stdin_fd);
240     Close(piperead_fd);
241     Close(pipewrite_fd);
242
243     /* exec proc */
244     if(execl(IPFWPATH,"ipfw","list",(char *)0) == -1){ 
245       err_quit("ERR in comm-ipfw: execlp error no= %d", errno);
246     }
247     exit(1);
248   }
249   /* parent proc */
250   
251   /* close unuse IO */
252   Close(pipewrite_fd);
253   
254   /* search unused rule number in the list read from pipe */
255   /* check duplication of clientAddr to existing rules */
256   newNum=-1;
257   readinNum=0;
258   eofFound=0;
259   abnormalRes=0;
260
261   /* get rule range from config */
262   ipfwmin=GetIpfwMin();
263   ipfwmax=GetIpfwMax();
264   ipfwinterval=GetIpfwInterval();
265
266   for(num=ipfwmin;num<=ipfwmax;num+=ipfwinterval){
267
268     /* skip rules smaller than num */
269     while(readinNum<num){
270       if(Readln(piperead_fd, buf, BUFFMAXLN-1)==0){
271         /* EOF */
272         eofFound=1;
273         break;
274       }
275       if( sscanf(buf, "%d", &readinNum) !=1 ){
276         err_msg("ERR in comm-ipfw: abnormal ipfw response[ %s ]", buf);
277         abnormalRes=1;
278       }
279     }
280     
281     /* if get abnormal response, error is returned */ 
282     if(abnormalRes){
283       newNum=-3;
284       break;
285     }
286
287     /* if no rules larger or equal to num, then search end */
288     if(eofFound){
289       if(newNum<0) newNum=num;
290       break;
291     }
292
293     /* if num is already used, then check dup and go to next search */
294     if(readinNum==num){
295       /* if clientAddr is found in rule, then err exit */
296       if(((p=(char*)strstr(buf+1,clientAddr4))!=NULL)
297         && isspace(*(p-1))
298         && !isalnum(*(p+strlen(clientAddr4)))){
299         err_msg("ERR in comm-ipfw: overlapped request from %s", clientAddr4);
300         newNum=-2;
301         break;
302       }
303       continue;
304     }
305
306     /* num is not used */
307     if(newNum<0)newNum=num;
308     if(readinNum>ipfwmax)break;
309   }
310   
311   /* close pipe */
312   Close(piperead_fd);
313     
314   /* wait child end */
315   wait(&st);
316
317   if(newNum==-1){
318     err_msg("ERR in comm-ipfw: cannot get unused ipfw number");
319   }
320
321   snprintf(ruleNumber4, WORDMAXLN, "%d", newNum); /* to string */
322
323   return newNum;
324 }
325
326 /****************************************/
327 /* get packet count from ipfw and ip6fw */
328 /****************************************/
329 int getPacketCount(struct clientAddr *pClientAddr)
330 {
331   int packets=0;
332   struct clientAddr *pNow;
333   pNow=pClientAddr;
334
335   while(pNow!=NULL){
336     if(pNow->type==4){
337       packets+=GetPacketCount4(pNow->ruleNumber);
338     }else if(pNow->type==6){
339       packets+=GetPacketCount6(pNow->ruleNumber);
340     }
341     pNow=pNow->next;
342   }
343
344   return packets;
345 }
346
347 /*******************************/
348 /* get packet count from ipfw  */
349 /*******************************/
350 int getPacketCount4(char *ruleNumber)
351 {
352   int fd[2];
353   int piperead_fd,pipewrite_fd;
354   int stdin_fd=0,stdout_fd=1;
355   char buf[BUFFMAXLN];
356   int st;
357   int rule;
358   int packets,packetsSum;
359
360   /* create pipe */
361   if(pipe(fd)!=0){
362     err_msg("ERR in comm-ipfw: Cannot create pipe for ipfw\n");
363     return -1;
364   }
365   piperead_fd=fd[0];
366   pipewrite_fd=fd[1];
367
368   /* fork */
369   if(Fork()==0){
370     /* child proc */
371
372     /* connect pipeout to stdout */
373     Close(stdout_fd);
374     dup(pipewrite_fd);
375
376     /* close other IO */
377     Close(stdin_fd);
378     Close(piperead_fd);
379     Close(pipewrite_fd);
380
381     /* exec proc */
382     if(execl(IPFWPATH,"ipfw","-a","list",ruleNumber,(char *)0) == -1){ 
383       err_quit("ERR in comm-ipfw: execl error no= %d", errno);
384     }
385   }
386   /* parent proc */
387   
388   /* close unuse IO */
389   Close(pipewrite_fd);
390   
391   /* search unused number in the list read from pipe */
392
393   packetsSum=0;
394     
395   while(Readln(piperead_fd, buf, BUFFMAXLN-1)!=0){
396     sscanf(buf, "%d %d", &rule, &packets);   /* get packet count */
397     packetsSum+=packets;
398   }
399
400   /* close pipe */
401   Close(piperead_fd);
402     
403   /* wait child end */
404   wait(&st);
405
406   return packetsSum;
407 }
408
409
410 /**********************************************/
411 /* function called by signal int              */
412 /**********************************************/
413 static void sigFunc(int signo)
414 {
415   return;
416 }
417
418 /**********************************************/
419 /**********************************************/
420 int GetRuleNumber4(char *clientAddr4)
421 {
422   int ret;
423
424   if(DEBUG) err_msg("DEBUG:=>getRuleNumber4(%s)",clientAddr4);
425   ret=getRuleNumber4(clientAddr4);
426   if(DEBUG) err_msg("DEBUG:(%d)<=getRuleNumber4( )",ret);
427
428   return ret;
429 }
430
431 int OpenClientGate4(char *clientAddr4, char *userid, char *macAddr4, char *userProperty)
432 {
433   int ret;
434
435   if(DEBUG) err_msg("DEBUG:=>openClientGate(%s,%s,%s,%s)",clientAddr4,userid,macAddr4,userProperty);
436   ret=openClientGate4(clientAddr4, userid, macAddr4, userProperty);
437   if(DEBUG) err_msg("DEBUG:(%d)<=openClientGate4( )",ret);
438
439   return ret;
440 }
441
442 void CloseClientGate4(struct clientAddr *pClientAddr, char *userid, char *macAddr4)
443 {
444   if(DEBUG) err_msg("DEBUG:=>closeClientGate4(%p,%s,%s)",pClientAddr,userid,macAddr4);
445   closeClientGate4(pClientAddr,userid,macAddr4);
446   if(DEBUG) err_msg("DEBUG:<=closeClientGate4( )");
447 }
448
449 int GetPacketCount(struct clientAddr *pClientAddr)
450 {
451   int ret;
452
453   if(DEBUG) err_msg("DEBUG:=>getPacketCount(%p)",pClientAddr);
454   ret=getPacketCount(pClientAddr);
455   if(DEBUG) err_msg("DEBUG:(%d)<=getPacketCount( )",ret);
456
457   return ret;
458 }
459
460 int GetPacketCount4(char *ruleNumber)
461 {
462   int ret;
463
464   if(DEBUG) err_msg("DEBUG:=>getPacketCount4(%s)",ruleNumber);
465   ret=getPacketCount4(ruleNumber);
466   if(DEBUG) err_msg("DEBUG:(%d)<=getPacketCount4( )",ret);
467
468   return ret;
469 }