firewall3: check the return value of fw3_parse_options()
[project/firewall3.git] / ipsets.c
index 955d434..7a72fd3 100644 (file)
--- a/ipsets.c
+++ b/ipsets.c
@@ -1,7 +1,7 @@
 /*
  * firewall3 - 3rd OpenWrt UCI firewall implementation
  *
- *   Copyright (C) 2013 Jo-Philipp Wich <jow@openwrt.org>
+ *   Copyright (C) 2013 Jo-Philipp Wich <jo@mein.io>
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -107,6 +107,11 @@ check_types(struct uci_element *e, struct fw3_ipset *ipset)
        {
                for (i = 0; i < ARRAY_SIZE(ipset_types); i++)
                {
+                       /* skip type for v6 if it does not support family */
+                       if (ipset->family != FW3_FAMILY_V4 &&
+                           !(ipset_types[i].optional & OPT_FAMILY))
+                               continue;
+
                        if (ipset_types[i].types == typelist)
                        {
                                ipset->method = ipset_types[i].method;
@@ -198,13 +203,10 @@ fw3_alloc_ipset(void)
 {
        struct fw3_ipset *ipset;
 
-       ipset = malloc(sizeof(*ipset));
-
+       ipset = calloc(1, sizeof(*ipset));
        if (!ipset)
                return NULL;
 
-       memset(ipset, 0, sizeof(*ipset));
-
        INIT_LIST_HEAD(&ipset->datatypes);
 
        ipset->enabled = true;
@@ -237,7 +239,8 @@ fw3_load_ipsets(struct fw3_state *state, struct uci_package *p)
                if (!ipset)
                        continue;
 
-               fw3_parse_options(ipset, fw3_ipset_opts, s);
+               if (!fw3_parse_options(ipset, fw3_ipset_opts, s))
+                       warn_elem(e, "has invalid options");
 
                if (ipset->external)
                {
@@ -259,6 +262,10 @@ fw3_load_ipsets(struct fw3_state *state, struct uci_package *p)
                {
                        warn_elem(e, "must not have family 'any'");
                }
+               else if (ipset->iprange.set && ipset->family != ipset->iprange.family)
+               {
+                       warn_elem(e, "has iprange of wrong address family");
+               }
                else if (list_empty(&ipset->datatypes))
                {
                        warn_elem(e, "has no datatypes assigned");
@@ -281,9 +288,6 @@ create_ipset(struct fw3_ipset *ipset, struct fw3_state *state)
 
        struct fw3_ipset_datatype *type;
 
-       if (ipset->external)
-               return;
-
        info(" * Creating ipset %s", ipset->name);
 
        first = true;
@@ -295,9 +299,12 @@ create_ipset(struct fw3_ipset *ipset, struct fw3_state *state)
                first = false;
        }
 
+       if (ipset->method == FW3_IPSET_METHOD_HASH)
+               fw3_pr(" family inet%s", (ipset->family == FW3_FAMILY_V4) ? "" : "6");
+
        if (ipset->iprange.set)
        {
-               fw3_pr(" range %s", fw3_address_to_string(&ipset->iprange, false));
+               fw3_pr(" range %s", fw3_address_to_string(&ipset->iprange, false, true));
        }
        else if (ipset->portrange.set)
        {
@@ -305,8 +312,6 @@ create_ipset(struct fw3_ipset *ipset, struct fw3_state *state)
                       ipset->portrange.port_min, ipset->portrange.port_max);
        }
 
-       fw3_pr(" family inet%s", (ipset->family == FW3_FAMILY_V4) ? "" : "6");
-
        if (ipset->timeout > 0)
                fw3_pr(" timeout %u", ipset->timeout);
 
@@ -325,31 +330,86 @@ create_ipset(struct fw3_ipset *ipset, struct fw3_state *state)
 void
 fw3_create_ipsets(struct fw3_state *state)
 {
+       int tries;
+       bool exec = false;
        struct fw3_ipset *ipset;
 
        if (state->disable_ipsets)
                return;
 
+       /* spawn ipsets */
        list_for_each_entry(ipset, &state->ipsets, list)
+       {
+               if (ipset->external)
+                       continue;
+
+               if (!exec)
+               {
+                       exec = fw3_command_pipe(false, "ipset", "-exist", "-");
+
+                       if (!exec)
+                               return;
+               }
+
                create_ipset(ipset, state);
+       }
+
+       if (exec)
+       {
+               fw3_pr("quit\n");
+               fw3_command_close();
+       }
+
+       /* wait for ipsets to appear */
+       list_for_each_entry(ipset, &state->ipsets, list)
+       {
+               if (ipset->external)
+                       continue;
 
-       fw3_pr("quit\n");
+               for (tries = 0; !fw3_check_ipset(ipset) && tries < 10; tries++)
+                       usleep(50000);
+       }
 }
 
 void
 fw3_destroy_ipsets(struct fw3_state *state)
 {
-       struct fw3_ipset *s;
+       int tries;
+       bool exec = false;
+       struct fw3_ipset *ipset;
 
-       list_for_each_entry(s, &state->ipsets, list)
+       /* destroy ipsets */
+       list_for_each_entry(ipset, &state->ipsets, list)
        {
-               info(" * Deleting ipset %s", s->name);
+               if (!exec)
+               {
+                       exec = fw3_command_pipe(false, "ipset", "-exist", "-");
+
+                       if (!exec)
+                               return;
+               }
+
+               info(" * Deleting ipset %s", ipset->name);
+
+               fw3_pr("flush %s\n", ipset->name);
+               fw3_pr("destroy %s\n", ipset->name);
+       }
 
-               fw3_pr("flush %s\n", s->name);
-               fw3_pr("destroy %s\n", s->name);
+       if (exec)
+       {
+               fw3_pr("quit\n");
+               fw3_command_close();
        }
 
-       fw3_pr("quit\n");
+       /* wait for ipsets to disappear */
+       list_for_each_entry(ipset, &state->ipsets, list)
+       {
+               if (ipset->external)
+                       continue;
+
+               for (tries = 0; fw3_check_ipset(ipset) && tries < 10; tries++)
+                       usleep(50000);
+       }
 }
 
 struct fw3_ipset *