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, xt_family(par), 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, xt_family(par), 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, xt_family(par), 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, xt_family(par), 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, xt_family(par), info->add_set.u.compat.dim, 263 info->add_set.u.compat.flags, 0, UINT_MAX); 264 ADT_OPT(del_opt, xt_family(par), 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, xt_family(par), info->add_set.dim, 336 info->add_set.flags, 0, UINT_MAX); 337 ADT_OPT(del_opt, xt_family(par), 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, xt_family(par), info->add_set.dim, 405 info->add_set.flags, info->flags, info->timeout); 406 ADT_OPT(del_opt, xt_family(par), 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 #define MOPT(opt, member) ((opt).ext.skbinfo.member) 427 428 static unsigned int 429 set_target_v3(struct sk_buff *skb, const struct xt_action_param *par) 430 { 431 const struct xt_set_info_target_v3 *info = par->targinfo; 432 int ret; 433 434 ADT_OPT(add_opt, xt_family(par), info->add_set.dim, 435 info->add_set.flags, info->flags, info->timeout); 436 ADT_OPT(del_opt, xt_family(par), info->del_set.dim, 437 info->del_set.flags, 0, UINT_MAX); 438 ADT_OPT(map_opt, xt_family(par), info->map_set.dim, 439 info->map_set.flags, 0, UINT_MAX); 440 441 /* Normalize to fit into jiffies */ 442 if (add_opt.ext.timeout != IPSET_NO_TIMEOUT && 443 add_opt.ext.timeout > UINT_MAX / MSEC_PER_SEC) 444 add_opt.ext.timeout = UINT_MAX / MSEC_PER_SEC; 445 if (info->add_set.index != IPSET_INVALID_ID) 446 ip_set_add(info->add_set.index, skb, par, &add_opt); 447 if (info->del_set.index != IPSET_INVALID_ID) 448 ip_set_del(info->del_set.index, skb, par, &del_opt); 449 if (info->map_set.index != IPSET_INVALID_ID) { 450 map_opt.cmdflags |= info->flags & (IPSET_FLAG_MAP_SKBMARK | 451 IPSET_FLAG_MAP_SKBPRIO | 452 IPSET_FLAG_MAP_SKBQUEUE); 453 ret = match_set(info->map_set.index, skb, par, &map_opt, 454 info->map_set.flags & IPSET_INV_MATCH); 455 if (!ret) 456 return XT_CONTINUE; 457 if (map_opt.cmdflags & IPSET_FLAG_MAP_SKBMARK) 458 skb->mark = (skb->mark & ~MOPT(map_opt,skbmarkmask)) 459 ^ MOPT(map_opt, skbmark); 460 if (map_opt.cmdflags & IPSET_FLAG_MAP_SKBPRIO) 461 skb->priority = MOPT(map_opt, skbprio); 462 if ((map_opt.cmdflags & IPSET_FLAG_MAP_SKBQUEUE) && 463 skb->dev && 464 skb->dev->real_num_tx_queues > MOPT(map_opt, skbqueue)) 465 skb_set_queue_mapping(skb, MOPT(map_opt, skbqueue)); 466 } 467 return XT_CONTINUE; 468 } 469 470 static int 471 set_target_v3_checkentry(const struct xt_tgchk_param *par) 472 { 473 const struct xt_set_info_target_v3 *info = par->targinfo; 474 ip_set_id_t index; 475 476 if (info->add_set.index != IPSET_INVALID_ID) { 477 index = ip_set_nfnl_get_byindex(par->net, 478 info->add_set.index); 479 if (index == IPSET_INVALID_ID) { 480 pr_warn("Cannot find add_set index %u as target\n", 481 info->add_set.index); 482 return -ENOENT; 483 } 484 } 485 486 if (info->del_set.index != IPSET_INVALID_ID) { 487 index = ip_set_nfnl_get_byindex(par->net, 488 info->del_set.index); 489 if (index == IPSET_INVALID_ID) { 490 pr_warn("Cannot find del_set index %u as target\n", 491 info->del_set.index); 492 if (info->add_set.index != IPSET_INVALID_ID) 493 ip_set_nfnl_put(par->net, 494 info->add_set.index); 495 return -ENOENT; 496 } 497 } 498 499 if (info->map_set.index != IPSET_INVALID_ID) { 500 if (strncmp(par->table, "mangle", 7)) { 501 pr_warn("--map-set only usable from mangle table\n"); 502 return -EINVAL; 503 } 504 if (((info->flags & IPSET_FLAG_MAP_SKBPRIO) | 505 (info->flags & IPSET_FLAG_MAP_SKBQUEUE)) && 506 !(par->hook_mask & (1 << NF_INET_FORWARD | 507 1 << NF_INET_LOCAL_OUT | 508 1 << NF_INET_POST_ROUTING))) { 509 pr_warn("mapping of prio or/and queue is allowed only from OUTPUT/FORWARD/POSTROUTING chains\n"); 510 return -EINVAL; 511 } 512 index = ip_set_nfnl_get_byindex(par->net, 513 info->map_set.index); 514 if (index == IPSET_INVALID_ID) { 515 pr_warn("Cannot find map_set index %u as target\n", 516 info->map_set.index); 517 if (info->add_set.index != IPSET_INVALID_ID) 518 ip_set_nfnl_put(par->net, 519 info->add_set.index); 520 if (info->del_set.index != IPSET_INVALID_ID) 521 ip_set_nfnl_put(par->net, 522 info->del_set.index); 523 return -ENOENT; 524 } 525 } 526 527 if (info->add_set.dim > IPSET_DIM_MAX || 528 info->del_set.dim > IPSET_DIM_MAX || 529 info->map_set.dim > IPSET_DIM_MAX) { 530 pr_warn("Protocol error: SET target dimension is over the limit!\n"); 531 if (info->add_set.index != IPSET_INVALID_ID) 532 ip_set_nfnl_put(par->net, info->add_set.index); 533 if (info->del_set.index != IPSET_INVALID_ID) 534 ip_set_nfnl_put(par->net, info->del_set.index); 535 if (info->map_set.index != IPSET_INVALID_ID) 536 ip_set_nfnl_put(par->net, info->map_set.index); 537 return -ERANGE; 538 } 539 540 return 0; 541 } 542 543 static void 544 set_target_v3_destroy(const struct xt_tgdtor_param *par) 545 { 546 const struct xt_set_info_target_v3 *info = par->targinfo; 547 548 if (info->add_set.index != IPSET_INVALID_ID) 549 ip_set_nfnl_put(par->net, info->add_set.index); 550 if (info->del_set.index != IPSET_INVALID_ID) 551 ip_set_nfnl_put(par->net, info->del_set.index); 552 if (info->map_set.index != IPSET_INVALID_ID) 553 ip_set_nfnl_put(par->net, info->map_set.index); 554 } 555 556 static struct xt_match set_matches[] __read_mostly = { 557 { 558 .name = "set", 559 .family = NFPROTO_IPV4, 560 .revision = 0, 561 .match = set_match_v0, 562 .matchsize = sizeof(struct xt_set_info_match_v0), 563 .checkentry = set_match_v0_checkentry, 564 .destroy = set_match_v0_destroy, 565 .me = THIS_MODULE 566 }, 567 { 568 .name = "set", 569 .family = NFPROTO_IPV4, 570 .revision = 1, 571 .match = set_match_v1, 572 .matchsize = sizeof(struct xt_set_info_match_v1), 573 .checkentry = set_match_v1_checkentry, 574 .destroy = set_match_v1_destroy, 575 .me = THIS_MODULE 576 }, 577 { 578 .name = "set", 579 .family = NFPROTO_IPV6, 580 .revision = 1, 581 .match = set_match_v1, 582 .matchsize = sizeof(struct xt_set_info_match_v1), 583 .checkentry = set_match_v1_checkentry, 584 .destroy = set_match_v1_destroy, 585 .me = THIS_MODULE 586 }, 587 /* --return-nomatch flag support */ 588 { 589 .name = "set", 590 .family = NFPROTO_IPV4, 591 .revision = 2, 592 .match = set_match_v1, 593 .matchsize = sizeof(struct xt_set_info_match_v1), 594 .checkentry = set_match_v1_checkentry, 595 .destroy = set_match_v1_destroy, 596 .me = THIS_MODULE 597 }, 598 { 599 .name = "set", 600 .family = NFPROTO_IPV6, 601 .revision = 2, 602 .match = set_match_v1, 603 .matchsize = sizeof(struct xt_set_info_match_v1), 604 .checkentry = set_match_v1_checkentry, 605 .destroy = set_match_v1_destroy, 606 .me = THIS_MODULE 607 }, 608 /* counters support: update, match */ 609 { 610 .name = "set", 611 .family = NFPROTO_IPV4, 612 .revision = 3, 613 .match = set_match_v3, 614 .matchsize = sizeof(struct xt_set_info_match_v3), 615 .checkentry = set_match_v3_checkentry, 616 .destroy = set_match_v3_destroy, 617 .me = THIS_MODULE 618 }, 619 { 620 .name = "set", 621 .family = NFPROTO_IPV6, 622 .revision = 3, 623 .match = set_match_v3, 624 .matchsize = sizeof(struct xt_set_info_match_v3), 625 .checkentry = set_match_v3_checkentry, 626 .destroy = set_match_v3_destroy, 627 .me = THIS_MODULE 628 }, 629 /* new revision for counters support: update, match */ 630 { 631 .name = "set", 632 .family = NFPROTO_IPV4, 633 .revision = 4, 634 .match = set_match_v4, 635 .matchsize = sizeof(struct xt_set_info_match_v4), 636 .checkentry = set_match_v4_checkentry, 637 .destroy = set_match_v4_destroy, 638 .me = THIS_MODULE 639 }, 640 { 641 .name = "set", 642 .family = NFPROTO_IPV6, 643 .revision = 4, 644 .match = set_match_v4, 645 .matchsize = sizeof(struct xt_set_info_match_v4), 646 .checkentry = set_match_v4_checkentry, 647 .destroy = set_match_v4_destroy, 648 .me = THIS_MODULE 649 }, 650 }; 651 652 static struct xt_target set_targets[] __read_mostly = { 653 { 654 .name = "SET", 655 .revision = 0, 656 .family = NFPROTO_IPV4, 657 .target = set_target_v0, 658 .targetsize = sizeof(struct xt_set_info_target_v0), 659 .checkentry = set_target_v0_checkentry, 660 .destroy = set_target_v0_destroy, 661 .me = THIS_MODULE 662 }, 663 { 664 .name = "SET", 665 .revision = 1, 666 .family = NFPROTO_IPV4, 667 .target = set_target_v1, 668 .targetsize = sizeof(struct xt_set_info_target_v1), 669 .checkentry = set_target_v1_checkentry, 670 .destroy = set_target_v1_destroy, 671 .me = THIS_MODULE 672 }, 673 { 674 .name = "SET", 675 .revision = 1, 676 .family = NFPROTO_IPV6, 677 .target = set_target_v1, 678 .targetsize = sizeof(struct xt_set_info_target_v1), 679 .checkentry = set_target_v1_checkentry, 680 .destroy = set_target_v1_destroy, 681 .me = THIS_MODULE 682 }, 683 /* --timeout and --exist flags support */ 684 { 685 .name = "SET", 686 .revision = 2, 687 .family = NFPROTO_IPV4, 688 .target = set_target_v2, 689 .targetsize = sizeof(struct xt_set_info_target_v2), 690 .checkentry = set_target_v2_checkentry, 691 .destroy = set_target_v2_destroy, 692 .me = THIS_MODULE 693 }, 694 { 695 .name = "SET", 696 .revision = 2, 697 .family = NFPROTO_IPV6, 698 .target = set_target_v2, 699 .targetsize = sizeof(struct xt_set_info_target_v2), 700 .checkentry = set_target_v2_checkentry, 701 .destroy = set_target_v2_destroy, 702 .me = THIS_MODULE 703 }, 704 /* --map-set support */ 705 { 706 .name = "SET", 707 .revision = 3, 708 .family = NFPROTO_IPV4, 709 .target = set_target_v3, 710 .targetsize = sizeof(struct xt_set_info_target_v3), 711 .checkentry = set_target_v3_checkentry, 712 .destroy = set_target_v3_destroy, 713 .me = THIS_MODULE 714 }, 715 { 716 .name = "SET", 717 .revision = 3, 718 .family = NFPROTO_IPV6, 719 .target = set_target_v3, 720 .targetsize = sizeof(struct xt_set_info_target_v3), 721 .checkentry = set_target_v3_checkentry, 722 .destroy = set_target_v3_destroy, 723 .me = THIS_MODULE 724 }, 725 }; 726 727 static int __init xt_set_init(void) 728 { 729 int ret = xt_register_matches(set_matches, ARRAY_SIZE(set_matches)); 730 731 if (!ret) { 732 ret = xt_register_targets(set_targets, 733 ARRAY_SIZE(set_targets)); 734 if (ret) 735 xt_unregister_matches(set_matches, 736 ARRAY_SIZE(set_matches)); 737 } 738 return ret; 739 } 740 741 static void __exit xt_set_fini(void) 742 { 743 xt_unregister_matches(set_matches, ARRAY_SIZE(set_matches)); 744 xt_unregister_targets(set_targets, ARRAY_SIZE(set_targets)); 745 } 746 747 module_init(xt_set_init); 748 module_exit(xt_set_fini); 749