X-Git-Url: http://git.archive.openwrt.org/?p=project%2Ffirewall3.git;a=blobdiff_plain;f=options.c;h=d88d3ba09b50b6f17173af7fbac5071a692fe440;hp=43025a8c36962b568e74a7073c87b1a6a808aeb2;hb=6039c7f4b0052c4da21520cdd604f04a5a67f50d;hpb=ea46bc485f05548bb2bd26bc446167e211962c92 diff --git a/options.c b/options.c index 43025a8..d88d3ba 100644 --- a/options.c +++ b/options.c @@ -1,7 +1,7 @@ /* * firewall3 - 3rd OpenWrt UCI firewall implementation * - * Copyright (C) 2013 Jo-Philipp Wich + * Copyright (C) 2013-2014 Jo-Philipp Wich * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -78,6 +78,7 @@ const char *fw3_flag_names[__FW3_FLAG_MAX] = { "MARK", "DNAT", "SNAT", + "MASQUERADE", "ACCEPT", "REJECT", @@ -142,9 +143,10 @@ fw3_parse_bool(void *ptr, const char *val, bool is_list) bool fw3_parse_int(void *ptr, const char *val, bool is_list) { - int n = strtol(val, NULL, 0); + char *e; + int n = strtol(val, &e, 0); - if (errno == ERANGE || errno == EINVAL) + if (e == val || *e) return false; *((int *)ptr) = n; @@ -163,7 +165,7 @@ bool fw3_parse_target(void *ptr, const char *val, bool is_list) { return parse_enum(ptr, val, &fw3_flag_names[FW3_FLAG_ACCEPT], - FW3_FLAG_ACCEPT, FW3_FLAG_SNAT); + FW3_FLAG_ACCEPT, FW3_FLAG_MASQUERADE); } bool @@ -242,8 +244,8 @@ fw3_parse_address(void *ptr, const char *val, bool is_list) struct fw3_address addr = { }; struct in_addr v4; struct in6_addr v6; - char *p, *s, *e; - int i, m = -1; + char *p = NULL, *m = NULL, *s, *e; + int bits = -1; if (*val == '!') { @@ -256,99 +258,114 @@ fw3_parse_address(void *ptr, const char *val, bool is_list) if (!s) return false; - if ((p = strchr(s, '/')) != NULL) - { + if ((m = strchr(s, '/')) != NULL) + *m++ = 0; + else if ((p = strchr(s, '-')) != NULL) *p++ = 0; - m = strtoul(p, &e, 10); - if ((e == p) || (*e != 0)) + if (inet_pton(AF_INET6, s, &v6)) + { + addr.family = FW3_FAMILY_V6; + addr.address.v6 = v6; + + if (m) { - if (strchr(s, ':') || !inet_pton(AF_INET, p, &v4)) + if (!inet_pton(AF_INET6, m, &v6)) { - free(s); - return false; - } + bits = strtol(m, &e, 10); - for (i = 0, m = 32; !(v4.s_addr & 1) && (i < 32); i++) - { - m--; - v4.s_addr >>= 1; + if ((*e != 0) || !fw3_bitlen2netmask(addr.family, bits, &v6)) + goto fail; } - } - } - else if ((p = strchr(s, '-')) != NULL) - { - *p++ = 0; - if (inet_pton(AF_INET6, p, &v6)) - { - addr.family = FW3_FAMILY_V6; - addr.address2.v6 = v6; - addr.range = true; + addr.mask.v6 = v6; } - else if (inet_pton(AF_INET, p, &v4)) + else if (p) { - addr.family = FW3_FAMILY_V4; - addr.address2.v4 = v4; + if (!inet_pton(AF_INET6, p, &addr.mask.v6)) + goto fail; + addr.range = true; } else { - free(s); - return false; + memset(addr.mask.v6.s6_addr, 0xFF, 16); } } - - if (inet_pton(AF_INET6, s, &v6)) - { - addr.family = FW3_FAMILY_V6; - addr.address.v6 = v6; - addr.mask = (m >= 0) ? m : 128; - } else if (inet_pton(AF_INET, s, &v4)) { addr.family = FW3_FAMILY_V4; addr.address.v4 = v4; - addr.mask = (m >= 0) ? m : 32; + + if (m) + { + if (!inet_pton(AF_INET, m, &v4)) + { + bits = strtol(m, &e, 10); + + if ((*e != 0) || !fw3_bitlen2netmask(addr.family, bits, &v4)) + goto fail; + } + + addr.mask.v4 = v4; + } + else if (p) + { + if (!inet_pton(AF_INET, p, &addr.mask.v4)) + goto fail; + + addr.range = true; + } + else + { + addr.mask.v4.s_addr = 0xFFFFFFFF; + } } else { - free(s); - return false; + goto fail; } free(s); addr.set = true; put_value(ptr, &addr, sizeof(addr), is_list); return true; + +fail: + free(s); + return false; } bool fw3_parse_network(void *ptr, const char *val, bool is_list) { struct fw3_device dev = { }; - struct fw3_address *addr; - struct list_head *addr_list; + struct fw3_address *addr, *tmp; + LIST_HEAD(addr_list); if (!fw3_parse_address(ptr, val, is_list)) { if (!fw3_parse_device(&dev, val, false)) return false; - addr_list = fw3_ubus_address(dev.name); - - if (addr_list) + fw3_ubus_address(&addr_list, dev.name); + list_for_each_entry(addr, &addr_list, list) { - list_for_each_entry(addr, addr_list, list) - { - addr->invert = dev.invert; - addr->resolved = true; + addr->invert = dev.invert; + addr->resolved = true; + } - if (!put_value(ptr, addr, sizeof(*addr), is_list)) - break; - } + if (is_list) + { + list_splice_tail(&addr_list, ptr); + } + else if (!list_empty(&addr_list)) + { + memcpy(ptr, list_first_entry(&addr_list, typeof(*addr), list), + sizeof(*addr)); - fw3_free_list(addr_list); + list_for_each_entry_safe(addr, tmp, &addr_list, list) + free(addr); } } @@ -425,7 +442,7 @@ fw3_parse_port(void *ptr, const char *val, bool is_list) 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; @@ -518,6 +535,7 @@ fw3_parse_protocol(void *ptr, const char *val, bool is_list) { struct fw3_protocol proto = { }; struct protoent *ent; + char *e; if (*val == '!') { @@ -525,7 +543,7 @@ fw3_parse_protocol(void *ptr, const char *val, bool is_list) 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); @@ -556,9 +574,9 @@ fw3_parse_protocol(void *ptr, const char *val, bool is_list) return true; } - proto.protocol = strtoul(val, NULL, 10); + proto.protocol = strtoul(val, &e, 10); - if (errno == ERANGE || errno == EINVAL) + if ((e == val) || (*e != 0)) return false; put_value(ptr, &proto, sizeof(proto), is_list); @@ -577,20 +595,22 @@ fw3_parse_ipset_datatype(void *ptr, const char *val, bool is_list) { struct fw3_ipset_datatype type = { }; + type.dir = "src"; + if (!strncmp(val, "dest_", 5)) { val += 5; - type.dest = true; + type.dir = "dst"; } else if (!strncmp(val, "dst_", 4)) { val += 4; - type.dest = true; + type.dir = "dst"; } else if (!strncmp(val, "src_", 4)) { val += 4; - type.dest = false; + type.dir = "src"; } if (parse_enum(&type.type, val, &fw3_ipset_type_names[FW3_IPSET_TYPE_IP], @@ -698,7 +718,7 @@ fw3_parse_weekdays(void *ptr, const char *val, bool is_list) if (*val == '!') { - setbit(*(uint8_t *)ptr, 0); + fw3_setbit(*(uint8_t *)ptr, 0); while (isspace(*++val)); } @@ -718,7 +738,7 @@ fw3_parse_weekdays(void *ptr, const char *val, bool is_list) } } - setbit(*(uint8_t *)ptr, w); + fw3_setbit(*(uint8_t *)ptr, w); } free(s); @@ -733,7 +753,7 @@ fw3_parse_monthdays(void *ptr, const char *val, bool is_list) if (*val == '!') { - setbit(*(uint32_t *)ptr, 0); + fw3_setbit(*(uint32_t *)ptr, 0); while (isspace(*++val)); } @@ -750,7 +770,7 @@ fw3_parse_monthdays(void *ptr, const char *val, bool is_list) return false; } - setbit(*(uint32_t *)ptr, d); + fw3_setbit(*(uint32_t *)ptr, d); } free(s); @@ -809,8 +829,64 @@ fw3_parse_mark(void *ptr, const char *val, bool is_list) return true; } +bool +fw3_parse_setmatch(void *ptr, const char *val, bool is_list) +{ + struct fw3_setmatch *m = ptr; + char *p, *s; + int i; + + if (*val == '!') + { + m->invert = true; + while (isspace(*++val)); + } + + if (!(s = strdup(val))) + return false; + + if (!(p = strtok(s, " \t"))) + { + free(s); + return false; + } + + strncpy(m->name, p, sizeof(m->name)); + + for (i = 0, p = strtok(NULL, " \t,"); + i < 3 && p != NULL; + i++, p = strtok(NULL, " \t,")) + { + if (!strncmp(p, "dest", 4) || !strncmp(p, "dst", 3)) + m->dir[i] = "dst"; + else if (!strncmp(p, "src", 3)) + m->dir[i] = "src"; + } + + free(s); + + m->set = true; + return true; +} + +bool +fw3_parse_direction(void *ptr, const char *val, bool is_list) +{ + bool *is_out = ptr; + bool valid = true; -void + if (!strcmp(val, "in") || !strcmp(val, "ingress")) + *is_out = false; + else if (!strcmp(val, "out") || !strcmp(val, "egress")) + *is_out = true; + else + valid = false; + + return valid; +} + + +bool fw3_parse_options(void *s, const struct fw3_option *opts, struct uci_section *section) { @@ -820,6 +896,7 @@ fw3_parse_options(void *s, const struct fw3_option *opts, struct uci_option *o; const struct fw3_option *opt; struct list_head *dest; + bool valid = true; uci_foreach_element(§ion->options, e) { @@ -839,6 +916,7 @@ fw3_parse_options(void *s, const struct fw3_option *opts, if (!opt->elem_size) { warn_elem(e, "must not be a list"); + valid = false; } else { @@ -852,6 +930,7 @@ fw3_parse_options(void *s, const struct fw3_option *opts, if (!opt->parse(dest, l->name, true)) { warn_elem(e, "has invalid value '%s'", l->name); + valid = false; continue; } } @@ -867,7 +946,10 @@ fw3_parse_options(void *s, const struct fw3_option *opts, if (!opt->elem_size) { if (!opt->parse((char *)s + opt->offset, o->v.string, false)) + { warn_elem(e, "has invalid value '%s'", o->v.string); + valid = false; + } } else { @@ -878,6 +960,7 @@ fw3_parse_options(void *s, const struct fw3_option *opts, if (!opt->parse(dest, p, true)) { warn_elem(e, "has invalid value '%s'", p); + valid = false; continue; } } @@ -891,11 +974,119 @@ fw3_parse_options(void *s, const struct fw3_option *opts, if (!known) warn_elem(e, "is unknown"); } + + return valid; +} + + +bool +fw3_parse_blob_options(void *s, const struct fw3_option *opts, + struct blob_attr *a, const char *name) +{ + 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: '%s' must not be a list\n", + name, 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: '%s' has invalid value '%s'\n", + name, 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: '%s' has invalid value '%s'\n", + name, 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: '%s' has invalid value '%s'\n", + name, opt->name, p); + valid = false; + continue; + } + } + } + } + + known = true; + break; + } + + if (!known && strcmp(blobmsg_name(o), "type")) + fprintf(stderr, "%s: '%s' is unknown\n", name, blobmsg_name(o)); + } + + return valid; } const char * -fw3_address_to_string(struct fw3_address *address, bool allow_invert) +fw3_address_to_string(struct fw3_address *address, bool allow_invert, bool as_cidr) { char *p, ip[INET6_ADDRSTRLEN]; static char buf[INET6_ADDRSTRLEN * 2 + 2]; @@ -913,13 +1104,21 @@ fw3_address_to_string(struct fw3_address *address, bool allow_invert) if (address->range) { inet_ntop(address->family == FW3_FAMILY_V4 ? AF_INET : AF_INET6, - &address->address2.v4, ip, sizeof(ip)); + &address->mask.v4, ip, sizeof(ip)); p += sprintf(p, "-%s", ip); } + else if (!as_cidr) + { + inet_ntop(address->family == FW3_FAMILY_V4 ? AF_INET : AF_INET6, + &address->mask.v4, ip, sizeof(ip)); + + p += sprintf(p, "/%s", ip); + } else { - p += sprintf(p, "/%u", address->mask); + p += sprintf(p, "/%u", fw3_netmask2bitlen(address->family, + &address->mask.v6)); } return buf;