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 21 MODULE_LICENSE("GPL"); 22 MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); 23 MODULE_DESCRIPTION("Xtables: IP set match and target module"); 24 MODULE_ALIAS("xt_SET"); 25 MODULE_ALIAS("ipt_set"); 26 MODULE_ALIAS("ip6t_set"); 27 MODULE_ALIAS("ipt_SET"); 28 MODULE_ALIAS("ip6t_SET"); 29 30 static inline int 31 match_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) \ 41 struct 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 51 static bool 52 set_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 62 static void 63 compat_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 78 static int 79 set_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 103 static void 104 set_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 113 static bool 114 set_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 127 static int 128 set_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 149 static void 150 set_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 159 static bool 160 match_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 177 static bool 178 set_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 0; 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 205 static bool 206 match_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 223 static bool 224 set_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 0; 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 251 static unsigned int 252 set_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 268 static int 269 set_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 310 static void 311 set_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 323 static unsigned int 324 set_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 340 static int 341 set_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 378 static void 379 set_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 391 static unsigned int 392 set_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 417 static unsigned int 418 set_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 460 static int 461 set_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 535 static void 536 set_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 549 static 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 645 static 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 720 static 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 734 static 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 740 module_init(xt_set_init); 741 module_exit(xt_set_fini); 742