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