| @@ -366,6 +366,140 @@ set_target_v2(struct sk_buff *skb, const struct xt_action_param *par) · 365 unmodified lines |
| 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 = { · 121 unmodified lines |
| 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) |