Blame view

net/netfilter/xt_set.c 19.6 KB
d2912cb15   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-only
d956798d8   Jozsef Kadlecsik   netfilter: xtable...
2
3
4
  /* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
   *                         Patrick Schaaf <bof@bof.de>
   *                         Martin Josefsson <gandalf@wlug.westbo.se>
fe03d4745   Jozsef Kadlecsik   Update my email a...
5
   * Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@netfilter.org>
d956798d8   Jozsef Kadlecsik   netfilter: xtable...
6
7
8
   */
  
  /* Kernel module which implements the set match and SET target
ca0f6a5cd   Jozsef Kadlecsik   netfilter: ipset:...
9
10
   * for netfilter/iptables.
   */
d956798d8   Jozsef Kadlecsik   netfilter: xtable...
11
12
13
  
  #include <linux/module.h>
  #include <linux/skbuff.h>
d956798d8   Jozsef Kadlecsik   netfilter: xtable...
14
15
  
  #include <linux/netfilter/x_tables.h>
a9756e6f6   Jozsef Kadlecsik   netfilter: ipset:...
16
  #include <linux/netfilter/ipset/ip_set.h>
a9756e6f6   Jozsef Kadlecsik   netfilter: ipset:...
17
  #include <uapi/linux/netfilter/xt_set.h>
d956798d8   Jozsef Kadlecsik   netfilter: xtable...
18
19
  
  MODULE_LICENSE("GPL");
fe03d4745   Jozsef Kadlecsik   Update my email a...
20
  MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@netfilter.org>");
d956798d8   Jozsef Kadlecsik   netfilter: xtable...
21
22
23
24
25
26
27
28
29
  MODULE_DESCRIPTION("Xtables: IP set match and target module");
  MODULE_ALIAS("xt_SET");
  MODULE_ALIAS("ipt_set");
  MODULE_ALIAS("ip6t_set");
  MODULE_ALIAS("ipt_SET");
  MODULE_ALIAS("ip6t_SET");
  
  static inline int
  match_set(ip_set_id_t index, const struct sk_buff *skb,
b66554cf0   Jozsef Kadlecsik   netfilter: ipset:...
30
  	  const struct xt_action_param *par,
075e64c04   Jozsef Kadlecsik   netfilter: ipset:...
31
  	  struct ip_set_adt_opt *opt, int inv)
d956798d8   Jozsef Kadlecsik   netfilter: xtable...
32
  {
b66554cf0   Jozsef Kadlecsik   netfilter: ipset:...
33
  	if (ip_set_test(index, skb, par, opt))
d956798d8   Jozsef Kadlecsik   netfilter: xtable...
34
35
36
  		inv = !inv;
  	return inv;
  }
4750005a8   Jozsef Kadlecsik   netfilter: ipset:...
37
38
39
40
41
42
43
44
45
46
47
  #define ADT_OPT(n, f, d, fs, cfs, t, p, b, po, bo)	\
  struct ip_set_adt_opt n = {				\
  	.family	= f,					\
  	.dim = d,					\
  	.flags = fs,					\
  	.cmdflags = cfs,				\
  	.ext.timeout = t,				\
  	.ext.packets = p,				\
  	.ext.bytes = b,					\
  	.ext.packets_op = po,				\
  	.ext.bytes_op = bo,				\
127f55912   Jozsef Kadlecsik   netfilter: ipset:...
48
  }
ac8cc925d   Jozsef Kadlecsik   netfilter: ipset:...
49

d956798d8   Jozsef Kadlecsik   netfilter: xtable...
50
51
52
53
54
55
  /* Revision 0 interface: backward compatible with netfilter/iptables */
  
  static bool
  set_match_v0(const struct sk_buff *skb, struct xt_action_param *par)
  {
  	const struct xt_set_info_match_v0 *info = par->matchinfo;
ca0f6a5cd   Jozsef Kadlecsik   netfilter: ipset:...
56

613dbd957   Pablo Neira Ayuso   netfilter: x_tabl...
57
  	ADT_OPT(opt, xt_family(par), info->match_set.u.compat.dim,
4750005a8   Jozsef Kadlecsik   netfilter: ipset:...
58
59
  		info->match_set.u.compat.flags, 0, UINT_MAX,
  		0, 0, 0, 0);
d956798d8   Jozsef Kadlecsik   netfilter: xtable...
60

b66554cf0   Jozsef Kadlecsik   netfilter: ipset:...
61
  	return match_set(info->match_set.index, skb, par, &opt,
d956798d8   Jozsef Kadlecsik   netfilter: xtable...
62
63
64
65
66
67
68
69
70
71
72
73
  			 info->match_set.u.compat.flags & IPSET_INV_MATCH);
  }
  
  static void
  compat_flags(struct xt_set_info_v0 *info)
  {
  	u_int8_t i;
  
  	/* Fill out compatibility data according to enum ip_set_kopt */
  	info->u.compat.dim = IPSET_DIM_ZERO;
  	if (info->u.flags[0] & IPSET_MATCH_INV)
  		info->u.compat.flags |= IPSET_INV_MATCH;
ca0f6a5cd   Jozsef Kadlecsik   netfilter: ipset:...
74
  	for (i = 0; i < IPSET_DIM_MAX - 1 && info->u.flags[i]; i++) {
d956798d8   Jozsef Kadlecsik   netfilter: xtable...
75
76
  		info->u.compat.dim++;
  		if (info->u.flags[i] & IPSET_SRC)
ca0f6a5cd   Jozsef Kadlecsik   netfilter: ipset:...
77
  			info->u.compat.flags |= (1 << info->u.compat.dim);
d956798d8   Jozsef Kadlecsik   netfilter: xtable...
78
79
80
81
82
83
84
85
  	}
  }
  
  static int
  set_match_v0_checkentry(const struct xt_mtchk_param *par)
  {
  	struct xt_set_info_match_v0 *info = par->matchinfo;
  	ip_set_id_t index;
1785e8f47   Vitaly Lavrov   netfiler: ipset: ...
86
  	index = ip_set_nfnl_get_byindex(par->net, info->match_set.index);
d956798d8   Jozsef Kadlecsik   netfilter: xtable...
87
88
  
  	if (index == IPSET_INVALID_ID) {
c82b31c5f   Florian Westphal   netfilter: xt_set...
89
90
91
  		pr_info_ratelimited("Cannot find set identified by id %u to match
  ",
  				    info->match_set.index);
d956798d8   Jozsef Kadlecsik   netfilter: xtable...
92
93
  		return -ENOENT;
  	}
ca0f6a5cd   Jozsef Kadlecsik   netfilter: ipset:...
94
  	if (info->match_set.u.flags[IPSET_DIM_MAX - 1] != 0) {
c82b31c5f   Florian Westphal   netfilter: xt_set...
95
96
  		pr_info_ratelimited("set match dimension is over the limit!
  ");
1785e8f47   Vitaly Lavrov   netfiler: ipset: ...
97
  		ip_set_nfnl_put(par->net, info->match_set.index);
d956798d8   Jozsef Kadlecsik   netfilter: xtable...
98
99
100
101
102
103
104
105
106
107
108
109
110
  		return -ERANGE;
  	}
  
  	/* Fill out compatibility data */
  	compat_flags(&info->match_set);
  
  	return 0;
  }
  
  static void
  set_match_v0_destroy(const struct xt_mtdtor_param *par)
  {
  	struct xt_set_info_match_v0 *info = par->matchinfo;
1785e8f47   Vitaly Lavrov   netfiler: ipset: ...
111
  	ip_set_nfnl_put(par->net, info->match_set.index);
d956798d8   Jozsef Kadlecsik   netfilter: xtable...
112
  }
bd3129fc5   Jozsef Kadlecsik   netfilter: ipset:...
113
114
115
116
117
118
  /* Revision 1 match */
  
  static bool
  set_match_v1(const struct sk_buff *skb, struct xt_action_param *par)
  {
  	const struct xt_set_info_match_v1 *info = par->matchinfo;
ca0f6a5cd   Jozsef Kadlecsik   netfilter: ipset:...
119

613dbd957   Pablo Neira Ayuso   netfilter: x_tabl...
120
  	ADT_OPT(opt, xt_family(par), info->match_set.dim,
4750005a8   Jozsef Kadlecsik   netfilter: ipset:...
121
122
  		info->match_set.flags, 0, UINT_MAX,
  		0, 0, 0, 0);
bd3129fc5   Jozsef Kadlecsik   netfilter: ipset:...
123
124
125
126
127
128
129
130
131
132
133
134
135
  
  	if (opt.flags & IPSET_RETURN_NOMATCH)
  		opt.cmdflags |= IPSET_FLAG_RETURN_NOMATCH;
  
  	return match_set(info->match_set.index, skb, par, &opt,
  			 info->match_set.flags & IPSET_INV_MATCH);
  }
  
  static int
  set_match_v1_checkentry(const struct xt_mtchk_param *par)
  {
  	struct xt_set_info_match_v1 *info = par->matchinfo;
  	ip_set_id_t index;
1785e8f47   Vitaly Lavrov   netfiler: ipset: ...
136
  	index = ip_set_nfnl_get_byindex(par->net, info->match_set.index);
bd3129fc5   Jozsef Kadlecsik   netfilter: ipset:...
137
138
  
  	if (index == IPSET_INVALID_ID) {
c82b31c5f   Florian Westphal   netfilter: xt_set...
139
140
141
  		pr_info_ratelimited("Cannot find set identified by id %u to match
  ",
  				    info->match_set.index);
bd3129fc5   Jozsef Kadlecsik   netfilter: ipset:...
142
143
144
  		return -ENOENT;
  	}
  	if (info->match_set.dim > IPSET_DIM_MAX) {
c82b31c5f   Florian Westphal   netfilter: xt_set...
145
146
  		pr_info_ratelimited("set match dimension is over the limit!
  ");
1785e8f47   Vitaly Lavrov   netfiler: ipset: ...
147
  		ip_set_nfnl_put(par->net, info->match_set.index);
bd3129fc5   Jozsef Kadlecsik   netfilter: ipset:...
148
149
150
151
152
153
154
155
156
157
  		return -ERANGE;
  	}
  
  	return 0;
  }
  
  static void
  set_match_v1_destroy(const struct xt_mtdtor_param *par)
  {
  	struct xt_set_info_match_v1 *info = par->matchinfo;
1785e8f47   Vitaly Lavrov   netfiler: ipset: ...
158
  	ip_set_nfnl_put(par->net, info->match_set.index);
bd3129fc5   Jozsef Kadlecsik   netfilter: ipset:...
159
160
161
162
163
  }
  
  /* Revision 3 match */
  
  static bool
bd3129fc5   Jozsef Kadlecsik   netfilter: ipset:...
164
165
166
  set_match_v3(const struct sk_buff *skb, struct xt_action_param *par)
  {
  	const struct xt_set_info_match_v3 *info = par->matchinfo;
ca0f6a5cd   Jozsef Kadlecsik   netfilter: ipset:...
167

613dbd957   Pablo Neira Ayuso   netfilter: x_tabl...
168
  	ADT_OPT(opt, xt_family(par), info->match_set.dim,
4750005a8   Jozsef Kadlecsik   netfilter: ipset:...
169
170
171
  		info->match_set.flags, info->flags, UINT_MAX,
  		info->packets.value, info->bytes.value,
  		info->packets.op, info->bytes.op);
bd3129fc5   Jozsef Kadlecsik   netfilter: ipset:...
172
173
174
175
  
  	if (info->packets.op != IPSET_COUNTER_NONE ||
  	    info->bytes.op != IPSET_COUNTER_NONE)
  		opt.cmdflags |= IPSET_FLAG_MATCH_COUNTERS;
4750005a8   Jozsef Kadlecsik   netfilter: ipset:...
176
177
  	return match_set(info->match_set.index, skb, par, &opt,
  			 info->match_set.flags & IPSET_INV_MATCH);
bd3129fc5   Jozsef Kadlecsik   netfilter: ipset:...
178
179
180
181
  }
  
  #define set_match_v3_checkentry	set_match_v1_checkentry
  #define set_match_v3_destroy	set_match_v1_destroy
a51b9199b   Jozsef Kadlecsik   netfilter: ipset:...
182
183
184
  /* Revision 4 match */
  
  static bool
a51b9199b   Jozsef Kadlecsik   netfilter: ipset:...
185
186
187
  set_match_v4(const struct sk_buff *skb, struct xt_action_param *par)
  {
  	const struct xt_set_info_match_v4 *info = par->matchinfo;
ca0f6a5cd   Jozsef Kadlecsik   netfilter: ipset:...
188

613dbd957   Pablo Neira Ayuso   netfilter: x_tabl...
189
  	ADT_OPT(opt, xt_family(par), info->match_set.dim,
4750005a8   Jozsef Kadlecsik   netfilter: ipset:...
190
191
192
  		info->match_set.flags, info->flags, UINT_MAX,
  		info->packets.value, info->bytes.value,
  		info->packets.op, info->bytes.op);
a51b9199b   Jozsef Kadlecsik   netfilter: ipset:...
193
194
195
196
  
  	if (info->packets.op != IPSET_COUNTER_NONE ||
  	    info->bytes.op != IPSET_COUNTER_NONE)
  		opt.cmdflags |= IPSET_FLAG_MATCH_COUNTERS;
4750005a8   Jozsef Kadlecsik   netfilter: ipset:...
197
198
  	return match_set(info->match_set.index, skb, par, &opt,
  			 info->match_set.flags & IPSET_INV_MATCH);
a51b9199b   Jozsef Kadlecsik   netfilter: ipset:...
199
200
201
202
  }
  
  #define set_match_v4_checkentry	set_match_v1_checkentry
  #define set_match_v4_destroy	set_match_v1_destroy
bd3129fc5   Jozsef Kadlecsik   netfilter: ipset:...
203
  /* Revision 0 interface: backward compatible with netfilter/iptables */
d956798d8   Jozsef Kadlecsik   netfilter: xtable...
204
205
206
207
  static unsigned int
  set_target_v0(struct sk_buff *skb, const struct xt_action_param *par)
  {
  	const struct xt_set_info_target_v0 *info = par->targinfo;
ca0f6a5cd   Jozsef Kadlecsik   netfilter: ipset:...
208

613dbd957   Pablo Neira Ayuso   netfilter: x_tabl...
209
  	ADT_OPT(add_opt, xt_family(par), info->add_set.u.compat.dim,
4750005a8   Jozsef Kadlecsik   netfilter: ipset:...
210
211
  		info->add_set.u.compat.flags, 0, UINT_MAX,
  		0, 0, 0, 0);
613dbd957   Pablo Neira Ayuso   netfilter: x_tabl...
212
  	ADT_OPT(del_opt, xt_family(par), info->del_set.u.compat.dim,
4750005a8   Jozsef Kadlecsik   netfilter: ipset:...
213
214
  		info->del_set.u.compat.flags, 0, UINT_MAX,
  		0, 0, 0, 0);
d956798d8   Jozsef Kadlecsik   netfilter: xtable...
215
216
  
  	if (info->add_set.index != IPSET_INVALID_ID)
b66554cf0   Jozsef Kadlecsik   netfilter: ipset:...
217
  		ip_set_add(info->add_set.index, skb, par, &add_opt);
d956798d8   Jozsef Kadlecsik   netfilter: xtable...
218
  	if (info->del_set.index != IPSET_INVALID_ID)
b66554cf0   Jozsef Kadlecsik   netfilter: ipset:...
219
  		ip_set_del(info->del_set.index, skb, par, &del_opt);
d956798d8   Jozsef Kadlecsik   netfilter: xtable...
220
221
222
223
224
225
226
227
228
229
230
  
  	return XT_CONTINUE;
  }
  
  static int
  set_target_v0_checkentry(const struct xt_tgchk_param *par)
  {
  	struct xt_set_info_target_v0 *info = par->targinfo;
  	ip_set_id_t index;
  
  	if (info->add_set.index != IPSET_INVALID_ID) {
1785e8f47   Vitaly Lavrov   netfiler: ipset: ...
231
  		index = ip_set_nfnl_get_byindex(par->net, info->add_set.index);
d956798d8   Jozsef Kadlecsik   netfilter: xtable...
232
  		if (index == IPSET_INVALID_ID) {
c82b31c5f   Florian Westphal   netfilter: xt_set...
233
234
235
  			pr_info_ratelimited("Cannot find add_set index %u as target
  ",
  					    info->add_set.index);
d956798d8   Jozsef Kadlecsik   netfilter: xtable...
236
237
238
239
240
  			return -ENOENT;
  		}
  	}
  
  	if (info->del_set.index != IPSET_INVALID_ID) {
1785e8f47   Vitaly Lavrov   netfiler: ipset: ...
241
  		index = ip_set_nfnl_get_byindex(par->net, info->del_set.index);
d956798d8   Jozsef Kadlecsik   netfilter: xtable...
242
  		if (index == IPSET_INVALID_ID) {
c82b31c5f   Florian Westphal   netfilter: xt_set...
243
244
245
  			pr_info_ratelimited("Cannot find del_set index %u as target
  ",
  					    info->del_set.index);
eafbd3fde   Jozsef Kadlecsik   netfilter: ipset:...
246
  			if (info->add_set.index != IPSET_INVALID_ID)
1785e8f47   Vitaly Lavrov   netfiler: ipset: ...
247
  				ip_set_nfnl_put(par->net, info->add_set.index);
d956798d8   Jozsef Kadlecsik   netfilter: xtable...
248
249
250
  			return -ENOENT;
  		}
  	}
ca0f6a5cd   Jozsef Kadlecsik   netfilter: ipset:...
251
252
  	if (info->add_set.u.flags[IPSET_DIM_MAX - 1] != 0 ||
  	    info->del_set.u.flags[IPSET_DIM_MAX - 1] != 0) {
c82b31c5f   Florian Westphal   netfilter: xt_set...
253
254
  		pr_info_ratelimited("SET target dimension over the limit!
  ");
eafbd3fde   Jozsef Kadlecsik   netfilter: ipset:...
255
  		if (info->add_set.index != IPSET_INVALID_ID)
1785e8f47   Vitaly Lavrov   netfiler: ipset: ...
256
  			ip_set_nfnl_put(par->net, info->add_set.index);
eafbd3fde   Jozsef Kadlecsik   netfilter: ipset:...
257
  		if (info->del_set.index != IPSET_INVALID_ID)
1785e8f47   Vitaly Lavrov   netfiler: ipset: ...
258
  			ip_set_nfnl_put(par->net, info->del_set.index);
d956798d8   Jozsef Kadlecsik   netfilter: xtable...
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
  		return -ERANGE;
  	}
  
  	/* Fill out compatibility data */
  	compat_flags(&info->add_set);
  	compat_flags(&info->del_set);
  
  	return 0;
  }
  
  static void
  set_target_v0_destroy(const struct xt_tgdtor_param *par)
  {
  	const struct xt_set_info_target_v0 *info = par->targinfo;
  
  	if (info->add_set.index != IPSET_INVALID_ID)
1785e8f47   Vitaly Lavrov   netfiler: ipset: ...
275
  		ip_set_nfnl_put(par->net, info->add_set.index);
d956798d8   Jozsef Kadlecsik   netfilter: xtable...
276
  	if (info->del_set.index != IPSET_INVALID_ID)
1785e8f47   Vitaly Lavrov   netfiler: ipset: ...
277
  		ip_set_nfnl_put(par->net, info->del_set.index);
d956798d8   Jozsef Kadlecsik   netfilter: xtable...
278
  }
bd3129fc5   Jozsef Kadlecsik   netfilter: ipset:...
279
  /* Revision 1 target */
d956798d8   Jozsef Kadlecsik   netfilter: xtable...
280
281
  
  static unsigned int
ac8cc925d   Jozsef Kadlecsik   netfilter: ipset:...
282
  set_target_v1(struct sk_buff *skb, const struct xt_action_param *par)
d956798d8   Jozsef Kadlecsik   netfilter: xtable...
283
  {
ac8cc925d   Jozsef Kadlecsik   netfilter: ipset:...
284
  	const struct xt_set_info_target_v1 *info = par->targinfo;
ca0f6a5cd   Jozsef Kadlecsik   netfilter: ipset:...
285

613dbd957   Pablo Neira Ayuso   netfilter: x_tabl...
286
  	ADT_OPT(add_opt, xt_family(par), info->add_set.dim,
4750005a8   Jozsef Kadlecsik   netfilter: ipset:...
287
288
  		info->add_set.flags, 0, UINT_MAX,
  		0, 0, 0, 0);
613dbd957   Pablo Neira Ayuso   netfilter: x_tabl...
289
  	ADT_OPT(del_opt, xt_family(par), info->del_set.dim,
4750005a8   Jozsef Kadlecsik   netfilter: ipset:...
290
291
  		info->del_set.flags, 0, UINT_MAX,
  		0, 0, 0, 0);
d956798d8   Jozsef Kadlecsik   netfilter: xtable...
292
293
  
  	if (info->add_set.index != IPSET_INVALID_ID)
b66554cf0   Jozsef Kadlecsik   netfilter: ipset:...
294
  		ip_set_add(info->add_set.index, skb, par, &add_opt);
d956798d8   Jozsef Kadlecsik   netfilter: xtable...
295
  	if (info->del_set.index != IPSET_INVALID_ID)
b66554cf0   Jozsef Kadlecsik   netfilter: ipset:...
296
  		ip_set_del(info->del_set.index, skb, par, &del_opt);
d956798d8   Jozsef Kadlecsik   netfilter: xtable...
297
298
299
300
301
  
  	return XT_CONTINUE;
  }
  
  static int
ac8cc925d   Jozsef Kadlecsik   netfilter: ipset:...
302
  set_target_v1_checkentry(const struct xt_tgchk_param *par)
d956798d8   Jozsef Kadlecsik   netfilter: xtable...
303
  {
ac8cc925d   Jozsef Kadlecsik   netfilter: ipset:...
304
  	const struct xt_set_info_target_v1 *info = par->targinfo;
d956798d8   Jozsef Kadlecsik   netfilter: xtable...
305
306
307
  	ip_set_id_t index;
  
  	if (info->add_set.index != IPSET_INVALID_ID) {
1785e8f47   Vitaly Lavrov   netfiler: ipset: ...
308
  		index = ip_set_nfnl_get_byindex(par->net, info->add_set.index);
d956798d8   Jozsef Kadlecsik   netfilter: xtable...
309
  		if (index == IPSET_INVALID_ID) {
c82b31c5f   Florian Westphal   netfilter: xt_set...
310
311
312
  			pr_info_ratelimited("Cannot find add_set index %u as target
  ",
  					    info->add_set.index);
d956798d8   Jozsef Kadlecsik   netfilter: xtable...
313
314
315
316
317
  			return -ENOENT;
  		}
  	}
  
  	if (info->del_set.index != IPSET_INVALID_ID) {
1785e8f47   Vitaly Lavrov   netfiler: ipset: ...
318
  		index = ip_set_nfnl_get_byindex(par->net, info->del_set.index);
d956798d8   Jozsef Kadlecsik   netfilter: xtable...
319
  		if (index == IPSET_INVALID_ID) {
c82b31c5f   Florian Westphal   netfilter: xt_set...
320
321
322
  			pr_info_ratelimited("Cannot find del_set index %u as target
  ",
  					    info->del_set.index);
eafbd3fde   Jozsef Kadlecsik   netfilter: ipset:...
323
  			if (info->add_set.index != IPSET_INVALID_ID)
1785e8f47   Vitaly Lavrov   netfiler: ipset: ...
324
  				ip_set_nfnl_put(par->net, info->add_set.index);
d956798d8   Jozsef Kadlecsik   netfilter: xtable...
325
326
327
328
  			return -ENOENT;
  		}
  	}
  	if (info->add_set.dim > IPSET_DIM_MAX ||
eafbd3fde   Jozsef Kadlecsik   netfilter: ipset:...
329
  	    info->del_set.dim > IPSET_DIM_MAX) {
c82b31c5f   Florian Westphal   netfilter: xt_set...
330
331
  		pr_info_ratelimited("SET target dimension over the limit!
  ");
eafbd3fde   Jozsef Kadlecsik   netfilter: ipset:...
332
  		if (info->add_set.index != IPSET_INVALID_ID)
1785e8f47   Vitaly Lavrov   netfiler: ipset: ...
333
  			ip_set_nfnl_put(par->net, info->add_set.index);
eafbd3fde   Jozsef Kadlecsik   netfilter: ipset:...
334
  		if (info->del_set.index != IPSET_INVALID_ID)
1785e8f47   Vitaly Lavrov   netfiler: ipset: ...
335
  			ip_set_nfnl_put(par->net, info->del_set.index);
d956798d8   Jozsef Kadlecsik   netfilter: xtable...
336
337
338
339
340
341
342
  		return -ERANGE;
  	}
  
  	return 0;
  }
  
  static void
ac8cc925d   Jozsef Kadlecsik   netfilter: ipset:...
343
  set_target_v1_destroy(const struct xt_tgdtor_param *par)
d956798d8   Jozsef Kadlecsik   netfilter: xtable...
344
  {
ac8cc925d   Jozsef Kadlecsik   netfilter: ipset:...
345
  	const struct xt_set_info_target_v1 *info = par->targinfo;
d956798d8   Jozsef Kadlecsik   netfilter: xtable...
346
347
  
  	if (info->add_set.index != IPSET_INVALID_ID)
1785e8f47   Vitaly Lavrov   netfiler: ipset: ...
348
  		ip_set_nfnl_put(par->net, info->add_set.index);
d956798d8   Jozsef Kadlecsik   netfilter: xtable...
349
  	if (info->del_set.index != IPSET_INVALID_ID)
1785e8f47   Vitaly Lavrov   netfiler: ipset: ...
350
  		ip_set_nfnl_put(par->net, info->del_set.index);
d956798d8   Jozsef Kadlecsik   netfilter: xtable...
351
  }
ac8cc925d   Jozsef Kadlecsik   netfilter: ipset:...
352
353
354
355
356
357
  /* 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;
ca0f6a5cd   Jozsef Kadlecsik   netfilter: ipset:...
358

613dbd957   Pablo Neira Ayuso   netfilter: x_tabl...
359
  	ADT_OPT(add_opt, xt_family(par), info->add_set.dim,
4750005a8   Jozsef Kadlecsik   netfilter: ipset:...
360
361
  		info->add_set.flags, info->flags, info->timeout,
  		0, 0, 0, 0);
613dbd957   Pablo Neira Ayuso   netfilter: x_tabl...
362
  	ADT_OPT(del_opt, xt_family(par), info->del_set.dim,
4750005a8   Jozsef Kadlecsik   netfilter: ipset:...
363
364
  		info->del_set.flags, 0, UINT_MAX,
  		0, 0, 0, 0);
ac8cc925d   Jozsef Kadlecsik   netfilter: ipset:...
365

127f55912   Jozsef Kadlecsik   netfilter: ipset:...
366
  	/* Normalize to fit into jiffies */
075e64c04   Jozsef Kadlecsik   netfilter: ipset:...
367
  	if (add_opt.ext.timeout != IPSET_NO_TIMEOUT &&
30a2e1071   Jozsef Kadlecsik   netfilter: ipset:...
368
369
  	    add_opt.ext.timeout > IPSET_MAX_TIMEOUT)
  		add_opt.ext.timeout = IPSET_MAX_TIMEOUT;
ac8cc925d   Jozsef Kadlecsik   netfilter: ipset:...
370
  	if (info->add_set.index != IPSET_INVALID_ID)
b66554cf0   Jozsef Kadlecsik   netfilter: ipset:...
371
  		ip_set_add(info->add_set.index, skb, par, &add_opt);
ac8cc925d   Jozsef Kadlecsik   netfilter: ipset:...
372
  	if (info->del_set.index != IPSET_INVALID_ID)
b66554cf0   Jozsef Kadlecsik   netfilter: ipset:...
373
  		ip_set_del(info->del_set.index, skb, par, &del_opt);
ac8cc925d   Jozsef Kadlecsik   netfilter: ipset:...
374
375
376
377
378
379
  
  	return XT_CONTINUE;
  }
  
  #define set_target_v2_checkentry	set_target_v1_checkentry
  #define set_target_v2_destroy		set_target_v1_destroy
76cea4109   Anton Danilov   netfilter: ipset:...
380
  /* Revision 3 target */
bec810d97   Jozsef Kadlecsik   netfilter: ipset:...
381
  #define MOPT(opt, member)	((opt).ext.skbinfo.member)
76cea4109   Anton Danilov   netfilter: ipset:...
382
383
384
385
  static unsigned int
  set_target_v3(struct sk_buff *skb, const struct xt_action_param *par)
  {
  	const struct xt_set_info_target_v3 *info = par->targinfo;
ca0f6a5cd   Jozsef Kadlecsik   netfilter: ipset:...
386
  	int ret;
613dbd957   Pablo Neira Ayuso   netfilter: x_tabl...
387
  	ADT_OPT(add_opt, xt_family(par), info->add_set.dim,
4750005a8   Jozsef Kadlecsik   netfilter: ipset:...
388
389
  		info->add_set.flags, info->flags, info->timeout,
  		0, 0, 0, 0);
613dbd957   Pablo Neira Ayuso   netfilter: x_tabl...
390
  	ADT_OPT(del_opt, xt_family(par), info->del_set.dim,
4750005a8   Jozsef Kadlecsik   netfilter: ipset:...
391
392
  		info->del_set.flags, 0, UINT_MAX,
  		0, 0, 0, 0);
613dbd957   Pablo Neira Ayuso   netfilter: x_tabl...
393
  	ADT_OPT(map_opt, xt_family(par), info->map_set.dim,
4750005a8   Jozsef Kadlecsik   netfilter: ipset:...
394
395
  		info->map_set.flags, 0, UINT_MAX,
  		0, 0, 0, 0);
76cea4109   Anton Danilov   netfilter: ipset:...
396

76cea4109   Anton Danilov   netfilter: ipset:...
397
398
  	/* Normalize to fit into jiffies */
  	if (add_opt.ext.timeout != IPSET_NO_TIMEOUT &&
30a2e1071   Jozsef Kadlecsik   netfilter: ipset:...
399
400
  	    add_opt.ext.timeout > IPSET_MAX_TIMEOUT)
  		add_opt.ext.timeout = IPSET_MAX_TIMEOUT;
76cea4109   Anton Danilov   netfilter: ipset:...
401
402
403
404
405
406
407
408
409
410
411
412
413
  	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);
  	if (info->map_set.index != IPSET_INVALID_ID) {
  		map_opt.cmdflags |= info->flags & (IPSET_FLAG_MAP_SKBMARK |
  						   IPSET_FLAG_MAP_SKBPRIO |
  						   IPSET_FLAG_MAP_SKBQUEUE);
  		ret = match_set(info->map_set.index, skb, par, &map_opt,
  				info->map_set.flags & IPSET_INV_MATCH);
  		if (!ret)
  			return XT_CONTINUE;
  		if (map_opt.cmdflags & IPSET_FLAG_MAP_SKBMARK)
bec810d97   Jozsef Kadlecsik   netfilter: ipset:...
414
415
  			skb->mark = (skb->mark & ~MOPT(map_opt,skbmarkmask))
  				    ^ MOPT(map_opt, skbmark);
76cea4109   Anton Danilov   netfilter: ipset:...
416
  		if (map_opt.cmdflags & IPSET_FLAG_MAP_SKBPRIO)
bec810d97   Jozsef Kadlecsik   netfilter: ipset:...
417
  			skb->priority = MOPT(map_opt, skbprio);
76cea4109   Anton Danilov   netfilter: ipset:...
418
419
  		if ((map_opt.cmdflags & IPSET_FLAG_MAP_SKBQUEUE) &&
  		    skb->dev &&
bec810d97   Jozsef Kadlecsik   netfilter: ipset:...
420
421
  		    skb->dev->real_num_tx_queues > MOPT(map_opt, skbqueue))
  			skb_set_queue_mapping(skb, MOPT(map_opt, skbqueue));
76cea4109   Anton Danilov   netfilter: ipset:...
422
423
424
  	}
  	return XT_CONTINUE;
  }
76cea4109   Anton Danilov   netfilter: ipset:...
425
426
427
428
429
  static int
  set_target_v3_checkentry(const struct xt_tgchk_param *par)
  {
  	const struct xt_set_info_target_v3 *info = par->targinfo;
  	ip_set_id_t index;
b1732e163   Jozsef Kadlecsik   netfilter: ipset:...
430
  	int ret = 0;
76cea4109   Anton Danilov   netfilter: ipset:...
431
432
433
434
435
  
  	if (info->add_set.index != IPSET_INVALID_ID) {
  		index = ip_set_nfnl_get_byindex(par->net,
  						info->add_set.index);
  		if (index == IPSET_INVALID_ID) {
c82b31c5f   Florian Westphal   netfilter: xt_set...
436
437
438
  			pr_info_ratelimited("Cannot find add_set index %u as target
  ",
  					    info->add_set.index);
76cea4109   Anton Danilov   netfilter: ipset:...
439
440
441
442
443
444
445
446
  			return -ENOENT;
  		}
  	}
  
  	if (info->del_set.index != IPSET_INVALID_ID) {
  		index = ip_set_nfnl_get_byindex(par->net,
  						info->del_set.index);
  		if (index == IPSET_INVALID_ID) {
c82b31c5f   Florian Westphal   netfilter: xt_set...
447
448
449
  			pr_info_ratelimited("Cannot find del_set index %u as target
  ",
  					    info->del_set.index);
b1732e163   Jozsef Kadlecsik   netfilter: ipset:...
450
451
  			ret = -ENOENT;
  			goto cleanup_add;
76cea4109   Anton Danilov   netfilter: ipset:...
452
453
454
455
456
  		}
  	}
  
  	if (info->map_set.index != IPSET_INVALID_ID) {
  		if (strncmp(par->table, "mangle", 7)) {
c82b31c5f   Florian Westphal   netfilter: xt_set...
457
458
  			pr_info_ratelimited("--map-set only usable from mangle table
  ");
b1732e163   Jozsef Kadlecsik   netfilter: ipset:...
459
460
  			ret = -EINVAL;
  			goto cleanup_del;
76cea4109   Anton Danilov   netfilter: ipset:...
461
462
463
  		}
  		if (((info->flags & IPSET_FLAG_MAP_SKBPRIO) |
  		     (info->flags & IPSET_FLAG_MAP_SKBQUEUE)) &&
9dcceb137   Serhey Popovych   netfilter: xt_set...
464
  		     (par->hook_mask & ~(1 << NF_INET_FORWARD |
76cea4109   Anton Danilov   netfilter: ipset:...
465
466
  					 1 << NF_INET_LOCAL_OUT |
  					 1 << NF_INET_POST_ROUTING))) {
c82b31c5f   Florian Westphal   netfilter: xt_set...
467
468
  			pr_info_ratelimited("mapping of prio or/and queue is allowed only from OUTPUT/FORWARD/POSTROUTING chains
  ");
b1732e163   Jozsef Kadlecsik   netfilter: ipset:...
469
470
  			ret = -EINVAL;
  			goto cleanup_del;
76cea4109   Anton Danilov   netfilter: ipset:...
471
472
473
474
  		}
  		index = ip_set_nfnl_get_byindex(par->net,
  						info->map_set.index);
  		if (index == IPSET_INVALID_ID) {
c82b31c5f   Florian Westphal   netfilter: xt_set...
475
476
477
  			pr_info_ratelimited("Cannot find map_set index %u as target
  ",
  					    info->map_set.index);
b1732e163   Jozsef Kadlecsik   netfilter: ipset:...
478
479
  			ret = -ENOENT;
  			goto cleanup_del;
76cea4109   Anton Danilov   netfilter: ipset:...
480
481
482
483
484
485
  		}
  	}
  
  	if (info->add_set.dim > IPSET_DIM_MAX ||
  	    info->del_set.dim > IPSET_DIM_MAX ||
  	    info->map_set.dim > IPSET_DIM_MAX) {
c82b31c5f   Florian Westphal   netfilter: xt_set...
486
487
  		pr_info_ratelimited("SET target dimension over the limit!
  ");
b1732e163   Jozsef Kadlecsik   netfilter: ipset:...
488
489
  		ret = -ERANGE;
  		goto cleanup_mark;
76cea4109   Anton Danilov   netfilter: ipset:...
490
491
492
  	}
  
  	return 0;
b1732e163   Jozsef Kadlecsik   netfilter: ipset:...
493
494
495
496
497
498
499
500
501
502
  cleanup_mark:
  	if (info->map_set.index != IPSET_INVALID_ID)
  		ip_set_nfnl_put(par->net, info->map_set.index);
  cleanup_del:
  	if (info->del_set.index != IPSET_INVALID_ID)
  		ip_set_nfnl_put(par->net, info->del_set.index);
  cleanup_add:
  	if (info->add_set.index != IPSET_INVALID_ID)
  		ip_set_nfnl_put(par->net, info->add_set.index);
  	return ret;
76cea4109   Anton Danilov   netfilter: ipset:...
503
504
505
506
507
508
509
510
511
512
513
514
515
516
  }
  
  static void
  set_target_v3_destroy(const struct xt_tgdtor_param *par)
  {
  	const struct xt_set_info_target_v3 *info = par->targinfo;
  
  	if (info->add_set.index != IPSET_INVALID_ID)
  		ip_set_nfnl_put(par->net, info->add_set.index);
  	if (info->del_set.index != IPSET_INVALID_ID)
  		ip_set_nfnl_put(par->net, info->del_set.index);
  	if (info->map_set.index != IPSET_INVALID_ID)
  		ip_set_nfnl_put(par->net, info->map_set.index);
  }
d956798d8   Jozsef Kadlecsik   netfilter: xtable...
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
  static struct xt_match set_matches[] __read_mostly = {
  	{
  		.name		= "set",
  		.family		= NFPROTO_IPV4,
  		.revision	= 0,
  		.match		= set_match_v0,
  		.matchsize	= sizeof(struct xt_set_info_match_v0),
  		.checkentry	= set_match_v0_checkentry,
  		.destroy	= set_match_v0_destroy,
  		.me		= THIS_MODULE
  	},
  	{
  		.name		= "set",
  		.family		= NFPROTO_IPV4,
  		.revision	= 1,
ac8cc925d   Jozsef Kadlecsik   netfilter: ipset:...
532
533
534
535
  		.match		= set_match_v1,
  		.matchsize	= sizeof(struct xt_set_info_match_v1),
  		.checkentry	= set_match_v1_checkentry,
  		.destroy	= set_match_v1_destroy,
d956798d8   Jozsef Kadlecsik   netfilter: xtable...
536
537
538
539
540
541
  		.me		= THIS_MODULE
  	},
  	{
  		.name		= "set",
  		.family		= NFPROTO_IPV6,
  		.revision	= 1,
ac8cc925d   Jozsef Kadlecsik   netfilter: ipset:...
542
543
544
545
  		.match		= set_match_v1,
  		.matchsize	= sizeof(struct xt_set_info_match_v1),
  		.checkentry	= set_match_v1_checkentry,
  		.destroy	= set_match_v1_destroy,
d956798d8   Jozsef Kadlecsik   netfilter: xtable...
546
547
  		.me		= THIS_MODULE
  	},
3e0304a58   Jozsef Kadlecsik   netfilter: ipset:...
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
  	/* --return-nomatch flag support */
  	{
  		.name		= "set",
  		.family		= NFPROTO_IPV4,
  		.revision	= 2,
  		.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	= 2,
  		.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
  	},
6e01781d1   Jozsef Kadlecsik   netfilter: ipset:...
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
  	/* counters support: update, match */
  	{
  		.name		= "set",
  		.family		= NFPROTO_IPV4,
  		.revision	= 3,
  		.match		= set_match_v3,
  		.matchsize	= sizeof(struct xt_set_info_match_v3),
  		.checkentry	= set_match_v3_checkentry,
  		.destroy	= set_match_v3_destroy,
  		.me		= THIS_MODULE
  	},
  	{
  		.name		= "set",
  		.family		= NFPROTO_IPV6,
  		.revision	= 3,
  		.match		= set_match_v3,
  		.matchsize	= sizeof(struct xt_set_info_match_v3),
  		.checkentry	= set_match_v3_checkentry,
  		.destroy	= set_match_v3_destroy,
  		.me		= THIS_MODULE
  	},
a51b9199b   Jozsef Kadlecsik   netfilter: ipset:...
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
  	/* new revision for counters support: update, match */
  	{
  		.name		= "set",
  		.family		= NFPROTO_IPV4,
  		.revision	= 4,
  		.match		= set_match_v4,
  		.matchsize	= sizeof(struct xt_set_info_match_v4),
  		.checkentry	= set_match_v4_checkentry,
  		.destroy	= set_match_v4_destroy,
  		.me		= THIS_MODULE
  	},
  	{
  		.name		= "set",
  		.family		= NFPROTO_IPV6,
  		.revision	= 4,
  		.match		= set_match_v4,
  		.matchsize	= sizeof(struct xt_set_info_match_v4),
  		.checkentry	= set_match_v4_checkentry,
  		.destroy	= set_match_v4_destroy,
  		.me		= THIS_MODULE
  	},
d956798d8   Jozsef Kadlecsik   netfilter: xtable...
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
  };
  
  static struct xt_target set_targets[] __read_mostly = {
  	{
  		.name		= "SET",
  		.revision	= 0,
  		.family		= NFPROTO_IPV4,
  		.target		= set_target_v0,
  		.targetsize	= sizeof(struct xt_set_info_target_v0),
  		.checkentry	= set_target_v0_checkentry,
  		.destroy	= set_target_v0_destroy,
  		.me		= THIS_MODULE
  	},
  	{
  		.name		= "SET",
  		.revision	= 1,
  		.family		= NFPROTO_IPV4,
ac8cc925d   Jozsef Kadlecsik   netfilter: ipset:...
628
629
630
631
  		.target		= set_target_v1,
  		.targetsize	= sizeof(struct xt_set_info_target_v1),
  		.checkentry	= set_target_v1_checkentry,
  		.destroy	= set_target_v1_destroy,
d956798d8   Jozsef Kadlecsik   netfilter: xtable...
632
633
634
635
636
637
  		.me		= THIS_MODULE
  	},
  	{
  		.name		= "SET",
  		.revision	= 1,
  		.family		= NFPROTO_IPV6,
ac8cc925d   Jozsef Kadlecsik   netfilter: ipset:...
638
639
640
641
642
643
  		.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
  	},
3e0304a58   Jozsef Kadlecsik   netfilter: ipset:...
644
  	/* --timeout and --exist flags support */
ac8cc925d   Jozsef Kadlecsik   netfilter: ipset:...
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
  	{
  		.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,
d956798d8   Jozsef Kadlecsik   netfilter: xtable...
663
664
  		.me		= THIS_MODULE
  	},
76cea4109   Anton Danilov   netfilter: ipset:...
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
  	/* --map-set support */
  	{
  		.name		= "SET",
  		.revision	= 3,
  		.family		= NFPROTO_IPV4,
  		.target		= set_target_v3,
  		.targetsize	= sizeof(struct xt_set_info_target_v3),
  		.checkentry	= set_target_v3_checkentry,
  		.destroy	= set_target_v3_destroy,
  		.me		= THIS_MODULE
  	},
  	{
  		.name		= "SET",
  		.revision	= 3,
  		.family		= NFPROTO_IPV6,
  		.target		= set_target_v3,
  		.targetsize	= sizeof(struct xt_set_info_target_v3),
  		.checkentry	= set_target_v3_checkentry,
  		.destroy	= set_target_v3_destroy,
  		.me		= THIS_MODULE
  	},
d956798d8   Jozsef Kadlecsik   netfilter: xtable...
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
  };
  
  static int __init xt_set_init(void)
  {
  	int ret = xt_register_matches(set_matches, ARRAY_SIZE(set_matches));
  
  	if (!ret) {
  		ret = xt_register_targets(set_targets,
  					  ARRAY_SIZE(set_targets));
  		if (ret)
  			xt_unregister_matches(set_matches,
  					      ARRAY_SIZE(set_matches));
  	}
  	return ret;
  }
  
  static void __exit xt_set_fini(void)
  {
  	xt_unregister_matches(set_matches, ARRAY_SIZE(set_matches));
  	xt_unregister_targets(set_targets, ARRAY_SIZE(set_targets));
  }
  
  module_init(xt_set_init);
  module_exit(xt_set_fini);