X-Git-Url: http://git.archive.openwrt.org/?p=project%2Ffirewall3.git;a=blobdiff_plain;f=options.c;h=5a7a901a6433d47b032b9a7e01b0ba3900b2d947;hp=5d325fcbb49658c04c3188f64d162f509c3b2f70;hb=6e6a38ea87aebeaefe70869c226cadad0312f144;hpb=8fee8f9c520c58d07772cc6bd8f65d9eb1776a56 diff --git a/options.c b/options.c index 5d325fc..5a7a901 100644 --- a/options.c +++ b/options.c @@ -17,9 +17,119 @@ */ #include "options.h" +#include "ubus.h" + + +static bool +put_value(void *ptr, void *val, int elem_size, bool is_list) +{ + void *copy; + + if (is_list) + { + copy = malloc(elem_size); + + if (!copy) + return false; + + memcpy(copy, val, elem_size); + list_add_tail((struct list_head *)copy, (struct list_head *)ptr); + return true; + } + + memcpy(ptr, val, elem_size); + return false; +} + +static bool +parse_enum(void *ptr, const char *val, const char **values, int min, int max) +{ + int i, l = strlen(val); + + if (l > 0) + { + for (i = 0; i <= (max - min); i++) + { + if (!strncasecmp(val, values[i], l)) + { + *((int *)ptr) = min + i; + return true; + } + } + } + + return false; +} + + +const char *fw3_flag_names[__FW3_FLAG_MAX] = { + "filter", + "nat", + "mangle", + "raw", + + "IPv4", + "IPv6", + + "ACCEPT", + "REJECT", + "DROP", + "NOTRACK", + "MARK", + "DNAT", + "SNAT", + + "ACCEPT", + "REJECT", + "DROP", +}; + +const char *fw3_limit_units[__FW3_LIMIT_UNIT_MAX] = { + "second", + "minute", + "hour", + "day", +}; + +const char *fw3_ipset_method_names[__FW3_IPSET_METHOD_MAX] = { + "(bug)", + "bitmap", + "hash", + "list", +}; + +const char *fw3_ipset_type_names[__FW3_IPSET_TYPE_MAX] = { + "(bug)", + "ip", + "port", + "mac", + "net", + "set", +}; + +static const char *weekdays[] = { + "monday", + "tuesday", + "wednesday", + "thursday", + "friday", + "saturday", + "sunday", +}; + +static const char *include_types[] = { + "script", + "restore", +}; + +static const char *reflection_sources[] = { + "internal", + "external", +}; + bool -fw3_parse_bool(void *ptr, const char *val) +fw3_parse_bool(void *ptr, const char *val, bool is_list) { if (!strcmp(val, "true") || !strcmp(val, "yes") || !strcmp(val, "1")) *((bool *)ptr) = true; @@ -30,9 +140,9 @@ fw3_parse_bool(void *ptr, const char *val) } bool -fw3_parse_int(void *ptr, const char *val) +fw3_parse_int(void *ptr, const char *val, bool is_list) { - int n = strtol(val, NULL, 10); + int n = strtol(val, NULL, 0); if (errno == ERANGE || errno == EINVAL) return false; @@ -43,51 +153,21 @@ fw3_parse_int(void *ptr, const char *val) } bool -fw3_parse_string(void *ptr, const char *val) +fw3_parse_string(void *ptr, const char *val, bool is_list) { *((char **)ptr) = (char *)val; return true; } bool -fw3_parse_target(void *ptr, const char *val) +fw3_parse_target(void *ptr, const char *val, bool is_list) { - if (!strcmp(val, "ACCEPT")) - { - *((enum fw3_target *)ptr) = FW3_TARGET_ACCEPT; - return true; - } - else if (!strcmp(val, "REJECT")) - { - *((enum fw3_target *)ptr) = FW3_TARGET_REJECT; - return true; - } - else if (!strcmp(val, "DROP")) - { - *((enum fw3_target *)ptr) = FW3_TARGET_DROP; - return true; - } - else if (!strcmp(val, "NOTRACK")) - { - *((enum fw3_target *)ptr) = FW3_TARGET_NOTRACK; - return true; - } - else if (!strcmp(val, "DNAT")) - { - *((enum fw3_target *)ptr) = FW3_TARGET_DNAT; - return true; - } - else if (!strcmp(val, "SNAT")) - { - *((enum fw3_target *)ptr) = FW3_TARGET_SNAT; - return true; - } - - return false; + return parse_enum(ptr, val, &fw3_flag_names[FW3_FLAG_ACCEPT], + FW3_FLAG_ACCEPT, FW3_FLAG_SNAT); } bool -fw3_parse_limit(void *ptr, const char *val) +fw3_parse_limit(void *ptr, const char *val, bool is_list) { struct fw3_limit *limit = ptr; enum fw3_limit_unit u = FW3_LIMIT_UNIT_SECOND; @@ -111,15 +191,7 @@ fw3_parse_limit(void *ptr, const char *val) if (!strlen(e)) return false; - if (!strncmp(e, "second", strlen(e))) - u = FW3_LIMIT_UNIT_SECOND; - else if (!strncmp(e, "minute", strlen(e))) - u = FW3_LIMIT_UNIT_MINUTE; - else if (!strncmp(e, "hour", strlen(e))) - u = FW3_LIMIT_UNIT_HOUR; - else if (!strncmp(e, "day", strlen(e))) - u = FW3_LIMIT_UNIT_DAY; - else + if (!parse_enum(&u, e, fw3_limit_units, 0, FW3_LIMIT_UNIT_DAY)) return false; limit->rate = n; @@ -129,36 +201,45 @@ fw3_parse_limit(void *ptr, const char *val) } bool -fw3_parse_device(void *ptr, const char *val) +fw3_parse_device(void *ptr, const char *val, bool is_list) { - struct fw3_device *dev = ptr; + char *p; + struct fw3_device dev = { }; if (*val == '*') { - dev->set = true; - dev->any = true; + dev.set = true; + dev.any = true; + put_value(ptr, &dev, sizeof(dev), is_list); return true; } if (*val == '!') { - dev->invert = true; + dev.invert = true; 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); + snprintf(dev.name, sizeof(dev.name), "%s", val); else return false; - dev->set = true; + dev.set = true; + put_value(ptr, &dev, sizeof(dev), is_list); return true; } bool -fw3_parse_address(void *ptr, const char *val) +fw3_parse_address(void *ptr, const char *val, bool is_list) { - struct fw3_address *addr = ptr; + struct fw3_address addr = { }; struct in_addr v4; struct in6_addr v6; char *p, *s, *e; @@ -166,7 +247,7 @@ fw3_parse_address(void *ptr, const char *val) if (*val == '!') { - addr->invert = true; + addr.invert = true; while (isspace(*++val)); } @@ -195,18 +276,40 @@ fw3_parse_address(void *ptr, const char *val) } } } + 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; + } + else if (inet_pton(AF_INET, p, &v4)) + { + addr.family = FW3_FAMILY_V4; + addr.address2.v4 = v4; + addr.range = true; + } + else + { + free(s); + return false; + } + } if (inet_pton(AF_INET6, s, &v6)) { - addr->family = FW3_FAMILY_V6; - addr->address.v6 = v6; - addr->mask = (m >= 0) ? m : 128; + 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; + addr.family = FW3_FAMILY_V4; + addr.address.v4 = v4; + addr.mask = (m >= 0) ? m : 32; } else { @@ -215,26 +318,61 @@ fw3_parse_address(void *ptr, const char *val) } free(s); - addr->set = true; + addr.set = true; + put_value(ptr, &addr, sizeof(addr), is_list); return true; } bool -fw3_parse_mac(void *ptr, const char *val) +fw3_parse_network(void *ptr, const char *val, bool is_list) { - struct fw3_mac *addr = ptr; + struct fw3_device dev = { }; + struct fw3_address *addr; + struct 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) + { + list_for_each_entry(addr, addr_list, list) + { + addr->invert = dev.invert; + addr->resolved = true; + + if (!put_value(ptr, addr, sizeof(*addr), is_list)) + break; + } + + fw3_free_list(addr_list); + } + } + + return true; +} + +bool +fw3_parse_mac(void *ptr, const char *val, bool is_list) +{ + struct fw3_mac addr = { }; struct ether_addr *mac; if (*val == '!') { - addr->invert = true; + addr.invert = true; while (isspace(*++val)); } if ((mac = ether_aton(val)) != NULL) { - addr->mac = *mac; - addr->set = true; + addr.mac = *mac; + addr.set = true; + + put_value(ptr, &addr, sizeof(addr), is_list); return true; } @@ -242,16 +380,16 @@ fw3_parse_mac(void *ptr, const char *val) } bool -fw3_parse_port(void *ptr, const char *val) +fw3_parse_port(void *ptr, const char *val, bool is_list) { - struct fw3_port *range = ptr; + struct fw3_port range = { }; uint16_t n; uint16_t m; char *p; if (*val == '!') { - range->invert = true; + range.invert = true; while (isspace(*++val)); } @@ -270,21 +408,22 @@ fw3_parse_port(void *ptr, const char *val) if (errno == ERANGE || errno == EINVAL || m < n) return false; - range->port_min = n; - range->port_max = m; + range.port_min = n; + range.port_max = m; } else { - range->port_min = n; - range->port_max = n; + range.port_min = n; + range.port_max = n; } - range->set = true; + range.set = true; + put_value(ptr, &range, sizeof(range), is_list); return true; } bool -fw3_parse_family(void *ptr, const char *val) +fw3_parse_family(void *ptr, const char *val, bool is_list) { if (!strcmp(val, "any")) *((enum fw3_family *)ptr) = FW3_FAMILY_ANY; @@ -299,9 +438,9 @@ fw3_parse_family(void *ptr, const char *val) } bool -fw3_parse_icmptype(void *ptr, const char *val) +fw3_parse_icmptype(void *ptr, const char *val, bool is_list) { - struct fw3_icmptype *icmp = ptr; + struct fw3_icmptype icmp = { }; bool v4 = false; bool v6 = false; char *p; @@ -311,9 +450,9 @@ fw3_parse_icmptype(void *ptr, const char *val) { if (!strcmp(val, fw3_icmptype_list_v4[i].name)) { - icmp->type = fw3_icmptype_list_v4[i].type; - icmp->code_min = fw3_icmptype_list_v4[i].code_min; - icmp->code_max = fw3_icmptype_list_v4[i].code_max; + icmp.type = fw3_icmptype_list_v4[i].type; + icmp.code_min = fw3_icmptype_list_v4[i].code_min; + icmp.code_max = fw3_icmptype_list_v4[i].code_max; v4 = true; break; @@ -324,9 +463,9 @@ fw3_parse_icmptype(void *ptr, const char *val) { if (!strcmp(val, fw3_icmptype_list_v6[i].name)) { - icmp->type6 = fw3_icmptype_list_v6[i].type; - icmp->code6_min = fw3_icmptype_list_v6[i].code_min; - icmp->code6_max = fw3_icmptype_list_v6[i].code_max; + icmp.type6 = fw3_icmptype_list_v6[i].type; + icmp.code6_min = fw3_icmptype_list_v6[i].code_min; + icmp.code6_max = fw3_icmptype_list_v6[i].code_max; v6 = true; break; @@ -340,7 +479,7 @@ fw3_parse_icmptype(void *ptr, const char *val) if ((p == val) || (*p != '/' && *p != 0) || (i > 0xFF)) return false; - icmp->type = i; + icmp.type = i; if (*p == '/') { @@ -350,79 +489,116 @@ fw3_parse_icmptype(void *ptr, const char *val) if ((p == val) || (*p != 0) || (i > 0xFF)) return false; - icmp->code_min = i; - icmp->code_max = i; + icmp.code_min = i; + icmp.code_max = i; } else { - icmp->code_min = 0; - icmp->code_max = 0xFF; + icmp.code_min = 0; + icmp.code_max = 0xFF; } - icmp->type6 = icmp->type; - icmp->code6_min = icmp->code_max; - icmp->code6_max = icmp->code_max; + icmp.type6 = icmp.type; + icmp.code6_min = icmp.code_max; + icmp.code6_max = icmp.code_max; v4 = true; v6 = true; } - icmp->family = (v4 && v6) ? FW3_FAMILY_ANY - : (v6 ? FW3_FAMILY_V6 : FW3_FAMILY_V4); + icmp.family = (v4 && v6) ? FW3_FAMILY_ANY + : (v6 ? FW3_FAMILY_V6 : FW3_FAMILY_V4); + put_value(ptr, &icmp, sizeof(icmp), is_list); return true; } bool -fw3_parse_protocol(void *ptr, const char *val) +fw3_parse_protocol(void *ptr, const char *val, bool is_list) { - struct fw3_protocol *proto = ptr; + struct fw3_protocol proto = { }; struct protoent *ent; if (*val == '!') { - proto->invert = true; + proto.invert = true; while (isspace(*++val)); } if (!strcmp(val, "all")) { - proto->any = true; + proto.any = true; + put_value(ptr, &proto, sizeof(proto), is_list); return true; } else if (!strcmp(val, "icmpv6")) { val = "ipv6-icmp"; } + else if (!strcmp(val, "tcpudp")) + { + proto.protocol = 6; + if (put_value(ptr, &proto, sizeof(proto), is_list)) + { + proto.protocol = 17; + put_value(ptr, &proto, sizeof(proto), is_list); + } + + return true; + } ent = getprotobyname(val); if (ent) { - proto->protocol = ent->p_proto; + proto.protocol = ent->p_proto; + put_value(ptr, &proto, sizeof(proto), is_list); return true; } - proto->protocol = strtoul(val, NULL, 10); - return (errno != ERANGE && errno != EINVAL); + proto.protocol = strtoul(val, NULL, 10); + + if (errno == ERANGE || errno == EINVAL) + return false; + + put_value(ptr, &proto, sizeof(proto), is_list); + return true; +} + +bool +fw3_parse_ipset_method(void *ptr, const char *val, bool is_list) +{ + 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_method(void *ptr, const char *val) +fw3_parse_ipset_datatype(void *ptr, const char *val, bool is_list) { - if (!strncmp(val, "bitmap", strlen(val))) + struct fw3_ipset_datatype type = { }; + + type.dir = "src"; + + if (!strncmp(val, "dest_", 5)) { - *((enum fw3_ipset_method *)ptr) = FW3_IPSET_METHOD_BITMAP; - return true; + val += 5; + type.dir = "dst"; } - else if (!strncmp(val, "hash", strlen(val))) + else if (!strncmp(val, "dst_", 4)) { - *((enum fw3_ipset_method *)ptr) = FW3_IPSET_METHOD_HASH; - return true; + val += 4; + type.dir = "dst"; } - else if (!strncmp(val, "list", strlen(val))) + else if (!strncmp(val, "src_", 4)) + { + val += 4; + 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)) { - *((enum fw3_ipset_method *)ptr) = FW3_IPSET_METHOD_LIST; + put_value(ptr, &type, sizeof(type), is_list); return true; } @@ -430,68 +606,261 @@ fw3_parse_ipset_method(void *ptr, const char *val) } bool -fw3_parse_ipset_datatype(void *ptr, const char *val) +fw3_parse_date(void *ptr, const char *val, bool is_list) { - struct fw3_ipset_datatype *type = ptr; + unsigned int year = 1970, mon = 1, day = 1, hour = 0, min = 0, sec = 0; + struct tm tm = { 0 }; + char *p; - if (!strncmp(val, "dest_", 5)) + year = strtoul(val, &p, 10); + if ((*p != '-' && *p) || year < 1970 || year > 2038) + goto fail; + else if (!*p) + goto ret; + + mon = strtoul(++p, &p, 10); + if ((*p != '-' && *p) || mon > 12) + goto fail; + else if (!*p) + goto ret; + + day = strtoul(++p, &p, 10); + if ((*p != 'T' && *p) || day > 31) + goto fail; + else if (!*p) + goto ret; + + hour = strtoul(++p, &p, 10); + if ((*p != ':' && *p) || hour > 23) + goto fail; + else if (!*p) + goto ret; + + min = strtoul(++p, &p, 10); + if ((*p != ':' && *p) || min > 59) + goto fail; + else if (!*p) + goto ret; + + sec = strtoul(++p, &p, 10); + if (*p || sec > 59) + goto fail; + +ret: + tm.tm_year = year - 1900; + tm.tm_mon = mon - 1; + tm.tm_mday = day; + tm.tm_hour = hour; + tm.tm_min = min; + tm.tm_sec = sec; + + if (mktime(&tm) >= 0) + { + *((struct tm *)ptr) = tm; + return true; + } + +fail: + return false; +} + +bool +fw3_parse_time(void *ptr, const char *val, bool is_list) +{ + unsigned int hour = 0, min = 0, sec = 0; + char *p; + + hour = strtoul(val, &p, 10); + if (*p != ':' || hour > 23) + goto fail; + + min = strtoul(++p, &p, 10); + if ((*p != ':' && *p) || min > 59) + goto fail; + else if (!*p) + goto ret; + + sec = strtoul(++p, &p, 10); + if (*p || sec > 59) + goto fail; + +ret: + *((int *)ptr) = 60 * 60 * hour + 60 * min + sec; + return true; + +fail: + return false; +} + +bool +fw3_parse_weekdays(void *ptr, const char *val, bool is_list) +{ + unsigned int w = 0; + char *p, *s; + + if (*val == '!') { - val += 5; - type->dest = true; + setbit(*(uint8_t *)ptr, 0); + while (isspace(*++val)); } - else if (!strncmp(val, "dst_", 4)) + + if (!(s = strdup(val))) + return false; + + for (p = strtok(s, " \t"); p; p = strtok(NULL, " \t")) { - val += 4; - type->dest = true; + if (!parse_enum(&w, p, weekdays, 1, 7)) + { + w = strtoul(p, &p, 10); + + if (*p || w < 1 || w > 7) + { + free(s); + return false; + } + } + + setbit(*(uint8_t *)ptr, w); } - else if (!strncmp(val, "src_", 4)) + + free(s); + return true; +} + +bool +fw3_parse_monthdays(void *ptr, const char *val, bool is_list) +{ + unsigned int d; + char *p, *s; + + if (*val == '!') { - val += 4; - type->dest = false; + setbit(*(uint32_t *)ptr, 0); + while (isspace(*++val)); } - if (!strncmp(val, "ip", strlen(val))) + if (!(s = strdup(val))) + return false; + + for (p = strtok(s, " \t"); p; p = strtok(NULL, " \t")) { - type->type = FW3_IPSET_TYPE_IP; - return true; + d = strtoul(p, &p, 10); + + if (*p || d < 1 || d > 31) + { + free(s); + return false; + } + + setbit(*(uint32_t *)ptr, d); } - else if (!strncmp(val, "port", strlen(val))) + + free(s); + return true; +} + +bool +fw3_parse_include_type(void *ptr, const char *val, bool is_list) +{ + return parse_enum(ptr, val, include_types, + FW3_INC_TYPE_SCRIPT, FW3_INC_TYPE_RESTORE); +} + +bool +fw3_parse_reflection_source(void *ptr, const char *val, bool is_list) +{ + return parse_enum(ptr, val, reflection_sources, + 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 == '!') { - type->type = FW3_IPSET_TYPE_PORT; - return true; + m->invert = true; + while (isspace(*++val)); } - else if (!strncmp(val, "mac", strlen(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) { - type->type = FW3_IPSET_TYPE_MAC; - return true; + n = strtoul(s, &e, 0); + + if (e == s || *e) + return false; + + m->mask = n; } - else if (!strncmp(val, "net", strlen(val))) + + 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 == '!') { - type->type = FW3_IPSET_TYPE_NET; - return true; + m->invert = true; + while (isspace(*++val)); + } + + if (!(s = strdup(val))) + return false; + + if (!(p = strtok(s, " \t"))) + { + free(s); + return false; } - else if (!strncmp(val, "set", strlen(val))) + + strncpy(m->name, p, sizeof(m->name)); + + for (i = 0, p = strtok(NULL, " \t,"); + i < 3 && p != NULL; + i++, p = strtok(NULL, " \t,")) { - type->type = FW3_IPSET_TYPE_SET; - return true; + if (!strncmp(p, "dest", 4) || !strncmp(p, "dst", 3)) + m->dir[i] = "dst"; + else if (!strncmp(p, "src", 3)) + m->dir[i] = "src"; } - return false; + free(s); + + m->set = true; + return true; } void -fw3_parse_options(void *s, - struct fw3_option *opts, int n, +fw3_parse_options(void *s, const struct fw3_option *opts, struct uci_section *section) { - int i; - char *p; + char *p, *v; bool known; struct uci_element *e, *l; struct uci_option *o; - struct fw3_option *opt; - struct list_head *item; + const struct fw3_option *opt; struct list_head *dest; uci_foreach_element(§ion->options, e) @@ -499,11 +868,9 @@ fw3_parse_options(void *s, o = uci_to_option(e); known = false; - for (i = 0; i < n; i++) + for (opt = opts; opt->name; opt++) { - opt = &opts[i]; - - if (!opt->parse || !opt->name) + if (!opt->parse) continue; if (strcmp(opt->name, e->name)) @@ -517,62 +884,44 @@ fw3_parse_options(void *s, } else { + dest = (struct list_head *)((char *)s + opt->offset); + uci_foreach_element(&o->v.list, l) { if (!l->name) continue; - item = malloc(opt->elem_size); - - if (!item) - continue; - - memset(item, 0, opt->elem_size); - - if (!opt->parse(item, l->name)) + if (!opt->parse(dest, l->name, true)) { warn_elem(e, "has invalid value '%s'", l->name); - free(item); continue; } - - dest = (struct list_head *)((char *)s + opt->offset); - list_add_tail(item, dest); } } } else { - if (!o->v.string) + v = o->v.string; + + if (!v) continue; if (!opt->elem_size) { - if (!opt->parse((char *)s + opt->offset, o->v.string)) + if (!opt->parse((char *)s + opt->offset, o->v.string, false)) warn_elem(e, "has invalid value '%s'", o->v.string); } else { - for (p = strtok(o->v.string, " \t"); - p != NULL; - p = strtok(NULL, " \t")) - { - item = malloc(opt->elem_size); - - if (!item) - continue; + dest = (struct list_head *)((char *)s + opt->offset); - memset(item, 0, opt->elem_size); - - if (!opt->parse(item, p)) + for (p = strtok(v, " \t"); p != NULL; p = strtok(NULL, " \t")) + { + if (!opt->parse(dest, p, true)) { warn_elem(e, "has invalid value '%s'", p); - free(item); continue; } - - dest = (struct list_head *)((char *)s + opt->offset); - list_add_tail(item, dest); } } } @@ -587,214 +936,33 @@ fw3_parse_options(void *s, } -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); -} - -void -fw3_format_src_dest(struct fw3_address *src, struct fw3_address *dest) -{ - char s[INET6_ADDRSTRLEN]; - - if (src && src->set) - { - inet_ntop(src->family == FW3_FAMILY_V4 ? AF_INET : AF_INET6, - &src->address.v4, s, sizeof(s)); - - fw3_pr(" %s-s %s/%u", src->invert ? "! " : "", s, src->mask); - } - - if (dest && dest->set) - { - inet_ntop(dest->family == FW3_FAMILY_V4 ? AF_INET : AF_INET6, - &dest->address.v4, s, sizeof(s)); - - fw3_pr(" %s-d %s/%u", dest->invert ? "! " : "", s, dest->mask); - } -} - -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 (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); - } -} - -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); -} - -void -fw3_format_icmptype(struct fw3_icmptype *icmp, enum fw3_family family) -{ - if (!icmp) - return; + p += sprintf(p, "%s", ip); - if (family != FW3_FAMILY_V6) - { - 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 (address->range) { - 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; - - const char *units[] = { - [FW3_LIMIT_UNIT_SECOND] = "second", - [FW3_LIMIT_UNIT_MINUTE] = "minute", - [FW3_LIMIT_UNIT_HOUR] = "hour", - [FW3_LIMIT_UNIT_DAY] = "day", - }; + 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, 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_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 *); + p += sprintf(p, "/%u", address->mask); } - 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; }