Add support for netifd-generated rules
authorSteven Barth <steven@midlink.org>
Sun, 13 Apr 2014 16:48:39 +0000 (18:48 +0200)
committerSteven Barth <steven@midlink.org>
Mon, 14 Apr 2014 06:50:30 +0000 (08:50 +0200)
Signed-off-by: Steven Barth <steven@midlink.org>
main.c
options.c
options.h
rules.c
rules.h
snats.c
snats.h
ubus.c
ubus.h

diff --git a/main.c b/main.c
index bc1cfd7..27d5298 100644 (file)
--- a/main.c
+++ b/main.c
@@ -98,12 +98,16 @@ build_state(bool runtime)
                cfg_state = state;
        }
 
+
+       struct blob_buf b = {NULL, NULL, 0, NULL};
+       fw3_ubus_rules(&b);
+
        fw3_load_defaults(state, p);
        fw3_load_ipsets(state, p);
        fw3_load_zones(state, p);
-       fw3_load_rules(state, p);
+       fw3_load_rules(state, p, b.head);
        fw3_load_redirects(state, p);
-       fw3_load_snats(state, p);
+       fw3_load_snats(state, p, b.head);
        fw3_load_forwards(state, p);
        fw3_load_includes(state, p);
 
index 1dbdca8..80e5542 100644 (file)
--- a/options.c
+++ b/options.c
@@ -964,6 +964,107 @@ fw3_parse_options(void *s, const struct fw3_option *opts,
 }
 
 
+bool
+fw3_parse_blob_options(void *s, const struct fw3_option *opts,
+                  struct blob_attr *a)
+{
+       char *p, *v, buf[16];
+       bool known;
+       unsigned rem, erem;
+       struct blob_attr *o, *e;
+       const struct fw3_option *opt;
+       struct list_head *dest;
+       bool valid = true;
+
+       blobmsg_for_each_attr(o, a, rem)
+       {
+               known = false;
+
+               for (opt = opts; opt->name; opt++)
+               {
+                       if (!opt->parse)
+                               continue;
+
+                       if (strcmp(opt->name, blobmsg_name(o)))
+                               continue;
+
+                       if (blobmsg_type(o) == BLOBMSG_TYPE_ARRAY)
+                       {
+                               if (!opt->elem_size)
+                               {
+                                       fprintf(stderr, "%s must not be a list\n", opt->name);
+                                       valid = false;
+                               }
+                               else
+                               {
+                                       dest = (struct list_head *)((char *)s + opt->offset);
+
+                                       blobmsg_for_each_attr(e, o, erem)
+                                       {
+                                               if (blobmsg_type(e) == BLOBMSG_TYPE_INT32) {
+                                                       snprintf(buf, sizeof(buf), "%d", blobmsg_get_u32(e));
+                                                       v = buf;
+                                               } else {
+                                                       v = blobmsg_get_string(e);
+                                               }
+
+                                               if (!opt->parse(dest, v, true))
+                                               {
+                                                       fprintf(stderr, "%s has invalid value '%s'\n", opt->name, v);
+                                                       valid = false;
+                                                       continue;
+                                               }
+                                       }
+                               }
+                       }
+                       else
+                       {
+                               if (blobmsg_type(o) == BLOBMSG_TYPE_INT32) {
+                                       snprintf(buf, sizeof(buf), "%d", blobmsg_get_u32(o));
+                                       v = buf;
+                               } else {
+                                       v = blobmsg_get_string(o);
+                               }
+
+                               if (!v)
+                                       continue;
+
+                               if (!opt->elem_size)
+                               {
+                                       if (!opt->parse((char *)s + opt->offset, v, false))
+                                       {
+                                               fprintf(stderr, "%s has invalid value '%s'\n", opt->name, v);
+                                               valid = false;
+                                       }
+                               }
+                               else
+                               {
+                                       dest = (struct list_head *)((char *)s + opt->offset);
+
+                                       for (p = strtok(v, " \t"); p != NULL; p = strtok(NULL, " \t"))
+                                       {
+                                               if (!opt->parse(dest, p, true))
+                                               {
+                                                       fprintf(stderr, "%s has invalid value '%s'\n", opt->name, p);
+                                                       valid = false;
+                                                       continue;
+                                               }
+                                       }
+                               }
+                       }
+
+                       known = true;
+                       break;
+               }
+
+               if (!known)
+                       fprintf(stderr, "%s is unknown\n", blobmsg_name(o));
+       }
+
+       return valid;
+}
+
+
 const char *
 fw3_address_to_string(struct fw3_address *address, bool allow_invert)
 {
index 30c0a95..0a2fa7f 100644 (file)
--- a/options.h
+++ b/options.h
@@ -41,6 +41,7 @@
 
 #include <libubox/list.h>
 #include <libubox/utils.h>
+#include <libubox/blobmsg.h>
 
 #include "icmp_codes.h"
 #include "utils.h"
@@ -558,6 +559,8 @@ bool fw3_parse_direction(void *ptr, const char *val, bool is_list);
 
 bool fw3_parse_options(void *s, const struct fw3_option *opts,
                        struct uci_section *section);
+bool fw3_parse_blob_options(void *s, const struct fw3_option *opts,
+                       struct blob_attr *a);
 
 const char * fw3_address_to_string(struct fw3_address *address,
                                    bool allow_invert);
diff --git a/rules.c b/rules.c
index b41dfac..f45de6e 100644 (file)
--- a/rules.c
+++ b/rules.c
@@ -72,41 +72,71 @@ need_src_action_chain(struct fw3_rule *r)
        return (r->_src && r->_src->log && (r->target > FW3_FLAG_ACCEPT));
 }
 
+static struct fw3_rule*
+alloc_rule(struct fw3_state *state)
+{
+       struct fw3_rule *rule = calloc(1, sizeof(*rule));
+
+       if (rule) {
+               INIT_LIST_HEAD(&rule->proto);
+
+               INIT_LIST_HEAD(&rule->ip_src);
+               INIT_LIST_HEAD(&rule->mac_src);
+               INIT_LIST_HEAD(&rule->port_src);
+
+               INIT_LIST_HEAD(&rule->ip_dest);
+               INIT_LIST_HEAD(&rule->port_dest);
+
+               INIT_LIST_HEAD(&rule->icmp_type);
+
+               list_add_tail(&rule->list, &state->rules);
+               rule->enabled = true;
+       }
+
+       return rule;
+}
+
 void
-fw3_load_rules(struct fw3_state *state, struct uci_package *p)
+fw3_load_rules(struct fw3_state *state, struct uci_package *p,
+               struct blob_attr *a)
 {
        struct uci_section *s;
        struct uci_element *e;
-       struct fw3_rule *rule;
+       struct fw3_rule *rule, *n;
+       struct blob_attr *entry, *opt;
+       unsigned rem, orem;
 
        INIT_LIST_HEAD(&state->rules);
 
-       uci_foreach_element(&p->sections, e)
-       {
-               s = uci_to_section(e);
+       blob_for_each_attr(entry, a, rem) {
+               const char *type = NULL;
+               blobmsg_for_each_attr(opt, entry, orem)
+                       if (!strcmp(blobmsg_name(opt), "type"))
+                               type = blobmsg_get_string(opt);
 
-               if (strcmp(s->type, "rule"))
+               if (!type || strcmp(type, "rule"))
                        continue;
 
-               rule = malloc(sizeof(*rule));
-
-               if (!rule)
+               if (!(rule = alloc_rule(state)))
                        continue;
 
-               memset(rule, 0, sizeof(*rule));
-
-               INIT_LIST_HEAD(&rule->proto);
-
-               INIT_LIST_HEAD(&rule->ip_src);
-               INIT_LIST_HEAD(&rule->mac_src);
-               INIT_LIST_HEAD(&rule->port_src);
+               if (!fw3_parse_blob_options(rule, fw3_rule_opts, entry))
+               {
+                       fprintf(stderr, "ubus section skipped due to invalid options\n");
+                       fw3_free_rule(rule);
+                       continue;
+               }
+       }
 
-               INIT_LIST_HEAD(&rule->ip_dest);
-               INIT_LIST_HEAD(&rule->port_dest);
+       uci_foreach_element(&p->sections, e)
+       {
+               s = uci_to_section(e);
 
-               INIT_LIST_HEAD(&rule->icmp_type);
+               if (strcmp(s->type, "rule"))
+                       continue;
 
-               rule->enabled = true;
+               if (!(rule = alloc_rule(state)))
+                       continue;
 
                if (!fw3_parse_options(rule, fw3_rule_opts, s))
                {
@@ -114,7 +144,10 @@ fw3_load_rules(struct fw3_state *state, struct uci_package *p)
                        fw3_free_rule(rule);
                        continue;
                }
+       }
 
+       list_for_each_entry_safe(rule, n, &state->rules, list)
+       {
                if (!rule->enabled)
                {
                        fw3_free_rule(rule);
@@ -219,9 +252,6 @@ fw3_load_rules(struct fw3_state *state, struct uci_package *p)
                        setbit(rule->_src->flags[0], fw3_to_src_target(rule->target));
                        setbit(rule->_src->flags[1], fw3_to_src_target(rule->target));
                }
-
-               list_add_tail(&rule->list, &state->rules);
-               continue;
        }
 }
 
diff --git a/rules.h b/rules.h
index 6d332fc..bdd36a2 100644 (file)
--- a/rules.h
+++ b/rules.h
 
 extern const struct fw3_option fw3_rule_opts[];
 
-void fw3_load_rules(struct fw3_state *state, struct uci_package *p);
+void fw3_load_rules(struct fw3_state *state, struct uci_package *p, struct blob_attr *a);
 void fw3_print_rules(struct fw3_ipt_handle *handle, struct fw3_state *state);
 
-#define fw3_free_rule(rule) \
-       fw3_free_object(rule, fw3_rule_opts)
+static inline void fw3_free_rule(struct fw3_rule *rule)
+{
+       list_del(&rule->list);
+       fw3_free_object(rule, fw3_rule_opts);
+}
 
 #endif
diff --git a/snats.c b/snats.c
index 1e01192..7dae2ee 100644 (file)
--- a/snats.c
+++ b/snats.c
@@ -104,32 +104,62 @@ check_families(struct uci_element *e, struct fw3_snat *r)
        return true;
 }
 
+
+static struct fw3_snat*
+alloc_snat(struct fw3_state *state)
+{
+       struct fw3_snat *snat = calloc(1, sizeof(*snat));
+
+       if (snat) {
+               INIT_LIST_HEAD(&snat->proto);
+               list_add_tail(&snat->list, &state->snats);
+               snat->enabled = true;
+       }
+
+       return snat;
+}
+
+
 void
-fw3_load_snats(struct fw3_state *state, struct uci_package *p)
+fw3_load_snats(struct fw3_state *state, struct uci_package *p, struct blob_attr *a)
 {
        struct uci_section *s;
        struct uci_element *e;
-       struct fw3_snat *snat;
+       struct fw3_snat *snat, *n;
+       struct blob_attr *rule, *opt;
+       unsigned rem, orem;
 
        INIT_LIST_HEAD(&state->snats);
 
-       uci_foreach_element(&p->sections, e)
-       {
-               s = uci_to_section(e);
+       blob_for_each_attr(rule, a, rem) {
+               const char *type = NULL;
+               blobmsg_for_each_attr(opt, rule, orem)
+                       if (!strcmp(blobmsg_name(opt), "type"))
+                               type = blobmsg_get_string(opt);
 
-               if (strcmp(s->type, "nat"))
+               if (!type || strcmp(type, "nat"))
                        continue;
 
-               snat = malloc(sizeof(*snat));
+               if (!(snat = alloc_snat(state)))
+                       continue;
 
-               if (!snat)
+               if (!fw3_parse_blob_options(snat, fw3_snat_opts, rule))
+               {
+                       fprintf(stderr, "ubus section skipped due to invalid options\n");
+                       fw3_free_snat(snat);
                        continue;
+               }
+       }
 
-               memset(snat, 0, sizeof(*snat));
+       uci_foreach_element(&p->sections, e)
+       {
+               s = uci_to_section(e);
 
-               INIT_LIST_HEAD(&snat->proto);
+               if (strcmp(s->type, "nat"))
+                       continue;
 
-               snat->enabled = true;
+               if (!(snat = alloc_snat(state)))
+                       continue;
 
                if (!fw3_parse_options(snat, fw3_snat_opts, s))
                {
@@ -137,7 +167,10 @@ fw3_load_snats(struct fw3_state *state, struct uci_package *p)
                        fw3_free_snat(snat);
                        continue;
                }
+       }
 
+       list_for_each_entry_safe(snat, n, &state->snats, list)
+       {
                if (!snat->enabled)
                {
                        fw3_free_snat(snat);
@@ -220,8 +253,6 @@ fw3_load_snats(struct fw3_state *state, struct uci_package *p)
                        set(snat->_src->flags, FW3_FAMILY_V4, FW3_FLAG_SNAT);
                        snat->_src->conntrack = true;
                }
-
-               list_add_tail(&snat->list, &state->snats);
        }
 }
 
diff --git a/snats.h b/snats.h
index 00d1406..cf51151 100644 (file)
--- a/snats.h
+++ b/snats.h
 
 extern const struct fw3_option fw3_snat_opts[];
 
-void fw3_load_snats(struct fw3_state *state, struct uci_package *p);
+void fw3_load_snats(struct fw3_state *state, struct uci_package *p, struct blob_attr *a);
 void fw3_print_snats(struct fw3_ipt_handle *handle, struct fw3_state *state);
 
-#define fw3_free_snat(redir) \
-       fw3_free_object(redir, fw3_snat_opts)
+static inline void fw3_free_snat(struct fw3_snat *snat)
+{
+       list_del(&snat->list);
+       fw3_free_object(snat, fw3_snat_opts);
+}
 
 #endif
diff --git a/ubus.c b/ubus.c
index f8b0143..ec6d84f 100644 (file)
--- a/ubus.c
+++ b/ubus.c
@@ -212,3 +212,43 @@ fw3_ubus_zone_devices(struct fw3_zone *zone)
                        fw3_parse_device(&zone->networks, name, true);
        }
 }
+
+void
+fw3_ubus_rules(struct blob_buf *b)
+{
+       blob_buf_init(b, 0);
+
+       struct blob_attr *c, *cur, *dcur, *rule, *ropt;
+       unsigned r, rem, drem, rrem, orem;
+
+       blobmsg_for_each_attr(c, interfaces, r) {
+               const char *l3_device = NULL;
+               struct blob_attr *data = NULL;
+
+               blobmsg_for_each_attr(cur, c, rem) {
+                       if (!strcmp(blobmsg_name(cur), "l3_device"))
+                               l3_device = blobmsg_get_string(cur);
+                       else if (!strcmp(blobmsg_name(cur), "data"))
+                               data = cur;
+               }
+
+               if (!data || !l3_device)
+                       continue;
+
+               blobmsg_for_each_attr(dcur, data, drem) {
+                       if (strcmp(blobmsg_name(dcur), "firewall"))
+                               continue;
+
+                       blobmsg_for_each_attr(rule, dcur, rrem) {
+                               void *k = blobmsg_open_table(b, "");
+
+                               blobmsg_for_each_attr(ropt, rule, orem)
+                                       if (strcmp(blobmsg_name(ropt), "device"))
+                                               blobmsg_add_blob(b, ropt);
+
+                               blobmsg_add_string(b, "device", l3_device);
+                               blobmsg_close_table(b, k);
+                       }
+               }
+       }
+}
diff --git a/ubus.h b/ubus.h
index 4c10481..35eac90 100644 (file)
--- a/ubus.h
+++ b/ubus.h
@@ -34,4 +34,6 @@ struct list_head * fw3_ubus_address(const char *net);
 
 void fw3_ubus_zone_devices(struct fw3_zone *zone);
 
+void fw3_ubus_rules(struct blob_buf *b);
+
 #endif