Extend ipset option syntax to support specifying directions inplace.
authorJo-Philipp Wich <jow@openwrt.org>
Wed, 5 Jun 2013 10:01:34 +0000 (12:01 +0200)
committerJo-Philipp Wich <jow@openwrt.org>
Wed, 5 Jun 2013 10:35:56 +0000 (12:35 +0200)
iptables.c
iptables.h
options.c
options.h
redirects.c
rules.c
utils.c

index 87673ef01aa2f8273fb3d9063bb44643dda9b67a..e1ad2d40e7b641bb2ae11614f0a614b819783a6b 100644 (file)
@@ -795,29 +795,35 @@ fw3_ipt_rule_limit(struct fw3_ipt_rule *r, struct fw3_limit *limit)
 }
 
 void
-fw3_ipt_rule_ipset(struct fw3_ipt_rule *r, struct fw3_ipset *ipset,
-                   bool invert)
+fw3_ipt_rule_ipset(struct fw3_ipt_rule *r, struct fw3_setmatch *match)
 {
        char buf[sizeof("dst,dst,dst\0")];
        char *p = buf;
+       int i = 0;
 
+       struct fw3_ipset *set;
        struct fw3_ipset_datatype *type;
 
-       if (!ipset)
+       if (!match || !match->set || !match->ptr)
                return;
 
-       list_for_each_entry(type, &ipset->datatypes, list)
+       set = match->ptr;
+       list_for_each_entry(type, &set->datatypes, list)
        {
+               if (i >= 3)
+                       break;
+
                if (p > buf)
                        *p++ = ',';
 
-               p += sprintf(p, "%s", type->dest ? "dst" : "src");
+               p += sprintf(p, "%s", match->dir[i] ? match->dir[i] : type->dir);
+               i++;
        }
 
        fw3_ipt_rule_addarg(r, false, "-m", "set");
 
-       fw3_ipt_rule_addarg(r, invert, "--match-set",
-                           ipset->external ? ipset->external : ipset->name);
+       fw3_ipt_rule_addarg(r, match->invert, "--match-set",
+                           set->external ? set->external : set->name);
 
        fw3_ipt_rule_addarg(r, false, buf, NULL);
 }
index b97e5c58908d36b03a37ba29f2e10c777e0d96f7..c8d1add9ce452920044b8e395c6d30bdc9ea0bfc 100644 (file)
@@ -147,8 +147,7 @@ void fw3_ipt_rule_icmptype(struct fw3_ipt_rule *r, struct fw3_icmptype *icmp);
 
 void fw3_ipt_rule_limit(struct fw3_ipt_rule *r, struct fw3_limit *limit);
 
-void fw3_ipt_rule_ipset(struct fw3_ipt_rule *r, struct fw3_ipset *ipset,
-                        bool invert);
+void fw3_ipt_rule_ipset(struct fw3_ipt_rule *r, struct fw3_setmatch *match);
 
 void fw3_ipt_rule_time(struct fw3_ipt_rule *r, struct fw3_time *time);
 
index 43025a8c36962b568e74a7073c87b1a6a808aeb2..5a7a901a6433d47b032b9a7e01b0ba3900b2d947 100644 (file)
--- a/options.c
+++ b/options.c
@@ -577,20 +577,22 @@ fw3_parse_ipset_datatype(void *ptr, const char *val, bool is_list)
 {
        struct fw3_ipset_datatype type = { };
 
+       type.dir = "src";
+
        if (!strncmp(val, "dest_", 5))
        {
                val += 5;
-               type.dest = true;
+               type.dir = "dst";
        }
        else if (!strncmp(val, "dst_", 4))
        {
                val += 4;
-               type.dest = true;
+               type.dir = "dst";
        }
        else if (!strncmp(val, "src_", 4))
        {
                val += 4;
-               type.dest = false;
+               type.dir = "src";
        }
 
        if (parse_enum(&type.type, val, &fw3_ipset_type_names[FW3_IPSET_TYPE_IP],
@@ -809,6 +811,46 @@ fw3_parse_mark(void *ptr, const char *val, bool is_list)
        return true;
 }
 
+bool
+fw3_parse_setmatch(void *ptr, const char *val, bool is_list)
+{
+       struct fw3_setmatch *m = ptr;
+       char *p, *s;
+       int i;
+
+       if (*val == '!')
+       {
+               m->invert = true;
+               while (isspace(*++val));
+       }
+
+       if (!(s = strdup(val)))
+               return false;
+
+       if (!(p = strtok(s, " \t")))
+       {
+               free(s);
+               return false;
+       }
+
+       strncpy(m->name, p, sizeof(m->name));
+
+       for (i = 0, p = strtok(NULL, " \t,");
+            i < 3 && p != NULL;
+            i++, p = strtok(NULL, " \t,"))
+       {
+               if (!strncmp(p, "dest", 4) || !strncmp(p, "dst", 3))
+                       m->dir[i] = "dst";
+               else if (!strncmp(p, "src", 3))
+                       m->dir[i] = "src";
+       }
+
+       free(s);
+
+       m->set = true;
+       return true;
+}
+
 
 void
 fw3_parse_options(void *s, const struct fw3_option *opts,
index aeecef0d547ef04ac4d3b5b5eb3ff873a05d0b75..33c5d1449c2346ac97dc08cd7a9b2e70cb32e892 100644 (file)
--- a/options.h
+++ b/options.h
@@ -141,7 +141,16 @@ struct fw3_ipset_datatype
 {
        struct list_head list;
        enum fw3_ipset_type type;
-       bool dest;
+       const char *dir;
+};
+
+struct fw3_setmatch
+{
+       bool set;
+       bool invert;
+       char name[32];
+       const char *dir[3];
+       struct fw3_ipset *ptr;
 };
 
 struct fw3_device
@@ -320,9 +329,7 @@ struct fw3_rule
 
        struct fw3_device src;
        struct fw3_device dest;
-
-       struct fw3_ipset *_ipset;
-       struct fw3_device ipset;
+       struct fw3_setmatch ipset;
 
        struct list_head proto;
 
@@ -360,9 +367,7 @@ struct fw3_redirect
 
        struct fw3_device src;
        struct fw3_device dest;
-
-       struct fw3_ipset *_ipset;
-       struct fw3_device ipset;
+       struct fw3_setmatch ipset;
 
        struct list_head proto;
 
@@ -505,6 +510,7 @@ bool fw3_parse_time(void *ptr, const char *val, bool is_list);
 bool fw3_parse_weekdays(void *ptr, const char *val, bool is_list);
 bool fw3_parse_monthdays(void *ptr, const char *val, bool is_list);
 bool fw3_parse_mark(void *ptr, const char *val, bool is_list);
+bool fw3_parse_setmatch(void *ptr, const char *val, bool is_list);
 
 void fw3_parse_options(void *s, const struct fw3_option *opts,
                        struct uci_section *section);
index de3d42e2b8023fe63683cac2336a4c4e58761cb7..6d33f905ffbddc1c662dd689fb4e5c5a92ca8768 100644 (file)
@@ -28,7 +28,7 @@ const struct fw3_option fw3_redirect_opts[] = {
        FW3_OPT("src",                 device,    redirect,     src),
        FW3_OPT("dest",                device,    redirect,     dest),
 
-       FW3_OPT("ipset",               device,    redirect,     ipset),
+       FW3_OPT("ipset",               setmatch,  redirect,     ipset),
 
        FW3_LIST("proto",              protocol,  redirect,     proto),
 
@@ -82,7 +82,8 @@ check_families(struct uci_element *e, struct fw3_redirect *r)
                return false;
        }
 
-       if (r->_ipset && r->_ipset->family && r->_ipset->family != r->family)
+       if (r->ipset.ptr && r->ipset.ptr->family &&
+           r->ipset.ptr->family != r->family)
        {
                warn_elem(e, "refers to ipset with different family");
                return false;
@@ -228,8 +229,8 @@ fw3_load_redirects(struct fw3_state *state, struct uci_package *p)
                        fw3_free_redirect(redir);
                        continue;
                }
-               else if (redir->ipset.set && !redir->ipset.any &&
-                        !(redir->_ipset = fw3_lookup_ipset(state, redir->ipset.name)))
+               else if (redir->ipset.set &&
+                        !(redir->ipset.ptr = fw3_lookup_ipset(state, redir->ipset.name)))
                {
                        warn_elem(e, "refers to unknown ipset '%s'", redir->ipset.name);
                        fw3_free_redirect(redir);
@@ -443,7 +444,7 @@ print_redirect(struct fw3_ipt_handle *h, struct fw3_state *state,
                r = fw3_ipt_rule_create(h, proto, NULL, NULL, src, dst);
                fw3_ipt_rule_sport_dport(r, spt, dpt);
                fw3_ipt_rule_mac(r, mac);
-               fw3_ipt_rule_ipset(r, redir->_ipset, redir->ipset.invert);
+               fw3_ipt_rule_ipset(r, &redir->ipset);
                fw3_ipt_rule_time(r, &redir->time);
                fw3_ipt_rule_mark(r, &redir->mark);
                set_target_nat(r, redir);
@@ -461,7 +462,7 @@ print_redirect(struct fw3_ipt_handle *h, struct fw3_state *state,
                r = fw3_ipt_rule_create(h, proto, NULL, NULL, src, dst);
                fw3_ipt_rule_sport_dport(r, spt, dpt);
                fw3_ipt_rule_mac(r, mac);
-               fw3_ipt_rule_ipset(r, redir->_ipset, redir->ipset.invert);
+               fw3_ipt_rule_ipset(r, &redir->ipset);
                fw3_ipt_rule_time(r, &redir->time);
                fw3_ipt_rule_mark(r, &redir->mark);
                set_target_filter(r, redir);
@@ -548,23 +549,23 @@ expand_redirect(struct fw3_ipt_handle *handle, struct fw3_state *state,
                return;
        }
 
-       if (redir->_ipset)
+       if (redir->ipset.ptr)
        {
-               if (!fw3_is_family(redir->_ipset, handle->family))
+               if (!fw3_is_family(redir->ipset.ptr, handle->family))
                {
                        info("     ! Skipping due to different family in ipset");
                        return;
                }
 
-               if (!fw3_check_ipset(redir->_ipset))
+               if (!fw3_check_ipset(redir->ipset.ptr))
                {
                        info("     ! Skipping due to missing ipset '%s'",
-                            redir->_ipset->external ?
-                                       redir->_ipset->external : redir->_ipset->name);
+                            redir->ipset.ptr->external ?
+                                       redir->ipset.ptr->external : redir->ipset.ptr->name);
                        return;
                }
 
-               set(redir->_ipset->flags, handle->family, handle->family);
+               set(redir->ipset.ptr->flags, handle->family, handle->family);
        }
 
        fw3_foreach(proto, &redir->proto)
diff --git a/rules.c b/rules.c
index b6c3d751420c764c004c869a6b4cb21bceed2f06..a251f7c46855cf46f10a6d8ad770e03dcab50a82 100644 (file)
--- a/rules.c
+++ b/rules.c
@@ -28,7 +28,7 @@ const struct fw3_option fw3_rule_opts[] = {
        FW3_OPT("src",                 device,    rule,     src),
        FW3_OPT("dest",                device,    rule,     dest),
 
-       FW3_OPT("ipset",               device,    rule,     ipset),
+       FW3_OPT("ipset",               setmatch,  rule,     ipset),
 
        FW3_LIST("proto",              protocol,  rule,     proto),
 
@@ -133,8 +133,8 @@ fw3_load_rules(struct fw3_state *state, struct uci_package *p)
                        fw3_free_rule(rule);
                        continue;
                }
-               else if (rule->ipset.set && !rule->ipset.any &&
-                        !(rule->_ipset = fw3_lookup_ipset(state, rule->ipset.name)))
+               else if (rule->ipset.set &&
+                        !(rule->ipset.ptr = fw3_lookup_ipset(state, rule->ipset.name)))
                {
                        warn_elem(e, "refers to unknown ipset '%s'", rule->ipset.name);
                        fw3_free_rule(rule);
@@ -330,7 +330,7 @@ print_rule(struct fw3_ipt_handle *handle, struct fw3_state *state,
        fw3_ipt_rule_sport_dport(r, sport, dport);
        fw3_ipt_rule_icmptype(r, icmptype);
        fw3_ipt_rule_mac(r, mac);
-       fw3_ipt_rule_ipset(r, rule->_ipset, rule->ipset.invert);
+       fw3_ipt_rule_ipset(r, &rule->ipset);
        fw3_ipt_rule_limit(r, &rule->limit);
        fw3_ipt_rule_time(r, &rule->time);
        fw3_ipt_rule_mark(r, &rule->mark);
@@ -379,23 +379,23 @@ expand_rule(struct fw3_ipt_handle *handle, struct fw3_state *state,
                return;
        }
 
-       if (rule->_ipset)
+       if (rule->ipset.ptr)
        {
-               if (!fw3_is_family(rule->_ipset, handle->family))
+               if (!fw3_is_family(rule->ipset.ptr, handle->family))
                {
                        info("     ! Skipping due to different family in ipset");
                        return;
                }
 
-               if (!fw3_check_ipset(rule->_ipset))
+               if (!fw3_check_ipset(rule->ipset.ptr))
                {
                        info("     ! Skipping due to missing ipset '%s'",
-                            rule->_ipset->external
-                                       ? rule->_ipset->external : rule->_ipset->name);
+                            rule->ipset.ptr->external
+                                       ? rule->ipset.ptr->external : rule->ipset.ptr->name);
                        return;
                }
 
-               set(rule->_ipset->flags, handle->family, handle->family);
+               set(rule->ipset.ptr->flags, handle->family, handle->family);
        }
 
        list_for_each_entry(proto, &rule->proto, list)
diff --git a/utils.c b/utils.c
index 99310f731337879ee730f5a48a9c2c75522efdb4..66c186580428405da587eb8c2dd01c4b49e5e7a3 100644 (file)
--- a/utils.c
+++ b/utils.c
@@ -557,9 +557,7 @@ write_ipset_uci(struct uci_context *ctx, struct fw3_ipset *s,
 
        list_for_each_entry(type, &s->datatypes, list)
        {
-               sprintf(buf, "%s_%s", type->dest ? "dst" : "src",
-                                     fw3_ipset_type_names[type->type]);
-
+               sprintf(buf, "%s_%s", type->dir, fw3_ipset_type_names[type->type]);
                ptr.o      = NULL;
                ptr.option = "match";
                ptr.value  = buf;