1
2
3
4
5
6
7
8
9
10
11
12
13
14
15#include <linux/module.h>
16#include <linux/skbuff.h>
17
18#include <linux/netfilter/x_tables.h>
19#include <linux/netfilter/ipset/ip_set.h>
20#include <linux/netfilter/ipset/ip_set_timeout.h>
21#include <uapi/linux/netfilter/xt_set.h>
22
23MODULE_LICENSE("GPL");
24MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
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,
34 const struct xt_action_param *par,
35 struct ip_set_adt_opt *opt, int inv)
36{
37 if (ip_set_test(index, skb, par, opt))
38 inv = !inv;
39 return inv;
40}
41
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, \
53}
54
55
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;
61
62 ADT_OPT(opt, xt_family(par), info->match_set.u.compat.dim,
63 info->match_set.u.compat.flags, 0, UINT_MAX,
64 0, 0, 0, 0);
65
66 return match_set(info->match_set.index, skb, par, &opt,
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
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;
79 for (i = 0; i < IPSET_DIM_MAX - 1 && info->u.flags[i]; i++) {
80 info->u.compat.dim++;
81 if (info->u.flags[i] & IPSET_SRC)
82 info->u.compat.flags |= (1 << info->u.compat.dim);
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
92 index = ip_set_nfnl_get_byindex(par->net, info->match_set.index);
93
94 if (index == IPSET_INVALID_ID) {
95 pr_info_ratelimited("Cannot find set identified by id %u to match\n",
96 info->match_set.index);
97 return -ENOENT;
98 }
99 if (info->match_set.u.flags[IPSET_DIM_MAX - 1] != 0) {
100 pr_info_ratelimited("set match dimension is over the limit!\n");
101 ip_set_nfnl_put(par->net, info->match_set.index);
102 return -ERANGE;
103 }
104
105
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
116 ip_set_nfnl_put(par->net, info->match_set.index);
117}
118
119
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;
125
126 ADT_OPT(opt, xt_family(par), info->match_set.dim,
127 info->match_set.flags, 0, UINT_MAX,
128 0, 0, 0, 0);
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
143 index = ip_set_nfnl_get_byindex(par->net, info->match_set.index);
144
145 if (index == IPSET_INVALID_ID) {
146 pr_info_ratelimited("Cannot find set identified by id %u to match\n",
147 info->match_set.index);
148 return -ENOENT;
149 }
150 if (info->match_set.dim > IPSET_DIM_MAX) {
151 pr_info_ratelimited("set match dimension is over the limit!\n");
152 ip_set_nfnl_put(par->net, info->match_set.index);
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
164 ip_set_nfnl_put(par->net, info->match_set.index);
165}
166
167
168
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;
173
174 ADT_OPT(opt, xt_family(par), info->match_set.dim,
175 info->match_set.flags, info->flags, UINT_MAX,
176 info->packets.value, info->bytes.value,
177 info->packets.op, info->bytes.op);
178
179 if (info->packets.op != IPSET_COUNTER_NONE ||
180 info->bytes.op != IPSET_COUNTER_NONE)
181 opt.cmdflags |= IPSET_FLAG_MATCH_COUNTERS;
182
183 return match_set(info->match_set.index, skb, par, &opt,
184 info->match_set.flags & IPSET_INV_MATCH);
185}
186
187#define set_match_v3_checkentry set_match_v1_checkentry
188#define set_match_v3_destroy set_match_v1_destroy
189
190
191
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;
196
197 ADT_OPT(opt, xt_family(par), info->match_set.dim,
198 info->match_set.flags, info->flags, UINT_MAX,
199 info->packets.value, info->bytes.value,
200 info->packets.op, info->bytes.op);
201
202 if (info->packets.op != IPSET_COUNTER_NONE ||
203 info->bytes.op != IPSET_COUNTER_NONE)
204 opt.cmdflags |= IPSET_FLAG_MATCH_COUNTERS;
205
206 return match_set(info->match_set.index, skb, par, &opt,
207 info->match_set.flags & IPSET_INV_MATCH);
208}
209
210#define set_match_v4_checkentry set_match_v1_checkentry
211#define set_match_v4_destroy set_match_v1_destroy
212
213
214
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;
219
220 ADT_OPT(add_opt, xt_family(par), info->add_set.u.compat.dim,
221 info->add_set.u.compat.flags, 0, UINT_MAX,
222 0, 0, 0, 0);
223 ADT_OPT(del_opt, xt_family(par), info->del_set.u.compat.dim,
224 info->del_set.u.compat.flags, 0, UINT_MAX,
225 0, 0, 0, 0);
226
227 if (info->add_set.index != IPSET_INVALID_ID)
228 ip_set_add(info->add_set.index, skb, par, &add_opt);
229 if (info->del_set.index != IPSET_INVALID_ID)
230 ip_set_del(info->del_set.index, skb, par, &del_opt);
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) {
242 index = ip_set_nfnl_get_byindex(par->net, info->add_set.index);
243 if (index == IPSET_INVALID_ID) {
244 pr_info_ratelimited("Cannot find add_set index %u as target\n",
245 info->add_set.index);
246 return -ENOENT;
247 }
248 }
249
250 if (info->del_set.index != IPSET_INVALID_ID) {
251 index = ip_set_nfnl_get_byindex(par->net, info->del_set.index);
252 if (index == IPSET_INVALID_ID) {
253 pr_info_ratelimited("Cannot find del_set index %u as target\n",
254 info->del_set.index);
255 if (info->add_set.index != IPSET_INVALID_ID)
256 ip_set_nfnl_put(par->net, info->add_set.index);
257 return -ENOENT;
258 }
259 }
260 if (info->add_set.u.flags[IPSET_DIM_MAX - 1] != 0 ||
261 info->del_set.u.flags[IPSET_DIM_MAX - 1] != 0) {
262 pr_info_ratelimited("SET target dimension over the limit!\n");
263 if (info->add_set.index != IPSET_INVALID_ID)
264 ip_set_nfnl_put(par->net, info->add_set.index);
265 if (info->del_set.index != IPSET_INVALID_ID)
266 ip_set_nfnl_put(par->net, info->del_set.index);
267 return -ERANGE;
268 }
269
270
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)
283 ip_set_nfnl_put(par->net, info->add_set.index);
284 if (info->del_set.index != IPSET_INVALID_ID)
285 ip_set_nfnl_put(par->net, info->del_set.index);
286}
287
288
289
290static unsigned int
291set_target_v1(struct sk_buff *skb, const struct xt_action_param *par)
292{
293 const struct xt_set_info_target_v1 *info = par->targinfo;
294
295 ADT_OPT(add_opt, xt_family(par), info->add_set.dim,
296 info->add_set.flags, 0, UINT_MAX,
297 0, 0, 0, 0);
298 ADT_OPT(del_opt, xt_family(par), info->del_set.dim,
299 info->del_set.flags, 0, UINT_MAX,
300 0, 0, 0, 0);
301
302 if (info->add_set.index != IPSET_INVALID_ID)
303 ip_set_add(info->add_set.index, skb, par, &add_opt);
304 if (info->del_set.index != IPSET_INVALID_ID)
305 ip_set_del(info->del_set.index, skb, par, &del_opt);
306
307 return XT_CONTINUE;
308}
309
310static int
311set_target_v1_checkentry(const struct xt_tgchk_param *par)
312{
313 const struct xt_set_info_target_v1 *info = par->targinfo;
314 ip_set_id_t index;
315
316 if (info->add_set.index != IPSET_INVALID_ID) {
317 index = ip_set_nfnl_get_byindex(par->net, info->add_set.index);
318 if (index == IPSET_INVALID_ID) {
319 pr_info_ratelimited("Cannot find add_set index %u as target\n",
320 info->add_set.index);
321 return -ENOENT;
322 }
323 }
324
325 if (info->del_set.index != IPSET_INVALID_ID) {
326 index = ip_set_nfnl_get_byindex(par->net, info->del_set.index);
327 if (index == IPSET_INVALID_ID) {
328 pr_info_ratelimited("Cannot find del_set index %u as target\n",
329 info->del_set.index);
330 if (info->add_set.index != IPSET_INVALID_ID)
331 ip_set_nfnl_put(par->net, info->add_set.index);
332 return -ENOENT;
333 }
334 }
335 if (info->add_set.dim > IPSET_DIM_MAX ||
336 info->del_set.dim > IPSET_DIM_MAX) {
337 pr_info_ratelimited("SET target dimension over the limit!\n");
338 if (info->add_set.index != IPSET_INVALID_ID)
339 ip_set_nfnl_put(par->net, info->add_set.index);
340 if (info->del_set.index != IPSET_INVALID_ID)
341 ip_set_nfnl_put(par->net, info->del_set.index);
342 return -ERANGE;
343 }
344
345 return 0;
346}
347
348static void
349set_target_v1_destroy(const struct xt_tgdtor_param *par)
350{
351 const struct xt_set_info_target_v1 *info = par->targinfo;
352
353 if (info->add_set.index != IPSET_INVALID_ID)
354 ip_set_nfnl_put(par->net, info->add_set.index);
355 if (info->del_set.index != IPSET_INVALID_ID)
356 ip_set_nfnl_put(par->net, info->del_set.index);
357}
358
359
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;
365
366 ADT_OPT(add_opt, xt_family(par), info->add_set.dim,
367 info->add_set.flags, info->flags, info->timeout,
368 0, 0, 0, 0);
369 ADT_OPT(del_opt, xt_family(par), info->del_set.dim,
370 info->del_set.flags, 0, UINT_MAX,
371 0, 0, 0, 0);
372
373
374 if (add_opt.ext.timeout != IPSET_NO_TIMEOUT &&
375 add_opt.ext.timeout > IPSET_MAX_TIMEOUT)
376 add_opt.ext.timeout = IPSET_MAX_TIMEOUT;
377 if (info->add_set.index != IPSET_INVALID_ID)
378 ip_set_add(info->add_set.index, skb, par, &add_opt);
379 if (info->del_set.index != IPSET_INVALID_ID)
380 ip_set_del(info->del_set.index, skb, par, &del_opt);
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
388
389
390#define MOPT(opt, member) ((opt).ext.skbinfo.member)
391
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;
396 int ret;
397
398 ADT_OPT(add_opt, xt_family(par), info->add_set.dim,
399 info->add_set.flags, info->flags, info->timeout,
400 0, 0, 0, 0);
401 ADT_OPT(del_opt, xt_family(par), info->del_set.dim,
402 info->del_set.flags, 0, UINT_MAX,
403 0, 0, 0, 0);
404 ADT_OPT(map_opt, xt_family(par), info->map_set.dim,
405 info->map_set.flags, 0, UINT_MAX,
406 0, 0, 0, 0);
407
408
409 if (add_opt.ext.timeout != IPSET_NO_TIMEOUT &&
410 add_opt.ext.timeout > IPSET_MAX_TIMEOUT)
411 add_opt.ext.timeout = IPSET_MAX_TIMEOUT;
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)
425 skb->mark = (skb->mark & ~MOPT(map_opt,skbmarkmask))
426 ^ MOPT(map_opt, skbmark);
427 if (map_opt.cmdflags & IPSET_FLAG_MAP_SKBPRIO)
428 skb->priority = MOPT(map_opt, skbprio);
429 if ((map_opt.cmdflags & IPSET_FLAG_MAP_SKBQUEUE) &&
430 skb->dev &&
431 skb->dev->real_num_tx_queues > MOPT(map_opt, skbqueue))
432 skb_set_queue_mapping(skb, MOPT(map_opt, skbqueue));
433 }
434 return XT_CONTINUE;
435}
436
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;
442
443 if (info->add_set.index != IPSET_INVALID_ID) {
444 index = ip_set_nfnl_get_byindex(par->net,
445 info->add_set.index);
446 if (index == IPSET_INVALID_ID) {
447 pr_info_ratelimited("Cannot find add_set index %u as target\n",
448 info->add_set.index);
449 return -ENOENT;
450 }
451 }
452
453 if (info->del_set.index != IPSET_INVALID_ID) {
454 index = ip_set_nfnl_get_byindex(par->net,
455 info->del_set.index);
456 if (index == IPSET_INVALID_ID) {
457 pr_info_ratelimited("Cannot find del_set index %u as target\n",
458 info->del_set.index);
459 if (info->add_set.index != IPSET_INVALID_ID)
460 ip_set_nfnl_put(par->net,
461 info->add_set.index);
462 return -ENOENT;
463 }
464 }
465
466 if (info->map_set.index != IPSET_INVALID_ID) {
467 if (strncmp(par->table, "mangle", 7)) {
468 pr_info_ratelimited("--map-set only usable from mangle table\n");
469 return -EINVAL;
470 }
471 if (((info->flags & IPSET_FLAG_MAP_SKBPRIO) |
472 (info->flags & IPSET_FLAG_MAP_SKBQUEUE)) &&
473 (par->hook_mask & ~(1 << NF_INET_FORWARD |
474 1 << NF_INET_LOCAL_OUT |
475 1 << NF_INET_POST_ROUTING))) {
476 pr_info_ratelimited("mapping of prio or/and queue is allowed only from OUTPUT/FORWARD/POSTROUTING chains\n");
477 return -EINVAL;
478 }
479 index = ip_set_nfnl_get_byindex(par->net,
480 info->map_set.index);
481 if (index == IPSET_INVALID_ID) {
482 pr_info_ratelimited("Cannot find map_set index %u as target\n",
483 info->map_set.index);
484 if (info->add_set.index != IPSET_INVALID_ID)
485 ip_set_nfnl_put(par->net,
486 info->add_set.index);
487 if (info->del_set.index != IPSET_INVALID_ID)
488 ip_set_nfnl_put(par->net,
489 info->del_set.index);
490 return -ENOENT;
491 }
492 }
493
494 if (info->add_set.dim > IPSET_DIM_MAX ||
495 info->del_set.dim > IPSET_DIM_MAX ||
496 info->map_set.dim > IPSET_DIM_MAX) {
497 pr_info_ratelimited("SET target dimension over the limit!\n");
498 if (info->add_set.index != IPSET_INVALID_ID)
499 ip_set_nfnl_put(par->net, info->add_set.index);
500 if (info->del_set.index != IPSET_INVALID_ID)
501 ip_set_nfnl_put(par->net, info->del_set.index);
502 if (info->map_set.index != IPSET_INVALID_ID)
503 ip_set_nfnl_put(par->net, info->map_set.index);
504 return -ERANGE;
505 }
506
507 return 0;
508}
509
510static void
511set_target_v3_destroy(const struct xt_tgdtor_param *par)
512{
513 const struct xt_set_info_target_v3 *info = par->targinfo;
514
515 if (info->add_set.index != IPSET_INVALID_ID)
516 ip_set_nfnl_put(par->net, info->add_set.index);
517 if (info->del_set.index != IPSET_INVALID_ID)
518 ip_set_nfnl_put(par->net, info->del_set.index);
519 if (info->map_set.index != IPSET_INVALID_ID)
520 ip_set_nfnl_put(par->net, info->map_set.index);
521}
522
523static struct xt_match set_matches[] __read_mostly = {
524 {
525 .name = "set",
526 .family = NFPROTO_IPV4,
527 .revision = 0,
528 .match = set_match_v0,
529 .matchsize = sizeof(struct xt_set_info_match_v0),
530 .checkentry = set_match_v0_checkentry,
531 .destroy = set_match_v0_destroy,
532 .me = THIS_MODULE
533 },
534 {
535 .name = "set",
536 .family = NFPROTO_IPV4,
537 .revision = 1,
538 .match = set_match_v1,
539 .matchsize = sizeof(struct xt_set_info_match_v1),
540 .checkentry = set_match_v1_checkentry,
541 .destroy = set_match_v1_destroy,
542 .me = THIS_MODULE
543 },
544 {
545 .name = "set",
546 .family = NFPROTO_IPV6,
547 .revision = 1,
548 .match = set_match_v1,
549 .matchsize = sizeof(struct xt_set_info_match_v1),
550 .checkentry = set_match_v1_checkentry,
551 .destroy = set_match_v1_destroy,
552 .me = THIS_MODULE
553 },
554
555 {
556 .name = "set",
557 .family = NFPROTO_IPV4,
558 .revision = 2,
559 .match = set_match_v1,
560 .matchsize = sizeof(struct xt_set_info_match_v1),
561 .checkentry = set_match_v1_checkentry,
562 .destroy = set_match_v1_destroy,
563 .me = THIS_MODULE
564 },
565 {
566 .name = "set",
567 .family = NFPROTO_IPV6,
568 .revision = 2,
569 .match = set_match_v1,
570 .matchsize = sizeof(struct xt_set_info_match_v1),
571 .checkentry = set_match_v1_checkentry,
572 .destroy = set_match_v1_destroy,
573 .me = THIS_MODULE
574 },
575
576 {
577 .name = "set",
578 .family = NFPROTO_IPV4,
579 .revision = 3,
580 .match = set_match_v3,
581 .matchsize = sizeof(struct xt_set_info_match_v3),
582 .checkentry = set_match_v3_checkentry,
583 .destroy = set_match_v3_destroy,
584 .me = THIS_MODULE
585 },
586 {
587 .name = "set",
588 .family = NFPROTO_IPV6,
589 .revision = 3,
590 .match = set_match_v3,
591 .matchsize = sizeof(struct xt_set_info_match_v3),
592 .checkentry = set_match_v3_checkentry,
593 .destroy = set_match_v3_destroy,
594 .me = THIS_MODULE
595 },
596
597 {
598 .name = "set",
599 .family = NFPROTO_IPV4,
600 .revision = 4,
601 .match = set_match_v4,
602 .matchsize = sizeof(struct xt_set_info_match_v4),
603 .checkentry = set_match_v4_checkentry,
604 .destroy = set_match_v4_destroy,
605 .me = THIS_MODULE
606 },
607 {
608 .name = "set",
609 .family = NFPROTO_IPV6,
610 .revision = 4,
611 .match = set_match_v4,
612 .matchsize = sizeof(struct xt_set_info_match_v4),
613 .checkentry = set_match_v4_checkentry,
614 .destroy = set_match_v4_destroy,
615 .me = THIS_MODULE
616 },
617};
618
619static struct xt_target set_targets[] __read_mostly = {
620 {
621 .name = "SET",
622 .revision = 0,
623 .family = NFPROTO_IPV4,
624 .target = set_target_v0,
625 .targetsize = sizeof(struct xt_set_info_target_v0),
626 .checkentry = set_target_v0_checkentry,
627 .destroy = set_target_v0_destroy,
628 .me = THIS_MODULE
629 },
630 {
631 .name = "SET",
632 .revision = 1,
633 .family = NFPROTO_IPV4,
634 .target = set_target_v1,
635 .targetsize = sizeof(struct xt_set_info_target_v1),
636 .checkentry = set_target_v1_checkentry,
637 .destroy = set_target_v1_destroy,
638 .me = THIS_MODULE
639 },
640 {
641 .name = "SET",
642 .revision = 1,
643 .family = NFPROTO_IPV6,
644 .target = set_target_v1,
645 .targetsize = sizeof(struct xt_set_info_target_v1),
646 .checkentry = set_target_v1_checkentry,
647 .destroy = set_target_v1_destroy,
648 .me = THIS_MODULE
649 },
650
651 {
652 .name = "SET",
653 .revision = 2,
654 .family = NFPROTO_IPV4,
655 .target = set_target_v2,
656 .targetsize = sizeof(struct xt_set_info_target_v2),
657 .checkentry = set_target_v2_checkentry,
658 .destroy = set_target_v2_destroy,
659 .me = THIS_MODULE
660 },
661 {
662 .name = "SET",
663 .revision = 2,
664 .family = NFPROTO_IPV6,
665 .target = set_target_v2,
666 .targetsize = sizeof(struct xt_set_info_target_v2),
667 .checkentry = set_target_v2_checkentry,
668 .destroy = set_target_v2_destroy,
669 .me = THIS_MODULE
670 },
671
672 {
673 .name = "SET",
674 .revision = 3,
675 .family = NFPROTO_IPV4,
676 .target = set_target_v3,
677 .targetsize = sizeof(struct xt_set_info_target_v3),
678 .checkentry = set_target_v3_checkentry,
679 .destroy = set_target_v3_destroy,
680 .me = THIS_MODULE
681 },
682 {
683 .name = "SET",
684 .revision = 3,
685 .family = NFPROTO_IPV6,
686 .target = set_target_v3,
687 .targetsize = sizeof(struct xt_set_info_target_v3),
688 .checkentry = set_target_v3_checkentry,
689 .destroy = set_target_v3_destroy,
690 .me = THIS_MODULE
691 },
692};
693
694static int __init xt_set_init(void)
695{
696 int ret = xt_register_matches(set_matches, ARRAY_SIZE(set_matches));
697
698 if (!ret) {
699 ret = xt_register_targets(set_targets,
700 ARRAY_SIZE(set_targets));
701 if (ret)
702 xt_unregister_matches(set_matches,
703 ARRAY_SIZE(set_matches));
704 }
705 return ret;
706}
707
708static void __exit xt_set_fini(void)
709{
710 xt_unregister_matches(set_matches, ARRAY_SIZE(set_matches));
711 xt_unregister_targets(set_targets, ARRAY_SIZE(set_targets));
712}
713
714module_init(xt_set_init);
715module_exit(xt_set_fini);
716