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