Commit 075e64c0 authored by Jozsef Kadlecsik's avatar Jozsef Kadlecsik Committed by Pablo Neira Ayuso

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: default avatarJozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent 8672d4d1
/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu> /* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
* Patrick Schaaf <bof@bof.de> * Patrick Schaaf <bof@bof.de>
* Martin Josefsson <gandalf@wlug.westbo.se> * Martin Josefsson <gandalf@wlug.westbo.se>
* Copyright (C) 2003-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 * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
...@@ -47,10 +47,30 @@ enum ip_set_feature { ...@@ -47,10 +47,30 @@ enum ip_set_feature {
IPSET_DUMP_LAST = (1 << IPSET_DUMP_LAST_FLAG), 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; struct ip_set;
typedef int (*ipset_adtfn)(struct ip_set *set, void *value, 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 */ /* Kernel API function options */
struct ip_set_adt_opt { struct ip_set_adt_opt {
...@@ -58,7 +78,7 @@ struct ip_set_adt_opt { ...@@ -58,7 +78,7 @@ struct ip_set_adt_opt {
u8 dim; /* Dimension of match/target */ u8 dim; /* Dimension of match/target */
u8 flags; /* Direction and negation flags */ u8 flags; /* Direction and negation flags */
u32 cmdflags; /* Command-like flags */ u32 cmdflags; /* Command-like flags */
u32 timeout; /* Timeout value */ struct ip_set_ext ext; /* Extensions */
}; };
/* Set type, variant-specific part */ /* Set type, variant-specific part */
...@@ -69,7 +89,7 @@ struct ip_set_type_variant { ...@@ -69,7 +89,7 @@ struct ip_set_type_variant {
* positive for matching element */ * positive for matching element */
int (*kadt)(struct ip_set *set, const struct sk_buff *skb, int (*kadt)(struct ip_set *set, const struct sk_buff *skb,
const struct xt_action_param *par, 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 /* Userspace: test/add/del entries
* returns negative error code, * returns negative error code,
...@@ -151,6 +171,8 @@ struct ip_set { ...@@ -151,6 +171,8 @@ struct ip_set {
u8 family; u8 family;
/* The type revision */ /* The type revision */
u8 revision; u8 revision;
/* Extensions */
u8 extensions;
/* The type specific data */ /* The type specific data */
void *data; void *data;
}; };
...@@ -167,19 +189,21 @@ extern void ip_set_nfnl_put(ip_set_id_t index); ...@@ -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, extern int ip_set_add(ip_set_id_t id, const struct sk_buff *skb,
const struct xt_action_param *par, 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, extern int ip_set_del(ip_set_id_t id, const struct sk_buff *skb,
const struct xt_action_param *par, 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, extern int ip_set_test(ip_set_id_t id, const struct sk_buff *skb,
const struct xt_action_param *par, const struct xt_action_param *par,
const struct ip_set_adt_opt *opt); struct ip_set_adt_opt *opt);
/* Utility functions */ /* Utility functions */
extern void *ip_set_alloc(size_t size); extern void *ip_set_alloc(size_t size);
extern void ip_set_free(void *members); extern void ip_set_free(void *members);
extern int ip_set_get_ipaddr4(struct nlattr *nla, __be32 *ipaddr); extern int ip_set_get_ipaddr4(struct nlattr *nla, __be32 *ipaddr);
extern int ip_set_get_ipaddr6(struct nlattr *nla, union nf_inet_addr *ipaddr); extern int ip_set_get_ipaddr6(struct nlattr *nla, union nf_inet_addr *ipaddr);
extern int ip_set_get_extensions(struct ip_set *set, struct nlattr *tb[],
struct ip_set_ext *ext);
static inline int static inline int
ip_set_get_hostipaddr4(struct nlattr *nla, u32 *ipaddr) ip_set_get_hostipaddr4(struct nlattr *nla, u32 *ipaddr)
...@@ -292,4 +316,12 @@ bitmap_bytes(u32 a, u32 b) ...@@ -292,4 +316,12 @@ bitmap_bytes(u32 a, u32 b)
return 4 * ((((b - a + 8) / 8) + 3) / 4); 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 */ #endif /*_IP_SET_H */
#ifndef _IP_SET_TIMEOUT_H #ifndef _IP_SET_TIMEOUT_H
#define _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 * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
...@@ -17,13 +17,14 @@ ...@@ -17,13 +17,14 @@
#define IPSET_GC_PERIOD(timeout) \ #define IPSET_GC_PERIOD(timeout) \
((timeout/3) ? min_t(u32, (timeout)/3, IPSET_GC_TIME) : 1) ((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_NO_TIMEOUT UINT_MAX #define IPSET_ELEM_PERMANENT 0
#define with_timeout(timeout) ((timeout) != IPSET_NO_TIMEOUT) /* Set is defined with timeout support: timeout value may be 0 */
#define IPSET_NO_TIMEOUT UINT_MAX
#define opt_timeout(opt, map) \ #define ip_set_adt_opt_timeout(opt, map) \
(with_timeout((opt)->timeout) ? (opt)->timeout : (map)->timeout) ((opt)->ext.timeout != IPSET_NO_TIMEOUT ? (opt)->ext.timeout : (map)->timeout)
static inline unsigned int static inline unsigned int
ip_set_timeout_uget(struct nlattr *tb) ip_set_timeout_uget(struct nlattr *tb)
...@@ -38,61 +39,6 @@ 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; 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 static inline bool
ip_set_timeout_test(unsigned long timeout) ip_set_timeout_test(unsigned long timeout)
{ {
...@@ -101,36 +47,32 @@ ip_set_timeout_test(unsigned long timeout) ...@@ -101,36 +47,32 @@ ip_set_timeout_test(unsigned long timeout)
} }
static inline bool static inline bool
ip_set_timeout_expired(unsigned long timeout) ip_set_timeout_expired(unsigned long *timeout)
{ {
return timeout != IPSET_ELEM_PERMANENT && return *timeout != IPSET_ELEM_PERMANENT &&
time_is_before_jiffies(timeout); time_is_before_jiffies(*timeout);
} }
static inline unsigned long static inline void
ip_set_timeout_set(u32 timeout) ip_set_timeout_set(unsigned long *timeout, u32 t)
{ {
unsigned long t; if (!t) {
*timeout = IPSET_ELEM_PERMANENT;
if (!timeout) return;
return IPSET_ELEM_PERMANENT; }
t = msecs_to_jiffies(timeout * 1000) + jiffies; *timeout = msecs_to_jiffies(t * 1000) + jiffies;
if (t == IPSET_ELEM_PERMANENT) if (*timeout == IPSET_ELEM_PERMANENT)
/* Bingo! :-) */ /* Bingo! :-) */
t++; (*timeout)--;
return t;
} }
static inline u32 static inline u32
ip_set_timeout_get(unsigned long timeout) ip_set_timeout_get(unsigned long *timeout)
{ {
return timeout == IPSET_ELEM_PERMANENT ? 0 : return *timeout == IPSET_ELEM_PERMANENT ? 0 :
jiffies_to_msecs(timeout - jiffies)/1000; jiffies_to_msecs(*timeout - jiffies)/1000;
} }
#endif /* ! IP_SET_BITMAP_TIMEOUT */
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
#endif /* _IP_SET_TIMEOUT_H */ #endif /* _IP_SET_TIMEOUT_H */
/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu> /* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
* Patrick Schaaf <bof@bof.de> * Patrick Schaaf <bof@bof.de>
* 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 * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
...@@ -315,6 +315,19 @@ ip_set_get_ipaddr6(struct nlattr *nla, union nf_inet_addr *ipaddr) ...@@ -315,6 +315,19 @@ ip_set_get_ipaddr6(struct nlattr *nla, union nf_inet_addr *ipaddr)
} }
EXPORT_SYMBOL_GPL(ip_set_get_ipaddr6); 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 * Creating/destroying/renaming/swapping affect the existence and
* the properties of a set. All of these can be executed from userspace * 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) ...@@ -365,8 +378,7 @@ ip_set_rcu_get(ip_set_id_t index)
int int
ip_set_test(ip_set_id_t index, const struct sk_buff *skb, ip_set_test(ip_set_id_t index, const struct sk_buff *skb,
const struct xt_action_param *par, const struct xt_action_param *par, struct ip_set_adt_opt *opt)
const struct ip_set_adt_opt *opt)
{ {
struct ip_set *set = ip_set_rcu_get(index); struct ip_set *set = ip_set_rcu_get(index);
int ret = 0; int ret = 0;
...@@ -404,8 +416,7 @@ EXPORT_SYMBOL_GPL(ip_set_test); ...@@ -404,8 +416,7 @@ EXPORT_SYMBOL_GPL(ip_set_test);
int int
ip_set_add(ip_set_id_t index, const struct sk_buff *skb, ip_set_add(ip_set_id_t index, const struct sk_buff *skb,
const struct xt_action_param *par, const struct xt_action_param *par, struct ip_set_adt_opt *opt)
const struct ip_set_adt_opt *opt)
{ {
struct ip_set *set = ip_set_rcu_get(index); struct ip_set *set = ip_set_rcu_get(index);
int ret; int ret;
...@@ -427,8 +438,7 @@ EXPORT_SYMBOL_GPL(ip_set_add); ...@@ -427,8 +438,7 @@ EXPORT_SYMBOL_GPL(ip_set_add);
int int
ip_set_del(ip_set_id_t index, const struct sk_buff *skb, ip_set_del(ip_set_id_t index, const struct sk_buff *skb,
const struct xt_action_param *par, const struct xt_action_param *par, struct ip_set_adt_opt *opt)
const struct ip_set_adt_opt *opt)
{ {
struct ip_set *set = ip_set_rcu_get(index); struct ip_set *set = ip_set_rcu_get(index);
int ret = 0; int ret = 0;
......
/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu> /* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
* Patrick Schaaf <bof@bof.de> * Patrick Schaaf <bof@bof.de>
* Martin Josefsson <gandalf@wlug.westbo.se> * Martin Josefsson <gandalf@wlug.westbo.se>
* Copyright (C) 2003-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 * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
...@@ -30,7 +30,7 @@ MODULE_ALIAS("ip6t_SET"); ...@@ -30,7 +30,7 @@ MODULE_ALIAS("ip6t_SET");
static inline int static inline int
match_set(ip_set_id_t index, const struct sk_buff *skb, match_set(ip_set_id_t index, const struct sk_buff *skb,
const struct xt_action_param *par, 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)) if (ip_set_test(index, skb, par, opt))
inv = !inv; inv = !inv;
...@@ -38,20 +38,12 @@ match_set(ip_set_id_t index, const struct sk_buff *skb, ...@@ -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) \ #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 = { \ struct ip_set_adt_opt n = { \
.family = f, \ .family = f, \
.dim = d, \ .dim = d, \
.flags = fs, \ .flags = fs, \
.cmdflags = cfs, \ .cmdflags = cfs, \
.timeout = t, \ .ext.timeout = t, \
} }
/* Revision 0 interface: backward compatible with netfilter/iptables */ /* Revision 0 interface: backward compatible with netfilter/iptables */
...@@ -305,15 +297,15 @@ static unsigned int ...@@ -305,15 +297,15 @@ static unsigned int
set_target_v2(struct sk_buff *skb, const struct xt_action_param *par) set_target_v2(struct sk_buff *skb, const struct xt_action_param *par)
{ {
const struct xt_set_info_target_v2 *info = par->targinfo; const struct xt_set_info_target_v2 *info = par->targinfo;
ADT_MOPT(add_opt, par->family, info->add_set.dim, ADT_OPT(add_opt, par->family, info->add_set.dim,
info->add_set.flags, info->flags, info->timeout); info->add_set.flags, info->flags, info->timeout);
ADT_OPT(del_opt, par->family, info->del_set.dim, ADT_OPT(del_opt, par->family, info->del_set.dim,
info->del_set.flags, 0, UINT_MAX); info->del_set.flags, 0, UINT_MAX);
/* Normalize to fit into jiffies */ /* Normalize to fit into jiffies */
if (add_opt.timeout != IPSET_NO_TIMEOUT && if (add_opt.ext.timeout != IPSET_NO_TIMEOUT &&
add_opt.timeout > UINT_MAX/MSEC_PER_SEC) add_opt.ext.timeout > UINT_MAX/MSEC_PER_SEC)
add_opt.timeout = UINT_MAX/MSEC_PER_SEC; add_opt.ext.timeout = UINT_MAX/MSEC_PER_SEC;
if (info->add_set.index != IPSET_INVALID_ID) if (info->add_set.index != IPSET_INVALID_ID)
ip_set_add(info->add_set.index, skb, par, &add_opt); ip_set_add(info->add_set.index, skb, par, &add_opt);
if (info->del_set.index != IPSET_INVALID_ID) 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, ...@@ -83,7 +83,7 @@ static int em_ipset_match(struct sk_buff *skb, struct tcf_ematch *em,
opt.dim = set->dim; opt.dim = set->dim;
opt.flags = set->flags; opt.flags = set->flags;
opt.cmdflags = 0; opt.cmdflags = 0;
opt.timeout = ~0u; opt.ext.timeout = ~0u;
network_offset = skb_network_offset(skb); network_offset = skb_network_offset(skb);
skb_pull(skb, network_offset); skb_pull(skb, network_offset);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment