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