For ingress rules, only jump into zone_name_src_ACTION chains if the target is not...
[project/firewall3.git] / ipsets.c
index 9f43523..06aafb7 100644 (file)
--- a/ipsets.c
+++ b/ipsets.c
@@ -126,7 +126,7 @@ check_types(struct uci_element *e, struct fw3_ipset *ipset)
                if (ipset_types[i].method == ipset->method &&
                    ipset_types[i].types == typelist)
                {
-                       if (!ipset->external || !*ipset->external)
+                       if (!ipset->external)
                        {
                                if ((ipset_types[i].required & OPT_IPRANGE) &&
                                        !ipset->iprange.set)
@@ -178,10 +178,10 @@ check_types(struct uci_element *e, struct fw3_ipset *ipset)
                                }
 
                                if (!(ipset_types[i].optional & OPT_FAMILY) &&
-                                   ipset->family != FW3_FAMILY_ANY)
+                                   ipset->family != FW3_FAMILY_V4)
                                {
                                        warn_elem(e, "family ignored");
-                                       ipset->family = FW3_FAMILY_ANY;
+                                       ipset->family = FW3_FAMILY_V4;
                                }
                        }
 
@@ -208,6 +208,7 @@ fw3_alloc_ipset(void)
        INIT_LIST_HEAD(&ipset->datatypes);
 
        ipset->enabled = true;
+       ipset->family  = FW3_FAMILY_V4;
 
        return ipset;
 }
@@ -238,6 +239,14 @@ fw3_load_ipsets(struct fw3_state *state, struct uci_package *p)
 
                fw3_parse_options(ipset, fw3_ipset_opts, s);
 
+               if (ipset->external)
+               {
+                       if (!*ipset->external)
+                               ipset->external = NULL;
+                       else if (!ipset->name)
+                               ipset->name = ipset->external;
+               }
+
                if (!ipset->name || !*ipset->name)
                {
                        warn_elem(e, "must have a name assigned");
@@ -246,6 +255,10 @@ fw3_load_ipsets(struct fw3_state *state, struct uci_package *p)
                //{
                //      warn_elem(e, "has duplicated set name '%s'", ipset->name);
                //}
+               else if (ipset->family == FW3_FAMILY_ANY)
+               {
+                       warn_elem(e, "must not have family 'any'");
+               }
                else if (list_empty(&ipset->datatypes))
                {
                        warn_elem(e, "has no datatypes assigned");
@@ -268,9 +281,6 @@ create_ipset(struct fw3_ipset *ipset, struct fw3_state *state)
 
        struct fw3_ipset_datatype *type;
 
-       if (ipset->external && *ipset->external)
-               return;
-
        info(" * Creating ipset %s", ipset->name);
 
        first = true;
@@ -292,8 +302,7 @@ create_ipset(struct fw3_ipset *ipset, struct fw3_state *state)
                       ipset->portrange.port_min, ipset->portrange.port_max);
        }
 
-       if (ipset->family != FW3_FAMILY_ANY)
-               fw3_pr(" family inet%s", (ipset->family == FW3_FAMILY_V4) ? "" : "6");
+       fw3_pr(" family inet%s", (ipset->family == FW3_FAMILY_V4) ? "" : "6");
 
        if (ipset->timeout > 0)
                fw3_pr(" timeout %u", ipset->timeout);
@@ -313,31 +322,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);
+       }
 
-       fw3_pr("quit\n");
+       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;
+
+               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;
+               }
 
-               fw3_pr("flush %s\n", s->name);
-               fw3_pr("destroy %s\n", s->name);
+               info(" * Deleting ipset %s", ipset->name);
+
+               fw3_pr("flush %s\n", ipset->name);
+               fw3_pr("destroy %s\n", ipset->name);
        }
 
-       fw3_pr("quit\n");
+       if (exec)
+       {
+               fw3_pr("quit\n");
+               fw3_command_close();
+       }
+
+       /* 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 *
@@ -382,7 +446,7 @@ fw3_check_ipset(struct fw3_ipset *set)
        req_name.op = IP_SET_OP_GET_BYNAME;
        req_name.version = req_ver.version;
        snprintf(req_name.set.name, IPSET_MAXNAMELEN - 1, "%s",
-                (set->external && *set->external) ? set->external : set->name);
+                set->external ? set->external : set->name);
 
        if (getsockopt(s, SOL_IP, SO_IP_SET, &req_name, &sz))
                goto out;