netfilter: ipset: Introduce extensions to elements in the core
Introduce extensions to elements in the core and prepare timeout as the first one. This patch also modifies the em_ipset classifier to use the new extension struct layout. Signed-off-by: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
This commit is contained in:
parent
8672d4d1a0
commit
075e64c041
|
@ -1,7 +1,7 @@
|
|||
/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
|
||||
* Patrick Schaaf <bof@bof.de>
|
||||
* Martin Josefsson <gandalf@wlug.westbo.se>
|
||||
* Copyright (C) 2003-2011 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
|
||||
* Copyright (C) 2003-2013 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
|
||||
|
@ -47,10 +47,30 @@ enum ip_set_feature {
|
|||
IPSET_DUMP_LAST = (1 << IPSET_DUMP_LAST_FLAG),
|
||||
};
|
||||
|
||||
/* Set extensions */
|
||||
enum ip_set_extension {
|
||||
IPSET_EXT_NONE = 0,
|
||||
IPSET_EXT_BIT_TIMEOUT = 1,
|
||||
IPSET_EXT_TIMEOUT = (1 << IPSET_EXT_BIT_TIMEOUT),
|
||||
};
|
||||
|
||||
/* Extension offsets */
|
||||
enum ip_set_offset {
|
||||
IPSET_OFFSET_TIMEOUT = 0,
|
||||
IPSET_OFFSET_MAX,
|
||||
};
|
||||
|
||||
#define SET_WITH_TIMEOUT(s) ((s)->extensions & IPSET_EXT_TIMEOUT)
|
||||
|
||||
struct ip_set_ext {
|
||||
unsigned long timeout;
|
||||
};
|
||||
|
||||
struct ip_set;
|
||||
|
||||
typedef int (*ipset_adtfn)(struct ip_set *set, void *value,
|
||||
u32 timeout, u32 flags);
|
||||
const struct ip_set_ext *ext,
|
||||
struct ip_set_ext *mext, u32 flags);
|
||||
|
||||
/* Kernel API function options */
|
||||
struct ip_set_adt_opt {
|
||||
|
@ -58,7 +78,7 @@ struct ip_set_adt_opt {
|
|||
u8 dim; /* Dimension of match/target */
|
||||
u8 flags; /* Direction and negation flags */
|
||||
u32 cmdflags; /* Command-like flags */
|
||||
u32 timeout; /* Timeout value */
|
||||
struct ip_set_ext ext; /* Extensions */
|
||||
};
|
||||
|
||||
/* Set type, variant-specific part */
|
||||
|
@ -69,7 +89,7 @@ struct ip_set_type_variant {
|
|||
* positive for matching element */
|
||||
int (*kadt)(struct ip_set *set, const struct sk_buff *skb,
|
||||
const struct xt_action_param *par,
|
||||
enum ipset_adt adt, const struct ip_set_adt_opt *opt);
|
||||
enum ipset_adt adt, struct ip_set_adt_opt *opt);
|
||||
|
||||
/* Userspace: test/add/del entries
|
||||
* returns negative error code,
|
||||
|
@ -151,6 +171,8 @@ struct ip_set {
|
|||
u8 family;
|
||||
/* The type revision */
|
||||
u8 revision;
|
||||
/* Extensions */
|
||||
u8 extensions;
|
||||
/* The type specific data */
|
||||
void *data;
|
||||
};
|
||||
|
@ -167,19 +189,21 @@ extern void ip_set_nfnl_put(ip_set_id_t index);
|
|||
|
||||
extern int ip_set_add(ip_set_id_t id, const struct sk_buff *skb,
|
||||
const struct xt_action_param *par,
|
||||
const struct ip_set_adt_opt *opt);
|
||||
struct ip_set_adt_opt *opt);
|
||||
extern int ip_set_del(ip_set_id_t id, const struct sk_buff *skb,
|
||||
const struct xt_action_param *par,
|
||||
const struct ip_set_adt_opt *opt);
|
||||
struct ip_set_adt_opt *opt);
|
||||
extern int ip_set_test(ip_set_id_t id, const struct sk_buff *skb,
|
||||
const struct xt_action_param *par,
|
||||
const struct ip_set_adt_opt *opt);
|
||||
struct ip_set_adt_opt *opt);
|
||||
|
||||
/* Utility functions */
|
||||
extern void *ip_set_alloc(size_t size);
|
||||
extern void ip_set_free(void *members);
|
||||
extern int ip_set_get_ipaddr4(struct nlattr *nla, __be32 *ipaddr);
|
||||
extern int ip_set_get_ipaddr6(struct nlattr *nla, union nf_inet_addr *ipaddr);
|
||||
extern int ip_set_get_extensions(struct ip_set *set, struct nlattr *tb[],
|
||||
struct ip_set_ext *ext);
|
||||
|
||||
static inline int
|
||||
ip_set_get_hostipaddr4(struct nlattr *nla, u32 *ipaddr)
|
||||
|
@ -292,4 +316,12 @@ bitmap_bytes(u32 a, u32 b)
|
|||
return 4 * ((((b - a + 8) / 8) + 3) / 4);
|
||||
}
|
||||
|
||||
#include <linux/netfilter/ipset/ip_set_timeout.h>
|
||||
|
||||
#define IP_SET_INIT_KEXT(skb, opt, map) \
|
||||
{ .timeout = ip_set_adt_opt_timeout(opt, map) }
|
||||
|
||||
#define IP_SET_INIT_UEXT(map) \
|
||||
{ .timeout = (map)->timeout }
|
||||
|
||||
#endif /*_IP_SET_H */
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef _IP_SET_TIMEOUT_H
|
||||
#define _IP_SET_TIMEOUT_H
|
||||
|
||||
/* Copyright (C) 2003-2011 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
|
||||
/* Copyright (C) 2003-2013 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
|
||||
|
@ -17,13 +17,14 @@
|
|||
#define IPSET_GC_PERIOD(timeout) \
|
||||
((timeout/3) ? min_t(u32, (timeout)/3, IPSET_GC_TIME) : 1)
|
||||
|
||||
/* Set is defined without timeout support: timeout value may be 0 */
|
||||
/* Entry is set with no timeout value */
|
||||
#define IPSET_ELEM_PERMANENT 0
|
||||
|
||||
/* Set is defined with timeout support: timeout value may be 0 */
|
||||
#define IPSET_NO_TIMEOUT UINT_MAX
|
||||
|
||||
#define with_timeout(timeout) ((timeout) != IPSET_NO_TIMEOUT)
|
||||
|
||||
#define opt_timeout(opt, map) \
|
||||
(with_timeout((opt)->timeout) ? (opt)->timeout : (map)->timeout)
|
||||
#define ip_set_adt_opt_timeout(opt, map) \
|
||||
((opt)->ext.timeout != IPSET_NO_TIMEOUT ? (opt)->ext.timeout : (map)->timeout)
|
||||
|
||||
static inline unsigned int
|
||||
ip_set_timeout_uget(struct nlattr *tb)
|
||||
|
@ -38,61 +39,6 @@ ip_set_timeout_uget(struct nlattr *tb)
|
|||
return timeout == IPSET_NO_TIMEOUT ? IPSET_NO_TIMEOUT - 1 : timeout;
|
||||
}
|
||||
|
||||
#ifdef IP_SET_BITMAP_TIMEOUT
|
||||
|
||||
/* Bitmap specific timeout constants and macros for the entries */
|
||||
|
||||
/* Bitmap entry is unset */
|
||||
#define IPSET_ELEM_UNSET 0
|
||||
/* Bitmap entry is set with no timeout value */
|
||||
#define IPSET_ELEM_PERMANENT (UINT_MAX/2)
|
||||
|
||||
static inline bool
|
||||
ip_set_timeout_test(unsigned long timeout)
|
||||
{
|
||||
return timeout != IPSET_ELEM_UNSET &&
|
||||
(timeout == IPSET_ELEM_PERMANENT ||
|
||||
time_is_after_jiffies(timeout));
|
||||
}
|
||||
|
||||
static inline bool
|
||||
ip_set_timeout_expired(unsigned long timeout)
|
||||
{
|
||||
return timeout != IPSET_ELEM_UNSET &&
|
||||
timeout != IPSET_ELEM_PERMANENT &&
|
||||
time_is_before_jiffies(timeout);
|
||||
}
|
||||
|
||||
static inline unsigned long
|
||||
ip_set_timeout_set(u32 timeout)
|
||||
{
|
||||
unsigned long t;
|
||||
|
||||
if (!timeout)
|
||||
return IPSET_ELEM_PERMANENT;
|
||||
|
||||
t = msecs_to_jiffies(timeout * 1000) + jiffies;
|
||||
if (t == IPSET_ELEM_UNSET || t == IPSET_ELEM_PERMANENT)
|
||||
/* Bingo! */
|
||||
t++;
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
static inline u32
|
||||
ip_set_timeout_get(unsigned long timeout)
|
||||
{
|
||||
return timeout == IPSET_ELEM_PERMANENT ? 0 :
|
||||
jiffies_to_msecs(timeout - jiffies)/1000;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/* Hash specific timeout constants and macros for the entries */
|
||||
|
||||
/* Hash entry is set with no timeout value */
|
||||
#define IPSET_ELEM_PERMANENT 0
|
||||
|
||||
static inline bool
|
||||
ip_set_timeout_test(unsigned long timeout)
|
||||
{
|
||||
|
@ -101,36 +47,32 @@ ip_set_timeout_test(unsigned long timeout)
|
|||
}
|
||||
|
||||
static inline bool
|
||||
ip_set_timeout_expired(unsigned long timeout)
|
||||
ip_set_timeout_expired(unsigned long *timeout)
|
||||
{
|
||||
return timeout != IPSET_ELEM_PERMANENT &&
|
||||
time_is_before_jiffies(timeout);
|
||||
return *timeout != IPSET_ELEM_PERMANENT &&
|
||||
time_is_before_jiffies(*timeout);
|
||||
}
|
||||
|
||||
static inline unsigned long
|
||||
ip_set_timeout_set(u32 timeout)
|
||||
static inline void
|
||||
ip_set_timeout_set(unsigned long *timeout, u32 t)
|
||||
{
|
||||
unsigned long t;
|
||||
if (!t) {
|
||||
*timeout = IPSET_ELEM_PERMANENT;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!timeout)
|
||||
return IPSET_ELEM_PERMANENT;
|
||||
|
||||
t = msecs_to_jiffies(timeout * 1000) + jiffies;
|
||||
if (t == IPSET_ELEM_PERMANENT)
|
||||
*timeout = msecs_to_jiffies(t * 1000) + jiffies;
|
||||
if (*timeout == IPSET_ELEM_PERMANENT)
|
||||
/* Bingo! :-) */
|
||||
t++;
|
||||
|
||||
return t;
|
||||
(*timeout)--;
|
||||
}
|
||||
|
||||
static inline u32
|
||||
ip_set_timeout_get(unsigned long timeout)
|
||||
ip_set_timeout_get(unsigned long *timeout)
|
||||
{
|
||||
return timeout == IPSET_ELEM_PERMANENT ? 0 :
|
||||
jiffies_to_msecs(timeout - jiffies)/1000;
|
||||
return *timeout == IPSET_ELEM_PERMANENT ? 0 :
|
||||
jiffies_to_msecs(*timeout - jiffies)/1000;
|
||||
}
|
||||
#endif /* ! IP_SET_BITMAP_TIMEOUT */
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
#endif /* _IP_SET_TIMEOUT_H */
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
|
||||
* Patrick Schaaf <bof@bof.de>
|
||||
* Copyright (C) 2003-2011 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
|
||||
* Copyright (C) 2003-2013 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
|
||||
|
@ -315,6 +315,19 @@ ip_set_get_ipaddr6(struct nlattr *nla, union nf_inet_addr *ipaddr)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(ip_set_get_ipaddr6);
|
||||
|
||||
int
|
||||
ip_set_get_extensions(struct ip_set *set, struct nlattr *tb[],
|
||||
struct ip_set_ext *ext)
|
||||
{
|
||||
if (tb[IPSET_ATTR_TIMEOUT]) {
|
||||
if (!(set->extensions & IPSET_EXT_TIMEOUT))
|
||||
return -IPSET_ERR_TIMEOUT;
|
||||
ext->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ip_set_get_extensions);
|
||||
|
||||
/*
|
||||
* Creating/destroying/renaming/swapping affect the existence and
|
||||
* the properties of a set. All of these can be executed from userspace
|
||||
|
@ -365,8 +378,7 @@ ip_set_rcu_get(ip_set_id_t index)
|
|||
|
||||
int
|
||||
ip_set_test(ip_set_id_t index, const struct sk_buff *skb,
|
||||
const struct xt_action_param *par,
|
||||
const struct ip_set_adt_opt *opt)
|
||||
const struct xt_action_param *par, struct ip_set_adt_opt *opt)
|
||||
{
|
||||
struct ip_set *set = ip_set_rcu_get(index);
|
||||
int ret = 0;
|
||||
|
@ -404,8 +416,7 @@ EXPORT_SYMBOL_GPL(ip_set_test);
|
|||
|
||||
int
|
||||
ip_set_add(ip_set_id_t index, const struct sk_buff *skb,
|
||||
const struct xt_action_param *par,
|
||||
const struct ip_set_adt_opt *opt)
|
||||
const struct xt_action_param *par, struct ip_set_adt_opt *opt)
|
||||
{
|
||||
struct ip_set *set = ip_set_rcu_get(index);
|
||||
int ret;
|
||||
|
@ -427,8 +438,7 @@ EXPORT_SYMBOL_GPL(ip_set_add);
|
|||
|
||||
int
|
||||
ip_set_del(ip_set_id_t index, const struct sk_buff *skb,
|
||||
const struct xt_action_param *par,
|
||||
const struct ip_set_adt_opt *opt)
|
||||
const struct xt_action_param *par, struct ip_set_adt_opt *opt)
|
||||
{
|
||||
struct ip_set *set = ip_set_rcu_get(index);
|
||||
int ret = 0;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
|
||||
* Patrick Schaaf <bof@bof.de>
|
||||
* Martin Josefsson <gandalf@wlug.westbo.se>
|
||||
* Copyright (C) 2003-2011 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
|
||||
* Copyright (C) 2003-2013 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
|
||||
|
@ -30,7 +30,7 @@ MODULE_ALIAS("ip6t_SET");
|
|||
static inline int
|
||||
match_set(ip_set_id_t index, const struct sk_buff *skb,
|
||||
const struct xt_action_param *par,
|
||||
const struct ip_set_adt_opt *opt, int inv)
|
||||
struct ip_set_adt_opt *opt, int inv)
|
||||
{
|
||||
if (ip_set_test(index, skb, par, opt))
|
||||
inv = !inv;
|
||||
|
@ -38,20 +38,12 @@ match_set(ip_set_id_t index, const struct sk_buff *skb,
|
|||
}
|
||||
|
||||
#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, \
|
||||
}
|
||||
#define ADT_MOPT(n, f, d, fs, cfs, t) \
|
||||
struct ip_set_adt_opt n = { \
|
||||
.family = f, \
|
||||
.dim = d, \
|
||||
.flags = fs, \
|
||||
.cmdflags = cfs, \
|
||||
.timeout = t, \
|
||||
.ext.timeout = t, \
|
||||
}
|
||||
|
||||
/* Revision 0 interface: backward compatible with netfilter/iptables */
|
||||
|
@ -305,15 +297,15 @@ 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_MOPT(add_opt, par->family, info->add_set.dim,
|
||||
info->add_set.flags, info->flags, info->timeout);
|
||||
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);
|
||||
|
||||
/* Normalize to fit into jiffies */
|
||||
if (add_opt.timeout != IPSET_NO_TIMEOUT &&
|
||||
add_opt.timeout > UINT_MAX/MSEC_PER_SEC)
|
||||
add_opt.timeout = UINT_MAX/MSEC_PER_SEC;
|
||||
if (add_opt.ext.timeout != IPSET_NO_TIMEOUT &&
|
||||
add_opt.ext.timeout > UINT_MAX/MSEC_PER_SEC)
|
||||
add_opt.ext.timeout = UINT_MAX/MSEC_PER_SEC;
|
||||
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)
|
||||
|
|
|
@ -83,7 +83,7 @@ static int em_ipset_match(struct sk_buff *skb, struct tcf_ematch *em,
|
|||
opt.dim = set->dim;
|
||||
opt.flags = set->flags;
|
||||
opt.cmdflags = 0;
|
||||
opt.timeout = ~0u;
|
||||
opt.ext.timeout = ~0u;
|
||||
|
||||
network_offset = skb_network_offset(skb);
|
||||
skb_pull(skb, network_offset);
|
||||
|
|
Loading…
Reference in New Issue