xt_set.c (20111B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu> 3 * Patrick Schaaf <bof@bof.de> 4 * Martin Josefsson <gandalf@wlug.westbo.se> 5 * Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@netfilter.org> 6 */ 7 8/* Kernel module which implements the set match and SET target 9 * for netfilter/iptables. 10 */ 11 12#include <linux/module.h> 13#include <linux/skbuff.h> 14 15#include <linux/netfilter/x_tables.h> 16#include <linux/netfilter/ipset/ip_set.h> 17#include <uapi/linux/netfilter/xt_set.h> 18 19MODULE_LICENSE("GPL"); 20MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@netfilter.org>"); 21MODULE_DESCRIPTION("Xtables: IP set match and target module"); 22MODULE_ALIAS("xt_SET"); 23MODULE_ALIAS("ipt_set"); 24MODULE_ALIAS("ip6t_set"); 25MODULE_ALIAS("ipt_SET"); 26MODULE_ALIAS("ip6t_SET"); 27 28static inline int 29match_set(ip_set_id_t index, const struct sk_buff *skb, 30 const struct xt_action_param *par, 31 struct ip_set_adt_opt *opt, int inv) 32{ 33 if (ip_set_test(index, skb, par, opt)) 34 inv = !inv; 35 return inv; 36} 37 38#define ADT_OPT(n, f, d, fs, cfs, t, p, b, po, bo) \ 39struct ip_set_adt_opt n = { \ 40 .family = f, \ 41 .dim = d, \ 42 .flags = fs, \ 43 .cmdflags = cfs, \ 44 .ext.timeout = t, \ 45 .ext.packets = p, \ 46 .ext.bytes = b, \ 47 .ext.packets_op = po, \ 48 .ext.bytes_op = bo, \ 49} 50 51/* Revision 0 interface: backward compatible with netfilter/iptables */ 52 53static bool 54set_match_v0(const struct sk_buff *skb, struct xt_action_param *par) 55{ 56 const struct xt_set_info_match_v0 *info = par->matchinfo; 57 58 ADT_OPT(opt, xt_family(par), info->match_set.u.compat.dim, 59 info->match_set.u.compat.flags, 0, UINT_MAX, 60 0, 0, 0, 0); 61 62 return match_set(info->match_set.index, skb, par, &opt, 63 info->match_set.u.compat.flags & IPSET_INV_MATCH); 64} 65 66static void 67compat_flags(struct xt_set_info_v0 *info) 68{ 69 u_int8_t i; 70 71 /* Fill out compatibility data according to enum ip_set_kopt */ 72 info->u.compat.dim = IPSET_DIM_ZERO; 73 if (info->u.flags[0] & IPSET_MATCH_INV) 74 info->u.compat.flags |= IPSET_INV_MATCH; 75 for (i = 0; i < IPSET_DIM_MAX - 1 && info->u.flags[i]; i++) { 76 info->u.compat.dim++; 77 if (info->u.flags[i] & IPSET_SRC) 78 info->u.compat.flags |= (1 << info->u.compat.dim); 79 } 80} 81 82static int 83set_match_v0_checkentry(const struct xt_mtchk_param *par) 84{ 85 struct xt_set_info_match_v0 *info = par->matchinfo; 86 ip_set_id_t index; 87 88 index = ip_set_nfnl_get_byindex(par->net, info->match_set.index); 89 90 if (index == IPSET_INVALID_ID) { 91 pr_info_ratelimited("Cannot find set identified by id %u to match\n", 92 info->match_set.index); 93 return -ENOENT; 94 } 95 if (info->match_set.u.flags[IPSET_DIM_MAX - 1] != 0) { 96 pr_info_ratelimited("set match dimension is over the limit!\n"); 97 ip_set_nfnl_put(par->net, info->match_set.index); 98 return -ERANGE; 99 } 100 101 /* Fill out compatibility data */ 102 compat_flags(&info->match_set); 103 104 return 0; 105} 106 107static void 108set_match_v0_destroy(const struct xt_mtdtor_param *par) 109{ 110 struct xt_set_info_match_v0 *info = par->matchinfo; 111 112 ip_set_nfnl_put(par->net, info->match_set.index); 113} 114 115/* Revision 1 match */ 116 117static bool 118set_match_v1(const struct sk_buff *skb, struct xt_action_param *par) 119{ 120 const struct xt_set_info_match_v1 *info = par->matchinfo; 121 122 ADT_OPT(opt, xt_family(par), info->match_set.dim, 123 info->match_set.flags, 0, UINT_MAX, 124 0, 0, 0, 0); 125 126 if (opt.flags & IPSET_RETURN_NOMATCH) 127 opt.cmdflags |= IPSET_FLAG_RETURN_NOMATCH; 128 129 return match_set(info->match_set.index, skb, par, &opt, 130 info->match_set.flags & IPSET_INV_MATCH); 131} 132 133static int 134set_match_v1_checkentry(const struct xt_mtchk_param *par) 135{ 136 struct xt_set_info_match_v1 *info = par->matchinfo; 137 ip_set_id_t index; 138 139 index = ip_set_nfnl_get_byindex(par->net, info->match_set.index); 140 141 if (index == IPSET_INVALID_ID) { 142 pr_info_ratelimited("Cannot find set identified by id %u to match\n", 143 info->match_set.index); 144 return -ENOENT; 145 } 146 if (info->match_set.dim > IPSET_DIM_MAX) { 147 pr_info_ratelimited("set match dimension is over the limit!\n"); 148 ip_set_nfnl_put(par->net, info->match_set.index); 149 return -ERANGE; 150 } 151 152 return 0; 153} 154 155static void 156set_match_v1_destroy(const struct xt_mtdtor_param *par) 157{ 158 struct xt_set_info_match_v1 *info = par->matchinfo; 159 160 ip_set_nfnl_put(par->net, info->match_set.index); 161} 162 163/* Revision 3 match */ 164 165static bool 166set_match_v3(const struct sk_buff *skb, struct xt_action_param *par) 167{ 168 const struct xt_set_info_match_v3 *info = par->matchinfo; 169 170 ADT_OPT(opt, xt_family(par), info->match_set.dim, 171 info->match_set.flags, info->flags, UINT_MAX, 172 info->packets.value, info->bytes.value, 173 info->packets.op, info->bytes.op); 174 175 if (info->packets.op != IPSET_COUNTER_NONE || 176 info->bytes.op != IPSET_COUNTER_NONE) 177 opt.cmdflags |= IPSET_FLAG_MATCH_COUNTERS; 178 179 return match_set(info->match_set.index, skb, par, &opt, 180 info->match_set.flags & IPSET_INV_MATCH); 181} 182 183#define set_match_v3_checkentry set_match_v1_checkentry 184#define set_match_v3_destroy set_match_v1_destroy 185 186/* Revision 4 match */ 187 188static bool 189set_match_v4(const struct sk_buff *skb, struct xt_action_param *par) 190{ 191 const struct xt_set_info_match_v4 *info = par->matchinfo; 192 193 ADT_OPT(opt, xt_family(par), info->match_set.dim, 194 info->match_set.flags, info->flags, UINT_MAX, 195 info->packets.value, info->bytes.value, 196 info->packets.op, info->bytes.op); 197 198 if (info->packets.op != IPSET_COUNTER_NONE || 199 info->bytes.op != IPSET_COUNTER_NONE) 200 opt.cmdflags |= IPSET_FLAG_MATCH_COUNTERS; 201 202 return match_set(info->match_set.index, skb, par, &opt, 203 info->match_set.flags & IPSET_INV_MATCH); 204} 205 206#define set_match_v4_checkentry set_match_v1_checkentry 207#define set_match_v4_destroy set_match_v1_destroy 208 209/* Revision 0 interface: backward compatible with netfilter/iptables */ 210 211static unsigned int 212set_target_v0(struct sk_buff *skb, const struct xt_action_param *par) 213{ 214 const struct xt_set_info_target_v0 *info = par->targinfo; 215 216 ADT_OPT(add_opt, xt_family(par), info->add_set.u.compat.dim, 217 info->add_set.u.compat.flags, 0, UINT_MAX, 218 0, 0, 0, 0); 219 ADT_OPT(del_opt, xt_family(par), info->del_set.u.compat.dim, 220 info->del_set.u.compat.flags, 0, UINT_MAX, 221 0, 0, 0, 0); 222 223 if (info->add_set.index != IPSET_INVALID_ID) 224 ip_set_add(info->add_set.index, skb, par, &add_opt); 225 if (info->del_set.index != IPSET_INVALID_ID) 226 ip_set_del(info->del_set.index, skb, par, &del_opt); 227 228 return XT_CONTINUE; 229} 230 231static int 232set_target_v0_checkentry(const struct xt_tgchk_param *par) 233{ 234 struct xt_set_info_target_v0 *info = par->targinfo; 235 ip_set_id_t index; 236 237 if (info->add_set.index != IPSET_INVALID_ID) { 238 index = ip_set_nfnl_get_byindex(par->net, info->add_set.index); 239 if (index == IPSET_INVALID_ID) { 240 pr_info_ratelimited("Cannot find add_set index %u as target\n", 241 info->add_set.index); 242 return -ENOENT; 243 } 244 } 245 246 if (info->del_set.index != IPSET_INVALID_ID) { 247 index = ip_set_nfnl_get_byindex(par->net, info->del_set.index); 248 if (index == IPSET_INVALID_ID) { 249 pr_info_ratelimited("Cannot find del_set index %u as target\n", 250 info->del_set.index); 251 if (info->add_set.index != IPSET_INVALID_ID) 252 ip_set_nfnl_put(par->net, info->add_set.index); 253 return -ENOENT; 254 } 255 } 256 if (info->add_set.u.flags[IPSET_DIM_MAX - 1] != 0 || 257 info->del_set.u.flags[IPSET_DIM_MAX - 1] != 0) { 258 pr_info_ratelimited("SET target dimension over the limit!\n"); 259 if (info->add_set.index != IPSET_INVALID_ID) 260 ip_set_nfnl_put(par->net, info->add_set.index); 261 if (info->del_set.index != IPSET_INVALID_ID) 262 ip_set_nfnl_put(par->net, info->del_set.index); 263 return -ERANGE; 264 } 265 266 /* Fill out compatibility data */ 267 compat_flags(&info->add_set); 268 compat_flags(&info->del_set); 269 270 return 0; 271} 272 273static void 274set_target_v0_destroy(const struct xt_tgdtor_param *par) 275{ 276 const struct xt_set_info_target_v0 *info = par->targinfo; 277 278 if (info->add_set.index != IPSET_INVALID_ID) 279 ip_set_nfnl_put(par->net, info->add_set.index); 280 if (info->del_set.index != IPSET_INVALID_ID) 281 ip_set_nfnl_put(par->net, info->del_set.index); 282} 283 284/* Revision 1 target */ 285 286static unsigned int 287set_target_v1(struct sk_buff *skb, const struct xt_action_param *par) 288{ 289 const struct xt_set_info_target_v1 *info = par->targinfo; 290 291 ADT_OPT(add_opt, xt_family(par), info->add_set.dim, 292 info->add_set.flags, 0, UINT_MAX, 293 0, 0, 0, 0); 294 ADT_OPT(del_opt, xt_family(par), info->del_set.dim, 295 info->del_set.flags, 0, UINT_MAX, 296 0, 0, 0, 0); 297 298 if (info->add_set.index != IPSET_INVALID_ID) 299 ip_set_add(info->add_set.index, skb, par, &add_opt); 300 if (info->del_set.index != IPSET_INVALID_ID) 301 ip_set_del(info->del_set.index, skb, par, &del_opt); 302 303 return XT_CONTINUE; 304} 305 306static int 307set_target_v1_checkentry(const struct xt_tgchk_param *par) 308{ 309 const struct xt_set_info_target_v1 *info = par->targinfo; 310 ip_set_id_t index; 311 312 if (info->add_set.index != IPSET_INVALID_ID) { 313 index = ip_set_nfnl_get_byindex(par->net, info->add_set.index); 314 if (index == IPSET_INVALID_ID) { 315 pr_info_ratelimited("Cannot find add_set index %u as target\n", 316 info->add_set.index); 317 return -ENOENT; 318 } 319 } 320 321 if (info->del_set.index != IPSET_INVALID_ID) { 322 index = ip_set_nfnl_get_byindex(par->net, info->del_set.index); 323 if (index == IPSET_INVALID_ID) { 324 pr_info_ratelimited("Cannot find del_set index %u as target\n", 325 info->del_set.index); 326 if (info->add_set.index != IPSET_INVALID_ID) 327 ip_set_nfnl_put(par->net, info->add_set.index); 328 return -ENOENT; 329 } 330 } 331 if (info->add_set.dim > IPSET_DIM_MAX || 332 info->del_set.dim > IPSET_DIM_MAX) { 333 pr_info_ratelimited("SET target dimension over the limit!\n"); 334 if (info->add_set.index != IPSET_INVALID_ID) 335 ip_set_nfnl_put(par->net, info->add_set.index); 336 if (info->del_set.index != IPSET_INVALID_ID) 337 ip_set_nfnl_put(par->net, info->del_set.index); 338 return -ERANGE; 339 } 340 341 return 0; 342} 343 344static void 345set_target_v1_destroy(const struct xt_tgdtor_param *par) 346{ 347 const struct xt_set_info_target_v1 *info = par->targinfo; 348 349 if (info->add_set.index != IPSET_INVALID_ID) 350 ip_set_nfnl_put(par->net, info->add_set.index); 351 if (info->del_set.index != IPSET_INVALID_ID) 352 ip_set_nfnl_put(par->net, info->del_set.index); 353} 354 355/* Revision 2 target */ 356 357static unsigned int 358set_target_v2(struct sk_buff *skb, const struct xt_action_param *par) 359{ 360 const struct xt_set_info_target_v2 *info = par->targinfo; 361 362 ADT_OPT(add_opt, xt_family(par), info->add_set.dim, 363 info->add_set.flags, info->flags, info->timeout, 364 0, 0, 0, 0); 365 ADT_OPT(del_opt, xt_family(par), info->del_set.dim, 366 info->del_set.flags, 0, UINT_MAX, 367 0, 0, 0, 0); 368 369 /* Normalize to fit into jiffies */ 370 if (add_opt.ext.timeout != IPSET_NO_TIMEOUT && 371 add_opt.ext.timeout > IPSET_MAX_TIMEOUT) 372 add_opt.ext.timeout = IPSET_MAX_TIMEOUT; 373 if (info->add_set.index != IPSET_INVALID_ID) 374 ip_set_add(info->add_set.index, skb, par, &add_opt); 375 if (info->del_set.index != IPSET_INVALID_ID) 376 ip_set_del(info->del_set.index, skb, par, &del_opt); 377 378 return XT_CONTINUE; 379} 380 381#define set_target_v2_checkentry set_target_v1_checkentry 382#define set_target_v2_destroy set_target_v1_destroy 383 384/* Revision 3 target */ 385 386#define MOPT(opt, member) ((opt).ext.skbinfo.member) 387 388static unsigned int 389set_target_v3(struct sk_buff *skb, const struct xt_action_param *par) 390{ 391 const struct xt_set_info_target_v3 *info = par->targinfo; 392 int ret; 393 394 ADT_OPT(add_opt, xt_family(par), info->add_set.dim, 395 info->add_set.flags, info->flags, info->timeout, 396 0, 0, 0, 0); 397 ADT_OPT(del_opt, xt_family(par), info->del_set.dim, 398 info->del_set.flags, 0, UINT_MAX, 399 0, 0, 0, 0); 400 ADT_OPT(map_opt, xt_family(par), info->map_set.dim, 401 info->map_set.flags, 0, UINT_MAX, 402 0, 0, 0, 0); 403 404 /* Normalize to fit into jiffies */ 405 if (add_opt.ext.timeout != IPSET_NO_TIMEOUT && 406 add_opt.ext.timeout > IPSET_MAX_TIMEOUT) 407 add_opt.ext.timeout = IPSET_MAX_TIMEOUT; 408 if (info->add_set.index != IPSET_INVALID_ID) 409 ip_set_add(info->add_set.index, skb, par, &add_opt); 410 if (info->del_set.index != IPSET_INVALID_ID) 411 ip_set_del(info->del_set.index, skb, par, &del_opt); 412 if (info->map_set.index != IPSET_INVALID_ID) { 413 map_opt.cmdflags |= info->flags & (IPSET_FLAG_MAP_SKBMARK | 414 IPSET_FLAG_MAP_SKBPRIO | 415 IPSET_FLAG_MAP_SKBQUEUE); 416 ret = match_set(info->map_set.index, skb, par, &map_opt, 417 info->map_set.flags & IPSET_INV_MATCH); 418 if (!ret) 419 return XT_CONTINUE; 420 if (map_opt.cmdflags & IPSET_FLAG_MAP_SKBMARK) 421 skb->mark = (skb->mark & ~MOPT(map_opt,skbmarkmask)) 422 ^ MOPT(map_opt, skbmark); 423 if (map_opt.cmdflags & IPSET_FLAG_MAP_SKBPRIO) 424 skb->priority = MOPT(map_opt, skbprio); 425 if ((map_opt.cmdflags & IPSET_FLAG_MAP_SKBQUEUE) && 426 skb->dev && 427 skb->dev->real_num_tx_queues > MOPT(map_opt, skbqueue)) 428 skb_set_queue_mapping(skb, MOPT(map_opt, skbqueue)); 429 } 430 return XT_CONTINUE; 431} 432 433static int 434set_target_v3_checkentry(const struct xt_tgchk_param *par) 435{ 436 const struct xt_set_info_target_v3 *info = par->targinfo; 437 ip_set_id_t index; 438 int ret = 0; 439 440 if (info->add_set.index != IPSET_INVALID_ID) { 441 index = ip_set_nfnl_get_byindex(par->net, 442 info->add_set.index); 443 if (index == IPSET_INVALID_ID) { 444 pr_info_ratelimited("Cannot find add_set index %u as target\n", 445 info->add_set.index); 446 return -ENOENT; 447 } 448 } 449 450 if (info->del_set.index != IPSET_INVALID_ID) { 451 index = ip_set_nfnl_get_byindex(par->net, 452 info->del_set.index); 453 if (index == IPSET_INVALID_ID) { 454 pr_info_ratelimited("Cannot find del_set index %u as target\n", 455 info->del_set.index); 456 ret = -ENOENT; 457 goto cleanup_add; 458 } 459 } 460 461 if (info->map_set.index != IPSET_INVALID_ID) { 462 if (strncmp(par->table, "mangle", 7)) { 463 pr_info_ratelimited("--map-set only usable from mangle table\n"); 464 ret = -EINVAL; 465 goto cleanup_del; 466 } 467 if (((info->flags & IPSET_FLAG_MAP_SKBPRIO) | 468 (info->flags & IPSET_FLAG_MAP_SKBQUEUE)) && 469 (par->hook_mask & ~(1 << NF_INET_FORWARD | 470 1 << NF_INET_LOCAL_OUT | 471 1 << NF_INET_POST_ROUTING))) { 472 pr_info_ratelimited("mapping of prio or/and queue is allowed only from OUTPUT/FORWARD/POSTROUTING chains\n"); 473 ret = -EINVAL; 474 goto cleanup_del; 475 } 476 index = ip_set_nfnl_get_byindex(par->net, 477 info->map_set.index); 478 if (index == IPSET_INVALID_ID) { 479 pr_info_ratelimited("Cannot find map_set index %u as target\n", 480 info->map_set.index); 481 ret = -ENOENT; 482 goto cleanup_del; 483 } 484 } 485 486 if (info->add_set.dim > IPSET_DIM_MAX || 487 info->del_set.dim > IPSET_DIM_MAX || 488 info->map_set.dim > IPSET_DIM_MAX) { 489 pr_info_ratelimited("SET target dimension over the limit!\n"); 490 ret = -ERANGE; 491 goto cleanup_mark; 492 } 493 494 return 0; 495cleanup_mark: 496 if (info->map_set.index != IPSET_INVALID_ID) 497 ip_set_nfnl_put(par->net, info->map_set.index); 498cleanup_del: 499 if (info->del_set.index != IPSET_INVALID_ID) 500 ip_set_nfnl_put(par->net, info->del_set.index); 501cleanup_add: 502 if (info->add_set.index != IPSET_INVALID_ID) 503 ip_set_nfnl_put(par->net, info->add_set.index); 504 return ret; 505} 506 507static void 508set_target_v3_destroy(const struct xt_tgdtor_param *par) 509{ 510 const struct xt_set_info_target_v3 *info = par->targinfo; 511 512 if (info->add_set.index != IPSET_INVALID_ID) 513 ip_set_nfnl_put(par->net, info->add_set.index); 514 if (info->del_set.index != IPSET_INVALID_ID) 515 ip_set_nfnl_put(par->net, info->del_set.index); 516 if (info->map_set.index != IPSET_INVALID_ID) 517 ip_set_nfnl_put(par->net, info->map_set.index); 518} 519 520static struct xt_match set_matches[] __read_mostly = { 521 { 522 .name = "set", 523 .family = NFPROTO_IPV4, 524 .revision = 0, 525 .match = set_match_v0, 526 .matchsize = sizeof(struct xt_set_info_match_v0), 527 .checkentry = set_match_v0_checkentry, 528 .destroy = set_match_v0_destroy, 529 .me = THIS_MODULE 530 }, 531 { 532 .name = "set", 533 .family = NFPROTO_IPV4, 534 .revision = 1, 535 .match = set_match_v1, 536 .matchsize = sizeof(struct xt_set_info_match_v1), 537 .checkentry = set_match_v1_checkentry, 538 .destroy = set_match_v1_destroy, 539 .me = THIS_MODULE 540 }, 541 { 542 .name = "set", 543 .family = NFPROTO_IPV6, 544 .revision = 1, 545 .match = set_match_v1, 546 .matchsize = sizeof(struct xt_set_info_match_v1), 547 .checkentry = set_match_v1_checkentry, 548 .destroy = set_match_v1_destroy, 549 .me = THIS_MODULE 550 }, 551 /* --return-nomatch flag support */ 552 { 553 .name = "set", 554 .family = NFPROTO_IPV4, 555 .revision = 2, 556 .match = set_match_v1, 557 .matchsize = sizeof(struct xt_set_info_match_v1), 558 .checkentry = set_match_v1_checkentry, 559 .destroy = set_match_v1_destroy, 560 .me = THIS_MODULE 561 }, 562 { 563 .name = "set", 564 .family = NFPROTO_IPV6, 565 .revision = 2, 566 .match = set_match_v1, 567 .matchsize = sizeof(struct xt_set_info_match_v1), 568 .checkentry = set_match_v1_checkentry, 569 .destroy = set_match_v1_destroy, 570 .me = THIS_MODULE 571 }, 572 /* counters support: update, match */ 573 { 574 .name = "set", 575 .family = NFPROTO_IPV4, 576 .revision = 3, 577 .match = set_match_v3, 578 .matchsize = sizeof(struct xt_set_info_match_v3), 579 .checkentry = set_match_v3_checkentry, 580 .destroy = set_match_v3_destroy, 581 .me = THIS_MODULE 582 }, 583 { 584 .name = "set", 585 .family = NFPROTO_IPV6, 586 .revision = 3, 587 .match = set_match_v3, 588 .matchsize = sizeof(struct xt_set_info_match_v3), 589 .checkentry = set_match_v3_checkentry, 590 .destroy = set_match_v3_destroy, 591 .me = THIS_MODULE 592 }, 593 /* new revision for counters support: update, match */ 594 { 595 .name = "set", 596 .family = NFPROTO_IPV4, 597 .revision = 4, 598 .match = set_match_v4, 599 .matchsize = sizeof(struct xt_set_info_match_v4), 600 .checkentry = set_match_v4_checkentry, 601 .destroy = set_match_v4_destroy, 602 .me = THIS_MODULE 603 }, 604 { 605 .name = "set", 606 .family = NFPROTO_IPV6, 607 .revision = 4, 608 .match = set_match_v4, 609 .matchsize = sizeof(struct xt_set_info_match_v4), 610 .checkentry = set_match_v4_checkentry, 611 .destroy = set_match_v4_destroy, 612 .me = THIS_MODULE 613 }, 614}; 615 616static struct xt_target set_targets[] __read_mostly = { 617 { 618 .name = "SET", 619 .revision = 0, 620 .family = NFPROTO_IPV4, 621 .target = set_target_v0, 622 .targetsize = sizeof(struct xt_set_info_target_v0), 623 .checkentry = set_target_v0_checkentry, 624 .destroy = set_target_v0_destroy, 625 .me = THIS_MODULE 626 }, 627 { 628 .name = "SET", 629 .revision = 1, 630 .family = NFPROTO_IPV4, 631 .target = set_target_v1, 632 .targetsize = sizeof(struct xt_set_info_target_v1), 633 .checkentry = set_target_v1_checkentry, 634 .destroy = set_target_v1_destroy, 635 .me = THIS_MODULE 636 }, 637 { 638 .name = "SET", 639 .revision = 1, 640 .family = NFPROTO_IPV6, 641 .target = set_target_v1, 642 .targetsize = sizeof(struct xt_set_info_target_v1), 643 .checkentry = set_target_v1_checkentry, 644 .destroy = set_target_v1_destroy, 645 .me = THIS_MODULE 646 }, 647 /* --timeout and --exist flags support */ 648 { 649 .name = "SET", 650 .revision = 2, 651 .family = NFPROTO_IPV4, 652 .target = set_target_v2, 653 .targetsize = sizeof(struct xt_set_info_target_v2), 654 .checkentry = set_target_v2_checkentry, 655 .destroy = set_target_v2_destroy, 656 .me = THIS_MODULE 657 }, 658 { 659 .name = "SET", 660 .revision = 2, 661 .family = NFPROTO_IPV6, 662 .target = set_target_v2, 663 .targetsize = sizeof(struct xt_set_info_target_v2), 664 .checkentry = set_target_v2_checkentry, 665 .destroy = set_target_v2_destroy, 666 .me = THIS_MODULE 667 }, 668 /* --map-set support */ 669 { 670 .name = "SET", 671 .revision = 3, 672 .family = NFPROTO_IPV4, 673 .target = set_target_v3, 674 .targetsize = sizeof(struct xt_set_info_target_v3), 675 .checkentry = set_target_v3_checkentry, 676 .destroy = set_target_v3_destroy, 677 .me = THIS_MODULE 678 }, 679 { 680 .name = "SET", 681 .revision = 3, 682 .family = NFPROTO_IPV6, 683 .target = set_target_v3, 684 .targetsize = sizeof(struct xt_set_info_target_v3), 685 .checkentry = set_target_v3_checkentry, 686 .destroy = set_target_v3_destroy, 687 .me = THIS_MODULE 688 }, 689}; 690 691static int __init xt_set_init(void) 692{ 693 int ret = xt_register_matches(set_matches, ARRAY_SIZE(set_matches)); 694 695 if (!ret) { 696 ret = xt_register_targets(set_targets, 697 ARRAY_SIZE(set_targets)); 698 if (ret) 699 xt_unregister_matches(set_matches, 700 ARRAY_SIZE(set_matches)); 701 } 702 return ret; 703} 704 705static void __exit xt_set_fini(void) 706{ 707 xt_unregister_matches(set_matches, ARRAY_SIZE(set_matches)); 708 xt_unregister_targets(set_targets, ARRAY_SIZE(set_targets)); 709} 710 711module_init(xt_set_init); 712module_exit(xt_set_fini);