Browse Source

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>
Pierre Lebleu 7 years ago
parent
commit
5cd4af49ac
3 changed files with 95 additions and 57 deletions
  1. 88 51
      ipsets.c
  2. 6 5
      ipsets.h
  3. 1 1
      main.c

+ 88 - 51
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);
 	}
 }
 

+ 6 - 5
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
 

+ 1 - 1
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);