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