iptables: fix regression with unintended free in need_protomatch
[project/firewall3.git] / ipsets.c
index 93bde0d30d998278a00b9c0d5cce57513c4810f6..e7cde16e930a438c8850a79b51b0e0cac65171bf 100644 (file)
--- a/ipsets.c
+++ b/ipsets.c
@@ -16,6 +16,8 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
+#include <ctype.h>
+
 #include "ipsets.h"
 
 
@@ -264,6 +266,7 @@ fw3_alloc_ipset(struct fw3_state *state)
        ipset->enabled    = true;
        ipset->family     = FW3_FAMILY_V4;
        ipset->reload_set = false;
+       ipset->timeout    = -1; /* no timeout by default */
 
        list_add_tail(&ipset->list, &state->ipsets);
 
@@ -337,6 +340,7 @@ load_file(struct fw3_ipset *ipset)
 {
        FILE *f;
        char line[128];
+       char *p;
 
        if (!ipset->loadfile)
                return;
@@ -350,8 +354,13 @@ load_file(struct fw3_ipset *ipset)
                return;
        }
 
-       while (fgets(line, sizeof(line), f))
-               fw3_pr("add %s %s", ipset->name, line);
+       while (fgets(line, sizeof(line), f)) {
+               p = line;
+               while (isspace(*p))
+                       p++;
+               if (*p && *p != '#')
+                       fw3_pr("add %s %s", ipset->name, line);
+       }
 
        fclose(f);
 }
@@ -387,7 +396,7 @@ create_ipset(struct fw3_ipset *ipset, struct fw3_state *state)
                       ipset->portrange.port_min, ipset->portrange.port_max);
        }
 
-       if (ipset->timeout > 0)
+       if (ipset->timeout >= 0)
                fw3_pr(" timeout %u", ipset->timeout);
 
        if (ipset->maxelem > 0)
@@ -427,13 +436,16 @@ fw3_create_ipsets(struct fw3_state *state, enum fw3_family family,
        /* spawn ipsets */
        list_for_each_entry(ipset, &state->ipsets, list)
        {
-               if (ipset->family != family ||
-                   (reload_set && !ipset->reload_set))
+               if (ipset->family != family)
                        continue;
 
                if (ipset->external)
                        continue;
 
+               if (fw3_check_ipset(ipset) &&
+                   (reload_set && !ipset->reload_set))
+                       continue;
+
                if (!exec)
                {
                        exec = fw3_command_pipe(false, "ipset", "-exist", "-");
@@ -568,3 +580,43 @@ out:
 
        return rv;
 }
+
+void
+fw3_ipsets_update_run_state(enum fw3_family family, struct fw3_state *run_state,
+                           struct fw3_state *cfg_state)
+{
+       struct fw3_ipset *ipset_run, *ipset_cfg;
+       bool in_cfg;
+
+       list_for_each_entry(ipset_run, &run_state->ipsets, list) {
+               if (ipset_run->family != family)
+                       continue;
+
+               in_cfg = false;
+
+               list_for_each_entry(ipset_cfg, &cfg_state->ipsets, list) {
+                       if (ipset_cfg->family != family)
+                               continue;
+
+                       if (strlen(ipset_run->name) ==
+                           strlen(ipset_cfg->name) &&
+                           !strcmp(ipset_run->name, ipset_cfg->name)) {
+                               in_cfg = true;
+                               break;
+                       }
+               }
+
+               /* If a set is found in run_state, but not in cfg_state then the
+                * set has been deleted/renamed. Set reload_set to true to force
+                * the old set to be destroyed in the "stop" fase of the reload.
+                * If the set is found, then copy the reload_set value from the
+                * configuration state. This ensures that the elements are
+                * always updated according to the configuration, and not the
+                * runtime state (which the user might have forgotten).
+                */
+               if (!in_cfg)
+                       ipset_run->reload_set = true;
+               else
+                       ipset_run->reload_set = ipset_cfg->reload_set;
+       }
+}