]> git.ipfire.org Git - thirdparty/iptables.git/commitdiff
make iptables-restore and iptables-save work again!
authorHarald Welte <laforge@gnumonks.org>
Fri, 1 Dec 2000 14:26:20 +0000 (14:26 +0000)
committerHarald Welte <laforge@gnumonks.org>
Fri, 1 Dec 2000 14:26:20 +0000 (14:26 +0000)
Makefile
iptables-restore.c
iptables-save.c
iptables-standalone.c
iptables.c

index 60acf0ef6dc5304a2aeaafd390ada70cb0bf5be4..dd28ae5fc652c1d93cea1ac348cfef48a00f2034 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -18,8 +18,8 @@ CFLAGS:=$(COPT_FLAGS) -Wall -Wunused -Iinclude/ -I$(KERNEL_DIR)/include -DNETFIL
 DEPFILES = $(SHARED_LIBS:%.so=%.d)
 SH_CFLAGS:=$(CFLAGS) -fPIC
 
-EXTRAS+=iptables iptables.o ip6tables ip6tables.o #iptables-save iptables-restore
-EXTRA_INSTALLS+=$(DESTDIR)$(BINDIR)/iptables $(DESTDIR)$(BINDIR)/ip6tables $(DESTDIR)$(MANDIR)/man8/iptables.8 #$(DESTDIR)$(BINDIR)/iptables-save $(DESTDIR)$(BINDIR)/iptables-restore
+EXTRAS+=iptables iptables.o iptables-save iptables-restore # ip6tables ip6tables.o 
+EXTRA_INSTALLS+=$(DESTDIR)$(BINDIR)/iptables $(DESTDIR)$(MANDIR)/man8/iptables.8 $(DESTDIR)$(BINDIR)/iptables-save $(DESTDIR)$(BINDIR)/iptables-restore # $(DESTDIR)$(BINDIR)/ip6tables 
 
 # Sparc64 hack
 ifeq ($(shell uname -m),sparc64)
index f9a95952d0e273176f9640a9a035a6792c74e0b4..5e017200caf9aec2edde97175a1e806af45c1ec2 100644 (file)
@@ -1,10 +1,23 @@
-/* Code to restore the iptables state, from file by iptables-save. */
+/* Code to restore the iptables state, from file by iptables-save. 
+ * (C) 2000 by Harald Welte <laforge@gnumonks.org>
+ * based on previous code from Rusty Russell <rusty@linuxcare.com.au>
+ *
+ * This coude is distributed under the terms of GNU GPL
+ */
+
 #include <getopt.h>
 #include <sys/errno.h>
 #include <string.h>
 #include <stdio.h>
-#include "packet-filter/userspace/iptables.h"
-#include "packet-filter/userspace/libiptc/libiptc.h"
+#include <stdlib.h>
+#include "iptables.h"
+#include "libiptc/libiptc.h"
+
+#ifdef DEBUG
+#define DEBUGP(x, args ...) fprintf(stderr, x, ## args)
+#else
+#define DEBUGP(x, args ...) 
+#endif
 
 /* Keeping track of external matches and targets.  */
 static struct option options[] = {
@@ -23,29 +36,28 @@ static void print_usage(const char *name, const char *version)
        exit(1);
 }
 
-static int clean_slate(iptc_handle_t *handle)
+iptc_handle_t create_handle(const char *tablename)
 {
-       /* Skip over builtins. */
-       const char *i, *last = IPTC_LABEL_OUTPUT;
-
-       /* Be careful iterating: it isn't safe during delete. */
-       /* Re-iterate after each delete successful */
-       while ((i = iptc_next_chain(last, handle)) != NULL) {
-               if (!iptc_flush_entries(i, handle)
-                   || !iptc_delete_chain(i, handle))
-                       return 0;
+       iptc_handle_t handle;
+
+       handle = iptc_init(tablename);
+       if (!handle) {
+               exit_error(PARAMETER_PROBLEM, "%s: unable to initialize"
+                       "table '%s'\n", program_name, tablename);
+               exit(1);
        }
-       return 1;
+       return handle;
 }
 
+
 int main(int argc, char *argv[])
 {
        iptc_handle_t handle;
        char buffer[10240];
        int counters = 0, binary = 0, verbose = 0;
        unsigned int line = 0;
-       int c;
-       const char *chain;
+       char curtable[IPT_TABLE_MAXNAMELEN + 1];
+       char curchain[IPT_FUNCTION_MAXNAMELEN + 1];
        FILE *in;
 
        program_name = "iptables-restore";
@@ -65,8 +77,8 @@ int main(int argc, char *argv[])
                exit(1);
        }
        else in = stdin;
-
-       handle = iptc_init();
+/*
+       handle = iptc_init("filter");
        if (!handle)
                exit_error(VERSION_PROBLEM,
                           "can't initialize iptables-restore: %s",
@@ -75,7 +87,7 @@ int main(int argc, char *argv[])
        if (!clean_slate(&handle))
                exit_error(OTHER_PROBLEM, "Deleting old chains: %s",
                           iptc_strerror(errno));
-
+*/
        /* Grab standard input. */
        while (fgets(buffer, sizeof(buffer), in)) {
                int ret;
@@ -85,37 +97,84 @@ int main(int argc, char *argv[])
                else if (buffer[0] == '#') {
                        if (verbose) fputs(buffer, stdout);
                        continue;
-               } else if (strcmp(buffer, "COMMIT\n") == 0)
+               } else if (strcmp(buffer, "COMMIT\n") == 0) {
+                       DEBUGP("Calling commit\n");
                        ret = iptc_commit(&handle);
-               else if (buffer[0] == ':') {
+               } else if (buffer[0] == '*') {
+                       /* New table */
+                       char *table;
+
+                       table = strtok(buffer+1, " \t\n");
+                       DEBUGP("line %u, table '%s'\n", line, table);
+                       if (!table) {
+                               exit_error(PARAMETER_PROBLEM, 
+                                       "%s: line %u table name invalid\n",
+                                       program_name, line);
+                               exit(1);
+                       }
+                       strncpy(curtable, table, IPT_TABLE_MAXNAMELEN);
+
+                       handle = create_handle(table);
+
+                       DEBUGP("Cleaning all chains of table '%s'\n", table);
+                       for_each_chain(flush_entries, verbose, 1, &handle) ;
+
+                       DEBUGP("Deleting all user-defined chains of table '%s'\n", table);
+                       for_each_chain(delete_chain, verbose, 0, &handle) ;
+
+                       ret = 1;
+
+               } else if (buffer[0] == ':') {
                        /* New chain. */
-                       char *chain, *policy;
+                       char *policy, *chain;
 
                        /* FIXME: Don't ignore counters. */
+
                        chain = strtok(buffer+1, " \t\n");
+                       DEBUGP("line %u, chain '%s'\n", line, chain);
                        if (!chain) {
                                exit_error(PARAMETER_PROBLEM,
                                           "%s: line %u chain name invalid\n",
                                           program_name, line);
                                exit(1);
                        }
+                       strncpy(curchain, chain, IPT_FUNCTION_MAXNAMELEN);
+
+                       /* why the f... does iptc_builtin not work here ? */
+//                     if (!iptc_builtin(curchain, &handle)) {
+                               DEBUGP("Creating new chain '%s'\n", curchain);
+                               if (!iptc_create_chain(curchain, &handle))
+                               DEBUGP("unable to create chain '%s':%s\n", curchain,
+                                       strerror(errno));
+//                     }
+
                        policy = strtok(NULL, " \t\n");
+                       DEBUGP("line %u, policy '%s'\n", line, policy);
                        if (!policy) {
                                exit_error(PARAMETER_PROBLEM,
                                           "%s: line %u policy invalid\n",
                                           program_name, line);
                                exit(1);
                        }
-                       if (strcmp(policy, "-") != 0
-                           && !iptc_set_policy(chain, policy, &handle))
-                               exit_error(OTHER_PROBLEM,
-                                          "Can't set policy `%s'"
-                                          " on `%s' line %u: %s\n",
-                                          chain, policy, line,
-                                          iptc_strerror(errno));
+
+                       if (strcmp(policy, "-") != 0) {
+
+                               DEBUGP("Setting policy of chain %s to %s\n",
+                                       chain, policy);
+
+                               if (!iptc_set_policy(chain, policy, &handle))
+                                       exit_error(OTHER_PROBLEM,
+                                               "Can't set policy `%s'"
+                                               " on `%s' line %u: %s\n",
+                                               chain, policy, line,
+                                               iptc_strerror(errno));
+                       }
+
+                       ret = 1;
+
                } else {
                        char *newargv[1024];
-                       int i;
+                       int i,a;
                        char *ptr = buffer;
 
                        /* FIXME: Don't ignore counters. */
@@ -127,9 +186,14 @@ int main(int argc, char *argv[])
                                                   line);
                        }
 
-                       /* strtok: a function only a coder could love */
                        newargv[0] = argv[0];
-                       for (i = 1; i < sizeof(newargv)/sizeof(char *); i++) {
+                       newargv[1] = "-t";
+                       newargv[2] = (char *) &curtable;
+                       newargv[3] = "-A";
+                       newargv[4] = (char *) &curchain;
+
+                       /* strtok: a function only a coder could love */
+                       for (i = 5; i < sizeof(newargv)/sizeof(char *); i++) {
                                if (!(newargv[i] = strtok(ptr, " \t\n")))
                                        break;
                                ptr = NULL;
@@ -141,7 +205,13 @@ int main(int argc, char *argv[])
                                exit(1);
                        }
 
-                       ret = do_command(i, newargv, &handle);
+                       DEBUGP("===>calling do_command(%u, argv, &%s, handle):\n",
+                                       i, curtable);
+
+                       for (a = 0; a <= i; a++)
+                               DEBUGP("argv[%u]: %s\n", a, newargv[a]);
+
+                       ret = do_command(i, newargv, &newargv[2], &handle);
                }
                if (!ret) {
                        fprintf(stderr, "%s: line %u failed\n",
index d858817eb9157f705edcd280ab164b2ae5866807..413e1ad3393f927fcc285aa646801f6fbbcb06b7 100644 (file)
@@ -1,7 +1,13 @@
 /* Code to save the iptables state, in human readable-form. */
+/* Authors: Paul 'Rusty' Russel <rusty@linuxcare.com.au> and
+ *         Harald Welte <laforge@gnumonks.org>
+ */
 #include <getopt.h>
 #include <sys/errno.h>
 #include <stdio.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
 #include <dlfcn.h>
 #include <time.h>
 #include "libiptc/libiptc.h"
@@ -47,6 +53,8 @@ print_iface(char letter, const char *iface, const unsigned char *mask,
                        break;
                }
        }
+
+       printf(" ");
 }
 
 /* These are hardcoded backups in iptables.c, so they are safe */
@@ -55,6 +63,7 @@ struct pprot {
        u_int8_t num;
 };
 
+/* FIXME: why don't we use /etc/services ? */
 static const struct pprot chain_protos[] = {
        { "tcp", IPPROTO_TCP },
        { "udp", IPPROTO_UDP },
@@ -78,6 +87,7 @@ static void print_proto(u_int16_t proto, int invert)
        }
 }
 
+#if 0
 static int non_zero(const void *ptr, size_t size)
 {
        unsigned int i;
@@ -88,74 +98,97 @@ static int non_zero(const void *ptr, size_t size)
 
        return 1;
 }
+#endif
+
+static int print_match(const struct ipt_entry_match *e)
+{
+       struct iptables_match *match
+               = find_match(e->u.user.name, TRY_LOAD);
+
+       if (match) {
+               printf("-m %s ", e->u.user.name);
+               match->save(NULL, e);
+       } else {
+               if (e->u.match_size) {
+                       fprintf(stderr,
+                               "Can't find library for match `%s'\n",
+                               e->u.user.name);
+                       exit(1);
+               }
+       }
+       return 0;
+}
+
+/* print a given ip including mask if neccessary */
+static void print_ip(char *prefix, u_int32_t ip, u_int32_t mask, int invert)
+{
+       if (!mask && !ip)
+               return;
+
+       printf("%s %s%u.%u.%u.%u",
+               prefix,
+               invert ? "! " : "",
+               IP_PARTS(ip));
+
+       if (mask != 0xffffffff) 
+               printf("/%u.%u.%u.%u ", IP_PARTS(mask));
+       else
+               printf(" ");
+}
 
 /* We want this to be readable, so only print out neccessary fields.
  * Because that's the kind of world I want to live in.  */
-static void print_rule(const struct ipt_entry *e, int counters)
+static void print_rule(const struct ipt_entry *e, 
+               iptc_handle_t *h, int counters)
 {
+       struct ipt_entry_target *t;
+
+       /* print counters */
        if (counters)
                printf("[%llu,%llu] ", e->counters.pcnt, e->counters.bcnt);
 
        /* Print IP part. */
-       if (e->ip.smsk.s_addr)
-               printf("-s %s%u.%u.%u.%u/%u.%u.%u.%u ",
-                      e->ip.invflags & IPT_INV_SRCIP ? "! " : "",
-                      IP_PARTS(e->ip.src.s_addr),
-                      IP_PARTS(e->ip.smsk.s_addr));
-       if (e->ip.dmsk.s_addr)
-               printf("-d %s%u.%u.%u.%u/%u.%u.%u.%u ",
-                      e->ip.invflags & IPT_INV_SRCIP ? "! " : "",
-                      IP_PARTS(e->ip.dst.s_addr),
-                      IP_PARTS(e->ip.dmsk.s_addr));
+       print_ip("-s", e->ip.src.s_addr,e->ip.smsk.s_addr,
+                       e->ip.invflags & IPT_INV_SRCIP);        
+
+       print_ip("-d", e->ip.dst.s_addr, e->ip.dmsk.s_addr,
+                       e->ip.invflags & IPT_INV_SRCIP);
 
        print_iface('i', e->ip.iniface, e->ip.iniface_mask,
                    e->ip.invflags & IPT_INV_VIA_IN);
+
        print_iface('o', e->ip.outiface, e->ip.outiface_mask,
                    e->ip.invflags & IPT_INV_VIA_OUT);
+
        print_proto(e->ip.proto, e->ip.invflags & IPT_INV_PROTO);
 
        if (e->ip.flags & IPT_F_FRAG)
                printf("%s-f ",
                       e->ip.invflags & IPT_INV_FRAG ? "! " : "");
 
-       if (e->ip.flags & IPT_F_TOS)
-               printf("-t %s0x%02X ",
-                      e->ip.invflags & IPT_INV_TOS ? "! " : "",
-                      e->ip.tos);
-
        /* Print matchinfo part */
-       if (e->match_name[0]) {
-               struct iptables_match *match
-                       = find_match(e->match_name, TRY_LOAD);
-
-               if (match)
-                       match->save(e);
-               else {
-                       /* If some bits are non-zero, it implies we *need*
-                          to understand it */
-                       if (non_zero(&e->matchinfo, sizeof(e->matchinfo))) {
-                               fprintf(stderr,
-                                       "Can't find library for match `%s'\n",
-                                       e->match_name);
-                               exit(1);
-                       }
-               }
+       if (e->target_offset) {
+               IPT_MATCH_ITERATE(e, print_match);
        }
 
+       /* Print target name */ 
+       printf("-j %s ", iptc_get_target(e, h));
+
        /* Print targinfo part */
-       if (e->target_name[0]) {
+       t = ipt_get_target(e);
+       if (t->u.user.name[0]) {
                struct iptables_target *target
-                       = find_target(e->target_name, TRY_LOAD);
+                       = find_target(t->u.user.name, TRY_LOAD);
 
                if (target)
-                       target->save(e);
+                       target->save(NULL, t);
                else {
                        /* If some bits are non-zero, it implies we *need*
                           to understand it */
-                       if (non_zero(&e->targinfo, sizeof(e->targinfo))) {
+                       if (t->u.target_size) {
                                fprintf(stderr,
                                        "Can't find library for target `%s'\n",
-                                       e->target_name);
+                                       t->u.user.name);
                                exit(1);
                        }
                }
@@ -164,15 +197,13 @@ static void print_rule(const struct ipt_entry *e, int counters)
 }
 
 /* Debugging prototype. */
-extern void dump_entries(iptc_handle_t handle);
-
 static int for_each_table(int (*func)(const char *tablename))
 {
         int ret = 1;
-       FILE *procfile;
+       FILE *procfile = NULL;
        char tablename[IPT_TABLE_MAXNAMELEN+1];
 
-       procfile = fopen("/proc/net/ip_tables_names", O_RDONLY);
+       procfile = fopen("/proc/net/ip_tables_names", "r");
        if (!procfile)
                return 0;
 
@@ -189,21 +220,6 @@ static int for_each_table(int (*func)(const char *tablename))
 }
        
 
-static int dump_table(const char *tablename)
-{
-       iptc_handle_t h;
-
-       if (!tablename)
-               return for_each_table(&dump_table);
-
-       /* Debugging dump. */
-       h = iptc_init(tablename);
-       if (!h)
-               exit_error(OTHER_PROBLEM, "iptc_init: %s\n",
-                          iptc_strerror(errno));
-       dump_entries(h);
-}
-       
 static int do_output(const char *tablename)
 {
        iptc_handle_t h;
@@ -222,39 +238,29 @@ static int do_output(const char *tablename)
 
                printf("# Generated by iptables-save v%s on %s",
                       NETFILTER_VERSION, ctime(&now));
+               printf("*%s\n", tablename);
 
                /* Dump out chain names */
                for (chain = iptc_first_chain(&h);
                     chain;
                     chain = iptc_next_chain(&h)) {
+                       const struct ipt_entry *e;
+
                        printf(":%s ", chain);
-                       if (iptc_builtin(chain, &h)) {
+                       if (iptc_builtin(chain, h)) {
                                struct ipt_counters count;
                                printf("%s ",
                                       iptc_get_policy(chain, &count, &h));
-                               printf("%llu %llu\n", count.pcnt, count.bcnt);
+                               printf("%llu:%llu\n", count.pcnt, count.bcnt);
                        } else {
                                printf("- 0 0\n");
                        }
-               }
 
-               /* Dump out rules */
-               for (chain = iptc_first_chain(&h);
-                    chain;
-                    chain = iptc_next_chain(&h)) {
-                       unsigned int i;
-
-                       for (i = 0; i < iptc_num_rules(chain, &h); i++) {
-                               const struct ipt_entry *e
-                                       = iptc_get_rule(chain, i, &h);
-
-                               if (!e)
-                                       exit_error(OTHER_PROBLEM,
-                                                  "Can't read rule %u"
-                                                  " of chain %s: %s\n",
-                                                  i, chain,
-                                                  iptc_strerror(errno));
-                               print_rule(e, counters);
+                       /* Dump out rules */
+                       e = iptc_first_rule(chain, &h);
+                       while(e) {
+                               print_rule(e, &h, counters);
+                               e = iptc_next_rule(e, &h);
                        }
                }
 
@@ -296,7 +302,7 @@ int main(int argc, char *argv[])
                        tablename = optarg;
                        break;
                case 'd':
-                       dump_table(tablename);
+                       do_output(tablename);
                        exit(0);
                }
        }
index dfbc0fa39f76fbe17e7b75f84b493f6fe08854fa..53d21890f85e53c0476db72e7934798ebdb7b601 100644 (file)
@@ -33,14 +33,21 @@ main(int argc, char *argv[])
 {
        int ret;
        char *table = "filter";
-       iptc_handle_t handle;
+       iptc_handle_t *handle;
+
+       handle = (iptc_handle_t *) malloc(sizeof(iptc_handle_t));
+       if (!handle) {
+               fprintf(stderr, "out of memory\n");
+               exit(1);
+       }
+       memset(handle, 0, sizeof(iptc_handle_t));
 
        program_name = "iptables";
        program_version = NETFILTER_VERSION;
 
-       ret = do_command(argc, argv, &table, &handle);
+       ret = do_command(argc, argv, &table, handle);
        if (ret)
-               ret = iptc_commit(&handle);
+               ret = iptc_commit(handle);
 
        if (!ret)
                fprintf(stderr, "iptables: %s\n",
index 4dbe8917d54c5ed20459c236fd50599e2036c68c..73f400b5330e8b84a945c10758fb9e506fc70aa6 100644 (file)
@@ -126,7 +126,7 @@ static struct option original_opts[] = {
 };
 
 #ifndef __OPTIMIZE__
-static struct ipt_entry_target *
+struct ipt_entry_target *
 ipt_get_target(struct ipt_entry *e)
 {
        return (void *)e + e->target_offset;
@@ -643,6 +643,9 @@ find_match(const char *name, enum ipt_tryload tryload)
                                   name, dlerror());
        }
 
+       if (ptr)
+               ptr->used = 1;
+
        return ptr;
 }
 
@@ -893,6 +896,9 @@ find_target(const char *name, enum ipt_tryload tryload)
                                   name, dlerror());
        }
 
+       if (ptr)
+               ptr->used = 1;
+
        return ptr;
 }
 
@@ -1290,7 +1296,7 @@ make_delete_mask(struct ipt_entry *fw)
        unsigned char *mask, *mptr;
 
        size = sizeof(struct ipt_entry);
-       for (m = iptables_matches; m; m = m->next)
+       for (m = iptables_matches; m && m->used; m = m->next)
                size += IPT_ALIGN(sizeof(struct ipt_entry_match)) + m->size;
 
        mask = fw_calloc(1, size
@@ -1300,7 +1306,7 @@ make_delete_mask(struct ipt_entry *fw)
        memset(mask, 0xFF, sizeof(struct ipt_entry));
        mptr = mask + sizeof(struct ipt_entry);
 
-       for (m = iptables_matches; m; m = m->next) {
+       for (m = iptables_matches; m && m->used; m = m->next) {
                memset(mptr, 0xFF,
                       IPT_ALIGN(sizeof(struct ipt_entry_match))
                       + m->userspacesize);
@@ -1370,7 +1376,7 @@ check_packet(const ipt_chainlabel chain,
        return ret;
 }
 
-static int
+int
 for_each_chain(int (*fn)(const ipt_chainlabel, int, iptc_handle_t *),
               int verbose, int builtinstoo, iptc_handle_t *handle)
 {
@@ -1406,7 +1412,7 @@ for_each_chain(int (*fn)(const ipt_chainlabel, int, iptc_handle_t *),
         return ret;
 }
 
-static int
+int
 flush_entries(const ipt_chainlabel chain, int verbose,
              iptc_handle_t *handle)
 {
@@ -1430,7 +1436,7 @@ zero_entries(const ipt_chainlabel chain, int verbose,
        return iptc_zero_entries(chain, handle);
 }
 
-static int
+int
 delete_chain(const ipt_chainlabel chain, int verbose,
             iptc_handle_t *handle)
 {
@@ -1505,7 +1511,7 @@ generate_entry(const struct ipt_entry *fw,
        struct ipt_entry *e;
 
        size = sizeof(struct ipt_entry);
-       for (m = matches; m; m = m->next)
+       for (m = matches; m && m->used; m = m->next)
                size += m->m->u.match_size;
 
        e = fw_malloc(size + target->u.target_size);
@@ -1514,7 +1520,7 @@ generate_entry(const struct ipt_entry *fw,
        e->next_offset = size + target->u.target_size;
 
        size = 0;
-       for (m = matches; m; m = m->next) {
+       for (m = matches; m && m->used; m = m->next) {
                memcpy(e->elems + size, m->m, m->m->u.match_size);
                size += m->m->u.match_size;
        }
@@ -1538,11 +1544,28 @@ int do_command(int argc, char *argv[], char **table, iptc_handle_t *handle)
        int ret = 1;
        struct iptables_match *m;
        struct iptables_target *target = NULL;
+       struct iptables_target *t;
        const char *jumpto = "";
        char *protocol = NULL;
 
        memset(&fw, 0, sizeof(fw));
 
+       /* re-set optind to 0 in case do_command gets called
+        * a second time */
+       optind = 0;
+
+       /* clear mflags in case do_command gets called a second time
+        * (we clear the global list of all matches for security)*/
+       for (m = iptables_matches; m; m = m->next) {
+               m->mflags = 0;
+               m->used = 0;
+       }
+
+       for (t = iptables_targets; t; t = t->next) {
+               t->tflags = 0;
+               t->used = 0;
+       }
+
        /* Suppress error messages: we may add new options if we
            demand-load a protocol. */
        opterr = 0;
@@ -1845,7 +1868,7 @@ int do_command(int argc, char *argv[], char **table, iptc_handle_t *handle)
                                               argv, invert,
                                               &target->tflags,
                                               &fw, &target->t))) {
-                               for (m = iptables_matches; m; m = m->next) {
+                               for (m = iptables_matches; m && m->used; m = m->next) {
                                        if (m->parse(c - m->option_offset,
                                                     argv, invert,
                                                     &m->mflags,
@@ -1886,7 +1909,7 @@ int do_command(int argc, char *argv[], char **table, iptc_handle_t *handle)
                invert = FALSE;
        }
 
-       for (m = iptables_matches; m; m = m->next)
+       for (m = iptables_matches; m && m->used; m = m->next)
                m->final_check(m->mflags);
        if (target)
                target->final_check(target->tflags);
@@ -1938,7 +1961,10 @@ int do_command(int argc, char *argv[], char **table, iptc_handle_t *handle)
                           "chain name `%s' too long (must be under %i chars)",
                           chain, IPT_FUNCTION_MAXNAMELEN);
 
-       *handle = iptc_init(*table);
+       /* only allocate handle if we weren't called with a handle */
+       if (!*handle)
+               *handle = iptc_init(*table);
+
        if (!*handle)
                exit_error(VERSION_PROBLEM,
                           "can't initialize iptables table `%s': %s",