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