X-Git-Url: http://git.archive.openwrt.org/?p=project%2Ffirewall3.git;a=blobdiff_plain;f=ipsets.c;h=d6ff9bd272a7dc3d5b96773be473a34e9664cd1a;hp=5e0d61f9c3f956c23c542b533fdda8884e31b70f;hb=54c0625e83a5ddf77e1753885c96f488ba38f78a;hpb=bb6873d86322a66bc01fc4195512ba5d2c78bddb diff --git a/ipsets.c b/ipsets.c index 5e0d61f..d6ff9bd 100644 --- a/ipsets.c +++ b/ipsets.c @@ -19,14 +19,16 @@ #include "ipsets.h" -static struct fw3_option ipset_opts[] = { +const struct fw3_option fw3_ipset_opts[] = { + FW3_OPT("enabled", bool, ipset, enabled), + FW3_OPT("name", string, ipset, name), FW3_OPT("family", family, ipset, family), FW3_OPT("storage", ipset_method, ipset, method), FW3_LIST("match", ipset_datatype, ipset, datatypes), - FW3_LIST("iprange", address, ipset, iprange), + FW3_OPT("iprange", address, ipset, iprange), FW3_OPT("portrange", port, ipset, portrange), FW3_OPT("netmask", int, ipset, netmask), @@ -35,6 +37,8 @@ static struct fw3_option ipset_opts[] = { FW3_OPT("timeout", int, ipset, timeout), FW3_OPT("external", string, ipset, external), + + { } }; #define T(m, t1, t2, t3, r, o) \ @@ -42,27 +46,41 @@ static struct fw3_option ipset_opts[] = { FW3_IPSET_TYPE_##t1 | (FW3_IPSET_TYPE_##t2 << 8) | (FW3_IPSET_TYPE_##t3 << 16), \ r, o } -static struct fw3_ipset_settype ipset_types[] = { - T(BITMAP, IP, UNSPEC, UNSPEC, FW3_IPSET_OPT_IPRANGE, - FW3_IPSET_OPT_NETMASK), - T(BITMAP, IP, MAC, UNSPEC, FW3_IPSET_OPT_IPRANGE, 0), - T(BITMAP, PORT, UNSPEC, UNSPEC, FW3_IPSET_OPT_PORTRANGE, 0), +enum ipset_optflag { + OPT_IPRANGE = (1 << 0), + OPT_PORTRANGE = (1 << 1), + OPT_NETMASK = (1 << 2), + OPT_HASHSIZE = (1 << 3), + OPT_MAXELEM = (1 << 4), + OPT_FAMILY = (1 << 5), +}; + +struct ipset_type { + enum fw3_ipset_method method; + uint32_t types; + uint8_t required; + uint8_t optional; +}; + +static struct ipset_type ipset_types[] = { + T(BITMAP, IP, UNSPEC, UNSPEC, OPT_IPRANGE, OPT_NETMASK), + T(BITMAP, IP, MAC, UNSPEC, OPT_IPRANGE, 0), + T(BITMAP, PORT, UNSPEC, UNSPEC, OPT_PORTRANGE, 0), T(HASH, IP, UNSPEC, UNSPEC, 0, - FW3_IPSET_OPT_FAMILY | FW3_IPSET_OPT_HASHSIZE | FW3_IPSET_OPT_MAXELEM | - FW3_IPSET_OPT_NETMASK), + OPT_FAMILY | OPT_HASHSIZE | OPT_MAXELEM | OPT_NETMASK), T(HASH, NET, UNSPEC, UNSPEC, 0, - FW3_IPSET_OPT_FAMILY | FW3_IPSET_OPT_HASHSIZE | FW3_IPSET_OPT_MAXELEM), + OPT_FAMILY | OPT_HASHSIZE | OPT_MAXELEM), T(HASH, IP, PORT, UNSPEC, 0, - FW3_IPSET_OPT_FAMILY | FW3_IPSET_OPT_HASHSIZE | FW3_IPSET_OPT_MAXELEM), + OPT_FAMILY | OPT_HASHSIZE | OPT_MAXELEM), T(HASH, NET, PORT, UNSPEC, 0, - FW3_IPSET_OPT_FAMILY | FW3_IPSET_OPT_HASHSIZE | FW3_IPSET_OPT_MAXELEM), + OPT_FAMILY | OPT_HASHSIZE | OPT_MAXELEM), T(HASH, IP, PORT, IP, 0, - FW3_IPSET_OPT_FAMILY | FW3_IPSET_OPT_HASHSIZE | FW3_IPSET_OPT_MAXELEM), + OPT_FAMILY | OPT_HASHSIZE | OPT_MAXELEM), T(HASH, IP, PORT, NET, 0, - FW3_IPSET_OPT_FAMILY | FW3_IPSET_OPT_HASHSIZE | FW3_IPSET_OPT_MAXELEM), + OPT_FAMILY | OPT_HASHSIZE | OPT_MAXELEM), - T(LIST, SET, UNSPEC, UNSPEC, 0, FW3_IPSET_OPT_MAXELEM), + T(LIST, SET, UNSPEC, UNSPEC, 0, OPT_MAXELEM), }; @@ -119,56 +137,56 @@ check_types(struct uci_element *e, struct fw3_ipset *ipset) { if (!ipset->external || !*ipset->external) { - if ((ipset_types[i].required & FW3_IPSET_OPT_IPRANGE) && - list_empty(&ipset->iprange)) + if ((ipset_types[i].required & OPT_IPRANGE) && + !ipset->iprange.set) { warn_elem(e, "requires an ip range"); return false; } - if ((ipset_types[i].required & FW3_IPSET_OPT_PORTRANGE) && + if ((ipset_types[i].required & OPT_PORTRANGE) && !ipset->portrange.set) { warn_elem(e, "requires a port range"); return false; } - if (!(ipset_types[i].required & FW3_IPSET_OPT_IPRANGE) && - !list_empty(&ipset->iprange)) + if (!(ipset_types[i].required & OPT_IPRANGE) && + ipset->iprange.set) { warn_elem(e, "iprange ignored"); - fw3_free_list(&ipset->iprange); + ipset->iprange.set = false; } - if (!(ipset_types[i].required & FW3_IPSET_OPT_PORTRANGE) && + if (!(ipset_types[i].required & OPT_PORTRANGE) && ipset->portrange.set) { warn_elem(e, "portrange ignored"); - memset(&ipset->portrange, 0, sizeof(ipset->portrange)); + ipset->portrange.set = false; } - if (!(ipset_types[i].optional & FW3_IPSET_OPT_NETMASK) && + if (!(ipset_types[i].optional & OPT_NETMASK) && ipset->netmask > 0) { warn_elem(e, "netmask ignored"); ipset->netmask = 0; } - if (!(ipset_types[i].optional & FW3_IPSET_OPT_HASHSIZE) && + if (!(ipset_types[i].optional & OPT_HASHSIZE) && ipset->hashsize > 0) { warn_elem(e, "hashsize ignored"); ipset->hashsize = 0; } - if (!(ipset_types[i].optional & FW3_IPSET_OPT_MAXELEM) && + if (!(ipset_types[i].optional & OPT_MAXELEM) && ipset->maxelem > 0) { warn_elem(e, "maxelem ignored"); ipset->maxelem = 0; } - if (!(ipset_types[i].optional & FW3_IPSET_OPT_FAMILY) && + if (!(ipset_types[i].optional & OPT_FAMILY) && ipset->family != FW3_FAMILY_ANY) { warn_elem(e, "family ignored"); @@ -184,6 +202,23 @@ check_types(struct uci_element *e, struct fw3_ipset *ipset) return false; } +struct fw3_ipset * +fw3_alloc_ipset(void) +{ + struct fw3_ipset *ipset; + + ipset = malloc(sizeof(*ipset)); + + if (!ipset) + return NULL; + + memset(ipset, 0, sizeof(*ipset)); + + INIT_LIST_HEAD(&ipset->datatypes); + + return ipset; +} + void fw3_load_ipsets(struct fw3_state *state, struct uci_package *p) { @@ -203,17 +238,12 @@ fw3_load_ipsets(struct fw3_state *state, struct uci_package *p) if (strcmp(s->type, "ipset")) continue; - ipset = malloc(sizeof(*ipset)); + ipset = fw3_alloc_ipset(); if (!ipset) continue; - memset(ipset, 0, sizeof(*ipset)); - - INIT_LIST_HEAD(&ipset->datatypes); - INIT_LIST_HEAD(&ipset->iprange); - - fw3_parse_options(ipset, ipset_opts, ARRAY_SIZE(ipset_opts), s); + fw3_parse_options(ipset, fw3_ipset_opts, s); if (!ipset->name || !*ipset->name) { @@ -239,13 +269,13 @@ fw3_load_ipsets(struct fw3_state *state, struct uci_package *p) static void -create_ipset(struct fw3_ipset *ipset) +create_ipset(struct fw3_ipset *ipset, struct fw3_state *state) { bool first = true; char s[INET6_ADDRSTRLEN]; struct fw3_ipset_datatype *type; - struct fw3_address *a1, *a2; + struct fw3_address *a; const char *methods[] = { "(bug)", @@ -277,29 +307,26 @@ create_ipset(struct fw3_ipset *ipset) first = false; } - if (!list_empty(&ipset->iprange)) + if (ipset->iprange.set) { - a1 = list_first_entry(&ipset->iprange, struct fw3_address, list); - a2 = list_last_entry(&ipset->iprange, struct fw3_address, list); + a = &ipset->iprange; - if (a1 == a2) + if (!a->range) { - inet_ntop(a1->family == FW3_FAMILY_V4 ? AF_INET : AF_INET6, - &a1->address.v6, s, sizeof(s)); + inet_ntop(a->family == FW3_FAMILY_V4 ? AF_INET : AF_INET6, + &a->address.v6, s, sizeof(s)); - fw3_pr(" range %s/%u", s, a1->mask); + fw3_pr(" range %s/%u", s, a->mask); } - else if (a1->family == a2->family && - fw3_is_family(ipset, a1->family) && - fw3_is_family(ipset, a2->family)) + else { - inet_ntop(a1->family == FW3_FAMILY_V4 ? AF_INET : AF_INET6, - &a1->address.v6, s, sizeof(s)); + inet_ntop(a->family == FW3_FAMILY_V4 ? AF_INET : AF_INET6, + &a->address.v6, s, sizeof(s)); fw3_pr(" range %s", s); - inet_ntop(a2->family == FW3_FAMILY_V4 ? AF_INET : AF_INET6, - &a2->address.v6, s, sizeof(s)); + inet_ntop(a->family == FW3_FAMILY_V4 ? AF_INET : AF_INET6, + &a->address2.v6, s, sizeof(s)); fw3_pr("-%s", s); } @@ -326,31 +353,12 @@ create_ipset(struct fw3_ipset *ipset) fw3_pr(" hashsize %u", ipset->hashsize); fw3_pr("\n"); -} - -static bool -ipset_loaded(struct list_head *statefile, const char *name) -{ - struct fw3_statefile_entry *e; - int mask = (1 << FW3_FAMILY_V4) | (1 << FW3_FAMILY_V6); - - if (!statefile) - return false; - - list_for_each_entry(e, statefile, list) - { - if (e->type != FW3_TYPE_IPSET) - continue; - - if (!strcmp(e->name, name) && (e->flags[0] & mask)) - return true; - } - return false; + fw3_set_running(ipset, &state->running_ipsets); } void -fw3_create_ipsets(struct fw3_state *state, struct list_head *statefile) +fw3_create_ipsets(struct fw3_state *state) { struct fw3_ipset *ipset; @@ -358,66 +366,53 @@ fw3_create_ipsets(struct fw3_state *state, struct list_head *statefile) return; list_for_each_entry(ipset, &state->ipsets, list) - if (!ipset_loaded(statefile, ipset->name)) - create_ipset(ipset); + if (!fw3_lookup_ipset(state, ipset->name, true)) + create_ipset(ipset, state); fw3_pr("quit\n"); } void -fw3_destroy_ipsets(struct fw3_state *state, struct list_head *statefile) +fw3_destroy_ipsets(struct fw3_state *state, enum fw3_family family) { - struct fw3_ipset *s; - struct fw3_statefile_entry *e; - int mask = (1 << FW3_FAMILY_V4) | (1 << FW3_FAMILY_V6); + struct fw3_ipset *s, *tmp; + uint32_t family_mask = (1 << FW3_FAMILY_V4) | (1 << FW3_FAMILY_V6); - if (!statefile) - return; - - list_for_each_entry(e, statefile, list) + list_for_each_entry_safe(s, tmp, &state->running_ipsets, running_list) { - if (e->type != FW3_TYPE_IPSET) - continue; - - if (!hasbit(state->defaults.flags, FW3_FAMILY_V4)) - delbit(e->flags[0], FW3_FAMILY_V4); + if (hasbit(s->running_flags, family)) + delbit(s->flags, family); - if (!hasbit(state->defaults.flags, FW3_FAMILY_V6)) - delbit(e->flags[0], FW3_FAMILY_V6); - - if ((s = fw3_lookup_ipset(state, e->name)) != NULL) - s->flags = e->flags[0]; - - if (!(e->flags[0] & mask)) + if (!(s->flags & family_mask)) { - info("Deleting ipset %s", e->name); + info("Deleting ipset %s", s->name); + + fw3_pr("flush %s\n", s->name); + fw3_pr("destroy %s\n", s->name); - fw3_pr("flush %s\n", e->name); - fw3_pr("destroy %s\n", e->name); + fw3_set_running(s, NULL); } } } -void -fw3_free_ipset(struct fw3_ipset *ipset) -{ - fw3_free_list(&ipset->datatypes); - fw3_free_list(&ipset->iprange); - - free(ipset); -} - struct fw3_ipset * -fw3_lookup_ipset(struct fw3_state *state, const char *name) +fw3_lookup_ipset(struct fw3_state *state, const char *name, bool running) { - struct fw3_ipset *ipset; + struct fw3_ipset *s; if (list_empty(&state->ipsets)) return NULL; - list_for_each_entry(ipset, &state->ipsets, list) - if (!strcmp(ipset->name, name)) - return ipset; + list_for_each_entry(s, &state->ipsets, list) + { + if (strcmp(s->name, name)) + continue; + + if (!running || s->running_list.next) + return s; + + break; + } return NULL; }