Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
0003  *                         Patrick Schaaf <bof@bof.de>
0004  *                         Martin Josefsson <gandalf@wlug.westbo.se>
0005  * Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@netfilter.org>
0006  */
0007 
0008 /* Kernel module which implements the set match and SET target
0009  * for netfilter/iptables.
0010  */
0011 
0012 #include <linux/module.h>
0013 #include <linux/skbuff.h>
0014 
0015 #include <linux/netfilter/x_tables.h>
0016 #include <linux/netfilter/ipset/ip_set.h>
0017 #include <uapi/linux/netfilter/xt_set.h>
0018 
0019 MODULE_LICENSE("GPL");
0020 MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@netfilter.org>");
0021 MODULE_DESCRIPTION("Xtables: IP set match and target module");
0022 MODULE_ALIAS("xt_SET");
0023 MODULE_ALIAS("ipt_set");
0024 MODULE_ALIAS("ip6t_set");
0025 MODULE_ALIAS("ipt_SET");
0026 MODULE_ALIAS("ip6t_SET");
0027 
0028 static inline int
0029 match_set(ip_set_id_t index, const struct sk_buff *skb,
0030       const struct xt_action_param *par,
0031       struct ip_set_adt_opt *opt, int inv)
0032 {
0033     if (ip_set_test(index, skb, par, opt))
0034         inv = !inv;
0035     return inv;
0036 }
0037 
0038 #define ADT_OPT(n, f, d, fs, cfs, t, p, b, po, bo)  \
0039 struct ip_set_adt_opt n = {             \
0040     .family = f,                    \
0041     .dim = d,                   \
0042     .flags = fs,                    \
0043     .cmdflags = cfs,                \
0044     .ext.timeout = t,               \
0045     .ext.packets = p,               \
0046     .ext.bytes = b,                 \
0047     .ext.packets_op = po,               \
0048     .ext.bytes_op = bo,             \
0049 }
0050 
0051 /* Revision 0 interface: backward compatible with netfilter/iptables */
0052 
0053 static bool
0054 set_match_v0(const struct sk_buff *skb, struct xt_action_param *par)
0055 {
0056     const struct xt_set_info_match_v0 *info = par->matchinfo;
0057 
0058     ADT_OPT(opt, xt_family(par), info->match_set.u.compat.dim,
0059         info->match_set.u.compat.flags, 0, UINT_MAX,
0060         0, 0, 0, 0);
0061 
0062     return match_set(info->match_set.index, skb, par, &opt,
0063              info->match_set.u.compat.flags & IPSET_INV_MATCH);
0064 }
0065 
0066 static void
0067 compat_flags(struct xt_set_info_v0 *info)
0068 {
0069     u_int8_t i;
0070 
0071     /* Fill out compatibility data according to enum ip_set_kopt */
0072     info->u.compat.dim = IPSET_DIM_ZERO;
0073     if (info->u.flags[0] & IPSET_MATCH_INV)
0074         info->u.compat.flags |= IPSET_INV_MATCH;
0075     for (i = 0; i < IPSET_DIM_MAX - 1 && info->u.flags[i]; i++) {
0076         info->u.compat.dim++;
0077         if (info->u.flags[i] & IPSET_SRC)
0078             info->u.compat.flags |= (1 << info->u.compat.dim);
0079     }
0080 }
0081 
0082 static int
0083 set_match_v0_checkentry(const struct xt_mtchk_param *par)
0084 {
0085     struct xt_set_info_match_v0 *info = par->matchinfo;
0086     ip_set_id_t index;
0087 
0088     index = ip_set_nfnl_get_byindex(par->net, info->match_set.index);
0089 
0090     if (index == IPSET_INVALID_ID) {
0091         pr_info_ratelimited("Cannot find set identified by id %u to match\n",
0092                     info->match_set.index);
0093         return -ENOENT;
0094     }
0095     if (info->match_set.u.flags[IPSET_DIM_MAX - 1] != 0) {
0096         pr_info_ratelimited("set match dimension is over the limit!\n");
0097         ip_set_nfnl_put(par->net, info->match_set.index);
0098         return -ERANGE;
0099     }
0100 
0101     /* Fill out compatibility data */
0102     compat_flags(&info->match_set);
0103 
0104     return 0;
0105 }
0106 
0107 static void
0108 set_match_v0_destroy(const struct xt_mtdtor_param *par)
0109 {
0110     struct xt_set_info_match_v0 *info = par->matchinfo;
0111 
0112     ip_set_nfnl_put(par->net, info->match_set.index);
0113 }
0114 
0115 /* Revision 1 match */
0116 
0117 static bool
0118 set_match_v1(const struct sk_buff *skb, struct xt_action_param *par)
0119 {
0120     const struct xt_set_info_match_v1 *info = par->matchinfo;
0121 
0122     ADT_OPT(opt, xt_family(par), info->match_set.dim,
0123         info->match_set.flags, 0, UINT_MAX,
0124         0, 0, 0, 0);
0125 
0126     if (opt.flags & IPSET_RETURN_NOMATCH)
0127         opt.cmdflags |= IPSET_FLAG_RETURN_NOMATCH;
0128 
0129     return match_set(info->match_set.index, skb, par, &opt,
0130              info->match_set.flags & IPSET_INV_MATCH);
0131 }
0132 
0133 static int
0134 set_match_v1_checkentry(const struct xt_mtchk_param *par)
0135 {
0136     struct xt_set_info_match_v1 *info = par->matchinfo;
0137     ip_set_id_t index;
0138 
0139     index = ip_set_nfnl_get_byindex(par->net, info->match_set.index);
0140 
0141     if (index == IPSET_INVALID_ID) {
0142         pr_info_ratelimited("Cannot find set identified by id %u to match\n",
0143                     info->match_set.index);
0144         return -ENOENT;
0145     }
0146     if (info->match_set.dim > IPSET_DIM_MAX) {
0147         pr_info_ratelimited("set match dimension is over the limit!\n");
0148         ip_set_nfnl_put(par->net, info->match_set.index);
0149         return -ERANGE;
0150     }
0151 
0152     return 0;
0153 }
0154 
0155 static void
0156 set_match_v1_destroy(const struct xt_mtdtor_param *par)
0157 {
0158     struct xt_set_info_match_v1 *info = par->matchinfo;
0159 
0160     ip_set_nfnl_put(par->net, info->match_set.index);
0161 }
0162 
0163 /* Revision 3 match */
0164 
0165 static bool
0166 set_match_v3(const struct sk_buff *skb, struct xt_action_param *par)
0167 {
0168     const struct xt_set_info_match_v3 *info = par->matchinfo;
0169 
0170     ADT_OPT(opt, xt_family(par), info->match_set.dim,
0171         info->match_set.flags, info->flags, UINT_MAX,
0172         info->packets.value, info->bytes.value,
0173         info->packets.op, info->bytes.op);
0174 
0175     if (info->packets.op != IPSET_COUNTER_NONE ||
0176         info->bytes.op != IPSET_COUNTER_NONE)
0177         opt.cmdflags |= IPSET_FLAG_MATCH_COUNTERS;
0178 
0179     return match_set(info->match_set.index, skb, par, &opt,
0180              info->match_set.flags & IPSET_INV_MATCH);
0181 }
0182 
0183 #define set_match_v3_checkentry set_match_v1_checkentry
0184 #define set_match_v3_destroy    set_match_v1_destroy
0185 
0186 /* Revision 4 match */
0187 
0188 static bool
0189 set_match_v4(const struct sk_buff *skb, struct xt_action_param *par)
0190 {
0191     const struct xt_set_info_match_v4 *info = par->matchinfo;
0192 
0193     ADT_OPT(opt, xt_family(par), info->match_set.dim,
0194         info->match_set.flags, info->flags, UINT_MAX,
0195         info->packets.value, info->bytes.value,
0196         info->packets.op, info->bytes.op);
0197 
0198     if (info->packets.op != IPSET_COUNTER_NONE ||
0199         info->bytes.op != IPSET_COUNTER_NONE)
0200         opt.cmdflags |= IPSET_FLAG_MATCH_COUNTERS;
0201 
0202     return match_set(info->match_set.index, skb, par, &opt,
0203              info->match_set.flags & IPSET_INV_MATCH);
0204 }
0205 
0206 #define set_match_v4_checkentry set_match_v1_checkentry
0207 #define set_match_v4_destroy    set_match_v1_destroy
0208 
0209 /* Revision 0 interface: backward compatible with netfilter/iptables */
0210 
0211 static unsigned int
0212 set_target_v0(struct sk_buff *skb, const struct xt_action_param *par)
0213 {
0214     const struct xt_set_info_target_v0 *info = par->targinfo;
0215 
0216     ADT_OPT(add_opt, xt_family(par), info->add_set.u.compat.dim,
0217         info->add_set.u.compat.flags, 0, UINT_MAX,
0218         0, 0, 0, 0);
0219     ADT_OPT(del_opt, xt_family(par), info->del_set.u.compat.dim,
0220         info->del_set.u.compat.flags, 0, UINT_MAX,
0221         0, 0, 0, 0);
0222 
0223     if (info->add_set.index != IPSET_INVALID_ID)
0224         ip_set_add(info->add_set.index, skb, par, &add_opt);
0225     if (info->del_set.index != IPSET_INVALID_ID)
0226         ip_set_del(info->del_set.index, skb, par, &del_opt);
0227 
0228     return XT_CONTINUE;
0229 }
0230 
0231 static int
0232 set_target_v0_checkentry(const struct xt_tgchk_param *par)
0233 {
0234     struct xt_set_info_target_v0 *info = par->targinfo;
0235     ip_set_id_t index;
0236 
0237     if (info->add_set.index != IPSET_INVALID_ID) {
0238         index = ip_set_nfnl_get_byindex(par->net, info->add_set.index);
0239         if (index == IPSET_INVALID_ID) {
0240             pr_info_ratelimited("Cannot find add_set index %u as target\n",
0241                         info->add_set.index);
0242             return -ENOENT;
0243         }
0244     }
0245 
0246     if (info->del_set.index != IPSET_INVALID_ID) {
0247         index = ip_set_nfnl_get_byindex(par->net, info->del_set.index);
0248         if (index == IPSET_INVALID_ID) {
0249             pr_info_ratelimited("Cannot find del_set index %u as target\n",
0250                         info->del_set.index);
0251             if (info->add_set.index != IPSET_INVALID_ID)
0252                 ip_set_nfnl_put(par->net, info->add_set.index);
0253             return -ENOENT;
0254         }
0255     }
0256     if (info->add_set.u.flags[IPSET_DIM_MAX - 1] != 0 ||
0257         info->del_set.u.flags[IPSET_DIM_MAX - 1] != 0) {
0258         pr_info_ratelimited("SET target dimension over the limit!\n");
0259         if (info->add_set.index != IPSET_INVALID_ID)
0260             ip_set_nfnl_put(par->net, info->add_set.index);
0261         if (info->del_set.index != IPSET_INVALID_ID)
0262             ip_set_nfnl_put(par->net, info->del_set.index);
0263         return -ERANGE;
0264     }
0265 
0266     /* Fill out compatibility data */
0267     compat_flags(&info->add_set);
0268     compat_flags(&info->del_set);
0269 
0270     return 0;
0271 }
0272 
0273 static void
0274 set_target_v0_destroy(const struct xt_tgdtor_param *par)
0275 {
0276     const struct xt_set_info_target_v0 *info = par->targinfo;
0277 
0278     if (info->add_set.index != IPSET_INVALID_ID)
0279         ip_set_nfnl_put(par->net, info->add_set.index);
0280     if (info->del_set.index != IPSET_INVALID_ID)
0281         ip_set_nfnl_put(par->net, info->del_set.index);
0282 }
0283 
0284 /* Revision 1 target */
0285 
0286 static unsigned int
0287 set_target_v1(struct sk_buff *skb, const struct xt_action_param *par)
0288 {
0289     const struct xt_set_info_target_v1 *info = par->targinfo;
0290 
0291     ADT_OPT(add_opt, xt_family(par), info->add_set.dim,
0292         info->add_set.flags, 0, UINT_MAX,
0293         0, 0, 0, 0);
0294     ADT_OPT(del_opt, xt_family(par), info->del_set.dim,
0295         info->del_set.flags, 0, UINT_MAX,
0296         0, 0, 0, 0);
0297 
0298     if (info->add_set.index != IPSET_INVALID_ID)
0299         ip_set_add(info->add_set.index, skb, par, &add_opt);
0300     if (info->del_set.index != IPSET_INVALID_ID)
0301         ip_set_del(info->del_set.index, skb, par, &del_opt);
0302 
0303     return XT_CONTINUE;
0304 }
0305 
0306 static int
0307 set_target_v1_checkentry(const struct xt_tgchk_param *par)
0308 {
0309     const struct xt_set_info_target_v1 *info = par->targinfo;
0310     ip_set_id_t index;
0311 
0312     if (info->add_set.index != IPSET_INVALID_ID) {
0313         index = ip_set_nfnl_get_byindex(par->net, info->add_set.index);
0314         if (index == IPSET_INVALID_ID) {
0315             pr_info_ratelimited("Cannot find add_set index %u as target\n",
0316                         info->add_set.index);
0317             return -ENOENT;
0318         }
0319     }
0320 
0321     if (info->del_set.index != IPSET_INVALID_ID) {
0322         index = ip_set_nfnl_get_byindex(par->net, info->del_set.index);
0323         if (index == IPSET_INVALID_ID) {
0324             pr_info_ratelimited("Cannot find del_set index %u as target\n",
0325                         info->del_set.index);
0326             if (info->add_set.index != IPSET_INVALID_ID)
0327                 ip_set_nfnl_put(par->net, info->add_set.index);
0328             return -ENOENT;
0329         }
0330     }
0331     if (info->add_set.dim > IPSET_DIM_MAX ||
0332         info->del_set.dim > IPSET_DIM_MAX) {
0333         pr_info_ratelimited("SET target dimension over the limit!\n");
0334         if (info->add_set.index != IPSET_INVALID_ID)
0335             ip_set_nfnl_put(par->net, info->add_set.index);
0336         if (info->del_set.index != IPSET_INVALID_ID)
0337             ip_set_nfnl_put(par->net, info->del_set.index);
0338         return -ERANGE;
0339     }
0340 
0341     return 0;
0342 }
0343 
0344 static void
0345 set_target_v1_destroy(const struct xt_tgdtor_param *par)
0346 {
0347     const struct xt_set_info_target_v1 *info = par->targinfo;
0348 
0349     if (info->add_set.index != IPSET_INVALID_ID)
0350         ip_set_nfnl_put(par->net, info->add_set.index);
0351     if (info->del_set.index != IPSET_INVALID_ID)
0352         ip_set_nfnl_put(par->net, info->del_set.index);
0353 }
0354 
0355 /* Revision 2 target */
0356 
0357 static unsigned int
0358 set_target_v2(struct sk_buff *skb, const struct xt_action_param *par)
0359 {
0360     const struct xt_set_info_target_v2 *info = par->targinfo;
0361 
0362     ADT_OPT(add_opt, xt_family(par), info->add_set.dim,
0363         info->add_set.flags, info->flags, info->timeout,
0364         0, 0, 0, 0);
0365     ADT_OPT(del_opt, xt_family(par), info->del_set.dim,
0366         info->del_set.flags, 0, UINT_MAX,
0367         0, 0, 0, 0);
0368 
0369     /* Normalize to fit into jiffies */
0370     if (add_opt.ext.timeout != IPSET_NO_TIMEOUT &&
0371         add_opt.ext.timeout > IPSET_MAX_TIMEOUT)
0372         add_opt.ext.timeout = IPSET_MAX_TIMEOUT;
0373     if (info->add_set.index != IPSET_INVALID_ID)
0374         ip_set_add(info->add_set.index, skb, par, &add_opt);
0375     if (info->del_set.index != IPSET_INVALID_ID)
0376         ip_set_del(info->del_set.index, skb, par, &del_opt);
0377 
0378     return XT_CONTINUE;
0379 }
0380 
0381 #define set_target_v2_checkentry    set_target_v1_checkentry
0382 #define set_target_v2_destroy       set_target_v1_destroy
0383 
0384 /* Revision 3 target */
0385 
0386 #define MOPT(opt, member)   ((opt).ext.skbinfo.member)
0387 
0388 static unsigned int
0389 set_target_v3(struct sk_buff *skb, const struct xt_action_param *par)
0390 {
0391     const struct xt_set_info_target_v3 *info = par->targinfo;
0392     int ret;
0393 
0394     ADT_OPT(add_opt, xt_family(par), info->add_set.dim,
0395         info->add_set.flags, info->flags, info->timeout,
0396         0, 0, 0, 0);
0397     ADT_OPT(del_opt, xt_family(par), info->del_set.dim,
0398         info->del_set.flags, 0, UINT_MAX,
0399         0, 0, 0, 0);
0400     ADT_OPT(map_opt, xt_family(par), info->map_set.dim,
0401         info->map_set.flags, 0, UINT_MAX,
0402         0, 0, 0, 0);
0403 
0404     /* Normalize to fit into jiffies */
0405     if (add_opt.ext.timeout != IPSET_NO_TIMEOUT &&
0406         add_opt.ext.timeout > IPSET_MAX_TIMEOUT)
0407         add_opt.ext.timeout = IPSET_MAX_TIMEOUT;
0408     if (info->add_set.index != IPSET_INVALID_ID)
0409         ip_set_add(info->add_set.index, skb, par, &add_opt);
0410     if (info->del_set.index != IPSET_INVALID_ID)
0411         ip_set_del(info->del_set.index, skb, par, &del_opt);
0412     if (info->map_set.index != IPSET_INVALID_ID) {
0413         map_opt.cmdflags |= info->flags & (IPSET_FLAG_MAP_SKBMARK |
0414                            IPSET_FLAG_MAP_SKBPRIO |
0415                            IPSET_FLAG_MAP_SKBQUEUE);
0416         ret = match_set(info->map_set.index, skb, par, &map_opt,
0417                 info->map_set.flags & IPSET_INV_MATCH);
0418         if (!ret)
0419             return XT_CONTINUE;
0420         if (map_opt.cmdflags & IPSET_FLAG_MAP_SKBMARK)
0421             skb->mark = (skb->mark & ~MOPT(map_opt,skbmarkmask))
0422                     ^ MOPT(map_opt, skbmark);
0423         if (map_opt.cmdflags & IPSET_FLAG_MAP_SKBPRIO)
0424             skb->priority = MOPT(map_opt, skbprio);
0425         if ((map_opt.cmdflags & IPSET_FLAG_MAP_SKBQUEUE) &&
0426             skb->dev &&
0427             skb->dev->real_num_tx_queues > MOPT(map_opt, skbqueue))
0428             skb_set_queue_mapping(skb, MOPT(map_opt, skbqueue));
0429     }
0430     return XT_CONTINUE;
0431 }
0432 
0433 static int
0434 set_target_v3_checkentry(const struct xt_tgchk_param *par)
0435 {
0436     const struct xt_set_info_target_v3 *info = par->targinfo;
0437     ip_set_id_t index;
0438     int ret = 0;
0439 
0440     if (info->add_set.index != IPSET_INVALID_ID) {
0441         index = ip_set_nfnl_get_byindex(par->net,
0442                         info->add_set.index);
0443         if (index == IPSET_INVALID_ID) {
0444             pr_info_ratelimited("Cannot find add_set index %u as target\n",
0445                         info->add_set.index);
0446             return -ENOENT;
0447         }
0448     }
0449 
0450     if (info->del_set.index != IPSET_INVALID_ID) {
0451         index = ip_set_nfnl_get_byindex(par->net,
0452                         info->del_set.index);
0453         if (index == IPSET_INVALID_ID) {
0454             pr_info_ratelimited("Cannot find del_set index %u as target\n",
0455                         info->del_set.index);
0456             ret = -ENOENT;
0457             goto cleanup_add;
0458         }
0459     }
0460 
0461     if (info->map_set.index != IPSET_INVALID_ID) {
0462         if (strncmp(par->table, "mangle", 7)) {
0463             pr_info_ratelimited("--map-set only usable from mangle table\n");
0464             ret = -EINVAL;
0465             goto cleanup_del;
0466         }
0467         if (((info->flags & IPSET_FLAG_MAP_SKBPRIO) |
0468              (info->flags & IPSET_FLAG_MAP_SKBQUEUE)) &&
0469              (par->hook_mask & ~(1 << NF_INET_FORWARD |
0470                      1 << NF_INET_LOCAL_OUT |
0471                      1 << NF_INET_POST_ROUTING))) {
0472             pr_info_ratelimited("mapping of prio or/and queue is allowed only from OUTPUT/FORWARD/POSTROUTING chains\n");
0473             ret = -EINVAL;
0474             goto cleanup_del;
0475         }
0476         index = ip_set_nfnl_get_byindex(par->net,
0477                         info->map_set.index);
0478         if (index == IPSET_INVALID_ID) {
0479             pr_info_ratelimited("Cannot find map_set index %u as target\n",
0480                         info->map_set.index);
0481             ret = -ENOENT;
0482             goto cleanup_del;
0483         }
0484     }
0485 
0486     if (info->add_set.dim > IPSET_DIM_MAX ||
0487         info->del_set.dim > IPSET_DIM_MAX ||
0488         info->map_set.dim > IPSET_DIM_MAX) {
0489         pr_info_ratelimited("SET target dimension over the limit!\n");
0490         ret = -ERANGE;
0491         goto cleanup_mark;
0492     }
0493 
0494     return 0;
0495 cleanup_mark:
0496     if (info->map_set.index != IPSET_INVALID_ID)
0497         ip_set_nfnl_put(par->net, info->map_set.index);
0498 cleanup_del:
0499     if (info->del_set.index != IPSET_INVALID_ID)
0500         ip_set_nfnl_put(par->net, info->del_set.index);
0501 cleanup_add:
0502     if (info->add_set.index != IPSET_INVALID_ID)
0503         ip_set_nfnl_put(par->net, info->add_set.index);
0504     return ret;
0505 }
0506 
0507 static void
0508 set_target_v3_destroy(const struct xt_tgdtor_param *par)
0509 {
0510     const struct xt_set_info_target_v3 *info = par->targinfo;
0511 
0512     if (info->add_set.index != IPSET_INVALID_ID)
0513         ip_set_nfnl_put(par->net, info->add_set.index);
0514     if (info->del_set.index != IPSET_INVALID_ID)
0515         ip_set_nfnl_put(par->net, info->del_set.index);
0516     if (info->map_set.index != IPSET_INVALID_ID)
0517         ip_set_nfnl_put(par->net, info->map_set.index);
0518 }
0519 
0520 static struct xt_match set_matches[] __read_mostly = {
0521     {
0522         .name       = "set",
0523         .family     = NFPROTO_IPV4,
0524         .revision   = 0,
0525         .match      = set_match_v0,
0526         .matchsize  = sizeof(struct xt_set_info_match_v0),
0527         .checkentry = set_match_v0_checkentry,
0528         .destroy    = set_match_v0_destroy,
0529         .me     = THIS_MODULE
0530     },
0531     {
0532         .name       = "set",
0533         .family     = NFPROTO_IPV4,
0534         .revision   = 1,
0535         .match      = set_match_v1,
0536         .matchsize  = sizeof(struct xt_set_info_match_v1),
0537         .checkentry = set_match_v1_checkentry,
0538         .destroy    = set_match_v1_destroy,
0539         .me     = THIS_MODULE
0540     },
0541     {
0542         .name       = "set",
0543         .family     = NFPROTO_IPV6,
0544         .revision   = 1,
0545         .match      = set_match_v1,
0546         .matchsize  = sizeof(struct xt_set_info_match_v1),
0547         .checkentry = set_match_v1_checkentry,
0548         .destroy    = set_match_v1_destroy,
0549         .me     = THIS_MODULE
0550     },
0551     /* --return-nomatch flag support */
0552     {
0553         .name       = "set",
0554         .family     = NFPROTO_IPV4,
0555         .revision   = 2,
0556         .match      = set_match_v1,
0557         .matchsize  = sizeof(struct xt_set_info_match_v1),
0558         .checkentry = set_match_v1_checkentry,
0559         .destroy    = set_match_v1_destroy,
0560         .me     = THIS_MODULE
0561     },
0562     {
0563         .name       = "set",
0564         .family     = NFPROTO_IPV6,
0565         .revision   = 2,
0566         .match      = set_match_v1,
0567         .matchsize  = sizeof(struct xt_set_info_match_v1),
0568         .checkentry = set_match_v1_checkentry,
0569         .destroy    = set_match_v1_destroy,
0570         .me     = THIS_MODULE
0571     },
0572     /* counters support: update, match */
0573     {
0574         .name       = "set",
0575         .family     = NFPROTO_IPV4,
0576         .revision   = 3,
0577         .match      = set_match_v3,
0578         .matchsize  = sizeof(struct xt_set_info_match_v3),
0579         .checkentry = set_match_v3_checkentry,
0580         .destroy    = set_match_v3_destroy,
0581         .me     = THIS_MODULE
0582     },
0583     {
0584         .name       = "set",
0585         .family     = NFPROTO_IPV6,
0586         .revision   = 3,
0587         .match      = set_match_v3,
0588         .matchsize  = sizeof(struct xt_set_info_match_v3),
0589         .checkentry = set_match_v3_checkentry,
0590         .destroy    = set_match_v3_destroy,
0591         .me     = THIS_MODULE
0592     },
0593     /* new revision for counters support: update, match */
0594     {
0595         .name       = "set",
0596         .family     = NFPROTO_IPV4,
0597         .revision   = 4,
0598         .match      = set_match_v4,
0599         .matchsize  = sizeof(struct xt_set_info_match_v4),
0600         .checkentry = set_match_v4_checkentry,
0601         .destroy    = set_match_v4_destroy,
0602         .me     = THIS_MODULE
0603     },
0604     {
0605         .name       = "set",
0606         .family     = NFPROTO_IPV6,
0607         .revision   = 4,
0608         .match      = set_match_v4,
0609         .matchsize  = sizeof(struct xt_set_info_match_v4),
0610         .checkentry = set_match_v4_checkentry,
0611         .destroy    = set_match_v4_destroy,
0612         .me     = THIS_MODULE
0613     },
0614 };
0615 
0616 static struct xt_target set_targets[] __read_mostly = {
0617     {
0618         .name       = "SET",
0619         .revision   = 0,
0620         .family     = NFPROTO_IPV4,
0621         .target     = set_target_v0,
0622         .targetsize = sizeof(struct xt_set_info_target_v0),
0623         .checkentry = set_target_v0_checkentry,
0624         .destroy    = set_target_v0_destroy,
0625         .me     = THIS_MODULE
0626     },
0627     {
0628         .name       = "SET",
0629         .revision   = 1,
0630         .family     = NFPROTO_IPV4,
0631         .target     = set_target_v1,
0632         .targetsize = sizeof(struct xt_set_info_target_v1),
0633         .checkentry = set_target_v1_checkentry,
0634         .destroy    = set_target_v1_destroy,
0635         .me     = THIS_MODULE
0636     },
0637     {
0638         .name       = "SET",
0639         .revision   = 1,
0640         .family     = NFPROTO_IPV6,
0641         .target     = set_target_v1,
0642         .targetsize = sizeof(struct xt_set_info_target_v1),
0643         .checkentry = set_target_v1_checkentry,
0644         .destroy    = set_target_v1_destroy,
0645         .me     = THIS_MODULE
0646     },
0647     /* --timeout and --exist flags support */
0648     {
0649         .name       = "SET",
0650         .revision   = 2,
0651         .family     = NFPROTO_IPV4,
0652         .target     = set_target_v2,
0653         .targetsize = sizeof(struct xt_set_info_target_v2),
0654         .checkentry = set_target_v2_checkentry,
0655         .destroy    = set_target_v2_destroy,
0656         .me     = THIS_MODULE
0657     },
0658     {
0659         .name       = "SET",
0660         .revision   = 2,
0661         .family     = NFPROTO_IPV6,
0662         .target     = set_target_v2,
0663         .targetsize = sizeof(struct xt_set_info_target_v2),
0664         .checkentry = set_target_v2_checkentry,
0665         .destroy    = set_target_v2_destroy,
0666         .me     = THIS_MODULE
0667     },
0668     /* --map-set support */
0669     {
0670         .name       = "SET",
0671         .revision   = 3,
0672         .family     = NFPROTO_IPV4,
0673         .target     = set_target_v3,
0674         .targetsize = sizeof(struct xt_set_info_target_v3),
0675         .checkentry = set_target_v3_checkentry,
0676         .destroy    = set_target_v3_destroy,
0677         .me     = THIS_MODULE
0678     },
0679     {
0680         .name       = "SET",
0681         .revision   = 3,
0682         .family     = NFPROTO_IPV6,
0683         .target     = set_target_v3,
0684         .targetsize = sizeof(struct xt_set_info_target_v3),
0685         .checkentry = set_target_v3_checkentry,
0686         .destroy    = set_target_v3_destroy,
0687         .me     = THIS_MODULE
0688     },
0689 };
0690 
0691 static int __init xt_set_init(void)
0692 {
0693     int ret = xt_register_matches(set_matches, ARRAY_SIZE(set_matches));
0694 
0695     if (!ret) {
0696         ret = xt_register_targets(set_targets,
0697                       ARRAY_SIZE(set_targets));
0698         if (ret)
0699             xt_unregister_matches(set_matches,
0700                           ARRAY_SIZE(set_matches));
0701     }
0702     return ret;
0703 }
0704 
0705 static void __exit xt_set_fini(void)
0706 {
0707     xt_unregister_matches(set_matches, ARRAY_SIZE(set_matches));
0708     xt_unregister_targets(set_targets, ARRAY_SIZE(set_targets));
0709 }
0710 
0711 module_init(xt_set_init);
0712 module_exit(xt_set_fini);