Make sure that NOTRACK is linked into firewall3 if it is part of libext*.a
[project/firewall3.git] / ipsets.c
index ecccd69..06aafb7 100644 (file)
--- a/ipsets.c
+++ b/ipsets.c
@@ -91,15 +91,6 @@ check_types(struct uci_element *e, struct fw3_ipset *ipset)
        uint32_t typelist = 0;
        struct fw3_ipset_datatype *type;
 
        uint32_t typelist = 0;
        struct fw3_ipset_datatype *type;
 
-       const char *methods[] = {
-               "(bug)",
-               "bitmap",
-               "hash",
-               "list",
-       };
-
-       typelist = 0;
-
        list_for_each_entry(type, &ipset->datatypes, list)
        {
                if (i >= 3)
        list_for_each_entry(type, &ipset->datatypes, list)
        {
                if (i >= 3)
@@ -121,7 +112,7 @@ check_types(struct uci_element *e, struct fw3_ipset *ipset)
                                ipset->method = ipset_types[i].method;
 
                                warn_elem(e, "defines no storage method, assuming '%s'",
                                ipset->method = ipset_types[i].method;
 
                                warn_elem(e, "defines no storage method, assuming '%s'",
-                                         methods[ipset->method]);
+                                         fw3_ipset_method_names[ipset->method]);
 
                                break;
                        }
 
                                break;
                        }
@@ -135,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_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)
                        {
                                if ((ipset_types[i].required & OPT_IPRANGE) &&
                                        !ipset->iprange.set)
@@ -187,10 +178,10 @@ check_types(struct uci_element *e, struct fw3_ipset *ipset)
                                }
 
                                if (!(ipset_types[i].optional & OPT_FAMILY) &&
                                }
 
                                if (!(ipset_types[i].optional & OPT_FAMILY) &&
-                                   ipset->family != FW3_FAMILY_ANY)
+                                   ipset->family != FW3_FAMILY_V4)
                                {
                                        warn_elem(e, "family ignored");
                                {
                                        warn_elem(e, "family ignored");
-                                       ipset->family = FW3_FAMILY_ANY;
+                                       ipset->family = FW3_FAMILY_V4;
                                }
                        }
 
                                }
                        }
 
@@ -216,6 +207,9 @@ fw3_alloc_ipset(void)
 
        INIT_LIST_HEAD(&ipset->datatypes);
 
 
        INIT_LIST_HEAD(&ipset->datatypes);
 
+       ipset->enabled = true;
+       ipset->family  = FW3_FAMILY_V4;
+
        return ipset;
 }
 
        return ipset;
 }
 
@@ -245,6 +239,14 @@ fw3_load_ipsets(struct fw3_state *state, struct uci_package *p)
 
                fw3_parse_options(ipset, fw3_ipset_opts, s);
 
 
                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");
                if (!ipset->name || !*ipset->name)
                {
                        warn_elem(e, "must have a name assigned");
@@ -253,6 +255,10 @@ fw3_load_ipsets(struct fw3_state *state, struct uci_package *p)
                //{
                //      warn_elem(e, "has duplicated set name '%s'", ipset->name);
                //}
                //{
                //      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");
                else if (list_empty(&ipset->datatypes))
                {
                        warn_elem(e, "has no datatypes assigned");
@@ -272,64 +278,23 @@ static void
 create_ipset(struct fw3_ipset *ipset, struct fw3_state *state)
 {
        bool first = true;
 create_ipset(struct fw3_ipset *ipset, struct fw3_state *state)
 {
        bool first = true;
-       char s[INET6_ADDRSTRLEN];
 
        struct fw3_ipset_datatype *type;
 
        struct fw3_ipset_datatype *type;
-       struct fw3_address *a;
-
-       const char *methods[] = {
-               "(bug)",
-               "bitmap",
-               "hash",
-               "list",
-       };
-
-       const char *types[] = {
-               "(bug)",
-               "ip",
-               "port",
-               "mac",
-               "net",
-               "set",
-       };
-
-       if (ipset->external && *ipset->external)
-               return;
 
        info(" * Creating ipset %s", ipset->name);
 
        first = true;
 
        info(" * Creating ipset %s", ipset->name);
 
        first = true;
-       fw3_pr("create %s %s", ipset->name, methods[ipset->method]);
+       fw3_pr("create %s %s", ipset->name, fw3_ipset_method_names[ipset->method]);
 
        list_for_each_entry(type, &ipset->datatypes, list)
        {
 
        list_for_each_entry(type, &ipset->datatypes, list)
        {
-               fw3_pr("%c%s", first ? ':' : ',', types[type->type]);
+               fw3_pr("%c%s", first ? ':' : ',', fw3_ipset_type_names[type->type]);
                first = false;
        }
 
        if (ipset->iprange.set)
        {
                first = false;
        }
 
        if (ipset->iprange.set)
        {
-               a = &ipset->iprange;
-
-               if (!a->range)
-               {
-                       inet_ntop(a->family == FW3_FAMILY_V4 ? AF_INET : AF_INET6,
-                                 &a->address.v6, s, sizeof(s));
-
-                       fw3_pr(" range %s/%u", s, a->mask);
-               }
-               else
-               {
-                       inet_ntop(a->family == FW3_FAMILY_V4 ? AF_INET : AF_INET6,
-                                 &a->address.v6, s, sizeof(s));
-
-                       fw3_pr(" range %s", s);
-
-                       inet_ntop(a->family == FW3_FAMILY_V4 ? AF_INET : AF_INET6,
-                                 &a->address2.v6, s, sizeof(s));
-
-                       fw3_pr("-%s", s);
-               }
+               fw3_pr(" range %s", fw3_address_to_string(&ipset->iprange, false));
        }
        else if (ipset->portrange.set)
        {
        }
        else if (ipset->portrange.set)
        {
@@ -337,8 +302,7 @@ create_ipset(struct fw3_ipset *ipset, struct fw3_state *state)
                       ipset->portrange.port_min, ipset->portrange.port_max);
        }
 
                       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);
 
        if (ipset->timeout > 0)
                fw3_pr(" timeout %u", ipset->timeout);
@@ -358,40 +322,90 @@ create_ipset(struct fw3_ipset *ipset, struct fw3_state *state)
 void
 fw3_create_ipsets(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;
 
        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)
        list_for_each_entry(ipset, &state->ipsets, list)
-               if (!hasbit(ipset->flags[0], FW3_FLAG_DELETED))
-                       if (!fw3_lookup_ipset(state, ipset->name, true))
-                               create_ipset(ipset, state);
+       {
+               if (ipset->external)
+                       continue;
 
 
-       fw3_pr("quit\n");
+               for (tries = 0; !fw3_check_ipset(ipset) && tries < 10; tries++)
+                       usleep(50000);
+       }
 }
 
 void
 }
 
 void
-fw3_destroy_ipsets(struct fw3_state *state, enum fw3_family family)
+fw3_destroy_ipsets(struct fw3_state *state)
 {
 {
-       struct fw3_ipset *s, *tmp;
+       int tries;
+       bool exec = false;
+       struct fw3_ipset *ipset;
 
 
-       list_for_each_entry_safe(s, tmp, &state->ipsets, list)
+       /* destroy ipsets */
+       list_for_each_entry(ipset, &state->ipsets, list)
        {
        {
-               del(s->flags, family, family);
-
-               if (fw3_no_family(s->flags[family == FW3_FAMILY_V6]))
+               if (!exec)
                {
                {
-                       info(" * Deleting ipset %s", s->name);
+                       exec = fw3_command_pipe(false, "ipset", "-exist", "-");
 
 
-                       fw3_pr("flush %s\n", s->name);
-                       fw3_pr("destroy %s\n", s->name);
+                       if (!exec)
+                               return;
                }
                }
+
+               info(" * Deleting ipset %s", ipset->name);
+
+               fw3_pr("flush %s\n", ipset->name);
+               fw3_pr("destroy %s\n", ipset->name);
+       }
+
+       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 *
        }
 }
 
 struct fw3_ipset *
-fw3_lookup_ipset(struct fw3_state *state, const char *name, bool running)
+fw3_lookup_ipset(struct fw3_state *state, const char *name)
 {
        struct fw3_ipset *s;
 
 {
        struct fw3_ipset *s;
 
@@ -408,3 +422,40 @@ fw3_lookup_ipset(struct fw3_state *state, const char *name, bool running)
 
        return NULL;
 }
 
        return NULL;
 }
+
+bool
+fw3_check_ipset(struct fw3_ipset *set)
+{
+       bool rv = false;
+
+       socklen_t sz;
+       int s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
+       struct ip_set_req_version req_ver;
+       struct ip_set_req_get_set req_name;
+
+       if (s < 0 || fcntl(s, F_SETFD, FD_CLOEXEC))
+               goto out;
+
+       sz = sizeof(req_ver);
+       req_ver.op = IP_SET_OP_VERSION;
+
+       if (getsockopt(s, SOL_IP, SO_IP_SET, &req_ver, &sz))
+               goto out;
+
+       sz = sizeof(req_name);
+       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->name);
+
+       if (getsockopt(s, SOL_IP, SO_IP_SET, &req_name, &sz))
+               goto out;
+
+       rv = ((sz == sizeof(req_name)) && (req_name.set.index != IPSET_INVALID_ID));
+
+out:
+       if (s >= 0)
+               close(s);
+
+       return rv;
+}