summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPierre Lebleu <pme.lebleu@gmail.com>2017-05-04 10:52:56 +0200
committerJo-Philipp Wich <jo@mein.io>2017-05-09 23:54:15 +0200
commit5cd4af49acce3c8cdc26003be45a562f82121f09 (patch)
tree2597a76b6d1a46843a10b11e9f236802d32a2a11
parent02d68323ec83a5163caa4da3ed5f96860f607dae (diff)
downloadfirewall3-5cd4af49acce3c8cdc26003be45a562f82121f09.tar.gz
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 <pme.lebleu@gmail.com>
-rw-r--r--ipsets.c139
-rw-r--r--ipsets.h11
-rw-r--r--main.c2
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);