selectively delete chains in filter and nat tables
authorJo-Philipp Wich <jow@openwrt.org>
Mon, 18 Feb 2013 01:54:15 +0000 (02:54 +0100)
committerJo-Philipp Wich <jow@openwrt.org>
Mon, 18 Feb 2013 19:41:56 +0000 (20:41 +0100)
13 files changed:
defaults.c
defaults.h
forwards.c
ipsets.c
ipsets.h
main.c
options.h
redirects.c
rules.c
utils.c
utils.h
zones.c
zones.h

index 498e5d5..1a25eaf 100644 (file)
 #include "defaults.h"
 
 
+#define C(f, tbl, def, name) \
+       { FW3_FAMILY_##f, FW3_TABLE_##tbl, FW3_DEFAULT_##def, name }
+
+struct chain {
+       enum fw3_family family;
+       enum fw3_table table;
+       enum fw3_default flag;
+       const char *name;
+};
+
+static const struct chain default_chains[] = {
+       C(ANY, FILTER, UNSPEC,        "delegate_input"),
+       C(ANY, FILTER, UNSPEC,        "delegate_output"),
+       C(ANY, FILTER, UNSPEC,        "delegate_forward"),
+       C(ANY, FILTER, CUSTOM_CHAINS, "input_rule"),
+       C(ANY, FILTER, CUSTOM_CHAINS, "output_rule"),
+       C(ANY, FILTER, CUSTOM_CHAINS, "forwarding_rule"),
+       C(ANY, FILTER, UNSPEC,        "reject"),
+       C(ANY, FILTER, SYN_FLOOD,     "syn_flood"),
+
+       C(V4,  NAT,    UNSPEC,        "delegate_prerouting"),
+       C(V4,  NAT,    UNSPEC,        "delegate_postrouting"),
+       C(V4,  NAT,    CUSTOM_CHAINS, "prerouting_rule"),
+       C(V4,  NAT,    CUSTOM_CHAINS, "postrouting_rule"),
+
+       C(ANY, MANGLE, UNSPEC,        "mssfix"),
+       C(ANY, RAW,    UNSPEC,        "notrack"),
+};
+
+static const struct chain toplevel_rules[] = {
+       C(ANY, FILTER, UNSPEC,        "INPUT -j delegate_input"),
+       C(ANY, FILTER, UNSPEC,        "OUTPUT -j delegate_output"),
+       C(ANY, FILTER, UNSPEC,        "FORWARD -j delegate_forward"),
+
+       C(V4,  NAT,    UNSPEC,        "PREROUTING -j delegate_prerouting"),
+       C(V4,  NAT,    UNSPEC,        "POSTROUTING -j delegate_postrouting"),
+
+       C(ANY, MANGLE, UNSPEC,        "FORWARD -j mssfix"),
+       C(ANY, RAW,    UNSPEC,        "PREROUTING -j notrack"),
+};
+
 static struct fw3_option default_opts[] = {
        FW3_OPT("input",               target,   defaults, policy_input),
        FW3_OPT("forward",             target,   defaults, policy_forward),
@@ -44,6 +85,33 @@ static struct fw3_option default_opts[] = {
 };
 
 
+static bool
+print_chains(enum fw3_table table, enum fw3_family family,
+             const char *fmt, uint8_t flags,
+             const struct chain *chains, int n)
+{
+       bool rv = false;
+       const struct chain *c;
+
+       for (c = chains; n > 0; c++, n--)
+       {
+               if (!fw3_is_family(c, family))
+                       continue;
+
+               if (c->table != table)
+                       continue;
+
+               if ((c->flag != FW3_DEFAULT_UNSPEC) && !(flags & (1 << c->flag)))
+                       continue;
+
+               fw3_pr(fmt, c->name);
+
+               rv = true;
+       }
+
+       return rv;
+}
+
 static void
 check_policy(struct uci_element *e, enum fw3_target *pol, const char *name)
 {
@@ -93,6 +161,12 @@ fw3_load_defaults(struct fw3_state *state, struct uci_package *p)
                check_policy(e, &defs->policy_input, "input");
                check_policy(e, &defs->policy_output, "output");
                check_policy(e, &defs->policy_forward, "forward");
+
+               if (defs->custom_chains)
+                       defs->has_flag |= (1 << FW3_DEFAULT_CUSTOM_CHAINS);
+
+               if (defs->syn_flood)
+                       defs->has_flag |= (1 << FW3_DEFAULT_SYN_FLOOD);
        }
 }
 
@@ -111,72 +185,53 @@ fw3_print_default_chains(enum fw3_table table, enum fw3_family family,
                "(bug)",
        };
 
-       switch (table)
+       if (table == FW3_TABLE_FILTER)
        {
-       case FW3_TABLE_FILTER:
                fw3_pr(":INPUT %s [0:0]\n", policy[defs->policy_input]);
                fw3_pr(":FORWARD %s [0:0]\n", policy[defs->policy_forward]);
                fw3_pr(":OUTPUT %s [0:0]\n", policy[defs->policy_output]);
-
-               if (defs->custom_chains)
-               {
-                       fw3_pr(":input_rule - [0:0]\n");
-                       fw3_pr(":output_rule - [0:0]\n");
-                       fw3_pr(":forwarding_rule - [0:0]\n");
-               }
-
-               fw3_pr(":delegate_input - [0:0]\n");
-               fw3_pr(":delegate_output - [0:0]\n");
-               fw3_pr(":delegate_forward - [0:0]\n");
-               fw3_pr(":reject - [0:0]\n");
-               fw3_pr(":syn_flood - [0:0]\n");
-               break;
-
-       case FW3_TABLE_NAT:
-               if (defs->custom_chains)
-               {
-                       fw3_pr(":prerouting_rule - [0:0]\n");
-                       fw3_pr(":postrouting_rule - [0:0]\n");
-               }
-               break;
-
-       case FW3_TABLE_MANGLE:
-               fw3_pr(":mssfix - [0:0]\n");
-               break;
-
-       case FW3_TABLE_RAW:
-               if (!defs->drop_invalid)
-                       fw3_pr(":notrack - [0:0]\n");
-               break;
        }
+
+       print_chains(table, family, ":%s - [0:0]\n", defs->has_flag,
+                    default_chains, ARRAY_SIZE(default_chains));
 }
 
 void
-fw3_print_default_rules(enum fw3_table table, enum fw3_family family,
-                        struct fw3_state *state)
+fw3_print_default_head_rules(enum fw3_table table, enum fw3_family family,
+                             struct fw3_state *state)
 {
        int i;
        struct fw3_defaults *defs = &state->defaults;
        const char *chains[] = {
-               "INPUT",
-               "OUTPUT",
-               "FORWARD",
+               "input",
+               "output",
+               "forward",
        };
 
+       print_chains(table, family, "-A %s\n", 0,
+                    toplevel_rules, ARRAY_SIZE(toplevel_rules));
+
        switch (table)
        {
        case FW3_TABLE_FILTER:
-               fw3_pr("-A INPUT -i lo -j ACCEPT\n");
-               fw3_pr("-A OUTPUT -o lo -j ACCEPT\n");
+               fw3_pr("-A delegate_input -i lo -j ACCEPT\n");
+               fw3_pr("-A delegate_output -o lo -j ACCEPT\n");
+
+               if (defs->custom_chains)
+               {
+                       fw3_pr("-A delegate_input -j input_rule\n");
+                       fw3_pr("-A delegate_output -j output_rule\n");
+                       fw3_pr("-A delegate_forward -j forwarding_rule\n");
+               }
 
                for (i = 0; i < ARRAY_SIZE(chains); i++)
                {
-                       fw3_pr("-A %s -m conntrack --ctstate RELATED,ESTABLISHED "
+                       fw3_pr("-A delegate_%s -m conntrack --ctstate RELATED,ESTABLISHED "
                               "-j ACCEPT\n", chains[i]);
 
                        if (defs->drop_invalid)
                        {
-                               fw3_pr("-A %s -m conntrack --ctstate INVALID -j DROP\n",
+                               fw3_pr("-A delegate_%s -m conntrack --ctstate INVALID -j DROP\n",
                                       chains[i]);
                        }
                }
@@ -188,96 +243,91 @@ fw3_print_default_rules(enum fw3_table table, enum fw3_family family,
                        fw3_pr(" -j RETURN\n");
 
                        fw3_pr("-A syn_flood -j DROP\n");
-                       fw3_pr("-A INPUT -p tcp --syn -j syn_flood\n");
-               }
-
-               if (defs->custom_chains)
-               {
-                       fw3_pr("-A INPUT -j input_rule\n");
-                       fw3_pr("-A OUTPUT -j output_rule\n");
-                       fw3_pr("-A FORWARD -j forwarding_rule\n");
+                       fw3_pr("-A delegate_input -p tcp --syn -j syn_flood\n");
                }
 
-               fw3_pr("-A INPUT -j delegate_input\n");
-               fw3_pr("-A OUTPUT -j delegate_output\n");
-               fw3_pr("-A FORWARD -j delegate_forward\n");
-
                fw3_pr("-A reject -p tcp -j REJECT --reject-with tcp-reset\n");
                fw3_pr("-A reject -j REJECT --reject-with port-unreach\n");
 
-               if (defs->policy_input == FW3_TARGET_REJECT)
-                       fw3_pr("-A INPUT -j reject\n");
-
-               if (defs->policy_output == FW3_TARGET_REJECT)
-                       fw3_pr("-A OUTPUT -j reject\n");
-
-               if (defs->policy_forward == FW3_TARGET_REJECT)
-                       fw3_pr("-A FORWARD -j reject\n");
-
                break;
 
        case FW3_TABLE_NAT:
                if (defs->custom_chains)
                {
-                       fw3_pr("-A PREROUTING -j prerouting_rule\n");
-                       fw3_pr("-A POSTROUTING -j postrouting_rule\n");
+                       fw3_pr("-A delegate_prerouting -j prerouting_rule\n");
+                       fw3_pr("-A delegate_postrouting -j postrouting_rule\n");
                }
                break;
 
-       case FW3_TABLE_MANGLE:
-               fw3_pr("-A FORWARD -j mssfix\n");
-               break;
-
-       case FW3_TABLE_RAW:
-               if (!defs->drop_invalid)
-                       fw3_pr("-A PREROUTING -j notrack\n");
+       default:
                break;
        }
 }
 
 void
-fw3_print_flush_rules(enum fw3_table table, enum fw3_family family,
-                                         struct fw3_state *state, bool complete)
+fw3_print_default_tail_rules(enum fw3_table table, enum fw3_family family,
+                             struct fw3_state *state)
 {
-       switch (table)
-       {
-       case FW3_TABLE_FILTER:
-               fw3_pr(":INPUT ACCEPT [0:0]\n");
-               fw3_pr(":OUTPUT ACCEPT [0:0]\n");
-               fw3_pr(":FORWARD ACCEPT [0:0]\n");
-               /* fall through */
+       struct fw3_defaults *defs = &state->defaults;
 
-       case FW3_TABLE_NAT:
-               fw3_pr("-F\n");
-               fw3_pr("-X\n");
-               break;
+       if (table != FW3_TABLE_FILTER)
+               return;
 
-       case FW3_TABLE_MANGLE:
-               if (complete)
-               {
-                       fw3_pr("-F\n");
-                       fw3_pr("-X\n");
-               }
-               else
-               {
-                       fw3_pr("-D FORWARD -j mssfix\n");
-                       fw3_pr("-F mssfix\n");
-                       fw3_pr("-X mssfix\n");
-               }
-               break;
+       if (defs->policy_input == FW3_TARGET_REJECT)
+               fw3_pr("-A delegate_input -j reject\n");
+
+       if (defs->policy_output == FW3_TARGET_REJECT)
+               fw3_pr("-A delegate_output -j reject\n");
+
+       if (defs->policy_forward == FW3_TARGET_REJECT)
+               fw3_pr("-A delegate_forward -j reject\n");
+}
+
+static void
+reset_policy(enum fw3_table table)
+{
+       if (table != FW3_TABLE_FILTER)
+               return;
+
+       fw3_pr(":INPUT ACCEPT [0:0]\n");
+       fw3_pr(":OUTPUT ACCEPT [0:0]\n");
+       fw3_pr(":FORWARD ACCEPT [0:0]\n");
+}
+
+void
+fw3_flush_rules(enum fw3_table table, enum fw3_family family,
+                bool pass2, struct list_head *statefile)
+{
+       struct fw3_statefile_entry *e;
 
-       case FW3_TABLE_RAW:
-               if (complete)
+       list_for_each_entry(e, statefile, list)
+       {
+               if (e->type != FW3_TYPE_DEFAULTS)
+                       continue;
+
+               if (!pass2)
                {
-                       fw3_pr("-F\n");
-                       fw3_pr("-X\n");
+                       reset_policy(table);
+
+                       print_chains(table, family, "-D %s\n", e->flags[0],
+                                    toplevel_rules, ARRAY_SIZE(toplevel_rules));
+
+                       print_chains(table, family, "-F %s\n", e->flags[0],
+                                    default_chains, ARRAY_SIZE(default_chains));
                }
                else
                {
-                       fw3_pr("-D PREROUTING -j notrack\n");
-                       fw3_pr("-F notrack\n");
-                       fw3_pr("-X notrack\n");
+                       print_chains(table, family, "-X %s\n", e->flags[0],
+                                    default_chains, ARRAY_SIZE(default_chains));
                }
-               break;
        }
 }
+
+void
+fw3_flush_all(enum fw3_table table)
+{
+       reset_policy(table);
+
+       fw3_pr("-F\n");
+       fw3_pr("-X\n");
+}
index 10ac68c..17f9ba9 100644 (file)
@@ -26,10 +26,15 @@ void fw3_load_defaults(struct fw3_state *state, struct uci_package *p);
 void fw3_print_default_chains(enum fw3_table table, enum fw3_family family,
                               struct fw3_state *state);
 
-void fw3_print_default_rules(enum fw3_table table, enum fw3_family family,
-                             struct fw3_state *state);
+void fw3_print_default_head_rules(enum fw3_table table, enum fw3_family family,
+                                  struct fw3_state *state);
 
-void fw3_print_flush_rules(enum fw3_table table, enum fw3_family family,
-                           struct fw3_state *state, bool complete);
+void fw3_print_default_tail_rules(enum fw3_table table, enum fw3_family family,
+                                  struct fw3_state *state);
+
+void fw3_flush_rules(enum fw3_table table, enum fw3_family family,
+                     bool pass2, struct list_head *statefile);
+
+void fw3_flush_all(enum fw3_table table);
 
 #endif
index c212c8c..d3750b5 100644 (file)
@@ -76,7 +76,7 @@ fw3_load_forwards(struct fw3_state *state, struct uci_package *p)
 
                if (forward->_dest)
                {
-                       forward->_dest->has_dest_target[FW3_TARGET_ACCEPT] = true;
+                       forward->_dest->has_dest_target |= (1 << FW3_TARGET_ACCEPT);
 
                        if (forward->_src &&
                            (forward->_src->conntrack || forward->_dest->conntrack))
index ca0bd29..215be73 100644 (file)
--- a/ipsets.c
+++ b/ipsets.c
@@ -351,39 +351,22 @@ fw3_create_ipsets(struct fw3_state *state)
 }
 
 void
-fw3_destroy_ipsets(struct fw3_state *state)
+fw3_destroy_ipsets(struct list_head *statefile)
 {
-       FILE *sf;
-
-       char *p;
-       char line[128];
-
-       sf = fopen(FW3_STATEFILE, "r");
-
-       if (!sf)
-               return;
+       struct fw3_statefile_entry *e;
 
        info("Destroying ipsets ...");
 
-       while (fgets(line, sizeof(line), sf))
+       list_for_each_entry(e, statefile, list)
        {
-               if (strncmp(line, "ipset ", 6))
-                       continue;
-
-               p = strtok(line+6, " \t\n");
-
-               if (!p || !strlen(p))
+               if (e->type != FW3_TYPE_IPSET)
                        continue;
 
-               info(" * %s", p);
+               info(" * %s", e->name);
 
-               fw3_pr("flush %s\n", p);
-               fw3_pr("destroy %s\n", p);
+               fw3_pr("flush %s\n", e->name);
+               fw3_pr("destroy %s\n", e->name);
        }
-
-       fw3_pr("quit\n");
-
-       fclose(sf);
 }
 
 void
index 5ad6d99..49c6e66 100644 (file)
--- a/ipsets.h
+++ b/ipsets.h
@@ -40,7 +40,8 @@ struct fw3_ipset_settype {
 
 void fw3_load_ipsets(struct fw3_state *state, struct uci_package *p);
 void fw3_create_ipsets(struct fw3_state *state);
-void fw3_destroy_ipsets(struct fw3_state *state);
+
+void fw3_destroy_ipsets(struct list_head *statefile);
 
 void fw3_free_ipset(struct fw3_ipset *ipset);
 
diff --git a/main.c b/main.c
index 79324a4..fdb901a 100644 (file)
--- a/main.c
+++ b/main.c
@@ -125,11 +125,13 @@ restore_pipe(enum fw3_family family, bool silent)
 }
 
 static int
-stop(struct fw3_state *state, bool complete)
+stop(struct fw3_state *state, bool complete, bool ipsets)
 {
        enum fw3_family family;
        enum fw3_table table;
 
+       struct list_head *statefile = fw3_read_state();
+
        const char *tables[] = {
                "filter",
                "nat",
@@ -153,24 +155,37 @@ stop(struct fw3_state *state, bool complete)
                             complete ? "Flush" : "Clear", tables[table]);
 
                        fw3_pr("*%s\n", tables[table]);
-                       fw3_print_flush_rules(table, family, state, complete);
+
+                       if (complete)
+                       {
+                               fw3_flush_all(table);
+                       }
+                       else
+                       {
+                               /* pass 1 */
+                               fw3_flush_rules(table, family, false, statefile);
+                               fw3_flush_zones(table, family, false, statefile);
+
+                               /* pass 2 */
+                               fw3_flush_rules(table, family, true, statefile);
+                               fw3_flush_zones(table, family, true, statefile);
+                       }
+
                        fw3_pr("COMMIT\n");
                }
 
                fw3_command_close();
        }
 
-       return 0;
-}
+       if (ipsets && fw3_command_pipe(false, "ipset", "-exist", "-"))
+       {
+               fw3_destroy_ipsets(statefile);
+               fw3_command_close();
+       }
 
-static void
-destroy_ipsets(struct fw3_state *state)
-{
-       if (!fw3_command_pipe(false, "ipset", "-exist", "-"))
-               return;
+       fw3_free_state(statefile);
 
-       fw3_destroy_ipsets(state);
-       fw3_command_close();
+       return 0;
 }
 
 static int
@@ -209,11 +224,12 @@ start(struct fw3_state *state)
                        fw3_pr("*%s\n", tables[table]);
                        fw3_print_default_chains(table, family, state);
                        fw3_print_zone_chains(table, family, state);
-                       fw3_print_default_rules(table, family, state);
+                       fw3_print_default_head_rules(table, family, state);
                        fw3_print_rules(table, family, state);
                        fw3_print_redirects(table, family, state);
                        fw3_print_forwards(table, family, state);
                        fw3_print_zone_rules(table, family, state);
+                       fw3_print_default_tail_rules(table, family, state);
                        fw3_pr("COMMIT\n");
                }
 
@@ -355,17 +371,13 @@ int main(int argc, char **argv)
                        goto out;
                }
 
-               rv = stop(state, false);
-
-               destroy_ipsets(state);
+               rv = stop(state, false, true);
 
                fw3_remove_state();
        }
        else if (!strcmp(argv[optind], "flush"))
        {
-               rv = stop(state, true);
-
-               destroy_ipsets(state);
+               rv = stop(state, true, true);
 
                if (fw3_has_state())
                        fw3_remove_state();
@@ -374,7 +386,7 @@ int main(int argc, char **argv)
        {
                if (fw3_has_state())
                {
-                       stop(state, false);
+                       stop(state, false, false);
                        fw3_remove_state();
                }
 
index 0d9fb99..ee2c008 100644 (file)
--- a/options.h
+++ b/options.h
 
 enum fw3_table
 {
-       FW3_TABLE_FILTER,
-       FW3_TABLE_NAT,
-       FW3_TABLE_MANGLE,
-       FW3_TABLE_RAW,
+       FW3_TABLE_FILTER = 0,
+       FW3_TABLE_NAT    = 1,
+       FW3_TABLE_MANGLE = 2,
+       FW3_TABLE_RAW    = 3,
 };
 
 enum fw3_family
@@ -70,6 +70,15 @@ enum fw3_target
        FW3_TARGET_SNAT    = 6,
 };
 
+enum fw3_default
+{
+       FW3_DEFAULT_UNSPEC        = 0,
+       FW3_DEFAULT_CUSTOM_CHAINS = 1,
+       FW3_DEFAULT_SYN_FLOOD     = 2,
+       FW3_DEFAULT_MTU_FIX       = 3,
+       FW3_DEFAULT_DROP_INVALID  = 4,
+};
+
 enum fw3_limit_unit
 {
        FW3_LIMIT_UNIT_SECOND = 0,
@@ -200,6 +209,8 @@ struct fw3_defaults
        bool custom_chains;
 
        bool disable_ipv6;
+
+       uint8_t has_flag;
 };
 
 struct fw3_zone
@@ -233,8 +244,8 @@ struct fw3_zone
 
        bool custom_chains;
 
-       bool has_src_target[FW3_TARGET_SNAT + 1];
-       bool has_dest_target[FW3_TARGET_SNAT + 1];
+       uint8_t has_src_target;
+       uint8_t has_dest_target;
 };
 
 struct fw3_rule
index 2bf2c37..1fc81f0 100644 (file)
@@ -133,16 +133,16 @@ fw3_load_redirects(struct fw3_state *state, struct uci_package *p)
                                warn_elem(e, "has no source specified");
                        else
                        {
-                               redir->_src->has_dest_target[redir->target] = true;
+                               redir->_src->has_dest_target |= (1 << redir->target);
                                redir->_src->conntrack = true;
                                valid = true;
                        }
 
                        if (redir->reflection && redir->_dest && redir->_src->masq)
                        {
-                               redir->_dest->has_dest_target[FW3_TARGET_ACCEPT] = true;
-                               redir->_dest->has_dest_target[FW3_TARGET_DNAT]   = true;
-                               redir->_dest->has_dest_target[FW3_TARGET_SNAT]   = true;
+                               redir->_dest->has_dest_target |= (1 << FW3_TARGET_ACCEPT);
+                               redir->_dest->has_dest_target |= (1 << FW3_TARGET_DNAT);
+                               redir->_dest->has_dest_target |= (1 << FW3_TARGET_SNAT);
                        }
                }
                else
@@ -155,7 +155,7 @@ fw3_load_redirects(struct fw3_state *state, struct uci_package *p)
                                warn_elem(e, "has no src_dip option specified");
                        else
                        {
-                               redir->_dest->has_dest_target[redir->target] = true;
+                               redir->_dest->has_dest_target |= (1 << redir->target);
                                redir->_dest->conntrack = true;
                                valid = true;
                        }
diff --git a/rules.c b/rules.c
index 3ad2a6a..12c04c9 100644 (file)
--- a/rules.c
+++ b/rules.c
@@ -142,7 +142,7 @@ fw3_load_rules(struct fw3_state *state, struct uci_package *p)
                }
 
                if (rule->_dest)
-                       rule->_dest->has_dest_target[rule->target] = true;
+                       rule->_dest->has_dest_target |= (1 << rule->target);
 
                list_add_tail(&rule->list, &state->rules);
                continue;
diff --git a/utils.c b/utils.c
index a5d0082..4691fe1 100644 (file)
--- a/utils.c
+++ b/utils.c
@@ -332,17 +332,93 @@ fw3_unlock(void)
 }
 
 
-bool fw3_has_state(void)
+bool
+fw3_has_state(void)
 {
        struct stat s;
        return !stat(FW3_STATEFILE, &s);
 }
 
-void fw3_write_state(void *state)
+struct list_head *
+fw3_read_state(void)
+{
+       FILE *sf;
+
+       int n;
+       char line[128];
+       const char *p;
+
+       struct list_head *state;
+       struct fw3_statefile_entry *entry;
+
+       state = malloc(sizeof(*state));
+
+       if (!state)
+               return NULL;
+
+       INIT_LIST_HEAD(state);
+
+       sf = fopen(FW3_STATEFILE, "r");
+
+       if (!sf)
+       {
+               warn("Cannot open state %s: %s", FW3_STATEFILE, strerror(errno));
+               free(state);
+
+               return NULL;
+       }
+
+       while (fgets(line, sizeof(line), sf))
+       {
+               entry = malloc(sizeof(*entry));
+
+               if (!entry)
+                       continue;
+
+               memset(entry, 0, sizeof(*entry));
+
+               p = strtok(line, " \t\n");
+
+               if (!p)
+                       continue;
+
+               entry->type = strtoul(p, NULL, 10);
+
+               p = strtok(NULL, " \t\n");
+
+               if (!p)
+                       continue;
+
+               entry->name = strdup(p);
+
+               for (n = 0, p = strtok(NULL, " \t\n");
+                    n < ARRAY_SIZE(entry->flags) && p != NULL;
+                    n++, p = strtok(NULL, " \t\n"))
+               {
+                       entry->flags[n] = strtoul(p, NULL, 10);
+               }
+
+               list_add_tail(&entry->list, state);
+       }
+
+       fclose(sf);
+
+       return state;
+}
+
+void
+fw3_free_state(struct list_head *statefile)
+{
+       fw3_free_list(statefile);
+       free(statefile);
+}
+
+void
+fw3_write_state(void *state)
 {
        FILE *sf;
-       int n, val;
        struct fw3_state *s = state;
+       struct fw3_defaults *d = &s->defaults;
        struct fw3_zone *z;
        struct fw3_ipset *i;
 
@@ -354,19 +430,12 @@ void fw3_write_state(void *state)
                return;
        }
 
+       fprintf(sf, "%u - %u\n", FW3_TYPE_DEFAULTS, d->has_flag);
+
        list_for_each_entry(z, &s->zones, list)
        {
-               for (n = FW3_TARGET_ACCEPT, val = 0; n <= FW3_TARGET_SNAT; n++)
-                       if (z->has_src_target[n])
-                               val |= (1 << n);
-
-               fprintf(sf, "zone %s %u", z->name, val);
-
-               for (n = FW3_TARGET_ACCEPT, val = 0; n <= FW3_TARGET_SNAT; n++)
-                       if (z->has_dest_target[n])
-                               val |= (1 << n);
-
-               fprintf(sf, " %u\n", val);
+               fprintf(sf, "%u %s %u %u\n", FW3_TYPE_ZONE,
+                       z->name, z->has_src_target, z->has_dest_target);
        }
 
        list_for_each_entry(i, &s->ipsets, list)
@@ -374,13 +443,14 @@ void fw3_write_state(void *state)
                if (i->external && *i->external)
                        continue;
 
-               fprintf(sf, "ipset %s\n", i->name);
+               fprintf(sf, "%u %s\n", FW3_TYPE_IPSET, i->name);
        }
 
        fclose(sf);
 }
 
-void fw3_remove_state(void)
+void
+fw3_remove_state(void)
 {
        if (unlink(FW3_STATEFILE))
                warn("Unable to remove state %s: %s", FW3_STATEFILE, strerror(errno));
diff --git a/utils.h b/utils.h
index 90d7c9a..2178b5a 100644 (file)
--- a/utils.h
+++ b/utils.h
@@ -79,4 +79,23 @@ bool fw3_has_state(void);
 void fw3_write_state(void *state);
 void fw3_remove_state(void);
 
+
+enum fw3_statefile_type
+{
+       FW3_TYPE_DEFAULTS = 0,
+       FW3_TYPE_ZONE     = 1,
+       FW3_TYPE_IPSET    = 2,
+};
+
+struct fw3_statefile_entry
+{
+       struct list_head list;
+       enum fw3_statefile_type type;
+       const char *name;
+       uint32_t flags[2];
+};
+
+struct list_head * fw3_read_state(void);
+void fw3_free_state(struct list_head *statefile);
+
 #endif
diff --git a/zones.c b/zones.c
index 2820348..3ab17bf 100644 (file)
--- a/zones.c
+++ b/zones.c
 #include "ubus.h"
 
 
+#define C(f, tbl, tgt, name) \
+       { FW3_FAMILY_##f, FW3_TABLE_##tbl, FW3_TARGET_##tgt, name }
+
+struct chain {
+       enum fw3_family family;
+       enum fw3_table table;
+       enum fw3_target target;
+       const char *name;
+};
+
+static const struct chain src_chains[] = {
+       C(ANY, FILTER, UNSPEC,  "zone_%s_input"),
+       C(ANY, FILTER, UNSPEC,  "zone_%s_output"),
+       C(ANY, FILTER, UNSPEC,  "zone_%s_forward"),
+
+       C(ANY, FILTER, ACCEPT,  "zone_%s_src_ACCEPT"),
+       C(ANY, FILTER, REJECT,  "zone_%s_src_REJECT"),
+       C(ANY, FILTER, DROP,    "zone_%s_src_DROP"),
+};
+
+static const struct chain dst_chains[] = {
+       C(ANY, FILTER, ACCEPT,  "zone_%s_dest_ACCEPT"),
+       C(ANY, FILTER, REJECT,  "zone_%s_dest_REJECT"),
+       C(ANY, FILTER, DROP,    "zone_%s_dest_DROP"),
+
+       C(V4,  NAT,    SNAT,    "zone_%s_postrouting"),
+       C(V4,  NAT,    DNAT,    "zone_%s_prerouting"),
+
+       C(ANY, RAW,    NOTRACK, "zone_%s_notrack"),
+};
+
 static struct fw3_option zone_opts[] = {
        FW3_OPT("name",                string,   zone,     name),
 
@@ -48,6 +79,35 @@ static struct fw3_option zone_opts[] = {
 };
 
 
+static bool
+print_chains(enum fw3_table table, enum fw3_family family,
+             const char *fmt, const char *name, uint8_t targets,
+             const struct chain *chains, int n)
+{
+       bool rv = false;
+       char cn[128] = { 0 };
+       const struct chain *c;
+
+       for (c = chains; n > 0; c++, n--)
+       {
+               if (!fw3_is_family(c, family))
+                       continue;
+
+               if (c->table != table)
+                       continue;
+
+               if ((c->target != FW3_TARGET_UNSPEC) && !(targets & (1 << c->target)))
+                       continue;
+
+               snprintf(cn, sizeof(cn), c->name, name);
+               fw3_pr(fmt, cn);
+
+               rv = true;
+       }
+
+       return rv;
+}
+
 static void
 check_policy(struct uci_element *e, enum fw3_target *pol, enum fw3_target def,
              const char *name)
@@ -141,13 +201,13 @@ fw3_load_zones(struct fw3_state *state, struct uci_package *p)
 
                if (zone->masq)
                {
-                       zone->has_dest_target[FW3_TARGET_SNAT] = true;
+                       zone->has_dest_target |= (1 << FW3_TARGET_SNAT);
                        zone->conntrack = true;
                }
 
-               zone->has_src_target[zone->policy_input] = true;
-               zone->has_dest_target[zone->policy_output] = true;
-               zone->has_dest_target[zone->policy_forward] = true;
+               zone->has_src_target  |= (1 << zone->policy_input);
+               zone->has_dest_target |= (1 << zone->policy_output);
+               zone->has_dest_target |= (1 << zone->policy_forward);
 
                list_add_tail(&zone->list, &state->zones);
        }
@@ -158,60 +218,22 @@ static void
 print_zone_chain(enum fw3_table table, enum fw3_family family,
                  struct fw3_zone *zone, bool disable_notrack)
 {
-       enum fw3_target t;
-       const char *targets[] = {
-               "(bug)",
-               "ACCEPT",
-               "REJECT",
-               "DROP",
-       };
+       bool s, d;
 
        if (!fw3_is_family(zone, family))
                return;
 
-       switch (table)
-       {
-       case FW3_TABLE_FILTER:
-               info("   * Zone '%s'", zone->name);
-
-               for (t = FW3_TARGET_ACCEPT; t <= FW3_TARGET_DROP; t++)
-               {
-                       if (zone->has_src_target[t])
-                               fw3_pr(":zone_%s_src_%s - [0:0]\n", zone->name, targets[t]);
-
-                       if (zone->has_dest_target[t])
-                               fw3_pr(":zone_%s_dest_%s - [0:0]\n", zone->name, targets[t]);
-               }
-
-               fw3_pr(":zone_%s_forward - [0:0]\n", zone->name);
-               fw3_pr(":zone_%s_input - [0:0]\n", zone->name);
-               fw3_pr(":zone_%s_output - [0:0]\n", zone->name);
-               break;
+       if (!zone->conntrack && !disable_notrack)
+               zone->has_dest_target |= (1 << FW3_TARGET_NOTRACK);
 
-       case FW3_TABLE_NAT:
-               if (family == FW3_FAMILY_V4)
-               {
-                       info("   * Zone '%s'", zone->name);
-
-                       if (zone->has_dest_target[FW3_TARGET_SNAT])
-                               fw3_pr(":zone_%s_postrouting - [0:0]\n", zone->name);
-
-                       if (zone->has_dest_target[FW3_TARGET_DNAT])
-                               fw3_pr(":zone_%s_prerouting - [0:0]\n", zone->name);
-               }
-               break;
+       s = print_chains(table, family, ":%s - [0:0]\n", zone->name,
+                        zone->has_src_target, src_chains, ARRAY_SIZE(src_chains));
 
-       case FW3_TABLE_RAW:
-               if (!zone->conntrack && !disable_notrack)
-               {
-                       info("   * Zone '%s'", zone->name);
-                       fw3_pr(":zone_%s_notrack - [0:0]\n", zone->name);
-               }
-               break;
+       d = print_chains(table, family, ":%s - [0:0]\n", zone->name,
+                        zone->has_dest_target, dst_chains, ARRAY_SIZE(dst_chains));
 
-       case FW3_TABLE_MANGLE:
-               break;
-       }
+       if (s || d)
+               info("   * Zone '%s'", zone->name);
 }
 
 static void
@@ -231,7 +253,7 @@ print_interface_rule(enum fw3_table table, enum fw3_family family,
        {
                for (t = FW3_TARGET_ACCEPT; t <= FW3_TARGET_DROP; t++)
                {
-                       if (zone->has_src_target[t])
+                       if (zone->has_src_target & (1 << t))
                        {
                                fw3_pr("-A zone_%s_src_%s", zone->name, targets[t*2]);
                                fw3_format_in_out(dev, NULL);
@@ -240,7 +262,7 @@ print_interface_rule(enum fw3_table table, enum fw3_family family,
                                fw3_pr(" -j %s\n", targets[t*2+1]);
                        }
 
-                       if (zone->has_dest_target[t])
+                       if (zone->has_dest_target & (1 << t))
                        {
                                fw3_pr("-A zone_%s_dest_%s", zone->name, targets[t*2]);
                                fw3_format_in_out(NULL, dev);
@@ -270,18 +292,18 @@ print_interface_rule(enum fw3_table table, enum fw3_family family,
        }
        else if (table == FW3_TABLE_NAT)
        {
-               if (zone->has_dest_target[FW3_TARGET_DNAT])
+               if (zone->has_dest_target & (1 << FW3_TARGET_DNAT))
                {
-                       fw3_pr("-A PREROUTING");
+                       fw3_pr("-A delegate_prerouting");
                        fw3_format_in_out(dev, NULL);
                        fw3_format_src_dest(sub, NULL);
                        fw3_format_extra(zone->extra_src);
                        fw3_pr(" -j zone_%s_prerouting\n", zone->name);
                }
 
-               if (zone->has_dest_target[FW3_TARGET_SNAT])
+               if (zone->has_dest_target & (1 << FW3_TARGET_SNAT))
                {
-                       fw3_pr("-A POSTROUTING");
+                       fw3_pr("-A delegate_postrouting");
                        fw3_format_in_out(NULL, dev);
                        fw3_format_src_dest(NULL, sub);
                        fw3_format_extra(zone->extra_dest);
@@ -382,7 +404,7 @@ print_zone_rule(enum fw3_table table, enum fw3_family family,
                {
                        for (t = FW3_TARGET_REJECT; t <= FW3_TARGET_DROP; t++)
                        {
-                               if (zone->has_src_target[t])
+                               if (zone->has_src_target & (1 << t))
                                {
                                        fw3_pr("-A zone_%s_src_%s", zone->name, targets[t]);
                                        fw3_format_limit(&zone->log_limit);
@@ -390,7 +412,7 @@ print_zone_rule(enum fw3_table table, enum fw3_family family,
                                                   targets[t], zone->name);
                                }
 
-                               if (zone->has_dest_target[t])
+                               if (zone->has_dest_target & (1 << t))
                                {
                                        fw3_pr("-A zone_%s_dest_%s", zone->name, targets[t]);
                                        fw3_format_limit(&zone->log_limit);
@@ -442,6 +464,24 @@ fw3_print_zone_rules(enum fw3_table table, enum fw3_family family,
                print_zone_rule(table, family, zone, state->defaults.drop_invalid);
 }
 
+void
+fw3_flush_zones(enum fw3_table table, enum fw3_family family,
+                           bool pass2, struct list_head *statefile)
+{
+       struct fw3_statefile_entry *e;
+
+       list_for_each_entry(e, statefile, list)
+       {
+               if (e->type != FW3_TYPE_ZONE)
+                       continue;
+
+               print_chains(table, family, pass2 ? "-X %s\n" : "-F %s\n",
+                            e->name, e->flags[0], src_chains, ARRAY_SIZE(src_chains));
+
+               print_chains(table, family, pass2 ? "-X %s\n" : "-F %s\n",
+                            e->name, e->flags[1], dst_chains, ARRAY_SIZE(dst_chains));
+       }
+}
 
 struct fw3_zone *
 fw3_lookup_zone(struct fw3_state *state, const char *name)
diff --git a/zones.h b/zones.h
index 8537af7..57e42df 100644 (file)
--- a/zones.h
+++ b/zones.h
@@ -29,6 +29,9 @@ void fw3_print_zone_chains(enum fw3_table table, enum fw3_family family,
 void fw3_print_zone_rules(enum fw3_table table, enum fw3_family family,
                           struct fw3_state *state);
 
+void fw3_flush_zones(enum fw3_table table, enum fw3_family family,
+                     bool pass2, struct list_head *statefile);
+
 struct fw3_zone * fw3_lookup_zone(struct fw3_state *state, const char *name);
 
 void fw3_free_zone(struct fw3_zone *zone);