1 /**************************************************
2 OpengateM - a MAC address authentication system
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 **************************************************/
25 /*************************************
26 This program uses following data structures
27 to maintain the state of each terminal.
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.
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.
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.
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 *************************************/
53 #include "opengatemd.h"
55 void sigHupHandler(int sig);
56 void sigIoHandler(int sig);
57 void sigTermHandler(int sig);
59 int sigHupArrived=FALSE;
60 int sigIoArrived=FALSE;
62 /*********************/
64 /*********************/
65 int main(int argc, char **argv)
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 */
90 char clientIpAddress[ADDRMAXLN]; /* udp client ip address */
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;
102 /* if unknown args, show help and exit */
108 /* if '-v' option, show makedir and exit */
110 printf("makedir: %s\n", MAKEDIR);
114 /* drop root privilege */
117 /* prepare config file */
118 if(OpenConfFile()==-1) terminateProg(0);
121 errToSyslog(atoi(GetConfValue("Syslog/Enable")));
122 openlog(GetConfValue("MacCheckDaemon"), LOG_PID, atoi(GetConfValue("Syslog/Facility")));
124 /* initialize config */
127 /* if reloadServiceMode, send HUP to resident daemon */
128 if(reloadServiceMode) ReloadDaemon();
130 /* if stopServiceMode, stop resident deamon and this process */
136 /* if endServiceMode, stop deamon and close sessions after setup */
137 if(endServiceMode) KillDaemon();
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) */
143 /* set lock file to prevent overlapped execution */
144 if(!LockDaemonLockFile()){
148 /* set signal functions */
149 signal(SIGHUP, sigHupHandler);
150 signal(SIGTERM, sigTermHandler);
157 if(!InitMngDb()) terminateProg(0);
159 PrepareUdpPort(sigIoHandler); /* UDP port runs as asynchronous */
161 /* if endService is indicated, close all sessions, and exit */
167 /* set check interval and remove residue sessions that are useless */
168 checkInterval=atoi(GetConfValue("UselessCheckInterval"));
169 uselessCheckTime=time(NULL);
170 DelUselessSessions();
172 /*** enter packet inspection loop ***/
175 /* if sig-hup flag is on, reload this program */
176 if(sigHupArrived)execlp(argv[0], argv[0], NULL);
178 /* if mac addresses are received from management proc by udp,
179 remove the addresses from caches */
182 while(GetDataFromUdpPort(macAddrInUdp, ADDRMAXLN, clientIpAddress)>0){
183 if(IsUdpClientTrusted(clientIpAddress)){
184 DelCacheItem(macAddrInUdp);
185 DelMacCacheItem(macAddrInUdp);
190 /* get one packet from pcap */
191 ret=GetNextPacketFromPcap(macAddressRaw, ipAddressRaw, &ipAddrLen, &ttl);
196 /* check useless sessions at some interval */
197 if( time(NULL) - uselessCheckTime > checkInterval ){
198 uselessCheckTime = time(NULL);
199 DelUselessSessions();
202 /* and return to loop top */
206 /* ignore not-ip packet */
207 if(ret==-1) continue;
209 /* ignore local packet */
212 /* ignore the packet checked recently */
213 if( IsRecentlyCheckedAddress(macAddressRaw) ) continue;
215 /**** only cache timeout packets proceeds to below ****/
217 /* convert address from network-raw form to presentation form */
218 ConvertMacFromRawToDisplay(macAddressRaw,macAddress);
219 if(!ConvertIpFromRawToDisplay(ipAddressRaw,ipAddrLen,ipAddress)) continue;
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);
226 /*** get the states of the terminal in data structures ***/
227 /* search the address in session table */
228 sessionFound = IsMatchedSessionFound(macAddress);
230 /* search the address in MAC DB cache */
231 macFound = QueryMacFromMacCache(macAddress, userId, extraId);
233 /* if not found in MAC DB cache, search DB and add it to cache */
235 macFound = QueryMacFromMngDb(macAddress, userId, extraId);
236 if(macFound) AddMacCacheItem(macAddress, userId, extraId);
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);
245 /* if no mac and started session, stop session */
246 if(!macFound && sessionFound){
247 DelSession(macAddress);
250 /* if valid mac and started session, renew check time */
251 if(macFound && sessionFound){
253 /* in normal case, ipfw rule exists. */
254 if(IsMacAddressFoundInIpfw(macAddress)) RenewSession(macAddress);
256 /* when no ipfw rule exists, reset the session */
258 DelSession(macAddress);
259 AddSession(macAddress, ipAddress, userId, extraId);
263 /* check useless sessions at some interval */
264 if( time(NULL) - uselessCheckTime > checkInterval ){
265 uselessCheckTime = time(NULL);
266 DelUselessSessions();
270 /* clear data structures (can't reach here, but coded for debugging) */
281 /********************************
282 open and lock proc lock file
283 to prevent overlapped daemon exec
284 ********************************/
285 int lockDaemonLockFile(void){
290 /* open process lock file */
291 lockFd = open(GetConfValue("DaemonLockFile"), O_RDWR|O_CREAT, 0644);
293 /* if cannot open or cannot lock, return false */
295 err_msg("ERR at %s#%d: cannot open daemon lock file:%s",__FILE__,__LINE__,
299 if(lockf(lockFd, F_TLOCK, 0)<0) return FALSE;
302 snprintf(str, WORDMAXLN, "%d", getpid());
303 write(lockFd, str, strlen(str)+1);
305 /* normally locked */
310 /******************************
311 daemonize the process
312 ******************************/
313 void daemonize(void){
318 /* detach from parent */
321 err_msg("ERR at %s#%d: cannot fork",__FILE__,__LINE__);
325 /* parent process exits */
328 /* child process runs from here */
329 /* set new prosess group */
332 /* close all file descriptors */
333 for(i=getdtablesize(); i>=0; i--) close(i);
335 /* connect stdin/out/err to null */
336 i=open("/dev/null", O_RDWR); dup(i); dup(i);
338 /* set newly created file permission */
341 if(debug>0) err_msg("INFO: Deamon started");
344 /****************************************
346 ****************************************/
347 void showHelp(char* procName){
349 printf("firewall control by mac address\n");
350 printf(" see detail in Opengate Homepage\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");
360 /*********************************
361 signal handler for SIGIO
362 *********************************/
363 void sigIoHandler(int sig){
368 /*********************************
369 signal handler for SIGHUP
370 *********************************/
371 void sigHupHandler(int sig){
373 if(debug>0)err_msg("INFO: Deamon receives HUP signal");
377 /*********************************
378 signal handler for SIGTERM
379 *********************************/
380 void sigTermHandler(int sig){
382 if(debug>0)err_msg("INFO: Deamon receives TERM signal");
386 /*********************************
388 *********************************/
389 void killDaemon(void){
395 /* get lock file name */
396 lockFileMd=GetConfValue("DaemonLockFile");
398 /* if lock file is not exists, skip */
399 if(stat(lockFileMd, &st)!=0){
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__
409 else if(fscanf(file, "%d", &pid)==0){
410 err_msg("ERR at %s#%d: cannot read proc lock file:%s",__FILE__,__LINE__
413 if(file!=NULL) fclose(file);
415 /* send kill signal to the pid process */
417 seteuid(0); /* get root privilege */
419 seteuid(getuid()); /* drop root privilege */
422 /* remove the lockfile */
426 /*********************************
427 reload daemon process
428 *********************************/
429 void reloadDaemon(void){
435 /* get lock file name */
436 lockFileMd=GetConfValue("DaemonLockFile");
438 /* if lock file is not exists, skip */
439 if(stat(lockFileMd, &st)!=0){
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__
449 else if(fscanf(file, "%d", &pid)==0){
450 err_msg("ERR at %s#%d: cannot read proc lock file:%s",__FILE__,__LINE__
453 if(file!=NULL)fclose(file);
455 /* send hup signal to the pid process */
457 seteuid(0); /* get root privilege */
459 seteuid(getuid()); /* drop root privilege */
463 /*************************************
464 put out end message and exit
465 *************************************/
466 void terminateProg(int ret){
468 /* close opengatemd.db */
471 if(debug>0) err_msg("INFO: Terminated");
476 /************************************
477 routines for debugging output
478 ***********************************/
479 int LockDaemonLockFile(void){
481 if(debug>1) err_msg("DEBUG:=>lockDaemonLockFile( )");
482 ret = lockDaemonLockFile();
483 if(debug>1) err_msg("DEBUG:(%d)<=lockDaemonLockFile( )",ret);
487 void Daemonize(void){
488 if(debug>1) err_msg("DEBUG:=>daemonize( )");
490 if(debug>1) err_msg("DEBUG:<=daemonize( )");
493 void ShowHelp(char* procName){
494 if(debug>1) err_msg("DEBUG:=>showHelp(%s)", procName);
496 if(debug>1) err_msg("DEBUG:<=showhelp( )");
498 void KillDaemon(void){
499 if(debug>1) err_msg("DEBUG:=>killDaemon( )");
501 if(debug>1) err_msg("DEBUG:<=killDaemon( )");
503 void ReloadDaemon(void){
504 if(debug>1) err_msg("DEBUG:=>reloadDaemon( )");
506 if(debug>1) err_msg("DEBUG:<=reloadDaemon( )");