summaryrefslogtreecommitdiffstats
path: root/plugin/firewall
diff options
context:
space:
mode:
Diffstat (limited to 'plugin/firewall')
-rw-r--r--plugin/firewall/eurephiafw.c288
-rw-r--r--plugin/firewall/eurephiafw.h34
-rw-r--r--plugin/firewall/eurephiafw_helpers.c97
-rw-r--r--plugin/firewall/eurephiafw_helpers.h36
-rw-r--r--plugin/firewall/eurephiafw_intf.h30
-rw-r--r--plugin/firewall/iptables/CMakeLists.txt12
-rw-r--r--plugin/firewall/iptables/efw_iptables.c234
7 files changed, 731 insertions, 0 deletions
diff --git a/plugin/firewall/eurephiafw.c b/plugin/firewall/eurephiafw.c
new file mode 100644
index 0000000..9fed02e
--- /dev/null
+++ b/plugin/firewall/eurephiafw.c
@@ -0,0 +1,288 @@
+/* eurephiafw.c -- Firewall interface loader for the eurephia module
+ *
+ * GPLv2 - Copyright (C) 2008 David Sommerseth <dazo@users.sourceforge.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2
+ * of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <signal.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include "eurephia_struct.h"
+#include "eurephia_log.h"
+#include "eurephiafw.h"
+#include "eurephiafw_intf.h"
+#include "eurephia_getsym.h"
+#include "eurephia_nullsafe.h"
+#include "eurephia_values.h"
+#include "eurephiafw_helpers.h"
+
+int eFW_unload(eurephiaCTX *ctx) {
+ if( ctx == NULL ) {
+ return 1;
+ }
+
+ if( ctx->eurephia_fw_intf != NULL ) {
+ eurephia_log(ctx, LOG_INFO, 3, "Unloading eurephia firewall interface");
+ dlclose(ctx->eurephia_fw_intf);
+ ctx->eurephia_fw_intf = NULL;
+ return 0;
+ }
+ return 1;
+}
+
+
+int eFW_load(eurephiaCTX *ctx, const char *intf) {
+ if( (intf == NULL) || (strlen(intf) == 0) ) {
+ eurephia_log(ctx, LOG_FATAL, 0, "No valid eurephia firewall interface indicated");
+ return 0;
+ }
+ eurephia_log(ctx, LOG_INFO, 2, "Loading eurephia firewall interface: %s", intf);
+
+ ctx->eurephia_fw_intf = dlopen(intf, RTLD_NOW);
+ if( ctx->eurephia_fw_intf == NULL ) {
+ eurephia_log(ctx, LOG_FATAL, 0, "Could not open the eurephia firewall interface (%s)", intf);
+ eurephia_log(ctx, LOG_FATAL, 1, "dlopen error: %s", dlerror());
+ return 0;
+ }
+
+ // Mandatory functions
+ eFWinterfaceVersion = eGetSym(ctx, ctx->eurephia_fw_intf, "eFWinterfaceVersion");
+ eFWinterfaceAPIversion = eGetSym(ctx, ctx->eurephia_fw_intf, "eFWinterfaceAPIversion");
+
+ eurephia_log(ctx, LOG_INFO, 1, "Firewall interface loaded: %s (API version %i)",
+ eFWinterfaceVersion(), eFWinterfaceAPIversion());
+
+ // Configure firewall interface functions
+ switch( eFWinterfaceAPIversion() ) {
+ default:
+ eurephia_log(ctx, LOG_WARNING, 0,
+ "eurephia Firewall interface API is newer than what the running eurephia version is "
+ "familiar with. Please consider to upgrade eurphia to take advantage of newer "
+ "features in the eurephiaDB driver.");
+
+ case 1:
+ eFW_RunFirewall = eGetSym(ctx, ctx->eurephia_fw_intf, "eFW_RunFirewall");
+ break;
+
+ }
+
+ if( ctx->fatal_error > 0 ) {
+ eurephia_log(ctx, LOG_FATAL, 0, "eurephia Firewall interface is not correctly initialised. "
+ "eurephia authentication will not be available");
+ eFW_unload(ctx);
+ return 0;
+ }
+ return 1;
+}
+
+void eFW_StartFirewall(eurephiaCTX *ctx) {
+ struct mq_attr mqattr;
+ eurephiaCTX *shadowctx = NULL;
+ char buf[1026], *fwdest = NULL;
+ unsigned int prio;
+
+ ctx->fwcfg = (eurephiaFWINTF *) malloc(sizeof(eurephiaFWINTF)+2);
+ memset(ctx->fwcfg, 0, sizeof(eurephiaFWINTF)+2);
+
+ // Create a fake eurephia context, just for logging
+ shadowctx = (eurephiaCTX *) malloc(sizeof(eurephiaCTX)+2);
+ memset(shadowctx, 0, sizeof(eurephiaCTX)+2);
+ shadowctx->loglevel = ctx->loglevel;
+ shadowctx->log = ctx->log;
+ (*ctx->fwcfg).thrdata.ctx = shadowctx;
+
+ (*ctx->fwcfg).thrdata.fw_command = strdup_nullsafe(eGet_value(ctx->dbc->config, "firewall_command"));
+ if( (*ctx->fwcfg).thrdata.fw_command == NULL) {
+ eurephia_log(ctx, LOG_PANIC, 0, "Could not find firewall_command in configuration. "
+ "Firewall updates will not be available.");
+ return;
+ } else {
+ eurephia_log(ctx, LOG_INFO, 1, "Using %s to update the firewall rules.",
+ (*ctx->fwcfg).thrdata.fw_command );
+ }
+
+ fwdest = eGet_value(ctx->dbc->config, "firewall_destination");
+ if( fwdest == NULL ) {
+ eurephia_log(ctx, LOG_PANIC, 0, "Could not find firewall_destination in configuration. "
+ "Firewall updates will not be available.");
+ return;
+ } else {
+ eurephia_log(ctx, LOG_INFO, 1, "Using '%s' as firewall rule for VPN accesses", fwdest);
+ }
+
+ eurephia_log(ctx, LOG_INFO, 3, "Starting eurephia firewall interface");
+
+ // Setup semaphores we need
+ if( efwSetupSemaphores(ctx, &(*ctx->fwcfg).thrdata) == 0 ) {
+ free_nullsafe(ctx->fwcfg->thrdata.fw_command);
+ return;
+ };
+
+ // Setup a message queue
+ if( efwSetupMessageQueue(ctx, &(*ctx->fwcfg).thrdata) == 0 ) {
+ free_nullsafe(ctx->fwcfg);
+ return;
+ }
+
+ // Make sure that these variables are not available in the child
+ madvise(ctx, sizeof(eurephiaCTX), MADV_DONTFORK);
+
+ // Start a new process (should run with root permissions) - which will do the firewall work
+ if( (ctx->fwcfg->fwproc_pid = fork()) < 0 ) {
+ eurephia_log(ctx, LOG_PANIC, 0,
+ "Could not fork out a child process for the firewall interface (%s)",
+ strerror(errno));
+ return;
+ }
+ switch( ctx->fwcfg->fwproc_pid ) {
+ case 0: // Child process
+ eFW_RunFirewall(&(*ctx->fwcfg).thrdata);
+ exit(-1); // If our child process exits abnormally.
+
+ default: // Main process
+ eurephia_log(ctx, LOG_INFO, 2, "Firewall updater process started (pid %i)",
+ ctx->fwcfg->fwproc_pid);
+ }
+
+ // Flush the message queue for old messages
+ if( mq_getattr((*ctx->fwcfg).thrdata.msgq, &mqattr) == 0 ) {
+ long i;
+
+ memset(&buf, 0, 1026);
+ if( mqattr.mq_curmsgs > 0 ) {
+ for( i = 0; i < mqattr.mq_curmsgs; i++ ) {
+ if( mq_receive((*ctx->fwcfg).thrdata.msgq, &buf[0], 1024, &prio) == -1 ) {
+ eurephia_log(ctx, LOG_CRITICAL, 0,
+ "Error while emptying messages from queue: %s",
+ strerror(errno));
+ } else {
+ DEBUG(ctx, 28, "Removed message on queue: %s", buf);
+ }
+ }
+ }
+ eurephia_log(ctx, LOG_INFO, 3, "Message queue for firewall updates is ready");
+ } else {
+ eurephia_log(ctx, LOG_FATAL, 0, "Could not retrieve message queue attributes (%s)",
+ strerror(errno));
+ }
+
+ // Indicate for the FW module that we are ready
+ sem_post(ctx->fwcfg->thrdata.semp_master);
+
+ // Waiting for the FW module to get ready
+ DEBUG(ctx, 28, "eFW master is ready, waiting for the eFW worker to get ready");
+ sem_wait(ctx->fwcfg->thrdata.semp_worker);
+ eurephia_log(ctx, LOG_INFO, 2, "eFW interface initialised.");
+
+ // Initialise the chain
+ memset(&buf, 0, 1026);
+ snprintf(buf, 1024, "I %s", fwdest);
+ if( mq_send((*ctx->fwcfg).thrdata.msgq, buf, strlen(buf)+1, 1) == -1 ) {
+ eurephia_log(ctx, LOG_ERROR, 0, "Could not request firewall initialisation of the %s chain: %s",
+ fwdest, strerror(errno));
+ };
+}
+
+void eFW_StopFirewall(eurephiaCTX *ctx) {
+ char buf[520], *fwdest = NULL;
+ int childret = -1;
+
+ if( ctx->fwcfg == NULL ) {
+ return;
+ }
+
+ eurephia_log(ctx, LOG_INFO, 2, "Stopping eurephia firewall interface");
+
+ // Flush the firewall chain before shutting down, to make sure
+ // we don't unintentionally some accesses open
+ fwdest = eGet_value(ctx->dbc->config, "firewall_destination");
+ if( fwdest != NULL ) {
+ memset(&buf, 0, 520);
+ snprintf(buf, 512, "F %s", fwdest);
+ if( mq_send((*ctx->fwcfg).thrdata.msgq, buf, strlen(buf)+1, 1) == -1 ) {
+ eurephia_log(ctx, LOG_CRITICAL, 0,
+ "Could not request firewall flushing of the %s chain: %s",
+ fwdest, strerror(errno));
+ };
+ } else {
+ eurephia_log(ctx, LOG_CRITICAL, 0, "firewall_destination not set in config. Will not flush "
+ "firewall before shutting down the firewall interface.");
+ }
+
+
+ // Send shutdown message to the firewall module process
+ memset(&buf, 0, 520);
+ snprintf(buf, 512, "FWSHUTDOWN%c", 0);
+ if( mq_send((*ctx->fwcfg).thrdata.msgq, buf, 11, 1) == -1 ) {
+ eurephia_log(ctx, LOG_PANIC, 0, "Could not initiate shutdown on eFW module: %s", strerror(errno));
+ kill(ctx->fwcfg->fwproc_pid, SIGABRT);
+ }
+
+ // Wait for the firewall module process to finish
+ if( waitpid(ctx->fwcfg->fwproc_pid, &childret, 0) != ctx->fwcfg->fwproc_pid ) {
+ eurephia_log(ctx, LOG_PANIC, 0, "Failed to wait for eFW module process to quit: %s",
+ strerror(errno));
+ kill(ctx->fwcfg->fwproc_pid, SIGABRT);
+ }
+
+ free_nullsafe((*ctx->fwcfg).thrdata.fw_command);
+ free_nullsafe(ctx->fwcfg);
+ eurephia_log(ctx, LOG_INFO, 2, "eurephia firewall interface is stopped");
+}
+
+
+int eFW_UpdateFirewall(eurephiaCTX *ctx, int mode,
+ const char *macaddr, const char *fwdest, const char *fwprofile) {
+ char buf[1026];
+
+ if( (*ctx->fwcfg).thrdata.fw_command == NULL ) {
+ eurephia_log(ctx, LOG_FATAL, 0, "Function call: eFW_UpdateFirewall() -- "
+ "firewall_command is not configured. Firewall rules was not updated.");
+ return 0;
+ }
+
+ memset(&buf, 0, 1026);
+ switch( mode ) {
+ case FWRULE_ADD:
+ eurephia_log(ctx, LOG_INFO, 3, "Function call: eFW_UpdateFirewall(ctx, %s, '%s', '%s', '%s')",
+ "ADD", macaddr, fwdest, fwprofile);
+ snprintf(buf, 1024, "A %s %s %s", macaddr, fwdest, fwprofile);
+ mq_send((*ctx->fwcfg).thrdata.msgq, buf, strlen(buf)+1, 1);
+ return 1;
+
+ case FWRULE_DELETE:
+ eurephia_log(ctx, LOG_INFO, 3, "Function call: eFW_UpdateFirewall(ctx, %s, '%s', '%s', '%s')",
+ "DELETE", macaddr, fwdest, fwprofile);
+ snprintf(buf, 1024, "D %s %s %s", macaddr, fwdest, fwprofile);
+ mq_send((*ctx->fwcfg).thrdata.msgq, buf, strlen(buf)+1, 1);
+ return 1;
+
+ default:
+ eurephia_log(ctx, LOG_CRITICAL, 0,
+ "Function call: eFW_UpdateFirewall(ctx, %s, '%s') - UNKNOWN MODE", "(unknown)",
+ macaddr);
+ return 0;
+ }
+}
diff --git a/plugin/firewall/eurephiafw.h b/plugin/firewall/eurephiafw.h
new file mode 100644
index 0000000..0c82b30
--- /dev/null
+++ b/plugin/firewall/eurephiafw.h
@@ -0,0 +1,34 @@
+/* eurephiafw.h -- Firewall interface loader for the eurephia module
+ *
+ * GPLv2 - Copyright (C) 2008 David Sommerseth <dazo@users.sourceforge.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2
+ * of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef EUREPHIAFW_H_
+#define EUREPHIAFW_H_
+
+#define FWRULE_ADD 0x101
+#define FWRULE_DELETE 0x102
+
+int eFW_load(eurephiaCTX *ctx, const char *intf);
+int eFW_unload(eurephiaCTX *ctx);
+
+void eFW_StartFirewall(eurephiaCTX *ctx);
+void eFW_StopFirewall(eurephiaCTX *ctx);
+int eFW_UpdateFirewall(eurephiaCTX *ctx, int mode, const char *macaddr, const char *fwdest, const char *fwprofile);
+
+#endif /* !EUREPHIAFW_H_ */
diff --git a/plugin/firewall/eurephiafw_helpers.c b/plugin/firewall/eurephiafw_helpers.c
new file mode 100644
index 0000000..ceb6d25
--- /dev/null
+++ b/plugin/firewall/eurephiafw_helpers.c
@@ -0,0 +1,97 @@
+/* eurephiafw_helpers.c -- Helper functions, shared between main module and
+ * firewall module. Setting up Posix MQ and semaphores
+ *
+ * GPLv2 - Copyright (C) 2008 David Sommerseth <dazo@users.sourceforge.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2
+ * of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <signal.h>
+#include <unistd.h>
+#include <semaphore.h>
+#include <mqueue.h>
+
+#include "eurephia_struct.h"
+#include "eurephia_log.h"
+#include "eurephiafw.h"
+#include "eurephiafw_helpers.h"
+
+
+int efwSetupSemaphores(eurephiaCTX *ctx, efw_threaddata *cfg) {
+ // Initialise the main process' semaphore
+ cfg->semp_master = sem_open(SEMPH_MASTER, O_CREAT, 0666, 0);
+ if( cfg->semp_master == SEM_FAILED ) {
+ eurephia_log(ctx, LOG_FATAL, 0, "Could not setup semaphore for eFW master: %s", strerror(errno));
+ return 0;
+ }
+
+ // Initialise the worker process' semaphore
+ cfg->semp_worker = sem_open(SEMPH_WORKER, O_CREAT, 0666, 0);
+ if( cfg->semp_worker == SEM_FAILED ) {
+ eurephia_log(ctx, LOG_FATAL, 0, "Could not setup semaphore for eFW worker: %s", strerror(errno));
+ return 0;
+ }
+ return 1;
+}
+
+int efwRemoveSemaphores(eurephiaCTX *ctx, efw_threaddata *cfg) {
+ if( sem_close(cfg->semp_worker) != 0 ) {
+ eurephia_log(ctx, LOG_WARNING, 0,
+ "eFW: Could not destroy semaphore for worker: %s", strerror(errno));
+ }
+ sem_unlink(SEMPH_WORKER);
+
+ if( sem_close(cfg->semp_master) != 0 ) {
+ eurephia_log(ctx, LOG_WARNING, 0,
+ "eFW: Could not destroy semaphore for master: %s", strerror(errno));
+ }
+ sem_unlink(SEMPH_MASTER);
+ return 1;
+}
+
+int efwSetupMessageQueue(eurephiaCTX *ctx, efw_threaddata *cfg) {
+ struct mq_attr mqattr;
+
+ // Prepare a POSIX Message Queue
+ mqattr.mq_maxmsg = 10;
+ mqattr.mq_msgsize = EFW_MSG_SIZE;
+ mqattr.mq_flags = 0;
+ cfg->msgq = mq_open(MQUEUE_NAME, O_RDWR | O_CREAT, 0600, &mqattr);
+ if( cfg->msgq < 0 ) {
+ eurephia_log(ctx, LOG_FATAL, 0, "Could not open message queue: %s", strerror(errno));
+ return 0;
+ }
+ return 1;
+}
+
+int efwRemoveMessageQueue(eurephiaCTX *ctx, efw_threaddata *cfg) {
+ // Close and remove the message queue used
+ if( mq_close((*cfg).msgq) != 0 ) {
+ eurephia_log(ctx, LOG_WARNING, 0, "Could not do close the message queue used for eFW: %s",
+ strerror(errno));
+ }
+
+ if( mq_unlink(MQUEUE_NAME) != 0 ) {
+ eurephia_log(ctx, LOG_WARNING, 0, "Could not do close the message queue used for eFW: %s",
+ strerror(errno));
+ }
+ return 1;
+}
+
diff --git a/plugin/firewall/eurephiafw_helpers.h b/plugin/firewall/eurephiafw_helpers.h
new file mode 100644
index 0000000..9c21a2f
--- /dev/null
+++ b/plugin/firewall/eurephiafw_helpers.h
@@ -0,0 +1,36 @@
+/* eurephiafw_helpers.h -- Helper functions, shared between main module and
+ * firewall module. Setting up Posix MQ and semaphores
+ *
+ * GPLv2 - Copyright (C) 2008 David Sommerseth <dazo@users.sourceforge.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2
+ * of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef EUREPHIAFW_HELPERS_H_
+#define EUREPHIAFW_HELPERS_H_
+
+#define EFW_MSG_SIZE 1024
+#define MQUEUE_NAME "/eurephiaFW"
+#define SEMPH_MASTER "eurephiafw_master"
+#define SEMPH_WORKER "eurephiafw_worker"
+
+int efwSetupSemaphores(eurephiaCTX *, efw_threaddata *);
+int efwRemoveSemaphores(eurephiaCTX *, efw_threaddata *);
+
+int efwSetupMessageQueue(eurephiaCTX *, efw_threaddata *);
+int efwRemoveMessageQueue(eurephiaCTX *, efw_threaddata *);
+
+#endif /* !EUREPHIAFW_HELPERS_H_ */
diff --git a/plugin/firewall/eurephiafw_intf.h b/plugin/firewall/eurephiafw_intf.h
new file mode 100644
index 0000000..0f18cc2
--- /dev/null
+++ b/plugin/firewall/eurephiafw_intf.h
@@ -0,0 +1,30 @@
+/* eurephiafw_intf.h --
+ *
+ * GPLv2 - Copyright (C) 2008 David Sommerseth <dazo@users.sourceforge.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2
+ * of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef EUREPHIAFW_INTF_H_
+#define EUREPHIAFW_INTF_H_
+
+// Mandatory functions for all FW interfaces
+const char *(*eFWinterfaceVersion) (void);
+int (*eFWinterfaceAPIversion) (void);
+
+void (*eFW_RunFirewall) (void *);
+
+#endif /* !EUREPHIAFW_INTF_H_ */
diff --git a/plugin/firewall/iptables/CMakeLists.txt b/plugin/firewall/iptables/CMakeLists.txt
new file mode 100644
index 0000000..0f77a1b
--- /dev/null
+++ b/plugin/firewall/iptables/CMakeLists.txt
@@ -0,0 +1,12 @@
+PROJECT(eurephiafw-iptables C)
+cmake_minimum_required(VERSION 2.6)
+SET(efw_ipt_SRC
+ efw_iptables.c
+ ../eurephiafw_helpers.c
+ ../../../common/eurephia_log.c
+)
+
+INCLUDE_DIRECTORIES(BEFORE ../..)
+ADD_LIBRARY(efw_iptables MODULE ${efw_ipt_SRC})
+TARGET_LINK_LIBRARIES(efw_iptables pthread rt gcc_s)
+SET_TARGET_PROPERTIES(efw_iptables PROPERTIES PREFIX "")
diff --git a/plugin/firewall/iptables/efw_iptables.c b/plugin/firewall/iptables/efw_iptables.c
new file mode 100644
index 0000000..9e0aaa4
--- /dev/null
+++ b/plugin/firewall/iptables/efw_iptables.c
@@ -0,0 +1,234 @@
+/* efw_iptables.c -- iptables implementation - updates Linux iptables
+ *
+ * GPLv2 - Copyright (C) 2008 David Sommerseth <dazo@users.sourceforge.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2
+ * of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <eurephia_nullsafe.h>
+#include <eurephia_log.h>
+#include <eurephia_struct.h>
+#include <eurephiafw_helpers.h>
+
+#define INTERFACEVER "1.0"
+#define INTERFACEAPIVER 1
+
+
+const char *eFWinterfaceVersion() {
+ return "eFW-iptables (v"INTERFACEVER") David Sommerseth 2008 (C) GPLv2";
+}
+
+int eFWinterfaceAPIversion() {
+ return INTERFACEAPIVER;
+}
+
+
+int process_input(eurephiaCTX *ctx, const char *fwcmd, const char *msg);
+int call_iptables(eurephiaCTX *ctx, const char *fwcmd, char **ipt_args);
+
+void eFW_RunFirewall(void *fwargs) {
+ efw_threaddata *cfg = (efw_threaddata *) fwargs;
+ eurephiaCTX *ctx = (eurephiaCTX *) cfg->ctx;
+ int quit = 0;
+ unsigned int prio;
+ char buf[EFW_MSG_SIZE+2];
+
+ DEBUG(ctx, 28, "eFW_RunFirewall: Waiting for eFW master to get ready");
+ sem_wait(cfg->semp_master);
+ DEBUG(ctx, 28, "eFW_RunFirewall: Telling eFW master that the worker process is ready");
+ sem_post(cfg->semp_worker);
+
+ if( cfg->fw_command == NULL ) {
+ eurephia_log(ctx, LOG_FATAL, 0,
+ "eFW_RunFirewall: firewall_command is not configured. "
+ "iptables will not be updated.");
+ exit(3);
+ }
+
+ // Main loop ... grab messages of the messague queue until shutdown command is sent, or a failure happens
+ while( quit == 0 ) {
+ memset(buf, 0, EFW_MSG_SIZE+2);
+ if( mq_receive(cfg->msgq, &buf[0], EFW_MSG_SIZE, &prio) == -1 ) {
+ eurephia_log(ctx, LOG_FATAL, 0,
+ "eFW_RunFirewall: Error while reading messages from queue: %s",
+ strerror(errno));
+ exit(2);
+ }
+ quit = (strncmp(buf, "FWSHUTDOWN", 10) == 0 );
+ if( !quit ) {
+ int res = 0;
+
+ DEBUG(ctx, 20, "eFW_RunFirewall: Received '%s'", buf);
+
+ res = process_input(ctx, cfg->fw_command, buf);
+ if( ! res ) {
+ quit = 1;
+ eurephia_log(ctx, LOG_FATAL, 0,
+ "eFW_RunFirewall: Failed updating iptables");
+ }
+ }
+ }
+
+ efwRemoveSemaphores(ctx, fwargs);
+ efwRemoveMessageQueue(ctx, fwargs);
+ exit(0);
+}
+
+
+int process_input(eurephiaCTX *ctx, const char *fwcmd, const char *input) {
+ char mode[3], *macaddr = NULL, *destchain = NULL, *jump = NULL;
+ char *msg = NULL, *orig_msg = NULL;
+ char *iptables_args[] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
+ int ret = 0;
+
+ orig_msg = strdup_nullsafe(input);
+ msg = orig_msg;
+ DEBUG(ctx, 36, "eFW_RunFirewall::process_input(ctx, '%s')", msg);
+
+ //
+ // Simple parsing of the input string
+ //
+ mode[0] = '-';
+ mode[1] = *msg;
+ mode[2] = 0;
+ msg += 2;
+
+ iptables_args[0] = (char *)fwcmd;
+
+ switch( mode[1] ) {
+ case 'A':
+ case 'D':
+ iptables_args[1] = mode;
+ macaddr = msg; // start of string for macaddr
+
+ // Search for end of macaddr and NULL terminate it
+ destchain = macaddr+1;
+ while( (*destchain != 0x20) || (*destchain == 0) ) {
+ destchain++;
+ }
+ if( *destchain == 0 ) {
+ return 0;
+ }
+ *destchain = 0; // end of string for macaddr
+ destchain++; // start of string for destchain
+ // Search for end of destchain and NULL terminate it
+ jump = destchain+1;
+ while( (*jump != 0x20) || (*jump == 0) ) {
+ jump++;
+ }
+ *jump = 0; // end of string for destchain
+ jump++; // start of string for jump
+
+ // Prepare iptables arguments
+ iptables_args[2] = destchain;
+ iptables_args[3] = "-m\0";
+ iptables_args[4] = "mac\0";
+ iptables_args[5] = "--mac-source\0";
+ iptables_args[6] = macaddr;
+ iptables_args[7] = "-m\0";
+ iptables_args[8] = "state\0";
+ iptables_args[9] = "--state\0";
+ iptables_args[10] = "NEW\0";
+ iptables_args[11] = "-j\0";
+ iptables_args[12] = jump;
+ iptables_args[13] = NULL;
+
+ eurephia_log(ctx, LOG_INFO, 3, "eFW_RunFirewall - updating iptables rules "
+ "==> mode: %s macaddr: '%s' destchain: '%s' jump: '%s'",
+ (mode[1] == 'A' ? "ADD":"DELETE"), macaddr, destchain, jump);
+ ret = call_iptables(ctx, fwcmd, iptables_args);
+ break;
+
+ case 'F':
+ iptables_args[1] = mode;
+ destchain = msg;
+ iptables_args[2] = destchain;
+ iptables_args[3] = NULL;
+ eurephia_log(ctx, LOG_INFO, 3, "eFW_RunFirewall - updating iptables rules "
+ "==> mode: FLUSH destchain: '%s'", destchain);
+ ret = call_iptables(ctx, fwcmd, iptables_args);
+ break;
+
+ case 'I':
+ // Init chain - flush it and then add needed rule for stateful inspection
+ destchain = msg;
+
+ eurephia_log(ctx, LOG_INFO, 3, "eFW_RunFirewall - Initialising iptables chain '%s'",
+ destchain);
+
+ // Flush phase
+ iptables_args[1] = "-F";
+ destchain = msg;
+ iptables_args[2] = destchain;
+ iptables_args[3] = NULL;
+ ret = call_iptables(ctx, fwcmd, iptables_args);
+
+ // Add stateful inspection
+ iptables_args[1] = "-I\0";
+ iptables_args[2] = destchain;
+ iptables_args[3] = "-m\0";
+ iptables_args[4] = "state\0";
+ iptables_args[5] = "--state\0";
+ iptables_args[6] = "ESTABLISHED,RELATED\0";
+ iptables_args[7] = "-j\0";
+ iptables_args[8] = "ACCEPT\0";
+ ret &= call_iptables(ctx, fwcmd, iptables_args);
+ break;
+
+ default:
+ eurephia_log(ctx, LOG_CRITICAL, 0, "eFW_RunFirewall::process_input: Malformed update request");
+ ret = 1;
+ }
+ free_nullsafe(orig_msg);
+ return ret;
+}
+
+int call_iptables(eurephiaCTX *ctx, const char *fwcmd, char **ipt_args) {
+ pid_t pid;
+ int cmdret = -1;
+
+ // Fork out a child process which will run the iptables command. Since the execve replaces
+ // the current process, we need to do the forking first.
+ if( (pid = fork()) < 0) {
+ eurephia_log(ctx, LOG_FATAL, 0,
+ "eFW_RunFirewall::process_input: Failed to fork process for %s", fwcmd);
+ return 0;
+ }
+
+ switch( pid ) {
+ case 0: // child process - execute the program and exit
+ execve(fwcmd, ipt_args, NULL);
+ exit(1); // execve should replace the process, but if it fails to do so, make sure we exit
+
+ default: // parent process
+ if( waitpid(pid, &cmdret, 0) != pid ) {
+ eurephia_log(ctx, LOG_WARNING, 0,
+ "eFW_RunFirewall::process_input: Failed to wait for process for %s"
+ " to complete (%s)", fwcmd, strerror(errno));
+ }
+ eurephia_log(ctx, LOG_INFO, 4, "eFW_RunFirewall - iptables exited with code: %i ", cmdret);
+ }
+ return 1;
+}