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@netfilter.org>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
11 /* Kernel module which implements the set match and SET target
12 * for netfilter/iptables.
15 #include <linux/module.h>
16 #include <linux/skbuff.h>
18 #include <linux/netfilter/x_tables.h>
19 #include <linux/netfilter/ipset/ip_set.h>
20 #include <linux/netfilter/ipset/ip_set_timeout.h>
21 #include <uapi/linux/netfilter/xt_set.h>
23 MODULE_LICENSE("GPL");
24 MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@netfilter.org>");
25 MODULE_DESCRIPTION("Xtables: IP set match and target module");
26 MODULE_ALIAS("xt_SET");
27 MODULE_ALIAS("ipt_set");
28 MODULE_ALIAS("ip6t_set");
29 MODULE_ALIAS("ipt_SET");
30 MODULE_ALIAS("ip6t_SET");
33 match_set(ip_set_id_t index, const struct sk_buff *skb,
34 const struct xt_action_param *par,
35 struct ip_set_adt_opt *opt, int inv)
37 if (ip_set_test(index, skb, par, opt))
42 #define ADT_OPT(n, f, d, fs, cfs, t, p, b, po, bo) \
43 struct ip_set_adt_opt n = { \
51 .ext.packets_op = po, \
55 /* Revision 0 interface: backward compatible with netfilter/iptables */
58 set_match_v0(const struct sk_buff *skb, struct xt_action_param *par)
60 const struct xt_set_info_match_v0 *info = par->matchinfo;
62 ADT_OPT(opt, xt_family(par), info->match_set.u.compat.dim,
63 info->match_set.u.compat.flags, 0, UINT_MAX,
66 return match_set(info->match_set.index, skb, par, &opt,
67 info->match_set.u.compat.flags & IPSET_INV_MATCH);
71 compat_flags(struct xt_set_info_v0 *info)
75 /* Fill out compatibility data according to enum ip_set_kopt */
76 info->u.compat.dim = IPSET_DIM_ZERO;
77 if (info->u.flags[0] & IPSET_MATCH_INV)
78 info->u.compat.flags |= IPSET_INV_MATCH;
79 for (i = 0; i < IPSET_DIM_MAX - 1 && info->u.flags[i]; i++) {
81 if (info->u.flags[i] & IPSET_SRC)
82 info->u.compat.flags |= (1 << info->u.compat.dim);
87 set_match_v0_checkentry(const struct xt_mtchk_param *par)
89 struct xt_set_info_match_v0 *info = par->matchinfo;
92 index = ip_set_nfnl_get_byindex(par->net, info->match_set.index);
94 if (index == IPSET_INVALID_ID) {
95 pr_info_ratelimited("Cannot find set identified by id %u to match\n",
96 info->match_set.index);
99 if (info->match_set.u.flags[IPSET_DIM_MAX - 1] != 0) {
100 pr_info_ratelimited("set match dimension is over the limit!\n");
101 ip_set_nfnl_put(par->net, info->match_set.index);
105 /* Fill out compatibility data */
106 compat_flags(&info->match_set);
112 set_match_v0_destroy(const struct xt_mtdtor_param *par)
114 struct xt_set_info_match_v0 *info = par->matchinfo;
116 ip_set_nfnl_put(par->net, info->match_set.index);
119 /* Revision 1 match */
122 set_match_v1(const struct sk_buff *skb, struct xt_action_param *par)
124 const struct xt_set_info_match_v1 *info = par->matchinfo;
126 ADT_OPT(opt, xt_family(par), info->match_set.dim,
127 info->match_set.flags, 0, UINT_MAX,
130 if (opt.flags & IPSET_RETURN_NOMATCH)
131 opt.cmdflags |= IPSET_FLAG_RETURN_NOMATCH;
133 return match_set(info->match_set.index, skb, par, &opt,
134 info->match_set.flags & IPSET_INV_MATCH);
138 set_match_v1_checkentry(const struct xt_mtchk_param *par)
140 struct xt_set_info_match_v1 *info = par->matchinfo;
143 index = ip_set_nfnl_get_byindex(par->net, info->match_set.index);
145 if (index == IPSET_INVALID_ID) {
146 pr_info_ratelimited("Cannot find set identified by id %u to match\n",
147 info->match_set.index);
150 if (info->match_set.dim > IPSET_DIM_MAX) {
151 pr_info_ratelimited("set match dimension is over the limit!\n");
152 ip_set_nfnl_put(par->net, info->match_set.index);
160 set_match_v1_destroy(const struct xt_mtdtor_param *par)
162 struct xt_set_info_match_v1 *info = par->matchinfo;
164 ip_set_nfnl_put(par->net, info->match_set.index);
167 /* Revision 3 match */
170 set_match_v3(const struct sk_buff *skb, struct xt_action_param *par)
172 const struct xt_set_info_match_v3 *info = par->matchinfo;
174 ADT_OPT(opt, xt_family(par), info->match_set.dim,
175 info->match_set.flags, info->flags, UINT_MAX,
176 info->packets.value, info->bytes.value,
177 info->packets.op, info->bytes.op);
179 if (info->packets.op != IPSET_COUNTER_NONE ||
180 info->bytes.op != IPSET_COUNTER_NONE)
181 opt.cmdflags |= IPSET_FLAG_MATCH_COUNTERS;
183 return match_set(info->match_set.index, skb, par, &opt,
184 info->match_set.flags & IPSET_INV_MATCH);
187 #define set_match_v3_checkentry set_match_v1_checkentry
188 #define set_match_v3_destroy set_match_v1_destroy
190 /* Revision 4 match */
193 set_match_v4(const struct sk_buff *skb, struct xt_action_param *par)
195 const struct xt_set_info_match_v4 *info = par->matchinfo;
197 ADT_OPT(opt, xt_family(par), info->match_set.dim,
198 info->match_set.flags, info->flags, UINT_MAX,
199 info->packets.value, info->bytes.value,
200 info->packets.op, info->bytes.op);
202 if (info->packets.op != IPSET_COUNTER_NONE ||
203 info->bytes.op != IPSET_COUNTER_NONE)
204 opt.cmdflags |= IPSET_FLAG_MATCH_COUNTERS;
206 return match_set(info->match_set.index, skb, par, &opt,
207 info->match_set.flags & IPSET_INV_MATCH);
210 #define set_match_v4_checkentry set_match_v1_checkentry
211 #define set_match_v4_destroy set_match_v1_destroy
213 /* Revision 0 interface: backward compatible with netfilter/iptables */
216 set_target_v0(struct sk_buff *skb, const struct xt_action_param *par)
218 const struct xt_set_info_target_v0 *info = par->targinfo;
220 ADT_OPT(add_opt, xt_family(par), info->add_set.u.compat.dim,
221 info->add_set.u.compat.flags, 0, UINT_MAX,
223 ADT_OPT(del_opt, xt_family(par), info->del_set.u.compat.dim,
224 info->del_set.u.compat.flags, 0, UINT_MAX,
227 if (info->add_set.index != IPSET_INVALID_ID)
228 ip_set_add(info->add_set.index, skb, par, &add_opt);
229 if (info->del_set.index != IPSET_INVALID_ID)
230 ip_set_del(info->del_set.index, skb, par, &del_opt);
236 set_target_v0_checkentry(const struct xt_tgchk_param *par)
238 struct xt_set_info_target_v0 *info = par->targinfo;
241 if (info->add_set.index != IPSET_INVALID_ID) {
242 index = ip_set_nfnl_get_byindex(par->net, info->add_set.index);
243 if (index == IPSET_INVALID_ID) {
244 pr_info_ratelimited("Cannot find add_set index %u as target\n",
245 info->add_set.index);
250 if (info->del_set.index != IPSET_INVALID_ID) {
251 index = ip_set_nfnl_get_byindex(par->net, info->del_set.index);
252 if (index == IPSET_INVALID_ID) {
253 pr_info_ratelimited("Cannot find del_set index %u as target\n",
254 info->del_set.index);
255 if (info->add_set.index != IPSET_INVALID_ID)
256 ip_set_nfnl_put(par->net, info->add_set.index);
260 if (info->add_set.u.flags[IPSET_DIM_MAX - 1] != 0 ||
261 info->del_set.u.flags[IPSET_DIM_MAX - 1] != 0) {
262 pr_info_ratelimited("SET target dimension over the limit!\n");
263 if (info->add_set.index != IPSET_INVALID_ID)
264 ip_set_nfnl_put(par->net, info->add_set.index);
265 if (info->del_set.index != IPSET_INVALID_ID)
266 ip_set_nfnl_put(par->net, info->del_set.index);
270 /* Fill out compatibility data */
271 compat_flags(&info->add_set);
272 compat_flags(&info->del_set);
278 set_target_v0_destroy(const struct xt_tgdtor_param *par)
280 const struct xt_set_info_target_v0 *info = par->targinfo;
282 if (info->add_set.index != IPSET_INVALID_ID)
283 ip_set_nfnl_put(par->net, info->add_set.index);
284 if (info->del_set.index != IPSET_INVALID_ID)
285 ip_set_nfnl_put(par->net, info->del_set.index);
288 /* Revision 1 target */
291 set_target_v1(struct sk_buff *skb, const struct xt_action_param *par)
293 const struct xt_set_info_target_v1 *info = par->targinfo;
295 ADT_OPT(add_opt, xt_family(par), info->add_set.dim,
296 info->add_set.flags, 0, UINT_MAX,
298 ADT_OPT(del_opt, xt_family(par), info->del_set.dim,
299 info->del_set.flags, 0, UINT_MAX,
302 if (info->add_set.index != IPSET_INVALID_ID)
303 ip_set_add(info->add_set.index, skb, par, &add_opt);
304 if (info->del_set.index != IPSET_INVALID_ID)
305 ip_set_del(info->del_set.index, skb, par, &del_opt);
311 set_target_v1_checkentry(const struct xt_tgchk_param *par)
313 const struct xt_set_info_target_v1 *info = par->targinfo;
316 if (info->add_set.index != IPSET_INVALID_ID) {
317 index = ip_set_nfnl_get_byindex(par->net, info->add_set.index);
318 if (index == IPSET_INVALID_ID) {
319 pr_info_ratelimited("Cannot find add_set index %u as target\n",
320 info->add_set.index);
325 if (info->del_set.index != IPSET_INVALID_ID) {
326 index = ip_set_nfnl_get_byindex(par->net, info->del_set.index);
327 if (index == IPSET_INVALID_ID) {
328 pr_info_ratelimited("Cannot find del_set index %u as target\n",
329 info->del_set.index);
330 if (info->add_set.index != IPSET_INVALID_ID)
331 ip_set_nfnl_put(par->net, info->add_set.index);
335 if (info->add_set.dim > IPSET_DIM_MAX ||
336 info->del_set.dim > IPSET_DIM_MAX) {
337 pr_info_ratelimited("SET target dimension over the limit!\n");
338 if (info->add_set.index != IPSET_INVALID_ID)
339 ip_set_nfnl_put(par->net, info->add_set.index);
340 if (info->del_set.index != IPSET_INVALID_ID)
341 ip_set_nfnl_put(par->net, info->del_set.index);
349 set_target_v1_destroy(const struct xt_tgdtor_param *par)
351 const struct xt_set_info_target_v1 *info = par->targinfo;
353 if (info->add_set.index != IPSET_INVALID_ID)
354 ip_set_nfnl_put(par->net, info->add_set.index);
355 if (info->del_set.index != IPSET_INVALID_ID)
356 ip_set_nfnl_put(par->net, info->del_set.index);
359 /* Revision 2 target */
362 set_target_v2(struct sk_buff *skb, const struct xt_action_param *par)
364 const struct xt_set_info_target_v2 *info = par->targinfo;
366 ADT_OPT(add_opt, xt_family(par), info->add_set.dim,
367 info->add_set.flags, info->flags, info->timeout,
369 ADT_OPT(del_opt, xt_family(par), info->del_set.dim,
370 info->del_set.flags, 0, UINT_MAX,
373 /* Normalize to fit into jiffies */
374 if (add_opt.ext.timeout != IPSET_NO_TIMEOUT &&
375 add_opt.ext.timeout > IPSET_MAX_TIMEOUT)
376 add_opt.ext.timeout = IPSET_MAX_TIMEOUT;
377 if (info->add_set.index != IPSET_INVALID_ID)
378 ip_set_add(info->add_set.index, skb, par, &add_opt);
379 if (info->del_set.index != IPSET_INVALID_ID)
380 ip_set_del(info->del_set.index, skb, par, &del_opt);
385 #define set_target_v2_checkentry set_target_v1_checkentry
386 #define set_target_v2_destroy set_target_v1_destroy
388 /* Revision 3 target */
390 #define MOPT(opt, member) ((opt).ext.skbinfo.member)
393 set_target_v3(struct sk_buff *skb, const struct xt_action_param *par)
395 const struct xt_set_info_target_v3 *info = par->targinfo;
398 ADT_OPT(add_opt, xt_family(par), info->add_set.dim,
399 info->add_set.flags, info->flags, info->timeout,
401 ADT_OPT(del_opt, xt_family(par), info->del_set.dim,
402 info->del_set.flags, 0, UINT_MAX,
404 ADT_OPT(map_opt, xt_family(par), info->map_set.dim,
405 info->map_set.flags, 0, UINT_MAX,
408 /* Normalize to fit into jiffies */
409 if (add_opt.ext.timeout != IPSET_NO_TIMEOUT &&
410 add_opt.ext.timeout > IPSET_MAX_TIMEOUT)
411 add_opt.ext.timeout = IPSET_MAX_TIMEOUT;
412 if (info->add_set.index != IPSET_INVALID_ID)
413 ip_set_add(info->add_set.index, skb, par, &add_opt);
414 if (info->del_set.index != IPSET_INVALID_ID)
415 ip_set_del(info->del_set.index, skb, par, &del_opt);
416 if (info->map_set.index != IPSET_INVALID_ID) {
417 map_opt.cmdflags |= info->flags & (IPSET_FLAG_MAP_SKBMARK |
418 IPSET_FLAG_MAP_SKBPRIO |
419 IPSET_FLAG_MAP_SKBQUEUE);
420 ret = match_set(info->map_set.index, skb, par, &map_opt,
421 info->map_set.flags & IPSET_INV_MATCH);
424 if (map_opt.cmdflags & IPSET_FLAG_MAP_SKBMARK)
425 skb->mark = (skb->mark & ~MOPT(map_opt,skbmarkmask))
426 ^ MOPT(map_opt, skbmark);
427 if (map_opt.cmdflags & IPSET_FLAG_MAP_SKBPRIO)
428 skb->priority = MOPT(map_opt, skbprio);
429 if ((map_opt.cmdflags & IPSET_FLAG_MAP_SKBQUEUE) &&
431 skb->dev->real_num_tx_queues > MOPT(map_opt, skbqueue))
432 skb_set_queue_mapping(skb, MOPT(map_opt, skbqueue));
438 set_target_v3_checkentry(const struct xt_tgchk_param *par)
440 const struct xt_set_info_target_v3 *info = par->targinfo;
444 if (info->add_set.index != IPSET_INVALID_ID) {
445 index = ip_set_nfnl_get_byindex(par->net,
446 info->add_set.index);
447 if (index == IPSET_INVALID_ID) {
448 pr_info_ratelimited("Cannot find add_set index %u as target\n",
449 info->add_set.index);
454 if (info->del_set.index != IPSET_INVALID_ID) {
455 index = ip_set_nfnl_get_byindex(par->net,
456 info->del_set.index);
457 if (index == IPSET_INVALID_ID) {
458 pr_info_ratelimited("Cannot find del_set index %u as target\n",
459 info->del_set.index);
465 if (info->map_set.index != IPSET_INVALID_ID) {
466 if (strncmp(par->table, "mangle", 7)) {
467 pr_info_ratelimited("--map-set only usable from mangle table\n");
471 if (((info->flags & IPSET_FLAG_MAP_SKBPRIO) |
472 (info->flags & IPSET_FLAG_MAP_SKBQUEUE)) &&
473 (par->hook_mask & ~(1 << NF_INET_FORWARD |
474 1 << NF_INET_LOCAL_OUT |
475 1 << NF_INET_POST_ROUTING))) {
476 pr_info_ratelimited("mapping of prio or/and queue is allowed only from OUTPUT/FORWARD/POSTROUTING chains\n");
480 index = ip_set_nfnl_get_byindex(par->net,
481 info->map_set.index);
482 if (index == IPSET_INVALID_ID) {
483 pr_info_ratelimited("Cannot find map_set index %u as target\n",
484 info->map_set.index);
490 if (info->add_set.dim > IPSET_DIM_MAX ||
491 info->del_set.dim > IPSET_DIM_MAX ||
492 info->map_set.dim > IPSET_DIM_MAX) {
493 pr_info_ratelimited("SET target dimension over the limit!\n");
500 if (info->map_set.index != IPSET_INVALID_ID)
501 ip_set_nfnl_put(par->net, info->map_set.index);
503 if (info->del_set.index != IPSET_INVALID_ID)
504 ip_set_nfnl_put(par->net, info->del_set.index);
506 if (info->add_set.index != IPSET_INVALID_ID)
507 ip_set_nfnl_put(par->net, info->add_set.index);
512 set_target_v3_destroy(const struct xt_tgdtor_param *par)
514 const struct xt_set_info_target_v3 *info = par->targinfo;
516 if (info->add_set.index != IPSET_INVALID_ID)
517 ip_set_nfnl_put(par->net, info->add_set.index);
518 if (info->del_set.index != IPSET_INVALID_ID)
519 ip_set_nfnl_put(par->net, info->del_set.index);
520 if (info->map_set.index != IPSET_INVALID_ID)
521 ip_set_nfnl_put(par->net, info->map_set.index);
524 static struct xt_match set_matches[] __read_mostly = {
527 .family = NFPROTO_IPV4,
529 .match = set_match_v0,
530 .matchsize = sizeof(struct xt_set_info_match_v0),
531 .checkentry = set_match_v0_checkentry,
532 .destroy = set_match_v0_destroy,
537 .family = NFPROTO_IPV4,
539 .match = set_match_v1,
540 .matchsize = sizeof(struct xt_set_info_match_v1),
541 .checkentry = set_match_v1_checkentry,
542 .destroy = set_match_v1_destroy,
547 .family = NFPROTO_IPV6,
549 .match = set_match_v1,
550 .matchsize = sizeof(struct xt_set_info_match_v1),
551 .checkentry = set_match_v1_checkentry,
552 .destroy = set_match_v1_destroy,
555 /* --return-nomatch flag support */
558 .family = NFPROTO_IPV4,
560 .match = set_match_v1,
561 .matchsize = sizeof(struct xt_set_info_match_v1),
562 .checkentry = set_match_v1_checkentry,
563 .destroy = set_match_v1_destroy,
568 .family = NFPROTO_IPV6,
570 .match = set_match_v1,
571 .matchsize = sizeof(struct xt_set_info_match_v1),
572 .checkentry = set_match_v1_checkentry,
573 .destroy = set_match_v1_destroy,
576 /* counters support: update, match */
579 .family = NFPROTO_IPV4,
581 .match = set_match_v3,
582 .matchsize = sizeof(struct xt_set_info_match_v3),
583 .checkentry = set_match_v3_checkentry,
584 .destroy = set_match_v3_destroy,
589 .family = NFPROTO_IPV6,
591 .match = set_match_v3,
592 .matchsize = sizeof(struct xt_set_info_match_v3),
593 .checkentry = set_match_v3_checkentry,
594 .destroy = set_match_v3_destroy,
597 /* new revision for counters support: update, match */
600 .family = NFPROTO_IPV4,
602 .match = set_match_v4,
603 .matchsize = sizeof(struct xt_set_info_match_v4),
604 .checkentry = set_match_v4_checkentry,
605 .destroy = set_match_v4_destroy,
610 .family = NFPROTO_IPV6,
612 .match = set_match_v4,
613 .matchsize = sizeof(struct xt_set_info_match_v4),
614 .checkentry = set_match_v4_checkentry,
615 .destroy = set_match_v4_destroy,
620 static struct xt_target set_targets[] __read_mostly = {
624 .family = NFPROTO_IPV4,
625 .target = set_target_v0,
626 .targetsize = sizeof(struct xt_set_info_target_v0),
627 .checkentry = set_target_v0_checkentry,
628 .destroy = set_target_v0_destroy,
634 .family = NFPROTO_IPV4,
635 .target = set_target_v1,
636 .targetsize = sizeof(struct xt_set_info_target_v1),
637 .checkentry = set_target_v1_checkentry,
638 .destroy = set_target_v1_destroy,
644 .family = NFPROTO_IPV6,
645 .target = set_target_v1,
646 .targetsize = sizeof(struct xt_set_info_target_v1),
647 .checkentry = set_target_v1_checkentry,
648 .destroy = set_target_v1_destroy,
651 /* --timeout and --exist flags support */
655 .family = NFPROTO_IPV4,
656 .target = set_target_v2,
657 .targetsize = sizeof(struct xt_set_info_target_v2),
658 .checkentry = set_target_v2_checkentry,
659 .destroy = set_target_v2_destroy,
665 .family = NFPROTO_IPV6,
666 .target = set_target_v2,
667 .targetsize = sizeof(struct xt_set_info_target_v2),
668 .checkentry = set_target_v2_checkentry,
669 .destroy = set_target_v2_destroy,
672 /* --map-set support */
676 .family = NFPROTO_IPV4,
677 .target = set_target_v3,
678 .targetsize = sizeof(struct xt_set_info_target_v3),
679 .checkentry = set_target_v3_checkentry,
680 .destroy = set_target_v3_destroy,
686 .family = NFPROTO_IPV6,
687 .target = set_target_v3,
688 .targetsize = sizeof(struct xt_set_info_target_v3),
689 .checkentry = set_target_v3_checkentry,
690 .destroy = set_target_v3_destroy,
695 static int __init xt_set_init(void)
697 int ret = xt_register_matches(set_matches, ARRAY_SIZE(set_matches));
700 ret = xt_register_targets(set_targets,
701 ARRAY_SIZE(set_targets));
703 xt_unregister_matches(set_matches,
704 ARRAY_SIZE(set_matches));
709 static void __exit xt_set_fini(void)
711 xt_unregister_matches(set_matches, ARRAY_SIZE(set_matches));
712 xt_unregister_targets(set_targets, ARRAY_SIZE(set_targets));
715 module_init(xt_set_init);
716 module_exit(xt_set_fini);