00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00032 #include <stdio.h>
00033 #include <stdlib.h>
00034 #include <string.h>
00035 #include <errno.h>
00036 #include <unistd.h>
00037 #include <pthread.h>
00038 #include <sys/wait.h>
00039
00040 #define EUREPHIA_FWINTF
00041 #include <eurephiafw_struct.h>
00042 #include <eurephia_context.h>
00043 #include <eurephia_nullsafe.h>
00044 #include <eurephia_log.h>
00045 #include <eurephiafw_helpers.h>
00046
00047 #define INTERFACEVER "1.0"
00048 #define INTERFACEAPIVER 1
00055 const char *eFWinterfaceVersion() {
00056 return "eFW-iptables (v"INTERFACEVER") David Sommerseth 2008 (C) GPLv2";
00057 }
00058
00059
00065 int eFWinterfaceAPIversion() {
00066 return INTERFACEAPIVER;
00067 }
00068
00069
00070 int process_input(eurephiaCTX *ctx, const char *fwcmd, const char *msg);
00071 int call_iptables(eurephiaCTX *ctx, const char *fwcmd, char **ipt_args);
00072
00073
00079 void eFW_RunFirewall(void *fwargs) {
00080 efw_threaddata *cfg = (efw_threaddata *) fwargs;
00081 eurephiaCTX *ctx = (eurephiaCTX *) cfg->ctx;
00082 int quit = 0;
00083 unsigned int prio;
00084 char buf[EFW_MSG_SIZE+2];
00085 struct timespec tsp;
00086
00087 DEBUG(ctx, 28, "eFW_RunFirewall: Waiting for eFW master to get ready");
00088 sem_wait(cfg->semp_master);
00089 DEBUG(ctx, 28, "eFW_RunFirewall: Telling eFW master that the worker process is ready");
00090 sem_post(cfg->semp_worker);
00091
00092 if( cfg->fw_command == NULL ) {
00093 eurephia_log(ctx, LOG_FATAL, 0,
00094 "eFW_RunFirewall: firewall_command is not configured. "
00095 "iptables will not be updated.");
00096 exit(3);
00097 }
00098
00099 eurephia_log(ctx, LOG_INFO, 1, "efw_iptables: Firewall interface started");
00100
00101
00102 while( quit == 0 ) {
00103 memset(buf, 0, EFW_MSG_SIZE+2);
00104 if( mq_receive(cfg->msgq, &buf[0], EFW_MSG_SIZE, &prio) == -1 ) {
00105 eurephia_log(ctx, LOG_FATAL, 0,
00106 "eFW_RunFirewall: Error while reading messages from queue: %s",
00107 strerror(errno));
00108 exit(2);
00109 }
00110 quit = (strncmp(buf, "FWSHUTDOWN", 10) == 0 );
00111 if( !quit ) {
00112 int res = 0;
00113
00114 DEBUG(ctx, 20, "eFW_RunFirewall: Received '%s'", buf);
00115
00116 res = process_input(ctx, cfg->fw_command, buf);
00117 if( ! res ) {
00118 quit = 1;
00119 eurephia_log(ctx, LOG_FATAL, 0,
00120 "eFW_RunFirewall: Failed updating iptables");
00121 }
00122 }
00123 }
00124
00125
00126 efwRemoveMessageQueue(ctx, fwargs);
00127
00128 DEBUG(ctx, 28, "eFW_RunFirewall: Telling eFW master that the worker process is about to shut down");
00129 sem_post(cfg->semp_worker);
00130
00131 DEBUG(ctx, 28, "eFW_RunFirewall: Waiting for eFW master to acknowledge");
00132
00133 if( clock_gettime(CLOCK_REALTIME, &tsp) == -1 ) {
00134 eurephia_log(ctx, LOG_FATAL, 0, "eFW_RunFirewall: Could not prepare timeout for shutdown ack: %s",
00135 strerror(errno));
00136 sleep(10);
00137 } else {
00138 tsp.tv_sec += 30;
00139
00140
00141 if( sem_timedwait(cfg->semp_master, &tsp) == -1 ) {
00142 eurephia_log(ctx, LOG_PANIC, 0, "eFW_RunFirewall: Did not receive any shutdown ack: %s",
00143 strerror(errno));
00144 } else {
00145 eurephia_log(ctx, LOG_INFO, 1, "efw_iptables: Firewall interface is shut down");
00146 }
00147 }
00148 efwRemoveSemaphores(ctx, fwargs);
00149 exit(0);
00150 }
00151
00152
00163 int process_input(eurephiaCTX *ctx, const char *fwcmd, const char *input) {
00164 char mode[3], *addr = NULL, *destchain = NULL, *jump = NULL;
00165 char *msg = NULL, *orig_msg = NULL;
00166 char *iptables_args[] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
00167 int ret = 0;
00168
00169 orig_msg = strdup_nullsafe(input);
00170 msg = orig_msg;
00171 DEBUG(ctx, 36, "eFW_RunFirewall::process_input(ctx, '%s')", msg);
00172
00173
00174
00175
00176 mode[0] = '-';
00177 mode[1] = *msg;
00178 mode[2] = 0;
00179 msg += 2;
00180
00181 iptables_args[0] = (char *)fwcmd;
00182
00183 switch( mode[1] ) {
00184 case 'A':
00185 case 'D':
00186 iptables_args[1] = mode;
00187 addr = msg;
00188
00189
00190 destchain = addr+1;
00191 while( (*destchain != 0x20) || (*destchain == 0) ) {
00192 destchain++;
00193 }
00194 if( *destchain == 0 ) {
00195 return 0;
00196 }
00197 *destchain = 0;
00198 destchain++;
00199
00200 jump = destchain+1;
00201 while( (*jump != 0x20) || (*jump == 0) ) {
00202 jump++;
00203 }
00204 *jump = 0;
00205 jump++;
00206
00207
00208 iptables_args[2] = destchain;
00209 iptables_args[3] = "-m\0";
00210 iptables_args[4] = "mac\0";
00211 iptables_args[5] = "--mac-source\0";
00212 iptables_args[6] = addr;
00213 iptables_args[7] = "-m\0";
00214 iptables_args[8] = "state\0";
00215 iptables_args[9] = "--state\0";
00216 iptables_args[10] = "NEW\0";
00217 iptables_args[11] = "-j\0";
00218 iptables_args[12] = jump;
00219 iptables_args[13] = NULL;
00220
00221 eurephia_log(ctx, LOG_INFO, 3, "eFW_RunFirewall - updating iptables rules "
00222 "==> mode: %s macaddr: '%s' destchain: '%s' jump: '%s'",
00223 (mode[1] == 'A' ? "ADD":"DELETE"), addr, destchain, jump);
00224 ret = call_iptables(ctx, fwcmd, iptables_args);
00225 break;
00226
00227 case 'B':
00228 addr = msg;
00229
00230
00231 destchain = addr+1;
00232 while( (*destchain != 0x20) || (*destchain == 0) ) {
00233 destchain++;
00234 }
00235 if( *destchain == 0 ) {
00236 return 0;
00237 }
00238 *destchain = 0;
00239 destchain++;
00240
00241
00242 jump = destchain+1;
00243 while( (*jump != 0x20) || (*jump == 0) ) {
00244 jump++;
00245 }
00246 *jump = 0;
00247 jump++;
00248 if( *jump == 0 ) {
00249 return 0;
00250 }
00251
00252 iptables_args[1] = "-A\0";
00253 iptables_args[2] = destchain;
00254 iptables_args[3] = "-s\0";
00255 iptables_args[4] = addr;
00256 iptables_args[5] = "-j\0";
00257 iptables_args[6] = jump;
00258 iptables_args[7] = NULL;
00259
00260 eurephia_log(ctx, LOG_INFO, 3, "eFW_RunFirewall - updating iptables rules "
00261 "==> mode: BLACKLIST destchain: '%s' IP address: %s Send to: '%s'",
00262 destchain, addr, jump);
00263 ret = call_iptables(ctx, fwcmd, iptables_args);
00264 break;
00265
00266 case 'F':
00267 iptables_args[1] = mode;
00268 destchain = msg;
00269 iptables_args[2] = destchain;
00270 iptables_args[3] = NULL;
00271 eurephia_log(ctx, LOG_INFO, 3, "eFW_RunFirewall - updating iptables rules "
00272 "==> mode: FLUSH destchain: '%s'", destchain);
00273 ret = call_iptables(ctx, fwcmd, iptables_args);
00274 break;
00275
00276 case 'I':
00277
00278 destchain = msg;
00279
00280 eurephia_log(ctx, LOG_INFO, 3, "eFW_RunFirewall - Initialising iptables chain '%s'",
00281 destchain);
00282
00283
00284 iptables_args[1] = "-F";
00285 destchain = msg;
00286 iptables_args[2] = destchain;
00287 iptables_args[3] = NULL;
00288 ret = call_iptables(ctx, fwcmd, iptables_args);
00289
00290
00291 iptables_args[1] = "-I\0";
00292 iptables_args[2] = destchain;
00293 iptables_args[3] = "-m\0";
00294 iptables_args[4] = "state\0";
00295 iptables_args[5] = "--state\0";
00296 iptables_args[6] = "ESTABLISHED,RELATED\0";
00297 iptables_args[7] = "-j\0";
00298 iptables_args[8] = "ACCEPT\0";
00299 ret &= call_iptables(ctx, fwcmd, iptables_args);
00300 break;
00301
00302 default:
00303 eurephia_log(ctx, LOG_CRITICAL, 0, "eFW_RunFirewall::process_input: Malformed update request");
00304 ret = 1;
00305 }
00306 free_nullsafe(ctx, orig_msg);
00307 return ret;
00308 }
00309
00310
00322 int call_iptables(eurephiaCTX *ctx, const char *fwcmd, char **ipt_args) {
00323 pid_t pid;
00324 int cmdret = -1;
00325
00326
00327
00328 if( (pid = fork()) < 0) {
00329 eurephia_log(ctx, LOG_FATAL, 0,
00330 "eFW_RunFirewall::process_input: Failed to fork process for %s", fwcmd);
00331 return 0;
00332 }
00333
00334 switch( pid ) {
00335 case 0:
00336 execve(fwcmd, ipt_args, NULL);
00337 exit(1);
00338
00339 default:
00340 if( waitpid(pid, &cmdret, 0) != pid ) {
00341 eurephia_log(ctx, LOG_WARNING, 0,
00342 "eFW_RunFirewall::process_input: Failed to wait for process for %s"
00343 " to complete (%s)", fwcmd, strerror(errno));
00344 }
00345 eurephia_log(ctx, LOG_INFO, 4, "eFW_RunFirewall - iptables exited with code: %i ", cmdret);
00346 }
00347 return 1;
00348 }