OSDN Git Service

Ver.0.8.1
[opengatem/opengatem.git] / mdsrc / opengatemd.c
1 /**************************************************
2 OpengateM - a MAC address authentication system
3 daemon main module 
4
5 Copyright (C) 2011 Opengate Project Team
6 Written by Yoshiaki Watanabe
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 /*************************************
26 This program uses following data structures 
27 to maintain the state of each terminal.
28
29    1. Packet Check Cache
30        To speed up the packet check process, the address checked once 
31          is ignored for a while.
32        The cache (key: MAC address) is used to decide 
33          the necessity of checking.
34        The cache is maintained the information of arrived packets 
35          by using hash-table and queue in the memory of local machine.
36    2. Session Table
37        The table (key: MAC address) maintains temporal information 
38          of terminals allowing the use of network now. 
39        The data are stored in the DB of local machine.
40    3. MAC address Table
41        The table (key: MAC address) maintains MAC addresses of terminals
42          and the owners' information.
43        The data are stored in the DB of a central machine
44          and accessed via network.
45    4. Cache of MAC address Table
46        As the network DB access is time-consuming, the access cache 
47          (key: MAC address) is maintained in the memory of local machine.
48
49 MAC address is used as main key for the user terminal.
50 IP address is kept only for information (firstly detected address only)
51 *************************************/
52
53 #include        "opengatemd.h"
54
55 void sigHupHandler(int sig);
56 void sigIoHandler(int sig);
57 void sigTermHandler(int sig);
58
59 int sigHupArrived=FALSE;
60 int sigIoArrived=FALSE;
61
62 /*********************/
63 /*  main routine     */
64 /*********************/
65 int  main(int argc, char **argv)
66 {
67   char ipAddress[ADDRMAXLN];  /* packet source ip address */
68   char macAddress[ADDRMAXLN]; /* packet source mac address */
69   unsigned char macAddressRaw[ADDRMAXLN];/* mac addr in raw form */
70   unsigned char ipAddressRaw[ADDRMAXLN];/* ip addr in raw form */
71   /* above is network raw binary, MAC(6bytes) and IP(4or16Bytes) */
72   int ipAddrLen;               /* ip address byte length 4 or 16 */         
73   char userId[USERMAXLN];     /* user id related to the mac address */
74   char extraId[USERMAXLN];    /* optional id for the user */
75   int macFound;               /* flag: mac address is resistered in db */
76   int sessionFound;           /* flag: session for the address exists */
77   int consoleMode=FALSE;      /* flag: start with console mode option */
78   int endServiceMode=FALSE;   /* flag: start with end service option */
79   int reloadServiceMode=FALSE;/* flag: start with reload option */ 
80   int stopServiceMode=FALSE;  /* flag: start with stop service option */ 
81   int showVersionMode=FALSE;  /* flag: show version */
82   int helpMode=FALSE;         /* flag: start with help mode */
83   int ttl;                    /* packet ttl(time to live) or hlim(hop limit) */
84   int i;                      /* for loop control */
85   int uselessCheckTime=0;     /* the last time for useless check */
86   int checkInterval;          /* useless session check interval */
87   int isNatOrRouter=FALSE;    /* the packet is sent from nat/router */
88   char macAddrInUdp[ADDRMAXLN]; /* mac address sent from udp port */
89   int ret;
90   char clientIpAddress[ADDRMAXLN]; /* udp client ip address */
91
92   /* analyze arguments */
93   for(i=1; i<argc; i++){
94     if(*argv[i]=='-' && *(argv[i]+1)=='c') consoleMode=TRUE;
95     else if(*argv[i]=='-' && *(argv[i]+1)=='e') endServiceMode=TRUE;
96     else if(*argv[i]=='-' && *(argv[i]+1)=='r') reloadServiceMode=TRUE;
97     else if(*argv[i]=='-' && *(argv[i]+1)=='s') stopServiceMode=TRUE;
98     else if(*argv[i]=='-' && *(argv[i]+1)=='v') showVersionMode=TRUE;
99     else helpMode=TRUE;
100   }
101
102   /* if unknown args, show help and exit */
103   if(helpMode){
104     ShowHelp(argv[0]);
105     terminateProg(0);
106   }
107
108   /* if '-v' option, show makedir and exit */  
109   if(showVersionMode){
110     printf("makedir: %s\n", MAKEDIR);
111     terminateProg(0);
112   }
113
114   /* drop root privilege */
115   seteuid(getuid());
116
117   /* prepare config file */
118   if(OpenConfFile()==-1) terminateProg(0);
119  
120   /* start log */
121   errToSyslog(atoi(GetConfValue("Syslog/Enable")));
122   openlog(GetConfValue("MacCheckDaemon"), LOG_PID, atoi(GetConfValue("Syslog/Facility")));
123
124   /* initialize config */
125   InitConf();
126
127   /* if reloadServiceMode, send HUP to resident daemon */
128   if(reloadServiceMode) ReloadDaemon();
129
130   /* if stopServiceMode, stop resident deamon and this process */
131   if(stopServiceMode){
132     KillDaemon();
133     terminateProg(0);
134   }
135
136   /* if endServiceMode, stop deamon and close sessions after setup */
137   if(endServiceMode) KillDaemon();
138
139   /* get runmode from command argument and set as daemon */
140   if(consoleMode)  errToSyslog(FALSE);    /* console mode (no syslog) */
141   else   Daemonize();                     /* daemon mode (fork&exit) */
142
143   /* set lock file to prevent overlapped execution */
144   if(!LockDaemonLockFile()){
145     terminateProg(0);
146   }
147
148   /* set signal functions */
149   signal(SIGHUP, sigHupHandler);
150   signal(SIGTERM, sigTermHandler);
151
152   /* initializing */
153   InitPcap();
154   InitCache();
155   InitMacCache();
156   InitWorkDb();
157   if(!InitMngDb()) terminateProg(0);
158   InitTtlCheck();
159   PrepareUdpPort(sigIoHandler); /* UDP port runs as asynchronous */
160
161   /* if endService is indicated, close all sessions, and exit */
162   if(endServiceMode){
163     DelAllSessions();
164     terminateProg(0);
165   }
166   
167   /* set check interval and remove residue sessions that are useless */
168   checkInterval=atoi(GetConfValue("UselessCheckInterval"));
169   uselessCheckTime=time(NULL);
170   DelUselessSessions();
171
172   /*** enter packet inspection loop ***/
173   while(1){
174
175     /* if sig-hup flag is on, reload this program */
176     if(sigHupArrived)execlp(argv[0], argv[0], NULL);
177
178     /* if mac addresses are received from management proc by udp, 
179        remove the addresses from caches */
180     if(sigIoArrived){
181       sigIoArrived=FALSE;
182       while(GetDataFromUdpPort(macAddrInUdp, ADDRMAXLN, clientIpAddress)>0){
183         if(IsUdpClientTrusted(clientIpAddress)){
184           DelCacheItem(macAddrInUdp);
185           DelMacCacheItem(macAddrInUdp);
186         }
187       }
188     }      
189
190     /* get one packet from pcap */
191     ret=GetNextPacketFromPcap(macAddressRaw, ipAddressRaw, &ipAddrLen, &ttl);
192
193     /* if no packet */
194     if(ret==0){
195
196       /* check useless sessions at some interval */
197       if( time(NULL) - uselessCheckTime > checkInterval ){
198         uselessCheckTime = time(NULL);
199         DelUselessSessions();
200       }
201
202       /* and return to loop top */
203       continue;
204     }
205
206     /* ignore not-ip packet */
207     if(ret==-1) continue;
208
209     /* ignore local packet */
210     if(ttl<=1) continue;
211    
212     /* ignore the packet checked recently */
213     if( IsRecentlyCheckedAddress(macAddressRaw) ) continue;
214
215     /**** only cache timeout packets proceeds to below ****/
216
217     /* convert address from network-raw form to presentation form */
218     ConvertMacFromRawToDisplay(macAddressRaw,macAddress);
219     if(!ConvertIpFromRawToDisplay(ipAddressRaw,ipAddrLen,ipAddress)) continue;
220
221     /* check nat/router and save info to db */
222     isNatOrRouter=IsSentViaNatOrRouter(ipAddress, macAddress, ttl);
223     if(isNatOrRouter) PutLogAtNatOrRouter(isNatOrRouter,ipAddress,macAddress,ttl);
224     PutMacInfoToWorkDb(macAddress, ttl, isNatOrRouter);
225
226     /*** get the states of the terminal in data structures ***/
227     /* search the address in session table */
228     sessionFound = IsMatchedSessionFound(macAddress);
229
230     /* search the address in MAC DB cache */ 
231     macFound = QueryMacFromMacCache(macAddress, userId, extraId);
232
233     /* if not found in MAC DB cache, search DB and add it to cache */
234     if(!macFound){
235       macFound = QueryMacFromMngDb(macAddress, userId, extraId);
236       if(macFound) AddMacCacheItem(macAddress, userId, extraId);
237     }
238
239     /*** depending the states, add/del/renew the session ***/
240     /* if valid mac and no session, start session */
241     if(macFound && !sessionFound){
242         AddSession(macAddress, ipAddress, userId, extraId);
243     }
244
245     /* if no mac and started session, stop session */
246     if(!macFound && sessionFound){
247       DelSession(macAddress);
248     }
249
250     /* if valid mac and started session, renew check time */
251     if(macFound && sessionFound){
252
253       /* in normal case, ipfw rule exists. */
254       if(IsMacAddressFoundInIpfw(macAddress)) RenewSession(macAddress);
255
256       /* when no ipfw rule exists, reset the session */
257       else{
258         DelSession(macAddress);
259         AddSession(macAddress, ipAddress, userId, extraId);     
260       }
261     }
262
263     /*  check useless sessions at some interval */
264     if( time(NULL) - uselessCheckTime > checkInterval ){
265       uselessCheckTime = time(NULL);
266       DelUselessSessions();
267     }
268   }
269
270   /* clear data structures (can't reach here, but coded for debugging) */
271   FreeCache();
272   FreeMacCache();
273   ClosePcap();
274   CloseConfFile();
275   CloseMngDb();
276
277   terminateProg(0);
278   return 0;
279 }
280
281 /********************************
282  open and lock proc lock file 
283  to prevent overlapped daemon exec
284 ********************************/
285 int lockDaemonLockFile(void){
286   
287   static int lockFd;
288   char str[WORDMAXLN];
289  
290   /* open process lock file */
291   lockFd = open(GetConfValue("DaemonLockFile"), O_RDWR|O_CREAT, 0644);
292   
293   /* if cannot open or cannot lock, return false */
294   if(lockFd<0){
295     err_msg("ERR at %s#%d: cannot open daemon lock file:%s",__FILE__,__LINE__,
296             lockFd);
297     return FALSE;
298   }
299   if(lockf(lockFd, F_TLOCK, 0)<0) return FALSE;
300
301   /* record pid */
302   snprintf(str, WORDMAXLN, "%d", getpid());
303   write(lockFd, str, strlen(str)+1);
304
305   /* normally locked */
306   return TRUE;
307 }
308
309
310 /******************************
311 daemonize the process
312 ******************************/
313 void daemonize(void){
314
315   int pid;
316   int i;
317
318   /* detach from parent */
319   pid = fork();
320   if(pid < 0){
321    err_msg("ERR at %s#%d: cannot fork",__FILE__,__LINE__);
322     terminateProg(0);
323   }
324
325   /* parent process exits */
326   if(pid > 0) exit(0);
327
328   /* child process runs from here */
329   /* set new prosess group */
330   setsid();
331
332   /* close all file descriptors */
333   for(i=getdtablesize(); i>=0; i--) close(i);
334
335   /* connect stdin/out/err to null */
336   i=open("/dev/null", O_RDWR); dup(i); dup(i);
337
338   /* set newly created file permission */
339   /* umask(033);   */
340
341   if(debug>0) err_msg("INFO: Deamon started");
342 }
343
344 /****************************************
345 show help message
346 ****************************************/
347 void showHelp(char* procName){
348    printf("\n");
349    printf("firewall control by mac address\n");
350    printf(" see detail in Opengate Homepage\n");
351    printf("\n");
352    printf(" format: %s [arg] \n", procName);
353    printf(" arg : -c = run on console (default is daemon)\n");
354    printf("     : -e = close all sessions and end service\n");
355    printf("     : -r = reload deamon\n");
356    printf("     : -s = stop deamon (not close sessions)\n");
357    printf("     : -v = show make dir to check version\n");
358  }
359
360 /*********************************
361 signal handler for SIGIO
362 *********************************/
363 void sigIoHandler(int sig){
364
365   sigIoArrived=TRUE;
366 }
367
368 /*********************************
369 signal handler for SIGHUP
370 *********************************/
371 void sigHupHandler(int sig){
372
373   if(debug>0)err_msg("INFO: Deamon receives HUP signal");
374   sigHupArrived=TRUE;
375 }
376
377 /*********************************
378 signal handler for SIGTERM
379 *********************************/
380 void sigTermHandler(int sig){
381
382   if(debug>0)err_msg("INFO: Deamon receives TERM signal");
383   terminateProg(0);
384 }
385
386 /*********************************
387 kill daemon process
388 *********************************/
389 void killDaemon(void){
390   FILE* file=NULL;
391   struct stat st;
392   int pid=0;
393   char* lockFileMd;
394
395   /* get lock file name */
396   lockFileMd=GetConfValue("DaemonLockFile");
397
398   /* if lock file is not exists, skip */
399   if(stat(lockFileMd, &st)!=0){
400     ;
401   }
402
403   /* read pid from the file */
404   else if((file=fopen(lockFileMd, "r"))==NULL){
405     err_msg("ERR at %s#%d: cannot open proc lock file:%s",__FILE__,__LINE__
406             ,lockFileMd);
407   }
408
409   else if(fscanf(file, "%d", &pid)==0){
410     err_msg("ERR at %s#%d: cannot read proc lock file:%s",__FILE__,__LINE__
411             ,lockFileMd);
412   }
413   if(file!=NULL) fclose(file);
414
415   /* send kill signal to the pid process */
416   if(pid!=0){
417     seteuid(0);   /* get root privilege */
418     kill(pid, SIGKILL);
419     seteuid(getuid());   /* drop root privilege */
420   }
421
422   /* remove the lockfile */
423   remove(lockFileMd);
424 }
425
426 /*********************************
427 reload daemon process
428 *********************************/
429 void reloadDaemon(void){
430   FILE* file=NULL;
431   struct stat st;
432   int pid=0;
433   char* lockFileMd;
434
435   /* get lock file name */
436   lockFileMd=GetConfValue("DaemonLockFile");
437
438   /* if lock file is not exists, skip */
439   if(stat(lockFileMd, &st)!=0){
440     ;
441   }
442
443   /* read pid from the file */
444   else if((file=fopen(lockFileMd, "r"))==NULL){
445     err_msg("ERR at %s#%d: cannot open proc lock file:%s",__FILE__,__LINE__
446             ,lockFileMd);
447   }
448
449   else if(fscanf(file, "%d", &pid)==0){
450     err_msg("ERR at %s#%d: cannot read proc lock file:%s",__FILE__,__LINE__
451             ,lockFileMd);
452   }
453   if(file!=NULL)fclose(file);
454
455   /* send hup signal to the pid process */
456   if(pid!=0){
457     seteuid(0);   /* get root privilege */
458     kill(pid, SIGHUP);
459     seteuid(getuid());   /* drop root privilege */
460   }
461 }
462
463 /*************************************
464 put out end message and exit 
465 *************************************/
466 void terminateProg(int ret){
467
468   /* close opengatemd.db */
469   FinalizeWorkDb();
470
471   if(debug>0) err_msg("INFO: Terminated");
472   exit(ret);
473 }
474
475
476 /************************************
477  routines for debugging output
478  ***********************************/
479 int LockDaemonLockFile(void){
480   int ret;
481   if(debug>1) err_msg("DEBUG:=>lockDaemonLockFile( )");
482   ret = lockDaemonLockFile();
483   if(debug>1) err_msg("DEBUG:(%d)<=lockDaemonLockFile( )",ret);
484   return ret;
485 }
486
487 void Daemonize(void){
488   if(debug>1) err_msg("DEBUG:=>daemonize( )");
489   daemonize();
490   if(debug>1) err_msg("DEBUG:<=daemonize( )");
491 }
492
493 void ShowHelp(char* procName){
494   if(debug>1) err_msg("DEBUG:=>showHelp(%s)", procName);
495   showHelp(procName);
496   if(debug>1) err_msg("DEBUG:<=showhelp( )");
497 }
498 void KillDaemon(void){
499   if(debug>1) err_msg("DEBUG:=>killDaemon( )");
500   killDaemon();
501   if(debug>1) err_msg("DEBUG:<=killDaemon( )");
502 }
503 void ReloadDaemon(void){
504   if(debug>1) err_msg("DEBUG:=>reloadDaemon( )");
505   reloadDaemon();
506   if(debug>1) err_msg("DEBUG:<=reloadDaemon( )");
507 }