X-Git-Url: http://git.archive.openwrt.org/?a=blobdiff_plain;f=options.c;h=e864db7ca3c3a12c9edeb0a87cf1ff5af60036c4;hb=92281eb747b56e748b7c3d754055919c23befdd4;hp=ef5eaa71e9e6e4ab1141e891f83b68aeaaae0670;hpb=6c4c4bf32e802f4629a17b57778eba4db2c84dfa;p=project%2Ffirewall3.git diff --git a/options.c b/options.c index ef5eaa7..e864db7 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 @@ -75,28 +75,32 @@ const char *fw3_flag_names[__FW3_FLAG_MAX] = { "REJECT", "DROP", "NOTRACK", + "MARK", "DNAT", "SNAT", + "MASQUERADE", "ACCEPT", "REJECT", "DROP", }; -static const char *limit_units[] = { +const char *fw3_limit_units[__FW3_LIMIT_UNIT_MAX] = { "second", "minute", "hour", "day", }; -static const char *ipset_methods[] = { +const char *fw3_ipset_method_names[__FW3_IPSET_METHOD_MAX] = { + "(bug)", "bitmap", "hash", "list", }; -static const char *ipset_types[] = { +const char *fw3_ipset_type_names[__FW3_IPSET_TYPE_MAX] = { + "(bug)", "ip", "port", "mac", @@ -139,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, 10); + char *e; + int n = strtol(val, &e, 0); - if (errno == ERANGE || errno == EINVAL) + if (e == val || *e) return false; *((int *)ptr) = n; @@ -160,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 @@ -188,7 +193,7 @@ fw3_parse_limit(void *ptr, const char *val, bool is_list) if (!strlen(e)) return false; - if (!parse_enum(&u, e, limit_units, 0, FW3_LIMIT_UNIT_DAY)) + if (!parse_enum(&u, e, fw3_limit_units, 0, FW3_LIMIT_UNIT_DAY)) return false; limit->rate = n; @@ -200,12 +205,14 @@ fw3_parse_limit(void *ptr, const char *val, bool is_list) bool fw3_parse_device(void *ptr, const char *val, bool is_list) { + char *p; struct fw3_device dev = { }; if (*val == '*') { dev.set = true; dev.any = true; + put_value(ptr, &dev, sizeof(dev), is_list); return true; } @@ -215,6 +222,12 @@ fw3_parse_device(void *ptr, const char *val, bool is_list) while (isspace(*++val)); } + if ((p = strchr(val, '@')) != NULL) + { + *p++ = 0; + snprintf(dev.network, sizeof(dev.network), "%s", p); + } + if (*val) snprintf(dev.name, sizeof(dev.name), "%s", val); else @@ -317,27 +330,20 @@ fw3_parse_network(void *ptr, const char *val, bool is_list) { struct fw3_device dev = { }; struct fw3_address *addr; - struct list_head *addr_list; + 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; - - if (!put_value(ptr, addr, sizeof(*addr), is_list)) - break; - } - - fw3_ubus_address_free(addr_list); + addr->invert = dev.invert; + addr->resolved = true; } + list_splice_tail(&addr_list, ptr); } return true; @@ -506,6 +512,7 @@ fw3_parse_protocol(void *ptr, const char *val, bool is_list) { struct fw3_protocol proto = { }; struct protoent *ent; + char *e; if (*val == '!') { @@ -516,6 +523,7 @@ fw3_parse_protocol(void *ptr, const char *val, bool is_list) if (!strcmp(val, "all")) { proto.any = true; + put_value(ptr, &proto, sizeof(proto), is_list); return true; } else if (!strcmp(val, "icmpv6")) @@ -543,9 +551,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); @@ -555,33 +563,41 @@ fw3_parse_protocol(void *ptr, const char *val, bool is_list) bool fw3_parse_ipset_method(void *ptr, const char *val, bool is_list) { - return parse_enum(ptr, val, ipset_methods, + return parse_enum(ptr, val, &fw3_ipset_method_names[FW3_IPSET_METHOD_BITMAP], FW3_IPSET_METHOD_BITMAP, FW3_IPSET_METHOD_LIST); } bool fw3_parse_ipset_datatype(void *ptr, const char *val, bool is_list) { - struct fw3_ipset_datatype *type = ptr; + 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], + FW3_IPSET_TYPE_IP, FW3_IPSET_TYPE_SET)) + { + put_value(ptr, &type, sizeof(type), is_list); + return true; } - return parse_enum(&type->type, val, ipset_types, - FW3_IPSET_TYPE_IP, FW3_IPSET_TYPE_SET); + return false; } bool @@ -752,8 +768,102 @@ fw3_parse_reflection_source(void *ptr, const char *val, bool is_list) FW3_REFLECTION_INTERNAL, FW3_REFLECTION_EXTERNAL); } +bool +fw3_parse_mark(void *ptr, const char *val, bool is_list) +{ + uint32_t n; + char *s, *e; + struct fw3_mark *m = ptr; + + if (*val == '!') + { + m->invert = true; + while (isspace(*++val)); + } + + if ((s = strchr(val, '/')) != NULL) + *s++ = 0; + + n = strtoul(val, &e, 0); + + if (e == val || *e) + return false; + + m->mark = n; + m->mask = 0xFFFFFFFF; + + if (s) + { + n = strtoul(s, &e, 0); + + if (e == s || *e) + return false; + + m->mask = n; + } + + m->set = true; + 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; + } -void + 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; + + 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) { @@ -763,6 +873,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) { @@ -782,6 +893,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 { @@ -795,6 +907,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; } } @@ -810,7 +923,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 { @@ -821,6 +937,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; } } @@ -834,322 +951,139 @@ fw3_parse_options(void *s, const struct fw3_option *opts, if (!known) warn_elem(e, "is unknown"); } -} - -void -fw3_format_in_out(struct fw3_device *in, struct fw3_device *out) -{ - if (in && !in->any) - fw3_pr(" %s-i %s", in->invert ? "! " : "", in->name); - - if (out && !out->any) - fw3_pr(" %s-o %s", out->invert ? "! " : "", out->name); + return valid; } -void -fw3_format_src_dest(struct fw3_address *src, struct fw3_address *dest) -{ - char s[INET6_ADDRSTRLEN]; - if ((src && src->range) || (dest && dest->range)) - fw3_pr(" -m iprange"); +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; - if (src && src->set) + blobmsg_for_each_attr(o, a, rem) { - if (src->range) - { - inet_ntop(src->family == FW3_FAMILY_V4 ? AF_INET : AF_INET6, - &src->address.v4, s, sizeof(s)); + known = false; - fw3_pr(" %s--src-range %s", src->invert ? "! " : "", s); + for (opt = opts; opt->name; opt++) + { + if (!opt->parse) + continue; - inet_ntop(src->family == FW3_FAMILY_V4 ? AF_INET : AF_INET6, - &src->address2.v4, s, sizeof(s)); + if (strcmp(opt->name, blobmsg_name(o))) + continue; - fw3_pr("-%s", s); - } - else - { - inet_ntop(src->family == FW3_FAMILY_V4 ? AF_INET : AF_INET6, - &src->address.v4, s, sizeof(s)); + 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); - fw3_pr(" %s-s %s/%u", src->invert ? "! " : "", s, src->mask); - } - } + 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 (dest && dest->set) - { - if (dest->range) - { - inet_ntop(dest->family == FW3_FAMILY_V4 ? AF_INET : AF_INET6, - &dest->address.v4, s, sizeof(s)); + 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); + } - fw3_pr(" %s--dst-range %s", dest->invert ? "! " : "", s); + if (!v) + continue; - inet_ntop(dest->family == FW3_FAMILY_V4 ? AF_INET : AF_INET6, - &dest->address2.v4, s, sizeof(s)); + 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); - fw3_pr("-%s", s); - } - else - { - inet_ntop(dest->family == FW3_FAMILY_V4 ? AF_INET : AF_INET6, - &dest->address.v4, s, sizeof(s)); + 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; + } + } + } + } - fw3_pr(" %s-d %s/%u", dest->invert ? "! " : "", s, dest->mask); + known = true; + break; } - } -} -void -fw3_format_sport_dport(struct fw3_port *sp, struct fw3_port *dp) -{ - if (sp && sp->set) - { - if (sp->port_min == sp->port_max) - fw3_pr(" %s--sport %u", sp->invert ? "! " : "", sp->port_min); - else - fw3_pr(" %s--sport %u:%u", - sp->invert ? "! " : "", sp->port_min, sp->port_max); + if (!known) + fprintf(stderr, "%s is unknown\n", blobmsg_name(o)); } - if (dp && dp->set) - { - if (dp->port_min == dp->port_max) - fw3_pr(" %s--dport %u", dp->invert ? "! " : "", dp->port_min); - else - fw3_pr(" %s--dport %u:%u", - dp->invert ? "! " : "", dp->port_min, dp->port_max); - } + return valid; } -void -fw3_format_mac(struct fw3_mac *mac) -{ - if (!mac) - return; - fw3_pr(" -m mac %s--mac-source %s", - mac->invert ? "! " : "", ether_ntoa(&mac->mac)); -} - -void -fw3_format_protocol(struct fw3_protocol *proto, enum fw3_family family) +const char * +fw3_address_to_string(struct fw3_address *address, bool allow_invert) { - uint16_t pr; + char *p, ip[INET6_ADDRSTRLEN]; + static char buf[INET6_ADDRSTRLEN * 2 + 2]; - if (!proto) - return; + p = buf; - pr = proto->protocol; + if (address->invert && allow_invert) + p += sprintf(p, "!"); - if (pr == 1 && family == FW3_FAMILY_V6) - pr = 58; + inet_ntop(address->family == FW3_FAMILY_V4 ? AF_INET : AF_INET6, + &address->address.v4, ip, sizeof(ip)); - if (proto->any) - fw3_pr(" -p all"); - else - fw3_pr(" %s-p %u", proto->invert ? "! " : "", pr); -} + p += sprintf(p, "%s", ip); -void -fw3_format_icmptype(struct fw3_icmptype *icmp, enum fw3_family family) -{ - if (!icmp) - return; - - if (family != FW3_FAMILY_V6) + if (address->range) { - if (icmp->code_min == 0 && icmp->code_max == 0xFF) - fw3_pr(" %s--icmp-type %u", icmp->invert ? "! " : "", icmp->type); - else - fw3_pr(" %s--icmp-type %u/%u", - icmp->invert ? "! " : "", icmp->type, icmp->code_min); - } - else - { - if (icmp->code6_min == 0 && icmp->code6_max == 0xFF) - fw3_pr(" %s--icmpv6-type %u", icmp->invert ? "! " : "", icmp->type6); - else - fw3_pr(" %s--icmpv6-type %u/%u", - icmp->invert ? "! " : "", icmp->type6, icmp->code6_min); - } -} - -void -fw3_format_limit(struct fw3_limit *limit) -{ - if (!limit) - return; + inet_ntop(address->family == FW3_FAMILY_V4 ? AF_INET : AF_INET6, + &address->address2.v4, ip, sizeof(ip)); - if (limit->rate > 0) - { - fw3_pr(" -m limit %s--limit %u/%s", - limit->invert ? "! " : "", - limit->rate, limit_units[limit->unit]); - - if (limit->burst > 0) - fw3_pr(" --limit-burst %u", limit->burst); + p += sprintf(p, "-%s", ip); } -} - -void -fw3_format_ipset(struct fw3_ipset *ipset, bool invert) -{ - bool first = true; - const char *name = NULL; - struct fw3_ipset_datatype *type; - - if (!ipset) - return; - - if (ipset->external && *ipset->external) - name = ipset->external; else - name = ipset->name; - - fw3_pr(" -m set %s--match-set %s", invert ? "! " : "", name); - - list_for_each_entry(type, &ipset->datatypes, list) - { - fw3_pr("%c%s", first ? ' ' : ',', type->dest ? "dst" : "src"); - first = false; - } -} - -void -fw3_format_time(struct fw3_time *time) -{ - int i; - struct tm empty = { 0 }; - char buf[sizeof("9999-99-99T23:59:59\0")]; - bool d1 = memcmp(&time->datestart, &empty, sizeof(empty)); - bool d2 = memcmp(&time->datestop, &empty, sizeof(empty)); - bool first; - - if (!d1 && !d2 && !time->timestart && !time->timestop && - !(time->monthdays & 0xFFFFFFFE) && !(time->weekdays & 0xFE)) - { - return; - } - - fw3_pr(" -m time"); - - if (time->utc) - fw3_pr(" --utc"); - - if (d1) - { - strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S", &time->datestart); - fw3_pr(" --datestart %s", buf); - } - - if (d2) - { - strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S", &time->datestop); - fw3_pr(" --datestop %s", buf); - } - - if (time->timestart) { - fw3_pr(" --timestart %02d:%02d:%02d", - time->timestart / 3600, - time->timestart % 3600 / 60, - time->timestart % 60); - } - - if (time->timestop) - { - fw3_pr(" --timestop %02d:%02d:%02d", - time->timestop / 3600, - time->timestop % 3600 / 60, - time->timestop % 60); - } - - if (time->monthdays & 0xFFFFFFFE) - { - fw3_pr(" %s--monthdays", hasbit(time->monthdays, 0) ? "! " : ""); - - for (i = 1, first = true; i < 32; i++) - { - if (hasbit(time->monthdays, i)) - { - fw3_pr("%c%u", first ? ' ' : ',', i); - first = false; - } - } + p += sprintf(p, "/%u", address->mask); } - if (time->weekdays & 0xFE) - { - fw3_pr(" %s--weekdays", hasbit(time->weekdays, 0) ? "! " : ""); - - for (i = 1, first = true; i < 8; i++) - { - if (hasbit(time->weekdays, i)) - { - fw3_pr("%c%u", first ? ' ' : ',', i); - first = false; - } - } - } -} - -void -__fw3_format_comment(const char *comment, ...) -{ - va_list ap; - int len = 0; - const char *c; - - if (!comment || !*comment) - return; - - fw3_pr(" -m comment --comment \""); - - c = comment; - - va_start(ap, comment); - - do - { - while (*c) - { - switch (*c) - { - case '"': - case '$': - case '`': - case '\\': - fw3_pr("\\"); - /* fall through */ - - default: - fw3_pr("%c", *c); - break; - } - - c++; - - if (len++ >= 255) - goto end; - } - - c = va_arg(ap, const char *); - } - while (c); - -end: - va_end(ap); - fw3_pr("\""); -} - -void -fw3_format_extra(const char *extra) -{ - if (!extra || !*extra) - return; - - fw3_pr(" %s", extra); + return buf; }