diff --git a/doc/changelog.txt b/doc/changelog.txt index 3a21fb4..922054b 100644 --- a/doc/changelog.txt +++ b/doc/changelog.txt @@ -1,6 +1,20 @@ HEAD ==== +Enhancements: +- update to ipset 6.0 + * allow "new" as a commad alias to "create" + * ipset: improve command argument parsing + * ipset: avoid the unnecessary argv[] loop + * ipset: pass ipset_arg argument pointer + * separate ipset errnos completely from system ones and bump protocol version + * resolving IP addresses did not work at listing/saving sets, fixed + * ipset: fix spelling error + * ipset: fix the Netlink sequence number + * ipset: turn Set name[] into a const pointer + * check ICMP and ICMPv6 with the set match and target in the testsuite + * avoid possible syntax clashing at saving hostnames + * fix linking with CONFIG_IPV6=n v1.33 (2011-02-02) diff --git a/extensions/ipset-6/README b/extensions/ipset-6/README new file mode 100644 index 0000000..a7ef16c --- /dev/null +++ b/extensions/ipset-6/README @@ -0,0 +1,88 @@ +This is the ipset source tree. Follow the next steps to install ipset. +If you upgrade from an earlier 5.x release, please read the UPGRADE +instructions too. + +0. You need the source tree of your kernel (version >= 2.6.34) + and it have to be configured with ip6tables support enabled, + modules compiled. Please apply the netlink.patch against your kernel + tree, which adds the new subsystem identifier for ipset. + + Recompile and install the patched kernel and its modules. Please note, + you have to run the patched kernel for ipset to work. + + The ipset source code depends on the libmnl library so the library + must be installed. You can download the libmnl library from + + git://git.netfilter.org/libmnl.git + +1. Initialize the compiling environment for ipset. The packages automake, + autoconf and libtool are required. + + % ./autogen.sh + +2. Run `./configure` and then compile the ipset binary and the kernel + modules. + + Configure parameters can be used to to override the default path + to the kernel source tree (/lib/modules/`uname -r`/build), + the maximum number of sets (256), the default hash sizes (1024). + See `./configure --help`. + + % ./configure + % make + % make modules + +3. Install the binary and the kernel modules + + # make install + # make modules_install + + After installing the modules, you can run the testsuite as well. + Please note, several assumptions must be met for the testsuite: + + - no sets defined + - iptables/ip6tables rules are not set up + - the destination for kernel logs is /var/log/kern.log + - the networks 10.255.255.0/24 and 1002:1002:1002:1002::/64 + are not in use + - sendip utility is installed + + # make tests + +4. Cleanup the source tree + + % make clean + % make modules_clean + +That's it! + +Read the ipset(8) and iptables(8), ip6tables(8) manpages on how to use +ipset and its match and target from iptables. + +Compatibilities and incompatibilities: + +- The ipset 6.x userspace utility contains a backward compatibility + interface to support the commandline syntax of ipset 4.x. + The commandline syntax of ipset 6.x is fully compatible with 5.x. +- The ipset 6.x userspace utility can't talk to the kernel part of ipset 5.x + or 4.x. +- The ipset 6.x kernel part can't talk to the userspace utility from + ipset 5.x or 4.x. +- The ipset 6.x kernel part can work together with the set match and SET + target from iptables 1.4.7 and below, however if you need the IPv6 support + from ipset 6.x, then you have to use iptables 1.4.8 or above. + +The ipset 6.x can interpret the commandline syntax of ipset 4.x, however +some internal changes mean different behaviour: + +- The "--matchunset" flag for the macipmap type is ignored and not used + anymore. +- The "--probes" and "--resize" parameters of the hash types are ignored + and not used anymore. +- The "--from", "--to" and "--network" parameters of the ipporthash, + ipportiphash and ipportnethash types are ignored and not used anymore. +- The hash types are not resized when new entries are added by the SET + target. If you use a set together with the SET target, create it with + the proper size because it won't be resized automatically. +- The iptree, iptreemap types are not implemented in ipset 6.x. The types + are automatically substituted with the hash:ip type. diff --git a/extensions/ipset-6/include/libipset/linux_ip_set.h b/extensions/ipset-6/include/libipset/linux_ip_set.h index 1fb7ea2..d4b6308 100644 --- a/extensions/ipset-6/include/libipset/linux_ip_set.h +++ b/extensions/ipset-6/include/libipset/linux_ip_set.h @@ -4,7 +4,7 @@ /* Copyright (C) 2000-2002 Joakim Axelsson * Patrick Schaaf * Martin Josefsson - * Copyright (C) 2003-2010 Jozsef Kadlecsik + * Copyright (C) 2003-2011 Jozsef Kadlecsik * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -12,7 +12,7 @@ */ /* The protocol version */ -#define IPSET_PROTOCOL 5 +#define IPSET_PROTOCOL 60 /* The max length of strings including NUL: set and type identifiers */ #define IPSET_MAXNAMELEN 32 @@ -118,7 +118,7 @@ enum { /* Error codes */ enum ipset_errno { - IPSET_ERR_PRIVATE = 128, + IPSET_ERR_PRIVATE = 4096, IPSET_ERR_PROTOCOL, IPSET_ERR_FIND_TYPE, IPSET_ERR_MAX_SETS, @@ -135,7 +135,7 @@ enum ipset_errno { IPSET_ERR_IPADDR_IPV6, /* Type specific error codes */ - IPSET_ERR_TYPE_SPECIFIC = 160, + IPSET_ERR_TYPE_SPECIFIC = 4352, }; /* Flags at command level */ diff --git a/extensions/ipset-6/include/libipset/parse.h b/extensions/ipset-6/include/libipset/parse.h index e87a60d..760df49 100644 --- a/extensions/ipset-6/include/libipset/parse.h +++ b/extensions/ipset-6/include/libipset/parse.h @@ -17,6 +17,7 @@ #define IPSET_PROTO_SEPARATOR ":" struct ipset_session; +struct ipset_arg; typedef int (*ipset_parsefn)(struct ipset_session *s, enum ipset_opt opt, const char *str); @@ -84,8 +85,8 @@ extern int ipset_parse_ignored(struct ipset_session *session, extern int ipset_parse_elem(struct ipset_session *session, enum ipset_opt opt, const char *str); extern int ipset_call_parser(struct ipset_session *session, - ipset_parsefn parse, const char *optstr, - enum ipset_opt optional, const char *str); + const struct ipset_arg *arg, + const char *str); /* Compatibility parser functions */ extern int ipset_parse_iptimeout(struct ipset_session *session, diff --git a/extensions/ipset-6/include/libipset/types.h b/extensions/ipset-6/include/libipset/types.h index f9c8f2d..d8973db 100644 --- a/extensions/ipset-6/include/libipset/types.h +++ b/extensions/ipset-6/include/libipset/types.h @@ -70,7 +70,7 @@ struct ipset_elem { * but for the readability the full list is supported. */ struct ipset_type { - char name[IPSET_MAXNAMELEN]; /* type name */ + const char *name; uint8_t revision; /* revision number */ uint8_t family; /* supported family */ uint8_t dimension; /* elem dimension */ diff --git a/extensions/ipset-6/ip_set.h b/extensions/ipset-6/ip_set.h index 9d4b961..ec1438f 100644 --- a/extensions/ipset-6/ip_set.h +++ b/extensions/ipset-6/ip_set.h @@ -14,7 +14,7 @@ #include /* The protocol version */ -#define IPSET_PROTOCOL 5 +#define IPSET_PROTOCOL 60 /* The max length of strings including NUL: set and type identifiers */ #define IPSET_MAXNAMELEN 32 @@ -120,7 +120,7 @@ enum { /* Error codes */ enum ipset_errno { - IPSET_ERR_PRIVATE = 128, + IPSET_ERR_PRIVATE = 4096, IPSET_ERR_PROTOCOL, IPSET_ERR_FIND_TYPE, IPSET_ERR_MAX_SETS, @@ -137,7 +137,7 @@ enum ipset_errno { IPSET_ERR_IPADDR_IPV6, /* Type specific error codes */ - IPSET_ERR_TYPE_SPECIFIC = 160, + IPSET_ERR_TYPE_SPECIFIC = 4352, }; /* Flags at command level */ @@ -231,7 +231,7 @@ struct ip_set_type_variant { * returns negative error code, * zero for no match/success to add/delete * positive for matching element */ - int (*uadt)(struct ip_set *set, struct nlattr *head, int len, + int (*uadt)(struct ip_set *set, struct nlattr *tb[], enum ipset_adt adt, u32 *lineno, u32 flags); /* Low level add/del/test functions */ @@ -274,8 +274,11 @@ struct ip_set_type { u8 revision; /* Create set */ - int (*create)(struct ip_set *set, - struct nlattr *head, int len, u32 flags); + int (*create)(struct ip_set *set, struct nlattr *tb[], u32 flags); + + /* Attribute policies */ + const struct nla_policy create_policy[IPSET_ATTR_CREATE_MAX + 1]; + const struct nla_policy adt_policy[IPSET_ATTR_ADT_MAX + 1]; /* Set this to THIS_MODULE if you are a module, otherwise NULL */ struct module *me; @@ -320,7 +323,7 @@ extern int ip_set_test(ip_set_id_t id, const struct sk_buff *skb, u8 family, u8 dim, u8 flags); /* Utility functions */ -extern void * ip_set_alloc(size_t size, gfp_t gfp_mask); +extern void * ip_set_alloc(size_t size); extern void ip_set_free(void *members); extern int ip_set_get_ipaddr4(struct nlattr *nla, __be32 *ipaddr); extern int ip_set_get_ipaddr6(struct nlattr *nla, union nf_inet_addr *ipaddr); diff --git a/extensions/ipset-6/ip_set_ahash.h b/extensions/ipset-6/ip_set_ahash.h index 2f4bb3a..b6c4c2f 100644 --- a/extensions/ipset-6/ip_set_ahash.h +++ b/extensions/ipset-6/ip_set_ahash.h @@ -311,8 +311,7 @@ retry: /* In case we have plenty of memory :-) */ return -IPSET_ERR_HASH_FULL; t = ip_set_alloc(sizeof(*t) - + jhash_size(htable_bits) * sizeof(struct hbucket), - GFP_KERNEL); + + jhash_size(htable_bits) * sizeof(struct hbucket)); if (!t) return -ENOMEM; t->htable_bits = htable_bits; @@ -525,7 +524,7 @@ type_pf_head(struct ip_set *set, struct sk_buff *skb) return 0; nla_put_failure: - return -EFAULT; + return -EMSGSIZE; } /* Reply a LIST/SAVE request: dump the elements of the specified set */ @@ -545,7 +544,7 @@ type_pf_list(const struct ip_set *set, atd = ipset_nest_start(skb, IPSET_ATTR_ADT); if (!atd) - return -EFAULT; + return -EMSGSIZE; pr_debug("list hash set %s\n", set->name); for (; cb->args[2] < jhash_size(t->htable_bits); cb->args[2]++) { incomplete = skb_tail_pointer(skb); @@ -559,7 +558,7 @@ type_pf_list(const struct ip_set *set, if (!nested) { if (cb->args[2] == first) { nla_nest_cancel(skb, atd); - return -EFAULT; + return -EMSGSIZE; } else goto nla_put_failure; } @@ -581,6 +580,7 @@ nla_put_failure: pr_warning("Can't list set %s: one bucket does not fit into " "a message. Please report it!\n", set->name); cb->args[2] = 0; + return -EMSGSIZE; } return 0; } @@ -589,7 +589,7 @@ static int type_pf_kadt(struct ip_set *set, const struct sk_buff * skb, enum ipset_adt adt, u8 pf, u8 dim, u8 flags); static int -type_pf_uadt(struct ip_set *set, struct nlattr *head, int len, +type_pf_uadt(struct ip_set *set, struct nlattr *tb[], enum ipset_adt adt, u32 *lineno, u32 flags); static const struct ip_set_type_variant type_pf_variant = { @@ -742,8 +742,7 @@ retry: /* In case we have plenty of memory :-) */ return -IPSET_ERR_HASH_FULL; t = ip_set_alloc(sizeof(*t) - + jhash_size(htable_bits) * sizeof(struct hbucket), - GFP_KERNEL); + + jhash_size(htable_bits) * sizeof(struct hbucket)); if (!t) return -ENOMEM; t->htable_bits = htable_bits; @@ -946,7 +945,7 @@ type_pf_tlist(const struct ip_set *set, atd = ipset_nest_start(skb, IPSET_ATTR_ADT); if (!atd) - return -EFAULT; + return -EMSGSIZE; for (; cb->args[2] < jhash_size(t->htable_bits); cb->args[2]++) { incomplete = skb_tail_pointer(skb); n = hbucket(t, cb->args[2]); @@ -960,7 +959,7 @@ type_pf_tlist(const struct ip_set *set, if (!nested) { if (cb->args[2] == first) { nla_nest_cancel(skb, atd); - return -EFAULT; + return -EMSGSIZE; } else goto nla_put_failure; } @@ -982,6 +981,7 @@ nla_put_failure: pr_warning("Can't list set %s: one bucket does not fit into " "a message. Please report it!\n", set->name); cb->args[2] = 0; + return -EMSGSIZE; } return 0; } diff --git a/extensions/ipset-6/ip_set_bitmap_ip.c b/extensions/ipset-6/ip_set_bitmap_ip.c index e011864..41cfded 100644 --- a/extensions/ipset-6/ip_set_bitmap_ip.c +++ b/extensions/ipset-6/ip_set_bitmap_ip.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include @@ -33,8 +32,7 @@ MODULE_AUTHOR("Jozsef Kadlecsik "); MODULE_DESCRIPTION("bitmap:ip type of IP sets"); MODULE_ALIAS("ip_set_bitmap:ip"); -/* Base variant */ - +/* Type structure */ struct bitmap_ip { void *members; /* the set members */ u32 first_ip; /* host byte order, included in range */ @@ -43,43 +41,188 @@ struct bitmap_ip { u32 hosts; /* number of hosts in a subnet */ size_t memsize; /* members size */ u8 netmask; /* subnet netmask */ + u32 timeout; /* timeout parameter */ + struct timer_list gc; /* garbage collection */ }; +/* Base variant */ + static inline u32 ip_to_id(const struct bitmap_ip *m, u32 ip) { return ((ip & ip_set_hostmask(m->netmask)) - m->first_ip)/m->hosts; } -static inline int -bitmap_ip_test(const struct bitmap_ip *map, u32 id) +static int +bitmap_ip_test(struct ip_set *set, void *value, u32 timeout) { + const struct bitmap_ip *map = set->data; + u16 id = *(u16 *)value; + return !!test_bit(id, map->members); } -static inline int -bitmap_ip_add(struct bitmap_ip *map, u32 id) +static int +bitmap_ip_add(struct ip_set *set, void *value, u32 timeout) { + struct bitmap_ip *map = set->data; + u16 id = *(u16 *)value; + if (test_and_set_bit(id, map->members)) return -IPSET_ERR_EXIST; return 0; } -static inline int -bitmap_ip_del(struct bitmap_ip *map, u32 id) +static int +bitmap_ip_del(struct ip_set *set, void *value, u32 timeout) { + struct bitmap_ip *map = set->data; + u16 id = *(u16 *)value; + if (!test_and_clear_bit(id, map->members)) return -IPSET_ERR_EXIST; return 0; } +static int +bitmap_ip_list(const struct ip_set *set, + struct sk_buff *skb, struct netlink_callback *cb) +{ + const struct bitmap_ip *map = set->data; + struct nlattr *atd, *nested; + u32 id, first = cb->args[2]; + + atd = ipset_nest_start(skb, IPSET_ATTR_ADT); + if (!atd) + return -EMSGSIZE; + for (; cb->args[2] < map->elements; cb->args[2]++) { + id = cb->args[2]; + if (!test_bit(id, map->members)) + continue; + nested = ipset_nest_start(skb, IPSET_ATTR_DATA); + if (!nested) { + if (id == first) { + nla_nest_cancel(skb, atd); + return -EMSGSIZE; + } else + goto nla_put_failure; + } + NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, + htonl(map->first_ip + id * map->hosts)); + ipset_nest_end(skb, nested); + } + ipset_nest_end(skb, atd); + /* Set listing finished */ + cb->args[2] = 0; + return 0; + +nla_put_failure: + nla_nest_cancel(skb, nested); + ipset_nest_end(skb, atd); + if (unlikely(id == first)) { + cb->args[2] = 0; + return -EMSGSIZE; + } + return 0; +} + +/* Timeout variant */ + +static int +bitmap_ip_ttest(struct ip_set *set, void *value, u32 timeout) +{ + const struct bitmap_ip *map = set->data; + const unsigned long *members = map->members; + u16 id = *(u16 *)value; + + return ip_set_timeout_test(members[id]); +} + +static int +bitmap_ip_tadd(struct ip_set *set, void *value, u32 timeout) +{ + struct bitmap_ip *map = set->data; + unsigned long *members = map->members; + u16 id = *(u16 *)value; + + if (ip_set_timeout_test(members[id])) + return -IPSET_ERR_EXIST; + + members[id] = ip_set_timeout_set(timeout); + + return 0; +} + +static int +bitmap_ip_tdel(struct ip_set *set, void *value, u32 timeout) +{ + struct bitmap_ip *map = set->data; + unsigned long *members = map->members; + u16 id = *(u16 *)value; + int ret = -IPSET_ERR_EXIST; + + if (ip_set_timeout_test(members[id])) + ret = 0; + + members[id] = IPSET_ELEM_UNSET; + return ret; +} + +static int +bitmap_ip_tlist(const struct ip_set *set, + struct sk_buff *skb, struct netlink_callback *cb) +{ + const struct bitmap_ip *map = set->data; + struct nlattr *adt, *nested; + u32 id, first = cb->args[2]; + const unsigned long *members = map->members; + + adt = ipset_nest_start(skb, IPSET_ATTR_ADT); + if (!adt) + return -EMSGSIZE; + for (; cb->args[2] < map->elements; cb->args[2]++) { + id = cb->args[2]; + if (!ip_set_timeout_test(members[id])) + continue; + nested = ipset_nest_start(skb, IPSET_ATTR_DATA); + if (!nested) { + if (id == first) { + nla_nest_cancel(skb, adt); + return -EMSGSIZE; + } else + goto nla_put_failure; + } + NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, + htonl(map->first_ip + id * map->hosts)); + NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, + htonl(ip_set_timeout_get(members[id]))); + ipset_nest_end(skb, nested); + } + ipset_nest_end(skb, adt); + + /* Set listing finished */ + cb->args[2] = 0; + + return 0; + +nla_put_failure: + nla_nest_cancel(skb, nested); + ipset_nest_end(skb, adt); + if (unlikely(id == first)) { + cb->args[2] = 0; + return -EMSGSIZE; + } + return 0; +} + static int bitmap_ip_kadt(struct ip_set *set, const struct sk_buff *skb, enum ipset_adt adt, u8 pf, u8 dim, u8 flags) { struct bitmap_ip *map = set->data; + ipset_adtfn adtfn = set->variant->adt[adt]; u32 ip; ip = ntohl(ip4addr(skb, flags & IPSET_DIM_ONE_SRC)); @@ -88,40 +231,21 @@ bitmap_ip_kadt(struct ip_set *set, const struct sk_buff *skb, ip = ip_to_id(map, ip); - switch (adt) { - case IPSET_TEST: - return bitmap_ip_test(map, ip); - case IPSET_ADD: - return bitmap_ip_add(map, ip); - case IPSET_DEL: - return bitmap_ip_del(map, ip); - default: - return -EINVAL; - } + return adtfn(set, &ip, map->timeout); } -static const struct nla_policy bitmap_ip_adt_policy[IPSET_ATTR_ADT_MAX+1] = { - [IPSET_ATTR_IP] = { .type = NLA_NESTED }, - [IPSET_ATTR_IP_TO] = { .type = NLA_NESTED }, - [IPSET_ATTR_CIDR] = { .type = NLA_U8 }, - [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, - [IPSET_ATTR_LINENO] = { .type = NLA_U32 }, -}; - static int -bitmap_ip_uadt(struct ip_set *set, struct nlattr *head, int len, +bitmap_ip_uadt(struct ip_set *set, struct nlattr *tb[], enum ipset_adt adt, u32 *lineno, u32 flags) { struct bitmap_ip *map = set->data; - struct nlattr *tb[IPSET_ATTR_ADT_MAX+1]; + ipset_adtfn adtfn = set->variant->adt[adt]; + u32 timeout = map->timeout; u32 ip, ip_to, id; int ret = 0; - if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len, - bitmap_ip_adt_policy)) - return -IPSET_ERR_PROTOCOL; - - if (unlikely(!tb[IPSET_ATTR_IP])) + if (unlikely(!tb[IPSET_ATTR_IP] || + !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT))) return -IPSET_ERR_PROTOCOL; if (tb[IPSET_ATTR_LINENO]) @@ -134,13 +258,16 @@ bitmap_ip_uadt(struct ip_set *set, struct nlattr *head, int len, if (ip < map->first_ip || ip > map->last_ip) return -IPSET_ERR_BITMAP_RANGE; - /* Set was defined without timeout support: - * don't ignore the attribute silently */ - if (tb[IPSET_ATTR_TIMEOUT]) - return -IPSET_ERR_TIMEOUT; + if (tb[IPSET_ATTR_TIMEOUT]) { + if (!with_timeout(map->timeout)) + return -IPSET_ERR_TIMEOUT; + timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); + } - if (adt == IPSET_TEST) - return bitmap_ip_test(map, ip_to_id(map, ip)); + if (adt == IPSET_TEST) { + id = ip_to_id(map, ip); + return adtfn(set, &id, timeout); + } if (tb[IPSET_ATTR_IP_TO]) { ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to); @@ -166,8 +293,7 @@ bitmap_ip_uadt(struct ip_set *set, struct nlattr *head, int len, for (; !before(ip_to, ip); ip += map->hosts) { id = ip_to_id(map, ip); - ret = adt == IPSET_ADD ? bitmap_ip_add(map, id) - : bitmap_ip_del(map, id); + ret = adtfn(set, &id, timeout);; if (ret && !ip_set_eexist(ret, flags)) return ret; @@ -182,6 +308,9 @@ bitmap_ip_destroy(struct ip_set *set) { struct bitmap_ip *map = set->data; + if (with_timeout(map->timeout)) + del_timer_sync(&map->gc); + ip_set_free(map->members); kfree(map); @@ -213,49 +342,13 @@ bitmap_ip_head(struct ip_set *set, struct sk_buff *skb) htonl(atomic_read(&set->ref) - 1)); NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE, htonl(sizeof(*map) + map->memsize)); + if (with_timeout(map->timeout)) + NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, htonl(map->timeout)); ipset_nest_end(skb, nested); return 0; nla_put_failure: - return -EFAULT; -} - -static int -bitmap_ip_list(const struct ip_set *set, - struct sk_buff *skb, struct netlink_callback *cb) -{ - const struct bitmap_ip *map = set->data; - struct nlattr *atd, *nested; - u32 id, first = cb->args[2]; - - atd = ipset_nest_start(skb, IPSET_ATTR_ADT); - if (!atd) - return -EFAULT; - for (; cb->args[2] < map->elements; cb->args[2]++) { - id = cb->args[2]; - if (!bitmap_ip_test(map, id)) - continue; - nested = ipset_nest_start(skb, IPSET_ATTR_DATA); - if (!nested) { - if (id == first) { - nla_nest_cancel(skb, atd); - return -EFAULT; - } else - goto nla_put_failure; - } - NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, - htonl(map->first_ip + id * map->hosts)); - ipset_nest_end(skb, nested); - } - ipset_nest_end(skb, atd); - /* Set listing finished */ - cb->args[2] = 0; - return 0; - -nla_put_failure: - nla_nest_cancel(skb, nested); - ipset_nest_end(skb, atd); - return 0; + return -EMSGSIZE; } static bool @@ -266,12 +359,18 @@ bitmap_ip_same_set(const struct ip_set *a, const struct ip_set *b) return x->first_ip == y->first_ip && x->last_ip == y->last_ip && - x->netmask == y->netmask; + x->netmask == y->netmask && + x->timeout == y->timeout; } static const struct ip_set_type_variant bitmap_ip = { .kadt = bitmap_ip_kadt, .uadt = bitmap_ip_uadt, + .adt = { + [IPSET_ADD] = bitmap_ip_add, + [IPSET_DEL] = bitmap_ip_del, + [IPSET_TEST] = bitmap_ip_test, + }, .destroy = bitmap_ip_destroy, .flush = bitmap_ip_flush, .head = bitmap_ip_head, @@ -279,261 +378,26 @@ static const struct ip_set_type_variant bitmap_ip = { .same_set = bitmap_ip_same_set, }; -/* Timeout variant */ - -struct bitmap_ip_timeout { - unsigned long *members; /* the set members */ - u32 first_ip; /* host byte order, included in range */ - u32 last_ip; /* host byte order, included in range */ - u32 elements; /* number of max elements in the set */ - u32 hosts; /* number of hosts in a subnet */ - size_t memsize; /* members size */ - u8 netmask; /* subnet netmask */ - - u32 timeout; /* timeout parameter */ - struct timer_list gc; /* garbage collection */ -}; - -static inline bool -bitmap_ip_timeout_test(const struct bitmap_ip_timeout *map, u32 id) -{ - return ip_set_timeout_test(map->members[id]); -} - -static inline int -bitmap_ip_timeout_add(struct bitmap_ip_timeout *map, - u32 id, u32 timeout) -{ - if (bitmap_ip_timeout_test(map, id)) - return -IPSET_ERR_EXIST; - - map->members[id] = ip_set_timeout_set(timeout); - - return 0; -} - -static inline int -bitmap_ip_timeout_del(struct bitmap_ip_timeout *map, u32 id) -{ - int ret = -IPSET_ERR_EXIST; - - if (bitmap_ip_timeout_test(map, id)) - ret = 0; - - map->members[id] = IPSET_ELEM_UNSET; - return ret; -} - -static int -bitmap_ip_timeout_kadt(struct ip_set *set, const struct sk_buff *skb, - enum ipset_adt adt, u8 pf, u8 dim, u8 flags) -{ - struct bitmap_ip_timeout *map = set->data; - u32 ip; - - ip = ntohl(ip4addr(skb, flags & IPSET_DIM_ONE_SRC)); - if (ip < map->first_ip || ip > map->last_ip) - return -IPSET_ERR_BITMAP_RANGE; - - ip = ip_to_id((const struct bitmap_ip *)map, ip); - - switch (adt) { - case IPSET_TEST: - return bitmap_ip_timeout_test(map, ip); - case IPSET_ADD: - return bitmap_ip_timeout_add(map, ip, map->timeout); - case IPSET_DEL: - return bitmap_ip_timeout_del(map, ip); - default: - return -EINVAL; - } -} - -static int -bitmap_ip_timeout_uadt(struct ip_set *set, struct nlattr *head, int len, - enum ipset_adt adt, u32 *lineno, u32 flags) -{ - struct bitmap_ip_timeout *map = set->data; - struct nlattr *tb[IPSET_ATTR_ADT_MAX+1]; - u32 ip, ip_to, id, timeout = map->timeout; - int ret = 0; - - if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len, - bitmap_ip_adt_policy)) - return -IPSET_ERR_PROTOCOL; - - if (unlikely(!tb[IPSET_ATTR_IP] || - !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT))) - return -IPSET_ERR_PROTOCOL; - - if (tb[IPSET_ATTR_LINENO]) - *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); - - ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip); - if (ret) - return ret; - - if (ip < map->first_ip || ip > map->last_ip) - return -IPSET_ERR_BITMAP_RANGE; - - if (adt == IPSET_TEST) - return bitmap_ip_timeout_test(map, - ip_to_id((const struct bitmap_ip *)map, ip)); - - if (tb[IPSET_ATTR_IP_TO]) { - ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to); - if (ret) - return ret; - if (ip > ip_to) { - swap(ip, ip_to); - if (ip < map->first_ip) - return -IPSET_ERR_BITMAP_RANGE; - } - } else if (tb[IPSET_ATTR_CIDR]) { - u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]); - - if (cidr > 32) - return -IPSET_ERR_INVALID_CIDR; - ip &= ip_set_hostmask(cidr); - ip_to = ip | ~ip_set_hostmask(cidr); - } else - ip_to = ip; - - if (ip_to > map->last_ip) - return -IPSET_ERR_BITMAP_RANGE; - - if (tb[IPSET_ATTR_TIMEOUT]) - timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); - - for (; !before(ip_to, ip); ip += map->hosts) { - id = ip_to_id((const struct bitmap_ip *)map, ip); - ret = adt == IPSET_ADD - ? bitmap_ip_timeout_add(map, id, timeout) - : bitmap_ip_timeout_del(map, id); - - if (ret && !ip_set_eexist(ret, flags)) - return ret; - else - ret = 0; - } - return ret; -} - -static void -bitmap_ip_timeout_destroy(struct ip_set *set) -{ - struct bitmap_ip_timeout *map = set->data; - - del_timer_sync(&map->gc); - ip_set_free(map->members); - kfree(map); - - set->data = NULL; -} - -static void -bitmap_ip_timeout_flush(struct ip_set *set) -{ - struct bitmap_ip_timeout *map = set->data; - - memset(map->members, IPSET_ELEM_UNSET, map->memsize); -} - -static int -bitmap_ip_timeout_head(struct ip_set *set, struct sk_buff *skb) -{ - const struct bitmap_ip_timeout *map = set->data; - struct nlattr *nested; - - nested = ipset_nest_start(skb, IPSET_ATTR_DATA); - if (!nested) - goto nla_put_failure; - NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, htonl(map->first_ip)); - NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP_TO, htonl(map->last_ip)); - if (map->netmask != 32) - NLA_PUT_U8(skb, IPSET_ATTR_NETMASK, map->netmask); - NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, htonl(map->timeout)); - NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES, - htonl(atomic_read(&set->ref) - 1)); - NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE, - htonl(sizeof(*map) + map->memsize)); - ipset_nest_end(skb, nested); - - return 0; -nla_put_failure: - return -EFAULT; -} - -static int -bitmap_ip_timeout_list(const struct ip_set *set, - struct sk_buff *skb, struct netlink_callback *cb) -{ - const struct bitmap_ip_timeout *map = set->data; - struct nlattr *adt, *nested; - u32 id, first = cb->args[2]; - const unsigned long *table = map->members; - - adt = ipset_nest_start(skb, IPSET_ATTR_ADT); - if (!adt) - return -EFAULT; - for (; cb->args[2] < map->elements; cb->args[2]++) { - id = cb->args[2]; - if (!bitmap_ip_timeout_test(map, id)) - continue; - nested = ipset_nest_start(skb, IPSET_ATTR_DATA); - if (!nested) { - if (id == first) { - nla_nest_cancel(skb, adt); - return -EFAULT; - } else - goto nla_put_failure; - } - NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, - htonl(map->first_ip + id * map->hosts)); - NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, - htonl(ip_set_timeout_get(table[id]))); - ipset_nest_end(skb, nested); - } - ipset_nest_end(skb, adt); - - /* Set listing finished */ - cb->args[2] = 0; - - return 0; - -nla_put_failure: - nla_nest_cancel(skb, nested); - ipset_nest_end(skb, adt); - return 0; -} - -static bool -bitmap_ip_timeout_same_set(const struct ip_set *a, const struct ip_set *b) -{ - const struct bitmap_ip_timeout *x = a->data; - const struct bitmap_ip_timeout *y = b->data; - - return x->first_ip == y->first_ip && - x->last_ip == y->last_ip && - x->netmask == y->netmask && - x->timeout == y->timeout; -} - -static const struct ip_set_type_variant bitmap_ip_timeout = { - .kadt = bitmap_ip_timeout_kadt, - .uadt = bitmap_ip_timeout_uadt, - .destroy = bitmap_ip_timeout_destroy, - .flush = bitmap_ip_timeout_flush, - .head = bitmap_ip_timeout_head, - .list = bitmap_ip_timeout_list, - .same_set = bitmap_ip_timeout_same_set, +static const struct ip_set_type_variant bitmap_tip = { + .kadt = bitmap_ip_kadt, + .uadt = bitmap_ip_uadt, + .adt = { + [IPSET_ADD] = bitmap_ip_tadd, + [IPSET_DEL] = bitmap_ip_tdel, + [IPSET_TEST] = bitmap_ip_ttest, + }, + .destroy = bitmap_ip_destroy, + .flush = bitmap_ip_flush, + .head = bitmap_ip_head, + .list = bitmap_ip_tlist, + .same_set = bitmap_ip_same_set, }; static void bitmap_ip_gc(unsigned long ul_set) { struct ip_set *set = (struct ip_set *) ul_set; - struct bitmap_ip_timeout *map = set->data; + struct bitmap_ip *map = set->data; unsigned long *table = map->members; u32 id; @@ -552,7 +416,7 @@ bitmap_ip_gc(unsigned long ul_set) static void bitmap_ip_gc_init(struct ip_set *set) { - struct bitmap_ip_timeout *map = set->data; + struct bitmap_ip *map = set->data; init_timer(&map->gc); map->gc.data = (unsigned long) set; @@ -563,21 +427,12 @@ bitmap_ip_gc_init(struct ip_set *set) /* Create bitmap:ip type of sets */ -static const struct nla_policy -bitmap_ip_create_policy[IPSET_ATTR_CREATE_MAX+1] = { - [IPSET_ATTR_IP] = { .type = NLA_NESTED }, - [IPSET_ATTR_IP_TO] = { .type = NLA_NESTED }, - [IPSET_ATTR_CIDR] = { .type = NLA_U8 }, - [IPSET_ATTR_NETMASK] = { .type = NLA_U8 }, - [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, -}; - static bool init_map_ip(struct ip_set *set, struct bitmap_ip *map, u32 first_ip, u32 last_ip, u32 elements, u32 hosts, u8 netmask) { - map->members = ip_set_alloc(map->memsize, GFP_KERNEL); + map->members = ip_set_alloc(map->memsize); if (!map->members) return false; map->first_ip = first_ip; @@ -585,6 +440,7 @@ init_map_ip(struct ip_set *set, struct bitmap_ip *map, map->elements = elements; map->hosts = hosts; map->netmask = netmask; + map->timeout = IPSET_NO_TIMEOUT; set->data = map; set->family = AF_INET; @@ -593,18 +449,13 @@ init_map_ip(struct ip_set *set, struct bitmap_ip *map, } static int -bitmap_ip_create(struct ip_set *set, struct nlattr *head, int len, - u32 flags) +bitmap_ip_create(struct ip_set *set, struct nlattr *tb[], u32 flags) { - struct nlattr *tb[IPSET_ATTR_CREATE_MAX+1]; + struct bitmap_ip *map; u32 first_ip, last_ip, hosts, elements; u8 netmask = 32; int ret; - if (nla_parse(tb, IPSET_ATTR_CREATE_MAX, head, len, - bitmap_ip_create_policy)) - return -IPSET_ERR_PROTOCOL; - if (unlikely(!tb[IPSET_ATTR_IP] || !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT))) return -IPSET_ERR_PROTOCOL; @@ -664,37 +515,27 @@ bitmap_ip_create(struct ip_set *set, struct nlattr *head, int len, pr_debug("hosts %u, elements %u\n", hosts, elements); + map = kzalloc(sizeof(*map), GFP_KERNEL); + if (!map) + return -ENOMEM; + if (tb[IPSET_ATTR_TIMEOUT]) { - struct bitmap_ip_timeout *map; - - map = kzalloc(sizeof(*map), GFP_KERNEL); - if (!map) - return -ENOMEM; - map->memsize = elements * sizeof(unsigned long); - if (!init_map_ip(set, (struct bitmap_ip *)map, - first_ip, last_ip, + if (!init_map_ip(set, map, first_ip, last_ip, elements, hosts, netmask)) { kfree(map); return -ENOMEM; } map->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); - set->variant = &bitmap_ip_timeout; + set->variant = &bitmap_tip; bitmap_ip_gc_init(set); } else { - struct bitmap_ip *map; - - map = kzalloc(sizeof(*map), GFP_KERNEL); - if (!map) - return -ENOMEM; - map->memsize = bitmap_bytes(0, elements - 1); - if (!init_map_ip(set, map, - first_ip, last_ip, + if (!init_map_ip(set, map, first_ip, last_ip, elements, hosts, netmask)) { kfree(map); return -ENOMEM; @@ -713,6 +554,20 @@ static struct ip_set_type bitmap_ip_type __read_mostly = { .family = AF_INET, .revision = 0, .create = bitmap_ip_create, + .create_policy = { + [IPSET_ATTR_IP] = { .type = NLA_NESTED }, + [IPSET_ATTR_IP_TO] = { .type = NLA_NESTED }, + [IPSET_ATTR_CIDR] = { .type = NLA_U8 }, + [IPSET_ATTR_NETMASK] = { .type = NLA_U8 }, + [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, + }, + .adt_policy = { + [IPSET_ATTR_IP] = { .type = NLA_NESTED }, + [IPSET_ATTR_IP_TO] = { .type = NLA_NESTED }, + [IPSET_ATTR_CIDR] = { .type = NLA_U8 }, + [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, + [IPSET_ATTR_LINENO] = { .type = NLA_U32 }, + }, .me = THIS_MODULE, }; diff --git a/extensions/ipset-6/ip_set_bitmap_ipmac.c b/extensions/ipset-6/ip_set_bitmap_ipmac.c index 7363527..50fcb3f 100644 --- a/extensions/ipset-6/ip_set_bitmap_ipmac.c +++ b/extensions/ipset-6/ip_set_bitmap_ipmac.c @@ -15,9 +15,6 @@ #include #include #include -#include -#include -#include #include #include #include @@ -175,7 +172,7 @@ bitmap_ipmac_list(const struct ip_set *set, atd = ipset_nest_start(skb, IPSET_ATTR_ADT); if (!atd) - return -EFAULT; + return -EMSGSIZE; for (; cb->args[2] <= last; cb->args[2]++) { id = cb->args[2]; elem = bitmap_ipmac_elem(map, id); @@ -185,7 +182,7 @@ bitmap_ipmac_list(const struct ip_set *set, if (!nested) { if (id == first) { nla_nest_cancel(skb, atd); - return -EFAULT; + return -EMSGSIZE; } else goto nla_put_failure; } @@ -205,6 +202,10 @@ bitmap_ipmac_list(const struct ip_set *set, nla_put_failure: nla_nest_cancel(skb, nested); ipset_nest_end(skb, atd); + if (unlikely(id == first)) { + cb->args[2] = 0; + return -EMSGSIZE; + } return 0; } @@ -298,7 +299,7 @@ bitmap_ipmac_tlist(const struct ip_set *set, atd = ipset_nest_start(skb, IPSET_ATTR_ADT); if (!atd) - return -EFAULT; + return -EMSGSIZE; for (; cb->args[2] <= last; cb->args[2]++) { id = cb->args[2]; elem = bitmap_ipmac_elem(map, id); @@ -308,7 +309,7 @@ bitmap_ipmac_tlist(const struct ip_set *set, if (!nested) { if (id == first) { nla_nest_cancel(skb, atd); - return -EFAULT; + return -EMSGSIZE; } else goto nla_put_failure; } @@ -331,7 +332,7 @@ bitmap_ipmac_tlist(const struct ip_set *set, nla_put_failure: nla_nest_cancel(skb, nested); ipset_nest_end(skb, atd); - return 0; + return -EMSGSIZE; } static int @@ -357,29 +358,16 @@ bitmap_ipmac_kadt(struct ip_set *set, const struct sk_buff *skb, return adtfn(set, &data, map->timeout); } -static const struct nla_policy -bitmap_ipmac_adt_policy[IPSET_ATTR_ADT_MAX + 1] = { - [IPSET_ATTR_IP] = { .type = NLA_NESTED }, - [IPSET_ATTR_ETHER] = { .type = NLA_BINARY, .len = ETH_ALEN }, - [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, - [IPSET_ATTR_LINENO] = { .type = NLA_U32 }, -}; - static int -bitmap_ipmac_uadt(struct ip_set *set, struct nlattr *head, int len, +bitmap_ipmac_uadt(struct ip_set *set, struct nlattr *tb[], enum ipset_adt adt, u32 *lineno, u32 flags) { const struct bitmap_ipmac *map = set->data; - struct nlattr *tb[IPSET_ATTR_ADT_MAX+1]; ipset_adtfn adtfn = set->variant->adt[adt]; struct ipmac data; u32 timeout = map->timeout; int ret = 0; - if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len, - bitmap_ipmac_adt_policy)) - return -IPSET_ERR_PROTOCOL; - if (unlikely(!tb[IPSET_ATTR_IP] || !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT))) return -IPSET_ERR_PROTOCOL; @@ -457,7 +445,7 @@ bitmap_ipmac_head(struct ip_set *set, struct sk_buff *skb) return 0; nla_put_failure: - return -EFAULT; + return -EMSGSIZE; } static bool @@ -538,20 +526,11 @@ bitmap_ipmac_gc_init(struct ip_set *set) /* Create bitmap:ip,mac type of sets */ -static const struct nla_policy -bitmap_ipmac_create_policy[IPSET_ATTR_CREATE_MAX+1] = { - [IPSET_ATTR_IP] = { .type = NLA_NESTED }, - [IPSET_ATTR_IP_TO] = { .type = NLA_NESTED }, - [IPSET_ATTR_CIDR] = { .type = NLA_U8 }, - [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, -}; - static bool init_map_ipmac(struct ip_set *set, struct bitmap_ipmac *map, u32 first_ip, u32 last_ip) { - map->members = ip_set_alloc((last_ip - first_ip + 1) * map->dsize, - GFP_KERNEL); + map->members = ip_set_alloc((last_ip - first_ip + 1) * map->dsize); if (!map->members) return false; map->first_ip = first_ip; @@ -565,18 +544,13 @@ init_map_ipmac(struct ip_set *set, struct bitmap_ipmac *map, } static int -bitmap_ipmac_create(struct ip_set *set, struct nlattr *head, int len, +bitmap_ipmac_create(struct ip_set *set, struct nlattr *tb[], u32 flags) { - struct nlattr *tb[IPSET_ATTR_CREATE_MAX+1]; u32 first_ip, last_ip, elements; struct bitmap_ipmac *map; int ret; - if (nla_parse(tb, IPSET_ATTR_CREATE_MAX, head, len, - bitmap_ipmac_create_policy)) - return -IPSET_ERR_PROTOCOL; - if (unlikely(!tb[IPSET_ATTR_IP] || !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT))) return -IPSET_ERR_PROTOCOL; @@ -647,6 +621,18 @@ static struct ip_set_type bitmap_ipmac_type = { .family = AF_INET, .revision = 0, .create = bitmap_ipmac_create, + .create_policy = { + [IPSET_ATTR_IP] = { .type = NLA_NESTED }, + [IPSET_ATTR_IP_TO] = { .type = NLA_NESTED }, + [IPSET_ATTR_CIDR] = { .type = NLA_U8 }, + [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, + }, + .adt_policy = { + [IPSET_ATTR_IP] = { .type = NLA_NESTED }, + [IPSET_ATTR_ETHER] = { .type = NLA_BINARY, .len = ETH_ALEN }, + [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, + [IPSET_ATTR_LINENO] = { .type = NLA_U32 }, + }, .me = THIS_MODULE, }; diff --git a/extensions/ipset-6/ip_set_bitmap_port.c b/extensions/ipset-6/ip_set_bitmap_port.c index 5c5c6f3..01dc2ff 100644 --- a/extensions/ipset-6/ip_set_bitmap_port.c +++ b/extensions/ipset-6/ip_set_bitmap_port.c @@ -9,13 +9,8 @@ #include #include -#include -#include #include #include -#include -#include -#include #include #include #include @@ -32,24 +27,33 @@ MODULE_AUTHOR("Jozsef Kadlecsik "); MODULE_DESCRIPTION("bitmap:port type of IP sets"); MODULE_ALIAS("ip_set_bitmap:port"); -/* Base variant */ - +/* Type structure */ struct bitmap_port { void *members; /* the set members */ u16 first_port; /* host byte order, included in range */ u16 last_port; /* host byte order, included in range */ size_t memsize; /* members size */ + u32 timeout; /* timeout parameter */ + struct timer_list gc; /* garbage collection */ }; -static inline int -bitmap_port_test(const struct bitmap_port *map, u16 id) +/* Base variant */ + +static int +bitmap_port_test(struct ip_set *set, void *value, u32 timeout) { + const struct bitmap_port *map = set->data; + u16 id = *(u16 *)value; + return !!test_bit(id, map->members); } -static inline int -bitmap_port_add(struct bitmap_port *map, u16 id) +static int +bitmap_port_add(struct ip_set *set, void *value, u32 timeout) { + struct bitmap_port *map = set->data; + u16 id = *(u16 *)value; + if (test_and_set_bit(id, map->members)) return -IPSET_ERR_EXIST; @@ -57,19 +61,157 @@ bitmap_port_add(struct bitmap_port *map, u16 id) } static int -bitmap_port_del(struct bitmap_port *map, u16 id) +bitmap_port_del(struct ip_set *set, void *value, u32 timeout) { + struct bitmap_port *map = set->data; + u16 id = *(u16 *)value; + if (!test_and_clear_bit(id, map->members)) return -IPSET_ERR_EXIST; return 0; } +static int +bitmap_port_list(const struct ip_set *set, + struct sk_buff *skb, struct netlink_callback *cb) +{ + const struct bitmap_port *map = set->data; + struct nlattr *atd, *nested; + u16 id, first = cb->args[2]; + u16 last = map->last_port - map->first_port; + + atd = ipset_nest_start(skb, IPSET_ATTR_ADT); + if (!atd) + return -EMSGSIZE; + for (; cb->args[2] <= last; cb->args[2]++) { + id = cb->args[2]; + if (!test_bit(id, map->members)) + continue; + nested = ipset_nest_start(skb, IPSET_ATTR_DATA); + if (!nested) { + if (id == first) { + nla_nest_cancel(skb, atd); + return -EMSGSIZE; + } else + goto nla_put_failure; + } + NLA_PUT_NET16(skb, IPSET_ATTR_PORT, + htons(map->first_port + id)); + ipset_nest_end(skb, nested); + } + ipset_nest_end(skb, atd); + /* Set listing finished */ + cb->args[2] = 0; + + return 0; + +nla_put_failure: + nla_nest_cancel(skb, nested); + ipset_nest_end(skb, atd); + if (unlikely(id == first)) { + cb->args[2] = 0; + return -EMSGSIZE; + } + return 0; +} + +/* Timeout variant */ + +static int +bitmap_port_ttest(struct ip_set *set, void *value, u32 timeout) +{ + const struct bitmap_port *map = set->data; + const unsigned long *members = map->members; + u16 id = *(u16 *)value; + + return ip_set_timeout_test(members[id]); +} + +static int +bitmap_port_tadd(struct ip_set *set, void *value, u32 timeout) +{ + struct bitmap_port *map = set->data; + unsigned long *members = map->members; + u16 id = *(u16 *)value; + + if (ip_set_timeout_test(members[id])) + return -IPSET_ERR_EXIST; + + members[id] = ip_set_timeout_set(timeout); + + return 0; +} + +static int +bitmap_port_tdel(struct ip_set *set, void *value, u32 timeout) +{ + struct bitmap_port *map = set->data; + unsigned long *members = map->members; + u16 id = *(u16 *)value; + int ret = -IPSET_ERR_EXIST; + + if (ip_set_timeout_test(members[id])) + ret = 0; + + members[id] = IPSET_ELEM_UNSET; + return ret; +} + +static int +bitmap_port_tlist(const struct ip_set *set, + struct sk_buff *skb, struct netlink_callback *cb) +{ + const struct bitmap_port *map = set->data; + struct nlattr *adt, *nested; + u16 id, first = cb->args[2]; + u16 last = map->last_port - map->first_port; + const unsigned long *members = map->members; + + adt = ipset_nest_start(skb, IPSET_ATTR_ADT); + if (!adt) + return -EMSGSIZE; + for (; cb->args[2] <= last; cb->args[2]++) { + id = cb->args[2]; + if (!ip_set_timeout_test(members[id])) + continue; + nested = ipset_nest_start(skb, IPSET_ATTR_DATA); + if (!nested) { + if (id == first) { + nla_nest_cancel(skb, adt); + return -EMSGSIZE; + } else + goto nla_put_failure; + } + NLA_PUT_NET16(skb, IPSET_ATTR_PORT, + htons(map->first_port + id)); + NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, + htonl(ip_set_timeout_get(members[id]))); + ipset_nest_end(skb, nested); + } + ipset_nest_end(skb, adt); + + /* Set listing finished */ + cb->args[2] = 0; + + return 0; + +nla_put_failure: + nla_nest_cancel(skb, nested); + ipset_nest_end(skb, adt); + if (unlikely(id == first)) { + cb->args[2] = 0; + return -EMSGSIZE; + } + return 0; +} + static int bitmap_port_kadt(struct ip_set *set, const struct sk_buff *skb, enum ipset_adt adt, u8 pf, u8 dim, u8 flags) { struct bitmap_port *map = set->data; + ipset_adtfn adtfn = set->variant->adt[adt]; __be16 __port; u16 port = 0; @@ -83,41 +225,23 @@ bitmap_port_kadt(struct ip_set *set, const struct sk_buff *skb, port -= map->first_port; - switch (adt) { - case IPSET_TEST: - return bitmap_port_test(map, port); - case IPSET_ADD: - return bitmap_port_add(map, port); - case IPSET_DEL: - return bitmap_port_del(map, port); - default: - return -EINVAL; - } + return adtfn(set, &port, map->timeout); } -static const struct nla_policy bitmap_port_adt_policy[IPSET_ATTR_ADT_MAX+1] = { - [IPSET_ATTR_PORT] = { .type = NLA_U16 }, - [IPSET_ATTR_PORT_TO] = { .type = NLA_U16 }, - [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, - [IPSET_ATTR_LINENO] = { .type = NLA_U32 }, -}; - static int -bitmap_port_uadt(struct ip_set *set, struct nlattr *head, int len, +bitmap_port_uadt(struct ip_set *set, struct nlattr *tb[], enum ipset_adt adt, u32 *lineno, u32 flags) { struct bitmap_port *map = set->data; - struct nlattr *tb[IPSET_ATTR_ADT_MAX+1]; + ipset_adtfn adtfn = set->variant->adt[adt]; + u32 timeout = map->timeout; u32 port; /* wraparound */ u16 id, port_to; int ret = 0; - if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len, - bitmap_port_adt_policy)) - return -IPSET_ERR_PROTOCOL; - if (unlikely(!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) || - !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO))) + !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) || + !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT))) return -IPSET_ERR_PROTOCOL; if (tb[IPSET_ATTR_LINENO]) @@ -127,11 +251,16 @@ bitmap_port_uadt(struct ip_set *set, struct nlattr *head, int len, if (port < map->first_port || port > map->last_port) return -IPSET_ERR_BITMAP_RANGE; - if (tb[IPSET_ATTR_TIMEOUT]) - return -IPSET_ERR_TIMEOUT; + if (tb[IPSET_ATTR_TIMEOUT]) { + if (!with_timeout(map->timeout)) + return -IPSET_ERR_TIMEOUT; + timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); + } - if (adt == IPSET_TEST) - return bitmap_port_test(map, port - map->first_port); + if (adt == IPSET_TEST) { + id = port - map->first_port; + return adtfn(set, &id, timeout); + } if (tb[IPSET_ATTR_PORT_TO]) { port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]); @@ -148,8 +277,7 @@ bitmap_port_uadt(struct ip_set *set, struct nlattr *head, int len, for (; port <= port_to; port++) { id = port - map->first_port; - ret = adt == IPSET_ADD ? bitmap_port_add(map, id) - : bitmap_port_del(map, id); + ret = adtfn(set, &id, timeout); if (ret && !ip_set_eexist(ret, flags)) return ret; @@ -164,6 +292,9 @@ bitmap_port_destroy(struct ip_set *set) { struct bitmap_port *map = set->data; + if (with_timeout(map->timeout)) + del_timer_sync(&map->gc); + ip_set_free(map->members); kfree(map); @@ -193,51 +324,13 @@ bitmap_port_head(struct ip_set *set, struct sk_buff *skb) htonl(atomic_read(&set->ref) - 1)); NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE, htonl(sizeof(*map) + map->memsize)); + if (with_timeout(map->timeout)) + NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, htonl(map->timeout)); ipset_nest_end(skb, nested); return 0; nla_put_failure: - return -EFAULT; -} - -static int -bitmap_port_list(const struct ip_set *set, - struct sk_buff *skb, struct netlink_callback *cb) -{ - const struct bitmap_port *map = set->data; - struct nlattr *atd, *nested; - u16 id, first = cb->args[2]; - u16 last = map->last_port - map->first_port; - - atd = ipset_nest_start(skb, IPSET_ATTR_ADT); - if (!atd) - return -EFAULT; - for (; cb->args[2] <= last; cb->args[2]++) { - id = cb->args[2]; - if (!test_bit(id, map->members)) - continue; - nested = ipset_nest_start(skb, IPSET_ATTR_DATA); - if (!nested) { - if (id == first) { - nla_nest_cancel(skb, atd); - return -EFAULT; - } else - goto nla_put_failure; - } - NLA_PUT_NET16(skb, IPSET_ATTR_PORT, - htons(map->first_port + id)); - ipset_nest_end(skb, nested); - } - ipset_nest_end(skb, atd); - /* Set listing finished */ - cb->args[2] = 0; - - return 0; - -nla_put_failure: - nla_nest_cancel(skb, nested); - ipset_nest_end(skb, atd); - return 0; + return -EMSGSIZE; } static bool @@ -247,12 +340,18 @@ bitmap_port_same_set(const struct ip_set *a, const struct ip_set *b) const struct bitmap_port *y = b->data; return x->first_port == y->first_port && - x->last_port == y->last_port; + x->last_port == y->last_port && + x->timeout == y->timeout; } static const struct ip_set_type_variant bitmap_port = { .kadt = bitmap_port_kadt, .uadt = bitmap_port_uadt, + .adt = { + [IPSET_ADD] = bitmap_port_add, + [IPSET_DEL] = bitmap_port_del, + [IPSET_TEST] = bitmap_port_test, + }, .destroy = bitmap_port_destroy, .flush = bitmap_port_flush, .head = bitmap_port_head, @@ -260,251 +359,26 @@ static const struct ip_set_type_variant bitmap_port = { .same_set = bitmap_port_same_set, }; -/* Timeout variant */ - -struct bitmap_port_timeout { - unsigned long *members; /* the set members */ - u16 first_port; /* host byte order, included in range */ - u16 last_port; /* host byte order, included in range */ - size_t memsize; /* members size */ - - u32 timeout; /* timeout parameter */ - struct timer_list gc; /* garbage collection */ -}; - -static inline bool -bitmap_port_timeout_test(const struct bitmap_port_timeout *map, u16 id) -{ - return ip_set_timeout_test(map->members[id]); -} - -static int -bitmap_port_timeout_add(const struct bitmap_port_timeout *map, - u16 id, u32 timeout) -{ - if (bitmap_port_timeout_test(map, id)) - return -IPSET_ERR_EXIST; - - map->members[id] = ip_set_timeout_set(timeout); - - return 0; -} - -static int -bitmap_port_timeout_del(const struct bitmap_port_timeout *map, - u16 id) -{ - int ret = -IPSET_ERR_EXIST; - - if (bitmap_port_timeout_test(map, id)) - ret = 0; - - map->members[id] = IPSET_ELEM_UNSET; - return ret; -} - -static int -bitmap_port_timeout_kadt(struct ip_set *set, const struct sk_buff *skb, - enum ipset_adt adt, u8 pf, u8 dim, u8 flags) -{ - struct bitmap_port_timeout *map = set->data; - __be16 __port; - u16 port = 0; - - if (!ip_set_get_ip_port(skb, pf, flags & IPSET_DIM_ONE_SRC, &__port)) - return -EINVAL; - - port = ntohs(__port); - - if (port < map->first_port || port > map->last_port) - return -IPSET_ERR_BITMAP_RANGE; - - port -= map->first_port; - - switch (adt) { - case IPSET_TEST: - return bitmap_port_timeout_test(map, port); - case IPSET_ADD: - return bitmap_port_timeout_add(map, port, map->timeout); - case IPSET_DEL: - return bitmap_port_timeout_del(map, port); - default: - return -EINVAL; - } -} - -static int -bitmap_port_timeout_uadt(struct ip_set *set, struct nlattr *head, int len, - enum ipset_adt adt, u32 *lineno, u32 flags) -{ - const struct bitmap_port_timeout *map = set->data; - struct nlattr *tb[IPSET_ATTR_ADT_MAX+1]; - u16 id, port_to; - u32 port, timeout = map->timeout; /* wraparound */ - int ret = 0; - - if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len, - bitmap_port_adt_policy)) - return -IPSET_ERR_PROTOCOL; - - if (unlikely(!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) || - !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) || - !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT))) - return -IPSET_ERR_PROTOCOL; - - if (tb[IPSET_ATTR_LINENO]) - *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); - - port = ip_set_get_h16(tb[IPSET_ATTR_PORT]); - if (port < map->first_port || port > map->last_port) - return -IPSET_ERR_BITMAP_RANGE; - - if (adt == IPSET_TEST) - return bitmap_port_timeout_test(map, port - map->first_port); - - if (tb[IPSET_ATTR_PORT_TO]) { - port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]); - if (port > port_to) { - swap(port, port_to); - if (port < map->first_port) - return -IPSET_ERR_BITMAP_RANGE; - } - } else - port_to = port; - - if (port_to > map->last_port) - return -IPSET_ERR_BITMAP_RANGE; - - if (tb[IPSET_ATTR_TIMEOUT]) - timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); - - for (; port <= port_to; port++) { - id = port - map->first_port; - ret = adt == IPSET_ADD - ? bitmap_port_timeout_add(map, id, timeout) - : bitmap_port_timeout_del(map, id); - - if (ret && !ip_set_eexist(ret, flags)) - return ret; - else - ret = 0; - } - return ret; -} - -static void -bitmap_port_timeout_destroy(struct ip_set *set) -{ - struct bitmap_port_timeout *map = set->data; - - del_timer_sync(&map->gc); - ip_set_free(map->members); - kfree(map); - - set->data = NULL; -} - -static void -bitmap_port_timeout_flush(struct ip_set *set) -{ - struct bitmap_port_timeout *map = set->data; - - memset(map->members, 0, map->memsize); -} - -static int -bitmap_port_timeout_head(struct ip_set *set, struct sk_buff *skb) -{ - const struct bitmap_port_timeout *map = set->data; - struct nlattr *nested; - - nested = ipset_nest_start(skb, IPSET_ATTR_DATA); - if (!nested) - goto nla_put_failure; - NLA_PUT_NET16(skb, IPSET_ATTR_PORT, htons(map->first_port)); - NLA_PUT_NET16(skb, IPSET_ATTR_PORT_TO, htons(map->last_port)); - NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT , htonl(map->timeout)); - NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES, - htonl(atomic_read(&set->ref) - 1)); - NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE, - htonl(sizeof(*map) + map->memsize)); - ipset_nest_end(skb, nested); - - return 0; -nla_put_failure: - return -EFAULT; -} - -static int -bitmap_port_timeout_list(const struct ip_set *set, - struct sk_buff *skb, struct netlink_callback *cb) -{ - const struct bitmap_port_timeout *map = set->data; - struct nlattr *adt, *nested; - u16 id, first = cb->args[2]; - u16 last = map->last_port - map->first_port; - const unsigned long *table = map->members; - - adt = ipset_nest_start(skb, IPSET_ATTR_ADT); - if (!adt) - return -EFAULT; - for (; cb->args[2] <= last; cb->args[2]++) { - id = cb->args[2]; - if (!bitmap_port_timeout_test(map, id)) - continue; - nested = ipset_nest_start(skb, IPSET_ATTR_DATA); - if (!nested) { - if (id == first) { - nla_nest_cancel(skb, adt); - return -EFAULT; - } else - goto nla_put_failure; - } - NLA_PUT_NET16(skb, IPSET_ATTR_PORT, - htons(map->first_port + id)); - NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, - htonl(ip_set_timeout_get(table[id]))); - ipset_nest_end(skb, nested); - } - ipset_nest_end(skb, adt); - - /* Set listing finished */ - cb->args[2] = 0; - - return 0; - -nla_put_failure: - nla_nest_cancel(skb, nested); - ipset_nest_end(skb, adt); - return 0; -} - -static bool -bitmap_port_timeout_same_set(const struct ip_set *a, const struct ip_set *b) -{ - const struct bitmap_port_timeout *x = a->data; - const struct bitmap_port_timeout *y = b->data; - - return x->first_port == y->first_port && - x->last_port == y->last_port && - x->timeout == y->timeout; -} - -static const struct ip_set_type_variant bitmap_port_timeout = { - .kadt = bitmap_port_timeout_kadt, - .uadt = bitmap_port_timeout_uadt, - .destroy = bitmap_port_timeout_destroy, - .flush = bitmap_port_timeout_flush, - .head = bitmap_port_timeout_head, - .list = bitmap_port_timeout_list, - .same_set = bitmap_port_timeout_same_set, +static const struct ip_set_type_variant bitmap_tport = { + .kadt = bitmap_port_kadt, + .uadt = bitmap_port_uadt, + .adt = { + [IPSET_ADD] = bitmap_port_tadd, + [IPSET_DEL] = bitmap_port_tdel, + [IPSET_TEST] = bitmap_port_ttest, + }, + .destroy = bitmap_port_destroy, + .flush = bitmap_port_flush, + .head = bitmap_port_head, + .list = bitmap_port_tlist, + .same_set = bitmap_port_same_set, }; static void bitmap_port_gc(unsigned long ul_set) { struct ip_set *set = (struct ip_set *) ul_set; - struct bitmap_port_timeout *map = set->data; + struct bitmap_port *map = set->data; unsigned long *table = map->members; u32 id; /* wraparound */ u16 last = map->last_port - map->first_port; @@ -524,7 +398,7 @@ bitmap_port_gc(unsigned long ul_set) static void bitmap_port_gc_init(struct ip_set *set) { - struct bitmap_port_timeout *map = set->data; + struct bitmap_port *map = set->data; init_timer(&map->gc); map->gc.data = (unsigned long) set; @@ -535,22 +409,16 @@ bitmap_port_gc_init(struct ip_set *set) /* Create bitmap:ip type of sets */ -static const struct nla_policy -bitmap_port_create_policy[IPSET_ATTR_CREATE_MAX+1] = { - [IPSET_ATTR_PORT] = { .type = NLA_U16 }, - [IPSET_ATTR_PORT_TO] = { .type = NLA_U16 }, - [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, -}; - static bool init_map_port(struct ip_set *set, struct bitmap_port *map, u16 first_port, u16 last_port) { - map->members = ip_set_alloc(map->memsize, GFP_KERNEL); + map->members = ip_set_alloc(map->memsize); if (!map->members) return false; map->first_port = first_port; map->last_port = last_port; + map->timeout = IPSET_NO_TIMEOUT; set->data = map; set->family = AF_UNSPEC; @@ -559,16 +427,12 @@ init_map_port(struct ip_set *set, struct bitmap_port *map, } static int -bitmap_port_create(struct ip_set *set, struct nlattr *head, int len, +bitmap_port_create(struct ip_set *set, struct nlattr *tb[], u32 flags) { - struct nlattr *tb[IPSET_ATTR_CREATE_MAX+1]; + struct bitmap_port *map; u16 first_port, last_port; - if (nla_parse(tb, IPSET_ATTR_CREATE_MAX, head, len, - bitmap_port_create_policy)) - return -IPSET_ERR_PROTOCOL; - if (unlikely(!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) || !ip_set_attr_netorder(tb, IPSET_ATTR_PORT_TO) || !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT))) @@ -583,33 +447,24 @@ bitmap_port_create(struct ip_set *set, struct nlattr *head, int len, last_port = tmp; } + map = kzalloc(sizeof(*map), GFP_KERNEL); + if (!map) + return -ENOMEM; + if (tb[IPSET_ATTR_TIMEOUT]) { - struct bitmap_port_timeout *map; - - map = kzalloc(sizeof(*map), GFP_KERNEL); - if (!map) - return -ENOMEM; - map->memsize = (last_port - first_port + 1) * sizeof(unsigned long); - if (!init_map_port(set, (struct bitmap_port *) map, - first_port, last_port)) { + if (!init_map_port(set, map, first_port, last_port)) { kfree(map); return -ENOMEM; } map->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); - set->variant = &bitmap_port_timeout; + set->variant = &bitmap_tport; bitmap_port_gc_init(set); } else { - struct bitmap_port *map; - - map = kzalloc(sizeof(*map), GFP_KERNEL); - if (!map) - return -ENOMEM; - map->memsize = bitmap_bytes(0, last_port - first_port); pr_debug("memsize: %zu\n", map->memsize); if (!init_map_port(set, map, first_port, last_port)) { @@ -630,6 +485,17 @@ static struct ip_set_type bitmap_port_type = { .family = AF_UNSPEC, .revision = 0, .create = bitmap_port_create, + .create_policy = { + [IPSET_ATTR_PORT] = { .type = NLA_U16 }, + [IPSET_ATTR_PORT_TO] = { .type = NLA_U16 }, + [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, + }, + .adt_policy = { + [IPSET_ATTR_PORT] = { .type = NLA_U16 }, + [IPSET_ATTR_PORT_TO] = { .type = NLA_U16 }, + [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, + [IPSET_ATTR_LINENO] = { .type = NLA_U32 }, + }, .me = THIS_MODULE, }; diff --git a/extensions/ipset-6/ip_set_core.c b/extensions/ipset-6/ip_set_core.c index d17cffe..83da444 100644 --- a/extensions/ipset-6/ip_set_core.c +++ b/extensions/ipset-6/ip_set_core.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -196,20 +197,24 @@ EXPORT_SYMBOL_GPL(ip_set_type_unregister); /* Utility functions */ void * -ip_set_alloc(size_t size, gfp_t gfp_mask) +ip_set_alloc(size_t size) { void *members = NULL; if (size < KMALLOC_MAX_SIZE) - members = kzalloc(size, gfp_mask | __GFP_NOWARN); + members = kzalloc(size, GFP_KERNEL | __GFP_NOWARN); if (members) { pr_debug("%p: allocated with kmalloc\n", members); return members; } - members = __vmalloc(size, gfp_mask | __GFP_ZERO | __GFP_HIGHMEM, +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 37) + members = __vmalloc(size, GFP_KERNEL | __GFP_ZERO | __GFP_HIGHMEM, PAGE_KERNEL); +#else + members = vzalloc(size); +#endif if (!members) return NULL; pr_debug("%p: allocated with vmalloc\n", members); @@ -249,8 +254,7 @@ ip_set_get_ipaddr4(struct nlattr *nla, __be32 *ipaddr) if (unlikely(!flag_nested(nla))) return -IPSET_ERR_PROTOCOL; - if (nla_parse(tb, IPSET_ATTR_IPADDR_MAX, nla_data(nla), nla_len(nla), - ipaddr_policy)) + if (nla_parse_nested(tb, IPSET_ATTR_IPADDR_MAX, nla, ipaddr_policy)) return -IPSET_ERR_PROTOCOL; if (unlikely(!ip_set_attr_netorder(tb, IPSET_ATTR_IPADDR_IPV4))) return -IPSET_ERR_PROTOCOL; @@ -268,8 +272,7 @@ ip_set_get_ipaddr6(struct nlattr *nla, union nf_inet_addr *ipaddr) if (unlikely(!flag_nested(nla))) return -IPSET_ERR_PROTOCOL; - if (nla_parse(tb, IPSET_ATTR_IPADDR_MAX, nla_data(nla), nla_len(nla), - ipaddr_policy)) + if (nla_parse_nested(tb, IPSET_ATTR_IPADDR_MAX, nla, ipaddr_policy)) return -IPSET_ERR_PROTOCOL; if (unlikely(!ip_set_attr_netorder(tb, IPSET_ATTR_IPADDR_IPV6))) return -IPSET_ERR_PROTOCOL; @@ -611,10 +614,11 @@ ip_set_create(struct sk_buff *skb, struct genl_info *info) struct ip_set *set, *clash; ip_set_id_t index = IPSET_INVALID_ID; + struct nlattr *tb[IPSET_ATTR_CREATE_MAX+1] = {}; const char *name, *typename; u8 family, revision; u32 flags = flag_exist(info->genlhdr); - int ret = 0, len; + int ret = 0; if (unlikely(protocol_failed(attr) || attr[IPSET_ATTR_SETNAME] == NULL || @@ -659,11 +663,14 @@ ip_set_create(struct sk_buff *skb, struct genl_info *info) /* * Without holding any locks, create private part. */ - len = attr[IPSET_ATTR_DATA] ? nla_len(attr[IPSET_ATTR_DATA]) : 0; - pr_debug("data len: %u\n", len); - ret = set->type->create(set, attr[IPSET_ATTR_DATA] ? - nla_data(attr[IPSET_ATTR_DATA]) : NULL, len, - flags); + if (attr[IPSET_ATTR_DATA] && + nla_parse_nested(tb, IPSET_ATTR_CREATE_MAX, attr[IPSET_ATTR_DATA], + set->type->create_policy)) { + ret = -IPSET_ERR_PROTOCOL; + goto put_out; + } + + ret = set->type->create(set, tb, flags); if (ret != 0) goto put_out; @@ -749,7 +756,7 @@ ip_set_destroy(struct sk_buff *skb, struct genl_info *info) } else { i = find_set_id(nla_data(attr[IPSET_ATTR_SETNAME])); if (i == IPSET_INVALID_ID) - return -EEXIST; + return -ENOENT; else if (atomic_read(&ip_set_list[i]->ref)) return -IPSET_ERR_BUSY; @@ -786,7 +793,7 @@ ip_set_flush(struct sk_buff *skb, struct genl_info *info) } else { i = find_set_id(nla_data(attr[IPSET_ATTR_SETNAME])); if (i == IPSET_INVALID_ID) - return -EEXIST; + return -ENOENT; ip_set_flush_set(ip_set_list[i]); } @@ -820,7 +827,7 @@ ip_set_rename(struct sk_buff *skb, struct genl_info *info) set = find_set(nla_data(attr[IPSET_ATTR_SETNAME])); if (set == NULL) - return -EEXIST; + return -ENOENT; if (atomic_read(&set->ref) != 0) return -IPSET_ERR_REFERENCED; @@ -860,7 +867,7 @@ ip_set_swap(struct sk_buff *skb, struct genl_info *info) from_id = find_set_id(nla_data(attr[IPSET_ATTR_SETNAME])); if (from_id == IPSET_INVALID_ID) - return -EEXIST; + return -ENOENT; to_id = find_set_id(nla_data(attr[IPSET_ATTR_SETNAME2])); if (to_id == IPSET_INVALID_ID) @@ -946,7 +953,7 @@ dump_init(struct netlink_callback *cb) index = find_set_id(nla_data(cda[IPSET_ATTR_SETNAME])); if (index == IPSET_INVALID_ID) - return -EEXIST; + return -ENOENT; cb->args[0] = DUMP_ONE; cb->args[1] = index; @@ -958,16 +965,18 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb) { ip_set_id_t index = IPSET_INVALID_ID, max; struct ip_set *set = NULL; - void *nlh = NULL; + struct nlmsghdr *nlh = NULL; unsigned int flags = NETLINK_CB(cb->skb).pid ? NLM_F_MULTI : 0; int ret = 0; if (cb->args[0] == DUMP_INIT) { ret = dump_init(cb); if (ret < 0) { + nlh = nlmsg_hdr(cb->skb); /* We have to create and send the error message * manually :-( */ - netlink_ack(cb->skb, nlmsg_hdr(cb->skb), ret); + if (nlh->nlmsg_flags & NLM_F_ACK) + netlink_ack(cb->skb, nlh, ret); return ret; } } @@ -982,7 +991,7 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb) set = ip_set_list[index]; if (set == NULL) { if (cb->args[0] == DUMP_ONE) { - ret = -EEXIST; + ret = -ENOENT; goto out; } continue; @@ -1004,7 +1013,7 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb) cb->nlh->nlmsg_seq, flags, IPSET_CMD_LIST); if (!nlh) { - ret = -EFAULT; + ret = -EMSGSIZE; goto release_refcount; } NLA_PUT_U8(skb, IPSET_ATTR_PROTOCOL, IPSET_PROTOCOL); @@ -1092,19 +1101,17 @@ static const struct nla_policy ip_set_adt_policy[IPSET_ATTR_CMD_MAX + 1] = { }; static int -call_ad(struct sk_buff *skb, struct nlattr *const attr[], - struct ip_set *set, const struct nlattr *nla, - enum ipset_adt adt, u32 flags) +call_ad(struct sock *ctnl, struct sk_buff *skb, struct ip_set *set, + struct nlattr *tb[], enum ipset_adt adt, + u32 flags, bool use_lineno) { - struct nlattr *head = nla_data(nla); - int ret, len = nla_len(nla), retried = 0; + int ret, retried = 0; u32 lineno = 0; bool eexist = flags & IPSET_FLAG_EXIST; do { write_lock_bh(&set->lock); - ret = set->variant->uadt(set, head, len, adt, - &lineno, flags); + ret = set->variant->uadt(set, tb, adt, &lineno, flags); write_unlock_bh(&set->lock); } while (ret == -EAGAIN && set->variant->resize && @@ -1112,11 +1119,38 @@ call_ad(struct sk_buff *skb, struct nlattr *const attr[], if (!ret || (ret == -IPSET_ERR_EXIST && eexist)) return 0; - if (lineno && attr[IPSET_ATTR_LINENO]) { + if (lineno && use_lineno) { /* Error in restore/batch mode: send back lineno */ - u32 *errline = nla_data(attr[IPSET_ATTR_LINENO]); + struct nlmsghdr *rep, *nlh = nlmsg_hdr(skb); + struct sk_buff *skb2; + struct nlmsgerr *errmsg; + size_t payload = sizeof(*errmsg) + nlmsg_len(nlh); + int min_len = NLMSG_SPACE(sizeof(struct nfgenmsg)); + struct nlattr *cda[IPSET_ATTR_CMD_MAX+1]; + struct nlattr *cmdattr; + u32 *errline; + + skb2 = nlmsg_new(payload, GFP_KERNEL); + if (skb2 == NULL) + return -ENOMEM; + rep = __nlmsg_put(skb2, NETLINK_CB(skb).pid, + nlh->nlmsg_seq, NLMSG_ERROR, payload, 0); + errmsg = nlmsg_data(rep); + errmsg->error = ret; + memcpy(&errmsg->msg, nlh, nlh->nlmsg_len); + cmdattr = (void *)&errmsg->msg + min_len; + + nla_parse(cda, IPSET_ATTR_CMD_MAX, + cmdattr, nlh->nlmsg_len - min_len, + ip_set_adt_policy); + + errline = nla_data(cda[IPSET_ATTR_LINENO]); *errline = lineno; + + netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT); + /* Signal netlink not to send its ACK/errmsg. */ + return -EINTR; } return ret; @@ -1126,10 +1160,13 @@ static int ip_set_uadd(struct sk_buff *skb, struct genl_info *info) { struct nlattr *const *attr = info->attrs; + struct sock *ctnl = genl_info_net(info)->genl_sock; struct ip_set *set; + struct nlattr *tb[IPSET_ATTR_ADT_MAX+1] = {}; const struct nlattr *nla; u32 flags = flag_exist(info->genlhdr); + bool use_lineno; int ret = 0; if (unlikely(protocol_failed(attr) || @@ -1145,20 +1182,28 @@ ip_set_uadd(struct sk_buff *skb, struct genl_info *info) set = find_set(nla_data(attr[IPSET_ATTR_SETNAME])); if (set == NULL) - return -EEXIST; + return -ENOENT; + use_lineno = !!attr[IPSET_ATTR_LINENO]; if (attr[IPSET_ATTR_DATA]) { - ret = call_ad(skb, attr, - set, attr[IPSET_ATTR_DATA], IPSET_ADD, flags); + if (nla_parse_nested(tb, IPSET_ATTR_ADT_MAX, + attr[IPSET_ATTR_DATA], + set->type->adt_policy)) + return -IPSET_ERR_PROTOCOL; + ret = call_ad(ctnl, skb, set, tb, IPSET_ADD, flags, + use_lineno); } else { int nla_rem; nla_for_each_nested(nla, attr[IPSET_ATTR_ADT], nla_rem) { + memset(tb, 0, sizeof(tb)); if (nla_type(nla) != IPSET_ATTR_DATA || - !flag_nested(nla)) + !flag_nested(nla) || + nla_parse_nested(tb, IPSET_ATTR_ADT_MAX, nla, + set->type->adt_policy)) return -IPSET_ERR_PROTOCOL; - ret = call_ad(skb, attr, - set, nla, IPSET_ADD, flags); + ret = call_ad(ctnl, skb, set, tb, IPSET_ADD, + flags, use_lineno); if (ret < 0) return ret; } @@ -1170,10 +1215,13 @@ static int ip_set_udel(struct sk_buff *skb, struct genl_info *info) { struct nlattr *const *attr = info->attrs; + struct sock *ctnl = genl_info_net(info)->genl_sock; struct ip_set *set; + struct nlattr *tb[IPSET_ATTR_ADT_MAX+1] = {}; const struct nlattr *nla; u32 flags = flag_exist(info->genlhdr); + bool use_lineno; int ret = 0; if (unlikely(protocol_failed(attr) || @@ -1189,20 +1237,28 @@ ip_set_udel(struct sk_buff *skb, struct genl_info *info) set = find_set(nla_data(attr[IPSET_ATTR_SETNAME])); if (set == NULL) - return -EEXIST; + return -ENOENT; + use_lineno = !!attr[IPSET_ATTR_LINENO]; if (attr[IPSET_ATTR_DATA]) { - ret = call_ad(skb, attr, - set, attr[IPSET_ATTR_DATA], IPSET_DEL, flags); + if (nla_parse_nested(tb, IPSET_ATTR_ADT_MAX, + attr[IPSET_ATTR_DATA], + set->type->adt_policy)) + return -IPSET_ERR_PROTOCOL; + ret = call_ad(ctnl, skb, set, tb, IPSET_DEL, flags, + use_lineno); } else { int nla_rem; nla_for_each_nested(nla, attr[IPSET_ATTR_ADT], nla_rem) { + memset(tb, 0, sizeof(*tb)); if (nla_type(nla) != IPSET_ATTR_DATA || - !flag_nested(nla)) + !flag_nested(nla) || + nla_parse_nested(tb, IPSET_ATTR_ADT_MAX, nla, + set->type->adt_policy)) return -IPSET_ERR_PROTOCOL; - ret = call_ad(skb, attr, - set, nla, IPSET_DEL, flags); + ret = call_ad(ctnl, skb, set, tb, IPSET_DEL, + flags, use_lineno); if (ret < 0) return ret; } @@ -1216,6 +1272,7 @@ ip_set_utest(struct sk_buff *skb, struct genl_info *info) struct nlattr *const *attr = info->attrs; struct ip_set *set; + struct nlattr *tb[IPSET_ATTR_ADT_MAX+1] = {}; int ret = 0; if (unlikely(protocol_failed(attr) || @@ -1226,13 +1283,14 @@ ip_set_utest(struct sk_buff *skb, struct genl_info *info) set = find_set(nla_data(attr[IPSET_ATTR_SETNAME])); if (set == NULL) - return -EEXIST; + return -ENOENT; + + if (nla_parse_nested(tb, IPSET_ATTR_ADT_MAX, attr[IPSET_ATTR_DATA], + set->type->adt_policy)) + return -IPSET_ERR_PROTOCOL; read_lock_bh(&set->lock); - ret = set->variant->uadt(set, - nla_data(attr[IPSET_ATTR_DATA]), - nla_len(attr[IPSET_ATTR_DATA]), - IPSET_TEST, NULL, 0); + ret = set->variant->uadt(set, tb, IPSET_TEST, NULL, 0); read_unlock_bh(&set->lock); /* Userspace can't trigger element to be re-added */ if (ret == -EAGAIN) @@ -1260,7 +1318,7 @@ ip_set_header(struct sk_buff *skb, struct genl_info *info) index = find_set_id(nla_data(attr[IPSET_ATTR_SETNAME])); if (index == IPSET_INVALID_ID) - return -EEXIST; + return -ENOENT; set = ip_set_list[index]; skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); @@ -1280,7 +1338,7 @@ ip_set_header(struct sk_buff *skb, struct genl_info *info) ret = genlmsg_unicast(genl_info_net(info), skb2, NETLINK_CB(skb).pid); if (ret < 0) - return -EFAULT; + return ret; return 0; @@ -1288,7 +1346,7 @@ nla_put_failure: nlmsg_cancel(skb2, nlh2); nlmsg_failure: kfree_skb(skb2); - return -EFAULT; + return -EMSGSIZE; } /* Get type data */ @@ -1341,7 +1399,7 @@ ip_set_type(struct sk_buff *skb, struct genl_info *info) pr_debug("Send TYPE, nlmsg_len: %u\n", skb2->len); ret = genlmsg_unicast(genl_info_net(info), skb2, NETLINK_CB(skb).pid); if (ret < 0) - return -EFAULT; + return ret; return 0; @@ -1349,7 +1407,7 @@ nla_put_failure: genlmsg_cancel(skb2, nlh2); nlmsg_failure: kfree_skb(skb2); - return -EFAULT; + return -EMSGSIZE; } /* Get protocol version */ @@ -1385,7 +1443,7 @@ ip_set_protocol(struct sk_buff *skb, struct genl_info *info) ret = genlmsg_unicast(genl_info_net(info), skb2, NETLINK_CB(skb).pid); if (ret < 0) - return -EFAULT; + return ret; return 0; @@ -1393,7 +1451,7 @@ nla_put_failure: genlmsg_cancel(skb2, nlh2); nlmsg_failure: kfree_skb(skb2); - return -EFAULT; + return -EMSGSIZE; } static struct genl_ops ip_set_netlink_subsys_cb[] __read_mostly = { diff --git a/extensions/ipset-6/ip_set_getport.c b/extensions/ipset-6/ip_set_getport.c index d6cf5d2..0daf5e5 100644 --- a/extensions/ipset-6/ip_set_getport.c +++ b/extensions/ipset-6/ip_set_getport.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "ip_set_getport.h" @@ -93,21 +94,23 @@ ip_set_get_ip4_port(const struct sk_buff *skb, bool src, } EXPORT_SYMBOL_GPL(ip_set_get_ip4_port); +#if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE) bool ip_set_get_ip6_port(const struct sk_buff *skb, bool src, __be16 *port, u8 *proto) { - unsigned int protooff = 0; - int protocol; - unsigned short fragoff; + int protoff; + u8 nexthdr; - protocol = ipv6_find_hdr(skb, &protooff, -1, &fragoff); - if (protocol <= 0 || fragoff) + nexthdr = ipv6_hdr(skb)->nexthdr; + protoff = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &nexthdr); + if (protoff < 0) return false; - return get_port(skb, protocol, protooff, src, port, proto); + return get_port(skb, nexthdr, protoff, src, port, proto); } EXPORT_SYMBOL_GPL(ip_set_get_ip6_port); +#endif bool ip_set_get_ip_port(const struct sk_buff *skb, u8 pf, bool src, __be16 *port) @@ -118,8 +121,10 @@ ip_set_get_ip_port(const struct sk_buff *skb, u8 pf, bool src, __be16 *port) switch (pf) { case AF_INET: ret = ip_set_get_ip4_port(skb, src, port, &proto); + break; case AF_INET6: ret = ip_set_get_ip6_port(skb, src, port, &proto); + break; default: return false; } diff --git a/extensions/ipset-6/ip_set_getport.h b/extensions/ipset-6/ip_set_getport.h index 694c433..3882a81 100644 --- a/extensions/ipset-6/ip_set_getport.h +++ b/extensions/ipset-6/ip_set_getport.h @@ -3,8 +3,18 @@ extern bool ip_set_get_ip4_port(const struct sk_buff *skb, bool src, __be16 *port, u8 *proto); + +#if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE) extern bool ip_set_get_ip6_port(const struct sk_buff *skb, bool src, __be16 *port, u8 *proto); +#else +static inline bool ip_set_get_ip6_port(const struct sk_buff *skb, bool src, + __be16 *port, u8 *proto) +{ + return false; +} +#endif + extern bool ip_set_get_ip_port(const struct sk_buff *skb, u8 pf, bool src, __be16 *port); diff --git a/extensions/ipset-6/ip_set_hash_ip.c b/extensions/ipset-6/ip_set_hash_ip.c index 3eaa910..5bc3a9a 100644 --- a/extensions/ipset-6/ip_set_hash_ip.c +++ b/extensions/ipset-6/ip_set_hash_ip.c @@ -12,9 +12,6 @@ #include #include #include -#include -#include -#include #include #include #include @@ -127,29 +124,16 @@ hash_ip4_kadt(struct ip_set *set, const struct sk_buff *skb, return adtfn(set, &ip, h->timeout); } -static const struct nla_policy hash_ip4_adt_policy[IPSET_ATTR_ADT_MAX + 1] = { - [IPSET_ATTR_IP] = { .type = NLA_NESTED }, - [IPSET_ATTR_IP_TO] = { .type = NLA_NESTED }, - [IPSET_ATTR_CIDR] = { .type = NLA_U8 }, - [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, - [IPSET_ATTR_LINENO] = { .type = NLA_U32 }, -}; - static int -hash_ip4_uadt(struct ip_set *set, struct nlattr *head, int len, +hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[], enum ipset_adt adt, u32 *lineno, u32 flags) { const struct ip_set_hash *h = set->data; - struct nlattr *tb[IPSET_ATTR_ADT_MAX+1]; ipset_adtfn adtfn = set->variant->adt[adt]; u32 ip, ip_to, hosts, timeout = h->timeout; __be32 nip; int ret = 0; - if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len, - hash_ip4_adt_policy)) - return -IPSET_ERR_PROTOCOL; - if (unlikely(!tb[IPSET_ATTR_IP] || !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT))) return -IPSET_ERR_PROTOCOL; @@ -320,22 +304,19 @@ static const struct nla_policy hash_ip6_adt_policy[IPSET_ATTR_ADT_MAX + 1] = { }; static int -hash_ip6_uadt(struct ip_set *set, struct nlattr *head, int len, +hash_ip6_uadt(struct ip_set *set, struct nlattr *tb[], enum ipset_adt adt, u32 *lineno, u32 flags) { const struct ip_set_hash *h = set->data; - struct nlattr *tb[IPSET_ATTR_ADT_MAX+1]; ipset_adtfn adtfn = set->variant->adt[adt]; union nf_inet_addr ip; u32 timeout = h->timeout; int ret; - if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len, - hash_ip6_adt_policy)) - return -IPSET_ERR_PROTOCOL; - if (unlikely(!tb[IPSET_ATTR_IP] || - !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT))) + !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || + tb[IPSET_ATTR_IP_TO] || + tb[IPSET_ATTR_CIDR])) return -IPSET_ERR_PROTOCOL; if (tb[IPSET_ATTR_LINENO]) @@ -362,20 +343,9 @@ hash_ip6_uadt(struct ip_set *set, struct nlattr *head, int len, /* Create hash:ip type of sets */ -static const struct nla_policy -hash_ip_create_policy[IPSET_ATTR_CREATE_MAX+1] = { - [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, - [IPSET_ATTR_MAXELEM] = { .type = NLA_U32 }, - [IPSET_ATTR_PROBES] = { .type = NLA_U8 }, - [IPSET_ATTR_RESIZE] = { .type = NLA_U8 }, - [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, - [IPSET_ATTR_NETMASK] = { .type = NLA_U8 }, -}; - static int -hash_ip_create(struct ip_set *set, struct nlattr *head, int len, u32 flags) +hash_ip_create(struct ip_set *set, struct nlattr *tb[], u32 flags) { - struct nlattr *tb[IPSET_ATTR_CREATE_MAX+1]; u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM; u8 netmask, hbits; struct ip_set_hash *h; @@ -386,10 +356,6 @@ hash_ip_create(struct ip_set *set, struct nlattr *head, int len, u32 flags) pr_debug("Create set %s with family %s\n", set->name, set->family == AF_INET ? "inet" : "inet6"); - if (nla_parse(tb, IPSET_ATTR_CREATE_MAX, head, len, - hash_ip_create_policy)) - return -IPSET_ERR_PROTOCOL; - if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) || !ip_set_optattr_netorder(tb, IPSET_ATTR_MAXELEM) || !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT))) @@ -425,8 +391,7 @@ hash_ip_create(struct ip_set *set, struct nlattr *head, int len, u32 flags) hbits = htable_bits(hashsize); h->table = ip_set_alloc( sizeof(struct htable) - + jhash_size(hbits) * sizeof(struct hbucket), - GFP_KERNEL); + + jhash_size(hbits) * sizeof(struct hbucket)); if (!h->table) { kfree(h); return -ENOMEM; @@ -465,6 +430,21 @@ static struct ip_set_type hash_ip_type __read_mostly = { .family = AF_UNSPEC, .revision = 0, .create = hash_ip_create, + .create_policy = { + [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, + [IPSET_ATTR_MAXELEM] = { .type = NLA_U32 }, + [IPSET_ATTR_PROBES] = { .type = NLA_U8 }, + [IPSET_ATTR_RESIZE] = { .type = NLA_U8 }, + [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, + [IPSET_ATTR_NETMASK] = { .type = NLA_U8 }, + }, + .adt_policy = { + [IPSET_ATTR_IP] = { .type = NLA_NESTED }, + [IPSET_ATTR_IP_TO] = { .type = NLA_NESTED }, + [IPSET_ATTR_CIDR] = { .type = NLA_U8 }, + [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, + [IPSET_ATTR_LINENO] = { .type = NLA_U32 }, + }, .me = THIS_MODULE, }; diff --git a/extensions/ipset-6/ip_set_hash_ipport.c b/extensions/ipset-6/ip_set_hash_ipport.c index 0ffc9fb..a2530e6 100644 --- a/extensions/ipset-6/ip_set_hash_ipport.c +++ b/extensions/ipset-6/ip_set_hash_ipport.c @@ -12,9 +12,6 @@ #include #include #include -#include -#include -#include #include #include #include @@ -144,34 +141,17 @@ hash_ipport4_kadt(struct ip_set *set, const struct sk_buff *skb, return adtfn(set, &data, h->timeout); } -static const struct nla_policy -hash_ipport_adt_policy[IPSET_ATTR_ADT_MAX + 1] = { - [IPSET_ATTR_IP] = { .type = NLA_NESTED }, - [IPSET_ATTR_IP_TO] = { .type = NLA_NESTED }, - [IPSET_ATTR_PORT] = { .type = NLA_U16 }, - [IPSET_ATTR_PORT_TO] = { .type = NLA_U16 }, - [IPSET_ATTR_CIDR] = { .type = NLA_U8 }, - [IPSET_ATTR_PROTO] = { .type = NLA_U8 }, - [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, - [IPSET_ATTR_LINENO] = { .type = NLA_U32 }, -}; - static int -hash_ipport4_uadt(struct ip_set *set, struct nlattr *head, int len, +hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[], enum ipset_adt adt, u32 *lineno, u32 flags) { const struct ip_set_hash *h = set->data; - struct nlattr *tb[IPSET_ATTR_ADT_MAX+1]; ipset_adtfn adtfn = set->variant->adt[adt]; struct hash_ipport4_elem data = { }; u32 ip, ip_to, p, port, port_to; u32 timeout = h->timeout; int ret; - if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len, - hash_ipport_adt_policy)) - return -IPSET_ERR_PROTOCOL; - if (unlikely(!tb[IPSET_ATTR_IP] || !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) || !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) || @@ -373,25 +353,22 @@ hash_ipport6_kadt(struct ip_set *set, const struct sk_buff *skb, } static int -hash_ipport6_uadt(struct ip_set *set, struct nlattr *head, int len, +hash_ipport6_uadt(struct ip_set *set, struct nlattr *tb[], enum ipset_adt adt, u32 *lineno, u32 flags) { const struct ip_set_hash *h = set->data; - struct nlattr *tb[IPSET_ATTR_ADT_MAX+1]; ipset_adtfn adtfn = set->variant->adt[adt]; struct hash_ipport6_elem data = { }; u32 port, port_to; u32 timeout = h->timeout; int ret; - if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len, - hash_ipport_adt_policy)) - return -IPSET_ERR_PROTOCOL; - if (unlikely(!tb[IPSET_ATTR_IP] || !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) || !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) || - !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT))) + !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || + tb[IPSET_ATTR_IP_TO] || + tb[IPSET_ATTR_CIDR])) return -IPSET_ERR_PROTOCOL; if (tb[IPSET_ATTR_LINENO]) @@ -456,20 +433,9 @@ hash_ipport6_uadt(struct ip_set *set, struct nlattr *head, int len, /* Create hash:ip type of sets */ -static const struct nla_policy -hash_ipport_create_policy[IPSET_ATTR_CREATE_MAX+1] = { - [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, - [IPSET_ATTR_MAXELEM] = { .type = NLA_U32 }, - [IPSET_ATTR_PROBES] = { .type = NLA_U8 }, - [IPSET_ATTR_RESIZE] = { .type = NLA_U8 }, - [IPSET_ATTR_PROTO] = { .type = NLA_U8 }, - [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, -}; - static int -hash_ipport_create(struct ip_set *set, struct nlattr *head, int len, u32 flags) +hash_ipport_create(struct ip_set *set, struct nlattr *tb[], u32 flags) { - struct nlattr *tb[IPSET_ATTR_CREATE_MAX+1]; struct ip_set_hash *h; u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM; u8 hbits; @@ -477,10 +443,6 @@ hash_ipport_create(struct ip_set *set, struct nlattr *head, int len, u32 flags) if (!(set->family == AF_INET || set->family == AF_INET6)) return -IPSET_ERR_INVALID_FAMILY; - if (nla_parse(tb, IPSET_ATTR_CREATE_MAX, head, len, - hash_ipport_create_policy)) - return -IPSET_ERR_PROTOCOL; - if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) || !ip_set_optattr_netorder(tb, IPSET_ATTR_MAXELEM) || !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT))) @@ -506,8 +468,7 @@ hash_ipport_create(struct ip_set *set, struct nlattr *head, int len, u32 flags) hbits = htable_bits(hashsize); h->table = ip_set_alloc( sizeof(struct htable) - + jhash_size(hbits) * sizeof(struct hbucket), - GFP_KERNEL); + + jhash_size(hbits) * sizeof(struct hbucket)); if (!h->table) { kfree(h); return -ENOMEM; @@ -546,6 +507,24 @@ static struct ip_set_type hash_ipport_type __read_mostly = { .family = AF_UNSPEC, .revision = 0, .create = hash_ipport_create, + .create_policy = { + [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, + [IPSET_ATTR_MAXELEM] = { .type = NLA_U32 }, + [IPSET_ATTR_PROBES] = { .type = NLA_U8 }, + [IPSET_ATTR_RESIZE] = { .type = NLA_U8 }, + [IPSET_ATTR_PROTO] = { .type = NLA_U8 }, + [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, + }, + .adt_policy = { + [IPSET_ATTR_IP] = { .type = NLA_NESTED }, + [IPSET_ATTR_IP_TO] = { .type = NLA_NESTED }, + [IPSET_ATTR_PORT] = { .type = NLA_U16 }, + [IPSET_ATTR_PORT_TO] = { .type = NLA_U16 }, + [IPSET_ATTR_CIDR] = { .type = NLA_U8 }, + [IPSET_ATTR_PROTO] = { .type = NLA_U8 }, + [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, + [IPSET_ATTR_LINENO] = { .type = NLA_U32 }, + }, .me = THIS_MODULE, }; diff --git a/extensions/ipset-6/ip_set_hash_ipportip.c b/extensions/ipset-6/ip_set_hash_ipportip.c index 5063775..a6d1797 100644 --- a/extensions/ipset-6/ip_set_hash_ipportip.c +++ b/extensions/ipset-6/ip_set_hash_ipportip.c @@ -12,9 +12,6 @@ #include #include #include -#include -#include -#include #include #include #include @@ -148,35 +145,17 @@ hash_ipportip4_kadt(struct ip_set *set, const struct sk_buff *skb, return adtfn(set, &data, h->timeout); } -static const struct nla_policy -hash_ipportip_adt_policy[IPSET_ATTR_ADT_MAX + 1] = { - [IPSET_ATTR_IP] = { .type = NLA_NESTED }, - [IPSET_ATTR_IP_TO] = { .type = NLA_NESTED }, - [IPSET_ATTR_IP2] = { .type = NLA_NESTED }, - [IPSET_ATTR_PORT] = { .type = NLA_U16 }, - [IPSET_ATTR_PORT_TO] = { .type = NLA_U16 }, - [IPSET_ATTR_CIDR] = { .type = NLA_U8 }, - [IPSET_ATTR_PROTO] = { .type = NLA_U8 }, - [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, - [IPSET_ATTR_LINENO] = { .type = NLA_U32 }, -}; - static int -hash_ipportip4_uadt(struct ip_set *set, struct nlattr *head, int len, +hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[], enum ipset_adt adt, u32 *lineno, u32 flags) { const struct ip_set_hash *h = set->data; - struct nlattr *tb[IPSET_ATTR_ADT_MAX+1]; ipset_adtfn adtfn = set->variant->adt[adt]; struct hash_ipportip4_elem data = { }; u32 ip, ip_to, p, port, port_to; u32 timeout = h->timeout; int ret; - if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len, - hash_ipportip_adt_policy)) - return -IPSET_ERR_PROTOCOL; - if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] || !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) || !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) || @@ -388,25 +367,22 @@ hash_ipportip6_kadt(struct ip_set *set, const struct sk_buff *skb, } static int -hash_ipportip6_uadt(struct ip_set *set, struct nlattr *head, int len, +hash_ipportip6_uadt(struct ip_set *set, struct nlattr *tb[], enum ipset_adt adt, u32 *lineno, u32 flags) { const struct ip_set_hash *h = set->data; - struct nlattr *tb[IPSET_ATTR_ADT_MAX+1]; ipset_adtfn adtfn = set->variant->adt[adt]; struct hash_ipportip6_elem data = { }; u32 port, port_to; u32 timeout = h->timeout; int ret; - if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len, - hash_ipportip_adt_policy)) - return -IPSET_ERR_PROTOCOL; - if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] || !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) || !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) || - !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT))) + !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || + tb[IPSET_ATTR_IP_TO] || + tb[IPSET_ATTR_CIDR])) return -IPSET_ERR_PROTOCOL; if (tb[IPSET_ATTR_LINENO]) @@ -475,20 +451,9 @@ hash_ipportip6_uadt(struct ip_set *set, struct nlattr *head, int len, /* Create hash:ip type of sets */ -static const struct nla_policy -hash_ipportip_create_policy[IPSET_ATTR_CREATE_MAX+1] = { - [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, - [IPSET_ATTR_MAXELEM] = { .type = NLA_U32 }, - [IPSET_ATTR_PROBES] = { .type = NLA_U8 }, - [IPSET_ATTR_RESIZE] = { .type = NLA_U8 }, - [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, -}; - static int -hash_ipportip_create(struct ip_set *set, struct nlattr *head, - int len, u32 flags) +hash_ipportip_create(struct ip_set *set, struct nlattr *tb[], u32 flags) { - struct nlattr *tb[IPSET_ATTR_CREATE_MAX+1]; struct ip_set_hash *h; u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM; u8 hbits; @@ -496,10 +461,6 @@ hash_ipportip_create(struct ip_set *set, struct nlattr *head, if (!(set->family == AF_INET || set->family == AF_INET6)) return -IPSET_ERR_INVALID_FAMILY; - if (nla_parse(tb, IPSET_ATTR_CREATE_MAX, head, len, - hash_ipportip_create_policy)) - return -IPSET_ERR_PROTOCOL; - if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) || !ip_set_optattr_netorder(tb, IPSET_ATTR_MAXELEM) || !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT))) @@ -525,8 +486,7 @@ hash_ipportip_create(struct ip_set *set, struct nlattr *head, hbits = htable_bits(hashsize); h->table = ip_set_alloc( sizeof(struct htable) - + jhash_size(hbits) * sizeof(struct hbucket), - GFP_KERNEL); + + jhash_size(hbits) * sizeof(struct hbucket)); if (!h->table) { kfree(h); return -ENOMEM; @@ -565,6 +525,24 @@ static struct ip_set_type hash_ipportip_type __read_mostly = { .family = AF_UNSPEC, .revision = 0, .create = hash_ipportip_create, + .create_policy = { + [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, + [IPSET_ATTR_MAXELEM] = { .type = NLA_U32 }, + [IPSET_ATTR_PROBES] = { .type = NLA_U8 }, + [IPSET_ATTR_RESIZE] = { .type = NLA_U8 }, + [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, + }, + .adt_policy = { + [IPSET_ATTR_IP] = { .type = NLA_NESTED }, + [IPSET_ATTR_IP_TO] = { .type = NLA_NESTED }, + [IPSET_ATTR_IP2] = { .type = NLA_NESTED }, + [IPSET_ATTR_PORT] = { .type = NLA_U16 }, + [IPSET_ATTR_PORT_TO] = { .type = NLA_U16 }, + [IPSET_ATTR_CIDR] = { .type = NLA_U8 }, + [IPSET_ATTR_PROTO] = { .type = NLA_U8 }, + [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, + [IPSET_ATTR_LINENO] = { .type = NLA_U32 }, + }, .me = THIS_MODULE, }; diff --git a/extensions/ipset-6/ip_set_hash_ipportnet.c b/extensions/ipset-6/ip_set_hash_ipportnet.c index 85fa6c7..258eeb9 100644 --- a/extensions/ipset-6/ip_set_hash_ipportnet.c +++ b/extensions/ipset-6/ip_set_hash_ipportnet.c @@ -12,9 +12,6 @@ #include #include #include -#include -#include -#include #include #include #include @@ -168,36 +165,17 @@ hash_ipportnet4_kadt(struct ip_set *set, const struct sk_buff *skb, return adtfn(set, &data, h->timeout); } -static const struct nla_policy -hash_ipportnet_adt_policy[IPSET_ATTR_ADT_MAX + 1] = { - [IPSET_ATTR_IP] = { .type = NLA_NESTED }, - [IPSET_ATTR_IP_TO] = { .type = NLA_NESTED }, - [IPSET_ATTR_IP2] = { .type = NLA_NESTED }, - [IPSET_ATTR_PORT] = { .type = NLA_U16 }, - [IPSET_ATTR_PORT_TO] = { .type = NLA_U16 }, - [IPSET_ATTR_CIDR] = { .type = NLA_U8 }, - [IPSET_ATTR_CIDR2] = { .type = NLA_U8 }, - [IPSET_ATTR_PROTO] = { .type = NLA_U8 }, - [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, - [IPSET_ATTR_LINENO] = { .type = NLA_U32 }, -}; - static int -hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *head, int len, +hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[], enum ipset_adt adt, u32 *lineno, u32 flags) { const struct ip_set_hash *h = set->data; - struct nlattr *tb[IPSET_ATTR_ADT_MAX+1]; ipset_adtfn adtfn = set->variant->adt[adt]; struct hash_ipportnet4_elem data = { .cidr = HOST_MASK }; u32 ip, ip_to, p, port, port_to; u32 timeout = h->timeout; int ret; - if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len, - hash_ipportnet_adt_policy)) - return -IPSET_ERR_PROTOCOL; - if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] || !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) || !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) || @@ -443,25 +421,22 @@ hash_ipportnet6_kadt(struct ip_set *set, const struct sk_buff *skb, } static int -hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *head, int len, +hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[], enum ipset_adt adt, u32 *lineno, u32 flags) { const struct ip_set_hash *h = set->data; - struct nlattr *tb[IPSET_ATTR_ADT_MAX+1]; ipset_adtfn adtfn = set->variant->adt[adt]; struct hash_ipportnet6_elem data = { .cidr = HOST_MASK }; u32 port, port_to; u32 timeout = h->timeout; int ret; - if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len, - hash_ipportnet_adt_policy)) - return -IPSET_ERR_PROTOCOL; - if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] || !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) || !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) || - !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT))) + !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || + tb[IPSET_ATTR_IP_TO] || + tb[IPSET_ATTR_CIDR])) return -IPSET_ERR_PROTOCOL; if (tb[IPSET_ATTR_LINENO]) @@ -538,20 +513,9 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *head, int len, /* Create hash:ip type of sets */ -static const struct nla_policy -hash_ipportnet_create_policy[IPSET_ATTR_CREATE_MAX+1] = { - [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, - [IPSET_ATTR_MAXELEM] = { .type = NLA_U32 }, - [IPSET_ATTR_PROBES] = { .type = NLA_U8 }, - [IPSET_ATTR_RESIZE] = { .type = NLA_U8 }, - [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, -}; - static int -hash_ipportnet_create(struct ip_set *set, struct nlattr *head, - int len, u32 flags) +hash_ipportnet_create(struct ip_set *set, struct nlattr *tb[], u32 flags) { - struct nlattr *tb[IPSET_ATTR_CREATE_MAX+1]; struct ip_set_hash *h; u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM; u8 hbits; @@ -559,10 +523,6 @@ hash_ipportnet_create(struct ip_set *set, struct nlattr *head, if (!(set->family == AF_INET || set->family == AF_INET6)) return -IPSET_ERR_INVALID_FAMILY; - if (nla_parse(tb, IPSET_ATTR_CREATE_MAX, head, len, - hash_ipportnet_create_policy)) - return -IPSET_ERR_PROTOCOL; - if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) || !ip_set_optattr_netorder(tb, IPSET_ATTR_MAXELEM) || !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT))) @@ -590,8 +550,7 @@ hash_ipportnet_create(struct ip_set *set, struct nlattr *head, hbits = htable_bits(hashsize); h->table = ip_set_alloc( sizeof(struct htable) - + jhash_size(hbits) * sizeof(struct hbucket), - GFP_KERNEL); + + jhash_size(hbits) * sizeof(struct hbucket)); if (!h->table) { kfree(h); return -ENOMEM; @@ -631,6 +590,25 @@ static struct ip_set_type hash_ipportnet_type __read_mostly = { .family = AF_UNSPEC, .revision = 0, .create = hash_ipportnet_create, + .create_policy = { + [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, + [IPSET_ATTR_MAXELEM] = { .type = NLA_U32 }, + [IPSET_ATTR_PROBES] = { .type = NLA_U8 }, + [IPSET_ATTR_RESIZE] = { .type = NLA_U8 }, + [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, + }, + .adt_policy = { + [IPSET_ATTR_IP] = { .type = NLA_NESTED }, + [IPSET_ATTR_IP_TO] = { .type = NLA_NESTED }, + [IPSET_ATTR_IP2] = { .type = NLA_NESTED }, + [IPSET_ATTR_PORT] = { .type = NLA_U16 }, + [IPSET_ATTR_PORT_TO] = { .type = NLA_U16 }, + [IPSET_ATTR_CIDR] = { .type = NLA_U8 }, + [IPSET_ATTR_CIDR2] = { .type = NLA_U8 }, + [IPSET_ATTR_PROTO] = { .type = NLA_U8 }, + [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, + [IPSET_ATTR_LINENO] = { .type = NLA_U32 }, + }, .me = THIS_MODULE, }; diff --git a/extensions/ipset-6/ip_set_hash_net.c b/extensions/ipset-6/ip_set_hash_net.c index 7f01112..c5d0722 100644 --- a/extensions/ipset-6/ip_set_hash_net.c +++ b/extensions/ipset-6/ip_set_hash_net.c @@ -12,9 +12,6 @@ #include #include #include -#include -#include -#include #include #include #include @@ -147,27 +144,16 @@ hash_net4_kadt(struct ip_set *set, const struct sk_buff *skb, return adtfn(set, &data, h->timeout); } -static const struct nla_policy hash_net_adt_policy[IPSET_ATTR_ADT_MAX + 1] = { - [IPSET_ATTR_IP] = { .type = NLA_NESTED }, - [IPSET_ATTR_CIDR] = { .type = NLA_U8 }, - [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, -}; - static int -hash_net4_uadt(struct ip_set *set, struct nlattr *head, int len, +hash_net4_uadt(struct ip_set *set, struct nlattr *tb[], enum ipset_adt adt, u32 *lineno, u32 flags) { const struct ip_set_hash *h = set->data; - struct nlattr *tb[IPSET_ATTR_ADT_MAX+1]; ipset_adtfn adtfn = set->variant->adt[adt]; struct hash_net4_elem data = { .cidr = HOST_MASK }; u32 timeout = h->timeout; int ret; - if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len, - hash_net_adt_policy)) - return -IPSET_ERR_PROTOCOL; - if (unlikely(!tb[IPSET_ATTR_IP] || !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT))) return -IPSET_ERR_PROTOCOL; @@ -324,20 +310,15 @@ hash_net6_kadt(struct ip_set *set, const struct sk_buff *skb, } static int -hash_net6_uadt(struct ip_set *set, struct nlattr *head, int len, +hash_net6_uadt(struct ip_set *set, struct nlattr *tb[], enum ipset_adt adt, u32 *lineno, u32 flags) { const struct ip_set_hash *h = set->data; - struct nlattr *tb[IPSET_ATTR_ADT_MAX+1]; ipset_adtfn adtfn = set->variant->adt[adt]; struct hash_net6_elem data = { .cidr = HOST_MASK }; u32 timeout = h->timeout; int ret; - if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len, - hash_net_adt_policy)) - return -IPSET_ERR_PROTOCOL; - if (unlikely(!tb[IPSET_ATTR_IP] || !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT))) return -IPSET_ERR_PROTOCOL; @@ -370,19 +351,9 @@ hash_net6_uadt(struct ip_set *set, struct nlattr *head, int len, /* Create hash:ip type of sets */ -static const struct nla_policy -hash_net_create_policy[IPSET_ATTR_CREATE_MAX+1] = { - [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, - [IPSET_ATTR_MAXELEM] = { .type = NLA_U32 }, - [IPSET_ATTR_PROBES] = { .type = NLA_U8 }, - [IPSET_ATTR_RESIZE] = { .type = NLA_U8 }, - [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, -}; - static int -hash_net_create(struct ip_set *set, struct nlattr *head, int len, u32 flags) +hash_net_create(struct ip_set *set, struct nlattr *tb[], u32 flags) { - struct nlattr *tb[IPSET_ATTR_CREATE_MAX+1]; u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM; struct ip_set_hash *h; u8 hbits; @@ -390,10 +361,6 @@ hash_net_create(struct ip_set *set, struct nlattr *head, int len, u32 flags) if (!(set->family == AF_INET || set->family == AF_INET6)) return -IPSET_ERR_INVALID_FAMILY; - if (nla_parse(tb, IPSET_ATTR_CREATE_MAX, head, len, - hash_net_create_policy)) - return -IPSET_ERR_PROTOCOL; - if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) || !ip_set_optattr_netorder(tb, IPSET_ATTR_MAXELEM) || !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT))) @@ -421,8 +388,7 @@ hash_net_create(struct ip_set *set, struct nlattr *head, int len, u32 flags) hbits = htable_bits(hashsize); h->table = ip_set_alloc( sizeof(struct htable) - + jhash_size(hbits) * sizeof(struct hbucket), - GFP_KERNEL); + + jhash_size(hbits) * sizeof(struct hbucket)); if (!h->table) { kfree(h); return -ENOMEM; @@ -461,6 +427,18 @@ static struct ip_set_type hash_net_type __read_mostly = { .family = AF_UNSPEC, .revision = 0, .create = hash_net_create, + .create_policy = { + [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, + [IPSET_ATTR_MAXELEM] = { .type = NLA_U32 }, + [IPSET_ATTR_PROBES] = { .type = NLA_U8 }, + [IPSET_ATTR_RESIZE] = { .type = NLA_U8 }, + [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, + }, + .adt_policy = { + [IPSET_ATTR_IP] = { .type = NLA_NESTED }, + [IPSET_ATTR_CIDR] = { .type = NLA_U8 }, + [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, + }, .me = THIS_MODULE, }; diff --git a/extensions/ipset-6/ip_set_hash_netport.c b/extensions/ipset-6/ip_set_hash_netport.c index 6e86b62..249c5b3 100644 --- a/extensions/ipset-6/ip_set_hash_netport.c +++ b/extensions/ipset-6/ip_set_hash_netport.c @@ -12,9 +12,6 @@ #include #include #include -#include -#include -#include #include #include #include @@ -164,33 +161,17 @@ hash_netport4_kadt(struct ip_set *set, const struct sk_buff *skb, return adtfn(set, &data, h->timeout); } -static const struct nla_policy -hash_netport_adt_policy[IPSET_ATTR_ADT_MAX + 1] = { - [IPSET_ATTR_IP] = { .type = NLA_NESTED }, - [IPSET_ATTR_PORT] = { .type = NLA_U16 }, - [IPSET_ATTR_PORT_TO] = { .type = NLA_U16 }, - [IPSET_ATTR_PROTO] = { .type = NLA_U8 }, - [IPSET_ATTR_CIDR] = { .type = NLA_U8 }, - [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, - [IPSET_ATTR_LINENO] = { .type = NLA_U32 }, -}; - static int -hash_netport4_uadt(struct ip_set *set, struct nlattr *head, int len, +hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[], enum ipset_adt adt, u32 *lineno, u32 flags) { const struct ip_set_hash *h = set->data; - struct nlattr *tb[IPSET_ATTR_ADT_MAX+1]; ipset_adtfn adtfn = set->variant->adt[adt]; struct hash_netport4_elem data = { .cidr = HOST_MASK }; u32 port, port_to; u32 timeout = h->timeout; int ret; - if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len, - hash_netport_adt_policy)) - return -IPSET_ERR_PROTOCOL; - if (unlikely(!tb[IPSET_ATTR_IP] || !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) || !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) || @@ -401,21 +382,16 @@ hash_netport6_kadt(struct ip_set *set, const struct sk_buff *skb, } static int -hash_netport6_uadt(struct ip_set *set, struct nlattr *head, int len, +hash_netport6_uadt(struct ip_set *set, struct nlattr *tb[], enum ipset_adt adt, u32 *lineno, u32 flags) { const struct ip_set_hash *h = set->data; - struct nlattr *tb[IPSET_ATTR_ADT_MAX+1]; ipset_adtfn adtfn = set->variant->adt[adt]; struct hash_netport6_elem data = { .cidr = HOST_MASK }; u32 port, port_to; u32 timeout = h->timeout; int ret; - if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len, - hash_netport_adt_policy)) - return -IPSET_ERR_PROTOCOL; - if (unlikely(!tb[IPSET_ATTR_IP] || !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) || !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) || @@ -490,20 +466,9 @@ hash_netport6_uadt(struct ip_set *set, struct nlattr *head, int len, /* Create hash:ip type of sets */ -static const struct nla_policy -hash_netport_create_policy[IPSET_ATTR_CREATE_MAX+1] = { - [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, - [IPSET_ATTR_MAXELEM] = { .type = NLA_U32 }, - [IPSET_ATTR_PROBES] = { .type = NLA_U8 }, - [IPSET_ATTR_RESIZE] = { .type = NLA_U8 }, - [IPSET_ATTR_PROTO] = { .type = NLA_U8 }, - [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, -}; - static int -hash_netport_create(struct ip_set *set, struct nlattr *head, int len, u32 flags) +hash_netport_create(struct ip_set *set, struct nlattr *tb[], u32 flags) { - struct nlattr *tb[IPSET_ATTR_CREATE_MAX+1]; struct ip_set_hash *h; u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM; u8 hbits; @@ -511,10 +476,6 @@ hash_netport_create(struct ip_set *set, struct nlattr *head, int len, u32 flags) if (!(set->family == AF_INET || set->family == AF_INET6)) return -IPSET_ERR_INVALID_FAMILY; - if (nla_parse(tb, IPSET_ATTR_CREATE_MAX, head, len, - hash_netport_create_policy)) - return -IPSET_ERR_PROTOCOL; - if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) || !ip_set_optattr_netorder(tb, IPSET_ATTR_MAXELEM) || !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT))) @@ -542,8 +503,7 @@ hash_netport_create(struct ip_set *set, struct nlattr *head, int len, u32 flags) hbits = htable_bits(hashsize); h->table = ip_set_alloc( sizeof(struct htable) - + jhash_size(hbits) * sizeof(struct hbucket), - GFP_KERNEL); + + jhash_size(hbits) * sizeof(struct hbucket)); if (!h->table) { kfree(h); return -ENOMEM; @@ -582,6 +542,23 @@ static struct ip_set_type hash_netport_type __read_mostly = { .family = AF_UNSPEC, .revision = 0, .create = hash_netport_create, + .create_policy = { + [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, + [IPSET_ATTR_MAXELEM] = { .type = NLA_U32 }, + [IPSET_ATTR_PROBES] = { .type = NLA_U8 }, + [IPSET_ATTR_RESIZE] = { .type = NLA_U8 }, + [IPSET_ATTR_PROTO] = { .type = NLA_U8 }, + [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, + }, + .adt_policy = { + [IPSET_ATTR_IP] = { .type = NLA_NESTED }, + [IPSET_ATTR_PORT] = { .type = NLA_U16 }, + [IPSET_ATTR_PORT_TO] = { .type = NLA_U16 }, + [IPSET_ATTR_PROTO] = { .type = NLA_U8 }, + [IPSET_ATTR_CIDR] = { .type = NLA_U8 }, + [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, + [IPSET_ATTR_LINENO] = { .type = NLA_U32 }, + }, .me = THIS_MODULE, }; diff --git a/extensions/ipset-6/ip_set_list_set.c b/extensions/ipset-6/ip_set_list_set.c index 398adc4..7fc98ff 100644 --- a/extensions/ipset-6/ip_set_list_set.c +++ b/extensions/ipset-6/ip_set_list_set.c @@ -111,16 +111,6 @@ list_set_kadt(struct ip_set *set, const struct sk_buff *skb, return -EINVAL; } -static const struct nla_policy list_set_adt_policy[IPSET_ATTR_ADT_MAX+1] = { - [IPSET_ATTR_NAME] = { .type = NLA_STRING, - .len = IPSET_MAXNAMELEN }, - [IPSET_ATTR_NAMEREF] = { .type = NLA_STRING, - .len = IPSET_MAXNAMELEN }, - [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, - [IPSET_ATTR_LINENO] = { .type = NLA_U32 }, - [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 }, -}; - static bool next_id_eq(const struct list_set *map, u32 i, ip_set_id_t id) { @@ -204,11 +194,10 @@ list_set_del(struct list_set *map, ip_set_id_t id, u32 i) } static int -list_set_uadt(struct ip_set *set, struct nlattr *head, int len, +list_set_uadt(struct ip_set *set, struct nlattr *tb[], enum ipset_adt adt, u32 *lineno, u32 flags) { struct list_set *map = set->data; - struct nlattr *tb[IPSET_ATTR_ADT_MAX+1]; bool with_timeout = with_timeout(map->timeout); int before = 0; u32 timeout = map->timeout; @@ -218,10 +207,6 @@ list_set_uadt(struct ip_set *set, struct nlattr *head, int len, u32 i; int ret = 0; - if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len, - list_set_adt_policy)) - return -IPSET_ERR_PROTOCOL; - if (unlikely(!tb[IPSET_ATTR_NAME] || !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS))) @@ -392,7 +377,7 @@ list_set_head(struct ip_set *set, struct sk_buff *skb) return 0; nla_put_failure: - return -EFAULT; + return -EMSGSIZE; } static int @@ -406,7 +391,7 @@ list_set_list(const struct ip_set *set, atd = ipset_nest_start(skb, IPSET_ATTR_ADT); if (!atd) - return -EFAULT; + return -EMSGSIZE; for (; cb->args[2] < map->size; cb->args[2]++) { i = cb->args[2]; e = list_set_elem(map, i); @@ -418,7 +403,7 @@ list_set_list(const struct ip_set *set, if (!nested) { if (i == first) { nla_nest_cancel(skb, atd); - return -EFAULT; + return -EMSGSIZE; } else goto nla_put_failure; } @@ -441,6 +426,10 @@ finish: nla_put_failure: nla_nest_cancel(skb, nested); ipset_nest_end(skb, atd); + if (unlikely(i == first)) { + cb->args[2] = 0; + return -EMSGSIZE; + } return 0; } @@ -501,12 +490,6 @@ list_set_gc_init(struct ip_set *set) /* Create list:set type of sets */ -static const struct nla_policy -list_set_create_policy[IPSET_ATTR_CREATE_MAX+1] = { - [IPSET_ATTR_SIZE] = { .type = NLA_U32 }, - [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, -}; - static bool init_list_set(struct ip_set *set, u32 size, size_t dsize, unsigned long timeout) @@ -533,16 +516,10 @@ init_list_set(struct ip_set *set, u32 size, size_t dsize, } static int -list_set_create(struct ip_set *set, struct nlattr *head, int len, - u32 flags) +list_set_create(struct ip_set *set, struct nlattr *tb[], u32 flags) { - struct nlattr *tb[IPSET_ATTR_CREATE_MAX+1]; u32 size = IP_SET_LIST_DEFAULT_SIZE; - if (nla_parse(tb, IPSET_ATTR_CREATE_MAX, head, len, - list_set_create_policy)) - return -IPSET_ERR_PROTOCOL; - if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_SIZE) || !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT))) return -IPSET_ERR_PROTOCOL; @@ -575,6 +552,19 @@ static struct ip_set_type list_set_type __read_mostly = { .family = AF_UNSPEC, .revision = 0, .create = list_set_create, + .create_policy = { + [IPSET_ATTR_SIZE] = { .type = NLA_U32 }, + [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, + }, + .adt_policy = { + [IPSET_ATTR_NAME] = { .type = NLA_STRING, + .len = IPSET_MAXNAMELEN }, + [IPSET_ATTR_NAMEREF] = { .type = NLA_STRING, + .len = IPSET_MAXNAMELEN }, + [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, + [IPSET_ATTR_LINENO] = { .type = NLA_U32 }, + [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 }, + }, .me = THIS_MODULE, }; diff --git a/extensions/ipset-6/libipset/mnl.c b/extensions/ipset-6/libipset/mnl.c index 9d1b630..91a5ee4 100644 --- a/extensions/ipset-6/libipset/mnl.c +++ b/extensions/ipset-6/libipset/mnl.c @@ -43,8 +43,8 @@ static const uint16_t cmdflags[] = { [IPSET_CMD_FLUSH-1] = NLM_F_REQUEST|NLM_F_ACK, [IPSET_CMD_RENAME-1] = NLM_F_REQUEST|NLM_F_ACK, [IPSET_CMD_SWAP-1] = NLM_F_REQUEST|NLM_F_ACK, - [IPSET_CMD_LIST-1] = NLM_F_REQUEST, - [IPSET_CMD_SAVE-1] = NLM_F_REQUEST, + [IPSET_CMD_LIST-1] = NLM_F_REQUEST|NLM_F_ACK, + [IPSET_CMD_SAVE-1] = NLM_F_REQUEST|NLM_F_ACK, [IPSET_CMD_ADD-1] = NLM_F_REQUEST|NLM_F_ACK|NLM_F_EXCL, [IPSET_CMD_DEL-1] = NLM_F_REQUEST|NLM_F_ACK|NLM_F_EXCL, [IPSET_CMD_TEST-1] = NLM_F_REQUEST|NLM_F_ACK, @@ -83,7 +83,7 @@ ipset_mnl_fill_hdr(struct ipset_handle *handle, enum ipset_cmd cmd, nlh->nlmsg_flags = NLM_F_REQUEST; if (cmdflags[cmd-1] & NLM_F_ACK) nlh->nlmsg_flags |= NLM_F_ACK; - nlh->nlmsg_seq = handle->seq = time(NULL); + nlh->nlmsg_seq = ++handle->seq; ghdr = mnl_nlmsg_put_extra_header(nlh, sizeof(struct genlmsghdr)); ghdr->cmd = cmd; @@ -225,6 +225,7 @@ ipset_mnl_init(mnl_cb_t *cb_ctl, void *data) handle->portid = mnl_socket_get_portid(handle->h); handle->cb_ctl = cb_ctl; handle->data = data; + handle->seq = time(NULL); if (ipset_mnl_getid(handle, false) < 0) goto close_nl; diff --git a/extensions/ipset-6/libipset/parse.c b/extensions/ipset-6/libipset/parse.c index e998df5..cd1ad32 100644 --- a/extensions/ipset-6/libipset/parse.c +++ b/extensions/ipset-6/libipset/parse.c @@ -1416,15 +1416,14 @@ ipset_parse_ignored(struct ipset_session *session, */ int ipset_call_parser(struct ipset_session *session, - ipset_parsefn parse, const char *optstr, - enum ipset_opt opt, const char *str) + const struct ipset_arg *arg, + const char *str) { if (ipset_data_flags_test(ipset_session_data(session), - IPSET_FLAG(opt))) - syntax_err("%s already specified", optstr); + IPSET_FLAG(arg->opt))) + syntax_err("%s already specified", arg->name[0]); - return parse(session, opt, parse == ipset_parse_ignored - ? optstr : str); + return arg->parse(session, arg->opt, str); } #define parse_elem(s, t, d, str) \ diff --git a/extensions/ipset-6/libipset/print.c b/extensions/ipset-6/libipset/print.c index 7ec786f..5284b0a 100644 --- a/extensions/ipset-6/libipset/print.c +++ b/extensions/ipset-6/libipset/print.c @@ -158,7 +158,8 @@ __getnameinfo##f(char *buf, unsigned int len, \ sizeof(saddr), \ buf, len, NULL, 0, flags); \ \ - if (err == EAI_AGAIN && !(flags & NI_NUMERICHOST)) \ + if (!(flags & NI_NUMERICHOST) && \ + (err == EAI_AGAIN || (err == 0 && strchr(buf, '-') != NULL))) \ err = getnameinfo((const struct sockaddr *)&saddr, \ sizeof(saddr), \ buf, len, NULL, 0, \ @@ -229,7 +230,7 @@ ipset_print_ip(char *buf, unsigned int len, D("CIDR: %u", cidr); } else cidr = family == AF_INET6 ? 128 : 32; - flags = env & (1 << IPSET_ENV_RESOLVE) ? 0 : NI_NUMERICHOST; + flags = (env & IPSET_ENV_RESOLVE) ? 0 : NI_NUMERICHOST; ip = ipset_data_get(data, opt); assert(ip); @@ -296,7 +297,7 @@ ipset_print_ipaddr(char *buf, unsigned int len, cidr = *(const uint8_t *) ipset_data_get(data, cidropt); else cidr = family == AF_INET6 ? 128 : 32; - flags = env & (1 << IPSET_ENV_RESOLVE) ? 0 : NI_NUMERICHOST; + flags = (env & IPSET_ENV_RESOLVE) ? 0 : NI_NUMERICHOST; ip = ipset_data_get(data, opt); assert(ip); diff --git a/extensions/ipset-6/libipset/types.c b/extensions/ipset-6/libipset/types.c index 69dac6a..5eb53c4 100644 --- a/extensions/ipset-6/libipset/types.c +++ b/extensions/ipset-6/libipset/types.c @@ -441,13 +441,15 @@ ipset_type_add(struct ipset_type *type) assert(type); + if (strlen(type->name) > IPSET_MAXNAMELEN - 1) + return -EINVAL; + /* Add to the list: higher revision numbers first */ for (t = typelist, prev = NULL; t != NULL; t = t->next) { if (STREQ(t->name, type->name)) { - if (t->revision == type->revision) { - errno = EEXIST; - return -1; - } else if (t->revision < type->revision) { + if (t->revision == type->revision) + return -EEXIST; + else if (t->revision < type->revision) { type->next = t; if (prev) prev->next = type; @@ -457,10 +459,9 @@ ipset_type_add(struct ipset_type *type) } } if (t->next != NULL && STREQ(t->next->name, type->name)) { - if (t->next->revision == type->revision) { - errno = EEXIST; - return -1; - } else if (t->next->revision < type->revision) { + if (t->next->revision == type->revision) + return -EEXIST; + else if (t->next->revision < type->revision) { type->next = t->next; t->next = type; return 0; diff --git a/extensions/ipset-6/src/errcode.c b/extensions/ipset-6/src/errcode.c index 313c500..6370ec7 100644 --- a/extensions/ipset-6/src/errcode.c +++ b/extensions/ipset-6/src/errcode.c @@ -21,8 +21,10 @@ /* Core kernel error codes */ static const struct ipset_errcode_table core_errcode_table[] = { /* Generic error codes */ - { EEXIST, 0, + { ENOENT, 0, "The set with the given name does not exist" }, + { EMSGSIZE, 0, + "Kernel error received: message could not be created" }, { IPSET_ERR_PROTOCOL, 0, "Kernel error received: ipset protocol error" }, @@ -30,14 +32,14 @@ static const struct ipset_errcode_table core_errcode_table[] = { { EEXIST, IPSET_CMD_CREATE, "Set cannot be created: set with the same name already exists" }, { IPSET_ERR_FIND_TYPE, 0, - "Kernel error received: set type does not supported" }, + "Kernel error received: set type not supported" }, { IPSET_ERR_MAX_SETS, 0, "Kernel error received: maximal number of sets reached, " "cannot create more." }, { IPSET_ERR_INVALID_NETMASK, 0, "The value of the netmask parameter is invalid" }, { IPSET_ERR_INVALID_FAMILY, 0, - "The protocol family not supported by the set type" }, + "Protocol family not supported by the set type" }, /* DESTROY specific error codes */ { IPSET_ERR_BUSY, IPSET_CMD_DESTROY, diff --git a/extensions/ipset-6/src/ipset.c b/extensions/ipset-6/src/ipset.c index 8ed3e10..05f8ef3 100644 --- a/extensions/ipset-6/src/ipset.c +++ b/extensions/ipset-6/src/ipset.c @@ -206,62 +206,54 @@ restore(char *argv0) static int call_parser(int *argc, char *argv[], const struct ipset_arg *args) { - int i = 1, ret = 0; + int ret = 0; const struct ipset_arg *arg; const char *optstr; /* Currently CREATE and ADT may have got additional arguments */ - if (!args) - goto done; - for (arg = args; arg->opt; arg++) { - for (i = 1; i < *argc; ) { - D("argc: %u, i: %u: %s vs %s", - *argc, i, argv[i], arg->name[0]); - if (!(ipset_match_option(argv[i], arg->name))) { - i++; + if (!args && *argc > 1) + goto err_unknown; + while (*argc > 1) { + for (arg = args; arg->opt; arg++) { + D("argc: %u, %s vs %s", *argc, argv[1], arg->name[0]); + if (!(ipset_match_option(argv[1], arg->name))) continue; - } - optstr = argv[i]; + + optstr = argv[1]; /* Shift off matched option */ D("match %s", arg->name[0]); - ipset_shift_argv(argc, argv, i); - D("argc: %u, i: %u", *argc, i); + ipset_shift_argv(argc, argv, 1); switch (arg->has_arg) { case IPSET_MANDATORY_ARG: - if (i + 1 > *argc) + if (*argc < 2) return exit_error(PARAMETER_PROBLEM, "Missing mandatory argument " "of option `%s'", arg->name[0]); /* Fall through */ case IPSET_OPTIONAL_ARG: - if (i + 1 <= *argc) { - ret = ipset_call_parser(session, - arg->parse, - optstr, arg->opt, - argv[i]); + if (*argc >= 2) { + ret = ipset_call_parser(session, arg, argv[1]); if (ret < 0) return ret; - ipset_shift_argv(argc, argv, i); + ipset_shift_argv(argc, argv, 1); break; } /* Fall through */ default: - ret = ipset_call_parser(session, - arg->parse, - optstr, arg->opt, - optstr); + ret = ipset_call_parser(session, arg, optstr); if (ret < 0) return ret; } + break; } + if (!arg->opt) + goto err_unknown; } -done: - if (i < *argc) - return exit_error(PARAMETER_PROBLEM, - "Unknown argument: `%s'", - argv[i]); return ret; + +err_unknown: + return exit_error(PARAMETER_PROBLEM, "Unknown argument: `%s'", argv[1]); } static enum ipset_adt @@ -476,61 +468,57 @@ parse_commandline(int argc, char *argv[]) /* Second: parse command */ for (command = ipset_commands; - command->cmd && cmd == IPSET_CMD_NONE; + argc > 1 && command->cmd && cmd == IPSET_CMD_NONE; command++) { - for (i = 1; i < argc; ) { - if (!ipset_match_cmd(argv[1], command->name)) { - i++; - continue; - } - if (restore_line != 0 - && (command->cmd == IPSET_CMD_RESTORE - || command->cmd == IPSET_CMD_VERSION - || command->cmd == IPSET_CMD_HELP)) - return exit_error(PARAMETER_PROBLEM, - "Command `%s' is invalid " - "in restore mode.", - command->name[0]); - if (interactive - && command->cmd == IPSET_CMD_RESTORE) { - printf("Restore command ignored " - "in interactive mode\n"); - return 0; - } + if (!ipset_match_cmd(argv[1], command->name)) + continue; - /* Shift off matched command arg */ - ipset_shift_argv(&argc, argv, i); - cmd = command->cmd; - switch (command->has_arg) { - case IPSET_MANDATORY_ARG: - case IPSET_MANDATORY_ARG2: - if (i + 1 > argc) - return exit_error(PARAMETER_PROBLEM, - "Missing mandatory argument " - "to command %s", - command->name[0]); - /* Fall through */ - case IPSET_OPTIONAL_ARG: - arg0 = argv[i]; - if (i + 1 <= argc) - /* Shift off first arg */ - ipset_shift_argv(&argc, argv, i); - break; - default: - break; - } - if (command->has_arg == IPSET_MANDATORY_ARG2) { - if (i + 1 > argc) - return exit_error(PARAMETER_PROBLEM, - "Missing second mandatory " - "argument to command %s", - command->name[0]); - arg1 = argv[i]; - /* Shift off second arg */ - ipset_shift_argv(&argc, argv, i); - } + if (restore_line != 0 + && (command->cmd == IPSET_CMD_RESTORE + || command->cmd == IPSET_CMD_VERSION + || command->cmd == IPSET_CMD_HELP)) + return exit_error(PARAMETER_PROBLEM, + "Command `%s' is invalid " + "in restore mode.", + command->name[0]); + if (interactive && command->cmd == IPSET_CMD_RESTORE) { + printf("Restore command ignored " + "in interactive mode\n"); + return 0; + } + + /* Shift off matched command arg */ + ipset_shift_argv(&argc, argv, 1); + cmd = command->cmd; + switch (command->has_arg) { + case IPSET_MANDATORY_ARG: + case IPSET_MANDATORY_ARG2: + if (argc < 2) + return exit_error(PARAMETER_PROBLEM, + "Missing mandatory argument " + "to command %s", + command->name[0]); + /* Fall through */ + case IPSET_OPTIONAL_ARG: + arg0 = argv[1]; + if (argc >= 2) + /* Shift off first arg */ + ipset_shift_argv(&argc, argv, 1); + break; + default: break; } + if (command->has_arg == IPSET_MANDATORY_ARG2) { + if (argc < 2) + return exit_error(PARAMETER_PROBLEM, + "Missing second mandatory " + "argument to command %s", + command->name[0]); + arg1 = argv[1]; + /* Shift off second arg */ + ipset_shift_argv(&argc, argv, 1); + } + break; } /* Third: catch interactive mode, handle help, version */ @@ -565,7 +553,8 @@ parse_commandline(int argc, char *argv[]) argv[1]); return exit_error(PARAMETER_PROBLEM, "No command specified."); case IPSET_CMD_VERSION: - printf("%s v%s.\n", program_name, program_version); + printf("%s v%s, protocol version: %u\n", + program_name, program_version, IPSET_PROTOCOL); if (interactive) return 0; return exit_error(NO_PROBLEM, NULL); diff --git a/extensions/ipset-6/src/ui.c b/extensions/ipset-6/src/ui.c index 176e1b2..3601c65 100644 --- a/extensions/ipset-6/src/ui.c +++ b/extensions/ipset-6/src/ui.c @@ -23,9 +23,9 @@ const struct ipset_commands ipset_commands[] = { /* Order is important */ - { /* c[reate], --create, n, -N */ + { /* c[reate], --create, n[ew], -N */ .cmd = IPSET_CMD_CREATE, - .name = { "create", "n" }, + .name = { "create", "new" }, .has_arg = IPSET_MANDATORY_ARG2, .help = "SETNAME TYPENAME [type-specific-options]\n" " Create a new set", @@ -143,14 +143,14 @@ ipset_match_cmd(const char *arg, const char * const name[]) if (len > strlen(name[0]) || !len) return false; - else if (strncmp(arg, name[0], len) == 0) + else if (len > 1 && + ((strncmp(arg, name[0], len) == 0) || + (name[1] != NULL && (strncmp(arg, name[1], len) == 0)))) return true; else if (len != 1) return false; - else if (name[1] == NULL) - return tolower(arg[0]) == name[0][0]; - else - return tolower(arg[0]) == name[1][0]; + else return tolower(arg[0]) == name[0][0] || + (name[1] != NULL && tolower(arg[0]) == name[1][0]); } const struct ipset_envopts ipset_envopts[] = { diff --git a/extensions/ipset-6/xt_set.c b/extensions/ipset-6/xt_set.c index 56e6937..f2a9088 100644 --- a/extensions/ipset-6/xt_set.c +++ b/extensions/ipset-6/xt_set.c @@ -56,10 +56,10 @@ match_set(ip_set_id_t index, const struct sk_buff *skb, #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35) #define CHECK_OK 1 -#define CHECK_FAIL 0 +#define CHECK_FAIL(err) 0 #else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35) */ #define CHECK_OK 0 -#define CHECK_FAIL (-EINVAL) +#define CHECK_FAIL(err) (err) #endif #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35) @@ -110,11 +110,12 @@ set_match_v0_checkentry(const struct xt_mtchk_param *par) if (index == IPSET_INVALID_ID) { pr_warning("Cannot find set indentified by id %u to match\n", info->match_set.index); - return CHECK_FAIL; /* error */ + return CHECK_FAIL(-ENOENT); /* error */ } if (info->match_set.u.flags[IPSET_DIM_MAX-1] != 0) { - pr_warning("That's nasty!\n"); - return CHECK_FAIL; /* error */ + pr_warning("Protocol error: set match dimension " + "is over the limit!\n"); + return CHECK_FAIL(-ERANGE); /* error */ } /* Fill out compatibility data */ @@ -167,24 +168,25 @@ set_target_v0_checkentry(const struct xt_tgchk_param *par) if (info->add_set.index != IPSET_INVALID_ID) { index = ip_set_nfnl_get_byindex(info->add_set.index); if (index == IPSET_INVALID_ID) { - pr_warning("cannot find add_set index %u as target\n", + pr_warning("Cannot find add_set index %u as target\n", info->add_set.index); - return CHECK_FAIL; /* error */ + return CHECK_FAIL(-ENOENT); /* error */ } } if (info->del_set.index != IPSET_INVALID_ID) { index = ip_set_nfnl_get_byindex(info->del_set.index); if (index == IPSET_INVALID_ID) { - pr_warning("cannot find del_set index %u as target\n", + pr_warning("Cannot find del_set index %u as target\n", info->del_set.index); - return CHECK_FAIL; /* error */ + return CHECK_FAIL(-ENOENT); /* error */ } } if (info->add_set.u.flags[IPSET_DIM_MAX-1] != 0 || info->del_set.u.flags[IPSET_DIM_MAX-1] != 0) { - pr_warning("That's nasty!\n"); - return CHECK_FAIL; /* error */ + pr_warning("Protocol error: SET target dimension " + "is over the limit!\n"); + return CHECK_FAIL(-ERANGE); /* error */ } /* Fill out compatibility data */ @@ -239,11 +241,12 @@ set_match_checkentry(const struct xt_mtchk_param *par) if (index == IPSET_INVALID_ID) { pr_warning("Cannot find set indentified by id %u to match\n", info->match_set.index); - return CHECK_FAIL; /* error */ + return CHECK_FAIL(-ENOENT); /* error */ } if (info->match_set.dim > IPSET_DIM_MAX) { - pr_warning("That's nasty!\n"); - return CHECK_FAIL; /* error */ + pr_warning("Protocol error: set match dimension " + "is over the limit!\n"); + return CHECK_FAIL(-ERANGE); /* error */ } return CHECK_OK; @@ -295,24 +298,25 @@ set_target_checkentry(const struct xt_tgchk_param *par) if (info->add_set.index != IPSET_INVALID_ID) { index = ip_set_nfnl_get_byindex(info->add_set.index); if (index == IPSET_INVALID_ID) { - pr_warning("cannot find add_set index %u as target\n", + pr_warning("Cannot find add_set index %u as target\n", info->add_set.index); - return CHECK_FAIL; /* error */ + return CHECK_FAIL(-ENOENT); /* error */ } } if (info->del_set.index != IPSET_INVALID_ID) { index = ip_set_nfnl_get_byindex(info->del_set.index); if (index == IPSET_INVALID_ID) { - pr_warning("cannot find del_set index %u as target\n", + pr_warning("Cannot find del_set index %u as target\n", info->del_set.index); - return CHECK_FAIL; /* error */ + return CHECK_FAIL(-ENOENT); /* error */ } } if (info->add_set.dim > IPSET_DIM_MAX || info->del_set.flags > IPSET_DIM_MAX) { - pr_warning("That's nasty!\n"); - return CHECK_FAIL; /* error */ + pr_warning("Protocol error: SET target dimension " + "is over the limit!\n"); + return CHECK_FAIL(-ERANGE); /* error */ } return CHECK_OK; diff --git a/extensions/ipset-6/xt_set.h b/extensions/ipset-6/xt_set.h index b5450a9..6d6e04f 100644 --- a/extensions/ipset-6/xt_set.h +++ b/extensions/ipset-6/xt_set.h @@ -1,6 +1,7 @@ #ifndef _XT_SET_H #define _XT_SET_H +#include #include "ip_set.h" /* Revision 0 interface: backward compatible with netfilter/iptables */ diff --git a/mconfig b/mconfig index 03c8719..221fcfb 100644 --- a/mconfig +++ b/mconfig @@ -1,30 +1,3 @@ # -*- Makefile -*- # -build_ACCOUNT=m -build_CHAOS=m -build_CHECKSUM= -build_DELUDE=m -build_DHCPMAC=m -build_DNETMAP= -build_ECHO= -build_IPMARK=m -build_LOGMARK=m -build_RAWNAT=m -build_STEAL=m -build_SYSRQ=m -build_TARPIT=m -build_TEE= -build_condition=m -build_fuzzy=m -build_geoip=m -build_gradm=m -build_iface=m -build_ipp2p=m -build_ipset4=m -build_ipset6= -build_ipv4options=m -build_length2=m -build_lscan=m -build_pknock=m -build_psd=m -build_quota2=m +build_ipset6=m