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)
--- /dev/null
+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.
/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
* Patrick Schaaf <bof@bof.de>
* Martin Josefsson <gandalf@wlug.westbo.se>
- * Copyright (C) 2003-2010 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+ * Copyright (C) 2003-2011 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
*
* 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
*/
/* 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
/* Error codes */
enum ipset_errno {
- IPSET_ERR_PRIVATE = 128,
+ IPSET_ERR_PRIVATE = 4096,
IPSET_ERR_PROTOCOL,
IPSET_ERR_FIND_TYPE,
IPSET_ERR_MAX_SETS,
IPSET_ERR_IPADDR_IPV6,
/* Type specific error codes */
- IPSET_ERR_TYPE_SPECIFIC = 160,
+ IPSET_ERR_TYPE_SPECIFIC = 4352,
};
/* Flags at command level */
#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);
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,
* 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 */
#include <linux/netlink.h>
/* 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
/* Error codes */
enum ipset_errno {
- IPSET_ERR_PRIVATE = 128,
+ IPSET_ERR_PRIVATE = 4096,
IPSET_ERR_PROTOCOL,
IPSET_ERR_FIND_TYPE,
IPSET_ERR_MAX_SETS,
IPSET_ERR_IPADDR_IPV6,
/* Type specific error codes */
- IPSET_ERR_TYPE_SPECIFIC = 160,
+ IPSET_ERR_TYPE_SPECIFIC = 4352,
};
/* Flags at command level */
* 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 */
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;
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);
/* 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;
return 0;
nla_put_failure:
- return -EFAULT;
+ return -EMSGSIZE;
}
/* Reply a LIST/SAVE request: dump the elements of the specified 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);
if (!nested) {
if (cb->args[2] == first) {
nla_nest_cancel(skb, atd);
- return -EFAULT;
+ return -EMSGSIZE;
} else
goto 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;
}
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 = {
/* 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;
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]);
if (!nested) {
if (cb->args[2] == first) {
nla_nest_cancel(skb, atd);
- return -EFAULT;
+ return -EMSGSIZE;
} else
goto 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;
}
#include <linux/ip.h>
#include <linux/skbuff.h>
#include <linux/errno.h>
-#include <linux/uaccess.h>
#include <linux/bitops.h>
#include <linux/spinlock.h>
#include <linux/netlink.h>
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 */
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)
-{
- return !!test_bit(id, map->members);
-}
-
-static inline int
-bitmap_ip_add(struct bitmap_ip *map, u32 id)
-{
- 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)
-{
- if (!test_and_clear_bit(id, map->members))
- return -IPSET_ERR_EXIST;
-
- 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)
+bitmap_ip_test(struct ip_set *set, void *value, u32 timeout)
{
- struct bitmap_ip *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(map, ip);
+ const struct bitmap_ip *map = set->data;
+ u16 id = *(u16 *)value;
- 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 !!test_bit(id, map->members);
}
-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,
- enum ipset_adt adt, u32 *lineno, u32 flags)
+bitmap_ip_add(struct ip_set *set, void *value, u32 timeout)
{
struct bitmap_ip *map = set->data;
- struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
- 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]))
- 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;
-
- /* Set was defined without timeout support:
- * don't ignore the attribute silently */
- if (tb[IPSET_ATTR_TIMEOUT])
- return -IPSET_ERR_TIMEOUT;
+ u16 id = *(u16 *)value;
- if (adt == IPSET_TEST)
- return bitmap_ip_test(map, ip_to_id(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;
-
- 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);
-
- if (ret && !ip_set_eexist(ret, flags))
- return ret;
- else
- ret = 0;
- }
- return ret;
-}
-
-static void
-bitmap_ip_destroy(struct ip_set *set)
-{
- struct bitmap_ip *map = set->data;
-
- ip_set_free(map->members);
- kfree(map);
-
- set->data = NULL;
-}
-
-static void
-bitmap_ip_flush(struct ip_set *set)
-{
- struct bitmap_ip *map = set->data;
+ if (test_and_set_bit(id, map->members))
+ return -IPSET_ERR_EXIST;
- memset(map->members, 0, map->memsize);
+ return 0;
}
static int
-bitmap_ip_head(struct ip_set *set, struct sk_buff *skb)
+bitmap_ip_del(struct ip_set *set, void *value, u32 timeout)
{
- const struct bitmap_ip *map = set->data;
- struct nlattr *nested;
+ struct bitmap_ip *map = set->data;
+ u16 id = *(u16 *)value;
- 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_REFERENCES,
- htonl(atomic_read(&set->ref) - 1));
- NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE,
- htonl(sizeof(*map) + map->memsize));
- ipset_nest_end(skb, nested);
+ if (!test_and_clear_bit(id, map->members))
+ return -IPSET_ERR_EXIST;
return 0;
-nla_put_failure:
- return -EFAULT;
}
static int
atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
if (!atd)
- return -EFAULT;
+ return -EMSGSIZE;
for (; cb->args[2] < map->elements; cb->args[2]++) {
id = cb->args[2];
- if (!bitmap_ip_test(map, id))
+ 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;
+ return -EMSGSIZE;
} else
goto nla_put_failure;
}
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;
}
-static bool
-bitmap_ip_same_set(const struct ip_set *a, const struct ip_set *b)
-{
- const struct bitmap_ip *x = a->data;
- const struct bitmap_ip *y = b->data;
-
- return x->first_ip == y->first_ip &&
- x->last_ip == y->last_ip &&
- x->netmask == y->netmask;
-}
-
-static const struct ip_set_type_variant bitmap_ip = {
- .kadt = bitmap_ip_kadt,
- .uadt = bitmap_ip_uadt,
- .destroy = bitmap_ip_destroy,
- .flush = bitmap_ip_flush,
- .head = bitmap_ip_head,
- .list = bitmap_ip_list,
- .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)
+static int
+bitmap_ip_ttest(struct ip_set *set, void *value, u32 timeout)
{
- return ip_set_timeout_test(map->members[id]);
+ 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 inline int
-bitmap_ip_timeout_add(struct bitmap_ip_timeout *map,
- u32 id, u32 timeout)
+static int
+bitmap_ip_tadd(struct ip_set *set, void *value, u32 timeout)
{
- if (bitmap_ip_timeout_test(map, id))
+ 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;
- map->members[id] = ip_set_timeout_set(timeout);
+ members[id] = ip_set_timeout_set(timeout);
return 0;
}
-static inline int
-bitmap_ip_timeout_del(struct bitmap_ip_timeout *map, u32 id)
+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 (bitmap_ip_timeout_test(map, id))
+ if (ip_set_timeout_test(members[id]))
ret = 0;
- map->members[id] = IPSET_ELEM_UNSET;
+ 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)
+bitmap_ip_tlist(const struct ip_set *set,
+ struct sk_buff *skb, struct netlink_callback *cb)
{
- struct bitmap_ip_timeout *map = set->data;
+ 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));
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;
- }
+ ip = ip_to_id(map, ip);
+
+ return adtfn(set, &ip, map->timeout);
}
static int
-bitmap_ip_timeout_uadt(struct ip_set *set, struct nlattr *head, int len,
- enum ipset_adt adt, u32 *lineno, u32 flags)
+bitmap_ip_uadt(struct ip_set *set, struct nlattr *tb[],
+ 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;
+ struct bitmap_ip *map = set->data;
+ 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] ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
return -IPSET_ERR_PROTOCOL;
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_TIMEOUT]) {
+ if (!with_timeout(map->timeout))
+ return -IPSET_ERR_TIMEOUT;
+ timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
+ }
+
+ 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);
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);
+ id = ip_to_id(map, ip);
+ ret = adtfn(set, &id, timeout);;
if (ret && !ip_set_eexist(ret, flags))
return ret;
}
static void
-bitmap_ip_timeout_destroy(struct ip_set *set)
+bitmap_ip_destroy(struct ip_set *set)
{
- struct bitmap_ip_timeout *map = set->data;
+ struct bitmap_ip *map = set->data;
+
+ if (with_timeout(map->timeout))
+ del_timer_sync(&map->gc);
- del_timer_sync(&map->gc);
ip_set_free(map->members);
kfree(map);
}
static void
-bitmap_ip_timeout_flush(struct ip_set *set)
+bitmap_ip_flush(struct ip_set *set)
{
- struct bitmap_ip_timeout *map = set->data;
+ struct bitmap_ip *map = set->data;
- memset(map->members, IPSET_ELEM_UNSET, map->memsize);
+ memset(map->members, 0, map->memsize);
}
static int
-bitmap_ip_timeout_head(struct ip_set *set, struct sk_buff *skb)
+bitmap_ip_head(struct ip_set *set, struct sk_buff *skb)
{
- const struct bitmap_ip_timeout *map = set->data;
+ const struct bitmap_ip *map = set->data;
struct nlattr *nested;
nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
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));
+ 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_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;
+ return -EMSGSIZE;
}
static bool
-bitmap_ip_timeout_same_set(const struct ip_set *a, const struct ip_set *b)
+bitmap_ip_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;
+ const struct bitmap_ip *x = a->data;
+ const struct bitmap_ip *y = b->data;
return x->first_ip == y->first_ip &&
x->last_ip == y->last_ip &&
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_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,
+ .list = bitmap_ip_list,
+ .same_set = bitmap_ip_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;
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;
/* 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;
map->elements = elements;
map->hosts = hosts;
map->netmask = netmask;
+ map->timeout = IPSET_NO_TIMEOUT;
set->data = map;
set->family = AF_INET;
}
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;
pr_debug("hosts %u, elements %u\n", hosts, elements);
- if (tb[IPSET_ATTR_TIMEOUT]) {
- struct bitmap_ip_timeout *map;
-
- map = kzalloc(sizeof(*map), GFP_KERNEL);
- if (!map)
- return -ENOMEM;
+ map = kzalloc(sizeof(*map), GFP_KERNEL);
+ if (!map)
+ return -ENOMEM;
+ if (tb[IPSET_ATTR_TIMEOUT]) {
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;
.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,
};
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/errno.h>
-#include <linux/uaccess.h>
-#include <linux/bitops.h>
-#include <linux/spinlock.h>
#include <linux/if_ether.h>
#include <linux/netlink.h>
#include <linux/jiffies.h>
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);
if (!nested) {
if (id == first) {
nla_nest_cancel(skb, atd);
- return -EFAULT;
+ return -EMSGSIZE;
} else
goto nla_put_failure;
}
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;
}
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);
if (!nested) {
if (id == first) {
nla_nest_cancel(skb, atd);
- return -EFAULT;
+ return -EMSGSIZE;
} else
goto nla_put_failure;
}
nla_put_failure:
nla_nest_cancel(skb, nested);
ipset_nest_end(skb, atd);
- return 0;
+ return -EMSGSIZE;
}
static int
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;
return 0;
nla_put_failure:
- return -EFAULT;
+ return -EMSGSIZE;
}
static bool
/* 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;
}
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;
.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,
};
#include <linux/module.h>
#include <linux/ip.h>
-#include <linux/tcp.h>
-#include <linux/udp.h>
#include <linux/skbuff.h>
#include <linux/errno.h>
-#include <linux/uaccess.h>
-#include <linux/bitops.h>
-#include <linux/spinlock.h>
#include <linux/netlink.h>
#include <linux/jiffies.h>
#include <linux/timer.h>
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)
-{
- return !!test_bit(id, map->members);
-}
-
-static inline int
-bitmap_port_add(struct bitmap_port *map, u16 id)
-{
- if (test_and_set_bit(id, map->members))
- return -IPSET_ERR_EXIST;
-
- return 0;
-}
+/* Base variant */
static int
-bitmap_port_del(struct bitmap_port *map, u16 id)
+bitmap_port_test(struct ip_set *set, void *value, u32 timeout)
{
- if (!test_and_clear_bit(id, map->members))
- return -IPSET_ERR_EXIST;
+ const struct bitmap_port *map = set->data;
+ u16 id = *(u16 *)value;
- return 0;
+ return !!test_bit(id, map->members);
}
static int
-bitmap_port_kadt(struct ip_set *set, const struct sk_buff *skb,
- enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
+bitmap_port_add(struct ip_set *set, void *value, u32 timeout)
{
struct bitmap_port *map = set->data;
- __be16 __port;
- u16 port = 0;
-
- if (!ip_set_get_ip_port(skb, pf, flags & IPSET_DIM_ONE_SRC, &__port))
- return -EINVAL;
+ u16 id = *(u16 *)value;
- port = ntohs(__port);
-
- if (port < map->first_port || port > map->last_port)
- return -IPSET_ERR_BITMAP_RANGE;
-
- port -= map->first_port;
+ if (test_and_set_bit(id, map->members))
+ return -IPSET_ERR_EXIST;
- 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 0;
}
-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,
- enum ipset_adt adt, u32 *lineno, u32 flags)
+bitmap_port_del(struct ip_set *set, void *value, u32 timeout)
{
struct bitmap_port *map = set->data;
- struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
- 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)))
- 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 (tb[IPSET_ATTR_TIMEOUT])
- return -IPSET_ERR_TIMEOUT;
-
- if (adt == IPSET_TEST)
- return bitmap_port_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;
+ u16 id = *(u16 *)value;
- if (port_to > map->last_port)
- return -IPSET_ERR_BITMAP_RANGE;
-
- for (; port <= port_to; port++) {
- id = port - map->first_port;
- ret = adt == IPSET_ADD ? bitmap_port_add(map, id)
- : bitmap_port_del(map, id);
-
- if (ret && !ip_set_eexist(ret, flags))
- return ret;
- else
- ret = 0;
- }
- return ret;
-}
-
-static void
-bitmap_port_destroy(struct ip_set *set)
-{
- struct bitmap_port *map = set->data;
-
- ip_set_free(map->members);
- kfree(map);
-
- set->data = NULL;
-}
-
-static void
-bitmap_port_flush(struct ip_set *set)
-{
- struct bitmap_port *map = set->data;
-
- memset(map->members, 0, map->memsize);
-}
-
-static int
-bitmap_port_head(struct ip_set *set, struct sk_buff *skb)
-{
- const struct bitmap_port *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_REFERENCES,
- htonl(atomic_read(&set->ref) - 1));
- NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE,
- htonl(sizeof(*map) + map->memsize));
- ipset_nest_end(skb, nested);
+ if (!test_and_clear_bit(id, map->members))
+ return -IPSET_ERR_EXIST;
return 0;
-nla_put_failure:
- return -EFAULT;
}
static int
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];
if (!test_bit(id, map->members))
if (!nested) {
if (id == first) {
nla_nest_cancel(skb, atd);
- return -EFAULT;
+ return -EMSGSIZE;
} else
goto nla_put_failure;
}
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;
}
-static bool
-bitmap_port_same_set(const struct ip_set *a, const struct ip_set *b)
-{
- const struct bitmap_port *x = a->data;
- const struct bitmap_port *y = b->data;
-
- return x->first_port == y->first_port &&
- x->last_port == y->last_port;
-}
-
-static const struct ip_set_type_variant bitmap_port = {
- .kadt = bitmap_port_kadt,
- .uadt = bitmap_port_uadt,
- .destroy = bitmap_port_destroy,
- .flush = bitmap_port_flush,
- .head = bitmap_port_head,
- .list = bitmap_port_list,
- .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)
+static int
+bitmap_port_ttest(struct ip_set *set, void *value, u32 timeout)
{
- return ip_set_timeout_test(map->members[id]);
+ 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_timeout_add(const struct bitmap_port_timeout *map,
- u16 id, u32 timeout)
+bitmap_port_tadd(struct ip_set *set, void *value, u32 timeout)
{
- if (bitmap_port_timeout_test(map, id))
+ 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;
- map->members[id] = ip_set_timeout_set(timeout);
+ members[id] = ip_set_timeout_set(timeout);
return 0;
}
static int
-bitmap_port_timeout_del(const struct bitmap_port_timeout *map,
- u16 id)
+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 (bitmap_port_timeout_test(map, id))
+ if (ip_set_timeout_test(members[id]))
ret = 0;
- map->members[id] = IPSET_ELEM_UNSET;
+ 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)
+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_timeout *map = set->data;
+ struct bitmap_port *map = set->data;
+ ipset_adtfn adtfn = set->variant->adt[adt];
__be16 __port;
u16 port = 0;
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;
- }
+ return adtfn(set, &port, map->timeout);
}
static int
-bitmap_port_timeout_uadt(struct ip_set *set, struct nlattr *head, int len,
- enum ipset_adt adt, u32 *lineno, u32 flags)
+bitmap_port_uadt(struct ip_set *set, struct nlattr *tb[],
+ enum ipset_adt adt, u32 *lineno, u32 flags)
{
- const struct bitmap_port_timeout *map = set->data;
- struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
+ struct bitmap_port *map = set->data;
+ ipset_adtfn adtfn = set->variant->adt[adt];
+ u32 timeout = map->timeout;
+ u32 port; /* wraparound */
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)))
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_TIMEOUT]) {
+ if (!with_timeout(map->timeout))
+ return -IPSET_ERR_TIMEOUT;
+ timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
+ }
+
+ 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]);
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);
+ ret = adtfn(set, &id, timeout);
if (ret && !ip_set_eexist(ret, flags))
return ret;
}
static void
-bitmap_port_timeout_destroy(struct ip_set *set)
+bitmap_port_destroy(struct ip_set *set)
{
- struct bitmap_port_timeout *map = set->data;
+ struct bitmap_port *map = set->data;
+
+ if (with_timeout(map->timeout))
+ del_timer_sync(&map->gc);
- del_timer_sync(&map->gc);
ip_set_free(map->members);
kfree(map);
}
static void
-bitmap_port_timeout_flush(struct ip_set *set)
+bitmap_port_flush(struct ip_set *set)
{
- struct bitmap_port_timeout *map = set->data;
+ struct bitmap_port *map = set->data;
memset(map->members, 0, map->memsize);
}
static int
-bitmap_port_timeout_head(struct ip_set *set, struct sk_buff *skb)
+bitmap_port_head(struct ip_set *set, struct sk_buff *skb)
{
- const struct bitmap_port_timeout *map = set->data;
+ const struct bitmap_port *map = set->data;
struct nlattr *nested;
nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
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));
+ 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_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;
+ return -EMSGSIZE;
}
static bool
-bitmap_port_timeout_same_set(const struct ip_set *a, const struct ip_set *b)
+bitmap_port_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;
+ const struct bitmap_port *x = a->data;
+ const struct bitmap_port *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_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,
+ .list = bitmap_port_list,
+ .same_set = bitmap_port_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;
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;
/* 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;
}
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)))
last_port = tmp;
}
- if (tb[IPSET_ATTR_TIMEOUT]) {
- struct bitmap_port_timeout *map;
-
- map = kzalloc(sizeof(*map), GFP_KERNEL);
- if (!map)
- return -ENOMEM;
+ map = kzalloc(sizeof(*map), GFP_KERNEL);
+ if (!map)
+ return -ENOMEM;
+ if (tb[IPSET_ATTR_TIMEOUT]) {
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)) {
.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,
};
#include <linux/spinlock.h>
#include <linux/netlink.h>
#include <linux/rculist.h>
+#include <linux/version.h>
#include <net/netlink.h>
#include <linux/netfilter.h>
/* 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);
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;
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;
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 ||
/*
* 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;
} 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;
} 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]);
}
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;
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)
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;
{
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;
}
}
set = ip_set_list[index];
if (set == NULL) {
if (cb->args[0] == DUMP_ONE) {
- ret = -EEXIST;
+ ret = -ENOENT;
goto out;
}
continue;
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);
};
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 &&
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;
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) ||
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;
}
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) ||
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;
}
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) ||
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)
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);
ret = genlmsg_unicast(genl_info_net(info), skb2, NETLINK_CB(skb).pid);
if (ret < 0)
- return -EFAULT;
+ return ret;
return 0;
nlmsg_cancel(skb2, nlh2);
nlmsg_failure:
kfree_skb(skb2);
- return -EFAULT;
+ return -EMSGSIZE;
}
/* Get type data */
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;
genlmsg_cancel(skb2, nlh2);
nlmsg_failure:
kfree_skb(skb2);
- return -EFAULT;
+ return -EMSGSIZE;
}
/* Get protocol version */
ret = genlmsg_unicast(genl_info_net(info), skb2, NETLINK_CB(skb).pid);
if (ret < 0)
- return -EFAULT;
+ return ret;
return 0;
genlmsg_cancel(skb2, nlh2);
nlmsg_failure:
kfree_skb(skb2);
- return -EFAULT;
+ return -EMSGSIZE;
}
static struct genl_ops ip_set_netlink_subsys_cb[] __read_mostly = {
#include <linux/icmpv6.h>
#include <linux/netfilter_ipv6/ip6_tables.h>
#include <net/ip.h>
+#include <net/ipv6.h>
#include "ip_set_getport.h"
}
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)
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;
}
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);
#include <linux/ip.h>
#include <linux/skbuff.h>
#include <linux/errno.h>
-#include <linux/uaccess.h>
-#include <linux/bitops.h>
-#include <linux/spinlock.h>
#include <linux/random.h>
#include <net/ip.h>
#include <net/ipv6.h>
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;
};
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])
/* 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;
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)))
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;
.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,
};
#include <linux/ip.h>
#include <linux/skbuff.h>
#include <linux/errno.h>
-#include <linux/uaccess.h>
-#include <linux/bitops.h>
-#include <linux/spinlock.h>
#include <linux/random.h>
#include <net/ip.h>
#include <net/ipv6.h>
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) ||
}
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])
/* 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;
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)))
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;
.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,
};
#include <linux/ip.h>
#include <linux/skbuff.h>
#include <linux/errno.h>
-#include <linux/uaccess.h>
-#include <linux/bitops.h>
-#include <linux/spinlock.h>
#include <linux/random.h>
#include <net/ip.h>
#include <net/ipv6.h>
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) ||
}
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])
/* 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;
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)))
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;
.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,
};
#include <linux/ip.h>
#include <linux/skbuff.h>
#include <linux/errno.h>
-#include <asm/uaccess.h>
-#include <asm/bitops.h>
-#include <linux/spinlock.h>
#include <linux/random.h>
#include <net/ip.h>
#include <net/ipv6.h>
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) ||
}
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])
/* 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;
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)))
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;
.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,
};
#include <linux/ip.h>
#include <linux/skbuff.h>
#include <linux/errno.h>
-#include <linux/uaccess.h>
-#include <linux/bitops.h>
-#include <linux/spinlock.h>
#include <linux/random.h>
#include <net/ip.h>
#include <net/ipv6.h>
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;
}
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;
/* 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;
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)))
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;
.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,
};
#include <linux/ip.h>
#include <linux/skbuff.h>
#include <linux/errno.h>
-#include <linux/uaccess.h>
-#include <linux/bitops.h>
-#include <linux/spinlock.h>
#include <linux/random.h>
#include <net/ip.h>
#include <net/ipv6.h>
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) ||
}
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) ||
/* 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;
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)))
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;
.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,
};
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)
{
}
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;
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)))
return 0;
nla_put_failure:
- return -EFAULT;
+ return -EMSGSIZE;
}
static int
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);
if (!nested) {
if (i == first) {
nla_nest_cancel(skb, atd);
- return -EFAULT;
+ return -EMSGSIZE;
} else
goto nla_put_failure;
}
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;
}
/* 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)
}
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;
.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,
};
[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,
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;
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;
*/
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) \
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, \
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);
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);
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;
}
}
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;
/* 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" },
{ 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,
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
/* 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))
+ if (!ipset_match_cmd(argv[1], command->name))
+ 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;
+ }
+
+ /* 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,
- "Command `%s' is invalid "
- "in restore mode.",
+ "Missing mandatory argument "
+ "to command %s",
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, 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);
- }
+ /* 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 */
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);
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",
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[] = {
#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)
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 */
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 */
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;
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;
#ifndef _XT_SET_H
#define _XT_SET_H
+#include <linux/types.h>
#include "ip_set.h"
/* Revision 0 interface: backward compatible with netfilter/iptables */
# -*- 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