Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+39 −7
Original line number Diff line number Diff line
/* 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 */
+22 −80
Original line number Diff line number Diff line
#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 */
#define IPSET_NO_TIMEOUT	UINT_MAX
/* Entry is set with no timeout value */
#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)	\
	(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 (!timeout)
		return IPSET_ELEM_PERMANENT;
	if (!t) {
		*timeout = IPSET_ELEM_PERMANENT;
		return;
	}

	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 */
+17 −7
Original line number Diff line number Diff line
/* 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;
+8 −16
Original line number Diff line number Diff line
/* 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,
	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)
+1 −1
Original line number Diff line number Diff line
@@ -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);