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