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);
}
+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)
{
#include <libubox/list.h>
#include <libubox/utils.h>
+#include <libubox/blobmsg.h>
#include "icmp_codes.h"
#include "utils.h"
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);
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))
{
fw3_free_rule(rule);
continue;
}
+ }
+ list_for_each_entry_safe(rule, n, &state->rules, list)
+ {
if (!rule->enabled)
{
fw3_free_rule(rule);
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;
}
}
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
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))
{
fw3_free_snat(snat);
continue;
}
+ }
+ list_for_each_entry_safe(snat, n, &state->snats, list)
+ {
if (!snat->enabled)
{
fw3_free_snat(snat);
set(snat->_src->flags, FW3_FAMILY_V4, FW3_FLAG_SNAT);
snat->_src->conntrack = true;
}
-
- list_add_tail(&snat->list, &state->snats);
}
}
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
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);
+ }
+ }
+ }
+}
void fw3_ubus_zone_devices(struct fw3_zone *zone);
+void fw3_ubus_rules(struct blob_buf *b);
+
#endif