Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Anton Danilov and committed by
Jozsef Kadlecsik
76cea410 cbee93d7

+165
+10
include/uapi/linux/netfilter/xt_set.h
··· 71 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 84 #endif /*_XT_SET_H*/
+155
net/netfilter/xt_set.c
··· 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", ··· 625 491 .targetsize = sizeof(struct xt_set_info_target_v2), 626 492 .checkentry = set_target_v2_checkentry, 627 493 .destroy = set_target_v2_destroy, 494 + .me = THIS_MODULE 495 + }, 496 + /* --map-set support */ 497 + { 498 + .name = "SET", 499 + .revision = 3, 500 + .family = NFPROTO_IPV4, 501 + .target = set_target_v3, 502 + .targetsize = sizeof(struct xt_set_info_target_v3), 503 + .checkentry = set_target_v3_checkentry, 504 + .destroy = set_target_v3_destroy, 505 + .me = THIS_MODULE 506 + }, 507 + { 508 + .name = "SET", 509 + .revision = 3, 510 + .family = NFPROTO_IPV6, 511 + .target = set_target_v3, 512 + .targetsize = sizeof(struct xt_set_info_target_v3), 513 + .checkentry = set_target_v3_checkentry, 514 + .destroy = set_target_v3_destroy, 628 515 .me = THIS_MODULE 629 516 }, 630 517 };