From 5cd4af49acce3c8cdc26003be45a562f82121f09 Mon Sep 17 00:00:00 2001 From: Pierre Lebleu Date: Thu, 4 May 2017 10:52:56 +0200 Subject: [PATCH] firewall3: add UBUS support for ipset sections It gives the ability to create ipset rules via procd services and netifd interface firewall data. Signed-off-by: Pierre Lebleu --- ipsets.c | 139 ++++++++++++++++++++++++++++++++++++++++----------------------- ipsets.h | 11 ++--- main.c | 2 +- 3 files changed, 95 insertions(+), 57 deletions(-) diff --git a/ipsets.c b/ipsets.c index 7a72fd3..30c6463 100644 --- a/ipsets.c +++ b/ipsets.c @@ -95,7 +95,7 @@ check_types(struct uci_element *e, struct fw3_ipset *ipset) { if (i >= 3) { - warn_elem(e, "must not have more than 3 datatypes assigned"); + warn_section("ipset", ipset, e, "must not have more than 3 datatypes assigned"); return false; } @@ -116,8 +116,8 @@ 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'", - fw3_ipset_method_names[ipset->method]); + warn_section("ipset", ipset, e, "defines no storage method, assuming '%s'", + fw3_ipset_method_names[ipset->method]); break; } @@ -136,56 +136,56 @@ check_types(struct uci_element *e, struct fw3_ipset *ipset) if ((ipset_types[i].required & OPT_IPRANGE) && !ipset->iprange.set) { - warn_elem(e, "requires an ip range"); + warn_section("ipset", ipset, e, "requires an ip range"); return false; } if ((ipset_types[i].required & OPT_PORTRANGE) && !ipset->portrange.set) { - warn_elem(e, "requires a port range"); + warn_section("ipset", ipset, e, "requires a port range"); return false; } if (!(ipset_types[i].required & OPT_IPRANGE) && ipset->iprange.set) { - warn_elem(e, "iprange ignored"); + warn_section("ipset", ipset, e, "iprange ignored"); ipset->iprange.set = false; } if (!(ipset_types[i].required & OPT_PORTRANGE) && ipset->portrange.set) { - warn_elem(e, "portrange ignored"); + warn_section("ipset", ipset, e, "portrange ignored"); ipset->portrange.set = false; } if (!(ipset_types[i].optional & OPT_NETMASK) && ipset->netmask > 0) { - warn_elem(e, "netmask ignored"); + warn_section("ipset", ipset, e, "netmask ignored"); ipset->netmask = 0; } if (!(ipset_types[i].optional & OPT_HASHSIZE) && ipset->hashsize > 0) { - warn_elem(e, "hashsize ignored"); + warn_section("ipset", ipset, e, "hashsize ignored"); ipset->hashsize = 0; } if (!(ipset_types[i].optional & OPT_MAXELEM) && ipset->maxelem > 0) { - warn_elem(e, "maxelem ignored"); + warn_section("ipset", ipset, e, "maxelem ignored"); ipset->maxelem = 0; } if (!(ipset_types[i].optional & OPT_FAMILY) && ipset->family != FW3_FAMILY_V4) { - warn_elem(e, "family ignored"); + warn_section("ipset", ipset, e, "family ignored"); ipset->family = FW3_FAMILY_V4; } } @@ -194,12 +194,51 @@ check_types(struct uci_element *e, struct fw3_ipset *ipset) } } - warn_elem(e, "has an invalid combination of storage method and matches"); + warn_section("ipset", ipset, e, "has an invalid combination of storage method and matches"); return false; } -struct fw3_ipset * -fw3_alloc_ipset(void) +static bool +check_ipset(struct fw3_state *state, struct fw3_ipset *ipset, struct uci_element *e) +{ + if (ipset->external) + { + if (!*ipset->external) + ipset->external = NULL; + else if (!ipset->name) + ipset->name = ipset->external; + } + + if (!ipset->name || !*ipset->name) + { + warn_section("ipset", ipset, e, "ipset must have a name assigned"); + } + //else if (fw3_lookup_ipset(state, ipset->name) != NULL) + //{ + // warn_section("ipset", ipset, e, "has duplicated set name", ipset->name); + //} + else if (ipset->family == FW3_FAMILY_ANY) + { + warn_section("ipset", ipset, e, "must not have family 'any'"); + } + else if (ipset->iprange.set && ipset->family != ipset->iprange.family) + { + warn_section("ipset", ipset, e, "has iprange of wrong address family"); + } + else if (list_empty(&ipset->datatypes)) + { + warn_section("ipset", ipset, e, "has no datatypes assigned"); + } + else if (check_types(e, ipset)) + { + return true; + } + + return false; +} + +static struct fw3_ipset * +fw3_alloc_ipset(struct fw3_state *state) { struct fw3_ipset *ipset; @@ -212,21 +251,52 @@ fw3_alloc_ipset(void) ipset->enabled = true; ipset->family = FW3_FAMILY_V4; + list_add_tail(&ipset->list, &state->ipsets); + return ipset; } void -fw3_load_ipsets(struct fw3_state *state, struct uci_package *p) +fw3_load_ipsets(struct fw3_state *state, struct uci_package *p, + struct blob_attr *a) { struct uci_section *s; struct uci_element *e; struct fw3_ipset *ipset; + struct blob_attr *entry; + unsigned rem; INIT_LIST_HEAD(&state->ipsets); if (state->disable_ipsets) return; + blob_for_each_attr(entry, a, rem) + { + const char *type; + const char *name = "ubus ipset"; + + if (!fw3_attr_parse_name_type(entry, &name, &type)) + continue; + + if (strcmp(type, "ipset")) + continue; + + ipset = fw3_alloc_ipset(state); + if (!ipset) + continue; + + if (!fw3_parse_blob_options(ipset, fw3_ipset_opts, entry, name)) + { + warn_section("ipset", ipset, NULL, "skipped due to invalid options"); + fw3_free_ipset(ipset); + continue; + } + + if (!check_ipset(state, ipset, NULL)) + fw3_free_ipset(ipset); + } + uci_foreach_element(&p->sections, e) { s = uci_to_section(e); @@ -234,7 +304,7 @@ fw3_load_ipsets(struct fw3_state *state, struct uci_package *p) if (strcmp(s->type, "ipset")) continue; - ipset = fw3_alloc_ipset(); + ipset = fw3_alloc_ipset(state); if (!ipset) continue; @@ -242,41 +312,8 @@ fw3_load_ipsets(struct fw3_state *state, struct uci_package *p) if (!fw3_parse_options(ipset, fw3_ipset_opts, s)) warn_elem(e, "has invalid options"); - 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"); - } - //else if (fw3_lookup_ipset(state, ipset->name) != NULL) - //{ - // 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 (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"); - } - else if (check_types(e, ipset)) - { - list_add_tail(&ipset->list, &state->ipsets); - continue; - } - - fw3_free_ipset(ipset); + if (!check_ipset(state, ipset, e)) + fw3_free_ipset(ipset); } } diff --git a/ipsets.h b/ipsets.h index b5fee6c..2ba862d 100644 --- a/ipsets.h +++ b/ipsets.h @@ -27,8 +27,7 @@ extern const struct fw3_option fw3_ipset_opts[]; -struct fw3_ipset * fw3_alloc_ipset(void); -void fw3_load_ipsets(struct fw3_state *state, struct uci_package *p); +void fw3_load_ipsets(struct fw3_state *state, struct uci_package *p, struct blob_attr *a); void fw3_create_ipsets(struct fw3_state *state); void fw3_destroy_ipsets(struct fw3_state *state); @@ -36,9 +35,11 @@ struct fw3_ipset * fw3_lookup_ipset(struct fw3_state *state, const char *name); bool fw3_check_ipset(struct fw3_ipset *set); -#define fw3_free_ipset(ipset) \ - fw3_free_object(ipset, fw3_ipset_opts) - +static inline void fw3_free_ipset(struct fw3_ipset *ipset) +{ + list_del(&ipset->list); + fw3_free_object(ipset, fw3_ipset_opts); +} #ifndef SO_IP_SET diff --git a/main.c b/main.c index 4cf46fd..6e275ef 100644 --- a/main.c +++ b/main.c @@ -101,7 +101,7 @@ build_state(bool runtime) fw3_ubus_rules(&b); fw3_load_defaults(state, p); - fw3_load_ipsets(state, p); + fw3_load_ipsets(state, p, b.head); fw3_load_zones(state, p); fw3_load_rules(state, p, b.head); fw3_load_redirects(state, p, b.head); -- 2.11.0