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