/*
* firewall3 - 3rd OpenWrt UCI firewall implementation
*
- * Copyright (C) 2013-2014 Jo-Philipp Wich <jow@openwrt.org>
+ * Copyright (C) 2013-2014 Jo-Philipp Wich <jo@mein.io>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
"REJECT",
"DROP",
"NOTRACK",
+ "HELPER",
"MARK",
"DNAT",
"SNAT",
addr.family = FW3_FAMILY_V6;
addr.address.v6 = v6;
- if (m && !inet_pton(AF_INET6, m, &addr.mask.v6))
+ if (m)
{
- bits = strtol(m, &e, 10);
+ if (!inet_pton(AF_INET6, m, &v6))
+ {
+ bits = strtol(m, &e, 10);
- if ((*e != 0) || !fw3_bitlen2netmask(addr.family, bits, &v6))
- goto fail;
+ if ((*e != 0) || !fw3_bitlen2netmask(addr.family, bits, &v6))
+ goto fail;
+ }
addr.mask.v6 = v6;
}
addr.family = FW3_FAMILY_V4;
addr.address.v4 = v4;
- if (m && !inet_pton(AF_INET, m, &addr.mask.v4))
+ if (m)
{
- bits = strtol(m, &e, 10);
+ if (!inet_pton(AF_INET, m, &v4))
+ {
+ bits = strtol(m, &e, 10);
- if ((*e != 0) || !fw3_bitlen2netmask(addr.family, bits, &v4))
- goto fail;
+ if ((*e != 0) || !fw3_bitlen2netmask(addr.family, bits, &v4))
+ goto fail;
+ }
addr.mask.v4 = v4;
}
struct fw3_device dev = { };
struct fw3_address *addr, *tmp;
LIST_HEAD(addr_list);
+ int n_addrs;
if (!fw3_parse_address(ptr, val, is_list))
{
if (!fw3_parse_device(&dev, val, false))
return false;
- fw3_ubus_address(&addr_list, dev.name);
+ n_addrs = fw3_ubus_address(&addr_list, dev.name);
+
list_for_each_entry(addr, &addr_list, list)
{
addr->invert = dev.invert;
addr->resolved = true;
}
+ /* add an empty address member with .set = false, .resolved = true
+ * to signal resolving failure to callers */
+ if (n_addrs == 0)
+ {
+ tmp = fw3_alloc(sizeof(*tmp));
+ tmp->resolved = true;
+
+ list_add_tail(&tmp->list, &addr_list);
+ }
+
if (is_list)
{
list_splice_tail(&addr_list, ptr);
bool
fw3_parse_family(void *ptr, const char *val, bool is_list)
{
- if (!strcmp(val, "any"))
+ if (!strcmp(val, "any") || !strcmp(val, "*"))
*((enum fw3_family *)ptr) = FW3_FAMILY_ANY;
else if (!strcmp(val, "inet") || strrchr(val, '4'))
*((enum fw3_family *)ptr) = FW3_FAMILY_V4;
while (isspace(*++val));
}
- if (!strcmp(val, "all"))
+ if (!strcmp(val, "all") || !strcmp(val, "any") || !strcmp(val, "*"))
{
proto.any = true;
put_value(ptr, &proto, sizeof(proto), is_list);
if (*val == '!')
{
- setbit(*(uint8_t *)ptr, 0);
+ fw3_setbit(*(uint8_t *)ptr, 0);
while (isspace(*++val));
}
}
}
- setbit(*(uint8_t *)ptr, w);
+ fw3_setbit(*(uint8_t *)ptr, w);
}
free(s);
if (*val == '!')
{
- setbit(*(uint32_t *)ptr, 0);
+ fw3_setbit(*(uint32_t *)ptr, 0);
while (isspace(*++val));
}
return false;
}
- setbit(*(uint32_t *)ptr, d);
+ fw3_setbit(*(uint32_t *)ptr, d);
}
free(s);
return valid;
}
+bool
+fw3_parse_cthelper(void *ptr, const char *val, bool is_list)
+{
+ struct fw3_cthelpermatch m = { };
+
+ if (*val == '!')
+ {
+ m.invert = true;
+ while (isspace(*++val));
+ }
+
+ if (*val)
+ {
+ m.set = true;
+ strncpy(m.name, val, sizeof(m.name) - 1);
+ put_value(ptr, &m, sizeof(m), is_list);
+ return true;
+ }
+
+ return false;
+}
+
+bool
+fw3_parse_setentry(void *ptr, const char *val, bool is_list)
+{
+ struct fw3_setentry e = { };
+
+ e.value = val;
+ put_value(ptr, &e, sizeof(e), is_list);
+
+ return true;
+}
+
bool
fw3_parse_options(void *s, const struct fw3_option *opts,
struct uci_section *section)
{
char *p, *v;
- bool known;
+ bool known, inv;
struct uci_element *e, *l;
struct uci_option *o;
const struct fw3_option *opt;
}
else
{
+ inv = false;
dest = (struct list_head *)((char *)s + opt->offset);
for (p = strtok(v, " \t"); p != NULL; p = strtok(NULL, " \t"))
{
+ /* If we encounter a sole "!" token, assume that it
+ * is meant to be part of the next token, so silently
+ * skip it and remember the state... */
+ if (!strcmp(p, "!"))
+ {
+ inv = true;
+ continue;
+ }
+
+ /* The previous token was a sole "!", rewind pointer
+ * back by one byte to precede the value with an
+ * exclamation mark which effectively turns
+ * ("!", "foo") into ("!foo") */
+ if (inv)
+ {
+ *--p = '!';
+ inv = false;
+ }
+
if (!opt->parse(dest, p, true))
{
warn_elem(e, "has invalid value '%s'", p);
continue;
}
}
+
+ /* The last token was a sole "!" without any subsequent
+ * text, so pass it to the option parser as-is. */
+ if (inv && !opt->parse(dest, "!", true))
+ {
+ warn_elem(e, "has invalid value '%s'", p);
+ valid = false;
+ }
}
}
bool
fw3_parse_blob_options(void *s, const struct fw3_option *opts,
- struct blob_attr *a)
+ struct blob_attr *a, const char *name)
{
char *p, *v, buf[16];
bool known;
{
if (!opt->elem_size)
{
- fprintf(stderr, "%s must not be a list\n", opt->name);
+ fprintf(stderr, "%s: '%s' must not be a list\n",
+ name, opt->name);
+
valid = false;
}
else
if (!opt->parse(dest, v, true))
{
- fprintf(stderr, "%s has invalid value '%s'\n", opt->name, v);
+ fprintf(stderr, "%s: '%s' has invalid value '%s'\n",
+ name, opt->name, v);
valid = false;
continue;
}
{
if (!opt->parse((char *)s + opt->offset, v, false))
{
- fprintf(stderr, "%s has invalid value '%s'\n", opt->name, v);
+ fprintf(stderr, "%s: '%s' has invalid value '%s'\n",
+ name, opt->name, v);
valid = false;
}
}
{
if (!opt->parse(dest, p, true))
{
- fprintf(stderr, "%s has invalid value '%s'\n", opt->name, p);
+ fprintf(stderr, "%s: '%s' has invalid value '%s'\n",
+ name, opt->name, p);
valid = false;
continue;
}
break;
}
- if (!known)
- fprintf(stderr, "%s is unknown\n", blobmsg_name(o));
+ if (!known && strcmp(blobmsg_name(o), "type"))
+ fprintf(stderr, "%s: '%s' is unknown\n", name, blobmsg_name(o));
}
return valid;