Merge branch 'ipset-6'

This commit is contained in:
Jan Engelhardt
2011-05-31 16:56:26 +02:00
44 changed files with 1489 additions and 1721 deletions

2
README
View File

@@ -19,7 +19,7 @@ simplified, and sped up.
Included in this package
========================
- ipset 4.5
- ipset 5.4.1
- ipset 6.6a-genl
- xt_ACCOUNT 1.16, libxt_ACCOUNT 1.3

View File

@@ -21,4 +21,4 @@ ipset_SOURCES = src/ipset.c src/errcode.c src/ui.c src/ipset_bitmap_ip.c \
src/ipset_list_set.c
ipset_LDADD = libipset.la
man_MANS = ipset.8
man_MANS = src/ipset.8

View File

@@ -44,6 +44,7 @@ enum ipset_opt {
IPSET_OPT_NAMEREF,
IPSET_OPT_IP2,
IPSET_OPT_CIDR2,
IPSET_OPT_IP2_TO,
IPSET_OPT_PROTO,
/* Swap/rename to */
IPSET_OPT_SETNAME2,

View File

@@ -12,7 +12,7 @@
*/
/* The protocol version */
#define IPSET_PROTOCOL 6
#define IPSET_PROTOCOL 0x60
/* The max length of strings including NUL: set and type identifiers */
#define IPSET_MAXNAMELEN 32
@@ -104,6 +104,7 @@ enum {
IPSET_ATTR_NAMEREF,
IPSET_ATTR_IP2,
IPSET_ATTR_CIDR2,
IPSET_ATTR_IP2_TO,
__IPSET_ATTR_ADT_MAX,
};
#define IPSET_ATTR_ADT_MAX (__IPSET_ATTR_ADT_MAX - 1)
@@ -142,6 +143,10 @@ enum ipset_errno {
enum ipset_cmd_flags {
IPSET_FLAG_BIT_EXIST = 0,
IPSET_FLAG_EXIST = (1 << IPSET_FLAG_BIT_EXIST),
IPSET_FLAG_BIT_LIST_SETNAME = 1,
IPSET_FLAG_LIST_SETNAME = (1 << IPSET_FLAG_BIT_LIST_SETNAME),
IPSET_FLAG_BIT_LIST_HEADER = 2,
IPSET_FLAG_LIST_HEADER = (1 << IPSET_FLAG_BIT_LIST_HEADER),
};
/* Flags at CADT attribute level */

View File

@@ -11,6 +11,10 @@ enum {
IPSET_ERR_INVALID_PROTO,
/* Protocol missing but must be specified */
IPSET_ERR_MISSING_PROTO,
/* Range not supported */
IPSET_ERR_HASH_RANGE_UNSUPPORTED,
/* Invalid range */
IPSET_ERR_HASH_RANGE,
};
#endif /* __IP_SET_HASH_H */

View File

@@ -60,6 +60,8 @@ extern int ipset_parse_ipnet(struct ipset_session *session,
enum ipset_opt opt, const char *str);
extern int ipset_parse_ip4_single6(struct ipset_session *session,
enum ipset_opt opt, const char *str);
extern int ipset_parse_ip4_net6(struct ipset_session *session,
enum ipset_opt opt, const char *str);
extern int ipset_parse_name(struct ipset_session *session,
enum ipset_opt opt, const char *str);
extern int ipset_parse_before(struct ipset_session *session,

View File

@@ -65,6 +65,10 @@ enum ipset_envopt {
IPSET_ENV_RESOLVE = (1 << IPSET_ENV_BIT_RESOLVE),
IPSET_ENV_BIT_EXIST = 3,
IPSET_ENV_EXIST = (1 << IPSET_ENV_BIT_EXIST),
IPSET_ENV_BIT_LIST_SETNAME = 4,
IPSET_ENV_LIST_SETNAME = (1 << IPSET_ENV_BIT_LIST_SETNAME),
IPSET_ENV_BIT_LIST_HEADER = 5,
IPSET_ENV_LIST_HEADER = (1 << IPSET_ENV_BIT_LIST_HEADER),
};
extern int ipset_envopt_parse(struct ipset_session *session,
@@ -92,4 +96,6 @@ typedef int (*ipset_outfn)(const char *fmt, ...)
extern struct ipset_session * ipset_session_init(ipset_outfn outfn);
extern int ipset_session_fini(struct ipset_session *session);
extern void ipset_debug_msg(const char *dir, void *buffer, int len);
#endif /* LIBIPSET_SESSION_H */

View File

@@ -14,7 +14,7 @@
#include <linux/netlink.h>
/* The protocol version */
#define IPSET_PROTOCOL 6
#define IPSET_PROTOCOL 0x60
/* The max length of strings including NUL: set and type identifiers */
#define IPSET_MAXNAMELEN 32
@@ -106,6 +106,7 @@ enum {
IPSET_ATTR_NAMEREF,
IPSET_ATTR_IP2,
IPSET_ATTR_CIDR2,
IPSET_ATTR_IP2_TO,
__IPSET_ATTR_ADT_MAX,
};
#define IPSET_ATTR_ADT_MAX (__IPSET_ATTR_ADT_MAX - 1)
@@ -144,6 +145,10 @@ enum ipset_errno {
enum ipset_cmd_flags {
IPSET_FLAG_BIT_EXIST = 0,
IPSET_FLAG_EXIST = (1 << IPSET_FLAG_BIT_EXIST),
IPSET_FLAG_BIT_LIST_SETNAME = 1,
IPSET_FLAG_LIST_SETNAME = (1 << IPSET_FLAG_BIT_LIST_SETNAME),
IPSET_FLAG_BIT_LIST_HEADER = 2,
IPSET_FLAG_LIST_HEADER = (1 << IPSET_FLAG_BIT_LIST_HEADER),
};
/* Flags at CADT attribute level */
@@ -167,6 +172,7 @@ enum ipset_adt {
#include <linux/ipv6.h>
#include <linux/netlink.h>
#include <linux/netfilter.h>
#include <linux/netfilter/x_tables.h>
#include <linux/vmalloc.h>
#include <net/netlink.h>
@@ -219,6 +225,15 @@ struct ip_set;
typedef int (*ipset_adtfn)(struct ip_set *set, void *value,
u32 timeout, u32 flags);
/* Kernel API function options */
struct ip_set_adt_opt {
u8 family; /* Actual protocol family */
u8 dim; /* Dimension of match/target */
u8 flags; /* Direction and negation flags */
u32 cmdflags; /* Command-like flags */
u32 timeout; /* Timeout value */
};
/* Set type, variant-specific part */
struct ip_set_type_variant {
/* Kernelspace: test/add/del entries
@@ -226,14 +241,15 @@ struct ip_set_type_variant {
* zero for no match/success to add/delete
* positive for matching element */
int (*kadt)(struct ip_set *set, const struct sk_buff * skb,
enum ipset_adt adt, u8 pf, u8 dim, u8 flags);
const struct xt_action_param *par,
enum ipset_adt adt, const struct ip_set_adt_opt *opt);
/* Userspace: test/add/del entries
* returns negative error code,
* zero for no match/success to add/delete
* positive for matching element */
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, bool retried);
/* Low level add/del/test functions */
ipset_adtfn adt[IPSET_ADT_MAX];
@@ -271,8 +287,8 @@ struct ip_set_type {
u8 dimension;
/* Supported family: may be AF_UNSPEC for both AF_INET/AF_INET6 */
u8 family;
/* Type revision */
u8 revision;
/* Type revisions */
u8 revision_min, revision_max;
/* Create set */
int (*create)(struct ip_set *set, struct nlattr *tb[], u32 flags);
@@ -303,6 +319,8 @@ struct ip_set {
const struct ip_set_type_variant *variant;
/* The actual INET family of the set */
u8 family;
/* The type revision */
u8 revision;
/* The type specific data */
void *data;
};
@@ -316,12 +334,16 @@ extern ip_set_id_t ip_set_nfnl_get_byindex(ip_set_id_t index);
extern void ip_set_nfnl_put(ip_set_id_t index);
/* API for iptables set match, and SET target */
extern int ip_set_add(ip_set_id_t id, const struct sk_buff *skb,
u8 family, u8 dim, u8 flags);
const struct xt_action_param *par,
const struct ip_set_adt_opt *opt);
extern int ip_set_del(ip_set_id_t id, const struct sk_buff *skb,
u8 family, u8 dim, u8 flags);
const struct xt_action_param *par,
const struct ip_set_adt_opt *opt);
extern int ip_set_test(ip_set_id_t id, const struct sk_buff *skb,
u8 family, u8 dim, u8 flags);
const struct xt_action_param *par,
const struct ip_set_adt_opt *opt);
/* Utility functions */
extern void * ip_set_alloc(size_t size);

View File

@@ -5,6 +5,11 @@
#include "jhash.h"
#include "ip_set_timeout.h"
#define CONCAT(a, b, c) a##b##c
#define TOKEN(a, b, c) CONCAT(a, b, c)
#define type_pf_next TOKEN(TYPE, PF, _elem)
/* Hashing which uses arrays to resolve clashing. The hash table is resized
* (doubled) when searching becomes too long.
* Internally jhash is used with the assumption that the size of the
@@ -54,6 +59,7 @@ struct ip_set_hash {
u32 initval; /* random jhash init value */
u32 timeout; /* timeout value, if enabled */
struct timer_list gc; /* garbage collection when timeout enabled */
struct type_pf_next next; /* temporary storage for uadd */
#ifdef IP_SET_HASH_WITH_NETMASK
u8 netmask; /* netmask value for subnets to store */
#endif
@@ -217,6 +223,7 @@ ip_set_hash_destroy(struct ip_set *set)
#define type_pf_data_netmask TOKEN(TYPE, PF, _data_netmask)
#define type_pf_data_list TOKEN(TYPE, PF, _data_list)
#define type_pf_data_tlist TOKEN(TYPE, PF, _data_tlist)
#define type_pf_data_next TOKEN(TYPE, PF, _data_next)
#define type_pf_elem TOKEN(TYPE, PF, _elem)
#define type_pf_telem TOKEN(TYPE, PF, _telem)
@@ -346,6 +353,9 @@ retry:
return 0;
}
static void
type_pf_data_next(struct ip_set_hash *h, const struct type_pf_elem *d);
/* Add an element to a hash and update the internal counters when succeeded,
* otherwise report the proper error code. */
static int
@@ -372,8 +382,11 @@ type_pf_add(struct ip_set *set, void *value, u32 timeout, u32 flags)
}
ret = type_pf_elem_add(n, value);
if (ret != 0)
if (ret != 0) {
if (ret == -EAGAIN)
type_pf_data_next(h, d);
goto out;
}
#ifdef IP_SET_HASH_WITH_NETS
add_cidr(h, d->cidr, HOST_MASK);
@@ -586,10 +599,11 @@ nla_put_failure:
static int
type_pf_kadt(struct ip_set *set, const struct sk_buff * skb,
enum ipset_adt adt, u8 pf, u8 dim, u8 flags);
const struct xt_action_param *par,
enum ipset_adt adt, const struct ip_set_adt_opt *opt);
static int
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, bool retried);
static const struct ip_set_type_variant type_pf_variant = {
.kadt = type_pf_kadt,
@@ -821,8 +835,11 @@ type_pf_tadd(struct ip_set *set, void *value, u32 timeout, u32 flags)
goto out;
}
ret = type_pf_elem_tadd(n, d, timeout);
if (ret != 0)
if (ret != 0) {
if (ret == -EAGAIN)
type_pf_data_next(h, d);
goto out;
}
#ifdef IP_SET_HASH_WITH_NETS
add_cidr(h, d->cidr, HOST_MASK);
@@ -840,7 +857,7 @@ type_pf_tdel(struct ip_set *set, void *value, u32 timeout, u32 flags)
struct htable *t = h->table;
const struct type_pf_elem *d = value;
struct hbucket *n;
int i, ret = 0;
int i;
struct type_pf_elem *data;
u32 key;
@@ -851,7 +868,7 @@ type_pf_tdel(struct ip_set *set, void *value, u32 timeout, u32 flags)
if (!type_pf_data_equal(data, d))
continue;
if (type_pf_data_expired(data))
ret = -IPSET_ERR_EXIST;
return -IPSET_ERR_EXIST;
if (i != n->pos - 1)
/* Not last one */
type_pf_data_copy(data, ahash_tdata(n, n->pos - 1));

View File

@@ -219,24 +219,25 @@ nla_put_failure:
static int
bitmap_ip_kadt(struct ip_set *set, const struct sk_buff *skb,
enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
const struct xt_action_param *par,
enum ipset_adt adt, const struct ip_set_adt_opt *opt)
{
struct bitmap_ip *map = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
u32 ip;
ip = ntohl(ip4addr(skb, flags & IPSET_DIM_ONE_SRC));
ip = ntohl(ip4addr(skb, opt->flags & IPSET_DIM_ONE_SRC));
if (ip < map->first_ip || ip > map->last_ip)
return -IPSET_ERR_BITMAP_RANGE;
ip = ip_to_id(map, ip);
return adtfn(set, &ip, map->timeout, flags);
return adtfn(set, &ip, opt_timeout(opt, map), opt->cmdflags);
}
static int
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, bool retried)
{
struct bitmap_ip *map = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
@@ -283,8 +284,7 @@ bitmap_ip_uadt(struct ip_set *set, struct nlattr *tb[],
if (cidr > 32)
return -IPSET_ERR_INVALID_CIDR;
ip &= ip_set_hostmask(cidr);
ip_to = ip | ~ip_set_hostmask(cidr);
ip_set_mask_from_to(ip, ip_to, cidr);
} else
ip_to = ip;
@@ -478,7 +478,7 @@ bitmap_ip_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
if (cidr >= 32)
return -IPSET_ERR_INVALID_CIDR;
last_ip = first_ip | ~ip_set_hostmask(cidr);
ip_set_mask_from_to(first_ip, last_ip, cidr);
} else
return -IPSET_ERR_PROTOCOL;
@@ -551,7 +551,8 @@ static struct ip_set_type bitmap_ip_type __read_mostly = {
.features = IPSET_TYPE_IP,
.dimension = IPSET_DIM_ONE,
.family = AF_INET,
.revision = 0,
.revision_min = 0,
.revision_max = 0,
.create = bitmap_ip_create,
.create_policy = {
[IPSET_ATTR_IP] = { .type = NLA_NESTED },

View File

@@ -338,17 +338,18 @@ nla_put_failure:
static int
bitmap_ipmac_kadt(struct ip_set *set, const struct sk_buff *skb,
enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
const struct xt_action_param *par,
enum ipset_adt adt, const struct ip_set_adt_opt *opt)
{
struct bitmap_ipmac *map = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
struct ipmac data;
/* MAC can be src only */
if (!(flags & IPSET_DIM_TWO_SRC))
if (!(opt->flags & IPSET_DIM_TWO_SRC))
return 0;
data.id = ntohl(ip4addr(skb, flags & IPSET_DIM_ONE_SRC));
data.id = ntohl(ip4addr(skb, opt->flags & IPSET_DIM_ONE_SRC));
if (data.id < map->first_ip || data.id > map->last_ip)
return -IPSET_ERR_BITMAP_RANGE;
@@ -360,12 +361,12 @@ bitmap_ipmac_kadt(struct ip_set *set, const struct sk_buff *skb,
data.id -= map->first_ip;
data.ether = eth_hdr(skb)->h_source;
return adtfn(set, &data, map->timeout, flags);
return adtfn(set, &data, opt_timeout(opt, map), opt->cmdflags);
}
static int
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, bool retried)
{
const struct bitmap_ipmac *map = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
@@ -578,7 +579,7 @@ bitmap_ipmac_create(struct ip_set *set, struct nlattr *tb[],
if (cidr >= 32)
return -IPSET_ERR_INVALID_CIDR;
last_ip = first_ip | ~ip_set_hostmask(cidr);
ip_set_mask_from_to(first_ip, last_ip, cidr);
} else
return -IPSET_ERR_PROTOCOL;
@@ -623,7 +624,8 @@ static struct ip_set_type bitmap_ipmac_type = {
.features = IPSET_TYPE_IP | IPSET_TYPE_MAC,
.dimension = IPSET_DIM_TWO,
.family = AF_INET,
.revision = 0,
.revision_min = 0,
.revision_max = 0,
.create = bitmap_ipmac_create,
.create_policy = {
[IPSET_ATTR_IP] = { .type = NLA_NESTED },

View File

@@ -208,14 +208,16 @@ nla_put_failure:
static int
bitmap_port_kadt(struct ip_set *set, const struct sk_buff *skb,
enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
const struct xt_action_param *par,
enum ipset_adt adt, const struct ip_set_adt_opt *opt)
{
struct bitmap_port *map = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
__be16 __port;
u16 port = 0;
if (!ip_set_get_ip_port(skb, pf, flags & IPSET_DIM_ONE_SRC, &__port))
if (!ip_set_get_ip_port(skb, opt->family,
opt->flags & IPSET_DIM_ONE_SRC, &__port))
return -EINVAL;
port = ntohs(__port);
@@ -225,12 +227,12 @@ bitmap_port_kadt(struct ip_set *set, const struct sk_buff *skb,
port -= map->first_port;
return adtfn(set, &port, map->timeout, flags);
return adtfn(set, &port, opt_timeout(opt, map), opt->cmdflags);
}
static int
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, bool retried)
{
struct bitmap_port *map = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
@@ -482,7 +484,8 @@ static struct ip_set_type bitmap_port_type = {
.features = IPSET_TYPE_PORT,
.dimension = IPSET_DIM_ONE,
.family = AF_UNSPEC,
.revision = 0,
.revision_min = 0,
.revision_max = 0,
.create = bitmap_port_create,
.create_policy = {
[IPSET_ATTR_PORT] = { .type = NLA_U16 },

File diff suppressed because it is too large Load Diff

View File

@@ -21,6 +21,7 @@
#include <net/netlink.h>
#include <linux/netfilter.h>
#include <linux/netfilter/x_tables.h>
#include <linux/netfilter/nfnetlink.h>
#include "ip_set.h"
#include <net/genetlink.h>
@@ -75,7 +76,8 @@ find_set_type(const char *name, u8 family, u8 revision)
list_for_each_entry_rcu(type, &ip_set_type_list, list)
if (STREQ(type->name, name) &&
(type->family == family || type->family == AF_UNSPEC) &&
type->revision == revision)
revision >= type->revision_min &&
revision <= type->revision_max)
return type;
return NULL;
}
@@ -148,10 +150,10 @@ retry:
if (STREQ(type->name, name) &&
(type->family == family || type->family == AF_UNSPEC)) {
found = true;
if (type->revision < *min)
*min = type->revision;
if (type->revision > *max)
*max = type->revision;
if (type->revision_min < *min)
*min = type->revision_min;
if (type->revision_max > *max)
*max = type->revision_max;
}
rcu_read_unlock();
if (found)
@@ -175,25 +177,27 @@ ip_set_type_register(struct ip_set_type *type)
int ret = 0;
if (type->protocol != IPSET_PROTOCOL) {
pr_warning("ip_set type %s, family %s, revision %u uses "
pr_warning("ip_set type %s, family %s, revision %u:%u uses "
"wrong protocol version %u (want %u)\n",
type->name, family_name(type->family),
type->revision, type->protocol, IPSET_PROTOCOL);
type->revision_min, type->revision_max,
type->protocol, IPSET_PROTOCOL);
return -EINVAL;
}
ip_set_type_lock();
if (find_set_type(type->name, type->family, type->revision)) {
if (find_set_type(type->name, type->family, type->revision_min)) {
/* Duplicate! */
pr_warning("ip_set type %s, family %s, revision %u "
pr_warning("ip_set type %s, family %s with revision min %u "
"already registered!\n", type->name,
family_name(type->family), type->revision);
family_name(type->family), type->revision_min);
ret = -EINVAL;
goto unlock;
}
list_add_rcu(&type->list, &ip_set_type_list);
pr_debug("type %s, family %s, revision %u registered.\n",
type->name, family_name(type->family), type->revision);
pr_debug("type %s, family %s, revision %u:%u registered.\n",
type->name, family_name(type->family),
type->revision_min, type->revision_max);
unlock:
ip_set_type_unlock();
return ret;
@@ -205,15 +209,15 @@ void
ip_set_type_unregister(struct ip_set_type *type)
{
ip_set_type_lock();
if (!find_set_type(type->name, type->family, type->revision)) {
pr_warning("ip_set type %s, family %s, revision %u "
if (!find_set_type(type->name, type->family, type->revision_min)) {
pr_warning("ip_set type %s, family %s with revision min %u "
"not registered\n", type->name,
family_name(type->family), type->revision);
family_name(type->family), type->revision_min);
goto unlock;
}
list_del_rcu(&type->list);
pr_debug("type %s, family %s, revision %u unregistered.\n",
type->name, family_name(type->family), type->revision);
pr_debug("type %s, family %s with revision min %u unregistered.\n",
type->name, family_name(type->family), type->revision_min);
unlock:
ip_set_type_unlock();
@@ -346,7 +350,8 @@ __ip_set_put(ip_set_id_t index)
int
ip_set_test(ip_set_id_t index, const struct sk_buff *skb,
u8 family, u8 dim, u8 flags)
const struct xt_action_param *par,
const struct ip_set_adt_opt *opt)
{
struct ip_set *set = ip_set_list[index];
int ret = 0;
@@ -354,19 +359,19 @@ ip_set_test(ip_set_id_t index, const struct sk_buff *skb,
BUG_ON(set == NULL);
pr_debug("set %s, index %u\n", set->name, index);
if (dim < set->type->dimension ||
!(family == set->family || set->family == AF_UNSPEC))
if (opt->dim < set->type->dimension ||
!(opt->family == set->family || set->family == AF_UNSPEC))
return 0;
read_lock_bh(&set->lock);
ret = set->variant->kadt(set, skb, IPSET_TEST, family, dim, flags);
ret = set->variant->kadt(set, skb, par, IPSET_TEST, opt);
read_unlock_bh(&set->lock);
if (ret == -EAGAIN) {
/* Type requests element to be completed */
pr_debug("element must be competed, ADD is triggered\n");
write_lock_bh(&set->lock);
set->variant->kadt(set, skb, IPSET_ADD, family, dim, flags);
set->variant->kadt(set, skb, par, IPSET_ADD, opt);
write_unlock_bh(&set->lock);
ret = 1;
}
@@ -378,7 +383,8 @@ EXPORT_SYMBOL_GPL(ip_set_test);
int
ip_set_add(ip_set_id_t index, const struct sk_buff *skb,
u8 family, u8 dim, u8 flags)
const struct xt_action_param *par,
const struct ip_set_adt_opt *opt)
{
struct ip_set *set = ip_set_list[index];
int ret;
@@ -386,12 +392,12 @@ ip_set_add(ip_set_id_t index, const struct sk_buff *skb,
BUG_ON(set == NULL);
pr_debug("set %s, index %u\n", set->name, index);
if (dim < set->type->dimension ||
!(family == set->family || set->family == AF_UNSPEC))
if (opt->dim < set->type->dimension ||
!(opt->family == set->family || set->family == AF_UNSPEC))
return 0;
write_lock_bh(&set->lock);
ret = set->variant->kadt(set, skb, IPSET_ADD, family, dim, flags);
ret = set->variant->kadt(set, skb, par, IPSET_ADD, opt);
write_unlock_bh(&set->lock);
return ret;
@@ -400,7 +406,8 @@ EXPORT_SYMBOL_GPL(ip_set_add);
int
ip_set_del(ip_set_id_t index, const struct sk_buff *skb,
u8 family, u8 dim, u8 flags)
const struct xt_action_param *par,
const struct ip_set_adt_opt *opt)
{
struct ip_set *set = ip_set_list[index];
int ret = 0;
@@ -408,12 +415,12 @@ ip_set_del(ip_set_id_t index, const struct sk_buff *skb,
BUG_ON(set == NULL);
pr_debug("set %s, index %u\n", set->name, index);
if (dim < set->type->dimension ||
!(family == set->family || set->family == AF_UNSPEC))
if (opt->dim < set->type->dimension ||
!(opt->family == set->family || set->family == AF_UNSPEC))
return 0;
write_lock_bh(&set->lock);
ret = set->variant->kadt(set, skb, IPSET_DEL, family, dim, flags);
ret = set->variant->kadt(set, skb, par, IPSET_DEL, opt);
write_unlock_bh(&set->lock);
return ret;
@@ -668,6 +675,7 @@ ip_set_create(struct sk_buff *skb, struct genl_info *info)
rwlock_init(&set->lock);
strlcpy(set->name, name, IPSET_MAXNAMELEN);
set->family = family;
set->revision = revision;
/*
* Next, check that we know the type, and take
@@ -708,7 +716,8 @@ ip_set_create(struct sk_buff *skb, struct genl_info *info)
(flags & IPSET_FLAG_EXIST) &&
STREQ(set->type->name, clash->type->name) &&
set->type->family == clash->type->family &&
set->type->revision == clash->type->revision &&
set->type->revision_min == clash->type->revision_min &&
set->type->revision_max == clash->type->revision_max &&
set->variant->same_set(set, clash))
ret = 0;
goto cleanup;
@@ -778,7 +787,7 @@ ip_set_destroy(struct sk_buff *skb, struct genl_info *info)
if (!attr[IPSET_ATTR_SETNAME]) {
for (i = 0; i < ip_set_max; i++) {
if (ip_set_list[i] != NULL && ip_set_list[i]->ref) {
ret = IPSET_ERR_BUSY;
ret = -IPSET_ERR_BUSY;
goto out;
}
}
@@ -825,7 +834,7 @@ ip_set_flush(struct sk_buff *skb, struct genl_info *info)
ip_set_id_t i;
if (unlikely(protocol_failed(attr)))
return -EPROTO;
return -IPSET_ERR_PROTOCOL;
if (!attr[IPSET_ATTR_SETNAME]) {
for (i = 0; i < ip_set_max; i++)
@@ -947,10 +956,13 @@ ip_set_swap(struct sk_buff *skb, struct genl_info *info)
/* List/save set data */
#define DUMP_INIT 0L
#define DUMP_ALL 1L
#define DUMP_ONE 2L
#define DUMP_LAST 3L
#define DUMP_INIT 0
#define DUMP_ALL 1
#define DUMP_ONE 2
#define DUMP_LAST 3
#define DUMP_TYPE(arg) (((u32)(arg)) & 0x0000FFFF)
#define DUMP_FLAGS(arg) (((u32)(arg)) >> 16)
static int
ip_set_dump_done(struct netlink_callback *cb)
@@ -983,6 +995,7 @@ dump_init(struct netlink_callback *cb)
int min_len = NLMSG_SPACE(sizeof(struct genlmsghdr));
struct nlattr *cda[IPSET_ATTR_CMD_MAX+1];
struct nlattr *attr = (void *)nlh + min_len;
u32 dump_type;
ip_set_id_t index;
/* Second pass, so parser can't fail */
@@ -994,17 +1007,22 @@ dump_init(struct netlink_callback *cb)
* [..]: type specific
*/
if (!cda[IPSET_ATTR_SETNAME]) {
cb->args[0] = DUMP_ALL;
return 0;
if (cda[IPSET_ATTR_SETNAME]) {
index = find_set_id(nla_data(cda[IPSET_ATTR_SETNAME]));
if (index == IPSET_INVALID_ID)
return -ENOENT;
dump_type = DUMP_ONE;
cb->args[1] = index;
} else
dump_type = DUMP_ALL;
if (cda[IPSET_ATTR_FLAGS]) {
u32 f = ip_set_get_h32(cda[IPSET_ATTR_FLAGS]);
dump_type |= (f << 16);
}
cb->args[0] = dump_type;
index = find_set_id(nla_data(cda[IPSET_ATTR_SETNAME]));
if (index == IPSET_INVALID_ID)
return -ENOENT;
cb->args[0] = DUMP_ONE;
cb->args[1] = index;
return 0;
}
@@ -1015,9 +1033,10 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb)
struct ip_set *set = NULL;
struct genlmsg_buf *nlh = NULL;
unsigned int flags = NETLINK_CB(cb->skb).pid ? NLM_F_MULTI : 0;
u32 dump_type, dump_flags;
int ret = 0;
if (cb->args[0] == DUMP_INIT) {
if (!cb->args[0]) {
ret = dump_init(cb);
if (ret < 0) {
struct nlmsghdr *nlh = nlmsg_hdr(cb->skb);
@@ -1032,13 +1051,17 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb)
if (cb->args[1] >= ip_set_max)
goto out;
pr_debug("args[0]: %ld args[1]: %ld\n", cb->args[0], cb->args[1]);
max = cb->args[0] == DUMP_ONE ? cb->args[1] + 1 : ip_set_max;
dump_type = DUMP_TYPE(cb->args[0]);
dump_flags = DUMP_FLAGS(cb->args[0]);
max = dump_type == DUMP_ONE ? cb->args[1] + 1 : ip_set_max;
dump_last:
pr_debug("args[0]: %u %u args[1]: %ld\n",
dump_type, dump_flags, cb->args[1]);
for (; cb->args[1] < max; cb->args[1]++) {
index = (ip_set_id_t) cb->args[1];
set = ip_set_list[index];
if (set == NULL) {
if (cb->args[0] == DUMP_ONE) {
if (dump_type == DUMP_ONE) {
ret = -ENOENT;
goto out;
}
@@ -1047,9 +1070,9 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb)
/* When dumping all sets, we must dump "sorted"
* so that lists (unions of sets) are dumped last.
*/
if (cb->args[0] != DUMP_ONE &&
!((cb->args[0] == DUMP_ALL) ^
(set->type->features & IPSET_DUMP_LAST)))
if (dump_type != DUMP_ONE &&
((dump_type == DUMP_ALL) ==
!!(set->type->features & IPSET_DUMP_LAST)))
continue;
pr_debug("List set: %s\n", set->name);
if (!cb->args[2]) {
@@ -1066,6 +1089,8 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb)
}
NLA_PUT_U8(skb, IPSET_ATTR_PROTOCOL, IPSET_PROTOCOL);
NLA_PUT_STRING(skb, IPSET_ATTR_SETNAME, set->name);
if (dump_flags & IPSET_FLAG_LIST_SETNAME)
goto next_set;
switch (cb->args[2]) {
case 0:
/* Core header data */
@@ -1074,40 +1099,45 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb)
NLA_PUT_U8(skb, IPSET_ATTR_FAMILY,
set->family);
NLA_PUT_U8(skb, IPSET_ATTR_REVISION,
set->type->revision);
set->revision);
ret = set->variant->head(set, skb);
if (ret < 0)
goto release_refcount;
if (dump_flags & IPSET_FLAG_LIST_HEADER)
goto next_set;
/* Fall through and add elements */
default:
read_lock_bh(&set->lock);
ret = set->variant->list(set, skb, cb);
read_unlock_bh(&set->lock);
if (!cb->args[2]) {
if (!cb->args[2])
/* Set is done, proceed with next one */
if (cb->args[0] == DUMP_ONE)
cb->args[1] = IPSET_INVALID_ID;
else
cb->args[1]++;
}
goto next_set;
goto release_refcount;
}
}
/* If we dump all sets, continue with dumping last ones */
if (dump_type == DUMP_ALL) {
dump_type = DUMP_LAST;
cb->args[0] = dump_type | (dump_flags << 16);
cb->args[1] = 0;
goto dump_last;
}
goto out;
nla_put_failure:
ret = -EFAULT;
next_set:
if (dump_type == DUMP_ONE)
cb->args[1] = IPSET_INVALID_ID;
else
cb->args[1]++;
release_refcount:
/* If there was an error or set is done, release set */
if (ret || !cb->args[2]) {
pr_debug("release set %s\n", ip_set_list[index]->name);
ip_set_put_byindex(index);
}
/* If we dump all sets, continue with dumping last ones */
if (cb->args[0] == DUMP_ALL && cb->args[1] >= max && !cb->args[2])
cb->args[0] = DUMP_LAST;
out:
if (nlh) {
genlmsg_end(skb, nlh);
@@ -1153,17 +1183,18 @@ call_ad(struct sock *ctnl, struct sk_buff *skb, struct ip_set *set,
struct nlattr *tb[], enum ipset_adt adt,
u32 flags, bool use_lineno)
{
int ret, retried = 0;
int ret;
u32 lineno = 0;
bool eexist = flags & IPSET_FLAG_EXIST;
bool eexist = flags & IPSET_FLAG_EXIST, retried = false;
do {
write_lock_bh(&set->lock);
ret = set->variant->uadt(set, tb, adt, &lineno, flags);
ret = set->variant->uadt(set, tb, adt, &lineno, flags, retried);
write_unlock_bh(&set->lock);
retried = true;
} while (ret == -EAGAIN &&
set->variant->resize &&
(ret = set->variant->resize(set, retried++)) == 0);
(ret = set->variant->resize(set, retried)) == 0);
if (!ret || (ret == -IPSET_ERR_EXIST && eexist))
return 0;
@@ -1338,7 +1369,7 @@ ip_set_utest(struct sk_buff *skb, struct genl_info *info)
return -IPSET_ERR_PROTOCOL;
read_lock_bh(&set->lock);
ret = set->variant->uadt(set, tb, IPSET_TEST, NULL, 0);
ret = set->variant->uadt(set, tb, IPSET_TEST, NULL, 0, 0);
read_unlock_bh(&set->lock);
/* Userspace can't trigger element to be re-added */
if (ret == -EAGAIN)
@@ -1381,7 +1412,7 @@ ip_set_header(struct sk_buff *skb, struct genl_info *info)
NLA_PUT_STRING(skb2, IPSET_ATTR_SETNAME, set->name);
NLA_PUT_STRING(skb2, IPSET_ATTR_TYPENAME, set->type->name);
NLA_PUT_U8(skb2, IPSET_ATTR_FAMILY, set->family);
NLA_PUT_U8(skb2, IPSET_ATTR_REVISION, set->type->revision);
NLA_PUT_U8(skb2, IPSET_ATTR_REVISION, set->revision);
genlmsg_end(skb2, nlh2);
ret = genlmsg_unicast(genl_info_net(info), skb2, NETLINK_CB(skb).pid);

View File

@@ -11,6 +11,10 @@ enum {
IPSET_ERR_INVALID_PROTO,
/* Protocol missing but must be specified */
IPSET_ERR_MISSING_PROTO,
/* Range not supported */
IPSET_ERR_HASH_RANGE_UNSUPPORTED,
/* Invalid range */
IPSET_ERR_HASH_RANGE,
};
#ifdef __KERNEL__

View File

@@ -108,25 +108,32 @@ nla_put_failure:
#define HOST_MASK 32
#include "ip_set_ahash.h"
static inline void
hash_ip4_data_next(struct ip_set_hash *h, const struct hash_ip4_elem *d)
{
h->next.ip = ntohl(d->ip);
}
static int
hash_ip4_kadt(struct ip_set *set, const struct sk_buff *skb,
enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
const struct xt_action_param *par,
enum ipset_adt adt, const struct ip_set_adt_opt *opt)
{
const struct ip_set_hash *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
__be32 ip;
ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &ip);
ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &ip);
ip &= ip_set_netmask(h->netmask);
if (ip == 0)
return -EINVAL;
return adtfn(set, &ip, h->timeout, flags);
return adtfn(set, &ip, opt_timeout(opt, h), opt->cmdflags);
}
static int
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, bool retried)
{
const struct ip_set_hash *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
@@ -171,13 +178,14 @@ hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[],
if (cidr > 32)
return -IPSET_ERR_INVALID_CIDR;
ip &= ip_set_hostmask(cidr);
ip_to = ip | ~ip_set_hostmask(cidr);
ip_set_mask_from_to(ip, ip_to, cidr);
} else
ip_to = ip;
hosts = h->netmask == 32 ? 1 : 2 << (32 - h->netmask - 1);
if (retried)
ip = h->next.ip;
for (; !before(ip_to, ip); ip += hosts) {
nip = htonl(ip);
if (nip == 0)
@@ -281,20 +289,26 @@ nla_put_failure:
#define HOST_MASK 128
#include "ip_set_ahash.h"
static inline void
hash_ip6_data_next(struct ip_set_hash *h, const struct hash_ip6_elem *d)
{
}
static int
hash_ip6_kadt(struct ip_set *set, const struct sk_buff *skb,
enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
const struct xt_action_param *par,
enum ipset_adt adt, const struct ip_set_adt_opt *opt)
{
const struct ip_set_hash *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
union nf_inet_addr ip;
ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &ip.in6);
ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &ip.in6);
ip6_netmask(&ip, h->netmask);
if (ipv6_addr_any(&ip.in6))
return -EINVAL;
return adtfn(set, &ip, h->timeout, flags);
return adtfn(set, &ip, opt_timeout(opt, h), opt->cmdflags);
}
static const struct nla_policy hash_ip6_adt_policy[IPSET_ATTR_ADT_MAX + 1] = {
@@ -305,7 +319,7 @@ static const struct nla_policy hash_ip6_adt_policy[IPSET_ATTR_ADT_MAX + 1] = {
static int
hash_ip6_uadt(struct ip_set *set, struct nlattr *tb[],
enum ipset_adt adt, u32 *lineno, u32 flags)
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
{
const struct ip_set_hash *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
@@ -428,7 +442,8 @@ static struct ip_set_type hash_ip_type __read_mostly = {
.features = IPSET_TYPE_IP,
.dimension = IPSET_DIM_ONE,
.family = AF_UNSPEC,
.revision = 0,
.revision_min = 0,
.revision_max = 0,
.create = hash_ip_create,
.create_policy = {
[IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },

View File

@@ -124,31 +124,40 @@ nla_put_failure:
#define HOST_MASK 32
#include "ip_set_ahash.h"
static inline void
hash_ipport4_data_next(struct ip_set_hash *h,
const struct hash_ipport4_elem *d)
{
h->next.ip = ntohl(d->ip);
h->next.port = ntohs(d->port);
}
static int
hash_ipport4_kadt(struct ip_set *set, const struct sk_buff *skb,
enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
const struct xt_action_param *par,
enum ipset_adt adt, const struct ip_set_adt_opt *opt)
{
const struct ip_set_hash *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_ipport4_elem data = { };
if (!ip_set_get_ip4_port(skb, flags & IPSET_DIM_TWO_SRC,
if (!ip_set_get_ip4_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
&data.port, &data.proto))
return -EINVAL;
ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip);
ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip);
return adtfn(set, &data, h->timeout, flags);
return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags);
}
static int
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, bool retried)
{
const struct ip_set_hash *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_ipport4_elem data = { };
u32 ip, ip_to, p, port, port_to;
u32 ip, ip_to, p = 0, port, port_to;
u32 timeout = h->timeout;
bool with_ports = false;
int ret;
@@ -208,8 +217,7 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[],
if (cidr > 32)
return -IPSET_ERR_INVALID_CIDR;
ip &= ip_set_hostmask(cidr);
ip_to = ip | ~ip_set_hostmask(cidr);
ip_set_mask_from_to(ip, ip_to, cidr);
} else
ip_to = ip;
@@ -220,8 +228,11 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[],
swap(port, port_to);
}
for (; !before(ip_to, ip); ip++)
for (p = port; p <= port_to; p++) {
if (retried)
ip = h->next.ip;
for (; !before(ip_to, ip); ip++) {
p = retried && ip == h->next.ip ? h->next.port : port;
for (; p <= port_to; p++) {
data.ip = htonl(ip);
data.port = htons(p);
ret = adtfn(set, &data, timeout, flags);
@@ -231,6 +242,7 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[],
else
ret = 0;
}
}
return ret;
}
@@ -328,26 +340,34 @@ nla_put_failure:
#define HOST_MASK 128
#include "ip_set_ahash.h"
static inline void
hash_ipport6_data_next(struct ip_set_hash *h,
const struct hash_ipport6_elem *d)
{
h->next.port = ntohs(d->port);
}
static int
hash_ipport6_kadt(struct ip_set *set, const struct sk_buff *skb,
enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
const struct xt_action_param *par,
enum ipset_adt adt, const struct ip_set_adt_opt *opt)
{
const struct ip_set_hash *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_ipport6_elem data = { };
if (!ip_set_get_ip6_port(skb, flags & IPSET_DIM_TWO_SRC,
if (!ip_set_get_ip6_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
&data.port, &data.proto))
return -EINVAL;
ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
return adtfn(set, &data, h->timeout, flags);
return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags);
}
static int
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, bool retried)
{
const struct ip_set_hash *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
@@ -405,6 +425,8 @@ hash_ipport6_uadt(struct ip_set *set, struct nlattr *tb[],
if (port > port_to)
swap(port, port_to);
if (retried)
port = h->next.port;
for (; port <= port_to; port++) {
data.port = htons(port);
ret = adtfn(set, &data, timeout, flags);
@@ -491,7 +513,8 @@ static struct ip_set_type hash_ipport_type __read_mostly = {
.features = IPSET_TYPE_IP | IPSET_TYPE_PORT,
.dimension = IPSET_DIM_TWO,
.family = AF_UNSPEC,
.revision = 1,
.revision_min = 0,
.revision_max = 1, /* SCTP and UDPLITE support added */
.create = hash_ipport_create,
.create_policy = {
[IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },

View File

@@ -127,32 +127,41 @@ nla_put_failure:
#define HOST_MASK 32
#include "ip_set_ahash.h"
static inline void
hash_ipportip4_data_next(struct ip_set_hash *h,
const struct hash_ipportip4_elem *d)
{
h->next.ip = ntohl(d->ip);
h->next.port = ntohs(d->port);
}
static int
hash_ipportip4_kadt(struct ip_set *set, const struct sk_buff *skb,
enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
const struct xt_action_param *par,
enum ipset_adt adt, const struct ip_set_adt_opt *opt)
{
const struct ip_set_hash *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_ipportip4_elem data = { };
if (!ip_set_get_ip4_port(skb, flags & IPSET_DIM_TWO_SRC,
if (!ip_set_get_ip4_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
&data.port, &data.proto))
return -EINVAL;
ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip);
ip4addrptr(skb, flags & IPSET_DIM_THREE_SRC, &data.ip2);
ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip);
ip4addrptr(skb, opt->flags & IPSET_DIM_THREE_SRC, &data.ip2);
return adtfn(set, &data, h->timeout, flags);
return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags);
}
static int
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, bool retried)
{
const struct ip_set_hash *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_ipportip4_elem data = { };
u32 ip, ip_to, p, port, port_to;
u32 ip, ip_to, p = 0, port, port_to;
u32 timeout = h->timeout;
bool with_ports = false;
int ret;
@@ -216,8 +225,7 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[],
if (cidr > 32)
return -IPSET_ERR_INVALID_CIDR;
ip &= ip_set_hostmask(cidr);
ip_to = ip | ~ip_set_hostmask(cidr);
ip_set_mask_from_to(ip, ip_to, cidr);
} else
ip_to = ip;
@@ -228,8 +236,11 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[],
swap(port, port_to);
}
for (; !before(ip_to, ip); ip++)
for (p = port; p <= port_to; p++) {
if (retried)
ip = h->next.ip;
for (; !before(ip_to, ip); ip++) {
p = retried && ip == h->next.ip ? h->next.port : port;
for (; p <= port_to; p++) {
data.ip = htonl(ip);
data.port = htons(p);
ret = adtfn(set, &data, timeout, flags);
@@ -239,6 +250,7 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[],
else
ret = 0;
}
}
return ret;
}
@@ -341,27 +353,35 @@ nla_put_failure:
#define HOST_MASK 128
#include "ip_set_ahash.h"
static inline void
hash_ipportip6_data_next(struct ip_set_hash *h,
const struct hash_ipportip6_elem *d)
{
h->next.port = ntohs(d->port);
}
static int
hash_ipportip6_kadt(struct ip_set *set, const struct sk_buff *skb,
enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
const struct xt_action_param *par,
enum ipset_adt adt, const struct ip_set_adt_opt *opt)
{
const struct ip_set_hash *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_ipportip6_elem data = { };
if (!ip_set_get_ip6_port(skb, flags & IPSET_DIM_TWO_SRC,
if (!ip_set_get_ip6_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
&data.port, &data.proto))
return -EINVAL;
ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
ip6addrptr(skb, flags & IPSET_DIM_THREE_SRC, &data.ip2.in6);
ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
ip6addrptr(skb, opt->flags & IPSET_DIM_THREE_SRC, &data.ip2.in6);
return adtfn(set, &data, h->timeout, flags);
return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags);
}
static int
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, bool retried)
{
const struct ip_set_hash *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
@@ -423,6 +443,8 @@ hash_ipportip6_uadt(struct ip_set *set, struct nlattr *tb[],
if (port > port_to)
swap(port, port_to);
if (retried)
port = h->next.port;
for (; port <= port_to; port++) {
data.port = htons(port);
ret = adtfn(set, &data, timeout, flags);
@@ -509,7 +531,8 @@ static struct ip_set_type hash_ipportip_type __read_mostly = {
.features = IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_TYPE_IP2,
.dimension = IPSET_DIM_THREE,
.family = AF_UNSPEC,
.revision = 1,
.revision_min = 0,
.revision_max = 1, /* SCTP and UDPLITE support added */
.create = hash_ipportip_create,
.create_policy = {
[IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },

View File

@@ -140,39 +140,51 @@ nla_put_failure:
#define HOST_MASK 32
#include "ip_set_ahash.h"
static inline void
hash_ipportnet4_data_next(struct ip_set_hash *h,
const struct hash_ipportnet4_elem *d)
{
h->next.ip = ntohl(d->ip);
h->next.port = ntohs(d->port);
h->next.ip2 = ntohl(d->ip2);
}
static int
hash_ipportnet4_kadt(struct ip_set *set, const struct sk_buff *skb,
enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
const struct xt_action_param *par,
enum ipset_adt adt, const struct ip_set_adt_opt *opt)
{
const struct ip_set_hash *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_ipportnet4_elem data =
{ .cidr = h->nets[0].cidr || HOST_MASK };
struct hash_ipportnet4_elem data = {
.cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK
};
if (data.cidr == 0)
return -EINVAL;
if (adt == IPSET_TEST)
data.cidr = HOST_MASK;
if (!ip_set_get_ip4_port(skb, flags & IPSET_DIM_TWO_SRC,
if (!ip_set_get_ip4_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
&data.port, &data.proto))
return -EINVAL;
ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip);
ip4addrptr(skb, flags & IPSET_DIM_THREE_SRC, &data.ip2);
ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip);
ip4addrptr(skb, opt->flags & IPSET_DIM_THREE_SRC, &data.ip2);
data.ip2 &= ip_set_netmask(data.cidr);
return adtfn(set, &data, h->timeout, flags);
return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags);
}
static int
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, bool retried)
{
const struct ip_set_hash *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_ipportnet4_elem data = { .cidr = HOST_MASK };
u32 ip, ip_to, p, port, port_to;
u32 ip, ip_to, p = 0, port, port_to;
u32 ip2_from = 0, ip2_to, ip2_last, ip2;
u32 timeout = h->timeout;
bool with_ports = false;
int ret;
@@ -186,21 +198,19 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
if (tb[IPSET_ATTR_LINENO])
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
ret = ip_set_get_ipaddr4(tb[IPSET_ATTR_IP], &data.ip);
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip);
if (ret)
return ret;
ret = ip_set_get_ipaddr4(tb[IPSET_ATTR_IP2], &data.ip2);
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP2], &ip2_from);
if (ret)
return ret;
if (tb[IPSET_ATTR_CIDR2])
if (tb[IPSET_ATTR_CIDR2]) {
data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR2]);
if (!data.cidr)
return -IPSET_ERR_INVALID_CIDR;
data.ip2 &= ip_set_netmask(data.cidr);
if (!data.cidr)
return -IPSET_ERR_INVALID_CIDR;
}
if (tb[IPSET_ATTR_PORT])
data.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
@@ -225,14 +235,16 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
}
with_ports = with_ports && tb[IPSET_ATTR_PORT_TO];
if (adt == IPSET_TEST ||
!(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR] ||
tb[IPSET_ATTR_PORT_TO])) {
!(tb[IPSET_ATTR_CIDR] || tb[IPSET_ATTR_IP_TO] || with_ports ||
tb[IPSET_ATTR_IP2_TO])) {
data.ip = htonl(ip);
data.ip2 = htonl(ip2_from & ip_set_hostmask(data.cidr));
ret = adtfn(set, &data, timeout, flags);
return ip_set_eexist(ret, flags) ? 0 : ret;
}
ip = ntohl(data.ip);
if (tb[IPSET_ATTR_IP_TO]) {
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
if (ret)
@@ -244,29 +256,50 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
if (cidr > 32)
return -IPSET_ERR_INVALID_CIDR;
ip &= ip_set_hostmask(cidr);
ip_to = ip | ~ip_set_hostmask(cidr);
} else
ip_to = ip;
ip_set_mask_from_to(ip, ip_to, cidr);
}
port_to = port = ntohs(data.port);
if (with_ports && tb[IPSET_ATTR_PORT_TO]) {
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 (tb[IPSET_ATTR_IP2_TO]) {
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP2_TO], &ip2_to);
if (ret)
return ret;
if (ip2_from > ip2_to)
swap(ip2_from, ip2_to);
if (ip2_from + UINT_MAX == ip2_to)
return -IPSET_ERR_HASH_RANGE;
} else {
ip_set_mask_from_to(ip2_from, ip2_to, data.cidr);
}
for (; !before(ip_to, ip); ip++)
for (p = port; p <= port_to; p++) {
data.ip = htonl(ip);
if (retried)
ip = h->next.ip;
for (; !before(ip_to, ip); ip++) {
data.ip = htonl(ip);
p = retried && ip == h->next.ip ? h->next.port : port;
for (; p <= port_to; p++) {
data.port = htons(p);
ret = adtfn(set, &data, timeout, flags);
ip2 = retried && ip == h->next.ip && p == h->next.port
? h->next.ip2 : ip2_from;
while (!after(ip2, ip2_to)) {
data.ip2 = htonl(ip2);
ip2_last = ip_set_range_to_cidr(ip2, ip2_to,
&data.cidr);
ret = adtfn(set, &data, timeout, flags);
if (ret && !ip_set_eexist(ret, flags))
return ret;
else
ret = 0;
if (ret && !ip_set_eexist(ret, flags))
return ret;
else
ret = 0;
ip2 = ip2_last + 1;
}
}
}
return ret;
}
@@ -388,34 +421,43 @@ nla_put_failure:
#define HOST_MASK 128
#include "ip_set_ahash.h"
static inline void
hash_ipportnet6_data_next(struct ip_set_hash *h,
const struct hash_ipportnet6_elem *d)
{
h->next.port = ntohs(d->port);
}
static int
hash_ipportnet6_kadt(struct ip_set *set, const struct sk_buff *skb,
enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
const struct xt_action_param *par,
enum ipset_adt adt, const struct ip_set_adt_opt *opt)
{
const struct ip_set_hash *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_ipportnet6_elem data =
{ .cidr = h->nets[0].cidr || HOST_MASK };
struct hash_ipportnet6_elem data = {
.cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK
};
if (data.cidr == 0)
return -EINVAL;
if (adt == IPSET_TEST)
data.cidr = HOST_MASK;
if (!ip_set_get_ip6_port(skb, flags & IPSET_DIM_TWO_SRC,
if (!ip_set_get_ip6_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
&data.port, &data.proto))
return -EINVAL;
ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
ip6addrptr(skb, flags & IPSET_DIM_THREE_SRC, &data.ip2.in6);
ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
ip6addrptr(skb, opt->flags & IPSET_DIM_THREE_SRC, &data.ip2.in6);
ip6_netmask(&data.ip2, data.cidr);
return adtfn(set, &data, h->timeout, flags);
return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags);
}
static int
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, bool retried)
{
const struct ip_set_hash *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
@@ -432,6 +474,8 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[],
tb[IPSET_ATTR_IP_TO] ||
tb[IPSET_ATTR_CIDR]))
return -IPSET_ERR_PROTOCOL;
if (unlikely(tb[IPSET_ATTR_IP_TO]))
return -IPSET_ERR_HASH_RANGE_UNSUPPORTED;
if (tb[IPSET_ATTR_LINENO])
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
@@ -485,6 +529,8 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[],
if (port > port_to)
swap(port, port_to);
if (retried)
port = h->next.port;
for (; port <= port_to; port++) {
data.port = htons(port);
ret = adtfn(set, &data, timeout, flags);
@@ -574,7 +620,9 @@ static struct ip_set_type hash_ipportnet_type __read_mostly = {
.features = IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_TYPE_IP2,
.dimension = IPSET_DIM_THREE,
.family = AF_UNSPEC,
.revision = 1,
.revision_min = 0,
/* 1 SCTP and UDPLITE support added */
.revision_max = 2, /* Range as input support for IPv4 added */
.create = hash_ipportnet_create,
.create_policy = {
[IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
@@ -587,6 +635,7 @@ static struct ip_set_type hash_ipportnet_type __read_mostly = {
[IPSET_ATTR_IP] = { .type = NLA_NESTED },
[IPSET_ATTR_IP_TO] = { .type = NLA_NESTED },
[IPSET_ATTR_IP2] = { .type = NLA_NESTED },
[IPSET_ATTR_IP2_TO] = { .type = NLA_NESTED },
[IPSET_ATTR_PORT] = { .type = NLA_U16 },
[IPSET_ATTR_PORT_TO] = { .type = NLA_U16 },
[IPSET_ATTR_CIDR] = { .type = NLA_U8 },

View File

@@ -125,33 +125,44 @@ nla_put_failure:
#define HOST_MASK 32
#include "ip_set_ahash.h"
static inline void
hash_net4_data_next(struct ip_set_hash *h,
const struct hash_net4_elem *d)
{
h->next.ip = ntohl(d->ip);
}
static int
hash_net4_kadt(struct ip_set *set, const struct sk_buff *skb,
enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
const struct xt_action_param *par,
enum ipset_adt adt, const struct ip_set_adt_opt *opt)
{
const struct ip_set_hash *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_net4_elem data = { .cidr = h->nets[0].cidr || HOST_MASK };
struct hash_net4_elem data = {
.cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK
};
if (data.cidr == 0)
return -EINVAL;
if (adt == IPSET_TEST)
data.cidr = HOST_MASK;
ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip);
ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip);
data.ip &= ip_set_netmask(data.cidr);
return adtfn(set, &data, h->timeout, flags);
return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags);
}
static int
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, bool retried)
{
const struct ip_set_hash *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_net4_elem data = { .cidr = HOST_MASK };
u32 timeout = h->timeout;
u32 ip = 0, ip_to, last;
int ret;
if (unlikely(!tb[IPSET_ATTR_IP] ||
@@ -161,27 +172,51 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[],
if (tb[IPSET_ATTR_LINENO])
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
ret = ip_set_get_ipaddr4(tb[IPSET_ATTR_IP], &data.ip);
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip);
if (ret)
return ret;
if (tb[IPSET_ATTR_CIDR])
if (tb[IPSET_ATTR_CIDR]) {
data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
if (!data.cidr)
return -IPSET_ERR_INVALID_CIDR;
data.ip &= ip_set_netmask(data.cidr);
if (!data.cidr)
return -IPSET_ERR_INVALID_CIDR;
}
if (tb[IPSET_ATTR_TIMEOUT]) {
if (!with_timeout(h->timeout))
return -IPSET_ERR_TIMEOUT;
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
}
if (adt == IPSET_TEST || !tb[IPSET_ATTR_IP_TO]) {
data.ip = htonl(ip & ip_set_hostmask(data.cidr));
ret = adtfn(set, &data, timeout, flags);
return ip_set_eexist(ret, flags) ? 0 : ret;
}
ret = adtfn(set, &data, timeout, flags);
return ip_set_eexist(ret, flags) ? 0 : ret;
ip_to = 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_to < ip)
swap(ip, ip_to);
if (ip + UINT_MAX == ip_to)
return -IPSET_ERR_HASH_RANGE;
}
if (retried)
ip = h->next.ip;
while (!after(ip, ip_to)) {
data.ip = htonl(ip);
last = ip_set_range_to_cidr(ip, ip_to, &data.cidr);
ret = adtfn(set, &data, timeout, flags);
if (ret && !ip_set_eexist(ret, flags))
return ret;
else
ret = 0;
ip = last + 1;
}
return ret;
}
static bool
@@ -290,28 +325,37 @@ nla_put_failure:
#define HOST_MASK 128
#include "ip_set_ahash.h"
static inline void
hash_net6_data_next(struct ip_set_hash *h,
const struct hash_net6_elem *d)
{
}
static int
hash_net6_kadt(struct ip_set *set, const struct sk_buff *skb,
enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
const struct xt_action_param *par,
enum ipset_adt adt, const struct ip_set_adt_opt *opt)
{
const struct ip_set_hash *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_net6_elem data = { .cidr = h->nets[0].cidr || HOST_MASK };
struct hash_net6_elem data = {
.cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK
};
if (data.cidr == 0)
return -EINVAL;
if (adt == IPSET_TEST)
data.cidr = HOST_MASK;
ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
ip6_netmask(&data.ip, data.cidr);
return adtfn(set, &data, h->timeout, flags);
return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags);
}
static int
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, bool retried)
{
const struct ip_set_hash *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
@@ -322,6 +366,8 @@ hash_net6_uadt(struct ip_set *set, struct nlattr *tb[],
if (unlikely(!tb[IPSET_ATTR_IP] ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
return -IPSET_ERR_PROTOCOL;
if (unlikely(tb[IPSET_ATTR_IP_TO]))
return -IPSET_ERR_HASH_RANGE_UNSUPPORTED;
if (tb[IPSET_ATTR_LINENO])
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
@@ -425,7 +471,8 @@ static struct ip_set_type hash_net_type __read_mostly = {
.features = IPSET_TYPE_IP,
.dimension = IPSET_DIM_ONE,
.family = AF_UNSPEC,
.revision = 0,
.revision_min = 0,
.revision_max = 1, /* Range as input support for IPv4 added */
.create = hash_net_create,
.create_policy = {
[IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
@@ -436,6 +483,7 @@ static struct ip_set_type hash_net_type __read_mostly = {
},
.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 },
},

View File

@@ -137,38 +137,48 @@ nla_put_failure:
#define HOST_MASK 32
#include "ip_set_ahash.h"
static inline void
hash_netport4_data_next(struct ip_set_hash *h,
const struct hash_netport4_elem *d)
{
h->next.ip = ntohl(d->ip);
h->next.port = ntohs(d->port);
}
static int
hash_netport4_kadt(struct ip_set *set, const struct sk_buff *skb,
enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
const struct xt_action_param *par,
enum ipset_adt adt, const struct ip_set_adt_opt *opt)
{
const struct ip_set_hash *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_netport4_elem data = {
.cidr = h->nets[0].cidr || HOST_MASK };
.cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK
};
if (data.cidr == 0)
return -EINVAL;
if (adt == IPSET_TEST)
data.cidr = HOST_MASK;
if (!ip_set_get_ip4_port(skb, flags & IPSET_DIM_TWO_SRC,
if (!ip_set_get_ip4_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
&data.port, &data.proto))
return -EINVAL;
ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip);
ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip);
data.ip &= ip_set_netmask(data.cidr);
return adtfn(set, &data, h->timeout, flags);
return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags);
}
static int
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, bool retried)
{
const struct ip_set_hash *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_netport4_elem data = { .cidr = HOST_MASK };
u32 port, port_to;
u32 port, port_to, p = 0, ip = 0, ip_to, last;
u32 timeout = h->timeout;
bool with_ports = false;
int ret;
@@ -182,15 +192,15 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],
if (tb[IPSET_ATTR_LINENO])
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
ret = ip_set_get_ipaddr4(tb[IPSET_ATTR_IP], &data.ip);
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip);
if (ret)
return ret;
if (tb[IPSET_ATTR_CIDR])
if (tb[IPSET_ATTR_CIDR]) {
data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
if (!data.cidr)
return -IPSET_ERR_INVALID_CIDR;
data.ip &= ip_set_netmask(data.cidr);
if (!data.cidr)
return -IPSET_ERR_INVALID_CIDR;
}
if (tb[IPSET_ATTR_PORT])
data.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
@@ -215,24 +225,47 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
}
if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) {
with_ports = with_ports && tb[IPSET_ATTR_PORT_TO];
if (adt == IPSET_TEST || !(with_ports || tb[IPSET_ATTR_IP_TO])) {
data.ip = htonl(ip & ip_set_hostmask(data.cidr));
ret = adtfn(set, &data, timeout, flags);
return ip_set_eexist(ret, flags) ? 0 : ret;
}
port = ntohs(data.port);
port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
if (port > port_to)
swap(port, port_to);
for (; port <= port_to; port++) {
data.port = htons(port);
ret = adtfn(set, &data, timeout, flags);
if (ret && !ip_set_eexist(ret, flags))
port = port_to = ntohs(data.port);
if (tb[IPSET_ATTR_PORT_TO]) {
port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
if (port_to < port)
swap(port, port_to);
}
if (tb[IPSET_ATTR_IP_TO]) {
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
if (ret)
return ret;
else
ret = 0;
if (ip_to < ip)
swap(ip, ip_to);
if (ip + UINT_MAX == ip_to)
return -IPSET_ERR_HASH_RANGE;
} else {
ip_set_mask_from_to(ip, ip_to, data.cidr);
}
if (retried)
ip = h->next.ip;
while (!after(ip, ip_to)) {
data.ip = htonl(ip);
last = ip_set_range_to_cidr(ip, ip_to, &data.cidr);
p = retried && ip == h->next.ip ? h->next.port : port;
for (; p <= port_to; p++) {
data.port = htons(p);
ret = adtfn(set, &data, timeout, flags);
if (ret && !ip_set_eexist(ret, flags))
return ret;
else
ret = 0;
}
ip = last + 1;
}
return ret;
}
@@ -350,33 +383,42 @@ nla_put_failure:
#define HOST_MASK 128
#include "ip_set_ahash.h"
static inline void
hash_netport6_data_next(struct ip_set_hash *h,
const struct hash_netport6_elem *d)
{
h->next.port = ntohs(d->port);
}
static int
hash_netport6_kadt(struct ip_set *set, const struct sk_buff *skb,
enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
const struct xt_action_param *par,
enum ipset_adt adt, const struct ip_set_adt_opt *opt)
{
const struct ip_set_hash *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_netport6_elem data = {
.cidr = h->nets[0].cidr || HOST_MASK };
.cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK
};
if (data.cidr == 0)
return -EINVAL;
if (adt == IPSET_TEST)
data.cidr = HOST_MASK;
if (!ip_set_get_ip6_port(skb, flags & IPSET_DIM_TWO_SRC,
if (!ip_set_get_ip6_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
&data.port, &data.proto))
return -EINVAL;
ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
ip6_netmask(&data.ip, data.cidr);
return adtfn(set, &data, h->timeout, flags);
return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags);
}
static int
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, bool retried)
{
const struct ip_set_hash *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
@@ -391,6 +433,8 @@ hash_netport6_uadt(struct ip_set *set, struct nlattr *tb[],
!ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
return -IPSET_ERR_PROTOCOL;
if (unlikely(tb[IPSET_ATTR_IP_TO]))
return -IPSET_ERR_HASH_RANGE_UNSUPPORTED;
if (tb[IPSET_ATTR_LINENO])
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
@@ -438,6 +482,8 @@ hash_netport6_uadt(struct ip_set *set, struct nlattr *tb[],
if (port > port_to)
swap(port, port_to);
if (retried)
port = h->next.port;
for (; port <= port_to; port++) {
data.port = htons(port);
ret = adtfn(set, &data, timeout, flags);
@@ -526,7 +572,9 @@ static struct ip_set_type hash_netport_type __read_mostly = {
.features = IPSET_TYPE_IP | IPSET_TYPE_PORT,
.dimension = IPSET_DIM_TWO,
.family = AF_UNSPEC,
.revision = 1,
.revision_min = 0,
/* 1 SCTP and UDPLITE support added */
.revision_max = 2, /* Range as input support for IPv4 added */
.create = hash_netport_create,
.create_policy = {
[IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
@@ -538,6 +586,7 @@ static struct ip_set_type hash_netport_type __read_mostly = {
},
.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_PROTO] = { .type = NLA_U8 },

View File

@@ -72,7 +72,8 @@ list_set_expired(const struct list_set *map, u32 id)
static int
list_set_kadt(struct ip_set *set, const struct sk_buff *skb,
enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
const struct xt_action_param *par,
enum ipset_adt adt, const struct ip_set_adt_opt *opt)
{
struct list_set *map = set->data;
struct set_elem *elem;
@@ -87,17 +88,17 @@ list_set_kadt(struct ip_set *set, const struct sk_buff *skb,
continue;
switch (adt) {
case IPSET_TEST:
ret = ip_set_test(elem->id, skb, pf, dim, flags);
ret = ip_set_test(elem->id, skb, par, opt);
if (ret > 0)
return ret;
break;
case IPSET_ADD:
ret = ip_set_add(elem->id, skb, pf, dim, flags);
ret = ip_set_add(elem->id, skb, par, opt);
if (ret == 0)
return ret;
break;
case IPSET_DEL:
ret = ip_set_del(elem->id, skb, pf, dim, flags);
ret = ip_set_del(elem->id, skb, par, opt);
if (ret == 0)
return ret;
break;
@@ -218,7 +219,7 @@ cleanup_entries(struct list_set *map)
static int
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, bool retried)
{
struct list_set *map = set->data;
bool with_timeout = with_timeout(map->timeout);
@@ -575,7 +576,8 @@ static struct ip_set_type list_set_type __read_mostly = {
.features = IPSET_TYPE_NAME | IPSET_DUMP_LAST,
.dimension = IPSET_DIM_ONE,
.family = AF_UNSPEC,
.revision = 0,
.revision_min = 0,
.revision_max = 0,
.create = list_set_create,
.create_policy = {
[IPSET_ATTR_SIZE] = { .type = NLA_U32 },

View File

@@ -22,6 +22,9 @@
#define with_timeout(timeout) ((timeout) != IPSET_NO_TIMEOUT)
#define opt_timeout(opt, map) \
(with_timeout((opt)->timeout) ? (opt)->timeout : (map)->timeout)
static inline unsigned int
ip_set_timeout_uget(struct nlattr *tb)
{
@@ -45,7 +48,7 @@ ip_set_timeout_test(unsigned long timeout)
{
return timeout != IPSET_ELEM_UNSET &&
(timeout == IPSET_ELEM_PERMANENT ||
time_after(timeout, jiffies));
time_is_after_jiffies(timeout));
}
static inline bool
@@ -53,7 +56,7 @@ ip_set_timeout_expired(unsigned long timeout)
{
return timeout != IPSET_ELEM_UNSET &&
timeout != IPSET_ELEM_PERMANENT &&
time_before(timeout, jiffies);
time_is_before_jiffies(timeout);
}
static inline unsigned long
@@ -64,7 +67,7 @@ ip_set_timeout_set(u32 timeout)
if (!timeout)
return IPSET_ELEM_PERMANENT;
t = timeout * HZ + jiffies;
t = msecs_to_jiffies(timeout * 1000) + jiffies;
if (t == IPSET_ELEM_UNSET || t == IPSET_ELEM_PERMANENT)
/* Bingo! */
t++;
@@ -75,7 +78,8 @@ ip_set_timeout_set(u32 timeout)
static inline u32
ip_set_timeout_get(unsigned long timeout)
{
return timeout == IPSET_ELEM_PERMANENT ? 0 : (timeout - jiffies)/HZ;
return timeout == IPSET_ELEM_PERMANENT ? 0 :
jiffies_to_msecs(timeout - jiffies)/1000;
}
#else
@@ -89,14 +93,14 @@ static inline bool
ip_set_timeout_test(unsigned long timeout)
{
return timeout == IPSET_ELEM_PERMANENT ||
time_after(timeout, jiffies);
time_is_after_jiffies(timeout);
}
static inline bool
ip_set_timeout_expired(unsigned long timeout)
{
return timeout != IPSET_ELEM_PERMANENT &&
time_before(timeout, jiffies);
time_is_before_jiffies(timeout);
}
static inline unsigned long
@@ -107,7 +111,7 @@ ip_set_timeout_set(u32 timeout)
if (!timeout)
return IPSET_ELEM_PERMANENT;
t = timeout * HZ + jiffies;
t = msecs_to_jiffies(timeout * 1000) + jiffies;
if (t == IPSET_ELEM_PERMANENT)
/* Bingo! :-) */
t++;
@@ -118,7 +122,8 @@ ip_set_timeout_set(u32 timeout)
static inline u32
ip_set_timeout_get(unsigned long timeout)
{
return timeout == IPSET_ELEM_PERMANENT ? 0 : (timeout - jiffies)/HZ;
return timeout == IPSET_ELEM_PERMANENT ? 0 :
jiffies_to_msecs(timeout - jiffies)/1000;
}
#endif /* ! IP_SET_BITMAP_TIMEOUT */

View File

@@ -66,6 +66,7 @@ struct ipset_data {
/* ADT/LIST/SAVE */
struct {
union nf_inet_addr ip2;
union nf_inet_addr ip2_to;
uint8_t cidr2;
uint8_t proto;
char ether[ETH_ALEN];
@@ -289,6 +290,11 @@ ipset_data_set(struct ipset_data *data, enum ipset_opt opt, const void *value)
return -1;
copy_addr(data->family, &data->adt.ip2, value);
break;
case IPSET_OPT_IP2_TO:
if (!(data->family == AF_INET || data->family == AF_INET6))
return -1;
copy_addr(data->family, &data->adt.ip2_to, value);
break;
case IPSET_OPT_CIDR2:
data->adt.cidr2 = *(const uint8_t *) value;
break;
@@ -401,6 +407,8 @@ ipset_data_get(const struct ipset_data *data, enum ipset_opt opt)
return data->adt.nameref;
case IPSET_OPT_IP2:
return &data->adt.ip2;
case IPSET_OPT_IP2_TO:
return &data->adt.ip2_to;
case IPSET_OPT_CIDR2:
return &data->adt.cidr2;
case IPSET_OPT_PROTO:
@@ -436,6 +444,7 @@ ipset_data_sizeof(enum ipset_opt opt, uint8_t family)
case IPSET_OPT_IP:
case IPSET_OPT_IP_TO:
case IPSET_OPT_IP2:
case IPSET_OPT_IP2_TO:
return family == AF_INET ? sizeof(uint32_t)
: sizeof(struct in6_addr);
case IPSET_OPT_PORT:

View File

@@ -0,0 +1,268 @@
/* Copyright 2011 Jozsef Kadlecsik (kadlec@blackhole.kfki.hu)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <arpa/inet.h> /* inet_ntop */
#include <libmnl/libmnl.h> /* libmnl backend */
struct ipset_attrname {
const char *name;
};
static const struct ipset_attrname cmdattr2name[] = {
[IPSET_ATTR_PROTOCOL] = { .name = "PROTOCOL" },
[IPSET_ATTR_SETNAME] = { .name = "SETNAME" },
[IPSET_ATTR_TYPENAME] = { .name = "TYPENAME" },
[IPSET_ATTR_REVISION] = { .name = "REVISION" },
[IPSET_ATTR_FAMILY] = { .name = "FAMILY" },
[IPSET_ATTR_FLAGS] = { .name = "FLAGS" },
[IPSET_ATTR_DATA] = { .name = "DATA" },
[IPSET_ATTR_ADT] = { .name = "ADT" },
[IPSET_ATTR_LINENO] = { .name = "LINENO" },
[IPSET_ATTR_PROTOCOL_MIN] = { .name = "PROTO_MIN" },
};
static const struct ipset_attrname createattr2name[] = {
[IPSET_ATTR_IP] = { .name = "IP" },
[IPSET_ATTR_IP_TO] = { .name = "IP_TO" },
[IPSET_ATTR_CIDR] = { .name = "CIDR" },
[IPSET_ATTR_PORT] = { .name = "PORT" },
[IPSET_ATTR_PORT_TO] = { .name = "PORT_TO" },
[IPSET_ATTR_TIMEOUT] = { .name = "TIMEOUT" },
[IPSET_ATTR_PROTO] = { .name = "PROTO" },
[IPSET_ATTR_CADT_FLAGS] = { .name = "CADT_FLAGS" },
[IPSET_ATTR_CADT_LINENO] = { .name = "CADT_LINENO" },
[IPSET_ATTR_GC] = { .name = "GC" },
[IPSET_ATTR_HASHSIZE] = { .name = "HASHSIZE" },
[IPSET_ATTR_MAXELEM] = { .name = "MAXELEM" },
[IPSET_ATTR_NETMASK] = { .name = "NETMASK" },
[IPSET_ATTR_PROBES] = { .name = "PROBES" },
[IPSET_ATTR_RESIZE] = { .name = "RESIZE" },
[IPSET_ATTR_SIZE] = { .name = "SIZE" },
[IPSET_ATTR_ELEMENTS] = { .name = "ELEMENTS" },
[IPSET_ATTR_REFERENCES] = { .name = "REFERENCES" },
[IPSET_ATTR_MEMSIZE] = { .name = "MEMSIZE" },
};
static const struct ipset_attrname adtattr2name[] = {
[IPSET_ATTR_IP] = { .name = "IP" },
[IPSET_ATTR_IP_TO] = { .name = "IP_TO" },
[IPSET_ATTR_CIDR] = { .name = "CIDR" },
[IPSET_ATTR_PORT] = { .name = "PORT" },
[IPSET_ATTR_PORT_TO] = { .name = "PORT_TO" },
[IPSET_ATTR_TIMEOUT] = { .name = "TIMEOUT" },
[IPSET_ATTR_PROTO] = { .name = "PROTO" },
[IPSET_ATTR_CADT_FLAGS] = { .name = "CADT_FLAGS" },
[IPSET_ATTR_CADT_LINENO] = { .name = "CADT_LINENO" },
[IPSET_ATTR_ETHER] = { .name = "ETHER" },
[IPSET_ATTR_NAME] = { .name = "NAME" },
[IPSET_ATTR_NAMEREF] = { .name = "NAMEREF" },
[IPSET_ATTR_IP2] = { .name = "IP2" },
[IPSET_ATTR_CIDR2] = { .name = "CIDR2" },
[IPSET_ATTR_IP2_TO] = { .name = "IP2_TO" },
};
static void
debug_cadt_attrs(int max, const struct ipset_attr_policy *policy,
const struct ipset_attrname attr2name[],
struct nlattr *nla[])
{
uint32_t v;
int i;
fprintf(stderr,"\t\t%s attributes:\n", policy == create_attrs ? "CREATE" : "ADT");
for (i = IPSET_ATTR_UNSPEC + 1; i <= max; i++) {
if (!nla[i])
continue;
switch (policy[i].type) {
case MNL_TYPE_U8:
v = * (uint8_t *) mnl_attr_get_payload(nla[i]);
fprintf(stderr, "\t\t%s: %u\n",
attr2name[i].name, v);
break;
case MNL_TYPE_U16:
v = * (uint16_t *) mnl_attr_get_payload(nla[i]);
fprintf(stderr, "\t\t%s: %u\n",
attr2name[i].name, ntohs(v));
break;
case MNL_TYPE_U32:
v = * (uint32_t *) mnl_attr_get_payload(nla[i]);
fprintf(stderr, "\t\t%s: %u\n",
attr2name[i].name, ntohl(v));
break;
case MNL_TYPE_NUL_STRING:
fprintf(stderr, "\t\t%s: %s\n",
attr2name[i].name,
(const char *) mnl_attr_get_payload(nla[i]));
break;
case MNL_TYPE_NESTED: {
struct nlattr *ipattr[IPSET_ATTR_IPADDR_MAX+1] = {};
char addr[INET6_ADDRSTRLEN];
void *d;
if (mnl_attr_parse_nested(nla[i], ipaddr_attr_cb, ipattr) < 0) {
fprintf(stderr, "\t\tIPADDR: cannot validate and parse attributes\n");
continue;
}
if (ipattr[IPSET_ATTR_IPADDR_IPV4]) {
d = mnl_attr_get_payload(ipattr[IPSET_ATTR_IPADDR_IPV4]);
inet_ntop(AF_INET, d, addr, INET6_ADDRSTRLEN);
fprintf(stderr, "\t\t%s: %s\n",
attr2name[i].name, addr);
} else if (ipattr[IPSET_ATTR_IPADDR_IPV6]) {
d = mnl_attr_get_payload(ipattr[IPSET_ATTR_IPADDR_IPV6]);
inet_ntop(AF_INET6, d, addr, INET6_ADDRSTRLEN);
fprintf(stderr, "\t\t%s: %s\n",
attr2name[i].name, addr);
}
break;
}
default:
fprintf(stderr, "\t\t%s: unresolved!\n",
attr2name[i].name);
}
}
}
static void
debug_cmd_attrs(int cmd, struct nlattr *nla[])
{
struct nlattr *adt[IPSET_ATTR_ADT_MAX+1] = {};
struct nlattr *cattr[IPSET_ATTR_CREATE_MAX+1] = {};
uint32_t v;
int i;
fprintf(stderr,"\tCommand attributes:\n");
for (i = IPSET_ATTR_UNSPEC + 1; i <= IPSET_ATTR_CMD_MAX; i++) {
if (!nla[i])
continue;
switch (cmd_attrs[i].type) {
case MNL_TYPE_U8:
v = * (uint8_t *) mnl_attr_get_payload(nla[i]);
fprintf(stderr, "\t%s: %u\n",
cmdattr2name[i].name, v);
break;
case MNL_TYPE_U16:
v = * (uint16_t *) mnl_attr_get_payload(nla[i]);
fprintf(stderr, "\t%s: %u\n",
cmdattr2name[i].name, ntohs(v));
break;
case MNL_TYPE_U32:
v = * (uint32_t *) mnl_attr_get_payload(nla[i]);
fprintf(stderr, "\t%s: %u\n",
cmdattr2name[i].name, ntohl(v));
break;
case MNL_TYPE_NUL_STRING:
fprintf(stderr, "\t%s: %s\n",
cmdattr2name[i].name,
(const char *) mnl_attr_get_payload(nla[i]));
break;
case MNL_TYPE_NESTED:
if (i == IPSET_ATTR_DATA) {
switch (cmd) {
case IPSET_CMD_ADD:
case IPSET_CMD_DEL:
case IPSET_CMD_TEST:
if (mnl_attr_parse_nested(nla[i], adt_attr_cb, adt) < 0) {
fprintf(stderr, "\tADT: cannot validate and parse attributes\n");
continue;
}
debug_cadt_attrs(IPSET_ATTR_ADT_MAX,
adt_attrs,
adtattr2name,
adt);
break;
default:
if (mnl_attr_parse_nested(nla[i], create_attr_cb, cattr) < 0) {
fprintf(stderr, "\tCREATE: cannot validate and parse attributes\n");
continue;
}
debug_cadt_attrs(IPSET_ATTR_CREATE_MAX,
create_attrs,
createattr2name,
cattr);
}
} else {
struct nlattr *tb;
mnl_attr_for_each_nested(tb, nla[i]) {
memset(adt, 0, sizeof(adt));
if (mnl_attr_parse_nested(tb, adt_attr_cb, adt) < 0) {
fprintf(stderr, "\tADT: cannot validate and parse attributes\n");
continue;
}
debug_cadt_attrs(IPSET_ATTR_ADT_MAX,
adt_attrs,
adtattr2name,
adt);
}
}
break;
default:
fprintf(stderr, "\t%s: unresolved!\n",
cmdattr2name[i].name);
}
}
}
void
ipset_debug_msg(const char *dir, void *buffer, int len)
{
const struct nlmsghdr *nlh = buffer;
struct nlattr *nla[IPSET_ATTR_CMD_MAX+1] = {};
int cmd, nfmsglen = MNL_ALIGN(sizeof(struct nfgenmsg));
debug = 0;
while (mnl_nlmsg_ok(nlh, len)) {
switch (nlh->nlmsg_type) {
case NLMSG_NOOP:
case NLMSG_DONE:
case NLMSG_OVERRUN:
fprintf(stderr, "Message header: %s msg %s\n"
"\tlen %d\n"
"\tseq %u\n",
dir,
nlh->nlmsg_type == NLMSG_NOOP ? "NOOP" :
nlh->nlmsg_type == NLMSG_DONE ? "DONE" : "OVERRUN",
len, nlh->nlmsg_seq);
goto next_msg;
case NLMSG_ERROR: {
const struct nlmsgerr *err = mnl_nlmsg_get_payload(nlh);
fprintf(stderr, "Message header: %s msg ERROR\n"
"\tlen %d\n"
"\terrcode %d\n"
"\tseq %u\n",
dir, len, err->error, nlh->nlmsg_seq);
goto next_msg;
}
default:
;
}
cmd = ipset_get_nlmsg_type(nlh);
fprintf(stderr, "Message header: %s cmd %s (%d)\n"
"\tlen %d\n"
"\tflag %s\n"
"\tseq %u\n",
dir,
cmd <= IPSET_CMD_NONE ? "NONE!" :
cmd >= IPSET_CMD_MAX ? "MAX!" : cmd2name[cmd], cmd,
len,
!(nlh->nlmsg_flags & NLM_F_EXCL) ? "EXIST" : "none",
nlh->nlmsg_seq);
if (cmd <= IPSET_CMD_NONE || cmd >= IPSET_CMD_MAX)
goto next_msg;
memset(nla, 0, sizeof(nla));
if (mnl_attr_parse(nlh, nfmsglen, cmd_attr_cb, nla) < MNL_CB_STOP) {
fprintf(stderr, "\tcannot validate and parse attributes\n");
goto next_msg;
}
debug_cmd_attrs(cmd, nla);
next_msg:
nlh = mnl_nlmsg_next(nlh, &len);
}
debug = 1;
}

View File

@@ -83,7 +83,6 @@ ipset_mnl_fill_hdr(struct ipset_handle *handle, enum ipset_cmd cmd,
nlh->nlmsg_flags = NLM_F_REQUEST;
if (cmdflags[cmd-1] & NLM_F_ACK)
nlh->nlmsg_flags |= NLM_F_ACK;
nlh->nlmsg_seq = ++handle->seq;
ghdr = mnl_nlmsg_put_extra_header(nlh, sizeof(struct genlmsghdr));
ghdr->cmd = cmd;
@@ -102,19 +101,24 @@ ipset_mnl_query(struct ipset_handle *handle, void *buffer, size_t len)
assert(handle);
assert(buffer);
nlh->nlmsg_seq = ++handle->seq;
#ifdef IPSET_DEBUG
ipset_debug_msg("sent", nlh, nlh->nlmsg_len);
#endif
if (mnl_socket_sendto(handle->h, nlh, nlh->nlmsg_len) < 0)
return -ECOMM;
D("message sent");
ret = mnl_socket_recvfrom(handle->h, buffer, len);
D("message received, ret: %d", ret);
#ifdef IPSET_DEBUG
ipset_debug_msg("received", buffer, ret);
#endif
while (ret > 0) {
ret = mnl_cb_run2(buffer, ret,
handle->seq, handle->portid,
handle->cb_ctl[NLMSG_MIN_TYPE],
handle->data,
handle->cb_ctl, NLMSG_MIN_TYPE);
D("nfln_cb_run2, ret: %d", ret);
D("nfln_cb_run2, ret: %d, errno %d", ret, errno);
if (ret <= 0)
break;
ret = mnl_socket_recvfrom(handle->h, buffer, len);

View File

@@ -667,8 +667,15 @@ parse_ipaddr(struct ipset_session *session,
char *saved = strdup(str);
char *a, *tmp = saved;
struct addrinfo *info;
enum ipset_opt copt = opt == IPSET_OPT_IP ? IPSET_OPT_CIDR
: IPSET_OPT_CIDR2;
enum ipset_opt copt, opt2;
if (opt == IPSET_OPT_IP) {
copt = IPSET_OPT_CIDR;
opt2 = IPSET_OPT_IP_TO;
} else {
copt = IPSET_OPT_CIDR2;
opt2 = IPSET_OPT_IP2_TO;
}
if (tmp == NULL)
return ipset_err(session,
@@ -691,7 +698,7 @@ parse_ipaddr(struct ipset_session *session,
|| !range)
goto out;
freeaddrinfo(info);
aerr = get_addrinfo(session, IPSET_OPT_IP_TO, a, &info, family);
aerr = get_addrinfo(session, opt2, a, &info, family);
out:
if (aerr != EINVAL)
@@ -973,6 +980,46 @@ ipset_parse_ip4_single6(struct ipset_session *session,
}
/**
* ipset_parse_ip4_net6 - parse IPv4|IPv6 address or address/cidr pattern
* @session: session structure
* @opt: option kind of the data
* @str: string to parse
*
* Parse string as an IPv4|IPv6 address or address/cidr pattern. For IPv4,
* address range is valid too.
* If family is not set yet in the data blob, INET is assumed.
* The values are stored in the data blob of the session.
*
* FIXME: if the hostname resolves to multiple addresses,
* the first one is used only.
*
* Returns 0 on success or a negative error code.
*/
int
ipset_parse_ip4_net6(struct ipset_session *session,
enum ipset_opt opt, const char *str)
{
struct ipset_data *data;
uint8_t family;
assert(session);
assert(opt == IPSET_OPT_IP || opt == IPSET_OPT_IP2);
assert(str);
data = ipset_session_data(session);
family = ipset_data_family(data);
if (family == AF_UNSPEC) {
family = AF_INET;
ipset_data_set(data, IPSET_OPT_FAMILY, &family);
}
return family == AF_INET ? parse_ip(session, opt, str, IPADDR_ANY)
: ipset_parse_ipnet(session, opt, str);
}
/**
* ipset_parse_iptimeout - parse IPv4|IPv6 address and timeout
* @session: session structure

View File

@@ -37,6 +37,7 @@ struct ipset_session {
/* Command state */
enum ipset_cmd cmd; /* Current command */
uint32_t lineno; /* Current lineno in restore mode */
uint32_t printed_set; /* Printed sets so far */
char saved_setname[IPSET_MAXNAMELEN]; /* Saved setname */
const struct ipset_type *saved_type; /* Saved type */
struct nlattr *nested[IPSET_NEST_MAX]; /* Pointer to nest levels */
@@ -138,6 +139,8 @@ ipset_envopt_parse(struct ipset_session *session, int opt,
case IPSET_ENV_QUIET:
case IPSET_ENV_RESOLVE:
case IPSET_ENV_EXIST:
case IPSET_ENV_LIST_SETNAME:
case IPSET_ENV_LIST_HEADER:
session->envopts |= opt;
return 0;
default:
@@ -468,6 +471,10 @@ static const struct ipset_attr_policy adt_attrs[] = {
.type = MNL_TYPE_U8,
.opt = IPSET_OPT_CIDR2,
},
[IPSET_ATTR_IP2_TO] = {
.type = MNL_TYPE_NESTED,
.opt = IPSET_OPT_IP2_TO,
},
};
static const struct ipset_attr_policy ipaddr_attrs[] = {
@@ -480,6 +487,10 @@ static const struct ipset_attr_policy ipaddr_attrs[] = {
},
};
#ifdef IPSET_DEBUG
static int debug = 1;
#endif
static int
generic_data_attr_cb(const struct nlattr *attr, void *data,
int attr_max, const struct ipset_attr_policy *policy)
@@ -487,14 +498,14 @@ generic_data_attr_cb(const struct nlattr *attr, void *data,
const struct nlattr **tb = data;
int type = mnl_attr_get_type(attr);
D("attr type: %u, len %u", type, attr->nla_len);
IF_D(debug, "attr type: %u, len %u", type, attr->nla_len);
if (mnl_attr_type_valid(attr, attr_max) < 0) {
D("attr type: %u INVALID", type);
IF_D(debug, "attr type: %u INVALID", type);
return MNL_CB_ERROR;
}
if (mnl_attr_validate(attr, policy[type].type) < 0) {
D("attr type: %u POLICY, attrlen %u", type,
mnl_attr_get_payload_len(attr));
IF_D(debug, "attr type: %u POLICY, attrlen %u", type,
mnl_attr_get_payload_len(attr));
return MNL_CB_ERROR;
}
if (policy[type].type == MNL_TYPE_NUL_STRING
@@ -829,8 +840,9 @@ list_create(struct ipset_session *session, struct nlattr *nla[])
type->name);
break;
case IPSET_LIST_PLAIN:
safe_snprintf(session, "Name: %s\n"
safe_snprintf(session, "%sName: %s\n"
"Type: %s\nHeader: ",
session->printed_set ? "\n" : "",
ipset_data_setname(data),
type->name);
break;
@@ -887,18 +899,24 @@ list_create(struct ipset_session *session, struct nlattr *nla[])
safe_dprintf(session, ipset_print_number, IPSET_OPT_MEMSIZE);
safe_snprintf(session, "\nReferences: ");
safe_dprintf(session, ipset_print_number, IPSET_OPT_REFERENCES);
safe_snprintf(session, "\nMembers:\n");
safe_snprintf(session,
session->envopts & IPSET_ENV_LIST_HEADER ?
"\n" : "\nMembers:\n");
break;
case IPSET_LIST_XML:
safe_snprintf(session, "</elements>\n <memsize>");
safe_snprintf(session, " <memsize>");
safe_dprintf(session, ipset_print_number, IPSET_OPT_MEMSIZE);
safe_snprintf(session, "</memsize>\n <references>");
safe_dprintf(session, ipset_print_number, IPSET_OPT_REFERENCES);
safe_snprintf(session, "</references>\n </header>\n <members>\n");
safe_snprintf(session,
session->envopts & IPSET_ENV_LIST_HEADER ?
"</references>\n </header>\n" :
"</references>\n </header>\n <members>\n");
break;
default:
break;
}
session->printed_set++;
return MNL_CB_OK;
}
@@ -910,16 +928,17 @@ print_set_done(struct ipset_session *session)
? "NONE" : session->saved_setname);
switch (session->mode) {
case IPSET_LIST_XML:
if (session->saved_setname[0] == '\0')
safe_snprintf(session, "\n");
else
if (session->envopts & IPSET_ENV_LIST_SETNAME)
break;
if (session->envopts & IPSET_ENV_LIST_HEADER) {
if (session->saved_setname[0] != '\0')
safe_snprintf(session, "</ipset>\n");
break;
}
if (session->saved_setname[0] != '\0')
safe_snprintf(session, " </members>\n</ipset>\n");
break;
case IPSET_LIST_SAVE:
/* No empty lines between the sets */
break;
default:
safe_snprintf(session, "\n");
break;
}
return call_outfn(session) ? MNL_CB_ERROR : MNL_CB_STOP;
@@ -931,8 +950,11 @@ callback_list(struct ipset_session *session, struct nlattr *nla[],
{
struct ipset_data *data = session->data;
if (setjmp(printf_failure))
if (setjmp(printf_failure)) {
session->saved_setname[0] = '\0';
session->printed_set = 0;
return MNL_CB_ERROR;
}
if (!nla[IPSET_ATTR_SETNAME])
FAILURE("Broken %s kernel message: missing setname!",
@@ -940,6 +962,17 @@ callback_list(struct ipset_session *session, struct nlattr *nla[],
ATTR2DATA(session, nla, IPSET_ATTR_SETNAME, cmd_attrs);
D("setname %s", ipset_data_setname(data));
if (session->envopts & IPSET_ENV_LIST_SETNAME &&
session->mode != IPSET_LIST_SAVE) {
if (session->mode == IPSET_LIST_XML)
safe_snprintf(session, "<ipset name=\"%s\"/>\n",
ipset_data_setname(data));
else
safe_snprintf(session, "%s\n",
ipset_data_setname(data));
return call_outfn(session) ? MNL_CB_ERROR : MNL_CB_OK;
}
if (STREQ(ipset_data_setname(data), session->saved_setname)) {
/* Header part already seen */
if (ipset_data_test(data, IPSET_OPT_TYPE)
@@ -1422,6 +1455,9 @@ rawdata2attr(struct ipset_session *session, struct nlmsghdr *nlh,
return 1;
switch (attr->type) {
case MNL_TYPE_NUL_STRING:
alen = strlen((const char *)d) + 1;
break;
case MNL_TYPE_U32: {
uint32_t value = htonl(*(const uint32_t *)d);
@@ -1497,7 +1533,7 @@ addattr_adt(struct ipset_session *session,
static int
build_send_private_msg(struct ipset_session *session, enum ipset_cmd cmd)
{
char buffer[PRIVATE_MSG_BUFLEN] __attribute__ ((aligned));
char buffer[PRIVATE_MSG_BUFLEN] __attribute__ ((aligned)) = {};
struct nlmsghdr *nlh = (void *)buffer;
struct ipset_data *data = session->data;
int len = PRIVATE_MSG_BUFLEN, ret;
@@ -1592,7 +1628,12 @@ build_msg(struct ipset_session *session, bool aggregate)
IPSET_ATTR_REVISION, cmd_attrs);
D("family: %u, type family %u",
ipset_data_family(data), type->family);
ADDATTR(session, nlh, data, IPSET_ATTR_FAMILY, AF_INET, cmd_attrs);
if (ipset_data_test(data, IPSET_OPT_FAMILY))
ADDATTR(session, nlh, data, IPSET_ATTR_FAMILY,
AF_INET, cmd_attrs);
else
/* bitmap:port and list:set types */
mnl_attr_put_u8(nlh, IPSET_ATTR_FAMILY, AF_UNSPEC);
/* Type-specific create attributes */
D("call open_nested");
@@ -1604,11 +1645,26 @@ build_msg(struct ipset_session *session, bool aggregate)
}
case IPSET_CMD_DESTROY:
case IPSET_CMD_FLUSH:
case IPSET_CMD_LIST:
case IPSET_CMD_SAVE:
if (ipset_data_test(data, IPSET_SETNAME))
ADDATTR_SETNAME(session, nlh, data);
break;
case IPSET_CMD_LIST: {
uint32_t flags = 0;
if (session->envopts & IPSET_ENV_LIST_SETNAME)
flags |= IPSET_FLAG_LIST_SETNAME;
if (session->envopts & IPSET_ENV_LIST_HEADER)
flags |= IPSET_FLAG_LIST_HEADER;
if (ipset_data_test(data, IPSET_SETNAME))
ADDATTR_SETNAME(session, nlh, data);
if (flags && session->mode != IPSET_LIST_SAVE) {
ipset_data_set(data, IPSET_OPT_FLAGS, &flags);
ADDATTR(session, nlh, data, IPSET_ATTR_FLAGS, AF_INET,
cmd_attrs);
}
break;
}
case IPSET_CMD_RENAME:
case IPSET_CMD_SWAP:
if (!ipset_data_test(data, IPSET_SETNAME))
@@ -1729,6 +1785,7 @@ ipset_commit(struct ipset_session *session)
/* Reset saved data and nested state */
session->saved_setname[0] = '\0';
session->printed_set = 0;
for (i = session->nestid - 1; i >= 0; i--)
session->nested[i] = NULL;
session->nestid = 0;
@@ -1926,3 +1983,7 @@ ipset_session_fini(struct ipset_session *session)
free(session);
return 0;
}
#ifdef IPSET_DEBUG
#include "debug.c"
#endif

View File

@@ -267,6 +267,19 @@ create_type_get(struct ipset_session *session)
kmax, tmin);
}
/* Disable unsupported revisions */
for (match = NULL, t = typelist; t != NULL; t = t->next) {
/* Skip revisions which are unsupported by the kernel */
if (t->kernel_check == IPSET_KERNEL_MISMATCH)
continue;
if (ipset_match_typename(typename, t)
&& MATCH_FAMILY(t, family)) {
if (t->revision < kmin || t->revision > kmax)
t->kernel_check = IPSET_KERNEL_MISMATCH;
else if (match == NULL)
match = t;
}
}
match->kernel_check = IPSET_KERNEL_OK;
found:
ipset_data_set(data, IPSET_OPT_TYPE, match);

View File

@@ -289,3 +289,24 @@ const union nf_inet_addr ip_set_hostmask_map[] = {
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF),
};
EXPORT_SYMBOL_GPL(ip_set_hostmask_map);
/* Find the largest network which matches the range from left, in host order. */
u32
ip_set_range_to_cidr(u32 from, u32 to, u8 *cidr)
{
u32 last;
u8 i;
for (i = 1; i < 32; i++) {
if ((from & ip_set_hostmask(i)) != from)
continue;
last = from | ~ip_set_hostmask(i);
if (!after(last, to)) {
*cidr = i;
return last;
}
}
*cidr = 32;
return from;
}
EXPORT_SYMBOL_GPL(ip_set_range_to_cidr);

View File

@@ -3,6 +3,7 @@
#include <asm/byteorder.h>
#include <linux/netfilter.h>
#include <net/tcp.h>
/* Prefixlen maps, by Jan Engelhardt */
extern const union nf_inet_addr ip_set_netmask_map[];
@@ -32,4 +33,12 @@ ip_set_hostmask6(u8 pfxlen)
return &ip_set_hostmask_map[pfxlen].ip6[0];
}
extern u32 ip_set_range_to_cidr(u32 from, u32 to, u8 *cidr);
#define ip_set_mask_from_to(from, to, cidr) \
do { \
from &= ip_set_hostmask(cidr); \
to = from | ~ip_set_hostmask(cidr); \
} while (0)
#endif /*_PFXLEN_H */

View File

@@ -1,89 +0,0 @@
#ifndef _IP_SET_SLIST_H
#define _IP_SET_SLIST_H
#include <linux/stddef.h>
#include <linux/prefetch.h>
#include <asm/system.h>
/*
* Single linked lists with a single pointer.
* Mostly useful for hash tables where the two pointer list head
* and list node is too wasteful.
*/
struct slist {
struct slist *next;
};
#define SLIST(name) struct slist name = { .next = NULL }
#define INIT_SLIST(ptr) ((ptr)->next = NULL)
#define slist_entry(ptr, type, member) container_of(ptr, type, member)
#define slist_for_each(pos, head) \
for (pos = (head)->next; pos && ({ prefetch(pos->next); 1; }); \
pos = pos->next)
#define slist_for_each_prev(prev, pos, head) \
for (prev = head, pos = (head)->next; \
pos && ({ prefetch(pos->next); 1; }); \
prev = pos, pos = pos->next)
#define slist_for_each_safe(pos, n, head) \
for (pos = (head)->next; pos && ({ n = pos->next; 1; }); \
pos = n)
/**
* slist_for_each_entry - iterate over list of given type
* @tpos: the type * to use as a loop cursor.
* @pos: the &struct slist to use as a loop cursor.
* @head: the head for your list.
* @member: the name of the slist within the struct.
*/
#define slist_for_each_entry(tpos, pos, head, member) \
for (pos = (head)->next; \
pos && ({ prefetch(pos->next); 1; }) && \
({ tpos = slist_entry(pos, typeof(*tpos), member); 1; });\
pos = pos->next)
/**
* slist_for_each_entry_continue - iterate over a hlist continuing
* after current point
* @tpos: the type * to use as a loop cursor.
* @pos: the &struct slist to use as a loop cursor.
* @member: the name of the slist within the struct.
*/
#define slist_for_each_entry_continue(tpos, pos, member) \
for (pos = (pos)->next; \
pos && ({ prefetch(pos->next); 1; }) && \
({ tpos = slist_entry(pos, typeof(*tpos), member); 1; });\
pos = pos->next)
/**
* slist_for_each_entry_from - iterate over a hlist continuing
* from current point
* @tpos: the type * to use as a loop cursor.
* @pos: the &struct slist to use as a loop cursor.
* @member: the name of the slist within the struct.
*/
#define slist_for_each_entry_from(tpos, pos, member) \
for (; pos && ({ prefetch(pos->next); 1; }) && \
({ tpos = slist_entry(pos, typeof(*tpos), member); 1; });\
pos = pos->next)
/**
* slist_for_each_entry_safe - iterate over list of given type safe against
* removal of list entry
* @tpos: the type * to use as a loop cursor.
* @pos: the &struct slist to use as a loop cursor.
* @n: another &struct slist to use as temporary storage
* @head: the head for your list.
* @member: the name of the slist within the struct.
*/
#define slist_for_each_entry_safe(tpos, pos, n, head, member) \
for (pos = (head)->next; \
pos && ({ n = pos->next; 1; }) && \
({ tpos = slist_entry(pos, typeof(*tpos), member); 1; });\
pos = n)
#endif /* _IP_SET_SLIST_H */

View File

@@ -113,6 +113,10 @@ static const struct ipset_errcode_table hash_errcode_table[] = {
"Invalid protocol specified" },
{ IPSET_ERR_MISSING_PROTO, 0,
"Protocol missing, but must be specified" },
{ IPSET_ERR_HASH_RANGE_UNSUPPORTED, 0,
"Range is not supported in the \"net\" component of the element" },
{ IPSET_ERR_HASH_RANGE, 0,
"Invalid range, covers the whole address space" },
{ },
};

View File

@@ -21,7 +21,7 @@ ipset \(em administration tool for IP sets
.PP
COMMANDS := { \fBcreate\fR | \fBadd\fR | \fBdel\fR | \fBtest\fR | \fBdestroy\fR | \fBlist\fR | \fBsave\fR | \fBrestore\fR | \fBflush\fR | \fBrename\fR | \fBswap\fR | \fBhelp\fR | \fBversion\fR | \fB\-\fR }
.PP
\fIOPTIONS\fR := { \fB\-exist\fR | \fB\-output\fR { \fBplain\fR | \fBsave\fR | \fBxml\fR } | \fB\-quiet\fR | \fB\-resolve\fR | \fB\-sorted\fR }
\fIOPTIONS\fR := { \fB\-exist\fR | \fB\-output\fR { \fBplain\fR | \fBsave\fR | \fBxml\fR } | \fB\-quiet\fR | \fB\-resolve\fR | \fB\-sorted\fR | \fB\-name\fR | \fB\-terse\fR }
.PP
\fBipset\fR \fBcreate\fR \fISETNAME\fR \fITYPENAME\fR [ \fICREATE\-OPTIONS\fR ]
.PP
@@ -109,7 +109,7 @@ Destroy the specified set or all the sets if none is given.
If the set has got reference(s), nothing is done and no set destroyed.
.TP
\fBlist\fP [ \fISETNAME\fP ]
\fBlist\fP [ \fISETNAME\fP ] [ \fIOPTIONS\fP ]
List the header data and the entries for the specified set, or for
all sets if none is given. The
\fB\-resolve\fP
@@ -120,8 +120,13 @@ type supports the operation). The option
\fB\-output\fR
can be used to control the format of the listing:
\fBplain\fR, \fBsave\fR or \fBxml\fR.
The default is
\fBplain\fR.
(The default is
\fBplain\fR.)
If the option
\fB\-name\fR
is specified, just the names of the existing sets are listed. If the option
\fB\-terse\fR
is specified, just the set names and headers are listed.
.TP
\fBsave\fP [ \fISETNAME\fP ]
Save the given set, or all sets if none is given
@@ -190,6 +195,13 @@ DNS lookups.
.TP
\fB\-s\fP, \fB\-sorted\fP
Sorted output. When listing sets entries are listed sorted. Not supported yet.
.TP
\fB\-n\fP, \fB\-name\fP
List just the names of the existing sets, i.e. suppress listing of set headers and members.
.TP
\fB\-t\fP, \fB\-terse\fP
List the set names and headers, i.e. suppress listing of set members.
.SH "SET TYPES"
A set type comprises of the storage method by which the data is stored and
the data type(s) which are stored in the set. Therefore the
@@ -202,7 +214,7 @@ command follows the syntax
where the current list of the methods are
\fBbitmap\fR, \fBhash\fR, and \fBlist\fR and the possible data types
are \fBip\fR, \fBmac\fR and \fBport\fR. The dimension of a set
are \fBip\fR, \fBnet\fR, \fBmac\fR and \fBport\fR. The dimension of a set
is equal to the number of data types in its type name.
When adding, deleting or testing entries in a set, the same comma separated
@@ -397,13 +409,16 @@ Network address with zero prefix size cannot be stored in this type of sets.
.PP
\fICREATE\-OPTIONS\fR := [ \fBfamily\fR { \fBinet\fR | \fBinet6\fR } ] | [ \fBhashsize\fR \fIvalue\fR ] [ \fBmaxelem\fR \fIvalue\fR ] [ \fBtimeout\fR \fIvalue\fR ]
.PP
\fIADD\-ENTRY\fR := \fIip\fR[/\fIcidr\fR]
\fIADD\-ENTRY\fR := \fInetaddr\fR
.PP
\fIADD\-OPTIONS\fR := [ \fBtimeout\fR \fIvalue\fR ]
.PP
\fIDEL\-ENTRY\fR := \fIip\fR[/\fIcidr\fR]
\fIDEL\-ENTRY\fR := \fInetaddr\fR
.PP
\fITEST\-ENTRY\fR := \fIip\fR[/\fIcidr\fR]
\fITEST\-ENTRY\fR := \fInetaddr\fR
.PP
where
\fInetaddr\fR := \fIip\fR[/\fIcidr\fR]
.PP
Optional \fBcreate\fR options:
.TP
@@ -419,6 +434,11 @@ correct value.
\fBmaxelem\fR \fIvalue\fR
The maximal number of elements which can be stored in the set, default 65536.
.PP
For the \fBinet\fR family one can add or delete multiple entries by specifying
a range, which is converted internally to network(s) equal to the range:
.PP
\fInetaddr\fR := { \fIip\fR[/\fIcidr\fR] | \fIfromaddr\fR\-\fItoaddr\fR }
.PP
When adding/deleting/testing entries, if the cidr prefix parameter is not specified,
then the host prefix value is assumed. When adding/deleting entries, the exact
element is added/deleted and overlapping elements are not checked by the kernel.
@@ -527,13 +547,16 @@ address with zero prefix size is not accepted either.
.PP
\fICREATE\-OPTIONS\fR := [ \fBfamily\fR { \fBinet\fR | \fBinet6\fR } ] | [ \fBhashsize\fR \fIvalue\fR ] [ \fBmaxelem\fR \fIvalue\fR ] [ \fBtimeout\fR \fIvalue\fR ]
.PP
\fIADD\-ENTRY\fR := \fIipaddr\fR[/\fIcidr\fR],[\fIproto\fR:]\fIport\fR
\fIADD\-ENTRY\fR := \fInetaddr\fR,[\fIproto\fR:]\fIport\fR
.PP
\fIADD\-OPTIONS\fR := [ \fBtimeout\fR \fIvalue\fR ]
.PP
\fIDEL\-ENTRY\fR := \fIipaddr\fR[/\fIcidr\fR],[\fIproto\fR:]\fIport\fR
\fIDEL\-ENTRY\fR := \fInetaddr\fR,[\fIproto\fR:]\fIport\fR
.PP
\fITEST\-ENTRY\fR := \fIipaddr\fR[/\fIcidr\fR],[\fIproto\fR:]\fIport\fR
\fITEST\-ENTRY\fR := \fInetaddr\fR,[\fIproto\fR:]\fIport\fR
.PP
where
\fInetaddr\fR := \fIip\fR[/\fIcidr\fR]
.PP
Optional \fBcreate\fR options:
.TP
@@ -549,7 +572,8 @@ correct value.
\fBmaxelem\fR \fIvalue\fR
The maximal number of elements which can be stored in the set, default 65536.
.PP
For the
For the \fInetaddr\fR part of the elements
see the description at the \fBhash:net\fR set type. For the
[\fIproto\fR:]\fIport\fR
part of the elements see the description at the
\fBhash:ip,port\fR set type.
@@ -633,18 +657,22 @@ address with zero prefix size cannot be stored either.
.PP
\fICREATE\-OPTIONS\fR := [ \fBfamily\fR { \fBinet\fR | \fBinet6\fR } ] | [ \fBhashsize\fR \fIvalue\fR ] [ \fBmaxelem\fR \fIvalue\fR ] [ \fBtimeout\fR \fIvalue\fR ]
.PP
\fIADD\-ENTRY\fR := \fIipaddr\fR,[\fIproto\fR:]\fIport\fR,\fIip\fR[/\fIcidr\fR]
\fIADD\-ENTRY\fR := \fIipaddr\fR,[\fIproto\fR:]\fIport\fR,\fInetaddr\fR
.PP
\fIADD\-OPTIONS\fR := [ \fBtimeout\fR \fIvalue\fR ]
.PP
\fIDEL\-ENTRY\fR := \fIipaddr\fR,[\fIproto\fR:]\fIport\fR,\fIip\fR[/\fIcidr\fR]
\fIDEL\-ENTRY\fR := \fIipaddr\fR,[\fIproto\fR:]\fIport\fR,\fInetaddr\fR
.PP
\fITEST\-ENTRY\fR := \fIipaddr\fR,[\fIproto\fR:]\fIport\fR,\fIip\fR[/\fIcidr\fR]
\fITEST\-ENTRY\fR := \fIipaddr\fR,[\fIproto\fR:]\fIport\fR,\fInetaddr\fR
.PP
For the first \fIipaddr\fR and
where
\fInetaddr\fR := \fIip\fR[/\fIcidr\fR]
.PP
For the \fIipaddr\fR and
[\fIproto\fR:]\fIport\fR
parts of the elements see the descriptions at the
\fBhash:ip,port\fR set type.
\fBhash:ip,port\fR set type. For the \fInetaddr\fR part of the elements
see the description at the \fBhash:net\fR set type.
.PP
Optional \fBcreate\fR options:
.TP

View File

@@ -39,10 +39,13 @@ extern struct ipset_type ipset_bitmap_ipmac0;
extern struct ipset_type ipset_bitmap_port0;
extern struct ipset_type ipset_hash_ip0;
extern struct ipset_type ipset_hash_net0;
extern struct ipset_type ipset_hash_netport0;
extern struct ipset_type ipset_hash_ipport0;
extern struct ipset_type ipset_hash_ipportip0;
extern struct ipset_type ipset_hash_ipportnet0;
extern struct ipset_type ipset_hash_net1;
extern struct ipset_type ipset_hash_netport1;
extern struct ipset_type ipset_hash_netport2;
extern struct ipset_type ipset_hash_ipport1;
extern struct ipset_type ipset_hash_ipportip1;
extern struct ipset_type ipset_hash_ipportnet1;
extern struct ipset_type ipset_hash_ipportnet2;
extern struct ipset_type ipset_list_set0;
enum exittype {
@@ -145,9 +148,9 @@ build_argv(char *buffer)
newargv[i] = NULL;
newargc = 1;
ptr = strtok(buffer, " \t\n");
ptr = strtok(buffer, " \t\r\n");
newargv[newargc++] = ptr;
while ((ptr = strtok(NULL, " \t\n")) != NULL) {
while ((ptr = strtok(NULL, " \t\r\n")) != NULL) {
if ((newargc + 1) < (int)(sizeof(newargv)/sizeof(char *)))
newargv[newargc++] = ptr;
else {
@@ -181,7 +184,7 @@ restore(char *argv0)
c++;
if (c[0] == '\0' || c[0] == '#')
continue;
else if (strcmp(c, "COMMIT\n") == 0) {
else if (STREQ(c, "COMMIT\n") || STREQ(c, "COMMIT\r\n")) {
ret = ipset_commit(session);
if (ret < 0)
handle_error();
@@ -715,16 +718,21 @@ parse_commandline(int argc, char *argv[])
int
main(int argc, char *argv[])
{
int ret;
/* Register types */
ipset_type_add(&ipset_bitmap_ip0);
ipset_type_add(&ipset_bitmap_ipmac0);
ipset_type_add(&ipset_bitmap_port0);
ipset_type_add(&ipset_hash_ip0);
ipset_type_add(&ipset_hash_net0);
ipset_type_add(&ipset_hash_netport0);
ipset_type_add(&ipset_hash_ipport0);
ipset_type_add(&ipset_hash_ipportip0);
ipset_type_add(&ipset_hash_ipportnet0);
ipset_type_add(&ipset_hash_net1);
ipset_type_add(&ipset_hash_netport1);
ipset_type_add(&ipset_hash_netport2);
ipset_type_add(&ipset_hash_ipport1);
ipset_type_add(&ipset_hash_ipportip1);
ipset_type_add(&ipset_hash_ipportnet1);
ipset_type_add(&ipset_hash_ipportnet2);
ipset_type_add(&ipset_list_set0);
/* Initialize session */
@@ -733,5 +741,9 @@ main(int argc, char *argv[])
return exit_error(OTHER_PROBLEM,
"Cannot initialize ipset session, aborting.");
return parse_commandline(argc, argv);
ret = parse_commandline(argc, argv);
ipset_session_fini(session);
return ret;
}

View File

@@ -81,7 +81,7 @@ static const char hash_ip_usage[] =
struct ipset_type ipset_hash_ip0 = {
.name = "hash:ip",
.alias = { "iphash", "iptree", "iptreemap", NULL },
.alias = { "iphash", NULL },
.revision = 0,
.family = AF_INET46,
.dimension = IPSET_DIM_ONE,
@@ -92,7 +92,6 @@ struct ipset_type ipset_hash_ip0 = {
.opt = IPSET_OPT_IP
},
},
.compat_parse_elem = ipset_parse_iptimeout,
.args = {
[IPSET_CREATE] = hash_ip_create_args,
[IPSET_ADD] = hash_ip_add_args,

View File

@@ -70,7 +70,7 @@ static const struct ipset_arg hash_ipport_add_args[] = {
{ },
};
static const char hash_ipport_usage[] =
static const char hash_ipport1_usage[] =
"create SETNAME hash:ip,port\n"
" [family inet|inet6]\n"
" [hashsize VALUE] [maxelem VALUE]\n"
@@ -85,7 +85,7 @@ static const char hash_ipport_usage[] =
" Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
" port range is supported both for IPv4 and IPv6.\n";
struct ipset_type ipset_hash_ipport0 = {
struct ipset_type ipset_hash_ipport1 = {
.name = "hash:ip,port",
.alias = { "ipporthash", NULL },
.revision = 1,
@@ -139,6 +139,6 @@ struct ipset_type ipset_hash_ipport0 = {
| IPSET_FLAG(IPSET_OPT_PROTO),
},
.usage = hash_ipport_usage,
.usage = hash_ipport1_usage,
.usagefn = ipset_port_usage,
};

View File

@@ -70,7 +70,7 @@ static const struct ipset_arg hash_ipportip_add_args[] = {
{ },
};
static const char hash_ipportip_usage[] =
static const char hash_ipportip1_usage[] =
"create SETNAME hash:ip,port,ip\n"
" [family inet|inet6]\n"
" [hashsize VALUE] [maxelem VALUE]\n"
@@ -85,7 +85,7 @@ static const char hash_ipportip_usage[] =
" Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
" port range is supported both for IPv4 and IPv6.\n";
struct ipset_type ipset_hash_ipportip0 = {
struct ipset_type ipset_hash_ipportip1 = {
.name = "hash:ip,port,ip",
.alias = { "ipportiphash", NULL },
.revision = 1,
@@ -150,6 +150,6 @@ struct ipset_type ipset_hash_ipportip0 = {
| IPSET_FLAG(IPSET_OPT_IP2),
},
.usage = hash_ipportip_usage,
.usage = hash_ipportip1_usage,
.usagefn = ipset_port_usage,
};

View File

@@ -70,7 +70,7 @@ static const struct ipset_arg hash_ipportnet_add_args[] = {
{ },
};
static const char hash_ipportnet_usage[] =
static const char hash_ipportnet1_usage[] =
"create SETNAME hash:ip,port,net\n"
" [family inet|inet6]\n"
" [hashsize VALUE] [maxelem VALUE]\n"
@@ -86,7 +86,7 @@ static const char hash_ipportnet_usage[] =
" Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
" port range is supported both for IPv4 and IPv6.\n";
struct ipset_type ipset_hash_ipportnet0 = {
struct ipset_type ipset_hash_ipportnet1 = {
.name = "hash:ip,port,net",
.alias = { "ipportnethash", NULL },
.revision = 1,
@@ -133,6 +133,7 @@ struct ipset_type ipset_hash_ipportnet0 = {
| IPSET_FLAG(IPSET_OPT_MAXELEM)
| IPSET_FLAG(IPSET_OPT_TIMEOUT),
[IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
| IPSET_FLAG(IPSET_OPT_CIDR)
| IPSET_FLAG(IPSET_OPT_IP_TO)
| IPSET_FLAG(IPSET_OPT_PORT)
| IPSET_FLAG(IPSET_OPT_PORT_TO)
@@ -141,6 +142,7 @@ struct ipset_type ipset_hash_ipportnet0 = {
| IPSET_FLAG(IPSET_OPT_CIDR2)
| IPSET_FLAG(IPSET_OPT_TIMEOUT),
[IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
| IPSET_FLAG(IPSET_OPT_CIDR)
| IPSET_FLAG(IPSET_OPT_IP_TO)
| IPSET_FLAG(IPSET_OPT_PORT)
| IPSET_FLAG(IPSET_OPT_PORT_TO)
@@ -154,6 +156,99 @@ struct ipset_type ipset_hash_ipportnet0 = {
| IPSET_FLAG(IPSET_OPT_CIDR2),
},
.usage = hash_ipportnet_usage,
.usage = hash_ipportnet1_usage,
.usagefn = ipset_port_usage,
};
static const char hash_ipportnet2_usage[] =
"create SETNAME hash:ip,port,net\n"
" [family inet|inet6]\n"
" [hashsize VALUE] [maxelem VALUE]\n"
" [timeout VALUE]\n"
"add SETNAME IP,PROTO:PORT,IP[/CIDR] [timeout VALUE]\n"
"del SETNAME IP,PROTO:PORT,IP[/CIDR]\n"
"test SETNAME IP,PROTO:PORT,IP[/CIDR]\n\n"
"where depending on the INET family\n"
" IP are valid IPv4 or IPv6 addresses (or hostnames),\n"
" CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
" Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
" in both IP components are supported for IPv4.\n"
" Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
" port range is supported both for IPv4 and IPv6.\n";
struct ipset_type ipset_hash_ipportnet2 = {
.name = "hash:ip,port,net",
.alias = { "ipportnethash", NULL },
.revision = 2,
.family = AF_INET46,
.dimension = IPSET_DIM_THREE,
.elem = {
[IPSET_DIM_ONE] = {
.parse = ipset_parse_ip4_single6,
.print = ipset_print_ip,
.opt = IPSET_OPT_IP
},
[IPSET_DIM_TWO] = {
.parse = ipset_parse_proto_port,
.print = ipset_print_proto_port,
.opt = IPSET_OPT_PORT
},
[IPSET_DIM_THREE] = {
.parse = ipset_parse_ip4_net6,
.print = ipset_print_ip,
.opt = IPSET_OPT_IP2
},
},
.args = {
[IPSET_CREATE] = hash_ipportnet_create_args,
[IPSET_ADD] = hash_ipportnet_add_args,
},
.mandatory = {
[IPSET_CREATE] = 0,
[IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
| IPSET_FLAG(IPSET_OPT_PORT)
| IPSET_FLAG(IPSET_OPT_PROTO)
| IPSET_FLAG(IPSET_OPT_IP2),
[IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
| IPSET_FLAG(IPSET_OPT_PORT)
| IPSET_FLAG(IPSET_OPT_PROTO)
| IPSET_FLAG(IPSET_OPT_IP2),
[IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
| IPSET_FLAG(IPSET_OPT_PORT)
| IPSET_FLAG(IPSET_OPT_PROTO)
| IPSET_FLAG(IPSET_OPT_IP2),
},
.full = {
[IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE)
| IPSET_FLAG(IPSET_OPT_MAXELEM)
| IPSET_FLAG(IPSET_OPT_TIMEOUT),
[IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
| IPSET_FLAG(IPSET_OPT_CIDR)
| IPSET_FLAG(IPSET_OPT_IP_TO)
| IPSET_FLAG(IPSET_OPT_PORT)
| IPSET_FLAG(IPSET_OPT_PORT_TO)
| IPSET_FLAG(IPSET_OPT_PROTO)
| IPSET_FLAG(IPSET_OPT_IP2)
| IPSET_FLAG(IPSET_OPT_CIDR2)
| IPSET_FLAG(IPSET_OPT_IP2_TO)
| IPSET_FLAG(IPSET_OPT_TIMEOUT),
[IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
| IPSET_FLAG(IPSET_OPT_CIDR)
| IPSET_FLAG(IPSET_OPT_IP_TO)
| IPSET_FLAG(IPSET_OPT_PORT)
| IPSET_FLAG(IPSET_OPT_PORT_TO)
| IPSET_FLAG(IPSET_OPT_PROTO)
| IPSET_FLAG(IPSET_OPT_IP2)
| IPSET_FLAG(IPSET_OPT_CIDR2)
| IPSET_FLAG(IPSET_OPT_IP2_TO),
[IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
| IPSET_FLAG(IPSET_OPT_PORT)
| IPSET_FLAG(IPSET_OPT_PROTO)
| IPSET_FLAG(IPSET_OPT_IP2)
| IPSET_FLAG(IPSET_OPT_CIDR2),
},
.usage = hash_ipportnet2_usage,
.usagefn = ipset_port_usage,
};

View File

@@ -57,7 +57,7 @@ static const struct ipset_arg hash_net_add_args[] = {
{ },
};
static const char hash_net_usage[] =
static const char hash_net0_usage[] =
"create SETNAME hash:net\n"
" [family inet|inet6]\n"
" [hashsize VALUE] [maxelem VALUE]\n"
@@ -105,5 +105,60 @@ struct ipset_type ipset_hash_net0 = {
| IPSET_FLAG(IPSET_OPT_CIDR),
},
.usage = hash_net_usage,
.usage = hash_net0_usage,
};
static const char hash_net1_usage[] =
"create SETNAME hash:net\n"
" [family inet|inet6]\n"
" [hashsize VALUE] [maxelem VALUE]\n"
" [timeout VALUE]\n"
"add SETNAME IP[/CIDR]|FROM-TO [timeout VALUE]\n"
"del SETNAME IP[/CIDR]|FROM-TO\n"
"test SETNAME IP[/CIDR]\n\n"
"where depending on the INET family\n"
" IP is an IPv4 or IPv6 address (or hostname),\n"
" CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
" IP range is not supported with IPv6.\n";
struct ipset_type ipset_hash_net1 = {
.name = "hash:net",
.alias = { "nethash", NULL },
.revision = 1,
.family = AF_INET46,
.dimension = IPSET_DIM_ONE,
.elem = {
[IPSET_DIM_ONE] = {
.parse = ipset_parse_ip4_net6,
.print = ipset_print_ip,
.opt = IPSET_OPT_IP
},
},
.args = {
[IPSET_CREATE] = hash_net_create_args,
[IPSET_ADD] = hash_net_add_args,
},
.mandatory = {
[IPSET_CREATE] = 0,
[IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP),
[IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP),
[IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP),
},
.full = {
[IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE)
| IPSET_FLAG(IPSET_OPT_MAXELEM)
| IPSET_FLAG(IPSET_OPT_TIMEOUT),
[IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
| IPSET_FLAG(IPSET_OPT_CIDR)
| IPSET_FLAG(IPSET_OPT_IP_TO)
| IPSET_FLAG(IPSET_OPT_TIMEOUT),
[IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
| IPSET_FLAG(IPSET_OPT_CIDR)
| IPSET_FLAG(IPSET_OPT_IP_TO),
[IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
| IPSET_FLAG(IPSET_OPT_CIDR),
},
.usage = hash_net1_usage,
};

View File

@@ -49,7 +49,7 @@ static const struct ipset_arg hash_netport_add_args[] = {
{ },
};
static const char hash_netport_usage[] =
static const char hash_netport1_usage[] =
"create SETNAME hash:net,port\n"
" [family inet|inet6]\n"
" [hashsize VALUE] [maxelem VALUE]\n"
@@ -63,7 +63,7 @@ static const char hash_netport_usage[] =
" Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
" port range is supported both for IPv4 and IPv6.\n";
struct ipset_type ipset_hash_netport0 = {
struct ipset_type ipset_hash_netport1 = {
.name = "hash:net,port",
.alias = { "netporthash", NULL },
.revision = 1,
@@ -118,6 +118,82 @@ struct ipset_type ipset_hash_netport0 = {
| IPSET_FLAG(IPSET_OPT_CIDR),
},
.usage = hash_netport_usage,
.usage = hash_netport1_usage,
.usagefn = ipset_port_usage,
};
static const char hash_netport2_usage[] =
"create SETNAME hash:net,port\n"
" [family inet|inet6]\n"
" [hashsize VALUE] [maxelem VALUE]\n"
" [timeout VALUE]\n"
"add SETNAME IP[/CIDR]|FROM-TO,PROTO:PORT [timeout VALUE]\n"
"del SETNAME IP[/CIDR]|FROM-TO,PROTO:PORT\n"
"test SETNAME IP[/CIDR],PROTO:PORT\n\n"
"where depending on the INET family\n"
" IP is a valid IPv4 or IPv6 address (or hostname),\n"
" CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
" Adding/deleting multiple elements with IPv4 is supported.\n"
" Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
" port range is supported both for IPv4 and IPv6.\n";
struct ipset_type ipset_hash_netport2 = {
.name = "hash:net,port",
.alias = { "netporthash", NULL },
.revision = 2,
.family = AF_INET46,
.dimension = IPSET_DIM_TWO,
.elem = {
[IPSET_DIM_ONE] = {
.parse = ipset_parse_ip4_net6,
.print = ipset_print_ip,
.opt = IPSET_OPT_IP
},
[IPSET_DIM_TWO] = {
.parse = ipset_parse_proto_port,
.print = ipset_print_proto_port,
.opt = IPSET_OPT_PORT
},
},
.args = {
[IPSET_CREATE] = hash_netport_create_args,
[IPSET_ADD] = hash_netport_add_args,
},
.mandatory = {
[IPSET_CREATE] = 0,
[IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
| IPSET_FLAG(IPSET_OPT_PROTO)
| IPSET_FLAG(IPSET_OPT_PORT),
[IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
| IPSET_FLAG(IPSET_OPT_PROTO)
| IPSET_FLAG(IPSET_OPT_PORT),
[IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
| IPSET_FLAG(IPSET_OPT_PROTO)
| IPSET_FLAG(IPSET_OPT_PORT),
},
.full = {
[IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE)
| IPSET_FLAG(IPSET_OPT_MAXELEM)
| IPSET_FLAG(IPSET_OPT_TIMEOUT),
[IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
| IPSET_FLAG(IPSET_OPT_CIDR)
| IPSET_FLAG(IPSET_OPT_IP_TO)
| IPSET_FLAG(IPSET_OPT_PORT)
| IPSET_FLAG(IPSET_OPT_PORT_TO)
| IPSET_FLAG(IPSET_OPT_PROTO)
| IPSET_FLAG(IPSET_OPT_TIMEOUT),
[IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
| IPSET_FLAG(IPSET_OPT_CIDR)
| IPSET_FLAG(IPSET_OPT_IP_TO)
| IPSET_FLAG(IPSET_OPT_PORT)
| IPSET_FLAG(IPSET_OPT_PORT_TO)
| IPSET_FLAG(IPSET_OPT_PROTO),
[IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
| IPSET_FLAG(IPSET_OPT_CIDR)
| IPSET_FLAG(IPSET_OPT_PORT)
| IPSET_FLAG(IPSET_OPT_PROTO),
},
.usage = hash_netport2_usage,
.usagefn = ipset_port_usage,
};

View File

@@ -188,6 +188,19 @@ const struct ipset_envopts ipset_envopts[] = {
" when adding already existing elements\n"
" or when deleting non-existing elements.",
},
{ .name = { "-n", "-name" },
.parse = ipset_envopt_parse,
.has_arg = IPSET_NO_ARG, .flag = IPSET_ENV_LIST_SETNAME,
.help = "\n"
" When listing, list just setnames from kernel.\n",
},
{ .name = { "-t", "-terse" },
.parse = ipset_envopt_parse,
.has_arg = IPSET_NO_ARG, .flag = IPSET_ENV_LIST_HEADER,
.help = "\n"
" When listing, list setnames and set headers\n"
" from kernel only.",
},
{ },
};
@@ -256,9 +269,9 @@ ipset_port_usage(void)
const char *name;
printf(" [PROTO:]PORT is a valid pattern of the following:\n"
" PORTNAME port name from /etc/services\n"
" PORTNUMBER port number identifier\n"
" tcp|udp:PORTNAME|PORTNUMBER\n"
" PORTNAME TCP port name from /etc/services\n"
" PORTNUMBER TCP port number identifier\n"
" tcp|sctp|udp|udplite:PORTNAME|PORTNUMBER\n"
" icmp:CODENAME supported ICMP codename\n"
" icmp:TYPE/CODE ICMP type/code value\n"
" icmpv6:CODENAME supported ICMPv6 codename\n"

View File

@@ -29,52 +29,33 @@ MODULE_ALIAS("ip6t_SET");
static inline int
match_set(ip_set_id_t index, const struct sk_buff *skb,
u8 pf, u8 dim, u8 flags, int inv)
const struct xt_action_param *par,
const struct ip_set_adt_opt *opt, int inv)
{
if (ip_set_test(index, skb, pf, dim, flags))
if (ip_set_test(index, skb, par, opt))
inv = !inv;
return inv;
}
#define ADT_OPT(n, f, d, fs, cfs, t) \
const struct ip_set_adt_opt n = { \
.family = f, \
.dim = d, \
.flags = fs, \
.cmdflags = cfs, \
.timeout = t, \
}
/* Revision 0 interface: backward compatible with netfilter/iptables */
/* Backward compatibility constrains (incomplete):
* 2.6.24: [NETLINK]: Introduce nested and byteorder flag to netlink attribute
* 2.6.25: is_vmalloc_addr(): Check if an address is within the vmalloc
* boundaries
* 2.6.27: rcu: split list.h and move rcu-protected lists into rculist.h
* 2.6.28: netfilter: ctnetlink: remove bogus module dependency between
* ctnetlink and nf_nat (nfnl_lock/nfnl_unlock)
* 2.6.29: generic swap(): introduce global macro swap(a, b)
* 2.6.31: netfilter: passive OS fingerprint xtables match
* 2.6.34: rcu: Add lockdep-enabled variants of rcu_dereference()
*/
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 34)
#error "Linux kernel version too old: must be >= 2.6.34"
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
#define CHECK_OK 1
#define CHECK_FAIL(err) 0
#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35) */
#define CHECK_OK 0
#define CHECK_FAIL(err) (err)
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
static bool
set_match_v0(const struct sk_buff *skb, const struct xt_match_param *par)
#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35) */
static bool
set_match_v0(const struct sk_buff *skb, struct xt_action_param *par)
#endif
{
const struct xt_set_info_match_v0 *info = par->matchinfo;
ADT_OPT(opt, par->family, info->match_set.u.compat.dim,
info->match_set.u.compat.flags, 0, UINT_MAX);
return match_set(info->match_set.index, skb, par->family,
info->match_set.u.compat.dim,
info->match_set.u.compat.flags,
return match_set(info->match_set.index, skb, par, &opt,
info->match_set.u.compat.flags & IPSET_INV_MATCH);
}
@@ -94,13 +75,8 @@ compat_flags(struct xt_set_info_v0 *info)
}
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
static bool
set_match_v0_checkentry(const struct xt_mtchk_param *par)
#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35) */
static int
set_match_v0_checkentry(const struct xt_mtchk_param *par)
#endif
{
struct xt_set_info_match_v0 *info = par->matchinfo;
ip_set_id_t index;
@@ -110,19 +86,19 @@ set_match_v0_checkentry(const struct xt_mtchk_param *par)
if (index == IPSET_INVALID_ID) {
pr_warning("Cannot find set indentified by id %u to match\n",
info->match_set.index);
return CHECK_FAIL(-ENOENT); /* error */
return -ENOENT;
}
if (info->match_set.u.flags[IPSET_DIM_MAX-1] != 0) {
pr_warning("Protocol error: set match dimension "
"is over the limit!\n");
ip_set_nfnl_put(info->match_set.index);
return CHECK_FAIL(-ERANGE); /* error */
return -ERANGE;
}
/* Fill out compatibility data */
compat_flags(&info->match_set);
return CHECK_OK;
return 0;
}
static void
@@ -133,35 +109,25 @@ set_match_v0_destroy(const struct xt_mtdtor_param *par)
ip_set_nfnl_put(info->match_set.index);
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
static unsigned int
set_target_v0(struct sk_buff *skb, const struct xt_target_param *par)
#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35) */
static unsigned int
set_target_v0(struct sk_buff *skb, const struct xt_action_param *par)
#endif
{
const struct xt_set_info_target_v0 *info = par->targinfo;
ADT_OPT(add_opt, par->family, info->add_set.u.compat.dim,
info->add_set.u.compat.flags, 0, UINT_MAX);
ADT_OPT(del_opt, par->family, info->del_set.u.compat.dim,
info->del_set.u.compat.flags, 0, UINT_MAX);
if (info->add_set.index != IPSET_INVALID_ID)
ip_set_add(info->add_set.index, skb, par->family,
info->add_set.u.compat.dim,
info->add_set.u.compat.flags);
ip_set_add(info->add_set.index, skb, par, &add_opt);
if (info->del_set.index != IPSET_INVALID_ID)
ip_set_del(info->del_set.index, skb, par->family,
info->del_set.u.compat.dim,
info->del_set.u.compat.flags);
ip_set_del(info->del_set.index, skb, par, &del_opt);
return XT_CONTINUE;
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
static bool
set_target_v0_checkentry(const struct xt_tgchk_param *par)
#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35) */
static int
set_target_v0_checkentry(const struct xt_tgchk_param *par)
#endif
{
struct xt_set_info_target_v0 *info = par->targinfo;
ip_set_id_t index;
@@ -171,7 +137,7 @@ set_target_v0_checkentry(const struct xt_tgchk_param *par)
if (index == IPSET_INVALID_ID) {
pr_warning("Cannot find add_set index %u as target\n",
info->add_set.index);
return CHECK_FAIL(-ENOENT); /* error */
return -ENOENT;
}
}
@@ -182,7 +148,7 @@ set_target_v0_checkentry(const struct xt_tgchk_param *par)
info->del_set.index);
if (info->add_set.index != IPSET_INVALID_ID)
ip_set_nfnl_put(info->add_set.index);
return CHECK_FAIL(-ENOENT); /* error */
return -ENOENT;
}
}
if (info->add_set.u.flags[IPSET_DIM_MAX-1] != 0 ||
@@ -193,14 +159,14 @@ set_target_v0_checkentry(const struct xt_tgchk_param *par)
ip_set_nfnl_put(info->add_set.index);
if (info->del_set.index != IPSET_INVALID_ID)
ip_set_nfnl_put(info->del_set.index);
return CHECK_FAIL(-ERANGE); /* error */
return -ERANGE;
}
/* Fill out compatibility data */
compat_flags(&info->add_set);
compat_flags(&info->del_set);
return CHECK_OK;
return 0;
}
static void
@@ -214,33 +180,23 @@ set_target_v0_destroy(const struct xt_tgdtor_param *par)
ip_set_nfnl_put(info->del_set.index);
}
/* Revision 1: current interface to netfilter/iptables */
/* Revision 1 match and target */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
static bool
set_match(const struct sk_buff *skb, const struct xt_match_param *par)
#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35) */
static bool
set_match(const struct sk_buff *skb, struct xt_action_param *par)
#endif
set_match_v1(const struct sk_buff *skb, struct xt_action_param *par)
{
const struct xt_set_info_match *info = par->matchinfo;
const struct xt_set_info_match_v1 *info = par->matchinfo;
ADT_OPT(opt, par->family, info->match_set.dim,
info->match_set.flags, 0, UINT_MAX);
return match_set(info->match_set.index, skb, par->family,
info->match_set.dim,
info->match_set.flags,
return match_set(info->match_set.index, skb, par, &opt,
info->match_set.flags & IPSET_INV_MATCH);
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
static bool
set_match_checkentry(const struct xt_mtchk_param *par)
#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35) */
static int
set_match_checkentry(const struct xt_mtchk_param *par)
#endif
set_match_v1_checkentry(const struct xt_mtchk_param *par)
{
struct xt_set_info_match *info = par->matchinfo;
struct xt_set_info_match_v1 *info = par->matchinfo;
ip_set_id_t index;
index = ip_set_nfnl_get_byindex(info->match_set.index);
@@ -248,59 +204,47 @@ set_match_checkentry(const struct xt_mtchk_param *par)
if (index == IPSET_INVALID_ID) {
pr_warning("Cannot find set indentified by id %u to match\n",
info->match_set.index);
return CHECK_FAIL(-ENOENT); /* error */
return -ENOENT;
}
if (info->match_set.dim > IPSET_DIM_MAX) {
pr_warning("Protocol error: set match dimension "
"is over the limit!\n");
ip_set_nfnl_put(info->match_set.index);
return CHECK_FAIL(-ERANGE); /* error */
return -ERANGE;
}
return CHECK_OK;
return 0;
}
static void
set_match_destroy(const struct xt_mtdtor_param *par)
set_match_v1_destroy(const struct xt_mtdtor_param *par)
{
struct xt_set_info_match *info = par->matchinfo;
struct xt_set_info_match_v1 *info = par->matchinfo;
ip_set_nfnl_put(info->match_set.index);
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
static unsigned int
set_target(struct sk_buff *skb, const struct xt_target_param *par)
#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35) */
static unsigned int
set_target(struct sk_buff *skb, const struct xt_action_param *par)
#endif
set_target_v1(struct sk_buff *skb, const struct xt_action_param *par)
{
const struct xt_set_info_target *info = par->targinfo;
const struct xt_set_info_target_v1 *info = par->targinfo;
ADT_OPT(add_opt, par->family, info->add_set.dim,
info->add_set.flags, 0, UINT_MAX);
ADT_OPT(del_opt, par->family, info->del_set.dim,
info->del_set.flags, 0, UINT_MAX);
if (info->add_set.index != IPSET_INVALID_ID)
ip_set_add(info->add_set.index,
skb, par->family,
info->add_set.dim,
info->add_set.flags);
ip_set_add(info->add_set.index, skb, par, &add_opt);
if (info->del_set.index != IPSET_INVALID_ID)
ip_set_del(info->del_set.index,
skb, par->family,
info->del_set.dim,
info->del_set.flags);
ip_set_del(info->del_set.index, skb, par, &del_opt);
return XT_CONTINUE;
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
static bool
set_target_checkentry(const struct xt_tgchk_param *par)
#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35) */
static int
set_target_checkentry(const struct xt_tgchk_param *par)
#endif
set_target_v1_checkentry(const struct xt_tgchk_param *par)
{
const struct xt_set_info_target *info = par->targinfo;
const struct xt_set_info_target_v1 *info = par->targinfo;
ip_set_id_t index;
if (info->add_set.index != IPSET_INVALID_ID) {
@@ -308,7 +252,7 @@ set_target_checkentry(const struct xt_tgchk_param *par)
if (index == IPSET_INVALID_ID) {
pr_warning("Cannot find add_set index %u as target\n",
info->add_set.index);
return CHECK_FAIL(-ENOENT); /* error */
return -ENOENT;
}
}
@@ -319,7 +263,7 @@ set_target_checkentry(const struct xt_tgchk_param *par)
info->del_set.index);
if (info->add_set.index != IPSET_INVALID_ID)
ip_set_nfnl_put(info->add_set.index);
return CHECK_FAIL(-ENOENT); /* error */
return -ENOENT;
}
}
if (info->add_set.dim > IPSET_DIM_MAX ||
@@ -330,16 +274,16 @@ set_target_checkentry(const struct xt_tgchk_param *par)
ip_set_nfnl_put(info->add_set.index);
if (info->del_set.index != IPSET_INVALID_ID)
ip_set_nfnl_put(info->del_set.index);
return CHECK_FAIL(-ERANGE); /* error */
return -ERANGE;
}
return CHECK_OK;
return 0;
}
static void
set_target_destroy(const struct xt_tgdtor_param *par)
set_target_v1_destroy(const struct xt_tgdtor_param *par)
{
const struct xt_set_info_target *info = par->targinfo;
const struct xt_set_info_target_v1 *info = par->targinfo;
if (info->add_set.index != IPSET_INVALID_ID)
ip_set_nfnl_put(info->add_set.index);
@@ -347,6 +291,28 @@ set_target_destroy(const struct xt_tgdtor_param *par)
ip_set_nfnl_put(info->del_set.index);
}
/* Revision 2 target */
static unsigned int
set_target_v2(struct sk_buff *skb, const struct xt_action_param *par)
{
const struct xt_set_info_target_v2 *info = par->targinfo;
ADT_OPT(add_opt, par->family, info->add_set.dim,
info->add_set.flags, info->flags, info->timeout);
ADT_OPT(del_opt, par->family, info->del_set.dim,
info->del_set.flags, 0, UINT_MAX);
if (info->add_set.index != IPSET_INVALID_ID)
ip_set_add(info->add_set.index, skb, par, &add_opt);
if (info->del_set.index != IPSET_INVALID_ID)
ip_set_del(info->del_set.index, skb, par, &del_opt);
return XT_CONTINUE;
}
#define set_target_v2_checkentry set_target_v1_checkentry
#define set_target_v2_destroy set_target_v1_destroy
static struct xt_match set_matches[] __read_mostly = {
{
.name = "set",
@@ -362,20 +328,20 @@ static struct xt_match set_matches[] __read_mostly = {
.name = "set",
.family = NFPROTO_IPV4,
.revision = 1,
.match = set_match,
.matchsize = sizeof(struct xt_set_info_match),
.checkentry = set_match_checkentry,
.destroy = set_match_destroy,
.match = set_match_v1,
.matchsize = sizeof(struct xt_set_info_match_v1),
.checkentry = set_match_v1_checkentry,
.destroy = set_match_v1_destroy,
.me = THIS_MODULE
},
{
.name = "set",
.family = NFPROTO_IPV6,
.revision = 1,
.match = set_match,
.matchsize = sizeof(struct xt_set_info_match),
.checkentry = set_match_checkentry,
.destroy = set_match_destroy,
.match = set_match_v1,
.matchsize = sizeof(struct xt_set_info_match_v1),
.checkentry = set_match_v1_checkentry,
.destroy = set_match_v1_destroy,
.me = THIS_MODULE
},
};
@@ -395,20 +361,40 @@ static struct xt_target set_targets[] __read_mostly = {
.name = "SET",
.revision = 1,
.family = NFPROTO_IPV4,
.target = set_target,
.targetsize = sizeof(struct xt_set_info_target),
.checkentry = set_target_checkentry,
.destroy = set_target_destroy,
.target = set_target_v1,
.targetsize = sizeof(struct xt_set_info_target_v1),
.checkentry = set_target_v1_checkentry,
.destroy = set_target_v1_destroy,
.me = THIS_MODULE
},
{
.name = "SET",
.revision = 1,
.family = NFPROTO_IPV6,
.target = set_target,
.targetsize = sizeof(struct xt_set_info_target),
.checkentry = set_target_checkentry,
.destroy = set_target_destroy,
.target = set_target_v1,
.targetsize = sizeof(struct xt_set_info_target_v1),
.checkentry = set_target_v1_checkentry,
.destroy = set_target_v1_destroy,
.me = THIS_MODULE
},
{
.name = "SET",
.revision = 2,
.family = NFPROTO_IPV4,
.target = set_target_v2,
.targetsize = sizeof(struct xt_set_info_target_v2),
.checkentry = set_target_v2_checkentry,
.destroy = set_target_v2_destroy,
.me = THIS_MODULE
},
{
.name = "SET",
.revision = 2,
.family = NFPROTO_IPV6,
.target = set_target_v2,
.targetsize = sizeof(struct xt_set_info_target_v2),
.checkentry = set_target_v2_checkentry,
.destroy = set_target_v2_destroy,
.me = THIS_MODULE
},
};

View File

@@ -35,7 +35,7 @@ struct xt_set_info_target_v0 {
struct xt_set_info_v0 del_set;
};
/* Revision 1: current interface to netfilter/iptables */
/* Revision 1 match and target */
struct xt_set_info {
ip_set_id_t index;
@@ -44,13 +44,22 @@ struct xt_set_info {
};
/* match and target infos */
struct xt_set_info_match {
struct xt_set_info_match_v1 {
struct xt_set_info match_set;
};
struct xt_set_info_target {
struct xt_set_info_target_v1 {
struct xt_set_info add_set;
struct xt_set_info del_set;
};
/* Revision 2 target */
struct xt_set_info_target_v2 {
struct xt_set_info add_set;
struct xt_set_info del_set;
u32 flags;
u32 timeout;
};
#endif /*_XT_SET_H*/