| @@ -366,6 +366,140 @@ set_target_v2(struct sk_buff *skb, const struct xt_action_param *par) · 365 unmodified lines |
| 366 | 366 | #define set_target_v2_checkentry set_target_v1_checkentry |
| 367 | 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 | 503 | static struct xt_match set_matches[] __read_mostly = { |
| 370 | 504 | { |
| 371 | 505 | .name = "set", |
| @@ -493,6 +627,27 @@ static struct xt_target set_targets[] __read_mostly = { · 121 unmodified lines |
| 493 | 627 | .destroy = set_target_v2_destroy, |
| 494 | 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 | 653 | static int __init xt_set_init(void) |