xref: /openbmc/linux/net/netfilter/xt_set.c (revision 30a2e107)
1d956798dSJozsef Kadlecsik /* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
2d956798dSJozsef Kadlecsik  *                         Patrick Schaaf <bof@bof.de>
3d956798dSJozsef Kadlecsik  *                         Martin Josefsson <gandalf@wlug.westbo.se>
4075e64c0SJozsef Kadlecsik  * Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
5d956798dSJozsef Kadlecsik  *
6d956798dSJozsef Kadlecsik  * This program is free software; you can redistribute it and/or modify
7d956798dSJozsef Kadlecsik  * it under the terms of the GNU General Public License version 2 as
8d956798dSJozsef Kadlecsik  * published by the Free Software Foundation.
9d956798dSJozsef Kadlecsik  */
10d956798dSJozsef Kadlecsik 
11d956798dSJozsef Kadlecsik /* Kernel module which implements the set match and SET target
12ca0f6a5cSJozsef Kadlecsik  * for netfilter/iptables.
13ca0f6a5cSJozsef Kadlecsik  */
14d956798dSJozsef Kadlecsik 
15d956798dSJozsef Kadlecsik #include <linux/module.h>
16d956798dSJozsef Kadlecsik #include <linux/skbuff.h>
17d956798dSJozsef Kadlecsik 
18d956798dSJozsef Kadlecsik #include <linux/netfilter/x_tables.h>
19a9756e6fSJozsef Kadlecsik #include <linux/netfilter/ipset/ip_set.h>
20a73f89a6SJozsef Kadlecsik #include <linux/netfilter/ipset/ip_set_timeout.h>
21a9756e6fSJozsef Kadlecsik #include <uapi/linux/netfilter/xt_set.h>
22d956798dSJozsef Kadlecsik 
23d956798dSJozsef Kadlecsik MODULE_LICENSE("GPL");
24d956798dSJozsef Kadlecsik MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
25d956798dSJozsef Kadlecsik MODULE_DESCRIPTION("Xtables: IP set match and target module");
26d956798dSJozsef Kadlecsik MODULE_ALIAS("xt_SET");
27d956798dSJozsef Kadlecsik MODULE_ALIAS("ipt_set");
28d956798dSJozsef Kadlecsik MODULE_ALIAS("ip6t_set");
29d956798dSJozsef Kadlecsik MODULE_ALIAS("ipt_SET");
30d956798dSJozsef Kadlecsik MODULE_ALIAS("ip6t_SET");
31d956798dSJozsef Kadlecsik 
32d956798dSJozsef Kadlecsik static inline int
33d956798dSJozsef Kadlecsik match_set(ip_set_id_t index, const struct sk_buff *skb,
34b66554cfSJozsef Kadlecsik 	  const struct xt_action_param *par,
35075e64c0SJozsef Kadlecsik 	  struct ip_set_adt_opt *opt, int inv)
36d956798dSJozsef Kadlecsik {
37b66554cfSJozsef Kadlecsik 	if (ip_set_test(index, skb, par, opt))
38d956798dSJozsef Kadlecsik 		inv = !inv;
39d956798dSJozsef Kadlecsik 	return inv;
40d956798dSJozsef Kadlecsik }
41d956798dSJozsef Kadlecsik 
424750005aSJozsef Kadlecsik #define ADT_OPT(n, f, d, fs, cfs, t, p, b, po, bo)	\
43127f5591SJozsef Kadlecsik struct ip_set_adt_opt n = {				\
44127f5591SJozsef Kadlecsik 	.family	= f,					\
45127f5591SJozsef Kadlecsik 	.dim = d,					\
46127f5591SJozsef Kadlecsik 	.flags = fs,					\
47127f5591SJozsef Kadlecsik 	.cmdflags = cfs,				\
48075e64c0SJozsef Kadlecsik 	.ext.timeout = t,				\
494750005aSJozsef Kadlecsik 	.ext.packets = p,				\
504750005aSJozsef Kadlecsik 	.ext.bytes = b,					\
514750005aSJozsef Kadlecsik 	.ext.packets_op = po,				\
524750005aSJozsef Kadlecsik 	.ext.bytes_op = bo,				\
53127f5591SJozsef Kadlecsik }
54ac8cc925SJozsef Kadlecsik 
55d956798dSJozsef Kadlecsik /* Revision 0 interface: backward compatible with netfilter/iptables */
56d956798dSJozsef Kadlecsik 
57d956798dSJozsef Kadlecsik static bool
58d956798dSJozsef Kadlecsik set_match_v0(const struct sk_buff *skb, struct xt_action_param *par)
59d956798dSJozsef Kadlecsik {
60d956798dSJozsef Kadlecsik 	const struct xt_set_info_match_v0 *info = par->matchinfo;
61ca0f6a5cSJozsef Kadlecsik 
62613dbd95SPablo Neira Ayuso 	ADT_OPT(opt, xt_family(par), info->match_set.u.compat.dim,
634750005aSJozsef Kadlecsik 		info->match_set.u.compat.flags, 0, UINT_MAX,
644750005aSJozsef Kadlecsik 		0, 0, 0, 0);
65d956798dSJozsef Kadlecsik 
66b66554cfSJozsef Kadlecsik 	return match_set(info->match_set.index, skb, par, &opt,
67d956798dSJozsef Kadlecsik 			 info->match_set.u.compat.flags & IPSET_INV_MATCH);
68d956798dSJozsef Kadlecsik }
69d956798dSJozsef Kadlecsik 
70d956798dSJozsef Kadlecsik static void
71d956798dSJozsef Kadlecsik compat_flags(struct xt_set_info_v0 *info)
72d956798dSJozsef Kadlecsik {
73d956798dSJozsef Kadlecsik 	u_int8_t i;
74d956798dSJozsef Kadlecsik 
75d956798dSJozsef Kadlecsik 	/* Fill out compatibility data according to enum ip_set_kopt */
76d956798dSJozsef Kadlecsik 	info->u.compat.dim = IPSET_DIM_ZERO;
77d956798dSJozsef Kadlecsik 	if (info->u.flags[0] & IPSET_MATCH_INV)
78d956798dSJozsef Kadlecsik 		info->u.compat.flags |= IPSET_INV_MATCH;
79d956798dSJozsef Kadlecsik 	for (i = 0; i < IPSET_DIM_MAX - 1 && info->u.flags[i]; i++) {
80d956798dSJozsef Kadlecsik 		info->u.compat.dim++;
81d956798dSJozsef Kadlecsik 		if (info->u.flags[i] & IPSET_SRC)
82d956798dSJozsef Kadlecsik 			info->u.compat.flags |= (1 << info->u.compat.dim);
83d956798dSJozsef Kadlecsik 	}
84d956798dSJozsef Kadlecsik }
85d956798dSJozsef Kadlecsik 
86d956798dSJozsef Kadlecsik static int
87d956798dSJozsef Kadlecsik set_match_v0_checkentry(const struct xt_mtchk_param *par)
88d956798dSJozsef Kadlecsik {
89d956798dSJozsef Kadlecsik 	struct xt_set_info_match_v0 *info = par->matchinfo;
90d956798dSJozsef Kadlecsik 	ip_set_id_t index;
91d956798dSJozsef Kadlecsik 
921785e8f4SVitaly Lavrov 	index = ip_set_nfnl_get_byindex(par->net, info->match_set.index);
93d956798dSJozsef Kadlecsik 
94d956798dSJozsef Kadlecsik 	if (index == IPSET_INVALID_ID) {
95c82b31c5SFlorian Westphal 		pr_info_ratelimited("Cannot find set identified by id %u to match\n",
96d956798dSJozsef Kadlecsik 				    info->match_set.index);
97d956798dSJozsef Kadlecsik 		return -ENOENT;
98d956798dSJozsef Kadlecsik 	}
99d956798dSJozsef Kadlecsik 	if (info->match_set.u.flags[IPSET_DIM_MAX - 1] != 0) {
100c82b31c5SFlorian Westphal 		pr_info_ratelimited("set match dimension is over the limit!\n");
1011785e8f4SVitaly Lavrov 		ip_set_nfnl_put(par->net, info->match_set.index);
102d956798dSJozsef Kadlecsik 		return -ERANGE;
103d956798dSJozsef Kadlecsik 	}
104d956798dSJozsef Kadlecsik 
105d956798dSJozsef Kadlecsik 	/* Fill out compatibility data */
106d956798dSJozsef Kadlecsik 	compat_flags(&info->match_set);
107d956798dSJozsef Kadlecsik 
108d956798dSJozsef Kadlecsik 	return 0;
109d956798dSJozsef Kadlecsik }
110d956798dSJozsef Kadlecsik 
111d956798dSJozsef Kadlecsik static void
112d956798dSJozsef Kadlecsik set_match_v0_destroy(const struct xt_mtdtor_param *par)
113d956798dSJozsef Kadlecsik {
114d956798dSJozsef Kadlecsik 	struct xt_set_info_match_v0 *info = par->matchinfo;
115d956798dSJozsef Kadlecsik 
1161785e8f4SVitaly Lavrov 	ip_set_nfnl_put(par->net, info->match_set.index);
117d956798dSJozsef Kadlecsik }
118d956798dSJozsef Kadlecsik 
119bd3129fcSJozsef Kadlecsik /* Revision 1 match */
120bd3129fcSJozsef Kadlecsik 
121bd3129fcSJozsef Kadlecsik static bool
122bd3129fcSJozsef Kadlecsik set_match_v1(const struct sk_buff *skb, struct xt_action_param *par)
123bd3129fcSJozsef Kadlecsik {
124bd3129fcSJozsef Kadlecsik 	const struct xt_set_info_match_v1 *info = par->matchinfo;
125ca0f6a5cSJozsef Kadlecsik 
126613dbd95SPablo Neira Ayuso 	ADT_OPT(opt, xt_family(par), info->match_set.dim,
1274750005aSJozsef Kadlecsik 		info->match_set.flags, 0, UINT_MAX,
1284750005aSJozsef Kadlecsik 		0, 0, 0, 0);
129bd3129fcSJozsef Kadlecsik 
130bd3129fcSJozsef Kadlecsik 	if (opt.flags & IPSET_RETURN_NOMATCH)
131bd3129fcSJozsef Kadlecsik 		opt.cmdflags |= IPSET_FLAG_RETURN_NOMATCH;
132bd3129fcSJozsef Kadlecsik 
133bd3129fcSJozsef Kadlecsik 	return match_set(info->match_set.index, skb, par, &opt,
134bd3129fcSJozsef Kadlecsik 			 info->match_set.flags & IPSET_INV_MATCH);
135bd3129fcSJozsef Kadlecsik }
136bd3129fcSJozsef Kadlecsik 
137bd3129fcSJozsef Kadlecsik static int
138bd3129fcSJozsef Kadlecsik set_match_v1_checkentry(const struct xt_mtchk_param *par)
139bd3129fcSJozsef Kadlecsik {
140bd3129fcSJozsef Kadlecsik 	struct xt_set_info_match_v1 *info = par->matchinfo;
141bd3129fcSJozsef Kadlecsik 	ip_set_id_t index;
142bd3129fcSJozsef Kadlecsik 
1431785e8f4SVitaly Lavrov 	index = ip_set_nfnl_get_byindex(par->net, info->match_set.index);
144bd3129fcSJozsef Kadlecsik 
145bd3129fcSJozsef Kadlecsik 	if (index == IPSET_INVALID_ID) {
146c82b31c5SFlorian Westphal 		pr_info_ratelimited("Cannot find set identified by id %u to match\n",
147bd3129fcSJozsef Kadlecsik 				    info->match_set.index);
148bd3129fcSJozsef Kadlecsik 		return -ENOENT;
149bd3129fcSJozsef Kadlecsik 	}
150bd3129fcSJozsef Kadlecsik 	if (info->match_set.dim > IPSET_DIM_MAX) {
151c82b31c5SFlorian Westphal 		pr_info_ratelimited("set match dimension is over the limit!\n");
1521785e8f4SVitaly Lavrov 		ip_set_nfnl_put(par->net, info->match_set.index);
153bd3129fcSJozsef Kadlecsik 		return -ERANGE;
154bd3129fcSJozsef Kadlecsik 	}
155bd3129fcSJozsef Kadlecsik 
156bd3129fcSJozsef Kadlecsik 	return 0;
157bd3129fcSJozsef Kadlecsik }
158bd3129fcSJozsef Kadlecsik 
159bd3129fcSJozsef Kadlecsik static void
160bd3129fcSJozsef Kadlecsik set_match_v1_destroy(const struct xt_mtdtor_param *par)
161bd3129fcSJozsef Kadlecsik {
162bd3129fcSJozsef Kadlecsik 	struct xt_set_info_match_v1 *info = par->matchinfo;
163bd3129fcSJozsef Kadlecsik 
1641785e8f4SVitaly Lavrov 	ip_set_nfnl_put(par->net, info->match_set.index);
165bd3129fcSJozsef Kadlecsik }
166bd3129fcSJozsef Kadlecsik 
167bd3129fcSJozsef Kadlecsik /* Revision 3 match */
168bd3129fcSJozsef Kadlecsik 
169bd3129fcSJozsef Kadlecsik static bool
170bd3129fcSJozsef Kadlecsik set_match_v3(const struct sk_buff *skb, struct xt_action_param *par)
171bd3129fcSJozsef Kadlecsik {
172bd3129fcSJozsef Kadlecsik 	const struct xt_set_info_match_v3 *info = par->matchinfo;
173ca0f6a5cSJozsef Kadlecsik 
174613dbd95SPablo Neira Ayuso 	ADT_OPT(opt, xt_family(par), info->match_set.dim,
1754750005aSJozsef Kadlecsik 		info->match_set.flags, info->flags, UINT_MAX,
1764750005aSJozsef Kadlecsik 		info->packets.value, info->bytes.value,
1774750005aSJozsef Kadlecsik 		info->packets.op, info->bytes.op);
178bd3129fcSJozsef Kadlecsik 
179bd3129fcSJozsef Kadlecsik 	if (info->packets.op != IPSET_COUNTER_NONE ||
180bd3129fcSJozsef Kadlecsik 	    info->bytes.op != IPSET_COUNTER_NONE)
181bd3129fcSJozsef Kadlecsik 		opt.cmdflags |= IPSET_FLAG_MATCH_COUNTERS;
182bd3129fcSJozsef Kadlecsik 
1834750005aSJozsef Kadlecsik 	return match_set(info->match_set.index, skb, par, &opt,
184bd3129fcSJozsef Kadlecsik 			 info->match_set.flags & IPSET_INV_MATCH);
185a51b9199SJozsef Kadlecsik }
186a51b9199SJozsef Kadlecsik 
187a51b9199SJozsef Kadlecsik #define set_match_v3_checkentry	set_match_v1_checkentry
188a51b9199SJozsef Kadlecsik #define set_match_v3_destroy	set_match_v1_destroy
189a51b9199SJozsef Kadlecsik 
190a51b9199SJozsef Kadlecsik /* Revision 4 match */
191a51b9199SJozsef Kadlecsik 
192a51b9199SJozsef Kadlecsik static bool
193a51b9199SJozsef Kadlecsik set_match_v4(const struct sk_buff *skb, struct xt_action_param *par)
194a51b9199SJozsef Kadlecsik {
195a51b9199SJozsef Kadlecsik 	const struct xt_set_info_match_v4 *info = par->matchinfo;
196ca0f6a5cSJozsef Kadlecsik 
197613dbd95SPablo Neira Ayuso 	ADT_OPT(opt, xt_family(par), info->match_set.dim,
1984750005aSJozsef Kadlecsik 		info->match_set.flags, info->flags, UINT_MAX,
1994750005aSJozsef Kadlecsik 		info->packets.value, info->bytes.value,
2004750005aSJozsef Kadlecsik 		info->packets.op, info->bytes.op);
201a51b9199SJozsef Kadlecsik 
202a51b9199SJozsef Kadlecsik 	if (info->packets.op != IPSET_COUNTER_NONE ||
203a51b9199SJozsef Kadlecsik 	    info->bytes.op != IPSET_COUNTER_NONE)
204a51b9199SJozsef Kadlecsik 		opt.cmdflags |= IPSET_FLAG_MATCH_COUNTERS;
205a51b9199SJozsef Kadlecsik 
2064750005aSJozsef Kadlecsik 	return match_set(info->match_set.index, skb, par, &opt,
207a51b9199SJozsef Kadlecsik 			 info->match_set.flags & IPSET_INV_MATCH);
208bd3129fcSJozsef Kadlecsik }
209bd3129fcSJozsef Kadlecsik 
210a51b9199SJozsef Kadlecsik #define set_match_v4_checkentry	set_match_v1_checkentry
211a51b9199SJozsef Kadlecsik #define set_match_v4_destroy	set_match_v1_destroy
212bd3129fcSJozsef Kadlecsik 
213bd3129fcSJozsef Kadlecsik /* Revision 0 interface: backward compatible with netfilter/iptables */
214bd3129fcSJozsef Kadlecsik 
215d956798dSJozsef Kadlecsik static unsigned int
216d956798dSJozsef Kadlecsik set_target_v0(struct sk_buff *skb, const struct xt_action_param *par)
217d956798dSJozsef Kadlecsik {
218d956798dSJozsef Kadlecsik 	const struct xt_set_info_target_v0 *info = par->targinfo;
219ca0f6a5cSJozsef Kadlecsik 
220613dbd95SPablo Neira Ayuso 	ADT_OPT(add_opt, xt_family(par), info->add_set.u.compat.dim,
2214750005aSJozsef Kadlecsik 		info->add_set.u.compat.flags, 0, UINT_MAX,
2224750005aSJozsef Kadlecsik 		0, 0, 0, 0);
223613dbd95SPablo Neira Ayuso 	ADT_OPT(del_opt, xt_family(par), info->del_set.u.compat.dim,
2244750005aSJozsef Kadlecsik 		info->del_set.u.compat.flags, 0, UINT_MAX,
2254750005aSJozsef Kadlecsik 		0, 0, 0, 0);
226d956798dSJozsef Kadlecsik 
227d956798dSJozsef Kadlecsik 	if (info->add_set.index != IPSET_INVALID_ID)
228b66554cfSJozsef Kadlecsik 		ip_set_add(info->add_set.index, skb, par, &add_opt);
229d956798dSJozsef Kadlecsik 	if (info->del_set.index != IPSET_INVALID_ID)
230b66554cfSJozsef Kadlecsik 		ip_set_del(info->del_set.index, skb, par, &del_opt);
231d956798dSJozsef Kadlecsik 
232d956798dSJozsef Kadlecsik 	return XT_CONTINUE;
233d956798dSJozsef Kadlecsik }
234d956798dSJozsef Kadlecsik 
235d956798dSJozsef Kadlecsik static int
236d956798dSJozsef Kadlecsik set_target_v0_checkentry(const struct xt_tgchk_param *par)
237d956798dSJozsef Kadlecsik {
238d956798dSJozsef Kadlecsik 	struct xt_set_info_target_v0 *info = par->targinfo;
239d956798dSJozsef Kadlecsik 	ip_set_id_t index;
240d956798dSJozsef Kadlecsik 
241d956798dSJozsef Kadlecsik 	if (info->add_set.index != IPSET_INVALID_ID) {
2421785e8f4SVitaly Lavrov 		index = ip_set_nfnl_get_byindex(par->net, info->add_set.index);
243d956798dSJozsef Kadlecsik 		if (index == IPSET_INVALID_ID) {
244c82b31c5SFlorian Westphal 			pr_info_ratelimited("Cannot find add_set index %u as target\n",
245d956798dSJozsef Kadlecsik 					    info->add_set.index);
246d956798dSJozsef Kadlecsik 			return -ENOENT;
247d956798dSJozsef Kadlecsik 		}
248d956798dSJozsef Kadlecsik 	}
249d956798dSJozsef Kadlecsik 
250d956798dSJozsef Kadlecsik 	if (info->del_set.index != IPSET_INVALID_ID) {
2511785e8f4SVitaly Lavrov 		index = ip_set_nfnl_get_byindex(par->net, info->del_set.index);
252d956798dSJozsef Kadlecsik 		if (index == IPSET_INVALID_ID) {
253c82b31c5SFlorian Westphal 			pr_info_ratelimited("Cannot find del_set index %u as target\n",
254d956798dSJozsef Kadlecsik 					    info->del_set.index);
255eafbd3fdSJozsef Kadlecsik 			if (info->add_set.index != IPSET_INVALID_ID)
2561785e8f4SVitaly Lavrov 				ip_set_nfnl_put(par->net, info->add_set.index);
257d956798dSJozsef Kadlecsik 			return -ENOENT;
258d956798dSJozsef Kadlecsik 		}
259d956798dSJozsef Kadlecsik 	}
260d956798dSJozsef Kadlecsik 	if (info->add_set.u.flags[IPSET_DIM_MAX - 1] != 0 ||
261d956798dSJozsef Kadlecsik 	    info->del_set.u.flags[IPSET_DIM_MAX - 1] != 0) {
262c82b31c5SFlorian Westphal 		pr_info_ratelimited("SET target dimension over the limit!\n");
263eafbd3fdSJozsef Kadlecsik 		if (info->add_set.index != IPSET_INVALID_ID)
2641785e8f4SVitaly Lavrov 			ip_set_nfnl_put(par->net, info->add_set.index);
265eafbd3fdSJozsef Kadlecsik 		if (info->del_set.index != IPSET_INVALID_ID)
2661785e8f4SVitaly Lavrov 			ip_set_nfnl_put(par->net, info->del_set.index);
267d956798dSJozsef Kadlecsik 		return -ERANGE;
268d956798dSJozsef Kadlecsik 	}
269d956798dSJozsef Kadlecsik 
270d956798dSJozsef Kadlecsik 	/* Fill out compatibility data */
271d956798dSJozsef Kadlecsik 	compat_flags(&info->add_set);
272d956798dSJozsef Kadlecsik 	compat_flags(&info->del_set);
273d956798dSJozsef Kadlecsik 
274d956798dSJozsef Kadlecsik 	return 0;
275d956798dSJozsef Kadlecsik }
276d956798dSJozsef Kadlecsik 
277d956798dSJozsef Kadlecsik static void
278d956798dSJozsef Kadlecsik set_target_v0_destroy(const struct xt_tgdtor_param *par)
279d956798dSJozsef Kadlecsik {
280d956798dSJozsef Kadlecsik 	const struct xt_set_info_target_v0 *info = par->targinfo;
281d956798dSJozsef Kadlecsik 
282d956798dSJozsef Kadlecsik 	if (info->add_set.index != IPSET_INVALID_ID)
2831785e8f4SVitaly Lavrov 		ip_set_nfnl_put(par->net, info->add_set.index);
284d956798dSJozsef Kadlecsik 	if (info->del_set.index != IPSET_INVALID_ID)
2851785e8f4SVitaly Lavrov 		ip_set_nfnl_put(par->net, info->del_set.index);
286d956798dSJozsef Kadlecsik }
287d956798dSJozsef Kadlecsik 
288bd3129fcSJozsef Kadlecsik /* Revision 1 target */
289d956798dSJozsef Kadlecsik 
290d956798dSJozsef Kadlecsik static unsigned int
291ac8cc925SJozsef Kadlecsik set_target_v1(struct sk_buff *skb, const struct xt_action_param *par)
292d956798dSJozsef Kadlecsik {
293ac8cc925SJozsef Kadlecsik 	const struct xt_set_info_target_v1 *info = par->targinfo;
294ca0f6a5cSJozsef Kadlecsik 
295613dbd95SPablo Neira Ayuso 	ADT_OPT(add_opt, xt_family(par), info->add_set.dim,
2964750005aSJozsef Kadlecsik 		info->add_set.flags, 0, UINT_MAX,
2974750005aSJozsef Kadlecsik 		0, 0, 0, 0);
298613dbd95SPablo Neira Ayuso 	ADT_OPT(del_opt, xt_family(par), info->del_set.dim,
2994750005aSJozsef Kadlecsik 		info->del_set.flags, 0, UINT_MAX,
3004750005aSJozsef Kadlecsik 		0, 0, 0, 0);
301d956798dSJozsef Kadlecsik 
302d956798dSJozsef Kadlecsik 	if (info->add_set.index != IPSET_INVALID_ID)
303b66554cfSJozsef Kadlecsik 		ip_set_add(info->add_set.index, skb, par, &add_opt);
304d956798dSJozsef Kadlecsik 	if (info->del_set.index != IPSET_INVALID_ID)
305b66554cfSJozsef Kadlecsik 		ip_set_del(info->del_set.index, skb, par, &del_opt);
306d956798dSJozsef Kadlecsik 
307d956798dSJozsef Kadlecsik 	return XT_CONTINUE;
308d956798dSJozsef Kadlecsik }
309d956798dSJozsef Kadlecsik 
310d956798dSJozsef Kadlecsik static int
311ac8cc925SJozsef Kadlecsik set_target_v1_checkentry(const struct xt_tgchk_param *par)
312d956798dSJozsef Kadlecsik {
313ac8cc925SJozsef Kadlecsik 	const struct xt_set_info_target_v1 *info = par->targinfo;
314d956798dSJozsef Kadlecsik 	ip_set_id_t index;
315d956798dSJozsef Kadlecsik 
316d956798dSJozsef Kadlecsik 	if (info->add_set.index != IPSET_INVALID_ID) {
3171785e8f4SVitaly Lavrov 		index = ip_set_nfnl_get_byindex(par->net, info->add_set.index);
318d956798dSJozsef Kadlecsik 		if (index == IPSET_INVALID_ID) {
319c82b31c5SFlorian Westphal 			pr_info_ratelimited("Cannot find add_set index %u as target\n",
320d956798dSJozsef Kadlecsik 					    info->add_set.index);
321d956798dSJozsef Kadlecsik 			return -ENOENT;
322d956798dSJozsef Kadlecsik 		}
323d956798dSJozsef Kadlecsik 	}
324d956798dSJozsef Kadlecsik 
325d956798dSJozsef Kadlecsik 	if (info->del_set.index != IPSET_INVALID_ID) {
3261785e8f4SVitaly Lavrov 		index = ip_set_nfnl_get_byindex(par->net, info->del_set.index);
327d956798dSJozsef Kadlecsik 		if (index == IPSET_INVALID_ID) {
328c82b31c5SFlorian Westphal 			pr_info_ratelimited("Cannot find del_set index %u as target\n",
329d956798dSJozsef Kadlecsik 					    info->del_set.index);
330eafbd3fdSJozsef Kadlecsik 			if (info->add_set.index != IPSET_INVALID_ID)
3311785e8f4SVitaly Lavrov 				ip_set_nfnl_put(par->net, info->add_set.index);
332d956798dSJozsef Kadlecsik 			return -ENOENT;
333d956798dSJozsef Kadlecsik 		}
334d956798dSJozsef Kadlecsik 	}
335d956798dSJozsef Kadlecsik 	if (info->add_set.dim > IPSET_DIM_MAX ||
336eafbd3fdSJozsef Kadlecsik 	    info->del_set.dim > IPSET_DIM_MAX) {
337c82b31c5SFlorian Westphal 		pr_info_ratelimited("SET target dimension over the limit!\n");
338eafbd3fdSJozsef Kadlecsik 		if (info->add_set.index != IPSET_INVALID_ID)
3391785e8f4SVitaly Lavrov 			ip_set_nfnl_put(par->net, info->add_set.index);
340eafbd3fdSJozsef Kadlecsik 		if (info->del_set.index != IPSET_INVALID_ID)
3411785e8f4SVitaly Lavrov 			ip_set_nfnl_put(par->net, info->del_set.index);
342d956798dSJozsef Kadlecsik 		return -ERANGE;
343d956798dSJozsef Kadlecsik 	}
344d956798dSJozsef Kadlecsik 
345d956798dSJozsef Kadlecsik 	return 0;
346d956798dSJozsef Kadlecsik }
347d956798dSJozsef Kadlecsik 
348d956798dSJozsef Kadlecsik static void
349ac8cc925SJozsef Kadlecsik set_target_v1_destroy(const struct xt_tgdtor_param *par)
350d956798dSJozsef Kadlecsik {
351ac8cc925SJozsef Kadlecsik 	const struct xt_set_info_target_v1 *info = par->targinfo;
352d956798dSJozsef Kadlecsik 
353d956798dSJozsef Kadlecsik 	if (info->add_set.index != IPSET_INVALID_ID)
3541785e8f4SVitaly Lavrov 		ip_set_nfnl_put(par->net, info->add_set.index);
355d956798dSJozsef Kadlecsik 	if (info->del_set.index != IPSET_INVALID_ID)
3561785e8f4SVitaly Lavrov 		ip_set_nfnl_put(par->net, info->del_set.index);
357d956798dSJozsef Kadlecsik }
358d956798dSJozsef Kadlecsik 
359ac8cc925SJozsef Kadlecsik /* Revision 2 target */
360ac8cc925SJozsef Kadlecsik 
361ac8cc925SJozsef Kadlecsik static unsigned int
362ac8cc925SJozsef Kadlecsik set_target_v2(struct sk_buff *skb, const struct xt_action_param *par)
363ac8cc925SJozsef Kadlecsik {
364ac8cc925SJozsef Kadlecsik 	const struct xt_set_info_target_v2 *info = par->targinfo;
365ca0f6a5cSJozsef Kadlecsik 
366613dbd95SPablo Neira Ayuso 	ADT_OPT(add_opt, xt_family(par), info->add_set.dim,
3674750005aSJozsef Kadlecsik 		info->add_set.flags, info->flags, info->timeout,
3684750005aSJozsef Kadlecsik 		0, 0, 0, 0);
369613dbd95SPablo Neira Ayuso 	ADT_OPT(del_opt, xt_family(par), info->del_set.dim,
3704750005aSJozsef Kadlecsik 		info->del_set.flags, 0, UINT_MAX,
3714750005aSJozsef Kadlecsik 		0, 0, 0, 0);
372ac8cc925SJozsef Kadlecsik 
373127f5591SJozsef Kadlecsik 	/* Normalize to fit into jiffies */
374075e64c0SJozsef Kadlecsik 	if (add_opt.ext.timeout != IPSET_NO_TIMEOUT &&
37530a2e107SJozsef Kadlecsik 	    add_opt.ext.timeout > IPSET_MAX_TIMEOUT)
37630a2e107SJozsef Kadlecsik 		add_opt.ext.timeout = IPSET_MAX_TIMEOUT;
377ac8cc925SJozsef Kadlecsik 	if (info->add_set.index != IPSET_INVALID_ID)
378b66554cfSJozsef Kadlecsik 		ip_set_add(info->add_set.index, skb, par, &add_opt);
379ac8cc925SJozsef Kadlecsik 	if (info->del_set.index != IPSET_INVALID_ID)
380b66554cfSJozsef Kadlecsik 		ip_set_del(info->del_set.index, skb, par, &del_opt);
381ac8cc925SJozsef Kadlecsik 
382ac8cc925SJozsef Kadlecsik 	return XT_CONTINUE;
383ac8cc925SJozsef Kadlecsik }
384ac8cc925SJozsef Kadlecsik 
385ac8cc925SJozsef Kadlecsik #define set_target_v2_checkentry	set_target_v1_checkentry
386ac8cc925SJozsef Kadlecsik #define set_target_v2_destroy		set_target_v1_destroy
387ac8cc925SJozsef Kadlecsik 
38876cea410SAnton Danilov /* Revision 3 target */
38976cea410SAnton Danilov 
390bec810d9SJozsef Kadlecsik #define MOPT(opt, member)	((opt).ext.skbinfo.member)
391bec810d9SJozsef Kadlecsik 
39276cea410SAnton Danilov static unsigned int
39376cea410SAnton Danilov set_target_v3(struct sk_buff *skb, const struct xt_action_param *par)
39476cea410SAnton Danilov {
39576cea410SAnton Danilov 	const struct xt_set_info_target_v3 *info = par->targinfo;
396ca0f6a5cSJozsef Kadlecsik 	int ret;
397ca0f6a5cSJozsef Kadlecsik 
398613dbd95SPablo Neira Ayuso 	ADT_OPT(add_opt, xt_family(par), info->add_set.dim,
3994750005aSJozsef Kadlecsik 		info->add_set.flags, info->flags, info->timeout,
4004750005aSJozsef Kadlecsik 		0, 0, 0, 0);
401613dbd95SPablo Neira Ayuso 	ADT_OPT(del_opt, xt_family(par), info->del_set.dim,
4024750005aSJozsef Kadlecsik 		info->del_set.flags, 0, UINT_MAX,
4034750005aSJozsef Kadlecsik 		0, 0, 0, 0);
404613dbd95SPablo Neira Ayuso 	ADT_OPT(map_opt, xt_family(par), info->map_set.dim,
4054750005aSJozsef Kadlecsik 		info->map_set.flags, 0, UINT_MAX,
4064750005aSJozsef Kadlecsik 		0, 0, 0, 0);
40776cea410SAnton Danilov 
40876cea410SAnton Danilov 	/* Normalize to fit into jiffies */
40976cea410SAnton Danilov 	if (add_opt.ext.timeout != IPSET_NO_TIMEOUT &&
41030a2e107SJozsef Kadlecsik 	    add_opt.ext.timeout > IPSET_MAX_TIMEOUT)
41130a2e107SJozsef Kadlecsik 		add_opt.ext.timeout = IPSET_MAX_TIMEOUT;
41276cea410SAnton Danilov 	if (info->add_set.index != IPSET_INVALID_ID)
41376cea410SAnton Danilov 		ip_set_add(info->add_set.index, skb, par, &add_opt);
41476cea410SAnton Danilov 	if (info->del_set.index != IPSET_INVALID_ID)
41576cea410SAnton Danilov 		ip_set_del(info->del_set.index, skb, par, &del_opt);
41676cea410SAnton Danilov 	if (info->map_set.index != IPSET_INVALID_ID) {
41776cea410SAnton Danilov 		map_opt.cmdflags |= info->flags & (IPSET_FLAG_MAP_SKBMARK |
41876cea410SAnton Danilov 						   IPSET_FLAG_MAP_SKBPRIO |
41976cea410SAnton Danilov 						   IPSET_FLAG_MAP_SKBQUEUE);
42076cea410SAnton Danilov 		ret = match_set(info->map_set.index, skb, par, &map_opt,
42176cea410SAnton Danilov 				info->map_set.flags & IPSET_INV_MATCH);
42276cea410SAnton Danilov 		if (!ret)
42376cea410SAnton Danilov 			return XT_CONTINUE;
42476cea410SAnton Danilov 		if (map_opt.cmdflags & IPSET_FLAG_MAP_SKBMARK)
425bec810d9SJozsef Kadlecsik 			skb->mark = (skb->mark & ~MOPT(map_opt,skbmarkmask))
426bec810d9SJozsef Kadlecsik 				    ^ MOPT(map_opt, skbmark);
42776cea410SAnton Danilov 		if (map_opt.cmdflags & IPSET_FLAG_MAP_SKBPRIO)
428bec810d9SJozsef Kadlecsik 			skb->priority = MOPT(map_opt, skbprio);
42976cea410SAnton Danilov 		if ((map_opt.cmdflags & IPSET_FLAG_MAP_SKBQUEUE) &&
43076cea410SAnton Danilov 		    skb->dev &&
431bec810d9SJozsef Kadlecsik 		    skb->dev->real_num_tx_queues > MOPT(map_opt, skbqueue))
432bec810d9SJozsef Kadlecsik 			skb_set_queue_mapping(skb, MOPT(map_opt, skbqueue));
43376cea410SAnton Danilov 	}
43476cea410SAnton Danilov 	return XT_CONTINUE;
43576cea410SAnton Danilov }
43676cea410SAnton Danilov 
43776cea410SAnton Danilov static int
43876cea410SAnton Danilov set_target_v3_checkentry(const struct xt_tgchk_param *par)
43976cea410SAnton Danilov {
44076cea410SAnton Danilov 	const struct xt_set_info_target_v3 *info = par->targinfo;
44176cea410SAnton Danilov 	ip_set_id_t index;
44276cea410SAnton Danilov 
44376cea410SAnton Danilov 	if (info->add_set.index != IPSET_INVALID_ID) {
44476cea410SAnton Danilov 		index = ip_set_nfnl_get_byindex(par->net,
44576cea410SAnton Danilov 						info->add_set.index);
44676cea410SAnton Danilov 		if (index == IPSET_INVALID_ID) {
447c82b31c5SFlorian Westphal 			pr_info_ratelimited("Cannot find add_set index %u as target\n",
44876cea410SAnton Danilov 					    info->add_set.index);
44976cea410SAnton Danilov 			return -ENOENT;
45076cea410SAnton Danilov 		}
45176cea410SAnton Danilov 	}
45276cea410SAnton Danilov 
45376cea410SAnton Danilov 	if (info->del_set.index != IPSET_INVALID_ID) {
45476cea410SAnton Danilov 		index = ip_set_nfnl_get_byindex(par->net,
45576cea410SAnton Danilov 						info->del_set.index);
45676cea410SAnton Danilov 		if (index == IPSET_INVALID_ID) {
457c82b31c5SFlorian Westphal 			pr_info_ratelimited("Cannot find del_set index %u as target\n",
45876cea410SAnton Danilov 					    info->del_set.index);
45976cea410SAnton Danilov 			if (info->add_set.index != IPSET_INVALID_ID)
46076cea410SAnton Danilov 				ip_set_nfnl_put(par->net,
46176cea410SAnton Danilov 						info->add_set.index);
46276cea410SAnton Danilov 			return -ENOENT;
46376cea410SAnton Danilov 		}
46476cea410SAnton Danilov 	}
46576cea410SAnton Danilov 
46676cea410SAnton Danilov 	if (info->map_set.index != IPSET_INVALID_ID) {
46776cea410SAnton Danilov 		if (strncmp(par->table, "mangle", 7)) {
468c82b31c5SFlorian Westphal 			pr_info_ratelimited("--map-set only usable from mangle table\n");
46976cea410SAnton Danilov 			return -EINVAL;
47076cea410SAnton Danilov 		}
47176cea410SAnton Danilov 		if (((info->flags & IPSET_FLAG_MAP_SKBPRIO) |
47276cea410SAnton Danilov 		     (info->flags & IPSET_FLAG_MAP_SKBQUEUE)) &&
4739dcceb13SSerhey Popovych 		     (par->hook_mask & ~(1 << NF_INET_FORWARD |
47476cea410SAnton Danilov 					 1 << NF_INET_LOCAL_OUT |
47576cea410SAnton Danilov 					 1 << NF_INET_POST_ROUTING))) {
476c82b31c5SFlorian Westphal 			pr_info_ratelimited("mapping of prio or/and queue is allowed only from OUTPUT/FORWARD/POSTROUTING chains\n");
47776cea410SAnton Danilov 			return -EINVAL;
47876cea410SAnton Danilov 		}
47976cea410SAnton Danilov 		index = ip_set_nfnl_get_byindex(par->net,
48076cea410SAnton Danilov 						info->map_set.index);
48176cea410SAnton Danilov 		if (index == IPSET_INVALID_ID) {
482c82b31c5SFlorian Westphal 			pr_info_ratelimited("Cannot find map_set index %u as target\n",
48376cea410SAnton Danilov 					    info->map_set.index);
48476cea410SAnton Danilov 			if (info->add_set.index != IPSET_INVALID_ID)
48576cea410SAnton Danilov 				ip_set_nfnl_put(par->net,
48676cea410SAnton Danilov 						info->add_set.index);
48776cea410SAnton Danilov 			if (info->del_set.index != IPSET_INVALID_ID)
48876cea410SAnton Danilov 				ip_set_nfnl_put(par->net,
48976cea410SAnton Danilov 						info->del_set.index);
49076cea410SAnton Danilov 			return -ENOENT;
49176cea410SAnton Danilov 		}
49276cea410SAnton Danilov 	}
49376cea410SAnton Danilov 
49476cea410SAnton Danilov 	if (info->add_set.dim > IPSET_DIM_MAX ||
49576cea410SAnton Danilov 	    info->del_set.dim > IPSET_DIM_MAX ||
49676cea410SAnton Danilov 	    info->map_set.dim > IPSET_DIM_MAX) {
497c82b31c5SFlorian Westphal 		pr_info_ratelimited("SET target dimension over the limit!\n");
49876cea410SAnton Danilov 		if (info->add_set.index != IPSET_INVALID_ID)
49976cea410SAnton Danilov 			ip_set_nfnl_put(par->net, info->add_set.index);
50076cea410SAnton Danilov 		if (info->del_set.index != IPSET_INVALID_ID)
50176cea410SAnton Danilov 			ip_set_nfnl_put(par->net, info->del_set.index);
50276cea410SAnton Danilov 		if (info->map_set.index != IPSET_INVALID_ID)
50376cea410SAnton Danilov 			ip_set_nfnl_put(par->net, info->map_set.index);
50476cea410SAnton Danilov 		return -ERANGE;
50576cea410SAnton Danilov 	}
50676cea410SAnton Danilov 
50776cea410SAnton Danilov 	return 0;
50876cea410SAnton Danilov }
50976cea410SAnton Danilov 
51076cea410SAnton Danilov static void
51176cea410SAnton Danilov set_target_v3_destroy(const struct xt_tgdtor_param *par)
51276cea410SAnton Danilov {
51376cea410SAnton Danilov 	const struct xt_set_info_target_v3 *info = par->targinfo;
51476cea410SAnton Danilov 
51576cea410SAnton Danilov 	if (info->add_set.index != IPSET_INVALID_ID)
51676cea410SAnton Danilov 		ip_set_nfnl_put(par->net, info->add_set.index);
51776cea410SAnton Danilov 	if (info->del_set.index != IPSET_INVALID_ID)
51876cea410SAnton Danilov 		ip_set_nfnl_put(par->net, info->del_set.index);
51976cea410SAnton Danilov 	if (info->map_set.index != IPSET_INVALID_ID)
52076cea410SAnton Danilov 		ip_set_nfnl_put(par->net, info->map_set.index);
52176cea410SAnton Danilov }
52276cea410SAnton Danilov 
523d956798dSJozsef Kadlecsik static struct xt_match set_matches[] __read_mostly = {
524d956798dSJozsef Kadlecsik 	{
525d956798dSJozsef Kadlecsik 		.name		= "set",
526d956798dSJozsef Kadlecsik 		.family		= NFPROTO_IPV4,
527d956798dSJozsef Kadlecsik 		.revision	= 0,
528d956798dSJozsef Kadlecsik 		.match		= set_match_v0,
529d956798dSJozsef Kadlecsik 		.matchsize	= sizeof(struct xt_set_info_match_v0),
530d956798dSJozsef Kadlecsik 		.checkentry	= set_match_v0_checkentry,
531d956798dSJozsef Kadlecsik 		.destroy	= set_match_v0_destroy,
532d956798dSJozsef Kadlecsik 		.me		= THIS_MODULE
533d956798dSJozsef Kadlecsik 	},
534d956798dSJozsef Kadlecsik 	{
535d956798dSJozsef Kadlecsik 		.name		= "set",
536d956798dSJozsef Kadlecsik 		.family		= NFPROTO_IPV4,
537d956798dSJozsef Kadlecsik 		.revision	= 1,
538ac8cc925SJozsef Kadlecsik 		.match		= set_match_v1,
539ac8cc925SJozsef Kadlecsik 		.matchsize	= sizeof(struct xt_set_info_match_v1),
540ac8cc925SJozsef Kadlecsik 		.checkentry	= set_match_v1_checkentry,
541ac8cc925SJozsef Kadlecsik 		.destroy	= set_match_v1_destroy,
542d956798dSJozsef Kadlecsik 		.me		= THIS_MODULE
543d956798dSJozsef Kadlecsik 	},
544d956798dSJozsef Kadlecsik 	{
545d956798dSJozsef Kadlecsik 		.name		= "set",
546d956798dSJozsef Kadlecsik 		.family		= NFPROTO_IPV6,
547d956798dSJozsef Kadlecsik 		.revision	= 1,
548ac8cc925SJozsef Kadlecsik 		.match		= set_match_v1,
549ac8cc925SJozsef Kadlecsik 		.matchsize	= sizeof(struct xt_set_info_match_v1),
550ac8cc925SJozsef Kadlecsik 		.checkentry	= set_match_v1_checkentry,
551ac8cc925SJozsef Kadlecsik 		.destroy	= set_match_v1_destroy,
552d956798dSJozsef Kadlecsik 		.me		= THIS_MODULE
553d956798dSJozsef Kadlecsik 	},
5543e0304a5SJozsef Kadlecsik 	/* --return-nomatch flag support */
5553e0304a5SJozsef Kadlecsik 	{
5563e0304a5SJozsef Kadlecsik 		.name		= "set",
5573e0304a5SJozsef Kadlecsik 		.family		= NFPROTO_IPV4,
5583e0304a5SJozsef Kadlecsik 		.revision	= 2,
5593e0304a5SJozsef Kadlecsik 		.match		= set_match_v1,
5603e0304a5SJozsef Kadlecsik 		.matchsize	= sizeof(struct xt_set_info_match_v1),
5613e0304a5SJozsef Kadlecsik 		.checkentry	= set_match_v1_checkentry,
5623e0304a5SJozsef Kadlecsik 		.destroy	= set_match_v1_destroy,
5633e0304a5SJozsef Kadlecsik 		.me		= THIS_MODULE
5643e0304a5SJozsef Kadlecsik 	},
5653e0304a5SJozsef Kadlecsik 	{
5663e0304a5SJozsef Kadlecsik 		.name		= "set",
5673e0304a5SJozsef Kadlecsik 		.family		= NFPROTO_IPV6,
5683e0304a5SJozsef Kadlecsik 		.revision	= 2,
5693e0304a5SJozsef Kadlecsik 		.match		= set_match_v1,
5703e0304a5SJozsef Kadlecsik 		.matchsize	= sizeof(struct xt_set_info_match_v1),
5713e0304a5SJozsef Kadlecsik 		.checkentry	= set_match_v1_checkentry,
5723e0304a5SJozsef Kadlecsik 		.destroy	= set_match_v1_destroy,
5733e0304a5SJozsef Kadlecsik 		.me		= THIS_MODULE
5743e0304a5SJozsef Kadlecsik 	},
5756e01781dSJozsef Kadlecsik 	/* counters support: update, match */
5766e01781dSJozsef Kadlecsik 	{
5776e01781dSJozsef Kadlecsik 		.name		= "set",
5786e01781dSJozsef Kadlecsik 		.family		= NFPROTO_IPV4,
5796e01781dSJozsef Kadlecsik 		.revision	= 3,
5806e01781dSJozsef Kadlecsik 		.match		= set_match_v3,
5816e01781dSJozsef Kadlecsik 		.matchsize	= sizeof(struct xt_set_info_match_v3),
5826e01781dSJozsef Kadlecsik 		.checkentry	= set_match_v3_checkentry,
5836e01781dSJozsef Kadlecsik 		.destroy	= set_match_v3_destroy,
5846e01781dSJozsef Kadlecsik 		.me		= THIS_MODULE
5856e01781dSJozsef Kadlecsik 	},
5866e01781dSJozsef Kadlecsik 	{
5876e01781dSJozsef Kadlecsik 		.name		= "set",
5886e01781dSJozsef Kadlecsik 		.family		= NFPROTO_IPV6,
5896e01781dSJozsef Kadlecsik 		.revision	= 3,
5906e01781dSJozsef Kadlecsik 		.match		= set_match_v3,
5916e01781dSJozsef Kadlecsik 		.matchsize	= sizeof(struct xt_set_info_match_v3),
5926e01781dSJozsef Kadlecsik 		.checkentry	= set_match_v3_checkentry,
5936e01781dSJozsef Kadlecsik 		.destroy	= set_match_v3_destroy,
5946e01781dSJozsef Kadlecsik 		.me		= THIS_MODULE
5956e01781dSJozsef Kadlecsik 	},
596a51b9199SJozsef Kadlecsik 	/* new revision for counters support: update, match */
597a51b9199SJozsef Kadlecsik 	{
598a51b9199SJozsef Kadlecsik 		.name		= "set",
599a51b9199SJozsef Kadlecsik 		.family		= NFPROTO_IPV4,
600a51b9199SJozsef Kadlecsik 		.revision	= 4,
601a51b9199SJozsef Kadlecsik 		.match		= set_match_v4,
602a51b9199SJozsef Kadlecsik 		.matchsize	= sizeof(struct xt_set_info_match_v4),
603a51b9199SJozsef Kadlecsik 		.checkentry	= set_match_v4_checkentry,
604a51b9199SJozsef Kadlecsik 		.destroy	= set_match_v4_destroy,
605a51b9199SJozsef Kadlecsik 		.me		= THIS_MODULE
606a51b9199SJozsef Kadlecsik 	},
607a51b9199SJozsef Kadlecsik 	{
608a51b9199SJozsef Kadlecsik 		.name		= "set",
609a51b9199SJozsef Kadlecsik 		.family		= NFPROTO_IPV6,
610a51b9199SJozsef Kadlecsik 		.revision	= 4,
611a51b9199SJozsef Kadlecsik 		.match		= set_match_v4,
612a51b9199SJozsef Kadlecsik 		.matchsize	= sizeof(struct xt_set_info_match_v4),
613a51b9199SJozsef Kadlecsik 		.checkentry	= set_match_v4_checkentry,
614a51b9199SJozsef Kadlecsik 		.destroy	= set_match_v4_destroy,
615a51b9199SJozsef Kadlecsik 		.me		= THIS_MODULE
616a51b9199SJozsef Kadlecsik 	},
617d956798dSJozsef Kadlecsik };
618d956798dSJozsef Kadlecsik 
619d956798dSJozsef Kadlecsik static struct xt_target set_targets[] __read_mostly = {
620d956798dSJozsef Kadlecsik 	{
621d956798dSJozsef Kadlecsik 		.name		= "SET",
622d956798dSJozsef Kadlecsik 		.revision	= 0,
623d956798dSJozsef Kadlecsik 		.family		= NFPROTO_IPV4,
624d956798dSJozsef Kadlecsik 		.target		= set_target_v0,
625d956798dSJozsef Kadlecsik 		.targetsize	= sizeof(struct xt_set_info_target_v0),
626d956798dSJozsef Kadlecsik 		.checkentry	= set_target_v0_checkentry,
627d956798dSJozsef Kadlecsik 		.destroy	= set_target_v0_destroy,
628d956798dSJozsef Kadlecsik 		.me		= THIS_MODULE
629d956798dSJozsef Kadlecsik 	},
630d956798dSJozsef Kadlecsik 	{
631d956798dSJozsef Kadlecsik 		.name		= "SET",
632d956798dSJozsef Kadlecsik 		.revision	= 1,
633d956798dSJozsef Kadlecsik 		.family		= NFPROTO_IPV4,
634ac8cc925SJozsef Kadlecsik 		.target		= set_target_v1,
635ac8cc925SJozsef Kadlecsik 		.targetsize	= sizeof(struct xt_set_info_target_v1),
636ac8cc925SJozsef Kadlecsik 		.checkentry	= set_target_v1_checkentry,
637ac8cc925SJozsef Kadlecsik 		.destroy	= set_target_v1_destroy,
638d956798dSJozsef Kadlecsik 		.me		= THIS_MODULE
639d956798dSJozsef Kadlecsik 	},
640d956798dSJozsef Kadlecsik 	{
641d956798dSJozsef Kadlecsik 		.name		= "SET",
642d956798dSJozsef Kadlecsik 		.revision	= 1,
643d956798dSJozsef Kadlecsik 		.family		= NFPROTO_IPV6,
644ac8cc925SJozsef Kadlecsik 		.target		= set_target_v1,
645ac8cc925SJozsef Kadlecsik 		.targetsize	= sizeof(struct xt_set_info_target_v1),
646ac8cc925SJozsef Kadlecsik 		.checkentry	= set_target_v1_checkentry,
647ac8cc925SJozsef Kadlecsik 		.destroy	= set_target_v1_destroy,
648ac8cc925SJozsef Kadlecsik 		.me		= THIS_MODULE
649ac8cc925SJozsef Kadlecsik 	},
6503e0304a5SJozsef Kadlecsik 	/* --timeout and --exist flags support */
651ac8cc925SJozsef Kadlecsik 	{
652ac8cc925SJozsef Kadlecsik 		.name		= "SET",
653ac8cc925SJozsef Kadlecsik 		.revision	= 2,
654ac8cc925SJozsef Kadlecsik 		.family		= NFPROTO_IPV4,
655ac8cc925SJozsef Kadlecsik 		.target		= set_target_v2,
656ac8cc925SJozsef Kadlecsik 		.targetsize	= sizeof(struct xt_set_info_target_v2),
657ac8cc925SJozsef Kadlecsik 		.checkentry	= set_target_v2_checkentry,
658ac8cc925SJozsef Kadlecsik 		.destroy	= set_target_v2_destroy,
659ac8cc925SJozsef Kadlecsik 		.me		= THIS_MODULE
660ac8cc925SJozsef Kadlecsik 	},
661ac8cc925SJozsef Kadlecsik 	{
662ac8cc925SJozsef Kadlecsik 		.name		= "SET",
663ac8cc925SJozsef Kadlecsik 		.revision	= 2,
664ac8cc925SJozsef Kadlecsik 		.family		= NFPROTO_IPV6,
665ac8cc925SJozsef Kadlecsik 		.target		= set_target_v2,
666ac8cc925SJozsef Kadlecsik 		.targetsize	= sizeof(struct xt_set_info_target_v2),
667ac8cc925SJozsef Kadlecsik 		.checkentry	= set_target_v2_checkentry,
668ac8cc925SJozsef Kadlecsik 		.destroy	= set_target_v2_destroy,
669d956798dSJozsef Kadlecsik 		.me		= THIS_MODULE
670d956798dSJozsef Kadlecsik 	},
67176cea410SAnton Danilov 	/* --map-set support */
67276cea410SAnton Danilov 	{
67376cea410SAnton Danilov 		.name		= "SET",
67476cea410SAnton Danilov 		.revision	= 3,
67576cea410SAnton Danilov 		.family		= NFPROTO_IPV4,
67676cea410SAnton Danilov 		.target		= set_target_v3,
67776cea410SAnton Danilov 		.targetsize	= sizeof(struct xt_set_info_target_v3),
67876cea410SAnton Danilov 		.checkentry	= set_target_v3_checkentry,
67976cea410SAnton Danilov 		.destroy	= set_target_v3_destroy,
68076cea410SAnton Danilov 		.me		= THIS_MODULE
68176cea410SAnton Danilov 	},
68276cea410SAnton Danilov 	{
68376cea410SAnton Danilov 		.name		= "SET",
68476cea410SAnton Danilov 		.revision	= 3,
68576cea410SAnton Danilov 		.family		= NFPROTO_IPV6,
68676cea410SAnton Danilov 		.target		= set_target_v3,
68776cea410SAnton Danilov 		.targetsize	= sizeof(struct xt_set_info_target_v3),
68876cea410SAnton Danilov 		.checkentry	= set_target_v3_checkentry,
68976cea410SAnton Danilov 		.destroy	= set_target_v3_destroy,
69076cea410SAnton Danilov 		.me		= THIS_MODULE
69176cea410SAnton Danilov 	},
692d956798dSJozsef Kadlecsik };
693d956798dSJozsef Kadlecsik 
694d956798dSJozsef Kadlecsik static int __init xt_set_init(void)
695d956798dSJozsef Kadlecsik {
696d956798dSJozsef Kadlecsik 	int ret = xt_register_matches(set_matches, ARRAY_SIZE(set_matches));
697d956798dSJozsef Kadlecsik 
698d956798dSJozsef Kadlecsik 	if (!ret) {
699d956798dSJozsef Kadlecsik 		ret = xt_register_targets(set_targets,
700d956798dSJozsef Kadlecsik 					  ARRAY_SIZE(set_targets));
701d956798dSJozsef Kadlecsik 		if (ret)
702d956798dSJozsef Kadlecsik 			xt_unregister_matches(set_matches,
703d956798dSJozsef Kadlecsik 					      ARRAY_SIZE(set_matches));
704d956798dSJozsef Kadlecsik 	}
705d956798dSJozsef Kadlecsik 	return ret;
706d956798dSJozsef Kadlecsik }
707d956798dSJozsef Kadlecsik 
708d956798dSJozsef Kadlecsik static void __exit xt_set_fini(void)
709d956798dSJozsef Kadlecsik {
710d956798dSJozsef Kadlecsik 	xt_unregister_matches(set_matches, ARRAY_SIZE(set_matches));
711d956798dSJozsef Kadlecsik 	xt_unregister_targets(set_targets, ARRAY_SIZE(set_targets));
712d956798dSJozsef Kadlecsik }
713d956798dSJozsef Kadlecsik 
714d956798dSJozsef Kadlecsik module_init(xt_set_init);
715d956798dSJozsef Kadlecsik module_exit(xt_set_fini);
716