add ebtablesu scheme, along with general cleanup
authorBart De Schuymer <bdschuym@pandora.be>
Wed, 19 Jan 2005 21:09:05 +0000 (21:09 +0000)
committerBart De Schuymer <bdschuym@pandora.be>
Wed, 19 Jan 2005 21:09:05 +0000 (21:09 +0000)
14 files changed:
ChangeLog
INSTALL
Makefile
communication.c
ebtables-standalone.c [new file with mode: 0644]
ebtables.8
ebtables.c
ebtablesd.c [new file with mode: 0644]
ebtablesu.c [new file with mode: 0644]
extensions/ebt_ip.c
extensions/ebt_limit.c
extensions/ebt_vlan.c
include/ebtables_u.h
libebtc.c

index d52160e..af1fe66 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+20051701
+       Since last entry:
+       * added ulog watcher
+       * made the ebtables code modular (make library functions).
+       * added the ebtablesd/ebtablesu scheme to allow faster
+         addition of rules (and to test the modular code).
+       * some small fixes
 20031102
        Since last entry:
        * <grzes_at_gnu.univ.gda.pl> added arpreply and among modules
diff --git a/INSTALL b/INSTALL
index 2d1e42f..371cbe4 100644 (file)
--- a/INSTALL
+++ b/INSTALL
@@ -17,9 +17,13 @@ WHAT GETS INSTALLED?
   The Makefile will append /man8/ebtables.8.
 - ethertypes is by default placed in /etc/, if you
   want to change this, include ETHERTYPESPATH=<<path>>.
-- the userspace program ebtables is compiled and the executable is copied
-  by default to /usr/sbin/ebtables. If you want to put the executable
-  somewhere else, include BINPATH=<<path>>.
+- The pipe used for communication by ebtablesd and ebtablesu is by
+  default the file /etc/ebtables-v$(PROGVERSION)/ebtablesd_pipe. To
+  change the directory, include PIPE_DIR=<<dir>>. There is no option
+  to change the name of the pipe.
+- the userspace programs ebtables ebtablesu and ebtablesd are compiled and
+  the executables are copied by default to /usr/sbin/ebtables. If you want
+  to put the executables somewhere else, include BINPATH=<<path>>.
 
 That's all
 
index e519c4e..671de96 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -38,15 +38,30 @@ KERNEL_INCLUDES?=include/
 ETHERTYPESPATH?=$(ETCDIR)
 ETHERTYPESFILE:=$(ETHERTYPESPATH)/ethertypes
 
-BINFILE:=$(BINDIR)/ebtables
+PIPE_DIR?=.
+PIPE=$(PIPE_DIR)/ebtablesd_pipe
+EBTD_CMDLINE_MAXLN?=2048
+EBTD_ARGC_MAX?=50
+
+BINFILE_EBT:=$(BINDIR)/$(PROGNAME)
+BINFILE_EBTD:=$(BINDIR)/$(PROGNAME)d
+BINFILE_EBTU:=$(BINDIR)/$(PROGNAME)u
 
 PROGSPECS:=-DPROGVERSION=\"$(PROGVERSION)\" \
        -DPROGNAME=\"$(PROGNAME)\" \
        -DPROGDATE=\"$(PROGDATE)\" \
        -D_PATH_ETHERTYPES=\"$(ETHERTYPESFILE)\"
 
+PROGSPECSD:=-DPROGVERSION=\"$(PROGVERSION)\" \
+       -DPROGNAME=\"$(PROGNAME)\" \
+       -DPROGDATE=\"$(PROGDATE)\" \
+       -D_PATH_ETHERTYPES=\"$(ETHERTYPESFILE)\" \
+       -DEBTD_CMDLINE_MAXLN=$(EBTD_CMDLINE_MAXLN) \
+       -DEBTD_ARGC_MAX=$(EBTD_ARGC_MAX) \
+       -DEBTD_PIPE=\"$(PIPE)\" \
+       -DEBTD_PIPE_DIR=\"$(PIPE_DIR)\"
 
-all: ebtables
+all: ebtables daemon
 
 communication.o: communication.c include/ebtables_u.h
        $(CC) $(CFLAGS) $(PROGSPECS) -c -o $@ $< -I$(KERNEL_INCLUDES)
@@ -63,11 +78,28 @@ getethertype.o: getethertype.c include/ethernetdb.h
 ebtables.o: ebtables.c include/ebtables_u.h
        $(CC) $(CFLAGS) $(PROGSPECS) -c -o $@ $< -I$(KERNEL_INCLUDES)
 
-ebtables: $(OBJECTS)
+ebtables-standalone.o: ebtables-standalone.c ebtables.c include/ebtables_u.h
+       $(CC) $(CFLAGS) $(PROGSPECS) -c $< ebtables.c -o $@ -I$(KERNEL_INCLUDES)
+
+ebtables: $(OBJECTS) ebtables-standalone.o
        $(LD) -shared -soname libebtc.so -o libebtc.so -lc $(OBJECTS2)
-       $(CC) $(CFLAGS) -o $@ ebtables.o -I$(KERNEL_INCLUDES) -L/root/ \
+       $(CC) $(CFLAGS) -o $@ ebtables-standalone.o -I$(KERNEL_INCLUDES) -L/root/ \
        -L. -Lextensions/ -lebtc $(EXT_LIBSI)
-       
+
+ebtablesu: ebtablesu.c
+       $(CC) $(CFLAGS) $(PROGSPECSD) $< -o $@
+
+ebtablesd.o: ebtablesd.c ebtables.c include/ebtables_u.h
+       $(CC) $(CFLAGS) $(PROGSPECSD) -c $< ebtables.c -o $@  -I$(KERNEL_INCLUDES)
+
+ebtablesd: $(OBJECTS) ebtablesd.o
+       $(LD) -shared -soname libebtc.so -o libebtc.so -lc $(OBJECTS2)
+       $(CC) $(CFLAGS) -o $@ ebtablesd.o -I$(KERNEL_INCLUDES) -L/root/ \
+       -L. -Lextensions/ -lebtc $(EXT_LIBSI)
+
+.PHONY: daemon
+daemon: ebtablesd ebtablesu
+
 $(MANDIR)/man8/ebtables.8: ebtables.8
        mkdir -p $(@D)
        install -m 0644 -o root -g root $< $@
@@ -77,9 +109,11 @@ $(ETHERTYPESFILE): ethertypes
        install -m 0644 -o root -g root $< $@
 
 .PHONY: exec
-exec: ebtables
+exec: ebtables daemon
        mkdir -p $(BINDIR)
-       install -m 0755 -o root -g root $< $(BINFILE)
+       install -m 0755 -o root -g root $(PROGNAME) $(BINFILE_EBT)
+       install -m 0755 -o root -g root $(PROGNAME)d  $(BINFILE_EBTD)
+       install -m 0755 -o root -g root $(PROGNAME)u $(BINFILE_EBTU)
 
 .PHONY: install
 install: $(MANDIR)/man8/ebtables.8 $(ETHERTYPESFILE) exec
@@ -89,7 +123,7 @@ install: $(MANDIR)/man8/ebtables.8 $(ETHERTYPESFILE) exec
 
 .PHONY: clean
 clean:
-       rm -f ebtables
+       rm -f ebtables ebtablesd ebtablesu
        rm -f *.o *.c~ *.so
        rm -f extensions/*.o extensions/*.c~ extensions/*.so
 
index af00fa2..81fca22 100644 (file)
@@ -31,15 +31,19 @@ extern char* hooknames[NF_BR_NUMHOOKS];
 
 int sockfd = -1;
 
-static void get_sockfd()
+static int get_sockfd()
 {
+       int ret = 0;
        if (sockfd == -1) {
                sockfd = socket(AF_INET, SOCK_RAW, PF_INET);
-               if (sockfd < 0)
+               if (sockfd < 0) {
                        ebt_print_error("Problem getting a socket, "
                                        "you probably don't have the right "
                                        "permissions");
+                       ret = -1;
+               }
        }
+       return ret;
 }
 
 static struct ebt_replace * translate_user2kernel(struct ebt_u_replace *u_repl)
@@ -62,7 +66,7 @@ static struct ebt_replace * translate_user2kernel(struct ebt_u_replace *u_repl)
        new->nentries = u_repl->nentries;
        new->num_counters = u_repl->num_counters;
        new->counters = sparc_cast u_repl->counters;
-       /* determine nr of udc */
+       /* Determine nr of udc */
        i = 0;
        cl = u_repl->udc;
        while (cl) {
@@ -71,7 +75,7 @@ static struct ebt_replace * translate_user2kernel(struct ebt_u_replace *u_repl)
        }
        i += NF_BR_NUMHOOKS;
        chain_offsets = (unsigned int *)malloc(i * sizeof(unsigned int));
-       /* determine size */
+       /* Determine size */
        i = 0;
        cl = u_repl->udc;
        while (1) {
@@ -109,7 +113,7 @@ static struct ebt_replace * translate_user2kernel(struct ebt_u_replace *u_repl)
                           sizeof(struct ebt_entry_target);
                        e = e->next;
                }
-               /* a little sanity check */
+               /* A little sanity check */
                if (j != entries->nentries)
                        ebt_print_bug("Wrong nentries: %d != %d, hook = %s", j,
                           entries->nentries, entries->name);
@@ -123,7 +127,7 @@ static struct ebt_replace * translate_user2kernel(struct ebt_u_replace *u_repl)
        if (!p)
                ebt_print_memory();
 
-       /* put everything in one block */
+       /* Put everything in one block */
        new->entries = sparc_cast p;
        i = 0;
        cl = u_repl->udc;
@@ -147,7 +151,7 @@ static struct ebt_replace * translate_user2kernel(struct ebt_u_replace *u_repl)
                hlp->policy = entries->policy;
                strcpy(hlp->name, entries->name);
                hlp->counter_offset = entries->counter_offset;
-               hlp->distinguisher = 0; /* make the kernel see the light */
+               hlp->distinguisher = 0; /* Make the kernel see the light */
                p += sizeof(struct ebt_entries);
                e = entries->entries;
                while (e) {
@@ -192,7 +196,7 @@ static struct ebt_replace * translate_user2kernel(struct ebt_u_replace *u_repl)
                        if (!strcmp(e->t->u.name, EBT_STANDARD_TARGET)) {
                                struct ebt_standard_target *st =
                                   (struct ebt_standard_target *)p;
-                               /* translate the jump to a udc */
+                               /* Translate the jump to a udc */
                                if (st->verdict >= 0)
                                        st->verdict = chain_offsets
                                           [st->verdict + NF_BR_NUMHOOKS];
@@ -207,7 +211,7 @@ static struct ebt_replace * translate_user2kernel(struct ebt_u_replace *u_repl)
                i++;
        }
 
-       /* sanity check */
+       /* Sanity check */
        if (p - (char *)new->entries != new->entries_size)
                ebt_print_bug("Entries_size bug");
        free(chain_offsets);
@@ -220,19 +224,22 @@ static void store_table_in_file(char *filename, struct ebt_replace *repl)
        int size;
        FILE *file;
 
-       /* start from an empty file with right priviliges */
+       /* Start from an empty file with right priviliges */
        command = (char *)malloc(strlen(filename) + 15);
        if (!command)
                ebt_print_memory();
        strcpy(command, "cat /dev/null>");
        strcpy(command + 14, filename);
-       if (system(command))
+       if (system(command)) {
                ebt_print_error("Couldn't create file %s", filename);
+               goto free_command;
+       }
        strcpy(command, "chmod 600 ");
        strcpy(command + 10, filename);
-       if (system(command))
+       if (system(command)) {
                ebt_print_error("Couldn't chmod file %s", filename);
-       free(command);
+               goto free_command;
+       }
 
        size = sizeof(struct ebt_replace) + repl->entries_size +
           repl->nentries * sizeof(struct ebt_counter);
@@ -242,18 +249,20 @@ static void store_table_in_file(char *filename, struct ebt_replace *repl)
        memcpy(data, repl, sizeof(struct ebt_replace));
        memcpy(data + sizeof(struct ebt_replace), (char *)repl->entries,
           repl->entries_size);
-       /* initialize counters to zero, deliver_counters() can update them */
+       /* Initialize counters to zero, deliver_counters() can update them */
        memset(data + sizeof(struct ebt_replace) + repl->entries_size,
           0, repl->nentries * sizeof(struct ebt_counter));
-       if (!(file = fopen(filename, "wb")))
+       if (!(file = fopen(filename, "wb"))) {
                ebt_print_error("Couldn't open file %s", filename);
-       if (fwrite(data, sizeof(char), size, file) != size) {
-               fclose(file);
+               goto free_data;
+       } else if (fwrite(data, sizeof(char), size, file) != size)
                ebt_print_error("Couldn't write everything to file %s",
                                filename);
-       }
        fclose(file);
+free_data:
        free(data);
+free_command:
+       free(command);
 }
 
 void ebt_deliver_table(struct ebt_u_replace *u_repl)
@@ -261,19 +270,20 @@ void ebt_deliver_table(struct ebt_u_replace *u_repl)
        socklen_t optlen;
        struct ebt_replace *repl;
 
-       /* translate the struct ebt_u_replace to a struct ebt_replace */
+       /* Translate the struct ebt_u_replace to a struct ebt_replace */
        repl = translate_user2kernel(u_repl);
        if (u_repl->filename != NULL) {
                store_table_in_file(u_repl->filename, repl);
                return;
        }
-       /* give the data to the kernel */
+       /* Give the data to the kernel */
        optlen = sizeof(struct ebt_replace) + repl->entries_size;
-       get_sockfd();
+       if (get_sockfd())
+               return;
        if (!setsockopt(sockfd, IPPROTO_IP, EBT_SO_SET_ENTRIES, repl, optlen))
                return;
-       if (u_repl->command == 8) { /* the ebtables module may not
-                                   * yet be loaded with --atomic-commit */
+       if (u_repl->command == 8) { /* The ebtables module may not
+                                    * yet be loaded with --atomic-commit */
                ebtables_insmod("ebtables");
                if (!setsockopt(sockfd, IPPROTO_IP, EBT_SO_SET_ENTRIES,
                    repl, optlen))
@@ -285,41 +295,46 @@ void ebt_deliver_table(struct ebt_u_replace *u_repl)
                    " the extension");
 }
 
-static void store_counters_in_file(char *filename, struct ebt_u_replace *repl)
+static int store_counters_in_file(char *filename, struct ebt_u_replace *repl)
 {
-       int size = repl->nentries * sizeof(struct ebt_counter);
+       int size = repl->nentries * sizeof(struct ebt_counter), ret = 0;
        unsigned int entries_size;
        struct ebt_replace hlp;
        FILE *file;
 
-       if (!(file = fopen(filename, "r+b")))
+       if (!(file = fopen(filename, "r+b"))) {
                ebt_print_error("Could not open file %s", filename);
-       /* 
-        * find out entries_size and then set the file pointer to the
-        * counters
-        */
+               return -1;
+       }
+       /* Find out entries_size and then set the file pointer to the
+        * counters */
        if (fseek(file, (char *)(&hlp.entries_size) - (char *)(&hlp), SEEK_SET)
           || fread(&entries_size, sizeof(char), sizeof(unsigned int), file) !=
           sizeof(unsigned int) ||
           fseek(file, entries_size + sizeof(struct ebt_replace), SEEK_SET)) {
-               fclose(file);
                ebt_print_error("File %s is corrupt", filename);
+               ret = -1;
+               goto close_file;
        }
        if (fwrite(repl->counters, sizeof(char), size, file) != size) {
-               fclose(file);
                ebt_print_error("Could not write everything to file %s",
                                filename);
+               ret = -1;
        }
+close_file:
        fclose(file);
+       return 0;
 }
 
-/* gets executed after ebt_deliver_table */
-void ebt_deliver_counters(struct ebt_u_replace *u_repl)
+/* Gets executed after ebt_deliver_table. Delivers the counters to the kernel
+ * and resets the counterchanges to CNT_NORM */
+void ebt_deliver_counters(struct ebt_u_replace *u_repl, int exec_style)
 {
        struct ebt_counter *old, *new, *newcounters;
        socklen_t optlen;
        struct ebt_replace repl;
-       struct ebt_cntchanges *cc = u_repl->counterchanges;
+       struct ebt_cntchanges *cc = u_repl->counterchanges, *cc2, **cc3;
+       int i;
 
        if (u_repl->nentries == 0)
                return;
@@ -333,24 +348,22 @@ void ebt_deliver_counters(struct ebt_u_replace *u_repl)
        new = newcounters;
        while (cc) {
                if (cc->type == CNT_NORM) {
-                       /*
-                        *'normal' rule, meaning we didn't do anything to it
-                        * So, we just copy
-                        */
+                       /* 'Normal' rule, meaning we didn't do anything to it
+                        * So, we just copy */
                        new->pcnt = old->pcnt;
                        new->bcnt = old->bcnt;
-                       /* we've used an old counter */
+                       /* We've used an old counter */
                        old++;
-                       /* we've set a new counter */
+                       /* We've set a new counter */
                        new++;
                } else if (cc->type == CNT_DEL) {
-                       /* don't use this old counter */
+                       /* Don't use this old counter */
                        old++;
                } else if (cc->type == CNT_ADD) {
-                       /* new counter, let it stay 0 */
+                       /* New counter, let it stay 0 */
                        new++;
                } else {
-                       /* zero it (let it stay 0) */
+                       /* Zero it (let it stay 0) */
                        old++;
                        new++;
                }
@@ -366,20 +379,38 @@ void ebt_deliver_counters(struct ebt_u_replace *u_repl)
        }
        optlen = u_repl->nentries * sizeof(struct ebt_counter) +
           sizeof(struct ebt_replace);
-       /* now put the stuff in the kernel's struct ebt_replace */
+       /* Now put the stuff in the kernel's struct ebt_replace */
        repl.counters = sparc_cast u_repl->counters;
        repl.num_counters = u_repl->num_counters;
        memcpy(repl.name, u_repl->name, sizeof(repl.name));
 
-       get_sockfd();
+       if (get_sockfd())
+               return;
        if (setsockopt(sockfd, IPPROTO_IP, EBT_SO_SET_COUNTERS, &repl, optlen))
                ebt_print_bug("Couldn't update kernel counters");
+
+       if (exec_style != EXEC_STYLE_DAEMON)
+               return;
+       /* Reset the counterchanges to CNT_NORM */
+       cc = u_repl->counterchanges;
+       for (i = 0; i < u_repl->nentries; i++) {
+               cc->type = CNT_NORM;
+               cc3 = &cc->next;
+               cc = cc->next;
+       }
+       *cc3 = NULL;
+       while (cc) {
+               cc2 = cc->next;
+               free(cc);
+               cc = cc2;
+       }
 }
 
 static int
 ebt_translate_match(struct ebt_entry_match *m, struct ebt_u_match_list ***l)
 {
        struct ebt_u_match_list *new;
+       int ret = 0;
 
        new = (struct ebt_u_match_list *)
           malloc(sizeof(struct ebt_u_match_list));
@@ -393,10 +424,12 @@ ebt_translate_match(struct ebt_entry_match *m, struct ebt_u_match_list ***l)
        new->next = NULL;
        **l = new;
        *l = &new->next;
-       if (ebt_find_match(new->m->u.name) == NULL)
+       if (ebt_find_match(new->m->u.name) == NULL) {
                ebt_print_error("Kernel match %s unsupported by userspace tool",
                                new->m->u.name);
-       return 0;
+               ret = -1;
+       }
+       return ret;
 }
 
 static int
@@ -404,6 +437,7 @@ ebt_translate_watcher(struct ebt_entry_watcher *w,
    struct ebt_u_watcher_list ***l)
 {
        struct ebt_u_watcher_list *new;
+       int ret = 0;
 
        new = (struct ebt_u_watcher_list *)
           malloc(sizeof(struct ebt_u_watcher_list));
@@ -417,10 +451,12 @@ ebt_translate_watcher(struct ebt_entry_watcher *w,
        new->next = NULL;
        **l = new;
        *l = &new->next;
-       if (ebt_find_watcher(new->w->u.name) == NULL)
+       if (ebt_find_watcher(new->w->u.name) == NULL) {
                ebt_print_error("Kernel watcher %s unsupported by userspace "
                                "tool", new->w->u.name);
-       return 0;
+               ret = -1;
+       }
+       return ret;
 }
 
 static int
@@ -428,7 +464,7 @@ ebt_translate_entry(struct ebt_entry *e, unsigned int *hook, int *n, int *cnt,
    int *totalcnt, struct ebt_u_entry ***u_e, struct ebt_u_replace *u_repl,
    unsigned int valid_hooks, char *base)
 {
-       /* an entry */
+       /* An entry */
        if (e->bitmask & EBT_ENTRY_OR_ENTRIES) {
                struct ebt_u_entry *new;
                struct ebt_u_match_list **m_l;
@@ -440,7 +476,7 @@ ebt_translate_entry(struct ebt_entry *e, unsigned int *hook, int *n, int *cnt,
                        ebt_print_memory();
                new->bitmask = e->bitmask;
                /*
-                * plain userspace code doesn't know about
+                * Plain userspace code doesn't know about
                 * EBT_ENTRY_OR_ENTRIES
                 */
                new->bitmask &= ~EBT_ENTRY_OR_ENTRIES;
@@ -467,12 +503,14 @@ ebt_translate_entry(struct ebt_entry *e, unsigned int *hook, int *n, int *cnt,
                   malloc(t->target_size + sizeof(struct ebt_entry_target));
                if (!new->t)
                        ebt_print_memory();
-               if (ebt_find_target(t->u.name) == NULL)
+               if (ebt_find_target(t->u.name) == NULL) {
                        ebt_print_error("Kernel target %s unsupported by "
                                        "userspace tool", t->u.name);
+                       return -1;
+               }
                memcpy(new->t, t, t->target_size +
                   sizeof(struct ebt_entry_target));
-               /* deal with jumps to udc */
+               /* Deal with jumps to udc */
                if (!strcmp(t->u.name, EBT_STANDARD_TARGET)) {
                        char *tmp = base;
                        int verdict = ((struct ebt_standard_target *)t)->verdict;
@@ -488,7 +526,7 @@ ebt_translate_entry(struct ebt_entry *e, unsigned int *hook, int *n, int *cnt,
                                        cl = cl->next;
                                }
                                if (!cl)
-                                       ebt_print_bug("can't find udc for "
+                                       ebt_print_bug("Can't find udc for "
                                                      "jump");
                                ((struct ebt_standard_target *)new->t)->verdict = i;
                        }
@@ -500,7 +538,7 @@ ebt_translate_entry(struct ebt_entry *e, unsigned int *hook, int *n, int *cnt,
                (*cnt)++;
                (*totalcnt)++;
                return 0;
-       } else { /* a new chain */
+       } else { /* A new chain */
                int i;
                struct ebt_entries *entries = (struct ebt_entries *)e;
                struct ebt_u_chain_list *cl;
@@ -513,8 +551,8 @@ ebt_translate_entry(struct ebt_entry *e, unsigned int *hook, int *n, int *cnt,
                        if (valid_hooks & (1 << i))
                                break;
                *hook = i;
-               /* makes use of fact that standard chains come before udc */
-               if (i >= NF_BR_NUMHOOKS) { /* udc */
+               /* Makes use of fact that standard chains come before udc */
+               if (i >= NF_BR_NUMHOOKS) { /* Udc */
                        i -= NF_BR_NUMHOOKS;
                        cl = u_repl->udc;
                        while (i-- > 0)
@@ -526,7 +564,7 @@ ebt_translate_entry(struct ebt_entry *e, unsigned int *hook, int *n, int *cnt,
        }
 }
 
-/* initialize all chain headers */
+/* Initialize all chain headers */
 static int
 ebt_translate_chains(struct ebt_entry *e, unsigned int *hook,
    struct ebt_u_replace *u_repl, unsigned int valid_hooks)
@@ -540,10 +578,10 @@ ebt_translate_chains(struct ebt_entry *e, unsigned int *hook,
                for (i = *hook + 1; i < NF_BR_NUMHOOKS; i++)
                        if (valid_hooks & (1 << i))
                                break;
-               /* makes use of fact that standard chains come before udc */
-               if (i >= NF_BR_NUMHOOKS) { /* udc */
+               /* Makes use of fact that standard chains come before udc */
+               if (i >= NF_BR_NUMHOOKS) { /* Udc */
                        chain_list = &u_repl->udc;
-                       /* add in the back */
+                       /* Add in the back */
                        while (*chain_list)
                                chain_list = &((*chain_list)->next);
                        *chain_list = (struct ebt_u_chain_list *)
@@ -556,10 +594,8 @@ ebt_translate_chains(struct ebt_entry *e, unsigned int *hook,
                        if (!((*chain_list)->udc))
                                ebt_print_memory();
                        new = (*chain_list)->udc;
-                       /*
-                        * ebt_translate_entry depends on this for knowing
-                        * to which chain is being jumped
-                        */
+                       /* ebt_translate_entry depends on this for knowing
+                        * to which chain is being jumped */
                        (*chain_list)->kernel_start = (char *)e;
                } else {
                        *hook = i;
@@ -578,19 +614,19 @@ ebt_translate_chains(struct ebt_entry *e, unsigned int *hook,
        return 0;
 }
 
-static void retrieve_from_file(char *filename, struct ebt_replace *repl,
+static int retrieve_from_file(char *filename, struct ebt_replace *repl,
    char command)
 {
        FILE *file;
        char *hlp = NULL, *entries;
        struct ebt_counter *counters;
-       int size;
+       int size, ret = 0;
 
-       if (!(file = fopen(filename, "r+b")))
+       if (!(file = fopen(filename, "r+b"))) {
                ebt_print_error("Could not open file %s", filename);
-       /*
-        * make sure table name is right if command isn't -L or --atomic-commit
-        */
+               return -1;
+       }
+       /* Make sure table name is right if command isn't -L or --atomic-commit */
        if (command != 'L' && command != 8) {
                hlp = (char *)malloc(strlen(repl->name) + 1);
                if (!hlp)
@@ -598,25 +634,30 @@ static void retrieve_from_file(char *filename, struct ebt_replace *repl,
                strcpy(hlp, repl->name);
        }
        if (fread(repl, sizeof(char), sizeof(struct ebt_replace), file)
-          != sizeof(struct ebt_replace))
+          != sizeof(struct ebt_replace)) {
                ebt_print_error("File %s is corrupt", filename);
+               ret = -1;
+               goto close_file;
+       }
        if (command != 'L' && command != 8 && strcmp(hlp, repl->name)) {
-               fclose(file);
                ebt_print_error("File %s contains wrong table name or is "
                                "corrupt", filename);
-               free(hlp);
+               ret = -1;
+               goto close_file;
        } else if (!ebt_find_table(repl->name)) {
-               fclose(file);
                ebt_print_error("File %s contains invalid table name",
                                filename);
+               ret = -1;
+               goto close_file;
        }
 
        size = sizeof(struct ebt_replace) +
           repl->nentries * sizeof(struct ebt_counter) + repl->entries_size;
        fseek(file, 0, SEEK_END);
        if (size != ftell(file)) {
-               fclose(file);
                ebt_print_error("File %s has wrong size", filename);
+               ret -1;
+               goto close_file;
        }
        entries = (char *)malloc(repl->entries_size);
        if (!entries)
@@ -630,7 +671,7 @@ static void retrieve_from_file(char *filename, struct ebt_replace *repl,
                        ebt_print_memory();
        } else
                repl->counters = sparc_cast NULL;
-       /* copy entries and counters */
+       /* Copy entries and counters */
        if (fseek(file, sizeof(struct ebt_replace), SEEK_SET) ||
           fread((char *)repl->entries, sizeof(char), repl->entries_size, file)
           != repl->entries_size ||
@@ -639,10 +680,15 @@ static void retrieve_from_file(char *filename, struct ebt_replace *repl,
           || fread((char *)repl->counters, sizeof(char),
           repl->nentries * sizeof(struct ebt_counter), file)
           != repl->nentries * sizeof(struct ebt_counter)) {
-               fclose(file);
                ebt_print_error("File %s is corrupt", filename);
+               free(entries);
+               repl->entries = NULL;
+               ret = -1;
        }
+close_file:
        fclose(file);
+       free(hlp);
+       return ret;
 }
 
 static int retrieve_from_kernel(struct ebt_replace *repl, char command,
@@ -653,7 +699,8 @@ static int retrieve_from_kernel(struct ebt_replace *repl, char command,
        char *entries;
 
        optlen = sizeof(struct ebt_replace);
-       get_sockfd();
+       if (get_sockfd())
+               return -1;
        /* --atomic-init || --init-table */
        if (init)
                optname = EBT_SO_GET_INIT_INFO;
@@ -676,7 +723,7 @@ static int retrieve_from_kernel(struct ebt_replace *repl, char command,
        else
                repl->counters = sparc_cast NULL;
 
-       /* we want to receive the counters */
+       /* We want to receive the counters */
        repl->num_counters = repl->nentries;
        optlen += repl->entries_size + repl->num_counters *
           sizeof(struct ebt_counter);
@@ -685,7 +732,7 @@ static int retrieve_from_kernel(struct ebt_replace *repl, char command,
        else
                optname = EBT_SO_GET_ENTRIES;
        if (getsockopt(sockfd, IPPROTO_IP, optname, repl, &optlen))
-               ebt_print_bug("hmm, what is wrong??? bug#1");
+               ebt_print_bug("Hmm, what is wrong??? bug#1");
 
        return 0;
 }
@@ -701,17 +748,16 @@ int ebt_get_table(struct ebt_u_replace *u_repl, int init)
        strcpy(repl.name, u_repl->name);
        if (u_repl->filename != NULL) {
                if (init)
-                       ebt_print_bug("getting initial table data from a "
+                       ebt_print_bug("Getting initial table data from a "
                                  "file is impossible");
-               retrieve_from_file(u_repl->filename, &repl, u_repl->command);
-               /*
-                * -L with a wrong table name should be dealt with silently
-                */
+               if (retrieve_from_file(u_repl->filename, &repl, u_repl->command))
+                       return -1;
+               /* -L with a wrong table name should be dealt with silently */
                strcpy(u_repl->name, repl.name);
-       } else if (retrieve_from_kernel(&repl, u_repl->command, init) == -1)
+       } else if (retrieve_from_kernel(&repl, u_repl->command, init))
                return -1;
 
-       /* translate the struct ebt_replace to a struct ebt_u_replace */
+       /* Translate the struct ebt_replace to a struct ebt_u_replace */
        u_repl->valid_hooks = repl.valid_hooks;
        u_repl->nentries = repl.nentries;
        u_repl->num_counters = repl.num_counters;
@@ -729,14 +775,13 @@ int ebt_get_table(struct ebt_u_replace *u_repl, int init)
                prev_cc = &(new_cc->next);
        }
        hook = -1;
+       /* FIXME: Clean up when an error is encountered */
        EBT_ENTRY_ITERATE(repl.entries, repl.entries_size, ebt_translate_chains,
           &hook, u_repl, u_repl->valid_hooks);
-       i = 0; /* holds the expected nr. of entries for the chain */
-       j = 0; /* holds the up to now counted entries for the chain */
-       /*
-        * holds the total nr. of entries,
-        * should equal u_repl->nentries afterwards
-        */
+       i = 0; /* Holds the expected nr. of entries for the chain */
+       j = 0; /* Holds the up to now counted entries for the chain */
+       /* Holds the total nr. of entries,
+        * should equal u_repl->nentries afterwards */
        k = 0;
        hook = -1;
        EBT_ENTRY_ITERATE((char *)repl.entries, repl.entries_size,
diff --git a/ebtables-standalone.c b/ebtables-standalone.c
new file mode 100644 (file)
index 0000000..d349d39
--- /dev/null
@@ -0,0 +1,14 @@
+#include <string.h>
+#include "include/ebtables_u.h"
+
+static struct ebt_u_replace replace;
+void ebt_early_init_once();
+
+int main(int argc, char *argv[])
+{
+       ebt_silent = 0;
+       ebt_early_init_once();
+       strcpy(replace.name, "filter");
+       do_command(argc, argv, EXEC_STYLE_PRG, &replace);
+       return 0;
+}
index 24a27a4..1dc8cd5 100644 (file)
 .\"     
 .\"
 .SH NAME
-ebtables (v.2.0.7) \- Ethernet bridge frame table administration
+ebtables (v.2.0.7), ebtablesd, ebtablesu \- Ethernet bridge frame table administration
 .SH SYNOPSIS
-.BR "ebtables " [ "-t table" ] " -" [ ADI ] " chain rule specification " [ "match extensions" "] [" "watcher extensions" ] " target"
+.BR "ebtables " [ -t " table ] " - [ ADI "] chain rule specification [match extensions] [watcher extensions] target"
 .br
-.BR "ebtables " [ "-t table" ] " -P chain ACCEPT " | " DROP " | " RETURN"
+.BR "ebtables " [ -t " table ] " -P " chain " ACCEPT " | " DROP " | " RETURN
 .br
-.BR "ebtables " [ "-t table" ] " -F " [ chain ]
+.BR "ebtables " [ -t " table ] " -F " [chain]"
 .br
-.BR "ebtables " [ "-t table" ] " -Z " [ chain ]
+.BR "ebtables " [ -t " table ] " -Z " [chain]"
 .br
-.BR "ebtables " [ "-t table" ] " -L " [ -Z "] [" " chain" "] [ [ [" --Ln "] [" --Lc "] ] | [" --Lx "] ] [" --Lmac2 "]"
+.BR "ebtables " [ -t " table ] " -L " [" -Z "] [chain] [ [ [" --Ln "] [" --Lc "] ] | [" --Lx "] ] [" --Lmac2 ]
 .br
-.BR "ebtables " [ "-t table" ] " -N chain " [ "-P ACCEPT " | " DROP " | " RETURN" ]
+.BR "ebtables " [ -t " table ] " -N " chain [" "-P ACCEPT " | " DROP " | " RETURN" ]
 .br
-.BR "ebtables " [ "-t table" ] " -X " [ chain ]
+.BR "ebtables " [ -t " table ] " -X " [chain]"
 .br
-.BR "ebtables " [ "-t table" ] " -E old-chain-name new-chain-name"
+.BR "ebtables " [ -t " table ] " -E " old-chain-name new-chain-name"
 .br
-.BR "ebtables " [ "-t table" ] " --init-table"
+.BR "ebtables " [ -t " table ] " --init-table
 .br
-.BR "ebtables " [ "-t table" "] [" "--atomic-file file" ] " --atomic-commit"
+.BR "ebtables " [ -t " table ] [" --atomic-file " file] " --atomic-commit
 .br
-.BR "ebtables " [ "-t table" "] [" "--atomic-file file" ] " --atomic-init"
+.BR "ebtables " [ -t " table ] [" --atomic-file " file] " --atomic-init
 .br
-.BR "ebtables " [ "-t table" "] [" "--atomic-file file" ] " --atomic-save"
+.BR "ebtables " [ -t " table ] [" --atomic-file " file] " --atomic-save
+.br
+.BR "ebtablesu open " table 
+.br
+.BR "ebtablesu fopen " "table file"
+.br
+.BR "ebtablesu free " table 
+.br
+.BR "ebtablesu commit " table
+.br
+.BR "ebtablesu fcommit " "table file"
+.br
+.B ebtablesu quit
 .br
 .SH DESCRIPTION
 .B ebtables
@@ -59,6 +71,52 @@ It is analogous to the
 .B iptables
 application, but less complicated, due to the fact that the Ethernet protocol
 is much simpler than the IP protocol.
+.br
+.BR ebtablesu " and " ebtablesd " can be used to speed up adding rules using a script when the"
+.B --atomic-commit
+option is not satisfactory. The
+.BR open " command makes ebtablesd open the specified kernel table for processing"
+.BR "" "in userspace (multiple tables can be open in the same time). The " fopen
+command opens the table from the specified file.
+.BR "" "The " free " command removes the specified table out of the memory of ebtablesd."
+No data is written to a file or to the kernel.
+.BR "" "The " commit " command stores the table from the memory of ebtablesd to the kernel."
+.BR "" "The " fcommit " command stores the table from the memory of ebtablesd to the specified file."
+This file can be read later, e.g. with
+.BR "ebtables --atomic-file " file " -L" .
+.BR "" "The " quit " command lets ebtablesd finish gracefully."
+All commands, options and extensions that ebtables uses can be used with ebtablesu, except for
+.BR --init-table ", " --atomic-file ", " --atomic-commit ", " --atomic-init ", " --atomic-save " and " -h .
+.br
+Example usage:
+.br
+# ebtablesd&
+.br
+# ebtablesu open filter
+.br
+# ebtablesu -A FORWARD -j DROP
+.br
+# ebtablesu commit filter
+.br
+# ebtablesu quit
+.br
+Alternatively, the commands can be echo'ed directly to the pipe used by ebtablesd,
+which has default location /tmp/ebtables-vx.y.z/ebtablesd_pipe, where
+x.y.z is the ebtables version (e.g. 2.0.7). Using echo instead of ebtablesu is
+much faster because echo is a bash built-in command. Commands like cat can be used
+too, of course.
+.br
+Example usage:
+.br
+# (./ebtablesd&) ; PIPE=/tmp/ebtables-v2.0.7/ebtablesd_pipe ; sleep 1
+.br
+# echo "ebtablesu open filter" >> $PIPE
+.br
+# echo "ebtablesu -A FORWARD -j DROP" >> $PIPE
+.br
+# echo "ebtablesu commit filter" >> $PIPE
+.br
+# echo "ebtablesu quit" >> $PIPE
 .SS CHAINS
 There are three ebtables tables with built-in chains in the
 Linux kernel. These tables are used to divide functionality into
index 8b0dd80..2d0cd61 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Author: Bart De Schuymer
  *
- *  This code is stongly inspired on the iptables code which is
+ *  This code was stongly inspired on the iptables code which is
  *  Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
  *
  * This program is free software; you can redistribute it and/or
 #include <fcntl.h>
 #include <sys/wait.h>
 
-/*
- * default command line options
- * do not mess around with the already assigned numbers unless
- * you know what you are doing
- */
+/* dDfault command line options. Do not mess around with the already
+ * assigned numbers unless you know what you are doing */
 static struct option ebt_original_options[] =
 {
        { "append"        , required_argument, 0, 'A' },
@@ -82,29 +79,23 @@ static struct option ebt_original_options[] =
 
 static struct option *ebt_options = ebt_original_options;
 
-/*
- * holds all the data
- */
-static struct ebt_u_replace replace;
+/* Holds all the data */
+static struct ebt_u_replace *replace;
 
-/*
- * the chosen table
- */
+/* The chosen table */
 static struct ebt_u_table *table = NULL;
 
-/*
- * The pointers in here are special:
+/* The pointers in here are special:
  * The struct ebt_target * pointer is actually a struct ebt_u_target * pointer.
  * instead of making yet a few other structs, we just do a cast.
  * We need a struct ebt_u_target pointer because we know the address of the data
  * they point to won't change. We want to allow that the struct ebt_u_target.t
  * member can change.
- * Same holds for the struct ebt_match and struct ebt_watcher pointers
- */
-struct ebt_u_entry *new_entry;
+ * Same holds for the struct ebt_match and struct ebt_watcher pointers */
+static struct ebt_u_entry *new_entry;
 
 
-static int global_option_offset = 0;
+static int global_option_offset;
 #define OPTION_OFFSET 256
 static struct option *
 merge_options(struct option *oldopts, const struct option *newopts,
@@ -130,7 +121,7 @@ merge_options(struct option *oldopts, const struct option *newopts,
                merge[num_old + i].val += *options_offset;
        }
        memset(merge + num_old + num_new, 0, sizeof(struct option));
-       /* only free dynamically allocated stuff */
+       /* Only free dynamically allocated stuff */
        if (oldopts != ebt_original_options)
                free(oldopts);
 
@@ -155,7 +146,7 @@ static void merge_target(struct ebt_u_target *t)
           (ebt_options, t->extra_ops, &(t->option_offset));
 }
 
-/* be backwards compatible, so don't use '+' in kernel */
+/* Be backwards compatible, so don't use '+' in kernel */
 #define IF_WILDCARD 1
 static void print_iface(const char *iface)
 {
@@ -168,18 +159,14 @@ static void print_iface(const char *iface)
                *c = IF_WILDCARD;
 }
 
-/*
- * we use replace.flags, so we can't use the following values:
- * 0x01 == OPT_COMMAND, 0x02 == OPT_TABLE, 0x100 == OPT_ZERO
- */
+/* We use replace->flags, so we can't use the following values:
+ * 0x01 == OPT_COMMAND, 0x02 == OPT_TABLE, 0x100 == OPT_ZERO */
 #define LIST_N    0x04
 #define LIST_C    0x08
 #define LIST_X    0x10
 #define LIST_MAC2 0x20
 
-/*
- * helper function for list_rules()
- */
+/* Helper function for list_rules() */
 static void list_em(struct ebt_u_entries *entries)
 {
        int i, j, space = 0, digits;
@@ -190,13 +177,13 @@ static void list_em(struct ebt_u_entries *entries)
        struct ebt_u_watcher *w;
        struct ebt_u_target *t;
 
-       if (replace.flags & LIST_MAC2)
+       if (replace->flags & LIST_MAC2)
                ebt_printstyle_mac = 2;
        hlp = entries->entries;
-       if (replace.flags & LIST_X && entries->policy != EBT_ACCEPT) {
-               printf("ebtables -t %s -P %s %s\n", replace.name,
+       if (replace->flags & LIST_X && entries->policy != EBT_ACCEPT) {
+               printf("ebtables -t %s -P %s %s\n", replace->name,
                   entries->name, ebt_standard_targets[-entries->policy - 1]);
-       } else if (!(replace.flags & LIST_X)) {
+       } else if (!(replace->flags & LIST_X)) {
                printf("\nBridge chain: %s, entries: %d, policy: %s\n",
                   entries->name, entries->nentries,
                   ebt_standard_targets[-entries->policy - 1]);
@@ -209,7 +196,7 @@ static void list_em(struct ebt_u_entries *entries)
        }
 
        for (i = 0; i < entries->nentries; i++) {
-               if (replace.flags & LIST_N) {
+               if (replace->flags & LIST_N) {
                        digits = 0;
                        /* A little work to get nice rule numbers. */
                        j = i + 1;
@@ -221,18 +208,16 @@ static void list_em(struct ebt_u_entries *entries)
                                printf(" ");
                        printf("%d. ", i + 1);
                }
-               if (replace.flags & LIST_X)
+               if (replace->flags & LIST_X)
                        printf("ebtables -t %s -A %s ",
-                          replace.name, entries->name);
+                          replace->name, entries->name);
 
                /* The standard target's print() uses this to find out
                 * the name of a udc */
-               hlp->replace = &replace;
+               hlp->replace = replace;
 
-               /*
-                * Don't print anything about the protocol if no protocol was
-                * specified, obviously this means any protocol will do.
-                */
+               /* Don't print anything about the protocol if no protocol was
+                * specified, obviously this means any protocol will do. */
                if (!(hlp->bitmask & EBT_NOPROTO)) {
                        printf("-p ");
                        if (hlp->invflags & EBT_IPROTO)
@@ -311,12 +296,12 @@ static void list_em(struct ebt_u_entries *entries)
                        printf("%s ", hlp->t->u.name);
                t = ebt_find_target(hlp->t->u.name);
                if (!t)
-                       ebt_print_bug("Target not found");
+                       ebt_print_bug("Target '%s' not found", hlp->t->u.name);
                t->print(hlp, hlp->t);
-               if (replace.flags & LIST_C)
+               if (replace->flags & LIST_C)
                        printf(", pcnt = %llu -- bcnt = %llu",
-                          replace.counters[entries->counter_offset + i].pcnt,
-                          replace.counters[entries->counter_offset + i].bcnt);
+                          replace->counters[entries->counter_offset + i].pcnt,
+                          replace->counters[entries->counter_offset + i].bcnt);
                printf("\n");
                hlp = hlp->next;
        }
@@ -356,10 +341,10 @@ static void print_help()
 "--proto  -p [!] proto         : protocol hexadecimal, by name or LENGTH\n"
 "--src    -s [!] address[/mask]: source mac address\n"
 "--dst    -d [!] address[/mask]: destination mac address\n"
-"--in-if  -i [!] name          : network input interface name\n"
-"--out-if -o [!] name          : network output interface name\n"
-"--logical-in  [!] name        : logical bridge input interface name\n"
-"--logical-out [!] name        : logical bridge output interface name\n"
+"--in-if  -i [!] name[+]       : network input interface name\n"
+"--out-if -o [!] name[+]       : network output interface name\n"
+"--logical-in  [!] name[+]     : logical bridge input interface name\n"
+"--logical-out [!] name[+]     : logical bridge output interface name\n"
 "--modprobe -M program         : try to insert modules using this program\n"
 "--version -V                  : print package version\n\n"
 "Environment variable:\n"
@@ -384,43 +369,39 @@ ATOMIC_ENV_VARIABLE "          : if set <FILE> (see above) will equal its value"
        exit(0);
 }
 
-/*
- * execute command L
- */
+/* Execute command L */
 static void list_rules()
 {
        int i;
 
-       if (!(replace.flags & LIST_X))
+       if (!(replace->flags & LIST_X))
                printf("Bridge table: %s\n", table->name);
-       if (replace.selected_chain != -1) {
-               list_em(ebt_to_chain(&replace));
+       if (replace->selected_chain != -1) {
+               list_em(ebt_to_chain(replace));
        } else {
-               struct ebt_u_chain_list *cl = replace.udc;
+               struct ebt_u_chain_list *cl = replace->udc;
 
-               /*
-                * create new chains and rename standard chains when necessary
-                */
-               if (replace.flags & LIST_X) {
+               /* Create new chains and rename standard chains when necessary */
+               if (replace->flags & LIST_X) {
                        while (cl) {
-                               printf("ebtables -t %s -N %s\n", replace.name,
+                               printf("ebtables -t %s -N %s\n", replace->name,
                                   cl->udc->name);
                                cl = cl->next;
                        }
-                       cl = replace.udc;
+                       cl = replace->udc;
                        for (i = 0; i < NF_BR_NUMHOOKS; i++)
-                               if (replace.valid_hooks & (1 << i) &&
-                                  strcmp(replace.hook_entry[i]->name,
+                               if (replace->valid_hooks & (1 << i) &&
+                                  strcmp(replace->hook_entry[i]->name,
                                          ebt_hooknames[i]))
                                        printf("ebtables -t %s -E %s %s\n",
-                                          replace.name, ebt_hooknames[i],
-                                          replace.hook_entry[i]->name);
+                                          replace->name, ebt_hooknames[i],
+                                          replace->hook_entry[i]->name);
                }
                i = 0;
                while (1) {
                        if (i < NF_BR_NUMHOOKS) {
-                               if (replace.valid_hooks & (1 << i))
-                                       list_em(replace.hook_entry[i]);
+                               if (replace->valid_hooks & (1 << i))
+                                       list_em(replace->hook_entry[i]);
                                i++;
                                continue;
                        } else {
@@ -440,7 +421,7 @@ static int parse_delete_rule(const char *argv, int *rule_nr, int *rule_nr_end)
        if (colon) {
                *colon = '\0';
                if (*(colon + 1) == '\0')
-                       *rule_nr_end = -1; /* until the last rule */
+                       *rule_nr_end = -1; /* Until the last rule */
                else {
                        *rule_nr_end = strtol(colon + 1, &buffer, 10);
                        if (*buffer != '\0' || *rule_nr_end == 0)
@@ -448,7 +429,7 @@ static int parse_delete_rule(const char *argv, int *rule_nr, int *rule_nr_end)
                }
        }
        if (colon == argv)
-               *rule_nr = 1; /* beginning with the first rule */
+               *rule_nr = 1; /* Beginning with the first rule */
        else {
                *rule_nr = strtol(argv, &buffer, 10);
                if (*buffer != '\0' || *rule_nr == 0)
@@ -459,7 +440,7 @@ static int parse_delete_rule(const char *argv, int *rule_nr, int *rule_nr_end)
        return 0;
 }
 
-static void parse_iface(char *iface, char *option)
+static int parse_iface(char *iface, char *option)
 {
        char *c;
 
@@ -467,15 +448,33 @@ static void parse_iface(char *iface, char *option)
                if (*(c + 1) != '\0') {
                        ebt_print_error("Spurious characters after '+' "
                                        "wildcard for %s", option);
+                       return -1;
                } else
                        *c = IF_WILDCARD;
        }
+       return 0;
+}
+
+void ebt_early_init_once()
+{
+       ebt_iterate_matches(merge_match);
+       ebt_iterate_watchers(merge_watcher);
+       ebt_iterate_targets(merge_target);
 }
 
-#define print_if_l_error ebt_print_error("Interface name length must be less " \
-   "than %d", IFNAMSIZ)
-#define print_epoto_error(__proto) ebt_print_error("Problem with the specified"\
-   " Ethernet protocol (%s), perhaps "_PATH_ETHERTYPES " is missing", __proto);
+#define ebt_print_error2(format, args...) {__ebt_print_error(format, ##args); \
+   return -1;}
+#define ebt_check_option2(flags,mask)  \
+({ebt_check_option(flags,mask);                \
+ if (ebt_errormsg[0] != '\0')          \
+       return -1;})
+#define ebt_check_inverse2(option)             \
+({int __ret = ebt_check_inverse(option);       \
+if (ebt_errormsg[0] != '\0')                   \
+       return -1;                              \
+__ret;})
+#define OPT_COMMANDS (replace->flags & OPT_COMMAND || replace->flags & OPT_ZERO)
+
 #define OPT_COMMAND    0x01
 #define OPT_TABLE      0x02
 #define OPT_IN         0x04
@@ -487,20 +486,17 @@ static void parse_iface(char *iface, char *option)
 #define OPT_ZERO       0x100
 #define OPT_LOGICALIN  0x200
 #define OPT_LOGICALOUT 0x400
-#define OPT_KERNELDATA 0x800 /* if set, we already have loaded the table
-                              * in userspace */
-/* the main thing */
-int main(int argc, char *argv[])
+#define OPT_KERNELDATA 0x800 /* This value is also defined in ebtablesd.c */
+int do_command(int argc, char *argv[], int exec_style,
+               struct ebt_u_replace *replace_)
 {
        char *buffer;
        int c, i;
-       /*
-        * this special one for the -Z option (we can have -Z <this> -L <that>)
-        */
+       /* Needed for the -Z option (we can have -Z <this> -L <that>) */
        int zerochain = -1;
        int policy = 0;
-       int rule_nr = 0; /* used for -[D,I] */
-       int rule_nr_end = 0; /* used for -I */
+       int rule_nr = 0;
+       int rule_nr_end = 0;
        struct ebt_u_target *t;
        struct ebt_u_match *m;
        struct ebt_u_watcher *w;
@@ -509,592 +505,476 @@ int main(int argc, char *argv[])
        struct ebt_u_entries *entries;
 
        opterr = 0;
+       ebt_modprobe = NULL;
+
+       replace = replace_;
+
+       /* The daemon doesn't use the environment variable */
+       if (exec_style == EXEC_STYLE_PRG) {
+               buffer = getenv(ATOMIC_ENV_VARIABLE);
+               if (buffer) {
+                       replace->filename = malloc(strlen(buffer) + 1);
+                       if (!replace->filename)
+                               ebt_print_memory();
+                       strcpy(replace->filename, buffer);
+                       buffer = NULL;
+               }
+       }
 
-       ebt_iterate_matches(merge_match);
-       ebt_iterate_watchers(merge_watcher);
-       ebt_iterate_targets(merge_target);
+       replace->flags &= OPT_KERNELDATA; /* ebtablesd needs OPT_KERNELDATA */
+       replace->selected_chain = -1;
+       replace->command = 'h';
 
-       buffer = getenv(ATOMIC_ENV_VARIABLE);
-       if (buffer) {
-               replace.filename = malloc(strlen(buffer)+1);
-               if (!replace.filename)
+       if (!new_entry) {
+               new_entry = (struct ebt_u_entry *)malloc(sizeof(struct ebt_u_entry));
+               if (!new_entry)
                        ebt_print_memory();
-               memcpy(replace.filename, buffer, strlen(buffer)+1);
-               buffer = NULL;
        }
-       /*
-        * initialize the table name, OPT_ flags, selected hook and command
-        */
-       strcpy(replace.name, "filter");
-       replace.flags = 0;
-       replace.selected_chain = -1;
-       replace.command = 'h';
-       replace.counterchanges = NULL;
-
-       new_entry = (struct ebt_u_entry *)malloc(sizeof(struct ebt_u_entry));
-       if (!new_entry)
-               ebt_print_memory();
-       /*
-        * put some sane values in our new entry
-        */
+       /* Put some sane values in our new entry */
        ebt_initialize_entry(new_entry);
-       new_entry->replace = &replace;
+       new_entry->replace = replace;
 
-       /*
-        * The scenario induced by this loop makes that:
+       /* The scenario induced by this loop makes that:
         * '-t'  ,'-M' and --atomic (if specified) have to come
-        * before '-A' and the like
-        */
+        * before '-A' and the like */
 
-       /*
-        * getopt saves the day
-        */
+       /* Getopt saves the day */
        while ((c = getopt_long(argc, argv,
           "-A:D:I:N:E:X::L::Z::F::P:Vhi:o:j:p:s:d:t:M:", ebt_options, NULL)) != -1) {
                switch (c) {
 
-               case 'A': /* add a rule */
-               case 'D': /* delete a rule */
-               case 'P': /* define policy */
-               case 'I': /* insert a rule */
-               case 'N': /* make a user defined chain */
-               case 'E': /* rename chain */
-               case 'X': /* delete chain */
+               case 'A': /* Add a rule */
+               case 'D': /* Delete a rule */
+               case 'P': /* Define policy */
+               case 'I': /* Insert a rule */
+               case 'N': /* Make a user defined chain */
+               case 'E': /* Rename chain */
+               case 'X': /* Delete chain */
                        /* We allow -N chainname -P policy */
-                       if (replace.command == 'N' && c == 'P') {
-                               replace.command = c;
-                               optind--;
+                       if (replace->command == 'N' && c == 'P') {
+                               replace->command = c;
+                               optind--; /* No table specified */
                                goto handle_P;
                        }
-                       replace.command = c;
-                       replace.flags |= OPT_COMMAND;
-                       if (!(replace.flags & OPT_KERNELDATA)) {
-                               ebt_get_kernel_table(&replace, table, 0);
-                               replace.flags |= OPT_KERNELDATA;
-                       }
-                       if (optarg && (optarg[0] == '-' ||
-                           !strcmp(optarg, "!")))
-                               ebt_print_error("No chain name specified");
+                       if (OPT_COMMANDS)
+                               ebt_print_error2("Multiple commands are not allowed");
+
+                       replace->command = c;
+                       replace->flags |= OPT_COMMAND;
+                       if (!(replace->flags & OPT_KERNELDATA))
+                               ebt_get_kernel_table(replace, 0);
+                       if (optarg && (optarg[0] == '-' || !strcmp(optarg, "!")))
+                               ebt_print_error2("No chain name specified");
                        if (c == 'N') {
-                               ebt_new_chain(&replace, optarg, EBT_ACCEPT);
+                               ebt_new_chain(replace, optarg, EBT_ACCEPT);
                                /* This is needed to get -N x -P y working */
-                               replace.selected_chain =
-                               ebt_get_chainnr(&replace, optarg);
+                               replace->selected_chain = ebt_get_chainnr(replace, optarg);
                                break;
-                       }
-                       if (c == 'X') {
-                               char *opt;
-
-                               if (!optarg && (optind >= argc ||
-                                  (argv[optind][0] == '-'
-                                   && strcmp(argv[optind], "!")))) {
-                                       replace.selected_chain = -1;
-                                       ebt_delete_chain(&replace);
+                       } else if (c == 'X') {
+                               if (optind >= argc) {
+                                       replace->selected_chain = -1;
+                                       ebt_delete_chain(replace);
                                        break;
                                }
-                               if (optarg)
-                                       opt = optarg;
-                               else {
-                                       opt = argv[optind];
-                                       optind++;
-                               }
-                               if ((replace.selected_chain =
-                                    ebt_get_chainnr(&replace, opt)) == -1)
-                                       ebt_print_error("Chain %s doesn't "
-                                                       "exist", opt);
-                               ebt_delete_chain(&replace);
+
+                               if (optind < argc - 1)
+                                       ebt_print_error2("No extra options allowed with -X");
+
+                               if ((replace->selected_chain = ebt_get_chainnr(replace, argv[optind])) == -1)
+                                       ebt_print_error2("Chain %s doesn't exist", argv[optind]);
+                               ebt_delete_chain(replace);
+                               if (ebt_errormsg[0] != '\0')
+                                       return -1;
+                               optind++;
                                break;
                        }
 
-                       if ((replace.selected_chain =
-                           ebt_get_chainnr(&replace, optarg)) == -1)
-                               ebt_print_error("Chain %s doesn't exist",
-                                               optarg);
+                       if ((replace->selected_chain = ebt_get_chainnr(replace, optarg)) == -1)
+                               ebt_print_error2("Chain %s doesn't exist", optarg);
                        if (c == 'E') {
-                               if (optind >= argc || argv[optind][0] == '-' ||
-                                  !strcmp(argv[optind], "!"))
-                                       ebt_print_error("No new chain name "
-                                                   "specified");
+                               if (optind >= argc)
+                                       ebt_print_error2("No new chain name specified");
+                               if (optind < argc - 1)
+                                       ebt_print_error2("No extra options allowed with -E");
                                if (strlen(argv[optind])>=EBT_CHAIN_MAXNAMELEN)
-                                       ebt_print_error("Chain name len can't "
-                                                   "exceed %d",
-                                                   EBT_CHAIN_MAXNAMELEN - 1);
-                               if (ebt_get_chainnr(&replace, argv[optind]) !=
-                                   -1)
-                                       ebt_print_error("Chain %s already "
-                                                       "exists", argv[optind]);
+                                       ebt_print_error2("Chain name length can't exceed %d", EBT_CHAIN_MAXNAMELEN - 1);
+                               if (ebt_get_chainnr(replace, argv[optind]) != -1)
+                                       ebt_print_error2("Chain %s already exists", argv[optind]);
                                if (ebt_find_target(argv[optind]))
-                                       ebt_print_error("Target with name %s "
-                                                       "exists", argv[optind]);
-                               ebt_rename_chain(&replace, argv[optind]);
+                                       ebt_print_error2("Target with name %s exists", argv[optind]);
+                               ebt_rename_chain(replace, argv[optind]);
                                optind++;
                                break;
-                       }
-
-                       if (c == 'D' && optind < argc &&
-                           (argv[optind][0] != '-' ||
-                           (argv[optind][1] >= '0' &&
-                            argv[optind][1] <= '9'))) {
-                               if (parse_delete_rule(argv[optind],
-                                   &rule_nr, &rule_nr_end))
-                                       ebt_print_error("Problem with the "
-                                                   "specified rule number(s)");
+                       } else if (c == 'D' && optind < argc && (argv[optind][0] != '-' || (argv[optind][1] >= '0' && argv[optind][1] <= '9'))) {
+                               if (optind != argc - 1)
+                                       ebt_print_error2("No extra options allowed with -D start_nr[:end_nr]");
+                               if (parse_delete_rule(argv[optind], &rule_nr, &rule_nr_end))
+                                       ebt_print_error2("Problem with the specified rule number(s)");
                                optind++;
-                       }
-                       if (c == 'I') {
-                               if (optind >= argc ||
-                                   (argv[optind][0] == '-' &&
-                                   (argv[optind][1] < '0' ||
-                                   argv[optind][1] > '9')))
-                                       ebt_print_error("No rulenr for -I"
-                                                   " specified");
+                       } else if (c == 'I') {
+                               if (optind >= argc || (argv[optind][0] == '-' && (argv[optind][1] < '0' || argv[optind][1] > '9')))
+                                       ebt_print_error2("No rulenr for -I specified");
                                rule_nr = strtol(argv[optind], &buffer, 10);
                                if (*buffer != '\0')
-                                       ebt_print_error("Problem with the "
-                                                   "specified rule number");
+                                       ebt_print_error2("Problem with the specified rule number");
                                optind++;
-                       }
-                       if (c == 'P') {
+                       } else if (c == 'P') {
 handle_P:
                                if (optind >= argc)
-                                       ebt_print_error("No policy specified");
-                               policy = 0;
+                                       ebt_print_error2("No policy specified");
                                for (i = 0; i < NUM_STANDARD_TARGETS; i++)
-                                       if (!strcmp(argv[optind],
-                                          ebt_standard_targets[i])) {
+                                       if (!strcmp(argv[optind], ebt_standard_targets[i])) {
                                                policy = -i -1;
                                                if (policy == EBT_CONTINUE)
-                                                       policy = 0;
+                                                       ebt_print_error2("Wrong policy: '%s'", argv[optind]);
                                                break;
                                        }
-                               if (policy == 0)
-                                       ebt_print_error("Wrong policy");
                                optind++;
                        }
                        break;
-
-               case 'L': /* list */
-               case 'F': /* flush */
-               case 'Z': /* zero counters */
+               case 'L': /* List */
+               case 'F': /* Flush */
+               case 'Z': /* Zero counters */
                        if (c == 'Z') {
-                               if (replace.flags & OPT_ZERO)
-                                       ebt_print_error("Multiple commands"
-                                                   " not allowed");
-                               if ( (replace.flags & OPT_COMMAND &&
-                                  replace.command != 'L'))
-                                       ebt_print_error("command -Z only "
-                                          "allowed together with command -L");
-                               replace.flags |= OPT_ZERO;
+                               if ((replace->flags & OPT_ZERO) || (replace->flags & OPT_COMMAND && replace->command != 'L'))
+print_zero:
+                                       ebt_print_error2("Command -Z only allowed together with command -L");
+                               replace->flags |= OPT_ZERO;
                        } else {
-                               replace.command = c;
-                               if (replace.flags & OPT_COMMAND)
-                                       ebt_print_error("Multiple commands"
-                                                   " not allowed");
-                               replace.flags |= OPT_COMMAND;
+                               replace->command = c;
+                               if (replace->flags & OPT_COMMAND)
+                                       ebt_print_error2("Multiple commands are not allowed");
+                               replace->flags |= OPT_COMMAND;
+                               if (replace->flags & OPT_ZERO)
+                                       goto print_zero;
                        }
-                       ebt_get_kernel_table(&replace, table, 0);
+
+#ifdef SILENT_DAEMON
+                       if (c== 'L' && exec_style == EXEC_STYLE_DAEMON)
+                               ebt_print_error2("-L not supported in daemon mode not supported in daemon mode");
+#endif
+
+                       if (!(replace->flags & OPT_KERNELDATA))
+                               ebt_get_kernel_table(replace, 0);
                        i = -1;
-                       if (optarg) {
-                               if ( (i = ebt_get_chainnr(&replace, optarg)) ==
-                                     -1 )
-                                       ebt_print_error("Bad chain");
-                       } else
-                               if (optind < argc && argv[optind][0] != '-') {
-                                       if ((i = ebt_get_chainnr(&replace,
-                                           argv[optind])) == -1)
-                                               ebt_print_error("Bad chain");
-                                       optind++;
-                               }
+                       if (optind < argc && argv[optind][0] != '-') {
+                               if ((i = ebt_get_chainnr(replace, argv[optind])) == -1)
+                                       ebt_print_error2("Bad chain");
+                               optind++;
+                       }
                        if (i != -1) {
                                if (c == 'Z')
                                        zerochain = i;
                                else
-                                       replace.selected_chain = i;
+                                       replace->selected_chain = i;
                        }
                        break;
-
-               case 'V': /* version */
-                       replace.command = 'V';
-                       if (replace.flags & OPT_COMMAND)
-                               ebt_print_error("Multiple commands not "
-                                               "allowed");
+               case 'V': /* Version */
+                       replace->command = 'V';
+                       if (OPT_COMMANDS)
+                               ebt_print_error2("Multiple commands are not allowed");
+                       if (exec_style == EXEC_STYLE_DAEMON)
+                               ebt_print_error2(PROGNAME" v"PROGVERSION" ("PROGDATE")\n");
                        PRINT_VERSION;
                        exit(0);
-
-               case 'M': /* modprobe */
-                       if (replace.command != 'h')
-                               ebt_print_error("Please put the -M option "
-                                               "earlier");
+               case 'M': /* Modprobe */
+                       if (OPT_COMMANDS)
+                               ebt_print_error2("Please put the -M option earlier");
                        ebt_modprobe = optarg;
                        break;
-
-               case 'h': /* help */
-                       if (replace.flags & OPT_COMMAND)
-                               ebt_print_error("Multiple commands not "
-                                               "allowed");
-                       replace.command = 'h';
-                       /*
-                        * All other arguments should be extension names
-                        */
+               case 'h': /* Help */
+                       if (exec_style == EXEC_STYLE_DAEMON)
+                               ebt_print_error2("-h not supported in daemon mode");
+                       if (OPT_COMMANDS)
+                               ebt_print_error2("Multiple commands are not allowed");
+                       replace->command = 'h';
+
+                       /* All other arguments should be extension names */
                        while (optind < argc) {
                                struct ebt_u_match *m;
                                struct ebt_u_watcher *w;
 
-                               if (!strcasecmp("list_extensions",
-                                  argv[optind]))
+                               if (!strcasecmp("list_extensions", argv[optind])) {
                                        ebt_list_extensions();
-                                       
+                                       exit(0);
+                               }
                                if ((m = ebt_find_match(argv[optind])))
                                        ebt_add_match(new_entry, m);
                                else if ((w = ebt_find_watcher(argv[optind])))
                                        ebt_add_watcher(new_entry, w);
                                else {
                                        if (!(t = ebt_find_target(argv[optind])))
-                                               ebt_print_error("Extension %s "
-                                                  "not found", argv[optind]);
-                                       if (replace.flags & OPT_JUMP)
-                                               ebt_print_error("Sorry, you "
-                                                "can only see help for one "
-                                                "target extension each time");
-                                       replace.flags |= OPT_JUMP;
-                                       new_entry->t =
-                                          (struct ebt_entry_target *)t;
+                                               ebt_print_error2("Extension %s not found", argv[optind]);
+                                       if (replace->flags & OPT_JUMP)
+                                               ebt_print_error2("Sorry, you can only see help for one target extension at a time");
+                                       replace->flags |= OPT_JUMP;
+                                       new_entry->t = (struct ebt_entry_target *)t;
                                }
                                optind++;
                        }
                        break;
-
-               case 't': /* table */
-                       if (replace.command != 'h')
-                               ebt_print_error("Please put the -t option "
-                                               "first");
-                       ebt_check_option(&replace.flags, OPT_TABLE);
+               case 't': /* Table */
+                       if (replace->command != 'h')
+                               ebt_print_error2("Please put the -t option first");
+                       ebt_check_option2(&(replace->flags), OPT_TABLE);
                        if (strlen(optarg) > EBT_TABLE_MAXNAMELEN - 1)
-                               ebt_print_error("Table name too long");
-                       strcpy(replace.name, optarg);
+                               ebt_print_error2("Table name too long");
+                       strcpy(replace->name, optarg);
                        break;
-
-               case 'i': /* input interface */
-               case 2  : /* logical input interface */
-               case 'o': /* output interface */
-               case 3  : /* logical output interface */
-               case 'j': /* target */
-               case 'p': /* net family protocol */
-               case 's': /* source mac */
-               case 'd': /* destination mac */
-                       if ((replace.flags & OPT_COMMAND) == 0)
-                               ebt_print_error("No command specified");
-                       if ( replace.command != 'A' &&
-                          replace.command != 'D' && replace.command != 'I')
-                               ebt_print_error("Command and option do not "
-                                               "match");
+               case 'i': /* Input interface */
+               case 2  : /* Logical input interface */
+               case 'o': /* Output interface */
+               case 3  : /* Logical output interface */
+               case 'j': /* Target */
+               case 'p': /* Net family protocol */
+               case 's': /* Source mac */
+               case 'd': /* Destination mac */
+                       if (!OPT_COMMANDS)
+                               ebt_print_error2("No command specified");
+                       if (replace->command != 'A' && replace->command != 'D' && replace->command != 'I')
+                               ebt_print_error2("Command and option do not match");
                        if (c == 'i') {
-                               ebt_check_option(&replace.flags, OPT_IN);
-                               if (replace.selected_chain > 2 &&
-                                  replace.selected_chain < NF_BR_BROUTING)
-                                       ebt_print_error("Use in-interface "
-                                          "only in "
-                                          "INPUT, FORWARD, PREROUTING and"
-                                          "BROUTING chains");
-                               if (ebt_check_inverse(optarg))
+                               ebt_check_option2(&(replace->flags), OPT_IN);
+                               if (replace->selected_chain > 2 && replace->selected_chain < NF_BR_BROUTING)
+                                       ebt_print_error2("Use -i only in INPUT, FORWARD, PREROUTING and BROUTING chains");
+                               if (ebt_check_inverse2(optarg))
                                        new_entry->invflags |= EBT_IIN;
 
-                               if (optind > argc)
-                                       ebt_print_error("No in-interface "
-                                                   "specified");
-                               if (strlen(argv[optind - 1]) >= IFNAMSIZ)
-                                       print_if_l_error;
-                               strcpy(new_entry->in, argv[optind - 1]);
-                               parse_iface(new_entry->in, "-i");
+                               if (strlen(optarg) >= IFNAMSIZ)
+                                       ebt_print_error2("Interface name length must be less than %d", IFNAMSIZ);
+                               strcpy(new_entry->in, optarg);
+                               if (parse_iface(new_entry->in, "-i"))
+                                       return -1;
                                break;
-                       }
-                       if (c == 2) {
-                               ebt_check_option(&replace.flags, OPT_LOGICALIN);
-                               if (replace.selected_chain > 2 &&
-                                  replace.selected_chain < NF_BR_BROUTING)
-                                       ebt_print_error("Use logical "
-                                          "in-interface "
-                                          "only in INPUT, FORWARD, "
-                                          "PREROUTING and BROUTING chains");
-                               if (ebt_check_inverse(optarg))
+                       } else if (c == 2) {
+                               ebt_check_option2(&(replace->flags), OPT_LOGICALIN);
+                               if (replace->selected_chain > 2 && replace->selected_chain < NF_BR_BROUTING)
+                                       ebt_print_error2("Use --logical-in only in INPUT, FORWARD, PREROUTING and BROUTING chains");
+                               if (ebt_check_inverse2(optarg))
                                        new_entry->invflags |= EBT_ILOGICALIN;
 
-                               if (optind > argc)
-                                       ebt_print_error("No logical "
-                                          "in-interface specified");
-                               if (strlen(argv[optind - 1]) >= IFNAMSIZ)
-                                       print_if_l_error;
-                               strcpy(new_entry->logical_in, argv[optind - 1]);
-                               parse_iface(new_entry->logical_in,
-                                           "--logical-in");
+                               if (strlen(optarg) >= IFNAMSIZ)
+                                       ebt_print_error2("Interface name length must be less than %d", IFNAMSIZ);
+                               strcpy(new_entry->logical_in, optarg);
+                               if (parse_iface(new_entry->logical_in, "--logical-in"))
+                                       return -1;
                                break;
-                       }
-                       if (c == 'o') {
-                               ebt_check_option(&replace.flags, OPT_OUT);
-                               if (replace.selected_chain < 2)
-                                       ebt_print_error("Use out-interface "
-                                          "only in OUTPUT, FORWARD and "
-                                          "POSTROUTING chains");
-                               if (ebt_check_inverse(optarg))
+                       } else if (c == 'o') {
+                               ebt_check_option2(&(replace->flags), OPT_OUT);
+                               if (replace->selected_chain < 2 || replace->selected_chain == NF_BR_BROUTING)
+                                       ebt_print_error2("Use -o only in OUTPUT, FORWARD and POSTROUTING chains");
+                               if (ebt_check_inverse2(optarg))
                                        new_entry->invflags |= EBT_IOUT;
 
-                               if (optind > argc)
-                                       ebt_print_error("No out-interface "
-                                                   "specified");
-
-                               if (strlen(argv[optind - 1]) >= IFNAMSIZ)
-                                       print_if_l_error;
-                               strcpy(new_entry->out, argv[optind - 1]);
-                               parse_iface(new_entry->out, "-o");
+                               if (strlen(optarg) >= IFNAMSIZ)
+                                       ebt_print_error2("Interface name length must be less than %d", IFNAMSIZ);
+                               strcpy(new_entry->out, optarg);
+                               if (parse_iface(new_entry->out, "-o"))
+                                       return -1;
                                break;
-                       }
-                       if (c == 3) {
-                               ebt_check_option(&replace.flags,
-                                                OPT_LOGICALOUT);
-                               if (replace.selected_chain < 2)
-                                       ebt_print_error("Use logical "
-                                          "out-interface "
-                                          "only in OUTPUT, FORWARD and "
-                                          "POSTROUTING chains");
-                               if (ebt_check_inverse(optarg))
+                       } else if (c == 3) {
+                               ebt_check_option2(&(replace->flags), OPT_LOGICALOUT);
+                               if (replace->selected_chain < 2)
+                                       ebt_print_error2("Use --logical-out only in OUTPUT, FORWARD and POSTROUTING chains");
+                               if (ebt_check_inverse2(optarg))
                                        new_entry->invflags |= EBT_ILOGICALOUT;
 
-                               if (optind > argc)
-                                       ebt_print_error("No logical "
-                                          "out-interface specified");
-
-                               if (strlen(argv[optind - 1]) >= IFNAMSIZ)
-                                       print_if_l_error;
-                               strcpy(new_entry->logical_out,
-                                  argv[optind - 1]);
-                               parse_iface(new_entry->logical_out,
-                                        "--logical-out");
+                               if (strlen(optarg) >= IFNAMSIZ)
+                                       ebt_print_error2("Interface name length must be less than %d", IFNAMSIZ);
+                               strcpy(new_entry->logical_out, optarg);
+                               if (parse_iface(new_entry->logical_out, "--logical-out"))
+                                       return -1;    
                                break;
-                       }
-                       if (c == 'j') {
-                               ebt_check_option(&replace.flags, OPT_JUMP);
+                       } else if (c == 'j') {
+                               ebt_check_option2(&(replace->flags), OPT_JUMP);
                                for (i = 0; i < NUM_STANDARD_TARGETS; i++)
-                                       if (!strcmp(optarg,
-                                          ebt_standard_targets[i])) {
-                                               t = ebt_find_target(
-                                                  EBT_STANDARD_TARGET);
-                                               ((struct ebt_standard_target *)
-                                                  t->t)->verdict = -i - 1;
+                                       if (!strcmp(optarg, ebt_standard_targets[i])) {
+                                               t = ebt_find_target(EBT_STANDARD_TARGET);
+                                               ((struct ebt_standard_target *) t->t)->verdict = -i - 1;
                                                break;
                                        }
-                               if (-i - 1 == EBT_RETURN) {
-                                       if (replace.selected_chain <
-                                           NF_BR_NUMHOOKS)
-                                               ebt_print_error("Return target"
-                                               " only for user defined "
-                                               "chains");
-                               }
-                               if (i != NUM_STANDARD_TARGETS)
+                               if (-i - 1 == EBT_RETURN && replace->selected_chain < NF_BR_NUMHOOKS) {
+                                       ebt_print_error2("Return target only for user defined chains");
+                               } else if (i != NUM_STANDARD_TARGETS)
                                        break;
-                               if ((i = ebt_get_chainnr(&replace, optarg)) !=
-                                    -1) {
+
+                               if ((i = ebt_get_chainnr(replace, optarg)) != -1) {
                                        if (i < NF_BR_NUMHOOKS)
-                                               ebt_print_error("don't jump"
-                                                 " to a standard chain");
+                                               ebt_print_error2("Don't jump to a standard chain");
                                        t = ebt_find_target(EBT_STANDARD_TARGET);
-                                       ((struct ebt_standard_target *)
-                                          t->t)->verdict = i - NF_BR_NUMHOOKS;
+                                       ((struct ebt_standard_target *) t->t)->verdict = i - NF_BR_NUMHOOKS;
                                        break;
                                } else {
-                                       /*
-                                        * must be an extension then
-                                        */
+                                       /* Must be an extension then */
                                        struct ebt_u_target *t;
 
                                        t = ebt_find_target(optarg);
-                                       /*
-                                        * -j standard not allowed either
-                                        */
-                                       if (!t || t ==
-                                          (struct ebt_u_target *)new_entry->t)
-                                               ebt_print_error("Illegal "
-                                                  "target name");
-                                       new_entry->t =
-                                          (struct ebt_entry_target *)t;
+                                       /* -j standard not allowed either */
+                                       if (!t || t == (struct ebt_u_target *)new_entry->t)
+                                               ebt_print_error2("Illegal target name");
+                                       new_entry->t = (struct ebt_entry_target *)t;
+                                       ebt_find_target(EBT_STANDARD_TARGET)->used = 0;
+                                       t->used = 1;
                                }
                                break;
-                       }
-                       if (c == 's') {
-                               ebt_check_option(&replace.flags, OPT_SOURCE);
-                               if (ebt_check_inverse(optarg))
+                       } else if (c == 's') {
+                               ebt_check_option2(&(replace->flags), OPT_SOURCE);
+                               if (ebt_check_inverse2(optarg))
                                        new_entry->invflags |= EBT_ISOURCE;
 
-                               if (optind > argc)
-                                       ebt_print_error("No source mac "
-                                                   "specified");
-                               if (ebt_get_mac_and_mask(argv[optind - 1],
-                                  new_entry->sourcemac, new_entry->sourcemsk))
-                                       ebt_print_error("Problem with "
-                                          "specified source mac");
+                               if (ebt_get_mac_and_mask(optarg, new_entry->sourcemac, new_entry->sourcemsk))
+                                       ebt_print_error2("Problem with specified source mac");
                                new_entry->bitmask |= EBT_SOURCEMAC;
                                break;
-                       }
-                       if (c == 'd') {
-                               ebt_check_option(&replace.flags, OPT_DEST);
-                               if (ebt_check_inverse(optarg))
+                       } else if (c == 'd') {
+                               ebt_check_option2(&(replace->flags), OPT_DEST);
+                               if (ebt_check_inverse2(optarg))
                                        new_entry->invflags |= EBT_IDEST;
 
-                               if (optind > argc)
-                                       ebt_print_error("No destination mac "
-                                                   "specified");
-                               if (ebt_get_mac_and_mask(argv[optind - 1],
-                                  new_entry->destmac, new_entry->destmsk))
-                                       ebt_print_error("Problem with "
-                                          "specified destination mac");
+                               if (ebt_get_mac_and_mask(optarg, new_entry->destmac, new_entry->destmsk))
+                                       ebt_print_error2("Problem with specified destination mac");
                                new_entry->bitmask |= EBT_DESTMAC;
                                break;
                        }
-                       ebt_check_option(&replace.flags, OPT_PROTOCOL);
-                       if (ebt_check_inverse(optarg))
+                       ebt_check_option2(&(replace->flags), OPT_PROTOCOL);
+                       if (ebt_check_inverse2(optarg))
                                new_entry->invflags |= EBT_IPROTO;
 
-                       if (optind > argc)
-                               ebt_print_error("No protocol specified");
                        new_entry->bitmask &= ~((unsigned int)EBT_NOPROTO);
-                       i = strtol(argv[optind - 1], &buffer, 16);
+                       i = strtol(optarg, &buffer, 16);
                        if (*buffer == '\0' && (i < 0 || i > 0xFFFF))
-                               ebt_print_error("Problem with the specified "
-                                           "protocol");
-                       new_entry->ethproto = i;
+                               ebt_print_error2("Problem with the specified protocol");
                        if (*buffer != '\0') {
                                struct ethertypeent *ent;
 
-                               if (!strcasecmp(argv[optind - 1], "LENGTH")) {
+                               if (!strcasecmp(optarg, "LENGTH")) {
                                        new_entry->bitmask |= EBT_802_3;
                                        break;
                                }
-                               ent = getethertypebyname(argv[optind - 1]);
+                               ent = getethertypebyname(optarg);
                                if (!ent)
-                                       print_epoto_error(argv[optind - 1]);
+                                       ebt_print_error2("Problem with the specified Ethernet protocol (%s), perhaps "_PATH_ETHERTYPES " is missing", optarg)
                                new_entry->ethproto = ent->e_ethertype;
-                       }
-                       if (new_entry->ethproto < 1536 &&
-                          !(new_entry->bitmask & EBT_802_3))
-                               ebt_print_error("Sorry, protocols have values "
-                                               "above or equal to 0x0600");
-                       break;
+                       } else
+                               new_entry->ethproto = i;
 
+                       if (new_entry->ethproto < 0x0600)
+                               ebt_print_error2("Sorry, protocols have values above or equal to 0x0600");
+                       break;
                case 4  : /* Lc */
-                       ebt_check_option(&replace.flags, LIST_C);
-                       if (replace.command != 'L')
+                       if (exec_style == EXEC_STYLE_DAEMON)
+                               ebt_print_error2("--Lc is not supported in daemon mode");
+                       ebt_check_option2(&(replace->flags), LIST_C);
+                       if (replace->command != 'L')
                                ebt_print_error("Use --Lc with -L");
-                       if (replace.flags & LIST_X)
-                               ebt_print_error("--Lx not compatible with "
-                                               "--Lc");
-                       replace.flags |= LIST_C;
+                       if (replace->flags & LIST_X)
+                               ebt_print_error2("--Lx is not compatible with --Lc");
+                       replace->flags |= LIST_C;
                        break;
                case 5  : /* Ln */
-                       ebt_check_option(&replace.flags, LIST_N);
-                       if (replace.command != 'L')
-                               ebt_print_error("Use --Ln with -L");
-                       if (replace.flags & LIST_X)
-                               ebt_print_error("--Lx not compatible with "
-                                               "--Ln");
-                       replace.flags |= LIST_N;
+                       if (exec_style == EXEC_STYLE_DAEMON)
+                               ebt_print_error2("--Ln is not supported in daemon mode");
+                       ebt_check_option2(&(replace->flags), LIST_N);
+                       if (replace->command != 'L')
+                               ebt_print_error2("Use --Ln with -L");
+                       if (replace->flags & LIST_X)
+                               ebt_print_error2("--Lx is not compatible with --Ln");
+                       replace->flags |= LIST_N;
                        break;
                case 6  : /* Lx */
-                       ebt_check_option(&replace.flags, LIST_X);
-                       if (replace.command != 'L')
-                               ebt_print_error("Use --Lx with -L");
-                       if (replace.flags & LIST_C)
-                               ebt_print_error("--Lx not compatible with "
-                                               "--Lc");
-                       if (replace.flags & LIST_N)
-                               ebt_print_error("--Lx not compatible with "
-                                               "--Ln");
-                       replace.flags |= LIST_X;
+                       if (exec_style == EXEC_STYLE_DAEMON)
+                               ebt_print_error2("--Lx is not supported in daemon mode");
+                       ebt_check_option2(&(replace->flags), LIST_X);
+                       if (replace->command != 'L')
+                               ebt_print_error2("Use --Lx with -L");
+                       if (replace->flags & LIST_C)
+                               ebt_print_error2("--Lx is not compatible with --Lc");
+                       if (replace->flags & LIST_N)
+                               ebt_print_error2("--Lx is not compatible with --Ln");
+                       replace->flags |= LIST_X;
                        break;
                case 12 : /* Lmac2 */
-                       ebt_check_option(&replace.flags, LIST_MAC2);
-                       if (replace.command != 'L')
-                               ebt_print_error("Use --Lmac2 with -L");
-                       replace.flags |= LIST_MAC2;
+                       if (exec_style == EXEC_STYLE_DAEMON)
+                               ebt_print_error("--Lmac2 is not supported in daemon mode");
+                       ebt_check_option2(&(replace->flags), LIST_MAC2);
+                       if (replace->command != 'L')
+                               ebt_print_error2("Use --Lmac2 with -L");
+                       replace->flags |= LIST_MAC2;
                        break;
                case 8 : /* atomic-commit */
-                       replace.command = c;
-                       if (replace.flags & OPT_COMMAND)
-                               ebt_print_error("Multiple commands not "
-                                               "allowed");
-                       replace.flags |= OPT_COMMAND;
-                       if (!replace.filename)
-                               ebt_print_error("No atomic file specified");
-                       /*
-                        * get the information from the file
-                        */
-                       ebt_get_table(&replace, 0);
-                       /*
-                        * we don't want the kernel giving us its counters,
+                       if (exec_style == EXEC_STYLE_DAEMON)
+                               ebt_print_error2("--atomic-commit is not supported in daemon mode");
+                       replace->command = c;
+                       if (OPT_COMMANDS)
+                               ebt_print_error2("Multiple commands are not allowed");
+                       replace->flags |= OPT_COMMAND;
+                       if (!replace->filename)
+                               ebt_print_error2("No atomic file specified");
+                       /* Get the information from the file */
+                       ebt_get_table(replace, 0);
+                       /* We don't want the kernel giving us its counters,
                         * they would overwrite the counters extracted from
-                        * the file
-                        */
-                       replace.num_counters = 0;
-                       /*
-                        * make sure the table will be written to the kernel
-                        */
-                       free(replace.filename);
-                       replace.filename = NULL;
+                        * the file */
+                       replace->num_counters = 0;
+                       /* Make sure the table will be written to the kernel */
+                       free(replace->filename);
+                       replace->filename = NULL;
                        break;
                case 7 : /* atomic-init */
                case 10: /* atomic-save */
                case 11: /* init-table */
-                       replace.command = c;
-                       if (replace.flags & OPT_COMMAND)
-                               ebt_print_error("Multiple commands not "
-                                               "allowed");
-                       if (c != 11 && !replace.filename)
-                               ebt_print_error("No atomic file specified");
-                       replace.flags |= OPT_COMMAND;
+                       if (exec_style == EXEC_STYLE_DAEMON) {
+                               if (c == 7) {
+                                       ebt_print_error2("--atomic-init is not supported in daemon mode");
+                               } else if (c == 10)
+                                       ebt_print_error2("--atomic-save is not supported in daemon mode");
+                               ebt_print_error2("--init-table is not supported in daemon mode");
+                       }
+                       replace->command = c;
+                       if (OPT_COMMANDS)
+                               ebt_print_error2("Multiple commands are not allowed");
+                       if (c != 11 && !replace->filename)
+                               ebt_print_error2("No atomic file specified");
+                       replace->flags |= OPT_COMMAND;
                        {
-                               char *tmp = replace.filename;
+                               char *tmp = replace->filename;
                                int init = 1;
 
                                if (c == 10)
                                        init = 0;
-                               tmp = replace.filename;
-                               /* get the kernel table */
-                               replace.filename = NULL;
-                               ebt_get_kernel_table(&replace, table, init);
-                               replace.filename = tmp;
+                               /* Get the kernel table */
+                               replace->filename = NULL;
+                               ebt_get_kernel_table(replace, init);
+                               replace->filename = tmp;
                        }
                        break;
                case 9 : /* atomic */
-                       if (replace.flags & OPT_COMMAND)
-                               ebt_print_error("--atomic has to come before"
-                                               " the command");
-                       /* another possible memory leak here */
-                       replace.filename = (char *)malloc(strlen(optarg) + 1);
-                       strcpy(replace.filename, optarg);
+                       if (exec_style == EXEC_STYLE_DAEMON)
+                               ebt_print_error2("--atomic is not supported in daemon mode");
+                       if (OPT_COMMANDS)
+                               ebt_print_error2("--atomic has to come before the command");
+                       /* A possible memory leak here, but this is not
+                        * executed in daemon mode */
+                       replace->filename = (char *)malloc(strlen(optarg) + 1);
+                       strcpy(replace->filename, optarg);
                        break;
                case 1 :
                        if (!strcmp(optarg, "!"))
-                               ebt_check_inverse(optarg);
+                               ebt_check_inverse2(optarg);
                        else
-                               ebt_print_error("Bad argument : %s", optarg);
-                       /*
-                        * ebt_check_inverse() did optind++
-                        */
+                               ebt_print_error2("Bad argument : %s", optarg);
+                       /* ebt_check_inverse() did optind++ */
                        optind--;
                        continue;
                default:
-                       /*
-                        * is it a target option?
-                        */
+                       /* Is it a target option? */
                        t = (struct ebt_u_target *)new_entry->t;
-                       if ((t->parse(c - t->option_offset, argv, argc,
-                          new_entry, &t->flags, &t->t)))
+                       if ((t->parse(c - t->option_offset, argv, argc, new_entry, &t->flags, &t->t)))
                                goto check_extension;
 
-                       /*
-                        * is it a match_option?
-                        */
+                       /* Is it a match_option? */
                        for (m = ebt_matches; m; m = m->next)
-                               if (m->parse(c - m->option_offset, argv,
-                                  argc, new_entry, &m->flags, &m->m))
+                               if (m->parse(c - m->option_offset, argv, argc, new_entry, &m->flags, &m->m))
                                        break;
 
                        if (m != NULL) {
@@ -1105,109 +985,107 @@ handle_P:
                                goto check_extension;
                        }
 
-                       /*
-                        * is it a watcher option?
-                        */
+                       /* Is it a watcher option? */
                        for (w = ebt_watchers; w; w = w->next)
-                               if (w->parse(c-w->option_offset, argv,
-                                  argc, new_entry, &w->flags, &w->w))
+                               if (w->parse(c-w->option_offset, argv, argc, new_entry, &w->flags, &w->w))
                                        break;
 
                        if (w == NULL)
-                               ebt_print_error("Unknown argument");
+                               ebt_print_error2("Unknown argument: '%s', %c, '%c'", argv[optind - 1], (char)optopt, (char)c);
                        if (w->used == 0) {
                                ebt_add_watcher(new_entry, w);
                                w->used = 1;
                        }
 check_extension:
-                       if (replace.command != 'A' && replace.command != 'I' &&
-                          replace.command != 'D')
-                               ebt_print_error("Extensions only for -A, "
-                                               "-I and -D");
+                       if (replace->command != 'A' && replace->command != 'I' && replace->command != 'D')
+                               ebt_print_error2("Extensions only for -A, -I and -D");
                }
                ebt_invert = 0;
        }
 
-       if ( !table && !(table = ebt_find_table(replace.name)) )
-               ebt_print_error("Bad table name");
+       /* Just in case we didn't catch an error */
+       if (ebt_errormsg[0] != '\0')
+               return -1;
 
-       if ( (replace.flags & OPT_COMMAND) && replace.command != 'L' &&
-          replace.flags & OPT_ZERO )
-               ebt_print_error("Command -Z only allowed together with "
-                               "command -L");
+       if (!(table = ebt_find_table(replace->name)))
+               ebt_print_error2("Bad table name");
 
-       /*
-        * do this after parsing everything, so we can print specific info
-        */
-       if (replace.command == 'h' && !(replace.flags & OPT_ZERO))
+       if (replace->command == 'h' && !(replace->flags & OPT_ZERO))
                print_help();
 
-       /*
-        * do the final checks
-        */
-       if (replace.command == 'A' || replace.command == 'I' ||
-          replace.command == 'D') {
-               /*
-                * this will put the hook_mask right for the chains
-                */
-               ebt_check_for_loops(&replace);
-               entries = ebt_to_chain(&replace);
+       /* Do the final checks */
+       if (replace->command == 'A' || replace->command == 'I' ||
+          replace->command == 'D') {
+               /* This will put the hook_mask right for the chains */
+               ebt_check_for_loops(replace);
+               if (ebt_errormsg[0] != '\0')
+                       return -1;
+               entries = ebt_to_chain(replace);
                m_l = new_entry->m_list;
                w_l = new_entry->w_list;
                t = (struct ebt_u_target *)new_entry->t;
                while (m_l) {
                        m = (struct ebt_u_match *)(m_l->m);
-                       m->final_check(new_entry, m->m, replace.name,
+                       m->final_check(new_entry, m->m, replace->name,
                           entries->hook_mask, 0);
+                       if (ebt_errormsg[0] != '\0')
+                               return -1;
                        m_l = m_l->next;
                }
                while (w_l) {
                        w = (struct ebt_u_watcher *)(w_l->w);
-                       w->final_check(new_entry, w->w, replace.name,
+                       w->final_check(new_entry, w->w, replace->name,
                           entries->hook_mask, 0);
+                       if (ebt_errormsg[0] != '\0')
+                               return -1;
                        w_l = w_l->next;
                }
-               t->final_check(new_entry, t->t, replace.name,
+               t->final_check(new_entry, t->t, replace->name,
                   entries->hook_mask, 0);
+               if (ebt_errormsg[0] != '\0')
+                       return -1;
        }
-       /*
-        * so, the extensions can work with the host endian
-        * the kernel does not have to do this of course
-        */
+       /* So, the extensions can work with the host endian.
+        * The kernel does not have to do this of course */
        new_entry->ethproto = htons(new_entry->ethproto);
 
-       if (replace.command == 'P') {
-               if (replace.selected_chain < NF_BR_NUMHOOKS &&
-                  policy == EBT_RETURN)
-                       ebt_print_error("Policy RETURN only allowed for user "
-                                       "defined chains");
-               ebt_change_policy(&replace, policy);
-       } else if (replace.command == 'L') {
+       if (replace->command == 'P') {
+               if (replace->selected_chain < NF_BR_NUMHOOKS && policy == EBT_RETURN)
+                       ebt_print_error2("Policy RETURN only allowed for user defined chains");
+               ebt_change_policy(replace, policy);
+               if (ebt_errormsg[0] != '\0')
+                       return -1;
+       } else if (replace->command == 'L') {
                list_rules();
-               if (replace.flags & OPT_ZERO) {
-                       replace.selected_chain = zerochain;
-                       ebt_zero_counters(&replace);
-               } else
+               if (!(replace->flags & OPT_ZERO) && exec_style == EXEC_STYLE_PRG)
                        exit(0);
        }
-       if (replace.flags & OPT_ZERO) {
-               replace.selected_chain = zerochain;
-               ebt_zero_counters(&replace);
-       } else if (replace.command == 'F')
-               ebt_flush_chains(&replace);
-       else if (replace.command == 'A' || replace.command == 'I') {
-               ebt_add_rule(&replace, new_entry, rule_nr);
-               ebt_check_for_loops(&replace);
-               /*
-                * do the final_check(), for all entries
-                * needed when adding a rule that has a chain target
-                */
+       if (replace->flags & OPT_ZERO) {
+               replace->selected_chain = zerochain;
+               ebt_zero_counters(replace);
+       } else if (replace->command == 'F') {
+               ebt_flush_chains(replace);
+       } else if (replace->command == 'A' || replace->command == 'I') {
+               ebt_add_rule(replace, new_entry, rule_nr);
+               if (ebt_errormsg[0] != '\0')
+                       return -1;
+               /* Makes undoing the add easier (jumps to delete_the_rule) */
+               if (rule_nr <= 0)
+                       rule_nr--;
+               rule_nr_end = rule_nr;
+
+               ebt_check_for_loops(replace);
+               if (ebt_errormsg[0] != '\0')
+                       goto delete_the_rule;
+
+               /* Do the final_check(), for all entries.
+                * This is needed when adding a rule that has a chain target */
                i = -1;
                while (1) {
                        struct ebt_u_entry *e;
 
                        i++;
-                       entries = ebt_nr_to_chain(&replace, i);
+                       entries = ebt_nr_to_chain(replace, i);
                        if (!entries) {
                                if (i < NF_BR_NUMHOOKS)
                                        continue;
@@ -1216,28 +1094,33 @@ check_extension:
                        }
                        e = entries->entries;
                        while (e) {
-                               /*
-                                * userspace extensions use host endian
-                                */
+                               /* Userspace extensions use host endian */
                                e->ethproto = ntohs(e->ethproto);
-                               ebt_do_final_checks(&replace, e, entries);
+                               ebt_do_final_checks(replace, e, entries);
+                               if (ebt_errormsg[0] != '\0')
+                                       goto delete_the_rule;
                                e->ethproto = htons(e->ethproto);
                                e = e->next;
                        }
                }
-       } else if (replace.command == 'D')
-               ebt_delete_rule(&replace, new_entry, rule_nr, rule_nr_end);
-       /*
-        * commands -N, -E, -X, --atomic-commit, --atomic-commit, --atomic-save,
-        * --init-table fall through
-        */
-
+               /* Don't reuse the added rule */
+               new_entry = NULL;
+       } else if (replace->command == 'D')
+delete_the_rule: /* This needs to be followed by a check on ebt_errormsg[0] */
+               ebt_delete_rule(replace, new_entry, rule_nr, rule_nr_end);
+       /* Commands -N, -E, -X, --atomic-commit, --atomic-commit, --atomic-save,
+        * --init-table fall through */
+
+       if (ebt_errormsg[0] != '\0')
+               return -1;
        if (table->check)
-               table->check(&replace);
+               table->check(replace);
 
-       ebt_deliver_table(&replace);
+       if (exec_style == EXEC_STYLE_PRG) {/* Implies ebt_errormsg[0] == '\0' */
+               ebt_deliver_table(replace);
 
-       if (replace.counterchanges)
-               ebt_deliver_counters(&replace);
+               if (replace->counterchanges)
+                       ebt_deliver_counters(replace, exec_style);
+       }
        return 0;
 }
diff --git a/ebtablesd.c b/ebtablesd.c
new file mode 100644 (file)
index 0000000..1f60791
--- /dev/null
@@ -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;
+}
diff --git a/ebtablesu.c b/ebtablesu.c
new file mode 100644 (file)
index 0000000..234d4f6
--- /dev/null
@@ -0,0 +1,61 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+int main(int argc, char *argv[])
+{
+       char *arguments, *pos;
+       int i, writefd, len = 0;
+
+       if ((writefd = open(EBTD_PIPE, O_WRONLY, 0)) == -1) {
+               perror("open");
+               return -1;
+       }
+
+       if (argc > EBTD_ARGC_MAX) {
+               printf("ebtablesd accepts at most %d arguments, %d arguments "
+                      "were specified. If you need this many arguments, "
+                      "recompile this tool with a higher value for "
+                      "EBTD_ARGC_MAX.\n", EBTD_ARGC_MAX - 1, argc - 1);
+               return -1;
+       } else if (argc == 1) {
+               printf("At least one argument is needed.\n");
+               return -1;
+       }
+
+       for (i = 0; i < argc; i++)
+               len += strlen(argv[i]);
+       /* Don't forget '\0' */
+       len += argc;
+       if (len > EBTD_CMDLINE_MAXLN) {
+               printf("ebtablesd has a maximum command line argument length "
+                      "of %d, an argument length of %d was received. If a "
+                      "smaller length is unfeasible, recompile this tool "
+                      "with a higher value for EBTD_CMDLINE_MAXLN.\n",
+                      EBTD_CMDLINE_MAXLN, len);
+               return -1;
+       }
+
+       if (!(arguments = (char *)malloc(len))) {
+               printf("ebtablesu: out of memory.\n");
+               return -1;
+       }
+
+       pos = arguments;
+       for (i = 0; i < argc; i++) {
+               strcpy(pos, argv[i]);
+               pos += strlen(argv[i]) + 1;
+       }
+
+       *(pos-1) = '\n';
+       if (write(writefd, arguments, len) == -1) {
+               perror("write");
+               return -1;
+       }
+       return 0;
+}
index 6d9233e..c81e687 100644 (file)
@@ -209,7 +209,7 @@ static int parse(int c, char **argv, int argc, const struct ebt_u_entry *entry,
                        ipinfo->invflags |= EBT_IP_PROTO;
                if (optind > argc)
                        ebt_print_error("Missing IP protocol argument");
-               (unsigned char) i = strtoul(argv[optind - 1], &end, 10);
+               i = strtoul(argv[optind - 1], &end, 10);
                if (*end != '\0') {
                        struct protoent *pe;
 
index 1c5c32b..6dcd50d 100644 (file)
@@ -203,15 +203,15 @@ static int compare(const struct ebt_entry_match* m1, const struct ebt_entry_matc
 
 static struct ebt_u_match limit_match =
 {
-       .name           EBT_LIMIT_MATCH,
-       .size           sizeof(struct ebt_limit_info),
-       .help           print_help,
-       .init           init,
-       .parse          parse,
-       .final_check    final_check,
-       .print          print,
-       .compare        compare,
-       .extra_ops      opts,
+       .name           EBT_LIMIT_MATCH,
+       .size           sizeof(struct ebt_limit_info),
+       .help           print_help,
+       .init           init,
+       .parse          parse,
+       .final_check    final_check,
+       .print          print,
+       .compare        compare,
+       .extra_ops      opts,
 };
 
 void _init(void)
index b4e1d38..0c94a66 100644 (file)
@@ -141,8 +141,7 @@ parse(int c,
                ebt_check_option(flags, OPT_VLAN_ID);
                CHECK_INV_FLAG(EBT_VLAN_ID);
                CHECK_IF_MISSING_VALUE;
-               (unsigned short) local.id =
-                   strtoul(argv[optind - 1], &end, 10);
+               local.id = strtoul(argv[optind - 1], &end, 10);
                CHECK_RANGE(local.id > 4094 || *end != '\0');
                vlaninfo->id = local.id;
                SET_BITMASK(EBT_VLAN_ID);
@@ -152,8 +151,7 @@ parse(int c,
                ebt_check_option(flags, OPT_VLAN_PRIO);
                CHECK_INV_FLAG(EBT_VLAN_PRIO);
                CHECK_IF_MISSING_VALUE;
-               (unsigned char) local.prio =
-                   strtoul(argv[optind - 1], &end, 10);
+               local.prio = strtoul(argv[optind - 1], &end, 10);
                CHECK_RANGE(local.prio >= 8 || *end != '\0');
                vlaninfo->prio = local.prio;
                SET_BITMASK(EBT_VLAN_PRIO);
@@ -163,8 +161,7 @@ parse(int c,
                ebt_check_option(flags, OPT_VLAN_ENCAP);
                CHECK_INV_FLAG(EBT_VLAN_ENCAP);
                CHECK_IF_MISSING_VALUE;
-               (unsigned short) local.encap =
-                   strtoul(argv[optind - 1], &end, 16);
+               local.encap = strtoul(argv[optind - 1], &end, 16);
                if (*end != '\0') {
                        ethent = getethertypebyname(argv[optind - 1]);
                        if (ethent == NULL)
index 5b040d2..d5264e3 100644 (file)
@@ -26,6 +26,9 @@
 #include <netinet/in.h>
 #include <linux/netfilter_bridge/ebtables.h>
 
+#define EXEC_STYLE_PRG         0
+#define EXEC_STYLE_DAEMON      1
+
 #ifndef EBT_MIN_ALIGN
 #define EBT_MIN_ALIGN (__alignof__(struct ebt_entry_target))
 #endif
@@ -223,8 +226,7 @@ void ebt_register_table(struct ebt_u_table *);
 void ebt_register_match(struct ebt_u_match *);
 void ebt_register_watcher(struct ebt_u_watcher *);
 void ebt_register_target(struct ebt_u_target *t);
-void ebt_get_kernel_table(struct ebt_u_replace *replace,
-                         struct ebt_u_table *table, int init);
+int ebt_get_kernel_table(struct ebt_u_replace *replace, int init);
 struct ebt_u_target *ebt_find_target(const char *name);
 struct ebt_u_match *ebt_find_match(const char *name);
 struct ebt_u_watcher *ebt_find_watcher(const char *name);
@@ -232,6 +234,8 @@ struct ebt_u_table *ebt_find_table(const char *name);
 int ebtables_insmod(const char *modname);
 void ebt_list_extensions();
 void ebt_initialize_entry(struct ebt_u_entry *e);
+void ebt_cleanup_replace(struct ebt_u_replace *replace);
+void ebt_reinit_extensions();
 void ebt_free_u_entry(struct ebt_u_entry *e);
 struct ebt_u_entries *ebt_name_to_chain(const struct ebt_u_replace *replace,
                                    const char* arg);
@@ -257,8 +261,9 @@ void ebt_rename_chain(struct ebt_u_replace *replace, const char *name);
 /**/
 void ebt_do_final_checks(struct ebt_u_replace *replace, struct ebt_u_entry *e,
                         struct ebt_u_entries *entries);
-int ebt_check_for_references(struct ebt_u_replace *replace);
-int ebt_check_for_references2(struct ebt_u_replace *replace, int chain_nr);
+int ebt_check_for_references(struct ebt_u_replace *replace, int print_err);
+int ebt_check_for_references2(struct ebt_u_replace *replace, int chain_nr,
+                             int print_err);
 void ebt_check_for_loops(struct ebt_u_replace *replace);
 void ebt_add_match(struct ebt_u_entry *new_entry, struct ebt_u_match *m);
 void ebt_add_watcher(struct ebt_u_entry *new_entry, struct ebt_u_watcher *w);
@@ -271,7 +276,7 @@ void __ebt_print_error(char *format, ...);
 /* communication.c */
 
 int ebt_get_table(struct ebt_u_replace *repl, int init);
-void ebt_deliver_counters(struct ebt_u_replace *repl);
+void ebt_deliver_counters(struct ebt_u_replace *repl, int exec_style);
 void ebt_deliver_table(struct ebt_u_replace *repl);
 
 /* useful_functions.c */
@@ -285,6 +290,9 @@ int ebt_get_mac_and_mask(char *from, char *to, char *mask);
 void ebt_parse_ip_address(char *address, uint32_t *addr, uint32_t *msk);
 char *ebt_mask_to_dotted(uint32_t mask);
 
+int do_command(int argc, char *argv[], int exec_style,
+               struct ebt_u_replace *replace_);
+
 struct ethertypeent *parseethertypebynumber(int type);
 
 #define ebt_print_bug(format, args...) \
index dfc277b..0fef235 100644 (file)
--- a/libebtc.c
+++ b/libebtc.c
@@ -40,9 +40,7 @@ static void decrease_chain_jumps(struct ebt_u_replace *replace);
 static void remove_udc(struct ebt_u_replace *replace);
 static int iterate_entries(struct ebt_u_replace *replace, int type);
 
-/*
- * The standard names
- */
+/* The standard names */
 const char *ebt_hooknames[NF_BR_NUMHOOKS] =
 {
        [NF_BR_PRE_ROUTING]"PREROUTING",
@@ -53,9 +51,7 @@ const char *ebt_hooknames[NF_BR_NUMHOOKS] =
        [NF_BR_BROUTING]"BROUTING"
 };
 
-/*
- * The four target names
- */
+/* The four target names */
 const char* ebt_standard_targets[NUM_STANDARD_TARGETS] =
 {
        "ACCEPT",
@@ -64,22 +60,18 @@ const char* ebt_standard_targets[NUM_STANDARD_TARGETS] =
        "RETURN",
 };
 
-/*
- * The lists of supported tables, matches, watchers and targets
- */
+/* The lists of supported tables, matches, watchers and targets */
 struct ebt_u_table *ebt_tables;
 struct ebt_u_match *ebt_matches;
 struct ebt_u_watcher *ebt_watchers;
 struct ebt_u_target *ebt_targets;
 
-/*
- * Find the right structure belonging to a name
- */
+/* Find the right structure belonging to a name */
 struct ebt_u_target *ebt_find_target(const char *name)
 {
        struct ebt_u_target *t = ebt_targets;
 
-       while(t && strcmp(t->name, name))
+       while (t && strcmp(t->name, name))
                t = t->next;
        return t;
 }
@@ -88,7 +80,7 @@ struct ebt_u_match *ebt_find_match(const char *name)
 {
        struct ebt_u_match *m = ebt_matches;
 
-       while(m && strcmp(m->name, name))
+       while (m && strcmp(m->name, name))
                m = m->next;
        return m;
 }
@@ -97,7 +89,7 @@ struct ebt_u_watcher *ebt_find_watcher(const char *name)
 {
        struct ebt_u_watcher *w = ebt_watchers;
 
-       while(w && strcmp(w->name, name))
+       while (w && strcmp(w->name, name))
                w = w->next;
        return w;
 }
@@ -111,9 +103,7 @@ struct ebt_u_table *ebt_find_table(const char *name)
        return t;
 }
 
-/*
- * Prints all registered extensions
- */
+/* Prints all registered extensions */
 void ebt_list_extensions()
 {
        struct ebt_u_table *tbl = ebt_tables;
@@ -123,59 +113,51 @@ void ebt_list_extensions()
 
        PRINT_VERSION;
        printf("Supported userspace extensions:\n\nSupported tables:\n");
-        while(tbl) {
+        while (tbl) {
                printf("%s\n", tbl->name);
                 tbl = tbl->next;
        }
        printf("\nSupported targets:\n");
-        while(t) {
+        while (t) {
                printf("%s\n", t->name);
                 t = t->next;
        }
        printf("\nSupported matches:\n");
-        while(m) {
+        while (m) {
                printf("%s\n", m->name);
                 m = m->next;
        }
        printf("\nSupported watchers:\n");
-        while(w) {
+        while (w) {
                printf("%s\n", w->name);
                 w = w->next;
        }
-       exit(0);
 }
 
-/*
- * Get the table from the kernel or from a binary file
+/* Get the table from the kernel or from a binary file
  * init: 1 = ask the kernel for the initial contents of a table, i.e. the
  *           way it looks when the table is insmod'ed
- *       0 = get the current data in the table
- */
-void ebt_get_kernel_table(struct ebt_u_replace *replace,
-                         struct ebt_u_table *table, int init)
+ *       0 = get the current data in the table */
+int ebt_get_kernel_table(struct ebt_u_replace *replace, int init)
 {
-       if ( !(table = ebt_find_table(replace->name)) )
+       if (!ebt_find_table(replace->name)) {
                ebt_print_error("Bad table name");
-       /*
-        * get the kernel's information
-        */
+               return -1;
+       }
+       /* Get the kernel's information */
        if (ebt_get_table(replace, init)) {
+               if (ebt_errormsg[0] != '\0')
+                       return -1;
                ebtables_insmod("ebtables");
-               if (ebt_get_table(replace, init))
-                       ebt_print_error("The kernel doesn't support the "
-                          "ebtables %s table", replace->name);
+               if (ebt_get_table(replace, init)) {
+                       ebt_print_error("The kernel doesn't support the ebtables %s table", replace->name);
+                       return -1;
+               }
        }
-       /*
-        * when listing a table contained in a file, we don't demand that
-        * the user knows the table's name, so we update table if necessary
-        */
-       if ( !(table = ebt_find_table(replace->name)) )
-               ebt_print_error("Bad table name");
+       return 0;
 }
 
-/*
- * Put sane values into a new entry
- */
+/* Put sane values into a new entry */
 void ebt_initialize_entry(struct ebt_u_entry *e)
 {
        e->bitmask = EBT_NOPROTO;
@@ -188,16 +170,14 @@ void ebt_initialize_entry(struct ebt_u_entry *e)
        e->m_list = NULL;
        e->w_list = NULL;
        e->t = (struct ebt_entry_target *)ebt_find_target(EBT_STANDARD_TARGET);
+       ebt_find_target(EBT_STANDARD_TARGET)->used = 1;
 
        if (!e->t)
                ebt_print_bug("Couldn't load standard target");
-       ((struct ebt_standard_target *)
-       ((struct ebt_u_target *)e->t)->t)->verdict = EBT_CONTINUE;
+       ((struct ebt_standard_target *)((struct ebt_u_target *)e->t)->t)->verdict = EBT_CONTINUE;
 }
 
-/*
- * replace is reborn, i.e. rebirth of replace
- */
+/* Free up the memory of the table held in userspace, *replace can be reused */
 void ebt_cleanup_replace(struct ebt_u_replace *replace)
 {
        int i;
@@ -245,6 +225,7 @@ void ebt_cleanup_replace(struct ebt_u_replace *replace)
        }
        udc1 = replace->udc;
        while (udc1) {
+               free(udc1->udc);
                udc2 = udc1->next;
                free(udc1);
                udc1 = udc2;
@@ -259,10 +240,8 @@ void ebt_cleanup_replace(struct ebt_u_replace *replace)
        replace->counterchanges = NULL;
 }
 
-/*
- * Should be called between 2 rule adds, f.e.
- */
-void ebt_reinit_extensions(struct ebt_u_replace *replace)
+/* Should be called, e.g., between 2 rule adds */
+void ebt_reinit_extensions()
 {
        struct ebt_u_match *m;
        struct ebt_u_watcher *w;
@@ -273,42 +252,46 @@ void ebt_reinit_extensions(struct ebt_u_replace *replace)
         * called for the first time or not (when necessary). */
        for (m = ebt_matches; m; m = m->next) {
                size = EBT_ALIGN(m->size) + sizeof(struct ebt_entry_match);
-               if (m->m)
-                       free(m->m);
-               m->m = (struct ebt_entry_match *)malloc(size);
-               if (!m->m)
-                       ebt_print_memory();
-               m->used = 0;
-               m->flags = 0;
+               if (m->used) {
+                       m->m = (struct ebt_entry_match *)malloc(size);
+                       if (!m->m)
+                               ebt_print_memory();
+                       strcpy(m->m->u.name, m->name);
+                       m->m->match_size = EBT_ALIGN(m->size);
+                       m->used = 0;
+                       m->flags = 0;
+               }
                m->init(m->m);
        }
        for (w = ebt_watchers; w; w = w->next) {
                size = EBT_ALIGN(w->size) + sizeof(struct ebt_entry_watcher);
-               if (w->w)
-                       free(w->w);
-               w->w = (struct ebt_entry_watcher *)malloc(size);
-               if (!w->w)
-                       ebt_print_memory();
-               w->used = 0;
-               w->flags = 0;
+               if (w->used) {
+                       w->w = (struct ebt_entry_watcher *)malloc(size);
+                       if (!w->w)
+                               ebt_print_memory();
+                       strcpy(w->w->u.name, w->name);
+                       w->w->watcher_size = EBT_ALIGN(w->size);
+                       w->used = 0;
+                       w->flags = 0;
+               }
                w->init(w->w);
        }
-       for (t = ebt_targets; m; t = t->next) {
+       for (t = ebt_targets; t; t = t->next) {
                size = EBT_ALIGN(t->size) + sizeof(struct ebt_entry_target);
-               if (t->t)
-                       free(t->t);
-               t->t = (struct ebt_entry_target *)malloc(size);
-               if (!t->t)
-                       ebt_print_memory();
-               t->used = 0;
-               t->flags = 0;
+               if (t->used) {
+                       t->t = (struct ebt_entry_target *)malloc(size);
+                       if (!t->t)
+                               ebt_print_memory();
+                       strcpy(t->t->u.name, t->name);
+                       t->t->target_size = EBT_ALIGN(t->size);
+                       t->used = 0;
+                       t->flags = 0;
+               }
                t->init(t->t);
        }
 }
 
-/*
- * This doesn't free e, becoz the calling function might need e->next
- */
+/* This doesn't free e, because the calling function might need e->next */
 void ebt_free_u_entry(struct ebt_u_entry *e)
 {
        struct ebt_u_match_list *m_l, *m_l2;
@@ -331,10 +314,8 @@ void ebt_free_u_entry(struct ebt_u_entry *e)
        free(e->t);
 }
 
-/*
- * Blatently stolen (again) from iptables.c userspace program
- * find out where the modprobe utility is located
- */
+/* Blatently stolen (again) from iptables.c userspace program
+ * find out where the modprobe utility is located */
 static char *get_modprobe(void)
 {
        int procfile;
@@ -350,8 +331,8 @@ static char *get_modprobe(void)
                case -1: goto fail;
                case 1024: goto fail; /* Partial read.  Wierd */
                }
-               if (ret[strlen(ret)-1]=='\n')
-                       ret[strlen(ret)-1]=0;
+               if (ret[strlen(ret)-1] == '\n')
+                       ret[strlen(ret)-1] = 0;
                close(procfile);
                return ret;
        }
@@ -362,9 +343,7 @@ static char *get_modprobe(void)
 }
 
 char *ebt_modprobe;
-/*
- * Try to load the kernel module
- */
+/* Try to load the kernel module */
 int ebtables_insmod(const char *modname)
 {
        char *buf = NULL;
@@ -385,12 +364,12 @@ int ebtables_insmod(const char *modname)
                argv[2] = NULL;
                execv(argv[0], argv);
 
-               /* not usually reached */
+               /* Not usually reached */
                exit(0);
        case -1:
                return -1;
 
-       default: /* parent */
+       default: /* Parent */
                wait(NULL);
        }
 
@@ -398,11 +377,9 @@ int ebtables_insmod(const char *modname)
        return 0;
 }
 
-/*
- * Gives back a pointer to the chain base, based on nr.
+/* Gives back a pointer to the chain base, based on nr.
  * If nr >= NF_BR_NUMHOOKS you'll get back a user-defined chain.
- * Returns NULL on failure.
- */
+ * Returns NULL on failure. */
 struct ebt_u_entries *ebt_nr_to_chain(const struct ebt_u_replace *replace,
                                       int nr)
 {
@@ -426,20 +403,16 @@ struct ebt_u_entries *ebt_nr_to_chain(const struct ebt_u_replace *replace,
        }
 }
 
-/*
- * Gives back a pointer to the chain base of selected_chain
- */
+/* Gives back a pointer to the chain base of selected_chain */
 struct ebt_u_entries *ebt_to_chain(const struct ebt_u_replace *replace)
 {
        return ebt_nr_to_chain(replace, replace->selected_chain);
 }
 
-/*
- * Parse the chain name and return a pointer to the chain base.
- * Returns NULL on failure.
- */
+/* Parse the chain name and return a pointer to the chain base.
+ * Returns NULL on failure. */
 struct ebt_u_entries *ebt_name_to_chain(const struct ebt_u_replace *replace,
-                                   const char* arg)
+                                       const char* arg)
 {
        int i;
        struct ebt_u_chain_list *cl = replace->udc;
@@ -458,10 +431,8 @@ struct ebt_u_entries *ebt_name_to_chain(const struct ebt_u_replace *replace,
        return NULL;
 }
 
-/*
- * Parse the chain name and return the corresponding chain nr
- * returns -1 on failure
- */
+/* Parse the chain name and return the corresponding chain nr
+ * returns -1 on failure */
 int ebt_get_chainnr(const struct ebt_u_replace *replace, const char* arg)
 {
        int i;
@@ -490,23 +461,19 @@ int ebt_get_chainnr(const struct ebt_u_replace *replace, const char* arg)
 ************
      */
 
-/*
- * Chainge the policy of selected_chain.
- * No sanity checks are done.
- */
+/* Change the policy of selected_chain.
+ * Handing a bad policy to this function is a bug. */
 void ebt_change_policy(struct ebt_u_replace *replace, int policy)
 {
        struct ebt_u_entries *entries = ebt_to_chain(replace);
 
        if (policy < -NUM_STANDARD_TARGETS || policy == EBT_CONTINUE)
-               ebt_print_bug("wrong policy: %d", policy);
+               ebt_print_bug("Wrong policy: %d", policy);
        entries->policy = policy;
 }
 
-/*
- * Flush one chain or the complete table
- * If selected_chain == -1: flush the complete table
- */
+/* Flush one chain or the complete table
+ * If selected_chain == -1: flush the complete table */
 void ebt_flush_chains(struct ebt_u_replace *replace)
 {
        int i, j, numdel;
@@ -515,17 +482,13 @@ void ebt_flush_chains(struct ebt_u_replace *replace)
        struct ebt_cntchanges *cc = replace->counterchanges;
        struct ebt_cntchanges **prev_cc =  &(replace->counterchanges);
 
-       /*
-        * flush whole table
-        */
+       /* Flush whole table */
        if (!entries) {
                if (replace->nentries == 0)
                        return;
                replace->nentries = 0;
 
-               /*
-                * free everything and zero (n)entries
-                */
+               /* Free everything and zero (n)entries */
                i = -1;
                while (1) {
                        i++;
@@ -547,9 +510,7 @@ void ebt_flush_chains(struct ebt_u_replace *replace)
                                u_e = tmp;
                        }
                }
-               /*
-                * update the counters
-                */
+               /* Update the counters */
                while (cc) {
                        if (cc->type == CNT_ADD) {
                                *prev_cc = cc->next;
@@ -569,10 +530,8 @@ void ebt_flush_chains(struct ebt_u_replace *replace)
        replace->nentries -= entries->nentries;
        numdel = entries->nentries;
 
-       /*
-        * delete the counters belonging to the specified chain,
-        * update counter_offset
-        */
+       /* Delete the counters belonging to the specified chain,
+        * update counter_offset */
        i = -1;
        while (1) {
                i++;
@@ -589,7 +548,7 @@ void ebt_flush_chains(struct ebt_u_replace *replace)
                }
                j = entries->nentries;
                while (j) {
-                       /* don't count deleted entries */
+                       /* Don't count deleted entries */
                        if (cc->type == CNT_DEL)
                                goto letscontinue;
                        if (i == replace->selected_chain) {
@@ -619,15 +578,12 @@ letscontinue:
                u_e = tmp;
        }
        entries->entries = NULL;
-       return;
 }
 
-/*
- * returns the rule number on success (starting from 0), -1 on failure
+/* Returns the rule number on success (starting from 0), -1 on failure
  *
  * This function expects the ebt_{match,watcher,target} members of new_entry
- * to contain pointers to ebt_u_{match,watcher,target}.
- */
+ * to contain pointers to ebt_u_{match,watcher,target} */
 int ebt_check_rule_exists(struct ebt_u_replace *replace,
                          struct ebt_u_entry *new_entry)
 {
@@ -641,10 +597,8 @@ int ebt_check_rule_exists(struct ebt_u_replace *replace,
        int i, j, k;
 
        u_e = entries->entries;
-       /*
-        * check for an existing rule (if there are duplicate rules,
-        * take the first occurance)
-        */
+       /* Check for an existing rule (if there are duplicate rules,
+        * take the first occurance) */
        for (i = 0; i < entries->nentries; i++, u_e = u_e->next) {
                if (!u_e)
                        ebt_print_bug("Hmm, trouble");
@@ -659,17 +613,15 @@ int ebt_check_rule_exists(struct ebt_u_replace *replace,
                if (strcmp(u_e->logical_out, new_entry->logical_out))
                        continue;
                if (new_entry->bitmask & EBT_SOURCEMAC &&
-                  memcmp(u_e->sourcemac, new_entry->sourcemac, ETH_ALEN))
+                   memcmp(u_e->sourcemac, new_entry->sourcemac, ETH_ALEN))
                        continue;
                if (new_entry->bitmask & EBT_DESTMAC &&
-                  memcmp(u_e->destmac, new_entry->destmac, ETH_ALEN))
+                   memcmp(u_e->destmac, new_entry->destmac, ETH_ALEN))
                        continue;
                if (new_entry->bitmask != u_e->bitmask ||
-                  new_entry->invflags != u_e->invflags)
+                   new_entry->invflags != u_e->invflags)
                        continue;
-               /*
-                * compare all matches
-                */
+               /* Compare all matches */
                m_l = new_entry->m_list;
                j = 0;
                while (m_l) {
@@ -682,9 +634,7 @@ int ebt_check_rule_exists(struct ebt_u_replace *replace,
                        j++;
                        m_l = m_l->next;
                }
-               /*
-                * now be sure they have the same nr of matches
-                */
+               /* Now be sure they have the same nr of matches */
                k = 0;
                m_l = u_e->m_list;
                while (m_l) {
@@ -694,9 +644,7 @@ int ebt_check_rule_exists(struct ebt_u_replace *replace,
                if (j != k)
                        continue;
 
-               /*
-                * compare all watchers
-                */
+               /* Compare all watchers */
                w_l = new_entry->w_list;
                j = 0;
                while (w_l) {
@@ -732,13 +680,14 @@ letscontinue:;
  * rule_nr > 0 : insert the rule right before the rule_nr'th rule
  *               (the first rule is rule 1)
  * rule_nr < 0 : insert the rule right before the (n+rule_nr+1)'th rule,
- *               where n denotes the number of rule in the chain
+ *               where n denotes the number of rules in the chain
  * rule_nr == 0: add a new rule at the end of the chain
  *
  * This function expects the ebt_{match,watcher,target} members of new_entry
  * to contain pointers to ebt_u_{match,watcher,target} and updates these
- * pointers before adding the rule to the chain.
- */
+ * pointers so that they point to ebt_{match,watcher,target}, before adding
+ * the rule to the chain. Don't free() the ebt_{match,watcher,target} after a
+ * successful call to ebt_add_rule() */
 void ebt_add_rule(struct ebt_u_replace *replace, struct ebt_u_entry *new_entry,
                  int rule_nr)
 {
@@ -754,17 +703,15 @@ void ebt_add_rule(struct ebt_u_replace *replace, struct ebt_u_entry *new_entry,
                rule_nr += entries->nentries;
        else
                rule_nr--;
-       if (rule_nr > entries->nentries || rule_nr < 0)
+       if (rule_nr > entries->nentries || rule_nr < 0) {
                ebt_print_error("The specified rule number is incorrect");
-       /*
-        * we're adding one rule
-        */
+               return;
+       }
+       /* We're adding one rule */
        replace->nentries++;
        entries->nentries++;
 
-       /*
-        * handle counter stuff
-        */
+       /* Handle counter stuff */
        for (i = 0; i < replace->selected_chain; i++) {
                if (i < NF_BR_NUMHOOKS && !(replace->valid_hooks & (1 << i)))
                        continue;
@@ -783,32 +730,26 @@ void ebt_add_rule(struct ebt_u_replace *replace, struct ebt_u_entry *new_entry,
                prev_cc = &(cc->next);
                cc = cc->next;
        }
-       if (cc && cc->type == CNT_DEL) /* The add is victorious and conquers
-                                       * the delete */
+       if (cc && cc->type == CNT_DEL)
                cc->type = CNT_OWRITE;
        else {
                new_cc = (struct ebt_cntchanges *)
                         malloc(sizeof(struct ebt_cntchanges));
+               if (!new_cc)
+                       ebt_print_memory();
                new_cc->type = CNT_ADD;
                new_cc->next = cc;
                *prev_cc = new_cc;
        }
-
-       /*
-        * go to the right position in the chain
-        */
+       /* Go to the right position in the chain */
        u_e = &entries->entries;
        for (i = 0; i < rule_nr; i++)
                u_e = &(*u_e)->next;
-       /*
-        * insert the rule
-        */
+       /* Insert the rule */
        new_entry->next = *u_e;
        *u_e = new_entry;
 
-       /*
-        * put the ebt_[match, watcher, target] pointers in place
-        */
+       /* Put the ebt_{match, watcher, target} pointers in place */
        m_l = new_entry->m_list;
        while (m_l) {
                m_l->m = ((struct ebt_u_match *)m_l->m)->m;
@@ -820,10 +761,7 @@ void ebt_add_rule(struct ebt_u_replace *replace, struct ebt_u_entry *new_entry,
                w_l = w_l->next;
        }
        new_entry->t = ((struct ebt_u_target *)new_entry->t)->t;
-
-       /*
-        * update the counter_offset of chains behind this one
-        */
+       /* Update the counter_offset of chains behind this one */
        i = replace->selected_chain;
        while (1) {
                i++;
@@ -838,14 +776,12 @@ void ebt_add_rule(struct ebt_u_replace *replace, struct ebt_u_entry *new_entry,
        }
 }
 
-/*
- * Delete a rule or rules
+/* Delete a rule or rules
  * begin == end == 0: delete the rule corresponding to new_entry
  *
- * the first rule has rule nr 1, the last rule has rule nr -1, etc.
+ * The first rule has rule nr 1, the last rule has rule nr -1, etc.
  * This function expects the ebt_{match,watcher,target} members of new_entry
- * to contain pointers to ebt_u_{match,watcher,target}.
- */
+ * to contain pointers to ebt_u_{match,watcher,target}. */
 void ebt_delete_rule(struct ebt_u_replace *replace,
                     struct ebt_u_entry *new_entry, int begin, int end)
 {
@@ -860,8 +796,10 @@ void ebt_delete_rule(struct ebt_u_replace *replace,
        if (end < 0)
                end += entries->nentries + 1;
 
-       if (begin < 0 || begin > end || end > entries->nentries)
+       if (begin < 0 || begin > end || end > entries->nentries) {
                ebt_print_error("Sorry, wrong rule numbers");
+               return;
+       }
 
        if ((begin * end == 0) && (begin + end != 0))
                ebt_print_bug("begin and end should be either both zero, "
@@ -872,20 +810,18 @@ void ebt_delete_rule(struct ebt_u_replace *replace,
        } else {
                begin = ebt_check_rule_exists(replace, new_entry);
                end = begin;
-               if (begin == -1)
+               if (begin == -1) {
                        ebt_print_error("Sorry, rule does not exist");
+                       return;
+               }
        }
 
-       /*
-        * we're deleting rules
-        */
+       /* We're deleting rules */
        nr_deletes = end - begin + 1;
        replace->nentries -= nr_deletes;
        entries->nentries -= nr_deletes;
 
-       /*
-        * handle counter stuff
-        */
+       /* Handle counter stuff */
        for (i = 0; i < replace->selected_chain; i++) {
                if (i < NF_BR_NUMHOOKS && !(replace->valid_hooks & (1 << i)))
                        continue;
@@ -920,27 +856,21 @@ void ebt_delete_rule(struct ebt_u_replace *replace,
                cc = cc->next;
        }
 
-       /*
-        * go to the right position in the chain
-        */
+       /* Go to the right position in the chain */
        u_e = &entries->entries;
        for (j = 0; j < begin; j++)
                u_e = &(*u_e)->next;
-       /*
-        * remove the rules
-        */
+       /* Remove the rules */
        j = nr_deletes;
        while(j--) {
                u_e2 = *u_e;
                *u_e = (*u_e)->next;
-               /* free everything */
+               /* Free everything */
                ebt_free_u_entry(u_e2);
                free(u_e2);
        }
 
-       /*
-        * update the counter_offset of chains behind this one
-        */
+       /* Update the counter_offset of chains behind this one */
        j = replace->selected_chain;
        while (1) {
                j++;
@@ -955,10 +885,8 @@ void ebt_delete_rule(struct ebt_u_replace *replace,
        }
 }
 
-/*
- * Selected_chain == -1 : zero all counters
- * else, zero the counters of selected_chain
- */
+/* Selected_chain == -1 : zero all counters
+ * Otherwise, zero the counters of selected_chain */
 void ebt_zero_counters(struct ebt_u_replace *replace)
 {
        struct ebt_u_entries *entries = ebt_to_chain(replace);
@@ -976,8 +904,7 @@ void ebt_zero_counters(struct ebt_u_replace *replace)
                        return;
 
                for (i = 0; i < replace->selected_chain; i++) {
-                       if (i < NF_BR_NUMHOOKS &&
-                           !(replace->valid_hooks & (1 << i)))
+                       if (i < NF_BR_NUMHOOKS && !(replace->valid_hooks & (1 << i)))
                                continue;
                        j = ebt_nr_to_chain(replace, i)->nentries;
                        while (j) {
@@ -998,20 +925,22 @@ void ebt_zero_counters(struct ebt_u_replace *replace)
        }
 }
 
-/*
- * Add a new chain and specify its policy
- */
+/* Add a new chain and specify its policy */
 void ebt_new_chain(struct ebt_u_replace *replace, const char *name, int policy)
 {
        struct ebt_u_chain_list *cl, **cl2;
 
-       if (ebt_get_chainnr(replace, name) != -1)
+       if (ebt_get_chainnr(replace, name) != -1) {
                ebt_print_error("Chain %s already exists", optarg);
-       if (ebt_find_target(name))
+               return;
+       } else if (ebt_find_target(name)) {
                ebt_print_error("Target with name %s exists", optarg);
-       if (strlen(optarg) >= EBT_CHAIN_MAXNAMELEN)
+               return;
+       } else if (strlen(optarg) >= EBT_CHAIN_MAXNAMELEN) {
                ebt_print_error("Chain name length can't exceed %d",
                                EBT_CHAIN_MAXNAMELEN - 1);
+               return;
+       }
        cl = (struct ebt_u_chain_list *)
             malloc(sizeof(struct ebt_u_chain_list));
        if (!cl)
@@ -1028,39 +957,37 @@ void ebt_new_chain(struct ebt_u_replace *replace, const char *name, int policy)
        strcpy(cl->udc->name, name);
        cl->udc->entries = NULL;
        cl->kernel_start = NULL;
-       /*
-        * put the new chain at the end
-        */
+       /* Put the new chain at the end */
        cl2 = &(replace->udc);
        while (*cl2)
                cl2 = &((*cl2)->next);
        *cl2 = cl;
 }
 
-/*
- * Selected_chain == -1: delete all non-referenced udc
- * selected_chain < NF_BR_NUMHOOKS is illegal
- */
+/* Selected_chain == -1: delete all non-referenced udc
+ * selected_chain < NF_BR_NUMHOOKS is illegal */
 void ebt_delete_chain(struct ebt_u_replace *replace)
 {
-       int chain_nr = replace->selected_chain;
+       int chain_nr = replace->selected_chain, print_error = 1;
 
        if (chain_nr != -1 && chain_nr < NF_BR_NUMHOOKS)
                ebt_print_bug("You can't remove a standard chain");
-       if (chain_nr == -1)
+       if (chain_nr == -1) {
+               print_error = 0;
                replace->selected_chain = NF_BR_NUMHOOKS;
+       }
        do {
                if (ebt_to_chain(replace) == NULL) {
                        if (chain_nr == -1)
                                break;
                        ebt_print_bug("udc nr %d doesn't exist", chain_nr);
                }
-               /*
-                * if the chain is referenced, don't delete it,
+               /* If the chain is referenced, don't delete it,
                 * also decrement jumps to a chain behind the
-                * one we're deleting
-                */
-               if (ebt_check_for_references(replace)) {
+                * one we're deleting */
+               if (ebt_check_for_references(replace, print_error)) {
+                       if (chain_nr != -1) 
+                               break;
                        replace->selected_chain++;
                        continue;
                }
@@ -1068,12 +995,10 @@ void ebt_delete_chain(struct ebt_u_replace *replace)
                ebt_flush_chains(replace);
                remove_udc(replace);
        } while (chain_nr == -1);
-       replace->selected_chain = chain_nr;
+       replace->selected_chain = chain_nr; /* Put back to -1 */
 }
 
-/*
- * Rename an existing chain.
- */
+/* Rename an existing chain. */
 void ebt_rename_chain(struct ebt_u_replace *replace, const char *name)
 {
        struct ebt_u_entries *entries = ebt_to_chain(replace);
@@ -1093,11 +1018,10 @@ void ebt_rename_chain(struct ebt_u_replace *replace, const char *name)
             */
 
 
-/*
- * executes the final_check() function for all extensions used by the rule
+/* Executes the final_check() function for all extensions used by the rule
  * ebt_check_for_loops should have been executed earlier, to make sure the
- * hook_mask is correct.
- */
+ * hook_mask is correct. The time argument to final_check() is set to 1,
+ * meaning it's the second time the final_check() function is executed. */
 void ebt_do_final_checks(struct ebt_u_replace *replace, struct ebt_u_entry *e,
                         struct ebt_u_entries *entries)
 {
@@ -1113,12 +1037,16 @@ void ebt_do_final_checks(struct ebt_u_replace *replace, struct ebt_u_entry *e,
                m = ebt_find_match(m_l->m->u.name);
                m->final_check(e, m_l->m, replace->name,
                   entries->hook_mask, 1);
+               if (ebt_errormsg[0] != '\0')
+                       return;
                m_l = m_l->next;
        }
        while (w_l) {
                w = ebt_find_watcher(w_l->w->u.name);
                w->final_check(e, w_l->w, replace->name,
                   entries->hook_mask, 1);
+               if (ebt_errormsg[0] != '\0')
+                       return;
                w_l = w_l->next;
        }
        t = ebt_find_target(e->t->u.name);
@@ -1126,26 +1054,29 @@ void ebt_do_final_checks(struct ebt_u_replace *replace, struct ebt_u_entry *e,
           entries->hook_mask, 1);
 }
 
-/*
- * returns 1 when the chain is referenced,
- * 0 when it isn't.
- */
-int ebt_check_for_references(struct ebt_u_replace *replace)
+/* Returns 1 (if it returns) when the chain is referenced, 0 when it isn't.
+ * print_err: 0 (resp. 1) = don't (resp. do) print error when referenced */
+int ebt_check_for_references(struct ebt_u_replace *replace, int print_err)
 {
-       return iterate_entries(replace, 1);
+       if (print_err)
+               return iterate_entries(replace, 1);
+       else
+               return iterate_entries(replace, 2);
 }
 
-/*
- * chain_nr: nr of the udc (>= NF_BR_NUMHOOKS)
- * returns 1 when the chain is referenced,
- * 0 when it isn't.
- */
-int ebt_check_for_references2(struct ebt_u_replace *replace, int chain_nr)
+/* chain_nr: nr of the udc (>= NF_BR_NUMHOOKS)
+ * Returns 1 (if it returns) when the chain is referenced, 0 when it isn't.
+ * print_err: 0 (resp. 1) = don't (resp. do) print error when referenced */
+int ebt_check_for_references2(struct ebt_u_replace *replace, int chain_nr,
+                              int print_err)
 {
        int tmp = replace->selected_chain, ret;
 
        replace->selected_chain = chain_nr;
-       ret = iterate_entries(replace, 1);
+       if (print_err)
+               ret = iterate_entries(replace, 1);
+       else
+               ret = iterate_entries(replace, 2);
        replace->selected_chain = tmp;
        return ret;
 }
@@ -1158,12 +1089,10 @@ struct ebt_u_stack
        struct ebt_u_entries *entries;
 };
 
-/*
- * Checks for loops
+/* Checks for loops
  * As a by-product, the hook_mask member of each chain is filled in
  * correctly. The check functions of the extensions need this hook_mask
- * to know from which standard chains they can be called.
- */
+ * to know from which standard chains they can be called. */
 void ebt_check_for_loops(struct ebt_u_replace *replace)
 {
        int chain_nr , i, j , k, sp = 0, verdict;
@@ -1172,9 +1101,7 @@ void ebt_check_for_loops(struct ebt_u_replace *replace)
        struct ebt_u_entry *e;
 
        i = -1;
-       /*
-        * initialize hook_mask to 0
-        */
+       /* Initialize hook_mask to 0 */
        while (1) {
                i++;
                if (i < NF_BR_NUMHOOKS && !(replace->valid_hooks & (1 << i)))
@@ -1191,17 +1118,13 @@ void ebt_check_for_loops(struct ebt_u_replace *replace)
                        ebt_print_memory();
        }
 
-       /*
-        * check for loops, starting from every base chain
-        */
+       /* Check for loops, starting from every base chain */
        for (i = 0; i < NF_BR_NUMHOOKS; i++) {
                if (!(replace->valid_hooks & (1 << i)))
                        continue;
                entries = ebt_nr_to_chain(replace, i);
-               /*
-                * (1 << NF_BR_NUMHOOKS) implies it's a standard chain
-                * (usefull in the final_check() funtions)
-                */
+               /* (1 << NF_BR_NUMHOOKS) implies it's a standard chain
+                * (usefull in the final_check() funtions) */
                entries->hook_mask = (1 << i) | (1 << NF_BR_NUMHOOKS);
                chain_nr = i;
 
@@ -1212,20 +1135,17 @@ void ebt_check_for_loops(struct ebt_u_replace *replace)
                        verdict = ((struct ebt_standard_target *)(e->t))->verdict;
                        if (verdict < 0)
                                goto letscontinue;
-                       entries2 = ebt_nr_to_chain(replace,
-                                                  verdict + NF_BR_NUMHOOKS);
+                       entries2 = ebt_nr_to_chain(replace, verdict + NF_BR_NUMHOOKS);
                        entries2->hook_mask |= entries->hook_mask;
-                       /*
-                        * now see if we've been here before
-                        */
+                       /* Now see if we've been here before */
                        for (k = 0; k < sp; k++)
-                               if (stack[k].chain_nr == verdict + NF_BR_NUMHOOKS)
-                                       ebt_print_error("Loop from chain %s to chain %s",
+                               if (stack[k].chain_nr == verdict + NF_BR_NUMHOOKS) {
+                                       ebt_print_error("Loop from chain '%s' to chain '%s'",
                                           ebt_nr_to_chain(replace, chain_nr)->name,
                                           ebt_nr_to_chain(replace, stack[k].chain_nr)->name);
-                       /*
-                        * jump to the chain, make sure we know how to get back
-                        */
+                                       goto free_stack;
+                               }
+                       /* Jump to the chain, make sure we know how to get back */
                        stack[sp].chain_nr = chain_nr;
                        stack[sp].n = j;
                        stack[sp].entries = entries;
@@ -1239,14 +1159,10 @@ void ebt_check_for_loops(struct ebt_u_replace *replace)
 letscontinue:
                        e = e->next;
                }
-               /*
-                * we are at the end of a standard chain
-                */
+               /* We are at the end of a standard chain */
                if (sp == 0)
                        continue;
-               /*
-                * go back to the chain one level higher
-                */
+               /* Go back to the chain one level higher */
                sp--;
                j = stack[sp].n;
                chain_nr = stack[sp].chain_nr;
@@ -1254,13 +1170,16 @@ letscontinue:
                entries = stack[sp].entries;
                goto letscontinue;
        }
+free_stack:
        free(stack);
        return;
 }
 
-/*
- * the user will use the match, so put it in new_entry
- */
+/* The user will use the match, so put it in new_entry. The ebt_u_match
+ * pointer is put in the ebt_entry_match pointer. ebt_add_rule will
+ * fill in the final value for new->m. Unless the rule is added to a chain,
+ * the pointer will keep pointing to the ebt_u_match (until the new_entry
+ * is freed). I know, I should use a union for these 2 pointer types... */
 void ebt_add_match(struct ebt_u_entry *new_entry, struct ebt_u_match *m)
 {
        struct ebt_u_match_list **m_list, *new;
@@ -1300,13 +1219,12 @@ void ebt_add_watcher(struct ebt_u_entry *new_entry, struct ebt_u_watcher *w)
          */
 
 
-/*
- * type = 0 => update chain jumps
- * type = 1 => check for reference
+/* type = 0 => update chain jumps
+ * type = 1 => check for reference, print error when referenced
+ * type = 2 => check for reference, don't print error when referenced
  *
- * returns 1 when type == 1 and the chain is referenced
- * returns 0 otherwise
- */
+ * Returns 1 when type == 1 and the chain is referenced
+ * returns 0 otherwise */
 static int iterate_entries(struct ebt_u_replace *replace, int type)
 {
        int i = -1, j, chain_nr = replace->selected_chain - NF_BR_NUMHOOKS;
@@ -1338,19 +1256,21 @@ static int iterate_entries(struct ebt_u_replace *replace, int type)
                                    verdict;
                        switch (type) {
                        case 1:
+                       case 2:
                        if (chain_jmp == chain_nr) {
-                               ebt_print_error("Can't delete the chain, it's "
-                                  "referenced in chain %s, rule %d",
-                                  entries->name, j);
+                               if (type == 2)
+                                       return 1;
+                               ebt_print_error("Can't delete the chain '%s', it's referenced in chain '%s', rule %d",
+                                               ebt_nr_to_chain(replace, chain_nr + NF_BR_NUMHOOKS)->name, entries->name, j);
                                return 1;
                        }
                        break;
                        case 0:
-                       /* adjust the chain jumps when necessary */
+                       /* Adjust the chain jumps when necessary */
                        if (chain_jmp > chain_nr)
                                ((struct ebt_standard_target *)e->t)->verdict--;
                        break;
-                       } /* end switch */
+                       } /* End switch */
                        e = e->next;
                }
        }
@@ -1362,9 +1282,7 @@ static void decrease_chain_jumps(struct ebt_u_replace *replace)
        iterate_entries(replace, 0);
 }
 
-/*
- * selected_chain >= NF_BR_NUMHOOKS
- */
+/* Selected_chain >= NF_BR_NUMHOOKS */
 static void remove_udc(struct ebt_u_replace *replace)
 {
        struct ebt_u_chain_list *cl, **cl2;
@@ -1375,7 +1293,7 @@ static void remove_udc(struct ebt_u_replace *replace)
        if (chain_nr < NF_BR_NUMHOOKS)
                ebt_print_bug("remove_udc: chain_nr = %d < %d", chain_nr,
                              NF_BR_NUMHOOKS);
-       /* first free the rules */
+       /* First free the rules */
        entries = ebt_nr_to_chain(replace, chain_nr);
        u_e = entries->entries;
        while (u_e) {
@@ -1395,10 +1313,7 @@ static void remove_udc(struct ebt_u_replace *replace)
        free(cl);
 }
 
-
-/*
- * used in initialization code of modules
- */
+/* Used in initialization code of modules */
 void ebt_register_match(struct ebt_u_match *m)
 {
        int size = EBT_ALIGN(m->size) + sizeof(struct ebt_entry_match);
@@ -1480,9 +1395,7 @@ void ebt_iterate_targets(void (*f)(struct ebt_u_target *))
                f(i);
 }
 
-/*
- * Don't use this function, use ebt_print_bug()
- */
+/* Don't use this function, use ebt_print_bug() */
 void __ebt_print_bug(char *file, int line, char *format, ...)
 {
        va_list l;
@@ -1495,26 +1408,20 @@ void __ebt_print_bug(char *file, int line, char *format, ...)
        exit (-1);
 }
 
-/*
- * The error messages are put in here when ebt_silent == 1
- * ebt_errormsg[0] == '\0' implies there was no error
- */
+/* The error messages are put in here when ebt_silent == 1
+ * ebt_errormsg[0] == '\0' implies there was no error */
 char ebt_errormsg[ERRORMSG_MAXLEN];
-/*
- * When error messages should not be printed on the screen, after which
- * the program exit()s, set ebt_silent to 1.
- */
+/* When error messages should not be printed on the screen, after which
+ * the program exit()s, set ebt_silent to 1. */
 int ebt_silent;
-/*
- * Don't use this function, use ebt_print_error()
- */
+/* Don't use this function, use ebt_print_error() */
 void __ebt_print_error(char *format, ...)
 {
        va_list l;
 
        va_start(l, format);
-       if (ebt_silent) {
-               snprintf(ebt_errormsg, ERRORMSG_MAXLEN, format, l);
+       if (ebt_silent && ebt_errormsg[0] == '\0') {
+               vsnprintf(ebt_errormsg, ERRORMSG_MAXLEN, format, l);
                va_end(l);
        } else {
                vprintf(format, l);