rework runtime state tracking
authorJo-Philipp Wich <jow@openwrt.org>
Wed, 20 Feb 2013 20:05:45 +0000 (21:05 +0100)
committerJo-Philipp Wich <jow@openwrt.org>
Thu, 21 Feb 2013 15:49:04 +0000 (16:49 +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 2d64695..0992f58 100644 (file)
@@ -295,30 +295,29 @@ reset_policy(enum fw3_table table)
 
 void
 fw3_flush_rules(enum fw3_table table, enum fw3_family family,
-                bool pass2, struct list_head *statefile)
+                bool pass2, struct fw3_state *state)
 {
-       struct fw3_statefile_entry *e;
+       struct fw3_defaults *d = &state->running_defaults;
 
-       list_for_each_entry(e, statefile, list)
+       if (!hasbit(d->flags, family))
+               return;
+
+       if (!pass2)
        {
-               if (e->type != FW3_TYPE_DEFAULTS)
-                       continue;
+               reset_policy(table);
 
-               if (!pass2)
-               {
-                       reset_policy(table);
+               print_chains(table, family, "-D %s\n", state->running_defaults.flags,
+                                        toplevel_rules, ARRAY_SIZE(toplevel_rules));
 
-                       print_chains(table, family, "-D %s\n", e->flags[0],
-                                    toplevel_rules, ARRAY_SIZE(toplevel_rules));
+               print_chains(table, family, "-F %s\n", state->running_defaults.flags,
+                                        default_chains, ARRAY_SIZE(default_chains));
+       }
+       else
+       {
+               print_chains(table, family, "-X %s\n", state->running_defaults.flags,
+                                        default_chains, ARRAY_SIZE(default_chains));
 
-                       print_chains(table, family, "-F %s\n", e->flags[0],
-                                    default_chains, ARRAY_SIZE(default_chains));
-               }
-               else
-               {
-                       print_chains(table, family, "-X %s\n", e->flags[0],
-                                    default_chains, ARRAY_SIZE(default_chains));
-               }
+               delbit(d->flags, family);
        }
 }
 
index 17f9ba9..72f3eef 100644 (file)
@@ -33,7 +33,7 @@ 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);
+                     bool pass2, struct fw3_state *state);
 
 void fw3_flush_all(enum fw3_table table);
 
index 1715abc..9abe4bf 100644 (file)
@@ -60,14 +60,14 @@ fw3_load_forwards(struct fw3_state *state, struct uci_package *p)
                        continue;
                }
                else if (forward->src.set && !forward->src.any &&
-                        !(forward->_src = fw3_lookup_zone(state, forward->src.name)))
+                        !(forward->_src = fw3_lookup_zone(state, forward->src.name, false)))
                {
                        warn_elem(e, "refers to not existing zone '%s'", forward->src.name);
                        fw3_free_forward(forward);
                        continue;
                }
                else if (forward->dest.set && !forward->dest.any &&
-                        !(forward->_dest = fw3_lookup_zone(state, forward->dest.name)))
+                        !(forward->_dest = fw3_lookup_zone(state, forward->dest.name, false)))
                {
                        warn_elem(e, "refers to not existing zone '%s'", forward->dest.name);
                        fw3_free_forward(forward);
index 5e0d61f..62ed131 100644 (file)
--- a/ipsets.c
+++ b/ipsets.c
@@ -184,6 +184,24 @@ check_types(struct uci_element *e, struct fw3_ipset *ipset)
        return false;
 }
 
+struct fw3_ipset *
+fw3_alloc_ipset(void)
+{
+       struct fw3_ipset *ipset;
+
+       ipset = malloc(sizeof(*ipset));
+
+       if (!ipset)
+               return NULL;
+
+       memset(ipset, 0, sizeof(*ipset));
+
+       INIT_LIST_HEAD(&ipset->datatypes);
+       INIT_LIST_HEAD(&ipset->iprange);
+
+       return ipset;
+}
+
 void
 fw3_load_ipsets(struct fw3_state *state, struct uci_package *p)
 {
@@ -203,16 +221,11 @@ fw3_load_ipsets(struct fw3_state *state, struct uci_package *p)
                if (strcmp(s->type, "ipset"))
                        continue;
 
-               ipset = malloc(sizeof(*ipset));
+               ipset = fw3_alloc_ipset();
 
                if (!ipset)
                        continue;
 
-               memset(ipset, 0, sizeof(*ipset));
-
-               INIT_LIST_HEAD(&ipset->datatypes);
-               INIT_LIST_HEAD(&ipset->iprange);
-
                fw3_parse_options(ipset, ipset_opts, ARRAY_SIZE(ipset_opts), s);
 
                if (!ipset->name || !*ipset->name)
@@ -239,7 +252,7 @@ fw3_load_ipsets(struct fw3_state *state, struct uci_package *p)
 
 
 static void
-create_ipset(struct fw3_ipset *ipset)
+create_ipset(struct fw3_ipset *ipset, struct fw3_state *state)
 {
        bool first = true;
        char s[INET6_ADDRSTRLEN];
@@ -326,31 +339,12 @@ create_ipset(struct fw3_ipset *ipset)
                fw3_pr(" hashsize %u", ipset->hashsize);
 
        fw3_pr("\n");
-}
-
-static bool
-ipset_loaded(struct list_head *statefile, const char *name)
-{
-       struct fw3_statefile_entry *e;
-       int mask = (1 << FW3_FAMILY_V4) | (1 << FW3_FAMILY_V6);
-
-       if (!statefile)
-               return false;
 
-       list_for_each_entry(e, statefile, list)
-       {
-               if (e->type != FW3_TYPE_IPSET)
-                       continue;
-
-               if (!strcmp(e->name, name) && (e->flags[0] & mask))
-                       return true;
-       }
-
-       return false;
+       fw3_set_running(ipset, &state->running_ipsets);
 }
 
 void
-fw3_create_ipsets(struct fw3_state *state, struct list_head *statefile)
+fw3_create_ipsets(struct fw3_state *state)
 {
        struct fw3_ipset *ipset;
 
@@ -358,42 +352,34 @@ fw3_create_ipsets(struct fw3_state *state, struct list_head *statefile)
                return;
 
        list_for_each_entry(ipset, &state->ipsets, list)
-               if (!ipset_loaded(statefile, ipset->name))
-                       create_ipset(ipset);
+               if (!fw3_lookup_ipset(state, ipset->name, true))
+                       create_ipset(ipset, state);
 
        fw3_pr("quit\n");
 }
 
 void
-fw3_destroy_ipsets(struct fw3_state *state, struct list_head *statefile)
+fw3_destroy_ipsets(struct fw3_state *state)
 {
-       struct fw3_ipset *s;
-       struct fw3_statefile_entry *e;
+       struct fw3_ipset *s, *tmp;
        int mask = (1 << FW3_FAMILY_V4) | (1 << FW3_FAMILY_V6);
 
-       if (!statefile)
-               return;
-
-       list_for_each_entry(e, statefile, list)
+       list_for_each_entry_safe(s, tmp, &state->running_ipsets, running_list)
        {
-               if (e->type != FW3_TYPE_IPSET)
-                       continue;
-
                if (!hasbit(state->defaults.flags, FW3_FAMILY_V4))
-                       delbit(e->flags[0], FW3_FAMILY_V4);
+                       delbit(s->flags, FW3_FAMILY_V4);
 
                if (!hasbit(state->defaults.flags, FW3_FAMILY_V6))
-                       delbit(e->flags[0], FW3_FAMILY_V6);
+                       delbit(s->flags, FW3_FAMILY_V6);
 
-               if ((s = fw3_lookup_ipset(state, e->name)) != NULL)
-                       s->flags = e->flags[0];
-
-               if (!(e->flags[0] & mask))
+               if (!(s->flags & mask))
                {
-                       info("Deleting ipset %s", e->name);
+                       info("Deleting ipset %s", s->name);
+
+                       fw3_pr("flush %s\n", s->name);
+                       fw3_pr("destroy %s\n", s->name);
 
-                       fw3_pr("flush %s\n", e->name);
-                       fw3_pr("destroy %s\n", e->name);
+                       fw3_set_running(s, NULL);
                }
        }
 }
@@ -408,16 +394,23 @@ fw3_free_ipset(struct fw3_ipset *ipset)
 }
 
 struct fw3_ipset *
-fw3_lookup_ipset(struct fw3_state *state, const char *name)
+fw3_lookup_ipset(struct fw3_state *state, const char *name, bool running)
 {
-       struct fw3_ipset *ipset;
+       struct fw3_ipset *s;
 
        if (list_empty(&state->ipsets))
                return NULL;
 
-       list_for_each_entry(ipset, &state->ipsets, list)
-               if (!strcmp(ipset->name, name))
-                       return ipset;
+       list_for_each_entry(s, &state->ipsets, list)
+       {
+               if (strcmp(s->name, name))
+                       continue;
+
+               if (!running || s->running_list.next)
+                       return s;
+
+               break;
+       }
 
        return NULL;
 }
index a169979..410c712 100644 (file)
--- a/ipsets.h
+++ b/ipsets.h
@@ -38,12 +38,14 @@ struct fw3_ipset_settype {
        uint8_t optional;
 };
 
+struct fw3_ipset * fw3_alloc_ipset(void);
 void fw3_load_ipsets(struct fw3_state *state, struct uci_package *p);
-void fw3_create_ipsets(struct fw3_state *state, struct list_head *statefile);
-void fw3_destroy_ipsets(struct fw3_state *state, struct list_head *statefile);
+void fw3_create_ipsets(struct fw3_state *state);
+void fw3_destroy_ipsets(struct fw3_state *state);
 
 void fw3_free_ipset(struct fw3_ipset *ipset);
 
-struct fw3_ipset * fw3_lookup_ipset(struct fw3_state *state, const char *name);
+struct fw3_ipset * fw3_lookup_ipset(struct fw3_state *state, const char *name,
+                                    bool running);
 
 #endif
diff --git a/main.c b/main.c
index 23c1497..62f51e1 100644 (file)
--- a/main.c
+++ b/main.c
@@ -62,6 +62,9 @@ build_state(void)
                state->disable_ipsets = true;
        }
 
+       INIT_LIST_HEAD(&state->running_zones);
+       INIT_LIST_HEAD(&state->running_ipsets);
+
        fw3_load_defaults(state, p);
        fw3_load_ipsets(state, p);
        fw3_load_zones(state, p);
@@ -69,6 +72,8 @@ build_state(void)
        fw3_load_redirects(state, p);
        fw3_load_forwards(state, p);
 
+       state->statefile = fw3_read_statefile(state);
+
        return state;
 }
 
@@ -89,6 +94,9 @@ free_state(struct fw3_state *state)
        list_for_each_safe(cur, tmp, &state->forwards)
                fw3_free_forward((struct fw3_forward *)cur);
 
+       list_for_each_safe(cur, tmp, &state->ipsets)
+               fw3_free_ipset((struct fw3_ipset *)cur);
+
        uci_free_context(state->uci);
 
        free(state);
@@ -117,22 +125,9 @@ restore_pipe(enum fw3_family family, bool silent)
 }
 
 static bool
-family_running(struct list_head *statefile, enum fw3_family family)
+family_running(struct fw3_state *state, enum fw3_family family)
 {
-       struct fw3_statefile_entry *e;
-
-       if (statefile)
-       {
-               list_for_each_entry(e, statefile, list)
-               {
-                       if (e->type != FW3_TYPE_DEFAULTS)
-                               continue;
-
-                       return hasbit(e->flags[0], family);
-               }
-       }
-
-       return false;
+       return hasbit(state->running_defaults.flags, family);
 }
 
 static bool
@@ -163,9 +158,7 @@ stop(struct fw3_state *state, bool complete, bool restart)
        enum fw3_family family;
        enum fw3_table table;
 
-       struct list_head *statefile = fw3_read_statefile();
-
-       if (!complete && !statefile)
+       if (!complete && !state->statefile)
        {
                if (!restart)
                        warn("The firewall appears to be stopped. "
@@ -176,7 +169,7 @@ stop(struct fw3_state *state, bool complete, bool restart)
 
        for (family = FW3_FAMILY_V4; family <= FW3_FAMILY_V6; family++)
        {
-               if (!complete && !family_running(statefile, family))
+               if (!complete && !family_running(state, family))
                        continue;
 
                if (!family_used(family) || !restore_pipe(family, true))
@@ -201,12 +194,12 @@ stop(struct fw3_state *state, bool complete, bool restart)
                        else
                        {
                                /* pass 1 */
-                               fw3_flush_rules(table, family, false, statefile);
-                               fw3_flush_zones(table, family, false, statefile);
+                               fw3_flush_rules(table, family, false, state);
+                               fw3_flush_zones(table, family, false, state);
 
                                /* pass 2 */
-                               fw3_flush_rules(table, family, true, statefile);
-                               fw3_flush_zones(table, family, true, statefile);
+                               fw3_flush_rules(table, family, true, state);
+                               fw3_flush_zones(table, family, true, state);
                        }
 
                        fw3_pr("COMMIT\n");
@@ -222,12 +215,10 @@ stop(struct fw3_state *state, bool complete, bool restart)
 
        if (!restart && fw3_command_pipe(false, "ipset", "-exist", "-"))
        {
-               fw3_destroy_ipsets(state, statefile);
+               fw3_destroy_ipsets(state);
                fw3_command_close();
        }
 
-       fw3_free_statefile(statefile);
-
        if (!rv)
                fw3_write_statefile(state);
 
@@ -241,12 +232,10 @@ start(struct fw3_state *state, bool restart)
        enum fw3_family family;
        enum fw3_table table;
 
-       struct list_head *statefile = fw3_read_statefile();
-
        if (!print_rules && !restart &&
            fw3_command_pipe(false, "ipset", "-exist", "-"))
        {
-               fw3_create_ipsets(state, statefile);
+               fw3_create_ipsets(state);
                fw3_command_close();
        }
 
@@ -255,10 +244,7 @@ start(struct fw3_state *state, bool restart)
                if (!family_used(family))
                        continue;
 
-               if (!family_loaded(state, family) || !restore_pipe(family, false))
-                       continue;
-
-               if (!print_rules && !restart && family_running(statefile, family))
+               if (!print_rules && !restart && family_running(state, family))
                {
                        warn("The %s firewall appears to be started already. "
                             "If it is indeed empty, remove the %s file and retry.",
@@ -267,6 +253,9 @@ start(struct fw3_state *state, bool restart)
                        continue;
                }
 
+               if (!family_loaded(state, family) || !restore_pipe(family, false))
+                       continue;
+
                info("Constructing %s rules ...", fw3_flag_names[family]);
 
                for (table = FW3_TABLE_FILTER; table <= FW3_TABLE_RAW; table++)
@@ -294,8 +283,6 @@ start(struct fw3_state *state, bool restart)
                rv = 0;
        }
 
-       fw3_free_statefile(statefile);
-
        if (!rv && !print_rules)
                fw3_write_statefile(state);
 
index e02f890..c45a9d4 100644 (file)
--- a/options.h
+++ b/options.h
@@ -219,6 +219,7 @@ struct fw3_defaults
 struct fw3_zone
 {
        struct list_head list;
+       struct list_head running_list;
 
        const char *name;
 
@@ -340,6 +341,7 @@ struct fw3_forward
 struct fw3_ipset
 {
        struct list_head list;
+       struct list_head running_list;
 
        const char *name;
        enum fw3_family family;
@@ -371,7 +373,12 @@ struct fw3_state
        struct list_head forwards;
        struct list_head ipsets;
 
+       struct fw3_defaults running_defaults;
+       struct list_head running_zones;
+       struct list_head running_ipsets;
+
        bool disable_ipsets;
+       bool statefile;
 };
 
 
index fc6b6b6..627438b 100644 (file)
@@ -132,14 +132,14 @@ fw3_load_redirects(struct fw3_state *state, struct uci_package *p)
                        continue;
                }
                else if (redir->src.set && !redir->src.any &&
-                        !(redir->_src = fw3_lookup_zone(state, redir->src.name)))
+                        !(redir->_src = fw3_lookup_zone(state, redir->src.name, false)))
                {
                        warn_elem(e, "refers to not existing zone '%s'", redir->src.name);
                        fw3_free_redirect(redir);
                        continue;
                }
                else if (redir->dest.set && !redir->dest.any &&
-                        !(redir->_dest = fw3_lookup_zone(state, redir->dest.name)))
+                        !(redir->_dest = fw3_lookup_zone(state, redir->dest.name, false)))
                {
                        warn_elem(e, "refers to not existing zone '%s'", redir->dest.name);
                        fw3_free_redirect(redir);
@@ -152,7 +152,7 @@ fw3_load_redirects(struct fw3_state *state, struct uci_package *p)
                        continue;
                }
                else if (redir->ipset.set && !redir->ipset.any &&
-                        !(redir->_ipset = fw3_lookup_ipset(state, redir->ipset.name)))
+                        !(redir->_ipset = fw3_lookup_ipset(state, redir->ipset.name, false)))
                {
                        warn_elem(e, "refers to unknown ipset '%s'", redir->ipset.name);
                        fw3_free_redirect(redir);
diff --git a/rules.c b/rules.c
index bc983a6..1979340 100644 (file)
--- a/rules.c
+++ b/rules.c
@@ -90,14 +90,14 @@ fw3_load_rules(struct fw3_state *state, struct uci_package *p)
                        continue;
                }
                else if (rule->src.set && !rule->src.any &&
-                        !(rule->_src = fw3_lookup_zone(state, rule->src.name)))
+                        !(rule->_src = fw3_lookup_zone(state, rule->src.name, false)))
                {
                        warn_elem(e, "refers to not existing zone '%s'", rule->src.name);
                        fw3_free_rule(rule);
                        continue;
                }
                else if (rule->dest.set && !rule->dest.any &&
-                        !(rule->_dest = fw3_lookup_zone(state, rule->dest.name)))
+                        !(rule->_dest = fw3_lookup_zone(state, rule->dest.name, false)))
                {
                        warn_elem(e, "refers to not existing zone '%s'", rule->dest.name);
                        fw3_free_rule(rule);
@@ -110,7 +110,7 @@ fw3_load_rules(struct fw3_state *state, struct uci_package *p)
                        continue;
                }
                else if (rule->ipset.set && !rule->ipset.any &&
-                        !(rule->_ipset = fw3_lookup_ipset(state, rule->ipset.name)))
+                        !(rule->_ipset = fw3_lookup_ipset(state, rule->ipset.name, false)))
                {
                        warn_elem(e, "refers to unknown ipset '%s'", rule->ipset.name);
                        fw3_free_rule(rule);
diff --git a/utils.c b/utils.c
index 1ba25fd..c9ca206 100644 (file)
--- a/utils.c
+++ b/utils.c
 #include "utils.h"
 #include "options.h"
 
+#include "zones.h"
+#include "ipsets.h"
+
+
 static int lock_fd = -1;
 static pid_t pipe_pid = -1;
 static FILE *pipe_fd = NULL;
@@ -332,66 +336,90 @@ fw3_unlock(void)
 }
 
 
-struct list_head *
-fw3_read_statefile(void)
+bool
+fw3_read_statefile(void *state)
 {
        FILE *sf;
 
-       int n;
+       int n, type;
        char line[128];
-       const char *p;
+       const char *p, *name;
 
-       struct list_head *state;
-       struct fw3_statefile_entry *entry;
+       uint16_t flags[2];
+
+       struct fw3_state *s = state;
+       struct fw3_zone *zone;
+       struct fw3_ipset *ipset;
 
        sf = fopen(FW3_STATEFILE, "r");
 
        if (!sf)
-               return NULL;
-
-       state = malloc(sizeof(*state));
-
-       if (!state)
-               return NULL;
-
-       INIT_LIST_HEAD(state);
+               return false;
 
        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");
+               type = strtoul(p, NULL, 10);
+               name = strtok(NULL, " \t\n");
 
-               if (!p)
+               if (!name)
                        continue;
 
-               entry->name = strdup(p);
-
                for (n = 0, p = strtok(NULL, " \t\n");
-                    n < ARRAY_SIZE(entry->flags) && p != NULL;
+                    n < ARRAY_SIZE(flags) && p != NULL;
                     n++, p = strtok(NULL, " \t\n"))
                {
-                       entry->flags[n] = strtoul(p, NULL, 10);
+                       flags[n] = strtoul(p, NULL, 10);
                }
 
-               list_add_tail(&entry->list, state);
+               switch (type)
+               {
+               case FW3_TYPE_DEFAULTS:
+                       s->running_defaults.flags = flags[0];
+                       break;
+
+               case FW3_TYPE_ZONE:
+                       if (!(zone = fw3_lookup_zone(state, name, false)))
+                       {
+                               zone = fw3_alloc_zone();
+
+                               if (!zone)
+                                       continue;
+
+                               zone->name = strdup(name);
+                               list_add_tail(&zone->list, &s->zones);
+                       }
+
+                       zone->src_flags = flags[0];
+                       zone->dst_flags = flags[1];
+                       list_add_tail(&zone->running_list, &s->running_zones);
+                       break;
+
+               case FW3_TYPE_IPSET:
+                       if (!(ipset = fw3_lookup_ipset(state, name, false)))
+                       {
+                               ipset = fw3_alloc_ipset();
+
+                               if (!ipset)
+                                       continue;
+
+                               ipset->name = strdup(name);
+                               list_add_tail(&ipset->list, &s->ipsets);
+                       }
+
+                       ipset->flags = flags[0];
+                       list_add_tail(&ipset->running_list, &s->running_ipsets);
+                       break;
+               }
        }
 
        fclose(sf);
 
-       return state;
+       return true;
 }
 
 void
@@ -424,40 +452,34 @@ fw3_write_statefile(void *state)
 
        fprintf(sf, "%u - %u\n", FW3_TYPE_DEFAULTS, d->flags);
 
-       list_for_each_entry(z, &s->zones, list)
+       list_for_each_entry(z, &s->running_zones, running_list)
        {
                fprintf(sf, "%u %s %u %u\n", FW3_TYPE_ZONE,
                        z->name, z->src_flags, z->dst_flags);
        }
 
-       list_for_each_entry(i, &s->ipsets, list)
+       list_for_each_entry(i, &s->running_ipsets, running_list)
        {
-               if (i->external && *i->external)
-                       continue;
-
-               if (!i->flags)
-                       continue;
-
                fprintf(sf, "%u %s %u\n", FW3_TYPE_IPSET, i->name, i->flags);
        }
 
        fclose(sf);
 }
 
-void
-fw3_free_statefile(struct list_head *statefile)
-{
-       struct fw3_statefile_entry *e, *tmp;
 
-       if (!statefile)
-               return;
+struct object_list_heads
+{
+       struct list_head list;
+       struct list_head running_list;
+};
 
-       list_for_each_entry_safe(e, tmp, statefile, list)
-       {
-               list_del(&e->list);
-               free(e->name);
-               free(e);
-       }
+void
+fw3_set_running(void *object, struct list_head *dest)
+{
+       struct object_list_heads *o = object;
 
-       free(statefile);
+       if (dest && !o->running_list.next)
+               list_add_tail(&o->running_list, dest);
+       else if (!dest && o->running_list.next)
+               list_del(&o->running_list);
 }
diff --git a/utils.h b/utils.h
index 5cadd58..f157daf 100644 (file)
--- a/utils.h
+++ b/utils.h
@@ -87,16 +87,9 @@ enum fw3_statefile_type
        FW3_TYPE_IPSET    = 2,
 };
 
-struct fw3_statefile_entry
-{
-       struct list_head list;
-       enum fw3_statefile_type type;
-       char *name;
-       uint32_t flags[2];
-};
-
-struct list_head * fw3_read_statefile(void);
+bool fw3_read_statefile(void *state);
 void fw3_write_statefile(void *state);
-void fw3_free_statefile(struct list_head *statefile);
+
+void fw3_set_running(void *object, struct list_head *dest);
 
 #endif
diff --git a/zones.c b/zones.c
index 9595c37..317acc8 100644 (file)
--- a/zones.c
+++ b/zones.c
@@ -144,6 +144,29 @@ resolve_networks(struct uci_element *e, struct fw3_zone *zone)
        }
 }
 
+struct fw3_zone *
+fw3_alloc_zone(void)
+{
+       struct fw3_zone *zone;
+
+       zone = malloc(sizeof(*zone));
+
+       if (!zone)
+               return NULL;
+
+       memset(zone, 0, sizeof(*zone));
+
+       INIT_LIST_HEAD(&zone->networks);
+       INIT_LIST_HEAD(&zone->devices);
+       INIT_LIST_HEAD(&zone->subnets);
+       INIT_LIST_HEAD(&zone->masq_src);
+       INIT_LIST_HEAD(&zone->masq_dest);
+
+       zone->log_limit.rate = 10;
+
+       return zone;
+}
+
 void
 fw3_load_zones(struct fw3_state *state, struct uci_package *p)
 {
@@ -161,21 +184,11 @@ fw3_load_zones(struct fw3_state *state, struct uci_package *p)
                if (strcmp(s->type, "zone"))
                        continue;
 
-               zone = malloc(sizeof(*zone));
+               zone = fw3_alloc_zone();
 
                if (!zone)
                        continue;
 
-               memset(zone, 0, sizeof(*zone));
-
-               INIT_LIST_HEAD(&zone->networks);
-               INIT_LIST_HEAD(&zone->devices);
-               INIT_LIST_HEAD(&zone->subnets);
-               INIT_LIST_HEAD(&zone->masq_src);
-               INIT_LIST_HEAD(&zone->masq_dest);
-
-               zone->log_limit.rate = 10;
-
                fw3_parse_options(zone, zone_opts, ARRAY_SIZE(zone_opts), s);
 
                if (!zone->extra_dest)
@@ -217,7 +230,7 @@ fw3_load_zones(struct fw3_state *state, struct uci_package *p)
 
 static void
 print_zone_chain(enum fw3_table table, enum fw3_family family,
-                 struct fw3_zone *zone, bool disable_notrack)
+                 struct fw3_zone *zone, struct fw3_state *state)
 {
        bool s, d;
 
@@ -226,7 +239,7 @@ print_zone_chain(enum fw3_table table, enum fw3_family family,
 
        setbit(zone->dst_flags, family);
 
-       if (!zone->conntrack && !disable_notrack)
+       if (!zone->conntrack && !state->defaults.drop_invalid)
                setbit(zone->dst_flags, FW3_TARGET_NOTRACK);
 
        s = print_chains(table, family, ":%s - [0:0]\n", zone->name,
@@ -236,7 +249,10 @@ print_zone_chain(enum fw3_table table, enum fw3_family family,
                         zone->dst_flags, dst_chains, ARRAY_SIZE(dst_chains));
 
        if (s || d)
+       {
                info("   * Zone '%s'", zone->name);
+               fw3_set_running(zone, &state->running_zones);
+       }
 }
 
 static void
@@ -442,7 +458,7 @@ fw3_print_zone_chains(enum fw3_table table, enum fw3_family family,
        struct fw3_zone *zone;
 
        list_for_each_entry(zone, &state->zones, list)
-               print_zone_chain(table, family, zone, state->defaults.drop_invalid);
+               print_zone_chain(table, family, zone, state);
 }
 
 void
@@ -457,28 +473,34 @@ fw3_print_zone_rules(enum fw3_table table, enum fw3_family family,
 
 void
 fw3_flush_zones(enum fw3_table table, enum fw3_family family,
-                           bool pass2, struct list_head *statefile)
+                           bool pass2, struct fw3_state *state)
 {
-       struct fw3_statefile_entry *e;
+       struct fw3_zone *z, *tmp;
+       int mask = (1 << FW3_FAMILY_V4) | (1 << FW3_FAMILY_V6);
 
-       list_for_each_entry(e, statefile, list)
+       list_for_each_entry_safe(z, tmp, &state->running_zones, running_list)
        {
-               if (e->type != FW3_TYPE_ZONE)
-                       continue;
-
-               if (!hasbit(e->flags[1], family))
+               if (!hasbit(z->dst_flags, family))
                        continue;
 
                print_chains(table, family, pass2 ? "-X %s\n" : "-F %s\n",
-                            e->name, e->flags[0], src_chains, ARRAY_SIZE(src_chains));
+                            z->name, z->src_flags, 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));
+                            z->name, z->dst_flags, dst_chains, ARRAY_SIZE(dst_chains));
+
+               if (pass2)
+               {
+                       delbit(z->dst_flags, family);
+
+                       if (!(z->dst_flags & mask))
+                               fw3_set_running(z, NULL);
+               }
        }
 }
 
 struct fw3_zone *
-fw3_lookup_zone(struct fw3_state *state, const char *name)
+fw3_lookup_zone(struct fw3_state *state, const char *name, bool running)
 {
        struct fw3_zone *z;
 
@@ -486,9 +508,16 @@ fw3_lookup_zone(struct fw3_state *state, const char *name)
                return NULL;
 
        list_for_each_entry(z, &state->zones, list)
-               if (!strcmp(z->name, name))
+       {
+               if (strcmp(z->name, name))
+                       continue;
+
+               if (!running || z->running_list.next)
                        return z;
 
+               break;
+       }
+
        return NULL;
 }
 
diff --git a/zones.h b/zones.h
index 57e42df..c462ea8 100644 (file)
--- a/zones.h
+++ b/zones.h
@@ -21,6 +21,8 @@
 
 #include "options.h"
 
+struct fw3_zone * fw3_alloc_zone(void);
+
 void fw3_load_zones(struct fw3_state *state, struct uci_package *p);
 
 void fw3_print_zone_chains(enum fw3_table table, enum fw3_family family,
@@ -30,9 +32,10 @@ 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);
+                     bool pass2, struct fw3_state *state);
 
-struct fw3_zone * fw3_lookup_zone(struct fw3_state *state, const char *name);
+struct fw3_zone * fw3_lookup_zone(struct fw3_state *state, const char *name,
+                                  bool running);
 
 void fw3_free_zone(struct fw3_zone *zone);