summaryrefslogtreecommitdiffstats
path: root/ebtablesd.c
diff options
context:
space:
mode:
Diffstat (limited to 'ebtablesd.c')
-rw-r--r--ebtablesd.c367
1 files changed, 367 insertions, 0 deletions
diff --git a/ebtablesd.c b/ebtablesd.c
new file mode 100644
index 0000000..1f60791
--- /dev/null
+++ b/ebtablesd.c
@@ -0,0 +1,367 @@
+/*
+ * ebtablesd.c, January 2005
+ *
+ * Author: Bart De Schuymer
+ *
+ * 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; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <fcntl.h>
+#include <errno.h>
+#include "include/ebtables_u.h"
+
+#define OPT_KERNELDATA 0x800 /* Also defined in ebtables.c */
+
+static struct ebt_u_replace replace[3];
+#define OPEN_METHOD_FILE 1
+#define OPEN_METHOD_KERNEL 2
+static int open_method[3];
+void ebt_early_init_once();
+
+static void sigpipe_handler(int sig)
+{
+}
+
+int main(int argc_, char *argv_[])
+{
+ char *argv[EBTD_ARGC_MAX], *args[4], name[] = "mkdir",
+ mkdir_option[] = "-p", mkdir_dir[] = EBTD_PIPE_DIR,
+ cmdline[EBTD_CMDLINE_MAXLN];
+ int readfd, stop = 0, base = 0, offset = 0, n = 0, ret = 0;
+
+ /* Make sure the pipe directory exists */
+ args[0] = name;
+ args[1] = mkdir_option;
+ args[2] = mkdir_dir;
+ args[3] = NULL;
+ switch (fork()) {
+ case 0:
+ execvp(args[0], args);
+
+ /* Not usually reached */
+ exit(0);
+ case -1:
+ return -1;
+
+ default: /* Parent */
+ wait(NULL);
+ }
+
+ if (mkfifo(EBTD_PIPE, 0600) < 0 && errno != EEXIST) {
+ printf("Error creating FIFO " EBTD_PIPE "\n");
+ ret = -1;
+ goto do_exit;
+ }
+
+ if ((readfd = open(EBTD_PIPE, O_RDONLY | O_NONBLOCK, 0)) == -1) {
+ perror("open");
+ ret = -1;
+ goto do_exit;
+ }
+
+ if (signal(SIGPIPE, sigpipe_handler) == SIG_ERR) {
+ perror("signal");
+ ret = -1;
+ goto do_exit;
+ }
+
+ ebt_silent = 1;
+
+ strcpy(replace[0].name, "filter");
+ strcpy(replace[1].name, "nat");
+ strcpy(replace[2].name, "broute");
+
+ ebt_early_init_once();
+
+ while (!stop) {
+ int n2, i, argc, table_nr, ntot;
+
+ /* base == 0 */
+ ntot = read(readfd, cmdline+offset, EBTD_CMDLINE_MAXLN-offset-1);
+ if (ntot <= 0)
+ continue;
+ ntot += offset;
+continue_read:
+ /* Change all ' ' into '\0'. This implies that the user is not
+ * allowed to use spaces (that don't distinguish options or
+ * commands) in her rules. This comes down to not allowing spaces
+ * in options like the string of --ulog-prefix (use '_' instead).
+ */
+ for (; offset < ntot; n++, offset++) {
+ if (cmdline[offset] == ' ')
+ cmdline[offset] = '\0';
+ if (cmdline[offset] == '\n') {
+ cmdline[offset] = '\0';
+ break;
+ }
+ }
+ if (n == 0) {
+ if (offset == ntot) {
+ /* The ntot bytes were parsed and ended with '\n' */
+ base = 0;
+ offset = 0;
+ continue;
+ }
+ offset++;
+ base = offset;
+ n = 0;
+ goto continue_read;
+ }
+ if (offset == ntot) { /* The ntot bytes were parsed but no complete rule is yet specified */
+ if (base == 0) {
+ ebt_print_error("ebtablesd: the maximum command line length is %d", EBTD_CMDLINE_MAXLN-1);
+ goto write_msg;
+ }
+ memmove(cmdline, cmdline+base+offset, ntot-offset);
+ offset -= base;
+ offset++;
+ base = 0;
+ continue;
+ }
+
+ table_nr = 0;
+ n2 = 0;
+ argc = 0;
+ while (n2 < n && argc < EBTD_ARGC_MAX) {
+ argv[argc++] = cmdline + base + n2;
+ n2 += strlen(cmdline + base + n2) + 1;
+ }
+ offset++; /* Move past the '\n' */
+ base = offset;
+
+ if (argc > EBTD_ARGC_MAX) {
+ ebt_print_error("ebtablesd: maximum %d arguments "
+ "allowed", EBTD_ARGC_MAX - 1);
+ goto write_msg;
+ }
+ if (argc == 1) {
+ ebt_print_error("ebtablesd: no arguments");
+ goto write_msg;
+ }
+
+ /* Parse the options */
+ if (!strcmp(argv[1], "-t")) {
+ if (argc < 3) {
+ ebt_print_error("ebtablesd: -t but no table");
+ goto write_msg;
+ }
+ for (i = 0; i < 3; i++)
+ if (!strcmp(replace[i].name, argv[2]))
+ break;
+ if (i == 3) {
+ ebt_print_error("ebtablesd: table '%s' was "
+ "not recognized", argv[2]);
+ goto write_msg;
+ }
+ table_nr = i;
+ } else if (!strcmp(argv[1], "free")) {
+ if (argc != 3) {
+ ebt_print_error("ebtablesd: command free "
+ "needs exactly one argument");
+ goto write_msg;
+ }
+ for (i = 0; i < 3; i++)
+ if (!strcmp(replace[i].name, argv[2]))
+ break;
+ if (i == 3) {
+ ebt_print_error("ebtablesd: table '%s' was "
+ "not recognized", argv[2]);
+ goto write_msg;
+ }
+ if (!(replace[i].flags & OPT_KERNELDATA)) {
+ ebt_print_error("ebtablesd: table %s has not "
+ "been opened");
+ goto write_msg;
+ }
+ ebt_cleanup_replace(&replace[i]);
+ replace[i].flags &= ~OPT_KERNELDATA;
+ goto write_msg;
+ } else if (!strcmp(argv[1], "open")) {
+ if (argc != 3) {
+ ebt_print_error("ebtablesd: command open "
+ "needs exactly one argument");
+ goto write_msg;
+ }
+
+ for (i = 0; i < 3; i++)
+ if (!strcmp(replace[i].name, argv[2]))
+ break;
+ if (i == 3) {
+ ebt_print_error("ebtablesd: table '%s' was "
+ "not recognized", argv[2]);
+ goto write_msg;
+ }
+ if (replace[i].flags & OPT_KERNELDATA) {
+ ebt_print_error("ebtablesd: table %s needs to "
+ "be freed before it can be "
+ "opened");
+ goto write_msg;
+ }
+ if (!ebt_get_kernel_table(&replace[i], 0)) {
+ replace[i].flags |= OPT_KERNELDATA;
+ open_method[i] = OPEN_METHOD_KERNEL;
+ }
+ goto write_msg;
+ } else if (!strcmp(argv[1], "fopen")) {
+ struct ebt_u_replace tmp;
+
+ memset(&tmp, 0, sizeof(tmp));
+ if (argc != 4) {
+ ebt_print_error("ebtablesd: command fopen "
+ "needs exactly two arguments");
+ goto write_msg;
+ }
+
+ for (i = 0; i < 3; i++)
+ if (!strcmp(replace[i].name, argv[2]))
+ break;
+ if (i == 3) {
+ ebt_print_error("ebtablesd: table '%s' was "
+ "not recognized", argv[2]);
+ goto write_msg;
+ }
+ if (replace[i].flags & OPT_KERNELDATA) {
+ ebt_print_error("ebtablesd: table %s needs to "
+ "be freed before it can be "
+ "opened");
+ goto write_msg;
+ }
+ tmp.filename = (char *)malloc(strlen(argv[3]) + 1);
+ if (!tmp.filename) {
+ ebt_print_error("Out of memory");
+ goto write_msg;
+ }
+ strcpy(tmp.filename, argv[3]);
+ strcpy(tmp.name, "filter");
+ tmp.command = 'L'; /* Make sure retrieve_from_file()
+ * doesn't complain about wrong
+ * table name */
+
+ ebt_get_kernel_table(&tmp, 0);
+ free(tmp.filename);
+ tmp.filename = NULL;
+ if (ebt_errormsg[0] != '\0')
+ goto write_msg;
+
+ if (strcmp(tmp.name, argv[2])) {
+ ebt_print_error("ebtablesd: opened file with "
+ "wrong table name '%s'", tmp.name);
+ ebt_cleanup_replace(&tmp);
+ goto write_msg;
+ }
+ replace[i] = tmp;
+ replace[i].command = '\0';
+ replace[i].flags |= OPT_KERNELDATA;
+ open_method[i] = OPEN_METHOD_FILE;
+ goto write_msg;
+ } else if (!strcmp(argv[1], "commit")) {
+ if (argc != 3) {
+ ebt_print_error("ebtablesd: command commit "
+ "needs exactly one argument");
+ goto write_msg;
+ }
+
+ for (i = 0; i < 3; i++)
+ if (!strcmp(replace[i].name, argv[2]))
+ break;
+ if (i == 3) {
+ ebt_print_error("ebtablesd: table '%s' was "
+ "not recognized", argv[2]);
+ goto write_msg;
+ }
+ if (!(replace[i].flags & OPT_KERNELDATA)) {
+ ebt_print_error("ebtablesd: table %s has not "
+ "been opened");
+ goto write_msg;
+ }
+ /* The counters from the kernel are useless if we
+ * didn't start from a kernel table */
+ if (open_method[i] == OPEN_METHOD_FILE)
+ replace[i].num_counters = 0;
+ ebt_deliver_table(&replace[i]);
+ if (ebt_errormsg[0] == '\0' && open_method[i] == OPEN_METHOD_KERNEL)
+ ebt_deliver_counters(&replace[i], EXEC_STYLE_DAEMON);
+ goto write_msg;
+ } else if (!strcmp(argv[1], "fcommit")) {
+ if (argc != 4) {
+ ebt_print_error("ebtablesd: command commit "
+ "needs exactly two argument");
+ goto write_msg;
+ }
+
+ for (i = 0; i < 3; i++)
+ if (!strcmp(replace[i].name, argv[2]))
+ break;
+ if (i == 3) {
+ ebt_print_error("ebtablesd: table '%s' was "
+ "not recognized", argv[2]);
+ goto write_msg;
+ }
+ if (!(replace[i].flags & OPT_KERNELDATA)) {
+ ebt_print_error("ebtablesd: table %s has not "
+ "been opened");
+ goto write_msg;
+ }
+ replace[i].filename = (char *)malloc(strlen(argv[3]) + 1);
+ if (!replace[i].filename) {
+ ebt_print_error("Out of memory");
+ goto write_msg;
+ }
+ strcpy(replace[i].filename, argv[3]);
+ ebt_deliver_table(&replace[i]);
+ if (ebt_errormsg[0] == '\0' && open_method[i] == OPEN_METHOD_KERNEL)
+ ebt_deliver_counters(&replace[i], EXEC_STYLE_DAEMON);
+ free(replace[i].filename);
+ replace[i].filename = NULL;
+ goto write_msg;
+ }else if (!strcmp(argv[1], "quit")) {
+ if (argc != 2) {
+ ebt_print_error("ebtablesd: command quit does "
+ "not take any arguments");
+ goto write_msg;
+ }
+ stop = 1;
+ goto write_msg;
+ }
+ if (!(replace[table_nr].flags & OPT_KERNELDATA)) {
+ ebt_print_error("ebtablesd: table %s has not been "
+ "opened", replace[table_nr].name);
+ goto write_msg;
+ }
+ optind = 1;
+printf("jak: ntot = %d, offset = %d, base = %d\n", ntot, offset, base);
+ do_command(argc, argv, EXEC_STYLE_DAEMON, &replace[table_nr]);
+ ebt_reinit_extensions();
+write_msg:
+#ifndef SILENT_DAEMON
+ if (ebt_errormsg[0] != '\0')
+ printf("%s\n", ebt_errormsg);
+#endif
+ ebt_errormsg[0]= '\0';
+ n = 0;
+ goto continue_read;
+ }
+do_exit:
+ unlink(EBTD_PIPE);
+
+ return 0;
+}