From 3a3d85b3c787271e4860ca590d716cf557c1fb7e Mon Sep 17 00:00:00 2001 From: Jo-Philipp Wich Date: Wed, 5 Jun 2013 12:01:34 +0200 Subject: [PATCH] Extend ipset option syntax to support specifying directions inplace. --- iptables.c | 20 +++++++++++++------- iptables.h | 3 +-- options.c | 48 +++++++++++++++++++++++++++++++++++++++++++++--- options.h | 20 +++++++++++++------- redirects.c | 25 +++++++++++++------------ rules.c | 20 ++++++++++---------- utils.c | 4 +--- 7 files changed, 96 insertions(+), 44 deletions(-) diff --git a/iptables.c b/iptables.c index 87673ef..e1ad2d4 100644 --- a/iptables.c +++ b/iptables.c @@ -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); } diff --git a/iptables.h b/iptables.h index b97e5c5..c8d1add 100644 --- a/iptables.h +++ b/iptables.h @@ -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); diff --git a/options.c b/options.c index 43025a8..5a7a901 100644 --- 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, diff --git a/options.h b/options.h index aeecef0..33c5d14 100644 --- 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); diff --git a/redirects.c b/redirects.c index de3d42e..6d33f90 100644 --- a/redirects.c +++ b/redirects.c @@ -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 b6c3d75..a251f7c 100644 --- 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 99310f7..66c1865 100644 --- 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; -- 2.25.1