ipset: update to 6.0

This commit is contained in:
Jan Engelhardt
2011-02-24 00:40:23 +01:00
parent ff27f61477
commit 18043f3e3a
30 changed files with 1016 additions and 1299 deletions

View File

@@ -1,6 +1,20 @@
HEAD 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) v1.33 (2011-02-02)

88
extensions/ipset-6/README Normal file
View File

@@ -0,0 +1,88 @@
This is the ipset source tree. Follow the next steps to install ipset.
If you upgrade from an earlier 5.x release, please read the UPGRADE
instructions too.
0. You need the source tree of your kernel (version >= 2.6.34)
and it have to be configured with ip6tables support enabled,
modules compiled. Please apply the netlink.patch against your kernel
tree, which adds the new subsystem identifier for ipset.
Recompile and install the patched kernel and its modules. Please note,
you have to run the patched kernel for ipset to work.
The ipset source code depends on the libmnl library so the library
must be installed. You can download the libmnl library from
git://git.netfilter.org/libmnl.git
1. Initialize the compiling environment for ipset. The packages automake,
autoconf and libtool are required.
% ./autogen.sh
2. Run `./configure` and then compile the ipset binary and the kernel
modules.
Configure parameters can be used to to override the default path
to the kernel source tree (/lib/modules/`uname -r`/build),
the maximum number of sets (256), the default hash sizes (1024).
See `./configure --help`.
% ./configure
% make
% make modules
3. Install the binary and the kernel modules
# make install
# make modules_install
After installing the modules, you can run the testsuite as well.
Please note, several assumptions must be met for the testsuite:
- no sets defined
- iptables/ip6tables rules are not set up
- the destination for kernel logs is /var/log/kern.log
- the networks 10.255.255.0/24 and 1002:1002:1002:1002::/64
are not in use
- sendip utility is installed
# make tests
4. Cleanup the source tree
% make clean
% make modules_clean
That's it!
Read the ipset(8) and iptables(8), ip6tables(8) manpages on how to use
ipset and its match and target from iptables.
Compatibilities and incompatibilities:
- The ipset 6.x userspace utility contains a backward compatibility
interface to support the commandline syntax of ipset 4.x.
The commandline syntax of ipset 6.x is fully compatible with 5.x.
- The ipset 6.x userspace utility can't talk to the kernel part of ipset 5.x
or 4.x.
- The ipset 6.x kernel part can't talk to the userspace utility from
ipset 5.x or 4.x.
- The ipset 6.x kernel part can work together with the set match and SET
target from iptables 1.4.7 and below, however if you need the IPv6 support
from ipset 6.x, then you have to use iptables 1.4.8 or above.
The ipset 6.x can interpret the commandline syntax of ipset 4.x, however
some internal changes mean different behaviour:
- The "--matchunset" flag for the macipmap type is ignored and not used
anymore.
- The "--probes" and "--resize" parameters of the hash types are ignored
and not used anymore.
- The "--from", "--to" and "--network" parameters of the ipporthash,
ipportiphash and ipportnethash types are ignored and not used anymore.
- The hash types are not resized when new entries are added by the SET
target. If you use a set together with the SET target, create it with
the proper size because it won't be resized automatically.
- The iptree, iptreemap types are not implemented in ipset 6.x. The types
are automatically substituted with the hash:ip type.

View File

@@ -4,7 +4,7 @@
/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu> /* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
* Patrick Schaaf <bof@bof.de> * Patrick Schaaf <bof@bof.de>
* Martin Josefsson <gandalf@wlug.westbo.se> * 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 * 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 * it under the terms of the GNU General Public License version 2 as
@@ -12,7 +12,7 @@
*/ */
/* The protocol version */ /* The protocol version */
#define IPSET_PROTOCOL 5 #define IPSET_PROTOCOL 60
/* The max length of strings including NUL: set and type identifiers */ /* The max length of strings including NUL: set and type identifiers */
#define IPSET_MAXNAMELEN 32 #define IPSET_MAXNAMELEN 32
@@ -118,7 +118,7 @@ enum {
/* Error codes */ /* Error codes */
enum ipset_errno { enum ipset_errno {
IPSET_ERR_PRIVATE = 128, IPSET_ERR_PRIVATE = 4096,
IPSET_ERR_PROTOCOL, IPSET_ERR_PROTOCOL,
IPSET_ERR_FIND_TYPE, IPSET_ERR_FIND_TYPE,
IPSET_ERR_MAX_SETS, IPSET_ERR_MAX_SETS,
@@ -135,7 +135,7 @@ enum ipset_errno {
IPSET_ERR_IPADDR_IPV6, IPSET_ERR_IPADDR_IPV6,
/* Type specific error codes */ /* Type specific error codes */
IPSET_ERR_TYPE_SPECIFIC = 160, IPSET_ERR_TYPE_SPECIFIC = 4352,
}; };
/* Flags at command level */ /* Flags at command level */

View File

@@ -17,6 +17,7 @@
#define IPSET_PROTO_SEPARATOR ":" #define IPSET_PROTO_SEPARATOR ":"
struct ipset_session; struct ipset_session;
struct ipset_arg;
typedef int (*ipset_parsefn)(struct ipset_session *s, typedef int (*ipset_parsefn)(struct ipset_session *s,
enum ipset_opt opt, const char *str); enum ipset_opt opt, const char *str);
@@ -84,8 +85,8 @@ extern int ipset_parse_ignored(struct ipset_session *session,
extern int ipset_parse_elem(struct ipset_session *session, extern int ipset_parse_elem(struct ipset_session *session,
enum ipset_opt opt, const char *str); enum ipset_opt opt, const char *str);
extern int ipset_call_parser(struct ipset_session *session, extern int ipset_call_parser(struct ipset_session *session,
ipset_parsefn parse, const char *optstr, const struct ipset_arg *arg,
enum ipset_opt optional, const char *str); const char *str);
/* Compatibility parser functions */ /* Compatibility parser functions */
extern int ipset_parse_iptimeout(struct ipset_session *session, extern int ipset_parse_iptimeout(struct ipset_session *session,

View File

@@ -70,7 +70,7 @@ struct ipset_elem {
* but for the readability the full list is supported. * but for the readability the full list is supported.
*/ */
struct ipset_type { struct ipset_type {
char name[IPSET_MAXNAMELEN]; /* type name */ const char *name;
uint8_t revision; /* revision number */ uint8_t revision; /* revision number */
uint8_t family; /* supported family */ uint8_t family; /* supported family */
uint8_t dimension; /* elem dimension */ uint8_t dimension; /* elem dimension */

View File

@@ -14,7 +14,7 @@
#include <linux/netlink.h> #include <linux/netlink.h>
/* The protocol version */ /* The protocol version */
#define IPSET_PROTOCOL 5 #define IPSET_PROTOCOL 60
/* The max length of strings including NUL: set and type identifiers */ /* The max length of strings including NUL: set and type identifiers */
#define IPSET_MAXNAMELEN 32 #define IPSET_MAXNAMELEN 32
@@ -120,7 +120,7 @@ enum {
/* Error codes */ /* Error codes */
enum ipset_errno { enum ipset_errno {
IPSET_ERR_PRIVATE = 128, IPSET_ERR_PRIVATE = 4096,
IPSET_ERR_PROTOCOL, IPSET_ERR_PROTOCOL,
IPSET_ERR_FIND_TYPE, IPSET_ERR_FIND_TYPE,
IPSET_ERR_MAX_SETS, IPSET_ERR_MAX_SETS,
@@ -137,7 +137,7 @@ enum ipset_errno {
IPSET_ERR_IPADDR_IPV6, IPSET_ERR_IPADDR_IPV6,
/* Type specific error codes */ /* Type specific error codes */
IPSET_ERR_TYPE_SPECIFIC = 160, IPSET_ERR_TYPE_SPECIFIC = 4352,
}; };
/* Flags at command level */ /* Flags at command level */
@@ -231,7 +231,7 @@ struct ip_set_type_variant {
* returns negative error code, * returns negative error code,
* zero for no match/success to add/delete * zero for no match/success to add/delete
* positive for matching element */ * 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); enum ipset_adt adt, u32 *lineno, u32 flags);
/* Low level add/del/test functions */ /* Low level add/del/test functions */
@@ -274,8 +274,11 @@ struct ip_set_type {
u8 revision; u8 revision;
/* Create set */ /* Create set */
int (*create)(struct ip_set *set, int (*create)(struct ip_set *set, struct nlattr *tb[], u32 flags);
struct nlattr *head, int len, 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 */ /* Set this to THIS_MODULE if you are a module, otherwise NULL */
struct module *me; struct module *me;
@@ -320,7 +323,7 @@ extern int ip_set_test(ip_set_id_t id, const struct sk_buff *skb,
u8 family, u8 dim, u8 flags); u8 family, u8 dim, u8 flags);
/* Utility functions */ /* 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 void ip_set_free(void *members);
extern int ip_set_get_ipaddr4(struct nlattr *nla, __be32 *ipaddr); 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); extern int ip_set_get_ipaddr6(struct nlattr *nla, union nf_inet_addr *ipaddr);

View File

@@ -311,8 +311,7 @@ retry:
/* In case we have plenty of memory :-) */ /* In case we have plenty of memory :-) */
return -IPSET_ERR_HASH_FULL; return -IPSET_ERR_HASH_FULL;
t = ip_set_alloc(sizeof(*t) t = ip_set_alloc(sizeof(*t)
+ jhash_size(htable_bits) * sizeof(struct hbucket), + jhash_size(htable_bits) * sizeof(struct hbucket));
GFP_KERNEL);
if (!t) if (!t)
return -ENOMEM; return -ENOMEM;
t->htable_bits = htable_bits; t->htable_bits = htable_bits;
@@ -525,7 +524,7 @@ type_pf_head(struct ip_set *set, struct sk_buff *skb)
return 0; return 0;
nla_put_failure: nla_put_failure:
return -EFAULT; return -EMSGSIZE;
} }
/* Reply a LIST/SAVE request: dump the elements of the specified set */ /* Reply a LIST/SAVE request: dump the elements of the specified set */
@@ -545,7 +544,7 @@ type_pf_list(const struct ip_set *set,
atd = ipset_nest_start(skb, IPSET_ATTR_ADT); atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
if (!atd) if (!atd)
return -EFAULT; return -EMSGSIZE;
pr_debug("list hash set %s\n", set->name); pr_debug("list hash set %s\n", set->name);
for (; cb->args[2] < jhash_size(t->htable_bits); cb->args[2]++) { for (; cb->args[2] < jhash_size(t->htable_bits); cb->args[2]++) {
incomplete = skb_tail_pointer(skb); incomplete = skb_tail_pointer(skb);
@@ -559,7 +558,7 @@ type_pf_list(const struct ip_set *set,
if (!nested) { if (!nested) {
if (cb->args[2] == first) { if (cb->args[2] == first) {
nla_nest_cancel(skb, atd); nla_nest_cancel(skb, atd);
return -EFAULT; return -EMSGSIZE;
} else } else
goto nla_put_failure; goto nla_put_failure;
} }
@@ -581,6 +580,7 @@ nla_put_failure:
pr_warning("Can't list set %s: one bucket does not fit into " pr_warning("Can't list set %s: one bucket does not fit into "
"a message. Please report it!\n", set->name); "a message. Please report it!\n", set->name);
cb->args[2] = 0; cb->args[2] = 0;
return -EMSGSIZE;
} }
return 0; return 0;
} }
@@ -589,7 +589,7 @@ static int
type_pf_kadt(struct ip_set *set, const struct sk_buff * skb, type_pf_kadt(struct ip_set *set, const struct sk_buff * skb,
enum ipset_adt adt, u8 pf, u8 dim, u8 flags); enum ipset_adt adt, u8 pf, u8 dim, u8 flags);
static int 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); enum ipset_adt adt, u32 *lineno, u32 flags);
static const struct ip_set_type_variant type_pf_variant = { static const struct ip_set_type_variant type_pf_variant = {
@@ -742,8 +742,7 @@ retry:
/* In case we have plenty of memory :-) */ /* In case we have plenty of memory :-) */
return -IPSET_ERR_HASH_FULL; return -IPSET_ERR_HASH_FULL;
t = ip_set_alloc(sizeof(*t) t = ip_set_alloc(sizeof(*t)
+ jhash_size(htable_bits) * sizeof(struct hbucket), + jhash_size(htable_bits) * sizeof(struct hbucket));
GFP_KERNEL);
if (!t) if (!t)
return -ENOMEM; return -ENOMEM;
t->htable_bits = htable_bits; t->htable_bits = htable_bits;
@@ -946,7 +945,7 @@ type_pf_tlist(const struct ip_set *set,
atd = ipset_nest_start(skb, IPSET_ATTR_ADT); atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
if (!atd) if (!atd)
return -EFAULT; return -EMSGSIZE;
for (; cb->args[2] < jhash_size(t->htable_bits); cb->args[2]++) { for (; cb->args[2] < jhash_size(t->htable_bits); cb->args[2]++) {
incomplete = skb_tail_pointer(skb); incomplete = skb_tail_pointer(skb);
n = hbucket(t, cb->args[2]); n = hbucket(t, cb->args[2]);
@@ -960,7 +959,7 @@ type_pf_tlist(const struct ip_set *set,
if (!nested) { if (!nested) {
if (cb->args[2] == first) { if (cb->args[2] == first) {
nla_nest_cancel(skb, atd); nla_nest_cancel(skb, atd);
return -EFAULT; return -EMSGSIZE;
} else } else
goto nla_put_failure; goto nla_put_failure;
} }
@@ -982,6 +981,7 @@ nla_put_failure:
pr_warning("Can't list set %s: one bucket does not fit into " pr_warning("Can't list set %s: one bucket does not fit into "
"a message. Please report it!\n", set->name); "a message. Please report it!\n", set->name);
cb->args[2] = 0; cb->args[2] = 0;
return -EMSGSIZE;
} }
return 0; return 0;
} }

View File

@@ -13,7 +13,6 @@
#include <linux/ip.h> #include <linux/ip.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/uaccess.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/netlink.h> #include <linux/netlink.h>
@@ -33,8 +32,7 @@ MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
MODULE_DESCRIPTION("bitmap:ip type of IP sets"); MODULE_DESCRIPTION("bitmap:ip type of IP sets");
MODULE_ALIAS("ip_set_bitmap:ip"); MODULE_ALIAS("ip_set_bitmap:ip");
/* Base variant */ /* Type structure */
struct bitmap_ip { struct bitmap_ip {
void *members; /* the set members */ void *members; /* the set members */
u32 first_ip; /* host byte order, included in range */ u32 first_ip; /* host byte order, included in range */
@@ -43,43 +41,188 @@ struct bitmap_ip {
u32 hosts; /* number of hosts in a subnet */ u32 hosts; /* number of hosts in a subnet */
size_t memsize; /* members size */ size_t memsize; /* members size */
u8 netmask; /* subnet netmask */ u8 netmask; /* subnet netmask */
u32 timeout; /* timeout parameter */
struct timer_list gc; /* garbage collection */
}; };
/* Base variant */
static inline u32 static inline u32
ip_to_id(const struct bitmap_ip *m, u32 ip) ip_to_id(const struct bitmap_ip *m, u32 ip)
{ {
return ((ip & ip_set_hostmask(m->netmask)) - m->first_ip)/m->hosts; return ((ip & ip_set_hostmask(m->netmask)) - m->first_ip)/m->hosts;
} }
static inline int static int
bitmap_ip_test(const struct bitmap_ip *map, u32 id) bitmap_ip_test(struct ip_set *set, void *value, u32 timeout)
{ {
const struct bitmap_ip *map = set->data;
u16 id = *(u16 *)value;
return !!test_bit(id, map->members); return !!test_bit(id, map->members);
} }
static inline int static int
bitmap_ip_add(struct bitmap_ip *map, u32 id) bitmap_ip_add(struct ip_set *set, void *value, u32 timeout)
{ {
struct bitmap_ip *map = set->data;
u16 id = *(u16 *)value;
if (test_and_set_bit(id, map->members)) if (test_and_set_bit(id, map->members))
return -IPSET_ERR_EXIST; return -IPSET_ERR_EXIST;
return 0; return 0;
} }
static inline int static int
bitmap_ip_del(struct bitmap_ip *map, u32 id) bitmap_ip_del(struct ip_set *set, void *value, u32 timeout)
{ {
struct bitmap_ip *map = set->data;
u16 id = *(u16 *)value;
if (!test_and_clear_bit(id, map->members)) if (!test_and_clear_bit(id, map->members))
return -IPSET_ERR_EXIST; return -IPSET_ERR_EXIST;
return 0; return 0;
} }
static int
bitmap_ip_list(const struct ip_set *set,
struct sk_buff *skb, struct netlink_callback *cb)
{
const struct bitmap_ip *map = set->data;
struct nlattr *atd, *nested;
u32 id, first = cb->args[2];
atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
if (!atd)
return -EMSGSIZE;
for (; cb->args[2] < map->elements; cb->args[2]++) {
id = cb->args[2];
if (!test_bit(id, map->members))
continue;
nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
if (!nested) {
if (id == first) {
nla_nest_cancel(skb, atd);
return -EMSGSIZE;
} else
goto nla_put_failure;
}
NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP,
htonl(map->first_ip + id * map->hosts));
ipset_nest_end(skb, nested);
}
ipset_nest_end(skb, atd);
/* Set listing finished */
cb->args[2] = 0;
return 0;
nla_put_failure:
nla_nest_cancel(skb, nested);
ipset_nest_end(skb, atd);
if (unlikely(id == first)) {
cb->args[2] = 0;
return -EMSGSIZE;
}
return 0;
}
/* Timeout variant */
static int
bitmap_ip_ttest(struct ip_set *set, void *value, u32 timeout)
{
const struct bitmap_ip *map = set->data;
const unsigned long *members = map->members;
u16 id = *(u16 *)value;
return ip_set_timeout_test(members[id]);
}
static int
bitmap_ip_tadd(struct ip_set *set, void *value, u32 timeout)
{
struct bitmap_ip *map = set->data;
unsigned long *members = map->members;
u16 id = *(u16 *)value;
if (ip_set_timeout_test(members[id]))
return -IPSET_ERR_EXIST;
members[id] = ip_set_timeout_set(timeout);
return 0;
}
static int
bitmap_ip_tdel(struct ip_set *set, void *value, u32 timeout)
{
struct bitmap_ip *map = set->data;
unsigned long *members = map->members;
u16 id = *(u16 *)value;
int ret = -IPSET_ERR_EXIST;
if (ip_set_timeout_test(members[id]))
ret = 0;
members[id] = IPSET_ELEM_UNSET;
return ret;
}
static int
bitmap_ip_tlist(const struct ip_set *set,
struct sk_buff *skb, struct netlink_callback *cb)
{
const struct bitmap_ip *map = set->data;
struct nlattr *adt, *nested;
u32 id, first = cb->args[2];
const unsigned long *members = map->members;
adt = ipset_nest_start(skb, IPSET_ATTR_ADT);
if (!adt)
return -EMSGSIZE;
for (; cb->args[2] < map->elements; cb->args[2]++) {
id = cb->args[2];
if (!ip_set_timeout_test(members[id]))
continue;
nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
if (!nested) {
if (id == first) {
nla_nest_cancel(skb, adt);
return -EMSGSIZE;
} else
goto nla_put_failure;
}
NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP,
htonl(map->first_ip + id * map->hosts));
NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
htonl(ip_set_timeout_get(members[id])));
ipset_nest_end(skb, nested);
}
ipset_nest_end(skb, adt);
/* Set listing finished */
cb->args[2] = 0;
return 0;
nla_put_failure:
nla_nest_cancel(skb, nested);
ipset_nest_end(skb, adt);
if (unlikely(id == first)) {
cb->args[2] = 0;
return -EMSGSIZE;
}
return 0;
}
static int static int
bitmap_ip_kadt(struct ip_set *set, const struct sk_buff *skb, bitmap_ip_kadt(struct ip_set *set, const struct sk_buff *skb,
enum ipset_adt adt, u8 pf, u8 dim, u8 flags) enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
{ {
struct bitmap_ip *map = set->data; struct bitmap_ip *map = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
u32 ip; u32 ip;
ip = ntohl(ip4addr(skb, flags & IPSET_DIM_ONE_SRC)); ip = ntohl(ip4addr(skb, flags & IPSET_DIM_ONE_SRC));
@@ -88,40 +231,21 @@ bitmap_ip_kadt(struct ip_set *set, const struct sk_buff *skb,
ip = ip_to_id(map, ip); ip = ip_to_id(map, ip);
switch (adt) { return adtfn(set, &ip, map->timeout);
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;
}
} }
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 static int
bitmap_ip_uadt(struct ip_set *set, struct nlattr *head, int len, bitmap_ip_uadt(struct ip_set *set, struct nlattr *tb[],
enum ipset_adt adt, u32 *lineno, u32 flags) enum ipset_adt adt, u32 *lineno, u32 flags)
{ {
struct bitmap_ip *map = set->data; struct bitmap_ip *map = set->data;
struct nlattr *tb[IPSET_ATTR_ADT_MAX+1]; ipset_adtfn adtfn = set->variant->adt[adt];
u32 timeout = map->timeout;
u32 ip, ip_to, id; u32 ip, ip_to, id;
int ret = 0; int ret = 0;
if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len, if (unlikely(!tb[IPSET_ATTR_IP] ||
bitmap_ip_adt_policy)) !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
return -IPSET_ERR_PROTOCOL;
if (unlikely(!tb[IPSET_ATTR_IP]))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
if (tb[IPSET_ATTR_LINENO]) if (tb[IPSET_ATTR_LINENO])
@@ -134,13 +258,16 @@ bitmap_ip_uadt(struct ip_set *set, struct nlattr *head, int len,
if (ip < map->first_ip || ip > map->last_ip) if (ip < map->first_ip || ip > map->last_ip)
return -IPSET_ERR_BITMAP_RANGE; return -IPSET_ERR_BITMAP_RANGE;
/* Set was defined without timeout support: if (tb[IPSET_ATTR_TIMEOUT]) {
* don't ignore the attribute silently */ if (!with_timeout(map->timeout))
if (tb[IPSET_ATTR_TIMEOUT]) return -IPSET_ERR_TIMEOUT;
return -IPSET_ERR_TIMEOUT; timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
}
if (adt == IPSET_TEST) if (adt == IPSET_TEST) {
return bitmap_ip_test(map, ip_to_id(map, ip)); id = ip_to_id(map, ip);
return adtfn(set, &id, timeout);
}
if (tb[IPSET_ATTR_IP_TO]) { if (tb[IPSET_ATTR_IP_TO]) {
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to); ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
@@ -166,8 +293,7 @@ bitmap_ip_uadt(struct ip_set *set, struct nlattr *head, int len,
for (; !before(ip_to, ip); ip += map->hosts) { for (; !before(ip_to, ip); ip += map->hosts) {
id = ip_to_id(map, ip); id = ip_to_id(map, ip);
ret = adt == IPSET_ADD ? bitmap_ip_add(map, id) ret = adtfn(set, &id, timeout);;
: bitmap_ip_del(map, id);
if (ret && !ip_set_eexist(ret, flags)) if (ret && !ip_set_eexist(ret, flags))
return ret; return ret;
@@ -182,6 +308,9 @@ bitmap_ip_destroy(struct ip_set *set)
{ {
struct bitmap_ip *map = set->data; struct bitmap_ip *map = set->data;
if (with_timeout(map->timeout))
del_timer_sync(&map->gc);
ip_set_free(map->members); ip_set_free(map->members);
kfree(map); kfree(map);
@@ -213,49 +342,13 @@ bitmap_ip_head(struct ip_set *set, struct sk_buff *skb)
htonl(atomic_read(&set->ref) - 1)); htonl(atomic_read(&set->ref) - 1));
NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE, NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE,
htonl(sizeof(*map) + map->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); ipset_nest_end(skb, nested);
return 0; return 0;
nla_put_failure: nla_put_failure:
return -EFAULT; return -EMSGSIZE;
}
static int
bitmap_ip_list(const struct ip_set *set,
struct sk_buff *skb, struct netlink_callback *cb)
{
const struct bitmap_ip *map = set->data;
struct nlattr *atd, *nested;
u32 id, first = cb->args[2];
atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
if (!atd)
return -EFAULT;
for (; cb->args[2] < map->elements; cb->args[2]++) {
id = cb->args[2];
if (!bitmap_ip_test(map, id))
continue;
nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
if (!nested) {
if (id == first) {
nla_nest_cancel(skb, atd);
return -EFAULT;
} else
goto nla_put_failure;
}
NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP,
htonl(map->first_ip + id * map->hosts));
ipset_nest_end(skb, nested);
}
ipset_nest_end(skb, atd);
/* Set listing finished */
cb->args[2] = 0;
return 0;
nla_put_failure:
nla_nest_cancel(skb, nested);
ipset_nest_end(skb, atd);
return 0;
} }
static bool static bool
@@ -266,12 +359,18 @@ bitmap_ip_same_set(const struct ip_set *a, const struct ip_set *b)
return x->first_ip == y->first_ip && return x->first_ip == y->first_ip &&
x->last_ip == y->last_ip && x->last_ip == y->last_ip &&
x->netmask == y->netmask; x->netmask == y->netmask &&
x->timeout == y->timeout;
} }
static const struct ip_set_type_variant bitmap_ip = { static const struct ip_set_type_variant bitmap_ip = {
.kadt = bitmap_ip_kadt, .kadt = bitmap_ip_kadt,
.uadt = bitmap_ip_uadt, .uadt = bitmap_ip_uadt,
.adt = {
[IPSET_ADD] = bitmap_ip_add,
[IPSET_DEL] = bitmap_ip_del,
[IPSET_TEST] = bitmap_ip_test,
},
.destroy = bitmap_ip_destroy, .destroy = bitmap_ip_destroy,
.flush = bitmap_ip_flush, .flush = bitmap_ip_flush,
.head = bitmap_ip_head, .head = bitmap_ip_head,
@@ -279,261 +378,26 @@ static const struct ip_set_type_variant bitmap_ip = {
.same_set = bitmap_ip_same_set, .same_set = bitmap_ip_same_set,
}; };
/* Timeout variant */ static const struct ip_set_type_variant bitmap_tip = {
.kadt = bitmap_ip_kadt,
struct bitmap_ip_timeout { .uadt = bitmap_ip_uadt,
unsigned long *members; /* the set members */ .adt = {
u32 first_ip; /* host byte order, included in range */ [IPSET_ADD] = bitmap_ip_tadd,
u32 last_ip; /* host byte order, included in range */ [IPSET_DEL] = bitmap_ip_tdel,
u32 elements; /* number of max elements in the set */ [IPSET_TEST] = bitmap_ip_ttest,
u32 hosts; /* number of hosts in a subnet */ },
size_t memsize; /* members size */ .destroy = bitmap_ip_destroy,
u8 netmask; /* subnet netmask */ .flush = bitmap_ip_flush,
.head = bitmap_ip_head,
u32 timeout; /* timeout parameter */ .list = bitmap_ip_tlist,
struct timer_list gc; /* garbage collection */ .same_set = bitmap_ip_same_set,
};
static inline bool
bitmap_ip_timeout_test(const struct bitmap_ip_timeout *map, u32 id)
{
return ip_set_timeout_test(map->members[id]);
}
static inline int
bitmap_ip_timeout_add(struct bitmap_ip_timeout *map,
u32 id, u32 timeout)
{
if (bitmap_ip_timeout_test(map, id))
return -IPSET_ERR_EXIST;
map->members[id] = ip_set_timeout_set(timeout);
return 0;
}
static inline int
bitmap_ip_timeout_del(struct bitmap_ip_timeout *map, u32 id)
{
int ret = -IPSET_ERR_EXIST;
if (bitmap_ip_timeout_test(map, id))
ret = 0;
map->members[id] = IPSET_ELEM_UNSET;
return ret;
}
static int
bitmap_ip_timeout_kadt(struct ip_set *set, const struct sk_buff *skb,
enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
{
struct bitmap_ip_timeout *map = set->data;
u32 ip;
ip = ntohl(ip4addr(skb, flags & IPSET_DIM_ONE_SRC));
if (ip < map->first_ip || ip > map->last_ip)
return -IPSET_ERR_BITMAP_RANGE;
ip = ip_to_id((const struct bitmap_ip *)map, ip);
switch (adt) {
case IPSET_TEST:
return bitmap_ip_timeout_test(map, ip);
case IPSET_ADD:
return bitmap_ip_timeout_add(map, ip, map->timeout);
case IPSET_DEL:
return bitmap_ip_timeout_del(map, ip);
default:
return -EINVAL;
}
}
static int
bitmap_ip_timeout_uadt(struct ip_set *set, struct nlattr *head, int len,
enum ipset_adt adt, u32 *lineno, u32 flags)
{
struct bitmap_ip_timeout *map = set->data;
struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
u32 ip, ip_to, id, timeout = map->timeout;
int ret = 0;
if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
bitmap_ip_adt_policy))
return -IPSET_ERR_PROTOCOL;
if (unlikely(!tb[IPSET_ATTR_IP] ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
return -IPSET_ERR_PROTOCOL;
if (tb[IPSET_ATTR_LINENO])
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip);
if (ret)
return ret;
if (ip < map->first_ip || ip > map->last_ip)
return -IPSET_ERR_BITMAP_RANGE;
if (adt == IPSET_TEST)
return bitmap_ip_timeout_test(map,
ip_to_id((const struct bitmap_ip *)map, ip));
if (tb[IPSET_ATTR_IP_TO]) {
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
if (ret)
return ret;
if (ip > ip_to) {
swap(ip, ip_to);
if (ip < map->first_ip)
return -IPSET_ERR_BITMAP_RANGE;
}
} else if (tb[IPSET_ATTR_CIDR]) {
u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
if (cidr > 32)
return -IPSET_ERR_INVALID_CIDR;
ip &= ip_set_hostmask(cidr);
ip_to = ip | ~ip_set_hostmask(cidr);
} else
ip_to = ip;
if (ip_to > map->last_ip)
return -IPSET_ERR_BITMAP_RANGE;
if (tb[IPSET_ATTR_TIMEOUT])
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
for (; !before(ip_to, ip); ip += map->hosts) {
id = ip_to_id((const struct bitmap_ip *)map, ip);
ret = adt == IPSET_ADD
? bitmap_ip_timeout_add(map, id, timeout)
: bitmap_ip_timeout_del(map, id);
if (ret && !ip_set_eexist(ret, flags))
return ret;
else
ret = 0;
}
return ret;
}
static void
bitmap_ip_timeout_destroy(struct ip_set *set)
{
struct bitmap_ip_timeout *map = set->data;
del_timer_sync(&map->gc);
ip_set_free(map->members);
kfree(map);
set->data = NULL;
}
static void
bitmap_ip_timeout_flush(struct ip_set *set)
{
struct bitmap_ip_timeout *map = set->data;
memset(map->members, IPSET_ELEM_UNSET, map->memsize);
}
static int
bitmap_ip_timeout_head(struct ip_set *set, struct sk_buff *skb)
{
const struct bitmap_ip_timeout *map = set->data;
struct nlattr *nested;
nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
if (!nested)
goto nla_put_failure;
NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, htonl(map->first_ip));
NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP_TO, htonl(map->last_ip));
if (map->netmask != 32)
NLA_PUT_U8(skb, IPSET_ATTR_NETMASK, map->netmask);
NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, htonl(map->timeout));
NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES,
htonl(atomic_read(&set->ref) - 1));
NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE,
htonl(sizeof(*map) + map->memsize));
ipset_nest_end(skb, nested);
return 0;
nla_put_failure:
return -EFAULT;
}
static int
bitmap_ip_timeout_list(const struct ip_set *set,
struct sk_buff *skb, struct netlink_callback *cb)
{
const struct bitmap_ip_timeout *map = set->data;
struct nlattr *adt, *nested;
u32 id, first = cb->args[2];
const unsigned long *table = map->members;
adt = ipset_nest_start(skb, IPSET_ATTR_ADT);
if (!adt)
return -EFAULT;
for (; cb->args[2] < map->elements; cb->args[2]++) {
id = cb->args[2];
if (!bitmap_ip_timeout_test(map, id))
continue;
nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
if (!nested) {
if (id == first) {
nla_nest_cancel(skb, adt);
return -EFAULT;
} else
goto nla_put_failure;
}
NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP,
htonl(map->first_ip + id * map->hosts));
NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
htonl(ip_set_timeout_get(table[id])));
ipset_nest_end(skb, nested);
}
ipset_nest_end(skb, adt);
/* Set listing finished */
cb->args[2] = 0;
return 0;
nla_put_failure:
nla_nest_cancel(skb, nested);
ipset_nest_end(skb, adt);
return 0;
}
static bool
bitmap_ip_timeout_same_set(const struct ip_set *a, const struct ip_set *b)
{
const struct bitmap_ip_timeout *x = a->data;
const struct bitmap_ip_timeout *y = b->data;
return x->first_ip == y->first_ip &&
x->last_ip == y->last_ip &&
x->netmask == y->netmask &&
x->timeout == y->timeout;
}
static const struct ip_set_type_variant bitmap_ip_timeout = {
.kadt = bitmap_ip_timeout_kadt,
.uadt = bitmap_ip_timeout_uadt,
.destroy = bitmap_ip_timeout_destroy,
.flush = bitmap_ip_timeout_flush,
.head = bitmap_ip_timeout_head,
.list = bitmap_ip_timeout_list,
.same_set = bitmap_ip_timeout_same_set,
}; };
static void static void
bitmap_ip_gc(unsigned long ul_set) bitmap_ip_gc(unsigned long ul_set)
{ {
struct ip_set *set = (struct ip_set *) 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; unsigned long *table = map->members;
u32 id; u32 id;
@@ -552,7 +416,7 @@ bitmap_ip_gc(unsigned long ul_set)
static void static void
bitmap_ip_gc_init(struct ip_set *set) 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); init_timer(&map->gc);
map->gc.data = (unsigned long) set; map->gc.data = (unsigned long) set;
@@ -563,21 +427,12 @@ bitmap_ip_gc_init(struct ip_set *set)
/* Create bitmap:ip type of sets */ /* 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 static bool
init_map_ip(struct ip_set *set, struct bitmap_ip *map, init_map_ip(struct ip_set *set, struct bitmap_ip *map,
u32 first_ip, u32 last_ip, u32 first_ip, u32 last_ip,
u32 elements, u32 hosts, u8 netmask) 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) if (!map->members)
return false; return false;
map->first_ip = first_ip; map->first_ip = first_ip;
@@ -585,6 +440,7 @@ init_map_ip(struct ip_set *set, struct bitmap_ip *map,
map->elements = elements; map->elements = elements;
map->hosts = hosts; map->hosts = hosts;
map->netmask = netmask; map->netmask = netmask;
map->timeout = IPSET_NO_TIMEOUT;
set->data = map; set->data = map;
set->family = AF_INET; set->family = AF_INET;
@@ -593,18 +449,13 @@ init_map_ip(struct ip_set *set, struct bitmap_ip *map,
} }
static int static int
bitmap_ip_create(struct ip_set *set, struct nlattr *head, int len, bitmap_ip_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
u32 flags)
{ {
struct nlattr *tb[IPSET_ATTR_CREATE_MAX+1]; struct bitmap_ip *map;
u32 first_ip, last_ip, hosts, elements; u32 first_ip, last_ip, hosts, elements;
u8 netmask = 32; u8 netmask = 32;
int ret; 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] || if (unlikely(!tb[IPSET_ATTR_IP] ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT))) !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
@@ -664,37 +515,27 @@ bitmap_ip_create(struct ip_set *set, struct nlattr *head, int len,
pr_debug("hosts %u, elements %u\n", hosts, elements); pr_debug("hosts %u, elements %u\n", hosts, elements);
map = kzalloc(sizeof(*map), GFP_KERNEL);
if (!map)
return -ENOMEM;
if (tb[IPSET_ATTR_TIMEOUT]) { if (tb[IPSET_ATTR_TIMEOUT]) {
struct bitmap_ip_timeout *map;
map = kzalloc(sizeof(*map), GFP_KERNEL);
if (!map)
return -ENOMEM;
map->memsize = elements * sizeof(unsigned long); map->memsize = elements * sizeof(unsigned long);
if (!init_map_ip(set, (struct bitmap_ip *)map, if (!init_map_ip(set, map, first_ip, last_ip,
first_ip, last_ip,
elements, hosts, netmask)) { elements, hosts, netmask)) {
kfree(map); kfree(map);
return -ENOMEM; return -ENOMEM;
} }
map->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); map->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
set->variant = &bitmap_ip_timeout; set->variant = &bitmap_tip;
bitmap_ip_gc_init(set); bitmap_ip_gc_init(set);
} else { } else {
struct bitmap_ip *map;
map = kzalloc(sizeof(*map), GFP_KERNEL);
if (!map)
return -ENOMEM;
map->memsize = bitmap_bytes(0, elements - 1); map->memsize = bitmap_bytes(0, elements - 1);
if (!init_map_ip(set, map, if (!init_map_ip(set, map, first_ip, last_ip,
first_ip, last_ip,
elements, hosts, netmask)) { elements, hosts, netmask)) {
kfree(map); kfree(map);
return -ENOMEM; return -ENOMEM;
@@ -713,6 +554,20 @@ static struct ip_set_type bitmap_ip_type __read_mostly = {
.family = AF_INET, .family = AF_INET,
.revision = 0, .revision = 0,
.create = bitmap_ip_create, .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, .me = THIS_MODULE,
}; };

View File

@@ -15,9 +15,6 @@
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/uaccess.h>
#include <linux/bitops.h>
#include <linux/spinlock.h>
#include <linux/if_ether.h> #include <linux/if_ether.h>
#include <linux/netlink.h> #include <linux/netlink.h>
#include <linux/jiffies.h> #include <linux/jiffies.h>
@@ -175,7 +172,7 @@ bitmap_ipmac_list(const struct ip_set *set,
atd = ipset_nest_start(skb, IPSET_ATTR_ADT); atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
if (!atd) if (!atd)
return -EFAULT; return -EMSGSIZE;
for (; cb->args[2] <= last; cb->args[2]++) { for (; cb->args[2] <= last; cb->args[2]++) {
id = cb->args[2]; id = cb->args[2];
elem = bitmap_ipmac_elem(map, id); elem = bitmap_ipmac_elem(map, id);
@@ -185,7 +182,7 @@ bitmap_ipmac_list(const struct ip_set *set,
if (!nested) { if (!nested) {
if (id == first) { if (id == first) {
nla_nest_cancel(skb, atd); nla_nest_cancel(skb, atd);
return -EFAULT; return -EMSGSIZE;
} else } else
goto nla_put_failure; goto nla_put_failure;
} }
@@ -205,6 +202,10 @@ bitmap_ipmac_list(const struct ip_set *set,
nla_put_failure: nla_put_failure:
nla_nest_cancel(skb, nested); nla_nest_cancel(skb, nested);
ipset_nest_end(skb, atd); ipset_nest_end(skb, atd);
if (unlikely(id == first)) {
cb->args[2] = 0;
return -EMSGSIZE;
}
return 0; return 0;
} }
@@ -298,7 +299,7 @@ bitmap_ipmac_tlist(const struct ip_set *set,
atd = ipset_nest_start(skb, IPSET_ATTR_ADT); atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
if (!atd) if (!atd)
return -EFAULT; return -EMSGSIZE;
for (; cb->args[2] <= last; cb->args[2]++) { for (; cb->args[2] <= last; cb->args[2]++) {
id = cb->args[2]; id = cb->args[2];
elem = bitmap_ipmac_elem(map, id); elem = bitmap_ipmac_elem(map, id);
@@ -308,7 +309,7 @@ bitmap_ipmac_tlist(const struct ip_set *set,
if (!nested) { if (!nested) {
if (id == first) { if (id == first) {
nla_nest_cancel(skb, atd); nla_nest_cancel(skb, atd);
return -EFAULT; return -EMSGSIZE;
} else } else
goto nla_put_failure; goto nla_put_failure;
} }
@@ -331,7 +332,7 @@ bitmap_ipmac_tlist(const struct ip_set *set,
nla_put_failure: nla_put_failure:
nla_nest_cancel(skb, nested); nla_nest_cancel(skb, nested);
ipset_nest_end(skb, atd); ipset_nest_end(skb, atd);
return 0; return -EMSGSIZE;
} }
static int static int
@@ -357,29 +358,16 @@ bitmap_ipmac_kadt(struct ip_set *set, const struct sk_buff *skb,
return adtfn(set, &data, map->timeout); 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 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) enum ipset_adt adt, u32 *lineno, u32 flags)
{ {
const struct bitmap_ipmac *map = set->data; const struct bitmap_ipmac *map = set->data;
struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
ipset_adtfn adtfn = set->variant->adt[adt]; ipset_adtfn adtfn = set->variant->adt[adt];
struct ipmac data; struct ipmac data;
u32 timeout = map->timeout; u32 timeout = map->timeout;
int ret = 0; 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] || if (unlikely(!tb[IPSET_ATTR_IP] ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT))) !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
@@ -457,7 +445,7 @@ bitmap_ipmac_head(struct ip_set *set, struct sk_buff *skb)
return 0; return 0;
nla_put_failure: nla_put_failure:
return -EFAULT; return -EMSGSIZE;
} }
static bool static bool
@@ -538,20 +526,11 @@ bitmap_ipmac_gc_init(struct ip_set *set)
/* Create bitmap:ip,mac type of sets */ /* 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 static bool
init_map_ipmac(struct ip_set *set, struct bitmap_ipmac *map, init_map_ipmac(struct ip_set *set, struct bitmap_ipmac *map,
u32 first_ip, u32 last_ip) u32 first_ip, u32 last_ip)
{ {
map->members = ip_set_alloc((last_ip - first_ip + 1) * map->dsize, map->members = ip_set_alloc((last_ip - first_ip + 1) * map->dsize);
GFP_KERNEL);
if (!map->members) if (!map->members)
return false; return false;
map->first_ip = first_ip; map->first_ip = first_ip;
@@ -565,18 +544,13 @@ init_map_ipmac(struct ip_set *set, struct bitmap_ipmac *map,
} }
static int 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) u32 flags)
{ {
struct nlattr *tb[IPSET_ATTR_CREATE_MAX+1];
u32 first_ip, last_ip, elements; u32 first_ip, last_ip, elements;
struct bitmap_ipmac *map; struct bitmap_ipmac *map;
int ret; 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] || if (unlikely(!tb[IPSET_ATTR_IP] ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT))) !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
@@ -647,6 +621,18 @@ static struct ip_set_type bitmap_ipmac_type = {
.family = AF_INET, .family = AF_INET,
.revision = 0, .revision = 0,
.create = bitmap_ipmac_create, .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, .me = THIS_MODULE,
}; };

View File

@@ -9,13 +9,8 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/ip.h> #include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/uaccess.h>
#include <linux/bitops.h>
#include <linux/spinlock.h>
#include <linux/netlink.h> #include <linux/netlink.h>
#include <linux/jiffies.h> #include <linux/jiffies.h>
#include <linux/timer.h> #include <linux/timer.h>
@@ -32,24 +27,33 @@ MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
MODULE_DESCRIPTION("bitmap:port type of IP sets"); MODULE_DESCRIPTION("bitmap:port type of IP sets");
MODULE_ALIAS("ip_set_bitmap:port"); MODULE_ALIAS("ip_set_bitmap:port");
/* Base variant */ /* Type structure */
struct bitmap_port { struct bitmap_port {
void *members; /* the set members */ void *members; /* the set members */
u16 first_port; /* host byte order, included in range */ u16 first_port; /* host byte order, included in range */
u16 last_port; /* host byte order, included in range */ u16 last_port; /* host byte order, included in range */
size_t memsize; /* members size */ size_t memsize; /* members size */
u32 timeout; /* timeout parameter */
struct timer_list gc; /* garbage collection */
}; };
static inline int /* Base variant */
bitmap_port_test(const struct bitmap_port *map, u16 id)
static int
bitmap_port_test(struct ip_set *set, void *value, u32 timeout)
{ {
const struct bitmap_port *map = set->data;
u16 id = *(u16 *)value;
return !!test_bit(id, map->members); return !!test_bit(id, map->members);
} }
static inline int static int
bitmap_port_add(struct bitmap_port *map, u16 id) bitmap_port_add(struct ip_set *set, void *value, u32 timeout)
{ {
struct bitmap_port *map = set->data;
u16 id = *(u16 *)value;
if (test_and_set_bit(id, map->members)) if (test_and_set_bit(id, map->members))
return -IPSET_ERR_EXIST; return -IPSET_ERR_EXIST;
@@ -57,19 +61,157 @@ bitmap_port_add(struct bitmap_port *map, u16 id)
} }
static int static int
bitmap_port_del(struct bitmap_port *map, u16 id) bitmap_port_del(struct ip_set *set, void *value, u32 timeout)
{ {
struct bitmap_port *map = set->data;
u16 id = *(u16 *)value;
if (!test_and_clear_bit(id, map->members)) if (!test_and_clear_bit(id, map->members))
return -IPSET_ERR_EXIST; return -IPSET_ERR_EXIST;
return 0; return 0;
} }
static int
bitmap_port_list(const struct ip_set *set,
struct sk_buff *skb, struct netlink_callback *cb)
{
const struct bitmap_port *map = set->data;
struct nlattr *atd, *nested;
u16 id, first = cb->args[2];
u16 last = map->last_port - map->first_port;
atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
if (!atd)
return -EMSGSIZE;
for (; cb->args[2] <= last; cb->args[2]++) {
id = cb->args[2];
if (!test_bit(id, map->members))
continue;
nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
if (!nested) {
if (id == first) {
nla_nest_cancel(skb, atd);
return -EMSGSIZE;
} else
goto nla_put_failure;
}
NLA_PUT_NET16(skb, IPSET_ATTR_PORT,
htons(map->first_port + id));
ipset_nest_end(skb, nested);
}
ipset_nest_end(skb, atd);
/* Set listing finished */
cb->args[2] = 0;
return 0;
nla_put_failure:
nla_nest_cancel(skb, nested);
ipset_nest_end(skb, atd);
if (unlikely(id == first)) {
cb->args[2] = 0;
return -EMSGSIZE;
}
return 0;
}
/* Timeout variant */
static int
bitmap_port_ttest(struct ip_set *set, void *value, u32 timeout)
{
const struct bitmap_port *map = set->data;
const unsigned long *members = map->members;
u16 id = *(u16 *)value;
return ip_set_timeout_test(members[id]);
}
static int
bitmap_port_tadd(struct ip_set *set, void *value, u32 timeout)
{
struct bitmap_port *map = set->data;
unsigned long *members = map->members;
u16 id = *(u16 *)value;
if (ip_set_timeout_test(members[id]))
return -IPSET_ERR_EXIST;
members[id] = ip_set_timeout_set(timeout);
return 0;
}
static int
bitmap_port_tdel(struct ip_set *set, void *value, u32 timeout)
{
struct bitmap_port *map = set->data;
unsigned long *members = map->members;
u16 id = *(u16 *)value;
int ret = -IPSET_ERR_EXIST;
if (ip_set_timeout_test(members[id]))
ret = 0;
members[id] = IPSET_ELEM_UNSET;
return ret;
}
static int
bitmap_port_tlist(const struct ip_set *set,
struct sk_buff *skb, struct netlink_callback *cb)
{
const struct bitmap_port *map = set->data;
struct nlattr *adt, *nested;
u16 id, first = cb->args[2];
u16 last = map->last_port - map->first_port;
const unsigned long *members = map->members;
adt = ipset_nest_start(skb, IPSET_ATTR_ADT);
if (!adt)
return -EMSGSIZE;
for (; cb->args[2] <= last; cb->args[2]++) {
id = cb->args[2];
if (!ip_set_timeout_test(members[id]))
continue;
nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
if (!nested) {
if (id == first) {
nla_nest_cancel(skb, adt);
return -EMSGSIZE;
} else
goto nla_put_failure;
}
NLA_PUT_NET16(skb, IPSET_ATTR_PORT,
htons(map->first_port + id));
NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
htonl(ip_set_timeout_get(members[id])));
ipset_nest_end(skb, nested);
}
ipset_nest_end(skb, adt);
/* Set listing finished */
cb->args[2] = 0;
return 0;
nla_put_failure:
nla_nest_cancel(skb, nested);
ipset_nest_end(skb, adt);
if (unlikely(id == first)) {
cb->args[2] = 0;
return -EMSGSIZE;
}
return 0;
}
static int static int
bitmap_port_kadt(struct ip_set *set, const struct sk_buff *skb, bitmap_port_kadt(struct ip_set *set, const struct sk_buff *skb,
enum ipset_adt adt, u8 pf, u8 dim, u8 flags) enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
{ {
struct bitmap_port *map = set->data; struct bitmap_port *map = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
__be16 __port; __be16 __port;
u16 port = 0; u16 port = 0;
@@ -83,41 +225,23 @@ bitmap_port_kadt(struct ip_set *set, const struct sk_buff *skb,
port -= map->first_port; port -= map->first_port;
switch (adt) { return adtfn(set, &port, map->timeout);
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;
}
} }
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 static int
bitmap_port_uadt(struct ip_set *set, struct nlattr *head, int len, bitmap_port_uadt(struct ip_set *set, struct nlattr *tb[],
enum ipset_adt adt, u32 *lineno, u32 flags) enum ipset_adt adt, u32 *lineno, u32 flags)
{ {
struct bitmap_port *map = set->data; struct bitmap_port *map = set->data;
struct nlattr *tb[IPSET_ATTR_ADT_MAX+1]; ipset_adtfn adtfn = set->variant->adt[adt];
u32 timeout = map->timeout;
u32 port; /* wraparound */ u32 port; /* wraparound */
u16 id, port_to; u16 id, port_to;
int ret = 0; 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) || if (unlikely(!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO))) !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
if (tb[IPSET_ATTR_LINENO]) if (tb[IPSET_ATTR_LINENO])
@@ -127,11 +251,16 @@ bitmap_port_uadt(struct ip_set *set, struct nlattr *head, int len,
if (port < map->first_port || port > map->last_port) if (port < map->first_port || port > map->last_port)
return -IPSET_ERR_BITMAP_RANGE; return -IPSET_ERR_BITMAP_RANGE;
if (tb[IPSET_ATTR_TIMEOUT]) if (tb[IPSET_ATTR_TIMEOUT]) {
return -IPSET_ERR_TIMEOUT; if (!with_timeout(map->timeout))
return -IPSET_ERR_TIMEOUT;
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
}
if (adt == IPSET_TEST) if (adt == IPSET_TEST) {
return bitmap_port_test(map, port - map->first_port); id = port - map->first_port;
return adtfn(set, &id, timeout);
}
if (tb[IPSET_ATTR_PORT_TO]) { if (tb[IPSET_ATTR_PORT_TO]) {
port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]); port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
@@ -148,8 +277,7 @@ bitmap_port_uadt(struct ip_set *set, struct nlattr *head, int len,
for (; port <= port_to; port++) { for (; port <= port_to; port++) {
id = port - map->first_port; id = port - map->first_port;
ret = adt == IPSET_ADD ? bitmap_port_add(map, id) ret = adtfn(set, &id, timeout);
: bitmap_port_del(map, id);
if (ret && !ip_set_eexist(ret, flags)) if (ret && !ip_set_eexist(ret, flags))
return ret; return ret;
@@ -164,6 +292,9 @@ bitmap_port_destroy(struct ip_set *set)
{ {
struct bitmap_port *map = set->data; struct bitmap_port *map = set->data;
if (with_timeout(map->timeout))
del_timer_sync(&map->gc);
ip_set_free(map->members); ip_set_free(map->members);
kfree(map); kfree(map);
@@ -193,51 +324,13 @@ bitmap_port_head(struct ip_set *set, struct sk_buff *skb)
htonl(atomic_read(&set->ref) - 1)); htonl(atomic_read(&set->ref) - 1));
NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE, NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE,
htonl(sizeof(*map) + map->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); ipset_nest_end(skb, nested);
return 0; return 0;
nla_put_failure: nla_put_failure:
return -EFAULT; return -EMSGSIZE;
}
static int
bitmap_port_list(const struct ip_set *set,
struct sk_buff *skb, struct netlink_callback *cb)
{
const struct bitmap_port *map = set->data;
struct nlattr *atd, *nested;
u16 id, first = cb->args[2];
u16 last = map->last_port - map->first_port;
atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
if (!atd)
return -EFAULT;
for (; cb->args[2] <= last; cb->args[2]++) {
id = cb->args[2];
if (!test_bit(id, map->members))
continue;
nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
if (!nested) {
if (id == first) {
nla_nest_cancel(skb, atd);
return -EFAULT;
} else
goto nla_put_failure;
}
NLA_PUT_NET16(skb, IPSET_ATTR_PORT,
htons(map->first_port + id));
ipset_nest_end(skb, nested);
}
ipset_nest_end(skb, atd);
/* Set listing finished */
cb->args[2] = 0;
return 0;
nla_put_failure:
nla_nest_cancel(skb, nested);
ipset_nest_end(skb, atd);
return 0;
} }
static bool static bool
@@ -247,12 +340,18 @@ bitmap_port_same_set(const struct ip_set *a, const struct ip_set *b)
const struct bitmap_port *y = b->data; const struct bitmap_port *y = b->data;
return x->first_port == y->first_port && return x->first_port == y->first_port &&
x->last_port == y->last_port; x->last_port == y->last_port &&
x->timeout == y->timeout;
} }
static const struct ip_set_type_variant bitmap_port = { static const struct ip_set_type_variant bitmap_port = {
.kadt = bitmap_port_kadt, .kadt = bitmap_port_kadt,
.uadt = bitmap_port_uadt, .uadt = bitmap_port_uadt,
.adt = {
[IPSET_ADD] = bitmap_port_add,
[IPSET_DEL] = bitmap_port_del,
[IPSET_TEST] = bitmap_port_test,
},
.destroy = bitmap_port_destroy, .destroy = bitmap_port_destroy,
.flush = bitmap_port_flush, .flush = bitmap_port_flush,
.head = bitmap_port_head, .head = bitmap_port_head,
@@ -260,251 +359,26 @@ static const struct ip_set_type_variant bitmap_port = {
.same_set = bitmap_port_same_set, .same_set = bitmap_port_same_set,
}; };
/* Timeout variant */ static const struct ip_set_type_variant bitmap_tport = {
.kadt = bitmap_port_kadt,
struct bitmap_port_timeout { .uadt = bitmap_port_uadt,
unsigned long *members; /* the set members */ .adt = {
u16 first_port; /* host byte order, included in range */ [IPSET_ADD] = bitmap_port_tadd,
u16 last_port; /* host byte order, included in range */ [IPSET_DEL] = bitmap_port_tdel,
size_t memsize; /* members size */ [IPSET_TEST] = bitmap_port_ttest,
},
u32 timeout; /* timeout parameter */ .destroy = bitmap_port_destroy,
struct timer_list gc; /* garbage collection */ .flush = bitmap_port_flush,
}; .head = bitmap_port_head,
.list = bitmap_port_tlist,
static inline bool .same_set = bitmap_port_same_set,
bitmap_port_timeout_test(const struct bitmap_port_timeout *map, u16 id)
{
return ip_set_timeout_test(map->members[id]);
}
static int
bitmap_port_timeout_add(const struct bitmap_port_timeout *map,
u16 id, u32 timeout)
{
if (bitmap_port_timeout_test(map, id))
return -IPSET_ERR_EXIST;
map->members[id] = ip_set_timeout_set(timeout);
return 0;
}
static int
bitmap_port_timeout_del(const struct bitmap_port_timeout *map,
u16 id)
{
int ret = -IPSET_ERR_EXIST;
if (bitmap_port_timeout_test(map, id))
ret = 0;
map->members[id] = IPSET_ELEM_UNSET;
return ret;
}
static int
bitmap_port_timeout_kadt(struct ip_set *set, const struct sk_buff *skb,
enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
{
struct bitmap_port_timeout *map = set->data;
__be16 __port;
u16 port = 0;
if (!ip_set_get_ip_port(skb, pf, flags & IPSET_DIM_ONE_SRC, &__port))
return -EINVAL;
port = ntohs(__port);
if (port < map->first_port || port > map->last_port)
return -IPSET_ERR_BITMAP_RANGE;
port -= map->first_port;
switch (adt) {
case IPSET_TEST:
return bitmap_port_timeout_test(map, port);
case IPSET_ADD:
return bitmap_port_timeout_add(map, port, map->timeout);
case IPSET_DEL:
return bitmap_port_timeout_del(map, port);
default:
return -EINVAL;
}
}
static int
bitmap_port_timeout_uadt(struct ip_set *set, struct nlattr *head, int len,
enum ipset_adt adt, u32 *lineno, u32 flags)
{
const struct bitmap_port_timeout *map = set->data;
struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
u16 id, port_to;
u32 port, timeout = map->timeout; /* wraparound */
int ret = 0;
if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
bitmap_port_adt_policy))
return -IPSET_ERR_PROTOCOL;
if (unlikely(!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
return -IPSET_ERR_PROTOCOL;
if (tb[IPSET_ATTR_LINENO])
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
port = ip_set_get_h16(tb[IPSET_ATTR_PORT]);
if (port < map->first_port || port > map->last_port)
return -IPSET_ERR_BITMAP_RANGE;
if (adt == IPSET_TEST)
return bitmap_port_timeout_test(map, port - map->first_port);
if (tb[IPSET_ATTR_PORT_TO]) {
port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
if (port > port_to) {
swap(port, port_to);
if (port < map->first_port)
return -IPSET_ERR_BITMAP_RANGE;
}
} else
port_to = port;
if (port_to > map->last_port)
return -IPSET_ERR_BITMAP_RANGE;
if (tb[IPSET_ATTR_TIMEOUT])
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
for (; port <= port_to; port++) {
id = port - map->first_port;
ret = adt == IPSET_ADD
? bitmap_port_timeout_add(map, id, timeout)
: bitmap_port_timeout_del(map, id);
if (ret && !ip_set_eexist(ret, flags))
return ret;
else
ret = 0;
}
return ret;
}
static void
bitmap_port_timeout_destroy(struct ip_set *set)
{
struct bitmap_port_timeout *map = set->data;
del_timer_sync(&map->gc);
ip_set_free(map->members);
kfree(map);
set->data = NULL;
}
static void
bitmap_port_timeout_flush(struct ip_set *set)
{
struct bitmap_port_timeout *map = set->data;
memset(map->members, 0, map->memsize);
}
static int
bitmap_port_timeout_head(struct ip_set *set, struct sk_buff *skb)
{
const struct bitmap_port_timeout *map = set->data;
struct nlattr *nested;
nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
if (!nested)
goto nla_put_failure;
NLA_PUT_NET16(skb, IPSET_ATTR_PORT, htons(map->first_port));
NLA_PUT_NET16(skb, IPSET_ATTR_PORT_TO, htons(map->last_port));
NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT , htonl(map->timeout));
NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES,
htonl(atomic_read(&set->ref) - 1));
NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE,
htonl(sizeof(*map) + map->memsize));
ipset_nest_end(skb, nested);
return 0;
nla_put_failure:
return -EFAULT;
}
static int
bitmap_port_timeout_list(const struct ip_set *set,
struct sk_buff *skb, struct netlink_callback *cb)
{
const struct bitmap_port_timeout *map = set->data;
struct nlattr *adt, *nested;
u16 id, first = cb->args[2];
u16 last = map->last_port - map->first_port;
const unsigned long *table = map->members;
adt = ipset_nest_start(skb, IPSET_ATTR_ADT);
if (!adt)
return -EFAULT;
for (; cb->args[2] <= last; cb->args[2]++) {
id = cb->args[2];
if (!bitmap_port_timeout_test(map, id))
continue;
nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
if (!nested) {
if (id == first) {
nla_nest_cancel(skb, adt);
return -EFAULT;
} else
goto nla_put_failure;
}
NLA_PUT_NET16(skb, IPSET_ATTR_PORT,
htons(map->first_port + id));
NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
htonl(ip_set_timeout_get(table[id])));
ipset_nest_end(skb, nested);
}
ipset_nest_end(skb, adt);
/* Set listing finished */
cb->args[2] = 0;
return 0;
nla_put_failure:
nla_nest_cancel(skb, nested);
ipset_nest_end(skb, adt);
return 0;
}
static bool
bitmap_port_timeout_same_set(const struct ip_set *a, const struct ip_set *b)
{
const struct bitmap_port_timeout *x = a->data;
const struct bitmap_port_timeout *y = b->data;
return x->first_port == y->first_port &&
x->last_port == y->last_port &&
x->timeout == y->timeout;
}
static const struct ip_set_type_variant bitmap_port_timeout = {
.kadt = bitmap_port_timeout_kadt,
.uadt = bitmap_port_timeout_uadt,
.destroy = bitmap_port_timeout_destroy,
.flush = bitmap_port_timeout_flush,
.head = bitmap_port_timeout_head,
.list = bitmap_port_timeout_list,
.same_set = bitmap_port_timeout_same_set,
}; };
static void static void
bitmap_port_gc(unsigned long ul_set) bitmap_port_gc(unsigned long ul_set)
{ {
struct ip_set *set = (struct ip_set *) 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; unsigned long *table = map->members;
u32 id; /* wraparound */ u32 id; /* wraparound */
u16 last = map->last_port - map->first_port; u16 last = map->last_port - map->first_port;
@@ -524,7 +398,7 @@ bitmap_port_gc(unsigned long ul_set)
static void static void
bitmap_port_gc_init(struct ip_set *set) 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); init_timer(&map->gc);
map->gc.data = (unsigned long) set; map->gc.data = (unsigned long) set;
@@ -535,22 +409,16 @@ bitmap_port_gc_init(struct ip_set *set)
/* Create bitmap:ip type of sets */ /* 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 static bool
init_map_port(struct ip_set *set, struct bitmap_port *map, init_map_port(struct ip_set *set, struct bitmap_port *map,
u16 first_port, u16 last_port) 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) if (!map->members)
return false; return false;
map->first_port = first_port; map->first_port = first_port;
map->last_port = last_port; map->last_port = last_port;
map->timeout = IPSET_NO_TIMEOUT;
set->data = map; set->data = map;
set->family = AF_UNSPEC; set->family = AF_UNSPEC;
@@ -559,16 +427,12 @@ init_map_port(struct ip_set *set, struct bitmap_port *map,
} }
static int 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) u32 flags)
{ {
struct nlattr *tb[IPSET_ATTR_CREATE_MAX+1]; struct bitmap_port *map;
u16 first_port, last_port; 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) || if (unlikely(!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
!ip_set_attr_netorder(tb, IPSET_ATTR_PORT_TO) || !ip_set_attr_netorder(tb, IPSET_ATTR_PORT_TO) ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT))) !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
@@ -583,33 +447,24 @@ bitmap_port_create(struct ip_set *set, struct nlattr *head, int len,
last_port = tmp; last_port = tmp;
} }
map = kzalloc(sizeof(*map), GFP_KERNEL);
if (!map)
return -ENOMEM;
if (tb[IPSET_ATTR_TIMEOUT]) { if (tb[IPSET_ATTR_TIMEOUT]) {
struct bitmap_port_timeout *map;
map = kzalloc(sizeof(*map), GFP_KERNEL);
if (!map)
return -ENOMEM;
map->memsize = (last_port - first_port + 1) map->memsize = (last_port - first_port + 1)
* sizeof(unsigned long); * sizeof(unsigned long);
if (!init_map_port(set, (struct bitmap_port *) map, if (!init_map_port(set, map, first_port, last_port)) {
first_port, last_port)) {
kfree(map); kfree(map);
return -ENOMEM; return -ENOMEM;
} }
map->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); map->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
set->variant = &bitmap_port_timeout; set->variant = &bitmap_tport;
bitmap_port_gc_init(set); bitmap_port_gc_init(set);
} else { } else {
struct bitmap_port *map;
map = kzalloc(sizeof(*map), GFP_KERNEL);
if (!map)
return -ENOMEM;
map->memsize = bitmap_bytes(0, last_port - first_port); map->memsize = bitmap_bytes(0, last_port - first_port);
pr_debug("memsize: %zu\n", map->memsize); pr_debug("memsize: %zu\n", map->memsize);
if (!init_map_port(set, map, first_port, last_port)) { if (!init_map_port(set, map, first_port, last_port)) {
@@ -630,6 +485,17 @@ static struct ip_set_type bitmap_port_type = {
.family = AF_UNSPEC, .family = AF_UNSPEC,
.revision = 0, .revision = 0,
.create = bitmap_port_create, .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, .me = THIS_MODULE,
}; };

View File

@@ -17,6 +17,7 @@
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/netlink.h> #include <linux/netlink.h>
#include <linux/rculist.h> #include <linux/rculist.h>
#include <linux/version.h>
#include <net/netlink.h> #include <net/netlink.h>
#include <linux/netfilter.h> #include <linux/netfilter.h>
@@ -196,20 +197,24 @@ EXPORT_SYMBOL_GPL(ip_set_type_unregister);
/* Utility functions */ /* Utility functions */
void * void *
ip_set_alloc(size_t size, gfp_t gfp_mask) ip_set_alloc(size_t size)
{ {
void *members = NULL; void *members = NULL;
if (size < KMALLOC_MAX_SIZE) if (size < KMALLOC_MAX_SIZE)
members = kzalloc(size, gfp_mask | __GFP_NOWARN); members = kzalloc(size, GFP_KERNEL | __GFP_NOWARN);
if (members) { if (members) {
pr_debug("%p: allocated with kmalloc\n", members); pr_debug("%p: allocated with kmalloc\n", members);
return 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); PAGE_KERNEL);
#else
members = vzalloc(size);
#endif
if (!members) if (!members)
return NULL; return NULL;
pr_debug("%p: allocated with vmalloc\n", members); pr_debug("%p: allocated with vmalloc\n", members);
@@ -249,8 +254,7 @@ ip_set_get_ipaddr4(struct nlattr *nla, __be32 *ipaddr)
if (unlikely(!flag_nested(nla))) if (unlikely(!flag_nested(nla)))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
if (nla_parse(tb, IPSET_ATTR_IPADDR_MAX, nla_data(nla), nla_len(nla), if (nla_parse_nested(tb, IPSET_ATTR_IPADDR_MAX, nla, ipaddr_policy))
ipaddr_policy))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
if (unlikely(!ip_set_attr_netorder(tb, IPSET_ATTR_IPADDR_IPV4))) if (unlikely(!ip_set_attr_netorder(tb, IPSET_ATTR_IPADDR_IPV4)))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
@@ -268,8 +272,7 @@ ip_set_get_ipaddr6(struct nlattr *nla, union nf_inet_addr *ipaddr)
if (unlikely(!flag_nested(nla))) if (unlikely(!flag_nested(nla)))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
if (nla_parse(tb, IPSET_ATTR_IPADDR_MAX, nla_data(nla), nla_len(nla), if (nla_parse_nested(tb, IPSET_ATTR_IPADDR_MAX, nla, ipaddr_policy))
ipaddr_policy))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
if (unlikely(!ip_set_attr_netorder(tb, IPSET_ATTR_IPADDR_IPV6))) if (unlikely(!ip_set_attr_netorder(tb, IPSET_ATTR_IPADDR_IPV6)))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
@@ -611,10 +614,11 @@ ip_set_create(struct sk_buff *skb, struct genl_info *info)
struct ip_set *set, *clash; struct ip_set *set, *clash;
ip_set_id_t index = IPSET_INVALID_ID; ip_set_id_t index = IPSET_INVALID_ID;
struct nlattr *tb[IPSET_ATTR_CREATE_MAX+1] = {};
const char *name, *typename; const char *name, *typename;
u8 family, revision; u8 family, revision;
u32 flags = flag_exist(info->genlhdr); u32 flags = flag_exist(info->genlhdr);
int ret = 0, len; int ret = 0;
if (unlikely(protocol_failed(attr) || if (unlikely(protocol_failed(attr) ||
attr[IPSET_ATTR_SETNAME] == NULL || attr[IPSET_ATTR_SETNAME] == NULL ||
@@ -659,11 +663,14 @@ ip_set_create(struct sk_buff *skb, struct genl_info *info)
/* /*
* Without holding any locks, create private part. * Without holding any locks, create private part.
*/ */
len = attr[IPSET_ATTR_DATA] ? nla_len(attr[IPSET_ATTR_DATA]) : 0; if (attr[IPSET_ATTR_DATA] &&
pr_debug("data len: %u\n", len); nla_parse_nested(tb, IPSET_ATTR_CREATE_MAX, attr[IPSET_ATTR_DATA],
ret = set->type->create(set, attr[IPSET_ATTR_DATA] ? set->type->create_policy)) {
nla_data(attr[IPSET_ATTR_DATA]) : NULL, len, ret = -IPSET_ERR_PROTOCOL;
flags); goto put_out;
}
ret = set->type->create(set, tb, flags);
if (ret != 0) if (ret != 0)
goto put_out; goto put_out;
@@ -749,7 +756,7 @@ ip_set_destroy(struct sk_buff *skb, struct genl_info *info)
} else { } else {
i = find_set_id(nla_data(attr[IPSET_ATTR_SETNAME])); i = find_set_id(nla_data(attr[IPSET_ATTR_SETNAME]));
if (i == IPSET_INVALID_ID) if (i == IPSET_INVALID_ID)
return -EEXIST; return -ENOENT;
else if (atomic_read(&ip_set_list[i]->ref)) else if (atomic_read(&ip_set_list[i]->ref))
return -IPSET_ERR_BUSY; return -IPSET_ERR_BUSY;
@@ -786,7 +793,7 @@ ip_set_flush(struct sk_buff *skb, struct genl_info *info)
} else { } else {
i = find_set_id(nla_data(attr[IPSET_ATTR_SETNAME])); i = find_set_id(nla_data(attr[IPSET_ATTR_SETNAME]));
if (i == IPSET_INVALID_ID) if (i == IPSET_INVALID_ID)
return -EEXIST; return -ENOENT;
ip_set_flush_set(ip_set_list[i]); ip_set_flush_set(ip_set_list[i]);
} }
@@ -820,7 +827,7 @@ ip_set_rename(struct sk_buff *skb, struct genl_info *info)
set = find_set(nla_data(attr[IPSET_ATTR_SETNAME])); set = find_set(nla_data(attr[IPSET_ATTR_SETNAME]));
if (set == NULL) if (set == NULL)
return -EEXIST; return -ENOENT;
if (atomic_read(&set->ref) != 0) if (atomic_read(&set->ref) != 0)
return -IPSET_ERR_REFERENCED; return -IPSET_ERR_REFERENCED;
@@ -860,7 +867,7 @@ ip_set_swap(struct sk_buff *skb, struct genl_info *info)
from_id = find_set_id(nla_data(attr[IPSET_ATTR_SETNAME])); from_id = find_set_id(nla_data(attr[IPSET_ATTR_SETNAME]));
if (from_id == IPSET_INVALID_ID) if (from_id == IPSET_INVALID_ID)
return -EEXIST; return -ENOENT;
to_id = find_set_id(nla_data(attr[IPSET_ATTR_SETNAME2])); to_id = find_set_id(nla_data(attr[IPSET_ATTR_SETNAME2]));
if (to_id == IPSET_INVALID_ID) if (to_id == IPSET_INVALID_ID)
@@ -946,7 +953,7 @@ dump_init(struct netlink_callback *cb)
index = find_set_id(nla_data(cda[IPSET_ATTR_SETNAME])); index = find_set_id(nla_data(cda[IPSET_ATTR_SETNAME]));
if (index == IPSET_INVALID_ID) if (index == IPSET_INVALID_ID)
return -EEXIST; return -ENOENT;
cb->args[0] = DUMP_ONE; cb->args[0] = DUMP_ONE;
cb->args[1] = index; cb->args[1] = index;
@@ -958,16 +965,18 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb)
{ {
ip_set_id_t index = IPSET_INVALID_ID, max; ip_set_id_t index = IPSET_INVALID_ID, max;
struct ip_set *set = NULL; struct ip_set *set = NULL;
void *nlh = NULL; struct nlmsghdr *nlh = NULL;
unsigned int flags = NETLINK_CB(cb->skb).pid ? NLM_F_MULTI : 0; unsigned int flags = NETLINK_CB(cb->skb).pid ? NLM_F_MULTI : 0;
int ret = 0; int ret = 0;
if (cb->args[0] == DUMP_INIT) { if (cb->args[0] == DUMP_INIT) {
ret = dump_init(cb); ret = dump_init(cb);
if (ret < 0) { if (ret < 0) {
nlh = nlmsg_hdr(cb->skb);
/* We have to create and send the error message /* We have to create and send the error message
* manually :-( */ * 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; return ret;
} }
} }
@@ -982,7 +991,7 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb)
set = ip_set_list[index]; set = ip_set_list[index];
if (set == NULL) { if (set == NULL) {
if (cb->args[0] == DUMP_ONE) { if (cb->args[0] == DUMP_ONE) {
ret = -EEXIST; ret = -ENOENT;
goto out; goto out;
} }
continue; continue;
@@ -1004,7 +1013,7 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb)
cb->nlh->nlmsg_seq, flags, cb->nlh->nlmsg_seq, flags,
IPSET_CMD_LIST); IPSET_CMD_LIST);
if (!nlh) { if (!nlh) {
ret = -EFAULT; ret = -EMSGSIZE;
goto release_refcount; goto release_refcount;
} }
NLA_PUT_U8(skb, IPSET_ATTR_PROTOCOL, IPSET_PROTOCOL); NLA_PUT_U8(skb, IPSET_ATTR_PROTOCOL, IPSET_PROTOCOL);
@@ -1092,19 +1101,17 @@ static const struct nla_policy ip_set_adt_policy[IPSET_ATTR_CMD_MAX + 1] = {
}; };
static int static int
call_ad(struct sk_buff *skb, struct nlattr *const attr[], call_ad(struct sock *ctnl, struct sk_buff *skb, struct ip_set *set,
struct ip_set *set, const struct nlattr *nla, struct nlattr *tb[], enum ipset_adt adt,
enum ipset_adt adt, u32 flags) u32 flags, bool use_lineno)
{ {
struct nlattr *head = nla_data(nla); int ret, retried = 0;
int ret, len = nla_len(nla), retried = 0;
u32 lineno = 0; u32 lineno = 0;
bool eexist = flags & IPSET_FLAG_EXIST; bool eexist = flags & IPSET_FLAG_EXIST;
do { do {
write_lock_bh(&set->lock); write_lock_bh(&set->lock);
ret = set->variant->uadt(set, head, len, adt, ret = set->variant->uadt(set, tb, adt, &lineno, flags);
&lineno, flags);
write_unlock_bh(&set->lock); write_unlock_bh(&set->lock);
} while (ret == -EAGAIN && } while (ret == -EAGAIN &&
set->variant->resize && set->variant->resize &&
@@ -1112,11 +1119,38 @@ call_ad(struct sk_buff *skb, struct nlattr *const attr[],
if (!ret || (ret == -IPSET_ERR_EXIST && eexist)) if (!ret || (ret == -IPSET_ERR_EXIST && eexist))
return 0; return 0;
if (lineno && attr[IPSET_ATTR_LINENO]) { if (lineno && use_lineno) {
/* Error in restore/batch mode: send back 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; *errline = lineno;
netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT);
/* Signal netlink not to send its ACK/errmsg. */
return -EINTR;
} }
return ret; return ret;
@@ -1126,10 +1160,13 @@ static int
ip_set_uadd(struct sk_buff *skb, struct genl_info *info) ip_set_uadd(struct sk_buff *skb, struct genl_info *info)
{ {
struct nlattr *const *attr = info->attrs; struct nlattr *const *attr = info->attrs;
struct sock *ctnl = genl_info_net(info)->genl_sock;
struct ip_set *set; struct ip_set *set;
struct nlattr *tb[IPSET_ATTR_ADT_MAX+1] = {};
const struct nlattr *nla; const struct nlattr *nla;
u32 flags = flag_exist(info->genlhdr); u32 flags = flag_exist(info->genlhdr);
bool use_lineno;
int ret = 0; int ret = 0;
if (unlikely(protocol_failed(attr) || if (unlikely(protocol_failed(attr) ||
@@ -1145,20 +1182,28 @@ ip_set_uadd(struct sk_buff *skb, struct genl_info *info)
set = find_set(nla_data(attr[IPSET_ATTR_SETNAME])); set = find_set(nla_data(attr[IPSET_ATTR_SETNAME]));
if (set == NULL) if (set == NULL)
return -EEXIST; return -ENOENT;
use_lineno = !!attr[IPSET_ATTR_LINENO];
if (attr[IPSET_ATTR_DATA]) { if (attr[IPSET_ATTR_DATA]) {
ret = call_ad(skb, attr, if (nla_parse_nested(tb, IPSET_ATTR_ADT_MAX,
set, attr[IPSET_ATTR_DATA], IPSET_ADD, flags); 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 { } else {
int nla_rem; int nla_rem;
nla_for_each_nested(nla, attr[IPSET_ATTR_ADT], 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 || 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; return -IPSET_ERR_PROTOCOL;
ret = call_ad(skb, attr, ret = call_ad(ctnl, skb, set, tb, IPSET_ADD,
set, nla, IPSET_ADD, flags); flags, use_lineno);
if (ret < 0) if (ret < 0)
return ret; return ret;
} }
@@ -1170,10 +1215,13 @@ static int
ip_set_udel(struct sk_buff *skb, struct genl_info *info) ip_set_udel(struct sk_buff *skb, struct genl_info *info)
{ {
struct nlattr *const *attr = info->attrs; struct nlattr *const *attr = info->attrs;
struct sock *ctnl = genl_info_net(info)->genl_sock;
struct ip_set *set; struct ip_set *set;
struct nlattr *tb[IPSET_ATTR_ADT_MAX+1] = {};
const struct nlattr *nla; const struct nlattr *nla;
u32 flags = flag_exist(info->genlhdr); u32 flags = flag_exist(info->genlhdr);
bool use_lineno;
int ret = 0; int ret = 0;
if (unlikely(protocol_failed(attr) || if (unlikely(protocol_failed(attr) ||
@@ -1189,20 +1237,28 @@ ip_set_udel(struct sk_buff *skb, struct genl_info *info)
set = find_set(nla_data(attr[IPSET_ATTR_SETNAME])); set = find_set(nla_data(attr[IPSET_ATTR_SETNAME]));
if (set == NULL) if (set == NULL)
return -EEXIST; return -ENOENT;
use_lineno = !!attr[IPSET_ATTR_LINENO];
if (attr[IPSET_ATTR_DATA]) { if (attr[IPSET_ATTR_DATA]) {
ret = call_ad(skb, attr, if (nla_parse_nested(tb, IPSET_ATTR_ADT_MAX,
set, attr[IPSET_ATTR_DATA], IPSET_DEL, flags); 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 { } else {
int nla_rem; int nla_rem;
nla_for_each_nested(nla, attr[IPSET_ATTR_ADT], 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 || 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; return -IPSET_ERR_PROTOCOL;
ret = call_ad(skb, attr, ret = call_ad(ctnl, skb, set, tb, IPSET_DEL,
set, nla, IPSET_DEL, flags); flags, use_lineno);
if (ret < 0) if (ret < 0)
return ret; return ret;
} }
@@ -1216,6 +1272,7 @@ ip_set_utest(struct sk_buff *skb, struct genl_info *info)
struct nlattr *const *attr = info->attrs; struct nlattr *const *attr = info->attrs;
struct ip_set *set; struct ip_set *set;
struct nlattr *tb[IPSET_ATTR_ADT_MAX+1] = {};
int ret = 0; int ret = 0;
if (unlikely(protocol_failed(attr) || if (unlikely(protocol_failed(attr) ||
@@ -1226,13 +1283,14 @@ ip_set_utest(struct sk_buff *skb, struct genl_info *info)
set = find_set(nla_data(attr[IPSET_ATTR_SETNAME])); set = find_set(nla_data(attr[IPSET_ATTR_SETNAME]));
if (set == NULL) 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); read_lock_bh(&set->lock);
ret = set->variant->uadt(set, ret = set->variant->uadt(set, tb, IPSET_TEST, NULL, 0);
nla_data(attr[IPSET_ATTR_DATA]),
nla_len(attr[IPSET_ATTR_DATA]),
IPSET_TEST, NULL, 0);
read_unlock_bh(&set->lock); read_unlock_bh(&set->lock);
/* Userspace can't trigger element to be re-added */ /* Userspace can't trigger element to be re-added */
if (ret == -EAGAIN) if (ret == -EAGAIN)
@@ -1260,7 +1318,7 @@ ip_set_header(struct sk_buff *skb, struct genl_info *info)
index = find_set_id(nla_data(attr[IPSET_ATTR_SETNAME])); index = find_set_id(nla_data(attr[IPSET_ATTR_SETNAME]));
if (index == IPSET_INVALID_ID) if (index == IPSET_INVALID_ID)
return -EEXIST; return -ENOENT;
set = ip_set_list[index]; set = ip_set_list[index];
skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
@@ -1280,7 +1338,7 @@ ip_set_header(struct sk_buff *skb, struct genl_info *info)
ret = genlmsg_unicast(genl_info_net(info), skb2, NETLINK_CB(skb).pid); ret = genlmsg_unicast(genl_info_net(info), skb2, NETLINK_CB(skb).pid);
if (ret < 0) if (ret < 0)
return -EFAULT; return ret;
return 0; return 0;
@@ -1288,7 +1346,7 @@ nla_put_failure:
nlmsg_cancel(skb2, nlh2); nlmsg_cancel(skb2, nlh2);
nlmsg_failure: nlmsg_failure:
kfree_skb(skb2); kfree_skb(skb2);
return -EFAULT; return -EMSGSIZE;
} }
/* Get type data */ /* Get type data */
@@ -1341,7 +1399,7 @@ ip_set_type(struct sk_buff *skb, struct genl_info *info)
pr_debug("Send TYPE, nlmsg_len: %u\n", skb2->len); pr_debug("Send TYPE, nlmsg_len: %u\n", skb2->len);
ret = genlmsg_unicast(genl_info_net(info), skb2, NETLINK_CB(skb).pid); ret = genlmsg_unicast(genl_info_net(info), skb2, NETLINK_CB(skb).pid);
if (ret < 0) if (ret < 0)
return -EFAULT; return ret;
return 0; return 0;
@@ -1349,7 +1407,7 @@ nla_put_failure:
genlmsg_cancel(skb2, nlh2); genlmsg_cancel(skb2, nlh2);
nlmsg_failure: nlmsg_failure:
kfree_skb(skb2); kfree_skb(skb2);
return -EFAULT; return -EMSGSIZE;
} }
/* Get protocol version */ /* Get protocol version */
@@ -1385,7 +1443,7 @@ ip_set_protocol(struct sk_buff *skb, struct genl_info *info)
ret = genlmsg_unicast(genl_info_net(info), skb2, NETLINK_CB(skb).pid); ret = genlmsg_unicast(genl_info_net(info), skb2, NETLINK_CB(skb).pid);
if (ret < 0) if (ret < 0)
return -EFAULT; return ret;
return 0; return 0;
@@ -1393,7 +1451,7 @@ nla_put_failure:
genlmsg_cancel(skb2, nlh2); genlmsg_cancel(skb2, nlh2);
nlmsg_failure: nlmsg_failure:
kfree_skb(skb2); kfree_skb(skb2);
return -EFAULT; return -EMSGSIZE;
} }
static struct genl_ops ip_set_netlink_subsys_cb[] __read_mostly = { static struct genl_ops ip_set_netlink_subsys_cb[] __read_mostly = {

View File

@@ -13,6 +13,7 @@
#include <linux/icmpv6.h> #include <linux/icmpv6.h>
#include <linux/netfilter_ipv6/ip6_tables.h> #include <linux/netfilter_ipv6/ip6_tables.h>
#include <net/ip.h> #include <net/ip.h>
#include <net/ipv6.h>
#include "ip_set_getport.h" #include "ip_set_getport.h"
@@ -93,21 +94,23 @@ ip_set_get_ip4_port(const struct sk_buff *skb, bool src,
} }
EXPORT_SYMBOL_GPL(ip_set_get_ip4_port); EXPORT_SYMBOL_GPL(ip_set_get_ip4_port);
#if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
bool bool
ip_set_get_ip6_port(const struct sk_buff *skb, bool src, ip_set_get_ip6_port(const struct sk_buff *skb, bool src,
__be16 *port, u8 *proto) __be16 *port, u8 *proto)
{ {
unsigned int protooff = 0; int protoff;
int protocol; u8 nexthdr;
unsigned short fragoff;
protocol = ipv6_find_hdr(skb, &protooff, -1, &fragoff); nexthdr = ipv6_hdr(skb)->nexthdr;
if (protocol <= 0 || fragoff) protoff = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &nexthdr);
if (protoff < 0)
return false; 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); EXPORT_SYMBOL_GPL(ip_set_get_ip6_port);
#endif
bool bool
ip_set_get_ip_port(const struct sk_buff *skb, u8 pf, bool src, __be16 *port) ip_set_get_ip_port(const struct sk_buff *skb, u8 pf, bool src, __be16 *port)
@@ -118,8 +121,10 @@ ip_set_get_ip_port(const struct sk_buff *skb, u8 pf, bool src, __be16 *port)
switch (pf) { switch (pf) {
case AF_INET: case AF_INET:
ret = ip_set_get_ip4_port(skb, src, port, &proto); ret = ip_set_get_ip4_port(skb, src, port, &proto);
break;
case AF_INET6: case AF_INET6:
ret = ip_set_get_ip6_port(skb, src, port, &proto); ret = ip_set_get_ip6_port(skb, src, port, &proto);
break;
default: default:
return false; return false;
} }

View File

@@ -3,8 +3,18 @@
extern bool ip_set_get_ip4_port(const struct sk_buff *skb, bool src, extern bool ip_set_get_ip4_port(const struct sk_buff *skb, bool src,
__be16 *port, u8 *proto); __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, extern bool ip_set_get_ip6_port(const struct sk_buff *skb, bool src,
__be16 *port, u8 *proto); __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, extern bool ip_set_get_ip_port(const struct sk_buff *skb, u8 pf, bool src,
__be16 *port); __be16 *port);

View File

@@ -12,9 +12,6 @@
#include <linux/ip.h> #include <linux/ip.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/uaccess.h>
#include <linux/bitops.h>
#include <linux/spinlock.h>
#include <linux/random.h> #include <linux/random.h>
#include <net/ip.h> #include <net/ip.h>
#include <net/ipv6.h> #include <net/ipv6.h>
@@ -127,29 +124,16 @@ hash_ip4_kadt(struct ip_set *set, const struct sk_buff *skb,
return adtfn(set, &ip, h->timeout); 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 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) enum ipset_adt adt, u32 *lineno, u32 flags)
{ {
const struct ip_set_hash *h = set->data; const struct ip_set_hash *h = set->data;
struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
ipset_adtfn adtfn = set->variant->adt[adt]; ipset_adtfn adtfn = set->variant->adt[adt];
u32 ip, ip_to, hosts, timeout = h->timeout; u32 ip, ip_to, hosts, timeout = h->timeout;
__be32 nip; __be32 nip;
int ret = 0; 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] || if (unlikely(!tb[IPSET_ATTR_IP] ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT))) !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
@@ -320,22 +304,19 @@ static const struct nla_policy hash_ip6_adt_policy[IPSET_ATTR_ADT_MAX + 1] = {
}; };
static int 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) enum ipset_adt adt, u32 *lineno, u32 flags)
{ {
const struct ip_set_hash *h = set->data; const struct ip_set_hash *h = set->data;
struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
ipset_adtfn adtfn = set->variant->adt[adt]; ipset_adtfn adtfn = set->variant->adt[adt];
union nf_inet_addr ip; union nf_inet_addr ip;
u32 timeout = h->timeout; u32 timeout = h->timeout;
int ret; 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] || 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; return -IPSET_ERR_PROTOCOL;
if (tb[IPSET_ATTR_LINENO]) if (tb[IPSET_ATTR_LINENO])
@@ -362,20 +343,9 @@ hash_ip6_uadt(struct ip_set *set, struct nlattr *head, int len,
/* Create hash:ip type of sets */ /* 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 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; u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
u8 netmask, hbits; u8 netmask, hbits;
struct ip_set_hash *h; struct ip_set_hash *h;
@@ -386,10 +356,6 @@ hash_ip_create(struct ip_set *set, struct nlattr *head, int len, u32 flags)
pr_debug("Create set %s with family %s\n", pr_debug("Create set %s with family %s\n",
set->name, set->family == AF_INET ? "inet" : "inet6"); 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) || 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_MAXELEM) ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT))) !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
@@ -425,8 +391,7 @@ hash_ip_create(struct ip_set *set, struct nlattr *head, int len, u32 flags)
hbits = htable_bits(hashsize); hbits = htable_bits(hashsize);
h->table = ip_set_alloc( h->table = ip_set_alloc(
sizeof(struct htable) sizeof(struct htable)
+ jhash_size(hbits) * sizeof(struct hbucket), + jhash_size(hbits) * sizeof(struct hbucket));
GFP_KERNEL);
if (!h->table) { if (!h->table) {
kfree(h); kfree(h);
return -ENOMEM; return -ENOMEM;
@@ -465,6 +430,21 @@ static struct ip_set_type hash_ip_type __read_mostly = {
.family = AF_UNSPEC, .family = AF_UNSPEC,
.revision = 0, .revision = 0,
.create = hash_ip_create, .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, .me = THIS_MODULE,
}; };

View File

@@ -12,9 +12,6 @@
#include <linux/ip.h> #include <linux/ip.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/uaccess.h>
#include <linux/bitops.h>
#include <linux/spinlock.h>
#include <linux/random.h> #include <linux/random.h>
#include <net/ip.h> #include <net/ip.h>
#include <net/ipv6.h> #include <net/ipv6.h>
@@ -144,34 +141,17 @@ hash_ipport4_kadt(struct ip_set *set, const struct sk_buff *skb,
return adtfn(set, &data, h->timeout); 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 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) enum ipset_adt adt, u32 *lineno, u32 flags)
{ {
const struct ip_set_hash *h = set->data; const struct ip_set_hash *h = set->data;
struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
ipset_adtfn adtfn = set->variant->adt[adt]; ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_ipport4_elem data = { }; struct hash_ipport4_elem data = { };
u32 ip, ip_to, p, port, port_to; u32 ip, ip_to, p, port, port_to;
u32 timeout = h->timeout; u32 timeout = h->timeout;
int ret; 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] || if (unlikely(!tb[IPSET_ATTR_IP] ||
!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) || !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) || !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
@@ -373,25 +353,22 @@ hash_ipport6_kadt(struct ip_set *set, const struct sk_buff *skb,
} }
static int 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) enum ipset_adt adt, u32 *lineno, u32 flags)
{ {
const struct ip_set_hash *h = set->data; const struct ip_set_hash *h = set->data;
struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
ipset_adtfn adtfn = set->variant->adt[adt]; ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_ipport6_elem data = { }; struct hash_ipport6_elem data = { };
u32 port, port_to; u32 port, port_to;
u32 timeout = h->timeout; u32 timeout = h->timeout;
int ret; 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] || if (unlikely(!tb[IPSET_ATTR_IP] ||
!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) || !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) || !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT))) !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
tb[IPSET_ATTR_IP_TO] ||
tb[IPSET_ATTR_CIDR]))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
if (tb[IPSET_ATTR_LINENO]) if (tb[IPSET_ATTR_LINENO])
@@ -456,20 +433,9 @@ hash_ipport6_uadt(struct ip_set *set, struct nlattr *head, int len,
/* Create hash:ip type of sets */ /* 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 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; struct ip_set_hash *h;
u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM; u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
u8 hbits; u8 hbits;
@@ -477,10 +443,6 @@ hash_ipport_create(struct ip_set *set, struct nlattr *head, int len, u32 flags)
if (!(set->family == AF_INET || set->family == AF_INET6)) if (!(set->family == AF_INET || set->family == AF_INET6))
return -IPSET_ERR_INVALID_FAMILY; 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) || 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_MAXELEM) ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT))) !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
@@ -506,8 +468,7 @@ hash_ipport_create(struct ip_set *set, struct nlattr *head, int len, u32 flags)
hbits = htable_bits(hashsize); hbits = htable_bits(hashsize);
h->table = ip_set_alloc( h->table = ip_set_alloc(
sizeof(struct htable) sizeof(struct htable)
+ jhash_size(hbits) * sizeof(struct hbucket), + jhash_size(hbits) * sizeof(struct hbucket));
GFP_KERNEL);
if (!h->table) { if (!h->table) {
kfree(h); kfree(h);
return -ENOMEM; return -ENOMEM;
@@ -546,6 +507,24 @@ static struct ip_set_type hash_ipport_type __read_mostly = {
.family = AF_UNSPEC, .family = AF_UNSPEC,
.revision = 0, .revision = 0,
.create = hash_ipport_create, .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, .me = THIS_MODULE,
}; };

View File

@@ -12,9 +12,6 @@
#include <linux/ip.h> #include <linux/ip.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/uaccess.h>
#include <linux/bitops.h>
#include <linux/spinlock.h>
#include <linux/random.h> #include <linux/random.h>
#include <net/ip.h> #include <net/ip.h>
#include <net/ipv6.h> #include <net/ipv6.h>
@@ -148,35 +145,17 @@ hash_ipportip4_kadt(struct ip_set *set, const struct sk_buff *skb,
return adtfn(set, &data, h->timeout); 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 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) enum ipset_adt adt, u32 *lineno, u32 flags)
{ {
const struct ip_set_hash *h = set->data; const struct ip_set_hash *h = set->data;
struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
ipset_adtfn adtfn = set->variant->adt[adt]; ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_ipportip4_elem data = { }; struct hash_ipportip4_elem data = { };
u32 ip, ip_to, p, port, port_to; u32 ip, ip_to, p, port, port_to;
u32 timeout = h->timeout; u32 timeout = h->timeout;
int ret; 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] || if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] ||
!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) || !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) || !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
@@ -388,25 +367,22 @@ hash_ipportip6_kadt(struct ip_set *set, const struct sk_buff *skb,
} }
static int 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) enum ipset_adt adt, u32 *lineno, u32 flags)
{ {
const struct ip_set_hash *h = set->data; const struct ip_set_hash *h = set->data;
struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
ipset_adtfn adtfn = set->variant->adt[adt]; ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_ipportip6_elem data = { }; struct hash_ipportip6_elem data = { };
u32 port, port_to; u32 port, port_to;
u32 timeout = h->timeout; u32 timeout = h->timeout;
int ret; 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] || if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] ||
!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) || !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) || !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT))) !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
tb[IPSET_ATTR_IP_TO] ||
tb[IPSET_ATTR_CIDR]))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
if (tb[IPSET_ATTR_LINENO]) if (tb[IPSET_ATTR_LINENO])
@@ -475,20 +451,9 @@ hash_ipportip6_uadt(struct ip_set *set, struct nlattr *head, int len,
/* Create hash:ip type of sets */ /* 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 static int
hash_ipportip_create(struct ip_set *set, struct nlattr *head, hash_ipportip_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
int len, u32 flags)
{ {
struct nlattr *tb[IPSET_ATTR_CREATE_MAX+1];
struct ip_set_hash *h; struct ip_set_hash *h;
u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM; u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
u8 hbits; u8 hbits;
@@ -496,10 +461,6 @@ hash_ipportip_create(struct ip_set *set, struct nlattr *head,
if (!(set->family == AF_INET || set->family == AF_INET6)) if (!(set->family == AF_INET || set->family == AF_INET6))
return -IPSET_ERR_INVALID_FAMILY; 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) || 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_MAXELEM) ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT))) !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
@@ -525,8 +486,7 @@ hash_ipportip_create(struct ip_set *set, struct nlattr *head,
hbits = htable_bits(hashsize); hbits = htable_bits(hashsize);
h->table = ip_set_alloc( h->table = ip_set_alloc(
sizeof(struct htable) sizeof(struct htable)
+ jhash_size(hbits) * sizeof(struct hbucket), + jhash_size(hbits) * sizeof(struct hbucket));
GFP_KERNEL);
if (!h->table) { if (!h->table) {
kfree(h); kfree(h);
return -ENOMEM; return -ENOMEM;
@@ -565,6 +525,24 @@ static struct ip_set_type hash_ipportip_type __read_mostly = {
.family = AF_UNSPEC, .family = AF_UNSPEC,
.revision = 0, .revision = 0,
.create = hash_ipportip_create, .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, .me = THIS_MODULE,
}; };

View File

@@ -12,9 +12,6 @@
#include <linux/ip.h> #include <linux/ip.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <asm/uaccess.h>
#include <asm/bitops.h>
#include <linux/spinlock.h>
#include <linux/random.h> #include <linux/random.h>
#include <net/ip.h> #include <net/ip.h>
#include <net/ipv6.h> #include <net/ipv6.h>
@@ -168,36 +165,17 @@ hash_ipportnet4_kadt(struct ip_set *set, const struct sk_buff *skb,
return adtfn(set, &data, h->timeout); 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 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) enum ipset_adt adt, u32 *lineno, u32 flags)
{ {
const struct ip_set_hash *h = set->data; const struct ip_set_hash *h = set->data;
struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
ipset_adtfn adtfn = set->variant->adt[adt]; ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_ipportnet4_elem data = { .cidr = HOST_MASK }; struct hash_ipportnet4_elem data = { .cidr = HOST_MASK };
u32 ip, ip_to, p, port, port_to; u32 ip, ip_to, p, port, port_to;
u32 timeout = h->timeout; u32 timeout = h->timeout;
int ret; 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] || if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] ||
!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) || !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) || !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
@@ -443,25 +421,22 @@ hash_ipportnet6_kadt(struct ip_set *set, const struct sk_buff *skb,
} }
static int 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) enum ipset_adt adt, u32 *lineno, u32 flags)
{ {
const struct ip_set_hash *h = set->data; const struct ip_set_hash *h = set->data;
struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
ipset_adtfn adtfn = set->variant->adt[adt]; ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_ipportnet6_elem data = { .cidr = HOST_MASK }; struct hash_ipportnet6_elem data = { .cidr = HOST_MASK };
u32 port, port_to; u32 port, port_to;
u32 timeout = h->timeout; u32 timeout = h->timeout;
int ret; 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] || if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] ||
!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) || !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) || !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT))) !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
tb[IPSET_ATTR_IP_TO] ||
tb[IPSET_ATTR_CIDR]))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
if (tb[IPSET_ATTR_LINENO]) if (tb[IPSET_ATTR_LINENO])
@@ -538,20 +513,9 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *head, int len,
/* Create hash:ip type of sets */ /* 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 static int
hash_ipportnet_create(struct ip_set *set, struct nlattr *head, hash_ipportnet_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
int len, u32 flags)
{ {
struct nlattr *tb[IPSET_ATTR_CREATE_MAX+1];
struct ip_set_hash *h; struct ip_set_hash *h;
u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM; u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
u8 hbits; u8 hbits;
@@ -559,10 +523,6 @@ hash_ipportnet_create(struct ip_set *set, struct nlattr *head,
if (!(set->family == AF_INET || set->family == AF_INET6)) if (!(set->family == AF_INET || set->family == AF_INET6))
return -IPSET_ERR_INVALID_FAMILY; 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) || 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_MAXELEM) ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT))) !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
@@ -590,8 +550,7 @@ hash_ipportnet_create(struct ip_set *set, struct nlattr *head,
hbits = htable_bits(hashsize); hbits = htable_bits(hashsize);
h->table = ip_set_alloc( h->table = ip_set_alloc(
sizeof(struct htable) sizeof(struct htable)
+ jhash_size(hbits) * sizeof(struct hbucket), + jhash_size(hbits) * sizeof(struct hbucket));
GFP_KERNEL);
if (!h->table) { if (!h->table) {
kfree(h); kfree(h);
return -ENOMEM; return -ENOMEM;
@@ -631,6 +590,25 @@ static struct ip_set_type hash_ipportnet_type __read_mostly = {
.family = AF_UNSPEC, .family = AF_UNSPEC,
.revision = 0, .revision = 0,
.create = hash_ipportnet_create, .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, .me = THIS_MODULE,
}; };

View File

@@ -12,9 +12,6 @@
#include <linux/ip.h> #include <linux/ip.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/uaccess.h>
#include <linux/bitops.h>
#include <linux/spinlock.h>
#include <linux/random.h> #include <linux/random.h>
#include <net/ip.h> #include <net/ip.h>
#include <net/ipv6.h> #include <net/ipv6.h>
@@ -147,27 +144,16 @@ hash_net4_kadt(struct ip_set *set, const struct sk_buff *skb,
return adtfn(set, &data, h->timeout); 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 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) enum ipset_adt adt, u32 *lineno, u32 flags)
{ {
const struct ip_set_hash *h = set->data; const struct ip_set_hash *h = set->data;
struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
ipset_adtfn adtfn = set->variant->adt[adt]; ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_net4_elem data = { .cidr = HOST_MASK }; struct hash_net4_elem data = { .cidr = HOST_MASK };
u32 timeout = h->timeout; u32 timeout = h->timeout;
int ret; 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] || if (unlikely(!tb[IPSET_ATTR_IP] ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT))) !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
@@ -324,20 +310,15 @@ hash_net6_kadt(struct ip_set *set, const struct sk_buff *skb,
} }
static int 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) enum ipset_adt adt, u32 *lineno, u32 flags)
{ {
const struct ip_set_hash *h = set->data; const struct ip_set_hash *h = set->data;
struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
ipset_adtfn adtfn = set->variant->adt[adt]; ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_net6_elem data = { .cidr = HOST_MASK }; struct hash_net6_elem data = { .cidr = HOST_MASK };
u32 timeout = h->timeout; u32 timeout = h->timeout;
int ret; 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] || if (unlikely(!tb[IPSET_ATTR_IP] ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT))) !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
@@ -370,19 +351,9 @@ hash_net6_uadt(struct ip_set *set, struct nlattr *head, int len,
/* Create hash:ip type of sets */ /* 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 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; u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
struct ip_set_hash *h; struct ip_set_hash *h;
u8 hbits; u8 hbits;
@@ -390,10 +361,6 @@ hash_net_create(struct ip_set *set, struct nlattr *head, int len, u32 flags)
if (!(set->family == AF_INET || set->family == AF_INET6)) if (!(set->family == AF_INET || set->family == AF_INET6))
return -IPSET_ERR_INVALID_FAMILY; 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) || 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_MAXELEM) ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT))) !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
@@ -421,8 +388,7 @@ hash_net_create(struct ip_set *set, struct nlattr *head, int len, u32 flags)
hbits = htable_bits(hashsize); hbits = htable_bits(hashsize);
h->table = ip_set_alloc( h->table = ip_set_alloc(
sizeof(struct htable) sizeof(struct htable)
+ jhash_size(hbits) * sizeof(struct hbucket), + jhash_size(hbits) * sizeof(struct hbucket));
GFP_KERNEL);
if (!h->table) { if (!h->table) {
kfree(h); kfree(h);
return -ENOMEM; return -ENOMEM;
@@ -461,6 +427,18 @@ static struct ip_set_type hash_net_type __read_mostly = {
.family = AF_UNSPEC, .family = AF_UNSPEC,
.revision = 0, .revision = 0,
.create = hash_net_create, .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, .me = THIS_MODULE,
}; };

View File

@@ -12,9 +12,6 @@
#include <linux/ip.h> #include <linux/ip.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/uaccess.h>
#include <linux/bitops.h>
#include <linux/spinlock.h>
#include <linux/random.h> #include <linux/random.h>
#include <net/ip.h> #include <net/ip.h>
#include <net/ipv6.h> #include <net/ipv6.h>
@@ -164,33 +161,17 @@ hash_netport4_kadt(struct ip_set *set, const struct sk_buff *skb,
return adtfn(set, &data, h->timeout); 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 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) enum ipset_adt adt, u32 *lineno, u32 flags)
{ {
const struct ip_set_hash *h = set->data; const struct ip_set_hash *h = set->data;
struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
ipset_adtfn adtfn = set->variant->adt[adt]; ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_netport4_elem data = { .cidr = HOST_MASK }; struct hash_netport4_elem data = { .cidr = HOST_MASK };
u32 port, port_to; u32 port, port_to;
u32 timeout = h->timeout; u32 timeout = h->timeout;
int ret; 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] || if (unlikely(!tb[IPSET_ATTR_IP] ||
!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) || !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) || !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
@@ -401,21 +382,16 @@ hash_netport6_kadt(struct ip_set *set, const struct sk_buff *skb,
} }
static int 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) enum ipset_adt adt, u32 *lineno, u32 flags)
{ {
const struct ip_set_hash *h = set->data; const struct ip_set_hash *h = set->data;
struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
ipset_adtfn adtfn = set->variant->adt[adt]; ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_netport6_elem data = { .cidr = HOST_MASK }; struct hash_netport6_elem data = { .cidr = HOST_MASK };
u32 port, port_to; u32 port, port_to;
u32 timeout = h->timeout; u32 timeout = h->timeout;
int ret; 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] || if (unlikely(!tb[IPSET_ATTR_IP] ||
!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) || !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) || !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
@@ -490,20 +466,9 @@ hash_netport6_uadt(struct ip_set *set, struct nlattr *head, int len,
/* Create hash:ip type of sets */ /* 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 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; struct ip_set_hash *h;
u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM; u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
u8 hbits; u8 hbits;
@@ -511,10 +476,6 @@ hash_netport_create(struct ip_set *set, struct nlattr *head, int len, u32 flags)
if (!(set->family == AF_INET || set->family == AF_INET6)) if (!(set->family == AF_INET || set->family == AF_INET6))
return -IPSET_ERR_INVALID_FAMILY; 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) || 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_MAXELEM) ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT))) !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
@@ -542,8 +503,7 @@ hash_netport_create(struct ip_set *set, struct nlattr *head, int len, u32 flags)
hbits = htable_bits(hashsize); hbits = htable_bits(hashsize);
h->table = ip_set_alloc( h->table = ip_set_alloc(
sizeof(struct htable) sizeof(struct htable)
+ jhash_size(hbits) * sizeof(struct hbucket), + jhash_size(hbits) * sizeof(struct hbucket));
GFP_KERNEL);
if (!h->table) { if (!h->table) {
kfree(h); kfree(h);
return -ENOMEM; return -ENOMEM;
@@ -582,6 +542,23 @@ static struct ip_set_type hash_netport_type __read_mostly = {
.family = AF_UNSPEC, .family = AF_UNSPEC,
.revision = 0, .revision = 0,
.create = hash_netport_create, .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, .me = THIS_MODULE,
}; };

View File

@@ -111,16 +111,6 @@ list_set_kadt(struct ip_set *set, const struct sk_buff *skb,
return -EINVAL; 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 static bool
next_id_eq(const struct list_set *map, u32 i, ip_set_id_t id) next_id_eq(const struct list_set *map, u32 i, ip_set_id_t id)
{ {
@@ -204,11 +194,10 @@ list_set_del(struct list_set *map, ip_set_id_t id, u32 i)
} }
static int 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) enum ipset_adt adt, u32 *lineno, u32 flags)
{ {
struct list_set *map = set->data; struct list_set *map = set->data;
struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
bool with_timeout = with_timeout(map->timeout); bool with_timeout = with_timeout(map->timeout);
int before = 0; int before = 0;
u32 timeout = map->timeout; u32 timeout = map->timeout;
@@ -218,10 +207,6 @@ list_set_uadt(struct ip_set *set, struct nlattr *head, int len,
u32 i; u32 i;
int ret = 0; 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] || if (unlikely(!tb[IPSET_ATTR_NAME] ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS))) !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS)))
@@ -392,7 +377,7 @@ list_set_head(struct ip_set *set, struct sk_buff *skb)
return 0; return 0;
nla_put_failure: nla_put_failure:
return -EFAULT; return -EMSGSIZE;
} }
static int static int
@@ -406,7 +391,7 @@ list_set_list(const struct ip_set *set,
atd = ipset_nest_start(skb, IPSET_ATTR_ADT); atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
if (!atd) if (!atd)
return -EFAULT; return -EMSGSIZE;
for (; cb->args[2] < map->size; cb->args[2]++) { for (; cb->args[2] < map->size; cb->args[2]++) {
i = cb->args[2]; i = cb->args[2];
e = list_set_elem(map, i); e = list_set_elem(map, i);
@@ -418,7 +403,7 @@ list_set_list(const struct ip_set *set,
if (!nested) { if (!nested) {
if (i == first) { if (i == first) {
nla_nest_cancel(skb, atd); nla_nest_cancel(skb, atd);
return -EFAULT; return -EMSGSIZE;
} else } else
goto nla_put_failure; goto nla_put_failure;
} }
@@ -441,6 +426,10 @@ finish:
nla_put_failure: nla_put_failure:
nla_nest_cancel(skb, nested); nla_nest_cancel(skb, nested);
ipset_nest_end(skb, atd); ipset_nest_end(skb, atd);
if (unlikely(i == first)) {
cb->args[2] = 0;
return -EMSGSIZE;
}
return 0; return 0;
} }
@@ -501,12 +490,6 @@ list_set_gc_init(struct ip_set *set)
/* Create list:set type of sets */ /* 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 static bool
init_list_set(struct ip_set *set, u32 size, size_t dsize, init_list_set(struct ip_set *set, u32 size, size_t dsize,
unsigned long timeout) unsigned long timeout)
@@ -533,16 +516,10 @@ init_list_set(struct ip_set *set, u32 size, size_t dsize,
} }
static int static int
list_set_create(struct ip_set *set, struct nlattr *head, int len, list_set_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
u32 flags)
{ {
struct nlattr *tb[IPSET_ATTR_CREATE_MAX+1];
u32 size = IP_SET_LIST_DEFAULT_SIZE; 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) || if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_SIZE) ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT))) !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
@@ -575,6 +552,19 @@ static struct ip_set_type list_set_type __read_mostly = {
.family = AF_UNSPEC, .family = AF_UNSPEC,
.revision = 0, .revision = 0,
.create = list_set_create, .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, .me = THIS_MODULE,
}; };

View File

@@ -43,8 +43,8 @@ static const uint16_t cmdflags[] = {
[IPSET_CMD_FLUSH-1] = NLM_F_REQUEST|NLM_F_ACK, [IPSET_CMD_FLUSH-1] = NLM_F_REQUEST|NLM_F_ACK,
[IPSET_CMD_RENAME-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_SWAP-1] = NLM_F_REQUEST|NLM_F_ACK,
[IPSET_CMD_LIST-1] = NLM_F_REQUEST, [IPSET_CMD_LIST-1] = NLM_F_REQUEST|NLM_F_ACK,
[IPSET_CMD_SAVE-1] = NLM_F_REQUEST, [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_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_DEL-1] = NLM_F_REQUEST|NLM_F_ACK|NLM_F_EXCL,
[IPSET_CMD_TEST-1] = NLM_F_REQUEST|NLM_F_ACK, [IPSET_CMD_TEST-1] = NLM_F_REQUEST|NLM_F_ACK,
@@ -83,7 +83,7 @@ ipset_mnl_fill_hdr(struct ipset_handle *handle, enum ipset_cmd cmd,
nlh->nlmsg_flags = NLM_F_REQUEST; nlh->nlmsg_flags = NLM_F_REQUEST;
if (cmdflags[cmd-1] & NLM_F_ACK) if (cmdflags[cmd-1] & NLM_F_ACK)
nlh->nlmsg_flags |= 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 = mnl_nlmsg_put_extra_header(nlh, sizeof(struct genlmsghdr));
ghdr->cmd = cmd; ghdr->cmd = cmd;
@@ -225,6 +225,7 @@ ipset_mnl_init(mnl_cb_t *cb_ctl, void *data)
handle->portid = mnl_socket_get_portid(handle->h); handle->portid = mnl_socket_get_portid(handle->h);
handle->cb_ctl = cb_ctl; handle->cb_ctl = cb_ctl;
handle->data = data; handle->data = data;
handle->seq = time(NULL);
if (ipset_mnl_getid(handle, false) < 0) if (ipset_mnl_getid(handle, false) < 0)
goto close_nl; goto close_nl;

View File

@@ -1416,15 +1416,14 @@ ipset_parse_ignored(struct ipset_session *session,
*/ */
int int
ipset_call_parser(struct ipset_session *session, ipset_call_parser(struct ipset_session *session,
ipset_parsefn parse, const char *optstr, const struct ipset_arg *arg,
enum ipset_opt opt, const char *str) const char *str)
{ {
if (ipset_data_flags_test(ipset_session_data(session), if (ipset_data_flags_test(ipset_session_data(session),
IPSET_FLAG(opt))) IPSET_FLAG(arg->opt)))
syntax_err("%s already specified", optstr); syntax_err("%s already specified", arg->name[0]);
return parse(session, opt, parse == ipset_parse_ignored return arg->parse(session, arg->opt, str);
? optstr : str);
} }
#define parse_elem(s, t, d, str) \ #define parse_elem(s, t, d, str) \

View File

@@ -158,7 +158,8 @@ __getnameinfo##f(char *buf, unsigned int len, \
sizeof(saddr), \ sizeof(saddr), \
buf, len, NULL, 0, flags); \ 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, \ err = getnameinfo((const struct sockaddr *)&saddr, \
sizeof(saddr), \ sizeof(saddr), \
buf, len, NULL, 0, \ buf, len, NULL, 0, \
@@ -229,7 +230,7 @@ ipset_print_ip(char *buf, unsigned int len,
D("CIDR: %u", cidr); D("CIDR: %u", cidr);
} else } else
cidr = family == AF_INET6 ? 128 : 32; 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); ip = ipset_data_get(data, opt);
assert(ip); assert(ip);
@@ -296,7 +297,7 @@ ipset_print_ipaddr(char *buf, unsigned int len,
cidr = *(const uint8_t *) ipset_data_get(data, cidropt); cidr = *(const uint8_t *) ipset_data_get(data, cidropt);
else else
cidr = family == AF_INET6 ? 128 : 32; 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); ip = ipset_data_get(data, opt);
assert(ip); assert(ip);

View File

@@ -441,13 +441,15 @@ ipset_type_add(struct ipset_type *type)
assert(type); assert(type);
if (strlen(type->name) > IPSET_MAXNAMELEN - 1)
return -EINVAL;
/* Add to the list: higher revision numbers first */ /* Add to the list: higher revision numbers first */
for (t = typelist, prev = NULL; t != NULL; t = t->next) { for (t = typelist, prev = NULL; t != NULL; t = t->next) {
if (STREQ(t->name, type->name)) { if (STREQ(t->name, type->name)) {
if (t->revision == type->revision) { if (t->revision == type->revision)
errno = EEXIST; return -EEXIST;
return -1; else if (t->revision < type->revision) {
} else if (t->revision < type->revision) {
type->next = t; type->next = t;
if (prev) if (prev)
prev->next = type; prev->next = type;
@@ -457,10 +459,9 @@ ipset_type_add(struct ipset_type *type)
} }
} }
if (t->next != NULL && STREQ(t->next->name, type->name)) { if (t->next != NULL && STREQ(t->next->name, type->name)) {
if (t->next->revision == type->revision) { if (t->next->revision == type->revision)
errno = EEXIST; return -EEXIST;
return -1; else if (t->next->revision < type->revision) {
} else if (t->next->revision < type->revision) {
type->next = t->next; type->next = t->next;
t->next = type; t->next = type;
return 0; return 0;

View File

@@ -21,8 +21,10 @@
/* Core kernel error codes */ /* Core kernel error codes */
static const struct ipset_errcode_table core_errcode_table[] = { static const struct ipset_errcode_table core_errcode_table[] = {
/* Generic error codes */ /* Generic error codes */
{ EEXIST, 0, { ENOENT, 0,
"The set with the given name does not exist" }, "The set with the given name does not exist" },
{ EMSGSIZE, 0,
"Kernel error received: message could not be created" },
{ IPSET_ERR_PROTOCOL, 0, { IPSET_ERR_PROTOCOL, 0,
"Kernel error received: ipset protocol error" }, "Kernel error received: ipset protocol error" },
@@ -30,14 +32,14 @@ static const struct ipset_errcode_table core_errcode_table[] = {
{ EEXIST, IPSET_CMD_CREATE, { EEXIST, IPSET_CMD_CREATE,
"Set cannot be created: set with the same name already exists" }, "Set cannot be created: set with the same name already exists" },
{ IPSET_ERR_FIND_TYPE, 0, { 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, { IPSET_ERR_MAX_SETS, 0,
"Kernel error received: maximal number of sets reached, " "Kernel error received: maximal number of sets reached, "
"cannot create more." }, "cannot create more." },
{ IPSET_ERR_INVALID_NETMASK, 0, { IPSET_ERR_INVALID_NETMASK, 0,
"The value of the netmask parameter is invalid" }, "The value of the netmask parameter is invalid" },
{ IPSET_ERR_INVALID_FAMILY, 0, { 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 */ /* DESTROY specific error codes */
{ IPSET_ERR_BUSY, IPSET_CMD_DESTROY, { IPSET_ERR_BUSY, IPSET_CMD_DESTROY,

View File

@@ -206,62 +206,54 @@ restore(char *argv0)
static int static int
call_parser(int *argc, char *argv[], const struct ipset_arg *args) 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 struct ipset_arg *arg;
const char *optstr; const char *optstr;
/* Currently CREATE and ADT may have got additional arguments */ /* Currently CREATE and ADT may have got additional arguments */
if (!args) if (!args && *argc > 1)
goto done; goto err_unknown;
for (arg = args; arg->opt; arg++) { while (*argc > 1) {
for (i = 1; i < *argc; ) { for (arg = args; arg->opt; arg++) {
D("argc: %u, i: %u: %s vs %s", D("argc: %u, %s vs %s", *argc, argv[1], arg->name[0]);
*argc, i, argv[i], arg->name[0]); if (!(ipset_match_option(argv[1], arg->name)))
if (!(ipset_match_option(argv[i], arg->name))) {
i++;
continue; continue;
}
optstr = argv[i]; optstr = argv[1];
/* Shift off matched option */ /* Shift off matched option */
D("match %s", arg->name[0]); D("match %s", arg->name[0]);
ipset_shift_argv(argc, argv, i); ipset_shift_argv(argc, argv, 1);
D("argc: %u, i: %u", *argc, i);
switch (arg->has_arg) { switch (arg->has_arg) {
case IPSET_MANDATORY_ARG: case IPSET_MANDATORY_ARG:
if (i + 1 > *argc) if (*argc < 2)
return exit_error(PARAMETER_PROBLEM, return exit_error(PARAMETER_PROBLEM,
"Missing mandatory argument " "Missing mandatory argument "
"of option `%s'", "of option `%s'",
arg->name[0]); arg->name[0]);
/* Fall through */ /* Fall through */
case IPSET_OPTIONAL_ARG: case IPSET_OPTIONAL_ARG:
if (i + 1 <= *argc) { if (*argc >= 2) {
ret = ipset_call_parser(session, ret = ipset_call_parser(session, arg, argv[1]);
arg->parse,
optstr, arg->opt,
argv[i]);
if (ret < 0) if (ret < 0)
return ret; return ret;
ipset_shift_argv(argc, argv, i); ipset_shift_argv(argc, argv, 1);
break; break;
} }
/* Fall through */ /* Fall through */
default: default:
ret = ipset_call_parser(session, ret = ipset_call_parser(session, arg, optstr);
arg->parse,
optstr, arg->opt,
optstr);
if (ret < 0) if (ret < 0)
return ret; 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; return ret;
err_unknown:
return exit_error(PARAMETER_PROBLEM, "Unknown argument: `%s'", argv[1]);
} }
static enum ipset_adt static enum ipset_adt
@@ -476,61 +468,57 @@ parse_commandline(int argc, char *argv[])
/* Second: parse command */ /* Second: parse command */
for (command = ipset_commands; for (command = ipset_commands;
command->cmd && cmd == IPSET_CMD_NONE; argc > 1 && command->cmd && cmd == IPSET_CMD_NONE;
command++) { command++) {
for (i = 1; i < argc; ) { if (!ipset_match_cmd(argv[1], command->name))
if (!ipset_match_cmd(argv[1], command->name)) { continue;
i++;
continue;
}
if (restore_line != 0
&& (command->cmd == IPSET_CMD_RESTORE
|| command->cmd == IPSET_CMD_VERSION
|| command->cmd == IPSET_CMD_HELP))
return exit_error(PARAMETER_PROBLEM,
"Command `%s' is invalid "
"in restore mode.",
command->name[0]);
if (interactive
&& command->cmd == IPSET_CMD_RESTORE) {
printf("Restore command ignored "
"in interactive mode\n");
return 0;
}
/* Shift off matched command arg */ if (restore_line != 0
ipset_shift_argv(&argc, argv, i); && (command->cmd == IPSET_CMD_RESTORE
cmd = command->cmd; || command->cmd == IPSET_CMD_VERSION
switch (command->has_arg) { || command->cmd == IPSET_CMD_HELP))
case IPSET_MANDATORY_ARG: return exit_error(PARAMETER_PROBLEM,
case IPSET_MANDATORY_ARG2: "Command `%s' is invalid "
if (i + 1 > argc) "in restore mode.",
return exit_error(PARAMETER_PROBLEM, command->name[0]);
"Missing mandatory argument " if (interactive && command->cmd == IPSET_CMD_RESTORE) {
"to command %s", printf("Restore command ignored "
command->name[0]); "in interactive mode\n");
/* Fall through */ return 0;
case IPSET_OPTIONAL_ARG: }
arg0 = argv[i];
if (i + 1 <= argc) /* Shift off matched command arg */
/* Shift off first arg */ ipset_shift_argv(&argc, argv, 1);
ipset_shift_argv(&argc, argv, i); cmd = command->cmd;
break; switch (command->has_arg) {
default: case IPSET_MANDATORY_ARG:
break; case IPSET_MANDATORY_ARG2:
} if (argc < 2)
if (command->has_arg == IPSET_MANDATORY_ARG2) { return exit_error(PARAMETER_PROBLEM,
if (i + 1 > argc) "Missing mandatory argument "
return exit_error(PARAMETER_PROBLEM, "to command %s",
"Missing second mandatory " command->name[0]);
"argument to command %s", /* Fall through */
command->name[0]); case IPSET_OPTIONAL_ARG:
arg1 = argv[i]; arg0 = argv[1];
/* Shift off second arg */ if (argc >= 2)
ipset_shift_argv(&argc, argv, i); /* Shift off first arg */
} ipset_shift_argv(&argc, argv, 1);
break;
default:
break; 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 */ /* Third: catch interactive mode, handle help, version */
@@ -565,7 +553,8 @@ parse_commandline(int argc, char *argv[])
argv[1]); argv[1]);
return exit_error(PARAMETER_PROBLEM, "No command specified."); return exit_error(PARAMETER_PROBLEM, "No command specified.");
case IPSET_CMD_VERSION: 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) if (interactive)
return 0; return 0;
return exit_error(NO_PROBLEM, NULL); return exit_error(NO_PROBLEM, NULL);

View File

@@ -23,9 +23,9 @@
const struct ipset_commands ipset_commands[] = { const struct ipset_commands ipset_commands[] = {
/* Order is important */ /* Order is important */
{ /* c[reate], --create, n, -N */ { /* c[reate], --create, n[ew], -N */
.cmd = IPSET_CMD_CREATE, .cmd = IPSET_CMD_CREATE,
.name = { "create", "n" }, .name = { "create", "new" },
.has_arg = IPSET_MANDATORY_ARG2, .has_arg = IPSET_MANDATORY_ARG2,
.help = "SETNAME TYPENAME [type-specific-options]\n" .help = "SETNAME TYPENAME [type-specific-options]\n"
" Create a new set", " Create a new set",
@@ -143,14 +143,14 @@ ipset_match_cmd(const char *arg, const char * const name[])
if (len > strlen(name[0]) || !len) if (len > strlen(name[0]) || !len)
return false; 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; return true;
else if (len != 1) else if (len != 1)
return false; return false;
else if (name[1] == NULL) else return tolower(arg[0]) == name[0][0] ||
return tolower(arg[0]) == name[0][0]; (name[1] != NULL && tolower(arg[0]) == name[1][0]);
else
return tolower(arg[0]) == name[1][0];
} }
const struct ipset_envopts ipset_envopts[] = { const struct ipset_envopts ipset_envopts[] = {

View File

@@ -56,10 +56,10 @@ match_set(ip_set_id_t index, const struct sk_buff *skb,
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35) #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
#define CHECK_OK 1 #define CHECK_OK 1
#define CHECK_FAIL 0 #define CHECK_FAIL(err) 0
#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35) */ #else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35) */
#define CHECK_OK 0 #define CHECK_OK 0
#define CHECK_FAIL (-EINVAL) #define CHECK_FAIL(err) (err)
#endif #endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35) #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
@@ -110,11 +110,12 @@ set_match_v0_checkentry(const struct xt_mtchk_param *par)
if (index == IPSET_INVALID_ID) { if (index == IPSET_INVALID_ID) {
pr_warning("Cannot find set indentified by id %u to match\n", pr_warning("Cannot find set indentified by id %u to match\n",
info->match_set.index); info->match_set.index);
return CHECK_FAIL; /* error */ return CHECK_FAIL(-ENOENT); /* error */
} }
if (info->match_set.u.flags[IPSET_DIM_MAX-1] != 0) { if (info->match_set.u.flags[IPSET_DIM_MAX-1] != 0) {
pr_warning("That's nasty!\n"); pr_warning("Protocol error: set match dimension "
return CHECK_FAIL; /* error */ "is over the limit!\n");
return CHECK_FAIL(-ERANGE); /* error */
} }
/* Fill out compatibility data */ /* Fill out compatibility data */
@@ -167,24 +168,25 @@ set_target_v0_checkentry(const struct xt_tgchk_param *par)
if (info->add_set.index != IPSET_INVALID_ID) { if (info->add_set.index != IPSET_INVALID_ID) {
index = ip_set_nfnl_get_byindex(info->add_set.index); index = ip_set_nfnl_get_byindex(info->add_set.index);
if (index == IPSET_INVALID_ID) { 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); info->add_set.index);
return CHECK_FAIL; /* error */ return CHECK_FAIL(-ENOENT); /* error */
} }
} }
if (info->del_set.index != IPSET_INVALID_ID) { if (info->del_set.index != IPSET_INVALID_ID) {
index = ip_set_nfnl_get_byindex(info->del_set.index); index = ip_set_nfnl_get_byindex(info->del_set.index);
if (index == IPSET_INVALID_ID) { 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); info->del_set.index);
return CHECK_FAIL; /* error */ return CHECK_FAIL(-ENOENT); /* error */
} }
} }
if (info->add_set.u.flags[IPSET_DIM_MAX-1] != 0 || if (info->add_set.u.flags[IPSET_DIM_MAX-1] != 0 ||
info->del_set.u.flags[IPSET_DIM_MAX-1] != 0) { info->del_set.u.flags[IPSET_DIM_MAX-1] != 0) {
pr_warning("That's nasty!\n"); pr_warning("Protocol error: SET target dimension "
return CHECK_FAIL; /* error */ "is over the limit!\n");
return CHECK_FAIL(-ERANGE); /* error */
} }
/* Fill out compatibility data */ /* Fill out compatibility data */
@@ -239,11 +241,12 @@ set_match_checkentry(const struct xt_mtchk_param *par)
if (index == IPSET_INVALID_ID) { if (index == IPSET_INVALID_ID) {
pr_warning("Cannot find set indentified by id %u to match\n", pr_warning("Cannot find set indentified by id %u to match\n",
info->match_set.index); info->match_set.index);
return CHECK_FAIL; /* error */ return CHECK_FAIL(-ENOENT); /* error */
} }
if (info->match_set.dim > IPSET_DIM_MAX) { if (info->match_set.dim > IPSET_DIM_MAX) {
pr_warning("That's nasty!\n"); pr_warning("Protocol error: set match dimension "
return CHECK_FAIL; /* error */ "is over the limit!\n");
return CHECK_FAIL(-ERANGE); /* error */
} }
return CHECK_OK; return CHECK_OK;
@@ -295,24 +298,25 @@ set_target_checkentry(const struct xt_tgchk_param *par)
if (info->add_set.index != IPSET_INVALID_ID) { if (info->add_set.index != IPSET_INVALID_ID) {
index = ip_set_nfnl_get_byindex(info->add_set.index); index = ip_set_nfnl_get_byindex(info->add_set.index);
if (index == IPSET_INVALID_ID) { 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); info->add_set.index);
return CHECK_FAIL; /* error */ return CHECK_FAIL(-ENOENT); /* error */
} }
} }
if (info->del_set.index != IPSET_INVALID_ID) { if (info->del_set.index != IPSET_INVALID_ID) {
index = ip_set_nfnl_get_byindex(info->del_set.index); index = ip_set_nfnl_get_byindex(info->del_set.index);
if (index == IPSET_INVALID_ID) { 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); info->del_set.index);
return CHECK_FAIL; /* error */ return CHECK_FAIL(-ENOENT); /* error */
} }
} }
if (info->add_set.dim > IPSET_DIM_MAX || if (info->add_set.dim > IPSET_DIM_MAX ||
info->del_set.flags > IPSET_DIM_MAX) { info->del_set.flags > IPSET_DIM_MAX) {
pr_warning("That's nasty!\n"); pr_warning("Protocol error: SET target dimension "
return CHECK_FAIL; /* error */ "is over the limit!\n");
return CHECK_FAIL(-ERANGE); /* error */
} }
return CHECK_OK; return CHECK_OK;

View File

@@ -1,6 +1,7 @@
#ifndef _XT_SET_H #ifndef _XT_SET_H
#define _XT_SET_H #define _XT_SET_H
#include <linux/types.h>
#include "ip_set.h" #include "ip_set.h"
/* Revision 0 interface: backward compatible with netfilter/iptables */ /* Revision 0 interface: backward compatible with netfilter/iptables */

29
mconfig
View File

@@ -1,30 +1,3 @@
# -*- Makefile -*- # -*- Makefile -*-
# #
build_ACCOUNT=m build_ipset6=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