1 /* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
2 * Patrick Schaaf <bof@bof.de>
3 * Martin Josefsson <gandalf@wlug.westbo.se>
4 * Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
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.
11 /* Kernel module which implements the set match and SET target
12 * for netfilter/iptables.
15 #include <linux/module.h>
16 #include <linux/skbuff.h>
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>
23 MODULE_LICENSE("GPL");
24 MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
25 MODULE_DESCRIPTION("Xtables: IP set match and target module");
26 MODULE_ALIAS("xt_SET");
27 MODULE_ALIAS("ipt_set");
28 MODULE_ALIAS("ip6t_set");
29 MODULE_ALIAS("ipt_SET");
30 MODULE_ALIAS("ip6t_SET");
33 match_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
)
37 if (ip_set_test(index
, skb
, par
, opt
))
42 #define ADT_OPT(n, f, d, fs, cfs, t, p, b, po, bo) \
43 struct ip_set_adt_opt n = { \
51 .ext.packets_op = po, \
55 /* Revision 0 interface: backward compatible with netfilter/iptables */
58 set_match_v0(const struct sk_buff
*skb
, struct xt_action_param
*par
)
60 const struct xt_set_info_match_v0
*info
= par
->matchinfo
;
62 ADT_OPT(opt
, xt_family(par
), info
->match_set
.u
.compat
.dim
,
63 info
->match_set
.u
.compat
.flags
, 0, UINT_MAX
,
66 return match_set(info
->match_set
.index
, skb
, par
, &opt
,
67 info
->match_set
.u
.compat
.flags
& IPSET_INV_MATCH
);
71 compat_flags(struct xt_set_info_v0
*info
)
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
;
79 for (i
= 0; i
< IPSET_DIM_MAX
- 1 && info
->u
.flags
[i
]; i
++) {
81 if (info
->u
.flags
[i
] & IPSET_SRC
)
82 info
->u
.compat
.flags
|= (1 << info
->u
.compat
.dim
);
87 set_match_v0_checkentry(const struct xt_mtchk_param
*par
)
89 struct xt_set_info_match_v0
*info
= par
->matchinfo
;
92 index
= ip_set_nfnl_get_byindex(par
->net
, info
->match_set
.index
);
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
);
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
);
105 /* Fill out compatibility data */
106 compat_flags(&info
->match_set
);
112 set_match_v0_destroy(const struct xt_mtdtor_param
*par
)
114 struct xt_set_info_match_v0
*info
= par
->matchinfo
;
116 ip_set_nfnl_put(par
->net
, info
->match_set
.index
);
119 /* Revision 1 match */
122 set_match_v1(const struct sk_buff
*skb
, struct xt_action_param
*par
)
124 const struct xt_set_info_match_v1
*info
= par
->matchinfo
;
126 ADT_OPT(opt
, xt_family(par
), info
->match_set
.dim
,
127 info
->match_set
.flags
, 0, UINT_MAX
,
130 if (opt
.flags
& IPSET_RETURN_NOMATCH
)
131 opt
.cmdflags
|= IPSET_FLAG_RETURN_NOMATCH
;
133 return match_set(info
->match_set
.index
, skb
, par
, &opt
,
134 info
->match_set
.flags
& IPSET_INV_MATCH
);
138 set_match_v1_checkentry(const struct xt_mtchk_param
*par
)
140 struct xt_set_info_match_v1
*info
= par
->matchinfo
;
143 index
= ip_set_nfnl_get_byindex(par
->net
, info
->match_set
.index
);
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
);
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
);
160 set_match_v1_destroy(const struct xt_mtdtor_param
*par
)
162 struct xt_set_info_match_v1
*info
= par
->matchinfo
;
164 ip_set_nfnl_put(par
->net
, info
->match_set
.index
);
167 /* Revision 3 match */
170 set_match_v3(const struct sk_buff
*skb
, struct xt_action_param
*par
)
172 const struct xt_set_info_match_v3
*info
= par
->matchinfo
;
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
);
179 if (info
->packets
.op
!= IPSET_COUNTER_NONE
||
180 info
->bytes
.op
!= IPSET_COUNTER_NONE
)
181 opt
.cmdflags
|= IPSET_FLAG_MATCH_COUNTERS
;
183 return match_set(info
->match_set
.index
, skb
, par
, &opt
,
184 info
->match_set
.flags
& IPSET_INV_MATCH
);
187 #define set_match_v3_checkentry set_match_v1_checkentry
188 #define set_match_v3_destroy set_match_v1_destroy
190 /* Revision 4 match */
193 set_match_v4(const struct sk_buff
*skb
, struct xt_action_param
*par
)
195 const struct xt_set_info_match_v4
*info
= par
->matchinfo
;
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
);
202 if (info
->packets
.op
!= IPSET_COUNTER_NONE
||
203 info
->bytes
.op
!= IPSET_COUNTER_NONE
)
204 opt
.cmdflags
|= IPSET_FLAG_MATCH_COUNTERS
;
206 return match_set(info
->match_set
.index
, skb
, par
, &opt
,
207 info
->match_set
.flags
& IPSET_INV_MATCH
);
210 #define set_match_v4_checkentry set_match_v1_checkentry
211 #define set_match_v4_destroy set_match_v1_destroy
213 /* Revision 0 interface: backward compatible with netfilter/iptables */
216 set_target_v0(struct sk_buff
*skb
, const struct xt_action_param
*par
)
218 const struct xt_set_info_target_v0
*info
= par
->targinfo
;
220 ADT_OPT(add_opt
, xt_family(par
), info
->add_set
.u
.compat
.dim
,
221 info
->add_set
.u
.compat
.flags
, 0, UINT_MAX
,
223 ADT_OPT(del_opt
, xt_family(par
), info
->del_set
.u
.compat
.dim
,
224 info
->del_set
.u
.compat
.flags
, 0, UINT_MAX
,
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
);
236 set_target_v0_checkentry(const struct xt_tgchk_param
*par
)
238 struct xt_set_info_target_v0
*info
= par
->targinfo
;
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
);
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
);
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
);
270 /* Fill out compatibility data */
271 compat_flags(&info
->add_set
);
272 compat_flags(&info
->del_set
);
278 set_target_v0_destroy(const struct xt_tgdtor_param
*par
)
280 const struct xt_set_info_target_v0
*info
= par
->targinfo
;
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
);
288 /* Revision 1 target */
291 set_target_v1(struct sk_buff
*skb
, const struct xt_action_param
*par
)
293 const struct xt_set_info_target_v1
*info
= par
->targinfo
;
295 ADT_OPT(add_opt
, xt_family(par
), info
->add_set
.dim
,
296 info
->add_set
.flags
, 0, UINT_MAX
,
298 ADT_OPT(del_opt
, xt_family(par
), info
->del_set
.dim
,
299 info
->del_set
.flags
, 0, UINT_MAX
,
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
);
311 set_target_v1_checkentry(const struct xt_tgchk_param
*par
)
313 const struct xt_set_info_target_v1
*info
= par
->targinfo
;
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
);
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
);
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
);
349 set_target_v1_destroy(const struct xt_tgdtor_param
*par
)
351 const struct xt_set_info_target_v1
*info
= par
->targinfo
;
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
);
359 /* Revision 2 target */
362 set_target_v2(struct sk_buff
*skb
, const struct xt_action_param
*par
)
364 const struct xt_set_info_target_v2
*info
= par
->targinfo
;
366 ADT_OPT(add_opt
, xt_family(par
), info
->add_set
.dim
,
367 info
->add_set
.flags
, info
->flags
, info
->timeout
,
369 ADT_OPT(del_opt
, xt_family(par
), info
->del_set
.dim
,
370 info
->del_set
.flags
, 0, UINT_MAX
,
373 /* Normalize to fit into jiffies */
374 if (add_opt
.ext
.timeout
!= IPSET_NO_TIMEOUT
&&
375 add_opt
.ext
.timeout
> UINT_MAX
/ MSEC_PER_SEC
)
376 add_opt
.ext
.timeout
= UINT_MAX
/ MSEC_PER_SEC
;
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
);
385 #define set_target_v2_checkentry set_target_v1_checkentry
386 #define set_target_v2_destroy set_target_v1_destroy
388 /* Revision 3 target */
390 #define MOPT(opt, member) ((opt).ext.skbinfo.member)
393 set_target_v3(struct sk_buff
*skb
, const struct xt_action_param
*par
)
395 const struct xt_set_info_target_v3
*info
= par
->targinfo
;
398 ADT_OPT(add_opt
, xt_family(par
), info
->add_set
.dim
,
399 info
->add_set
.flags
, info
->flags
, info
->timeout
,
401 ADT_OPT(del_opt
, xt_family(par
), info
->del_set
.dim
,
402 info
->del_set
.flags
, 0, UINT_MAX
,
404 ADT_OPT(map_opt
, xt_family(par
), info
->map_set
.dim
,
405 info
->map_set
.flags
, 0, UINT_MAX
,
408 /* Normalize to fit into jiffies */
409 if (add_opt
.ext
.timeout
!= IPSET_NO_TIMEOUT
&&
410 add_opt
.ext
.timeout
> UINT_MAX
/ MSEC_PER_SEC
)
411 add_opt
.ext
.timeout
= UINT_MAX
/ MSEC_PER_SEC
;
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
);
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
) &&
431 skb
->dev
->real_num_tx_queues
> MOPT(map_opt
, skbqueue
))
432 skb_set_queue_mapping(skb
, MOPT(map_opt
, skbqueue
));
438 set_target_v3_checkentry(const struct xt_tgchk_param
*par
)
440 const struct xt_set_info_target_v3
*info
= par
->targinfo
;
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
);
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
);
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");
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");
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
);
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
);
511 set_target_v3_destroy(const struct xt_tgdtor_param
*par
)
513 const struct xt_set_info_target_v3
*info
= par
->targinfo
;
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
);
523 static struct xt_match set_matches
[] __read_mostly
= {
526 .family
= NFPROTO_IPV4
,
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
,
536 .family
= NFPROTO_IPV4
,
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
,
546 .family
= NFPROTO_IPV6
,
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
,
554 /* --return-nomatch flag support */
557 .family
= NFPROTO_IPV4
,
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
,
567 .family
= NFPROTO_IPV6
,
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
,
575 /* counters support: update, match */
578 .family
= NFPROTO_IPV4
,
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
,
588 .family
= NFPROTO_IPV6
,
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
,
596 /* new revision for counters support: update, match */
599 .family
= NFPROTO_IPV4
,
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
,
609 .family
= NFPROTO_IPV6
,
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
,
619 static struct xt_target set_targets
[] __read_mostly
= {
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
,
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
,
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
,
650 /* --timeout and --exist flags support */
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
,
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
,
671 /* --map-set support */
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
,
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
,
694 static int __init
xt_set_init(void)
696 int ret
= xt_register_matches(set_matches
, ARRAY_SIZE(set_matches
));
699 ret
= xt_register_targets(set_targets
,
700 ARRAY_SIZE(set_targets
));
702 xt_unregister_matches(set_matches
,
703 ARRAY_SIZE(set_matches
));
708 static void __exit
xt_set_fini(void)
710 xt_unregister_matches(set_matches
, ARRAY_SIZE(set_matches
));
711 xt_unregister_targets(set_targets
, ARRAY_SIZE(set_targets
));
714 module_init(xt_set_init
);
715 module_exit(xt_set_fini
);