Update my email address
[linux-2.6-block.git] / net / netfilter / xt_set.c
CommitLineData
d956798d
JK
1/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
2 * Patrick Schaaf <bof@bof.de>
3 * Martin Josefsson <gandalf@wlug.westbo.se>
fe03d474 4 * Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@netfilter.org>
d956798d
JK
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10
11/* Kernel module which implements the set match and SET target
ca0f6a5c
JK
12 * for netfilter/iptables.
13 */
d956798d
JK
14
15#include <linux/module.h>
16#include <linux/skbuff.h>
d956798d
JK
17
18#include <linux/netfilter/x_tables.h>
a9756e6f 19#include <linux/netfilter/ipset/ip_set.h>
a73f89a6 20#include <linux/netfilter/ipset/ip_set_timeout.h>
a9756e6f 21#include <uapi/linux/netfilter/xt_set.h>
d956798d
JK
22
23MODULE_LICENSE("GPL");
fe03d474 24MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@netfilter.org>");
d956798d
JK
25MODULE_DESCRIPTION("Xtables: IP set match and target module");
26MODULE_ALIAS("xt_SET");
27MODULE_ALIAS("ipt_set");
28MODULE_ALIAS("ip6t_set");
29MODULE_ALIAS("ipt_SET");
30MODULE_ALIAS("ip6t_SET");
31
32static inline int
33match_set(ip_set_id_t index, const struct sk_buff *skb,
b66554cf 34 const struct xt_action_param *par,
075e64c0 35 struct ip_set_adt_opt *opt, int inv)
d956798d 36{
b66554cf 37 if (ip_set_test(index, skb, par, opt))
d956798d
JK
38 inv = !inv;
39 return inv;
40}
41
4750005a
JK
42#define ADT_OPT(n, f, d, fs, cfs, t, p, b, po, bo) \
43struct ip_set_adt_opt n = { \
44 .family = f, \
45 .dim = d, \
46 .flags = fs, \
47 .cmdflags = cfs, \
48 .ext.timeout = t, \
49 .ext.packets = p, \
50 .ext.bytes = b, \
51 .ext.packets_op = po, \
52 .ext.bytes_op = bo, \
127f5591 53}
ac8cc925 54
d956798d
JK
55/* Revision 0 interface: backward compatible with netfilter/iptables */
56
57static bool
58set_match_v0(const struct sk_buff *skb, struct xt_action_param *par)
59{
60 const struct xt_set_info_match_v0 *info = par->matchinfo;
ca0f6a5c 61
613dbd95 62 ADT_OPT(opt, xt_family(par), info->match_set.u.compat.dim,
4750005a
JK
63 info->match_set.u.compat.flags, 0, UINT_MAX,
64 0, 0, 0, 0);
d956798d 65
b66554cf 66 return match_set(info->match_set.index, skb, par, &opt,
d956798d
JK
67 info->match_set.u.compat.flags & IPSET_INV_MATCH);
68}
69
70static void
71compat_flags(struct xt_set_info_v0 *info)
72{
73 u_int8_t i;
74
75 /* Fill out compatibility data according to enum ip_set_kopt */
76 info->u.compat.dim = IPSET_DIM_ZERO;
77 if (info->u.flags[0] & IPSET_MATCH_INV)
78 info->u.compat.flags |= IPSET_INV_MATCH;
ca0f6a5c 79 for (i = 0; i < IPSET_DIM_MAX - 1 && info->u.flags[i]; i++) {
d956798d
JK
80 info->u.compat.dim++;
81 if (info->u.flags[i] & IPSET_SRC)
ca0f6a5c 82 info->u.compat.flags |= (1 << info->u.compat.dim);
d956798d
JK
83 }
84}
85
86static int
87set_match_v0_checkentry(const struct xt_mtchk_param *par)
88{
89 struct xt_set_info_match_v0 *info = par->matchinfo;
90 ip_set_id_t index;
91
1785e8f4 92 index = ip_set_nfnl_get_byindex(par->net, info->match_set.index);
d956798d
JK
93
94 if (index == IPSET_INVALID_ID) {
c82b31c5
FW
95 pr_info_ratelimited("Cannot find set identified by id %u to match\n",
96 info->match_set.index);
d956798d
JK
97 return -ENOENT;
98 }
ca0f6a5c 99 if (info->match_set.u.flags[IPSET_DIM_MAX - 1] != 0) {
c82b31c5 100 pr_info_ratelimited("set match dimension is over the limit!\n");
1785e8f4 101 ip_set_nfnl_put(par->net, info->match_set.index);
d956798d
JK
102 return -ERANGE;
103 }
104
105 /* Fill out compatibility data */
106 compat_flags(&info->match_set);
107
108 return 0;
109}
110
111static void
112set_match_v0_destroy(const struct xt_mtdtor_param *par)
113{
114 struct xt_set_info_match_v0 *info = par->matchinfo;
115
1785e8f4 116 ip_set_nfnl_put(par->net, info->match_set.index);
d956798d
JK
117}
118
bd3129fc
JK
119/* Revision 1 match */
120
121static bool
122set_match_v1(const struct sk_buff *skb, struct xt_action_param *par)
123{
124 const struct xt_set_info_match_v1 *info = par->matchinfo;
ca0f6a5c 125
613dbd95 126 ADT_OPT(opt, xt_family(par), info->match_set.dim,
4750005a
JK
127 info->match_set.flags, 0, UINT_MAX,
128 0, 0, 0, 0);
bd3129fc
JK
129
130 if (opt.flags & IPSET_RETURN_NOMATCH)
131 opt.cmdflags |= IPSET_FLAG_RETURN_NOMATCH;
132
133 return match_set(info->match_set.index, skb, par, &opt,
134 info->match_set.flags & IPSET_INV_MATCH);
135}
136
137static int
138set_match_v1_checkentry(const struct xt_mtchk_param *par)
139{
140 struct xt_set_info_match_v1 *info = par->matchinfo;
141 ip_set_id_t index;
142
1785e8f4 143 index = ip_set_nfnl_get_byindex(par->net, info->match_set.index);
bd3129fc
JK
144
145 if (index == IPSET_INVALID_ID) {
c82b31c5
FW
146 pr_info_ratelimited("Cannot find set identified by id %u to match\n",
147 info->match_set.index);
bd3129fc
JK
148 return -ENOENT;
149 }
150 if (info->match_set.dim > IPSET_DIM_MAX) {
c82b31c5 151 pr_info_ratelimited("set match dimension is over the limit!\n");
1785e8f4 152 ip_set_nfnl_put(par->net, info->match_set.index);
bd3129fc
JK
153 return -ERANGE;
154 }
155
156 return 0;
157}
158
159static void
160set_match_v1_destroy(const struct xt_mtdtor_param *par)
161{
162 struct xt_set_info_match_v1 *info = par->matchinfo;
163
1785e8f4 164 ip_set_nfnl_put(par->net, info->match_set.index);
bd3129fc
JK
165}
166
167/* Revision 3 match */
168
bd3129fc
JK
169static bool
170set_match_v3(const struct sk_buff *skb, struct xt_action_param *par)
171{
172 const struct xt_set_info_match_v3 *info = par->matchinfo;
ca0f6a5c 173
613dbd95 174 ADT_OPT(opt, xt_family(par), info->match_set.dim,
4750005a
JK
175 info->match_set.flags, info->flags, UINT_MAX,
176 info->packets.value, info->bytes.value,
177 info->packets.op, info->bytes.op);
bd3129fc
JK
178
179 if (info->packets.op != IPSET_COUNTER_NONE ||
180 info->bytes.op != IPSET_COUNTER_NONE)
181 opt.cmdflags |= IPSET_FLAG_MATCH_COUNTERS;
182
4750005a
JK
183 return match_set(info->match_set.index, skb, par, &opt,
184 info->match_set.flags & IPSET_INV_MATCH);
bd3129fc
JK
185}
186
187#define set_match_v3_checkentry set_match_v1_checkentry
188#define set_match_v3_destroy set_match_v1_destroy
189
a51b9199
JK
190/* Revision 4 match */
191
a51b9199
JK
192static bool
193set_match_v4(const struct sk_buff *skb, struct xt_action_param *par)
194{
195 const struct xt_set_info_match_v4 *info = par->matchinfo;
ca0f6a5c 196
613dbd95 197 ADT_OPT(opt, xt_family(par), info->match_set.dim,
4750005a
JK
198 info->match_set.flags, info->flags, UINT_MAX,
199 info->packets.value, info->bytes.value,
200 info->packets.op, info->bytes.op);
a51b9199
JK
201
202 if (info->packets.op != IPSET_COUNTER_NONE ||
203 info->bytes.op != IPSET_COUNTER_NONE)
204 opt.cmdflags |= IPSET_FLAG_MATCH_COUNTERS;
205
4750005a
JK
206 return match_set(info->match_set.index, skb, par, &opt,
207 info->match_set.flags & IPSET_INV_MATCH);
a51b9199
JK
208}
209
210#define set_match_v4_checkentry set_match_v1_checkentry
211#define set_match_v4_destroy set_match_v1_destroy
212
bd3129fc
JK
213/* Revision 0 interface: backward compatible with netfilter/iptables */
214
d956798d
JK
215static unsigned int
216set_target_v0(struct sk_buff *skb, const struct xt_action_param *par)
217{
218 const struct xt_set_info_target_v0 *info = par->targinfo;
ca0f6a5c 219
613dbd95 220 ADT_OPT(add_opt, xt_family(par), info->add_set.u.compat.dim,
4750005a
JK
221 info->add_set.u.compat.flags, 0, UINT_MAX,
222 0, 0, 0, 0);
613dbd95 223 ADT_OPT(del_opt, xt_family(par), info->del_set.u.compat.dim,
4750005a
JK
224 info->del_set.u.compat.flags, 0, UINT_MAX,
225 0, 0, 0, 0);
d956798d
JK
226
227 if (info->add_set.index != IPSET_INVALID_ID)
b66554cf 228 ip_set_add(info->add_set.index, skb, par, &add_opt);
d956798d 229 if (info->del_set.index != IPSET_INVALID_ID)
b66554cf 230 ip_set_del(info->del_set.index, skb, par, &del_opt);
d956798d
JK
231
232 return XT_CONTINUE;
233}
234
235static int
236set_target_v0_checkentry(const struct xt_tgchk_param *par)
237{
238 struct xt_set_info_target_v0 *info = par->targinfo;
239 ip_set_id_t index;
240
241 if (info->add_set.index != IPSET_INVALID_ID) {
1785e8f4 242 index = ip_set_nfnl_get_byindex(par->net, info->add_set.index);
d956798d 243 if (index == IPSET_INVALID_ID) {
c82b31c5
FW
244 pr_info_ratelimited("Cannot find add_set index %u as target\n",
245 info->add_set.index);
d956798d
JK
246 return -ENOENT;
247 }
248 }
249
250 if (info->del_set.index != IPSET_INVALID_ID) {
1785e8f4 251 index = ip_set_nfnl_get_byindex(par->net, info->del_set.index);
d956798d 252 if (index == IPSET_INVALID_ID) {
c82b31c5
FW
253 pr_info_ratelimited("Cannot find del_set index %u as target\n",
254 info->del_set.index);
eafbd3fd 255 if (info->add_set.index != IPSET_INVALID_ID)
1785e8f4 256 ip_set_nfnl_put(par->net, info->add_set.index);
d956798d
JK
257 return -ENOENT;
258 }
259 }
ca0f6a5c
JK
260 if (info->add_set.u.flags[IPSET_DIM_MAX - 1] != 0 ||
261 info->del_set.u.flags[IPSET_DIM_MAX - 1] != 0) {
c82b31c5 262 pr_info_ratelimited("SET target dimension over the limit!\n");
eafbd3fd 263 if (info->add_set.index != IPSET_INVALID_ID)
1785e8f4 264 ip_set_nfnl_put(par->net, info->add_set.index);
eafbd3fd 265 if (info->del_set.index != IPSET_INVALID_ID)
1785e8f4 266 ip_set_nfnl_put(par->net, info->del_set.index);
d956798d
JK
267 return -ERANGE;
268 }
269
270 /* Fill out compatibility data */
271 compat_flags(&info->add_set);
272 compat_flags(&info->del_set);
273
274 return 0;
275}
276
277static void
278set_target_v0_destroy(const struct xt_tgdtor_param *par)
279{
280 const struct xt_set_info_target_v0 *info = par->targinfo;
281
282 if (info->add_set.index != IPSET_INVALID_ID)
1785e8f4 283 ip_set_nfnl_put(par->net, info->add_set.index);
d956798d 284 if (info->del_set.index != IPSET_INVALID_ID)
1785e8f4 285 ip_set_nfnl_put(par->net, info->del_set.index);
d956798d
JK
286}
287
bd3129fc 288/* Revision 1 target */
d956798d
JK
289
290static unsigned int
ac8cc925 291set_target_v1(struct sk_buff *skb, const struct xt_action_param *par)
d956798d 292{
ac8cc925 293 const struct xt_set_info_target_v1 *info = par->targinfo;
ca0f6a5c 294
613dbd95 295 ADT_OPT(add_opt, xt_family(par), info->add_set.dim,
4750005a
JK
296 info->add_set.flags, 0, UINT_MAX,
297 0, 0, 0, 0);
613dbd95 298 ADT_OPT(del_opt, xt_family(par), info->del_set.dim,
4750005a
JK
299 info->del_set.flags, 0, UINT_MAX,
300 0, 0, 0, 0);
d956798d
JK
301
302 if (info->add_set.index != IPSET_INVALID_ID)
b66554cf 303 ip_set_add(info->add_set.index, skb, par, &add_opt);
d956798d 304 if (info->del_set.index != IPSET_INVALID_ID)
b66554cf 305 ip_set_del(info->del_set.index, skb, par, &del_opt);
d956798d
JK
306
307 return XT_CONTINUE;
308}
309
310static int
ac8cc925 311set_target_v1_checkentry(const struct xt_tgchk_param *par)
d956798d 312{
ac8cc925 313 const struct xt_set_info_target_v1 *info = par->targinfo;
d956798d
JK
314 ip_set_id_t index;
315
316 if (info->add_set.index != IPSET_INVALID_ID) {
1785e8f4 317 index = ip_set_nfnl_get_byindex(par->net, info->add_set.index);
d956798d 318 if (index == IPSET_INVALID_ID) {
c82b31c5
FW
319 pr_info_ratelimited("Cannot find add_set index %u as target\n",
320 info->add_set.index);
d956798d
JK
321 return -ENOENT;
322 }
323 }
324
325 if (info->del_set.index != IPSET_INVALID_ID) {
1785e8f4 326 index = ip_set_nfnl_get_byindex(par->net, info->del_set.index);
d956798d 327 if (index == IPSET_INVALID_ID) {
c82b31c5
FW
328 pr_info_ratelimited("Cannot find del_set index %u as target\n",
329 info->del_set.index);
eafbd3fd 330 if (info->add_set.index != IPSET_INVALID_ID)
1785e8f4 331 ip_set_nfnl_put(par->net, info->add_set.index);
d956798d
JK
332 return -ENOENT;
333 }
334 }
335 if (info->add_set.dim > IPSET_DIM_MAX ||
eafbd3fd 336 info->del_set.dim > IPSET_DIM_MAX) {
c82b31c5 337 pr_info_ratelimited("SET target dimension over the limit!\n");
eafbd3fd 338 if (info->add_set.index != IPSET_INVALID_ID)
1785e8f4 339 ip_set_nfnl_put(par->net, info->add_set.index);
eafbd3fd 340 if (info->del_set.index != IPSET_INVALID_ID)
1785e8f4 341 ip_set_nfnl_put(par->net, info->del_set.index);
d956798d
JK
342 return -ERANGE;
343 }
344
345 return 0;
346}
347
348static void
ac8cc925 349set_target_v1_destroy(const struct xt_tgdtor_param *par)
d956798d 350{
ac8cc925 351 const struct xt_set_info_target_v1 *info = par->targinfo;
d956798d
JK
352
353 if (info->add_set.index != IPSET_INVALID_ID)
1785e8f4 354 ip_set_nfnl_put(par->net, info->add_set.index);
d956798d 355 if (info->del_set.index != IPSET_INVALID_ID)
1785e8f4 356 ip_set_nfnl_put(par->net, info->del_set.index);
d956798d
JK
357}
358
ac8cc925
JK
359/* Revision 2 target */
360
361static unsigned int
362set_target_v2(struct sk_buff *skb, const struct xt_action_param *par)
363{
364 const struct xt_set_info_target_v2 *info = par->targinfo;
ca0f6a5c 365
613dbd95 366 ADT_OPT(add_opt, xt_family(par), info->add_set.dim,
4750005a
JK
367 info->add_set.flags, info->flags, info->timeout,
368 0, 0, 0, 0);
613dbd95 369 ADT_OPT(del_opt, xt_family(par), info->del_set.dim,
4750005a
JK
370 info->del_set.flags, 0, UINT_MAX,
371 0, 0, 0, 0);
ac8cc925 372
127f5591 373 /* Normalize to fit into jiffies */
075e64c0 374 if (add_opt.ext.timeout != IPSET_NO_TIMEOUT &&
30a2e107
JK
375 add_opt.ext.timeout > IPSET_MAX_TIMEOUT)
376 add_opt.ext.timeout = IPSET_MAX_TIMEOUT;
ac8cc925 377 if (info->add_set.index != IPSET_INVALID_ID)
b66554cf 378 ip_set_add(info->add_set.index, skb, par, &add_opt);
ac8cc925 379 if (info->del_set.index != IPSET_INVALID_ID)
b66554cf 380 ip_set_del(info->del_set.index, skb, par, &del_opt);
ac8cc925
JK
381
382 return XT_CONTINUE;
383}
384
385#define set_target_v2_checkentry set_target_v1_checkentry
386#define set_target_v2_destroy set_target_v1_destroy
387
76cea410
AD
388/* Revision 3 target */
389
bec810d9
JK
390#define MOPT(opt, member) ((opt).ext.skbinfo.member)
391
76cea410
AD
392static unsigned int
393set_target_v3(struct sk_buff *skb, const struct xt_action_param *par)
394{
395 const struct xt_set_info_target_v3 *info = par->targinfo;
ca0f6a5c
JK
396 int ret;
397
613dbd95 398 ADT_OPT(add_opt, xt_family(par), info->add_set.dim,
4750005a
JK
399 info->add_set.flags, info->flags, info->timeout,
400 0, 0, 0, 0);
613dbd95 401 ADT_OPT(del_opt, xt_family(par), info->del_set.dim,
4750005a
JK
402 info->del_set.flags, 0, UINT_MAX,
403 0, 0, 0, 0);
613dbd95 404 ADT_OPT(map_opt, xt_family(par), info->map_set.dim,
4750005a
JK
405 info->map_set.flags, 0, UINT_MAX,
406 0, 0, 0, 0);
76cea410 407
76cea410
AD
408 /* Normalize to fit into jiffies */
409 if (add_opt.ext.timeout != IPSET_NO_TIMEOUT &&
30a2e107
JK
410 add_opt.ext.timeout > IPSET_MAX_TIMEOUT)
411 add_opt.ext.timeout = IPSET_MAX_TIMEOUT;
76cea410
AD
412 if (info->add_set.index != IPSET_INVALID_ID)
413 ip_set_add(info->add_set.index, skb, par, &add_opt);
414 if (info->del_set.index != IPSET_INVALID_ID)
415 ip_set_del(info->del_set.index, skb, par, &del_opt);
416 if (info->map_set.index != IPSET_INVALID_ID) {
417 map_opt.cmdflags |= info->flags & (IPSET_FLAG_MAP_SKBMARK |
418 IPSET_FLAG_MAP_SKBPRIO |
419 IPSET_FLAG_MAP_SKBQUEUE);
420 ret = match_set(info->map_set.index, skb, par, &map_opt,
421 info->map_set.flags & IPSET_INV_MATCH);
422 if (!ret)
423 return XT_CONTINUE;
424 if (map_opt.cmdflags & IPSET_FLAG_MAP_SKBMARK)
bec810d9
JK
425 skb->mark = (skb->mark & ~MOPT(map_opt,skbmarkmask))
426 ^ MOPT(map_opt, skbmark);
76cea410 427 if (map_opt.cmdflags & IPSET_FLAG_MAP_SKBPRIO)
bec810d9 428 skb->priority = MOPT(map_opt, skbprio);
76cea410
AD
429 if ((map_opt.cmdflags & IPSET_FLAG_MAP_SKBQUEUE) &&
430 skb->dev &&
bec810d9
JK
431 skb->dev->real_num_tx_queues > MOPT(map_opt, skbqueue))
432 skb_set_queue_mapping(skb, MOPT(map_opt, skbqueue));
76cea410
AD
433 }
434 return XT_CONTINUE;
435}
436
76cea410
AD
437static int
438set_target_v3_checkentry(const struct xt_tgchk_param *par)
439{
440 const struct xt_set_info_target_v3 *info = par->targinfo;
441 ip_set_id_t index;
b1732e16 442 int ret = 0;
76cea410
AD
443
444 if (info->add_set.index != IPSET_INVALID_ID) {
445 index = ip_set_nfnl_get_byindex(par->net,
446 info->add_set.index);
447 if (index == IPSET_INVALID_ID) {
c82b31c5
FW
448 pr_info_ratelimited("Cannot find add_set index %u as target\n",
449 info->add_set.index);
76cea410
AD
450 return -ENOENT;
451 }
452 }
453
454 if (info->del_set.index != IPSET_INVALID_ID) {
455 index = ip_set_nfnl_get_byindex(par->net,
456 info->del_set.index);
457 if (index == IPSET_INVALID_ID) {
c82b31c5
FW
458 pr_info_ratelimited("Cannot find del_set index %u as target\n",
459 info->del_set.index);
b1732e16
JK
460 ret = -ENOENT;
461 goto cleanup_add;
76cea410
AD
462 }
463 }
464
465 if (info->map_set.index != IPSET_INVALID_ID) {
466 if (strncmp(par->table, "mangle", 7)) {
c82b31c5 467 pr_info_ratelimited("--map-set only usable from mangle table\n");
b1732e16
JK
468 ret = -EINVAL;
469 goto cleanup_del;
76cea410
AD
470 }
471 if (((info->flags & IPSET_FLAG_MAP_SKBPRIO) |
472 (info->flags & IPSET_FLAG_MAP_SKBQUEUE)) &&
9dcceb13 473 (par->hook_mask & ~(1 << NF_INET_FORWARD |
76cea410
AD
474 1 << NF_INET_LOCAL_OUT |
475 1 << NF_INET_POST_ROUTING))) {
c82b31c5 476 pr_info_ratelimited("mapping of prio or/and queue is allowed only from OUTPUT/FORWARD/POSTROUTING chains\n");
b1732e16
JK
477 ret = -EINVAL;
478 goto cleanup_del;
76cea410
AD
479 }
480 index = ip_set_nfnl_get_byindex(par->net,
481 info->map_set.index);
482 if (index == IPSET_INVALID_ID) {
c82b31c5
FW
483 pr_info_ratelimited("Cannot find map_set index %u as target\n",
484 info->map_set.index);
b1732e16
JK
485 ret = -ENOENT;
486 goto cleanup_del;
76cea410
AD
487 }
488 }
489
490 if (info->add_set.dim > IPSET_DIM_MAX ||
491 info->del_set.dim > IPSET_DIM_MAX ||
492 info->map_set.dim > IPSET_DIM_MAX) {
c82b31c5 493 pr_info_ratelimited("SET target dimension over the limit!\n");
b1732e16
JK
494 ret = -ERANGE;
495 goto cleanup_mark;
76cea410
AD
496 }
497
498 return 0;
b1732e16
JK
499cleanup_mark:
500 if (info->map_set.index != IPSET_INVALID_ID)
501 ip_set_nfnl_put(par->net, info->map_set.index);
502cleanup_del:
503 if (info->del_set.index != IPSET_INVALID_ID)
504 ip_set_nfnl_put(par->net, info->del_set.index);
505cleanup_add:
506 if (info->add_set.index != IPSET_INVALID_ID)
507 ip_set_nfnl_put(par->net, info->add_set.index);
508 return ret;
76cea410
AD
509}
510
511static void
512set_target_v3_destroy(const struct xt_tgdtor_param *par)
513{
514 const struct xt_set_info_target_v3 *info = par->targinfo;
515
516 if (info->add_set.index != IPSET_INVALID_ID)
517 ip_set_nfnl_put(par->net, info->add_set.index);
518 if (info->del_set.index != IPSET_INVALID_ID)
519 ip_set_nfnl_put(par->net, info->del_set.index);
520 if (info->map_set.index != IPSET_INVALID_ID)
521 ip_set_nfnl_put(par->net, info->map_set.index);
522}
523
d956798d
JK
524static struct xt_match set_matches[] __read_mostly = {
525 {
526 .name = "set",
527 .family = NFPROTO_IPV4,
528 .revision = 0,
529 .match = set_match_v0,
530 .matchsize = sizeof(struct xt_set_info_match_v0),
531 .checkentry = set_match_v0_checkentry,
532 .destroy = set_match_v0_destroy,
533 .me = THIS_MODULE
534 },
535 {
536 .name = "set",
537 .family = NFPROTO_IPV4,
538 .revision = 1,
ac8cc925
JK
539 .match = set_match_v1,
540 .matchsize = sizeof(struct xt_set_info_match_v1),
541 .checkentry = set_match_v1_checkentry,
542 .destroy = set_match_v1_destroy,
d956798d
JK
543 .me = THIS_MODULE
544 },
545 {
546 .name = "set",
547 .family = NFPROTO_IPV6,
548 .revision = 1,
ac8cc925
JK
549 .match = set_match_v1,
550 .matchsize = sizeof(struct xt_set_info_match_v1),
551 .checkentry = set_match_v1_checkentry,
552 .destroy = set_match_v1_destroy,
d956798d
JK
553 .me = THIS_MODULE
554 },
3e0304a5
JK
555 /* --return-nomatch flag support */
556 {
557 .name = "set",
558 .family = NFPROTO_IPV4,
559 .revision = 2,
560 .match = set_match_v1,
561 .matchsize = sizeof(struct xt_set_info_match_v1),
562 .checkentry = set_match_v1_checkentry,
563 .destroy = set_match_v1_destroy,
564 .me = THIS_MODULE
565 },
566 {
567 .name = "set",
568 .family = NFPROTO_IPV6,
569 .revision = 2,
570 .match = set_match_v1,
571 .matchsize = sizeof(struct xt_set_info_match_v1),
572 .checkentry = set_match_v1_checkentry,
573 .destroy = set_match_v1_destroy,
574 .me = THIS_MODULE
575 },
6e01781d
JK
576 /* counters support: update, match */
577 {
578 .name = "set",
579 .family = NFPROTO_IPV4,
580 .revision = 3,
581 .match = set_match_v3,
582 .matchsize = sizeof(struct xt_set_info_match_v3),
583 .checkentry = set_match_v3_checkentry,
584 .destroy = set_match_v3_destroy,
585 .me = THIS_MODULE
586 },
587 {
588 .name = "set",
589 .family = NFPROTO_IPV6,
590 .revision = 3,
591 .match = set_match_v3,
592 .matchsize = sizeof(struct xt_set_info_match_v3),
593 .checkentry = set_match_v3_checkentry,
594 .destroy = set_match_v3_destroy,
595 .me = THIS_MODULE
596 },
a51b9199
JK
597 /* new revision for counters support: update, match */
598 {
599 .name = "set",
600 .family = NFPROTO_IPV4,
601 .revision = 4,
602 .match = set_match_v4,
603 .matchsize = sizeof(struct xt_set_info_match_v4),
604 .checkentry = set_match_v4_checkentry,
605 .destroy = set_match_v4_destroy,
606 .me = THIS_MODULE
607 },
608 {
609 .name = "set",
610 .family = NFPROTO_IPV6,
611 .revision = 4,
612 .match = set_match_v4,
613 .matchsize = sizeof(struct xt_set_info_match_v4),
614 .checkentry = set_match_v4_checkentry,
615 .destroy = set_match_v4_destroy,
616 .me = THIS_MODULE
617 },
d956798d
JK
618};
619
620static struct xt_target set_targets[] __read_mostly = {
621 {
622 .name = "SET",
623 .revision = 0,
624 .family = NFPROTO_IPV4,
625 .target = set_target_v0,
626 .targetsize = sizeof(struct xt_set_info_target_v0),
627 .checkentry = set_target_v0_checkentry,
628 .destroy = set_target_v0_destroy,
629 .me = THIS_MODULE
630 },
631 {
632 .name = "SET",
633 .revision = 1,
634 .family = NFPROTO_IPV4,
ac8cc925
JK
635 .target = set_target_v1,
636 .targetsize = sizeof(struct xt_set_info_target_v1),
637 .checkentry = set_target_v1_checkentry,
638 .destroy = set_target_v1_destroy,
d956798d
JK
639 .me = THIS_MODULE
640 },
641 {
642 .name = "SET",
643 .revision = 1,
644 .family = NFPROTO_IPV6,
ac8cc925
JK
645 .target = set_target_v1,
646 .targetsize = sizeof(struct xt_set_info_target_v1),
647 .checkentry = set_target_v1_checkentry,
648 .destroy = set_target_v1_destroy,
649 .me = THIS_MODULE
650 },
3e0304a5 651 /* --timeout and --exist flags support */
ac8cc925
JK
652 {
653 .name = "SET",
654 .revision = 2,
655 .family = NFPROTO_IPV4,
656 .target = set_target_v2,
657 .targetsize = sizeof(struct xt_set_info_target_v2),
658 .checkentry = set_target_v2_checkentry,
659 .destroy = set_target_v2_destroy,
660 .me = THIS_MODULE
661 },
662 {
663 .name = "SET",
664 .revision = 2,
665 .family = NFPROTO_IPV6,
666 .target = set_target_v2,
667 .targetsize = sizeof(struct xt_set_info_target_v2),
668 .checkentry = set_target_v2_checkentry,
669 .destroy = set_target_v2_destroy,
d956798d
JK
670 .me = THIS_MODULE
671 },
76cea410
AD
672 /* --map-set support */
673 {
674 .name = "SET",
675 .revision = 3,
676 .family = NFPROTO_IPV4,
677 .target = set_target_v3,
678 .targetsize = sizeof(struct xt_set_info_target_v3),
679 .checkentry = set_target_v3_checkentry,
680 .destroy = set_target_v3_destroy,
681 .me = THIS_MODULE
682 },
683 {
684 .name = "SET",
685 .revision = 3,
686 .family = NFPROTO_IPV6,
687 .target = set_target_v3,
688 .targetsize = sizeof(struct xt_set_info_target_v3),
689 .checkentry = set_target_v3_checkentry,
690 .destroy = set_target_v3_destroy,
691 .me = THIS_MODULE
692 },
d956798d
JK
693};
694
695static int __init xt_set_init(void)
696{
697 int ret = xt_register_matches(set_matches, ARRAY_SIZE(set_matches));
698
699 if (!ret) {
700 ret = xt_register_targets(set_targets,
701 ARRAY_SIZE(set_targets));
702 if (ret)
703 xt_unregister_matches(set_matches,
704 ARRAY_SIZE(set_matches));
705 }
706 return ret;
707}
708
709static void __exit xt_set_fini(void)
710{
711 xt_unregister_matches(set_matches, ARRAY_SIZE(set_matches));
712 xt_unregister_targets(set_targets, ARRAY_SIZE(set_targets));
713}
714
715module_init(xt_set_init);
716module_exit(xt_set_fini);