X-Git-Url: http://git.archive.openwrt.org/?p=project%2Ffirewall3.git;a=blobdiff_plain;f=ipsets.c;h=03259444b564c30e582189836d1fe1e36154bbb5;hp=713b34378dd0551c2a1860c120f10438610bd1cb;hb=47b23946cb2d51c486cd01596744955f850e2060;hpb=9ce8ca5ec9d28f6e5449c6ce138648cbaf99b438;ds=sidebyside diff --git a/ipsets.c b/ipsets.c index 713b343..0325944 100644 --- a/ipsets.c +++ b/ipsets.c @@ -1,7 +1,7 @@ /* * firewall3 - 3rd OpenWrt UCI firewall implementation * - * Copyright (C) 2013 Jo-Philipp Wich + * Copyright (C) 2013 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 @@ -107,6 +107,11 @@ check_types(struct uci_element *e, struct fw3_ipset *ipset) { for (i = 0; i < ARRAY_SIZE(ipset_types); i++) { + /* skip type for v6 if it does not support family */ + if (ipset->family != FW3_FAMILY_V4 && + !(ipset_types[i].optional & OPT_FAMILY)) + continue; + if (ipset_types[i].types == typelist) { ipset->method = ipset_types[i].method; @@ -126,7 +131,7 @@ check_types(struct uci_element *e, struct fw3_ipset *ipset) if (ipset_types[i].method == ipset->method && ipset_types[i].types == typelist) { - if (!ipset->external || !*ipset->external) + if (!ipset->external) { if ((ipset_types[i].required & OPT_IPRANGE) && !ipset->iprange.set) @@ -178,10 +183,10 @@ check_types(struct uci_element *e, struct fw3_ipset *ipset) } if (!(ipset_types[i].optional & OPT_FAMILY) && - ipset->family != FW3_FAMILY_ANY) + ipset->family != FW3_FAMILY_V4) { warn_elem(e, "family ignored"); - ipset->family = FW3_FAMILY_ANY; + ipset->family = FW3_FAMILY_V4; } } @@ -198,16 +203,14 @@ fw3_alloc_ipset(void) { struct fw3_ipset *ipset; - ipset = malloc(sizeof(*ipset)); - + ipset = calloc(1, sizeof(*ipset)); if (!ipset) return NULL; - memset(ipset, 0, sizeof(*ipset)); - INIT_LIST_HEAD(&ipset->datatypes); ipset->enabled = true; + ipset->family = FW3_FAMILY_V4; return ipset; } @@ -238,6 +241,14 @@ fw3_load_ipsets(struct fw3_state *state, struct uci_package *p) fw3_parse_options(ipset, fw3_ipset_opts, s); + if (ipset->external) + { + if (!*ipset->external) + ipset->external = NULL; + else if (!ipset->name) + ipset->name = ipset->external; + } + if (!ipset->name || !*ipset->name) { warn_elem(e, "must have a name assigned"); @@ -246,6 +257,14 @@ fw3_load_ipsets(struct fw3_state *state, struct uci_package *p) //{ // warn_elem(e, "has duplicated set name '%s'", ipset->name); //} + else if (ipset->family == FW3_FAMILY_ANY) + { + warn_elem(e, "must not have family 'any'"); + } + else if (ipset->iprange.set && ipset->family != ipset->iprange.family) + { + warn_elem(e, "has iprange of wrong address family"); + } else if (list_empty(&ipset->datatypes)) { warn_elem(e, "has no datatypes assigned"); @@ -268,9 +287,6 @@ create_ipset(struct fw3_ipset *ipset, struct fw3_state *state) struct fw3_ipset_datatype *type; - if (ipset->external && *ipset->external) - return; - info(" * Creating ipset %s", ipset->name); first = true; @@ -282,9 +298,12 @@ create_ipset(struct fw3_ipset *ipset, struct fw3_state *state) first = false; } + if (ipset->method == FW3_IPSET_METHOD_HASH) + fw3_pr(" family inet%s", (ipset->family == FW3_FAMILY_V4) ? "" : "6"); + if (ipset->iprange.set) { - fw3_pr(" range %s", fw3_address_to_string(&ipset->iprange, false)); + fw3_pr(" range %s", fw3_address_to_string(&ipset->iprange, false, true)); } else if (ipset->portrange.set) { @@ -292,9 +311,6 @@ create_ipset(struct fw3_ipset *ipset, struct fw3_state *state) ipset->portrange.port_min, ipset->portrange.port_max); } - if (ipset->family != FW3_FAMILY_ANY) - fw3_pr(" family inet%s", (ipset->family == FW3_FAMILY_V4) ? "" : "6"); - if (ipset->timeout > 0) fw3_pr(" timeout %u", ipset->timeout); @@ -313,31 +329,86 @@ create_ipset(struct fw3_ipset *ipset, struct fw3_state *state) void fw3_create_ipsets(struct fw3_state *state) { + int tries; + bool exec = false; struct fw3_ipset *ipset; if (state->disable_ipsets) return; + /* spawn ipsets */ list_for_each_entry(ipset, &state->ipsets, list) + { + if (ipset->external) + continue; + + if (!exec) + { + exec = fw3_command_pipe(false, "ipset", "-exist", "-"); + + if (!exec) + return; + } + create_ipset(ipset, state); + } + + if (exec) + { + fw3_pr("quit\n"); + fw3_command_close(); + } + + /* wait for ipsets to appear */ + list_for_each_entry(ipset, &state->ipsets, list) + { + if (ipset->external) + continue; - fw3_pr("quit\n"); + for (tries = 0; !fw3_check_ipset(ipset) && tries < 10; tries++) + usleep(50000); + } } void fw3_destroy_ipsets(struct fw3_state *state) { - struct fw3_ipset *s; + int tries; + bool exec = false; + struct fw3_ipset *ipset; - list_for_each_entry(s, &state->ipsets, list) + /* destroy ipsets */ + list_for_each_entry(ipset, &state->ipsets, list) { - info(" * Deleting ipset %s", s->name); + if (!exec) + { + exec = fw3_command_pipe(false, "ipset", "-exist", "-"); - fw3_pr("flush %s\n", s->name); - fw3_pr("destroy %s\n", s->name); + if (!exec) + return; + } + + info(" * Deleting ipset %s", ipset->name); + + fw3_pr("flush %s\n", ipset->name); + fw3_pr("destroy %s\n", ipset->name); } - fw3_pr("quit\n"); + if (exec) + { + fw3_pr("quit\n"); + fw3_command_close(); + } + + /* wait for ipsets to disappear */ + list_for_each_entry(ipset, &state->ipsets, list) + { + if (ipset->external) + continue; + + for (tries = 0; fw3_check_ipset(ipset) && tries < 10; tries++) + usleep(50000); + } } struct fw3_ipset * @@ -358,3 +429,40 @@ fw3_lookup_ipset(struct fw3_state *state, const char *name) return NULL; } + +bool +fw3_check_ipset(struct fw3_ipset *set) +{ + bool rv = false; + + socklen_t sz; + int s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); + struct ip_set_req_version req_ver; + struct ip_set_req_get_set req_name; + + if (s < 0 || fcntl(s, F_SETFD, FD_CLOEXEC)) + goto out; + + sz = sizeof(req_ver); + req_ver.op = IP_SET_OP_VERSION; + + if (getsockopt(s, SOL_IP, SO_IP_SET, &req_ver, &sz)) + goto out; + + sz = sizeof(req_name); + req_name.op = IP_SET_OP_GET_BYNAME; + req_name.version = req_ver.version; + snprintf(req_name.set.name, IPSET_MAXNAMELEN - 1, "%s", + set->external ? set->external : set->name); + + if (getsockopt(s, SOL_IP, SO_IP_SET, &req_name, &sz)) + goto out; + + rv = ((sz == sizeof(req_name)) && (req_name.set.index != IPSET_INVALID_ID)); + +out: + if (s >= 0) + close(s); + + return rv; +}