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