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