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) |
