diff options
author | Anton Danilov <littlesmilingcloud@gmail.com> | 2014-09-02 06:21:20 -0400 |
---|---|---|
committer | Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> | 2014-09-15 16:20:21 -0400 |
commit | 76cea4109ca89dea218fdc652d2e1535fd9b5fc7 (patch) | |
tree | d6328b672e91bfb5c6398c123e3fcde41e5f521f | |
parent | cbee93d7b71bf9d73382e503a4f60848eec60ea8 (diff) |
netfilter: ipset: Add skbinfo extension support to SET target.
Signed-off-by: Anton Danilov <littlesmilingcloud@gmail.com>
Signed-off-by: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
-rw-r--r-- | include/uapi/linux/netfilter/xt_set.h | 10 | ||||
-rw-r--r-- | net/netfilter/xt_set.c | 155 |
2 files changed, 165 insertions, 0 deletions
diff --git a/include/uapi/linux/netfilter/xt_set.h b/include/uapi/linux/netfilter/xt_set.h index 964d3d42f874..d6a1df1f2947 100644 --- a/include/uapi/linux/netfilter/xt_set.h +++ b/include/uapi/linux/netfilter/xt_set.h | |||
@@ -71,4 +71,14 @@ struct xt_set_info_match_v3 { | |||
71 | __u32 flags; | 71 | __u32 flags; |
72 | }; | 72 | }; |
73 | 73 | ||
74 | /* Revision 3 target */ | ||
75 | |||
76 | struct xt_set_info_target_v3 { | ||
77 | struct xt_set_info add_set; | ||
78 | struct xt_set_info del_set; | ||
79 | struct xt_set_info map_set; | ||
80 | __u32 flags; | ||
81 | __u32 timeout; | ||
82 | }; | ||
83 | |||
74 | #endif /*_XT_SET_H*/ | 84 | #endif /*_XT_SET_H*/ |
diff --git a/net/netfilter/xt_set.c b/net/netfilter/xt_set.c index cb70f6ec5695..5732cd64acc0 100644 --- a/net/netfilter/xt_set.c +++ b/net/netfilter/xt_set.c | |||
@@ -366,6 +366,140 @@ set_target_v2(struct sk_buff *skb, const struct xt_action_param *par) | |||
366 | #define set_target_v2_checkentry set_target_v1_checkentry | 366 | #define set_target_v2_checkentry set_target_v1_checkentry |
367 | #define set_target_v2_destroy set_target_v1_destroy | 367 | #define set_target_v2_destroy set_target_v1_destroy |
368 | 368 | ||
369 | /* Revision 3 target */ | ||
370 | |||
371 | static unsigned int | ||
372 | set_target_v3(struct sk_buff *skb, const struct xt_action_param *par) | ||
373 | { | ||
374 | const struct xt_set_info_target_v3 *info = par->targinfo; | ||
375 | ADT_OPT(add_opt, par->family, info->add_set.dim, | ||
376 | info->add_set.flags, info->flags, info->timeout); | ||
377 | ADT_OPT(del_opt, par->family, info->del_set.dim, | ||
378 | info->del_set.flags, 0, UINT_MAX); | ||
379 | ADT_OPT(map_opt, par->family, info->map_set.dim, | ||
380 | info->map_set.flags, 0, UINT_MAX); | ||
381 | |||
382 | int ret; | ||
383 | |||
384 | /* Normalize to fit into jiffies */ | ||
385 | if (add_opt.ext.timeout != IPSET_NO_TIMEOUT && | ||
386 | add_opt.ext.timeout > UINT_MAX/MSEC_PER_SEC) | ||
387 | add_opt.ext.timeout = UINT_MAX/MSEC_PER_SEC; | ||
388 | if (info->add_set.index != IPSET_INVALID_ID) | ||
389 | ip_set_add(info->add_set.index, skb, par, &add_opt); | ||
390 | if (info->del_set.index != IPSET_INVALID_ID) | ||
391 | ip_set_del(info->del_set.index, skb, par, &del_opt); | ||
392 | if (info->map_set.index != IPSET_INVALID_ID) { | ||
393 | map_opt.cmdflags |= info->flags & (IPSET_FLAG_MAP_SKBMARK | | ||
394 | IPSET_FLAG_MAP_SKBPRIO | | ||
395 | IPSET_FLAG_MAP_SKBQUEUE); | ||
396 | ret = match_set(info->map_set.index, skb, par, &map_opt, | ||
397 | info->map_set.flags & IPSET_INV_MATCH); | ||
398 | if (!ret) | ||
399 | return XT_CONTINUE; | ||
400 | if (map_opt.cmdflags & IPSET_FLAG_MAP_SKBMARK) | ||
401 | skb->mark = (skb->mark & ~(map_opt.ext.skbmarkmask)) | ||
402 | ^ (map_opt.ext.skbmark); | ||
403 | if (map_opt.cmdflags & IPSET_FLAG_MAP_SKBPRIO) | ||
404 | skb->priority = map_opt.ext.skbprio; | ||
405 | if ((map_opt.cmdflags & IPSET_FLAG_MAP_SKBQUEUE) && | ||
406 | skb->dev && | ||
407 | skb->dev->real_num_tx_queues > map_opt.ext.skbqueue) | ||
408 | skb_set_queue_mapping(skb, map_opt.ext.skbqueue); | ||
409 | } | ||
410 | return XT_CONTINUE; | ||
411 | } | ||
412 | |||
413 | |||
414 | static int | ||
415 | set_target_v3_checkentry(const struct xt_tgchk_param *par) | ||
416 | { | ||
417 | const struct xt_set_info_target_v3 *info = par->targinfo; | ||
418 | ip_set_id_t index; | ||
419 | |||
420 | if (info->add_set.index != IPSET_INVALID_ID) { | ||
421 | index = ip_set_nfnl_get_byindex(par->net, | ||
422 | info->add_set.index); | ||
423 | if (index == IPSET_INVALID_ID) { | ||
424 | pr_warn("Cannot find add_set index %u as target\n", | ||
425 | info->add_set.index); | ||
426 | return -ENOENT; | ||
427 | } | ||
428 | } | ||
429 | |||
430 | if (info->del_set.index != IPSET_INVALID_ID) { | ||
431 | index = ip_set_nfnl_get_byindex(par->net, | ||
432 | info->del_set.index); | ||
433 | if (index == IPSET_INVALID_ID) { | ||
434 | pr_warn("Cannot find del_set index %u as target\n", | ||
435 | info->del_set.index); | ||
436 | if (info->add_set.index != IPSET_INVALID_ID) | ||
437 | ip_set_nfnl_put(par->net, | ||
438 | info->add_set.index); | ||
439 | return -ENOENT; | ||
440 | } | ||
441 | } | ||
442 | |||
443 | if (info->map_set.index != IPSET_INVALID_ID) { | ||
444 | if (strncmp(par->table, "mangle", 7)) { | ||
445 | pr_warn("--map-set only usable from mangle table\n"); | ||
446 | return -EINVAL; | ||
447 | } | ||
448 | if (((info->flags & IPSET_FLAG_MAP_SKBPRIO) | | ||
449 | (info->flags & IPSET_FLAG_MAP_SKBQUEUE)) && | ||
450 | !(par->hook_mask & (1 << NF_INET_FORWARD | | ||
451 | 1 << NF_INET_LOCAL_OUT | | ||
452 | 1 << NF_INET_POST_ROUTING))) { | ||
453 | pr_warn("mapping of prio or/and queue is allowed only" | ||
454 | "from OUTPUT/FORWARD/POSTROUTING chains\n"); | ||
455 | return -EINVAL; | ||
456 | } | ||
457 | index = ip_set_nfnl_get_byindex(par->net, | ||
458 | info->map_set.index); | ||
459 | if (index == IPSET_INVALID_ID) { | ||
460 | pr_warn("Cannot find map_set index %u as target\n", | ||
461 | info->map_set.index); | ||
462 | if (info->add_set.index != IPSET_INVALID_ID) | ||
463 | ip_set_nfnl_put(par->net, | ||
464 | info->add_set.index); | ||
465 | if (info->del_set.index != IPSET_INVALID_ID) | ||
466 | ip_set_nfnl_put(par->net, | ||
467 | info->del_set.index); | ||
468 | return -ENOENT; | ||
469 | } | ||
470 | } | ||
471 | |||
472 | if (info->add_set.dim > IPSET_DIM_MAX || | ||
473 | info->del_set.dim > IPSET_DIM_MAX || | ||
474 | info->map_set.dim > IPSET_DIM_MAX) { | ||
475 | pr_warn("Protocol error: SET target dimension " | ||
476 | "is over the limit!\n"); | ||
477 | if (info->add_set.index != IPSET_INVALID_ID) | ||
478 | ip_set_nfnl_put(par->net, info->add_set.index); | ||
479 | if (info->del_set.index != IPSET_INVALID_ID) | ||
480 | ip_set_nfnl_put(par->net, info->del_set.index); | ||
481 | if (info->map_set.index != IPSET_INVALID_ID) | ||
482 | ip_set_nfnl_put(par->net, info->map_set.index); | ||
483 | return -ERANGE; | ||
484 | } | ||
485 | |||
486 | return 0; | ||
487 | } | ||
488 | |||
489 | static void | ||
490 | set_target_v3_destroy(const struct xt_tgdtor_param *par) | ||
491 | { | ||
492 | const struct xt_set_info_target_v3 *info = par->targinfo; | ||
493 | |||
494 | if (info->add_set.index != IPSET_INVALID_ID) | ||
495 | ip_set_nfnl_put(par->net, info->add_set.index); | ||
496 | if (info->del_set.index != IPSET_INVALID_ID) | ||
497 | ip_set_nfnl_put(par->net, info->del_set.index); | ||
498 | if (info->map_set.index != IPSET_INVALID_ID) | ||
499 | ip_set_nfnl_put(par->net, info->map_set.index); | ||
500 | } | ||
501 | |||
502 | |||
369 | static struct xt_match set_matches[] __read_mostly = { | 503 | static struct xt_match set_matches[] __read_mostly = { |
370 | { | 504 | { |
371 | .name = "set", | 505 | .name = "set", |
@@ -493,6 +627,27 @@ static struct xt_target set_targets[] __read_mostly = { | |||
493 | .destroy = set_target_v2_destroy, | 627 | .destroy = set_target_v2_destroy, |
494 | .me = THIS_MODULE | 628 | .me = THIS_MODULE |
495 | }, | 629 | }, |
630 | /* --map-set support */ | ||
631 | { | ||
632 | .name = "SET", | ||
633 | .revision = 3, | ||
634 | .family = NFPROTO_IPV4, | ||
635 | .target = set_target_v3, | ||
636 | .targetsize = sizeof(struct xt_set_info_target_v3), | ||
637 | .checkentry = set_target_v3_checkentry, | ||
638 | .destroy = set_target_v3_destroy, | ||
639 | .me = THIS_MODULE | ||
640 | }, | ||
641 | { | ||
642 | .name = "SET", | ||
643 | .revision = 3, | ||
644 | .family = NFPROTO_IPV6, | ||
645 | .target = set_target_v3, | ||
646 | .targetsize = sizeof(struct xt_set_info_target_v3), | ||
647 | .checkentry = set_target_v3_checkentry, | ||
648 | .destroy = set_target_v3_destroy, | ||
649 | .me = THIS_MODULE | ||
650 | }, | ||
496 | }; | 651 | }; |
497 | 652 | ||
498 | static int __init xt_set_init(void) | 653 | static int __init xt_set_init(void) |