1d956798dSJozsef Kadlecsik /* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu> 2d956798dSJozsef Kadlecsik * Patrick Schaaf <bof@bof.de> 3d956798dSJozsef Kadlecsik * Martin Josefsson <gandalf@wlug.westbo.se> 4075e64c0SJozsef Kadlecsik * Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> 5d956798dSJozsef Kadlecsik * 6d956798dSJozsef Kadlecsik * This program is free software; you can redistribute it and/or modify 7d956798dSJozsef Kadlecsik * it under the terms of the GNU General Public License version 2 as 8d956798dSJozsef Kadlecsik * published by the Free Software Foundation. 9d956798dSJozsef Kadlecsik */ 10d956798dSJozsef Kadlecsik 11d956798dSJozsef Kadlecsik /* Kernel module which implements the set match and SET target 12ca0f6a5cSJozsef Kadlecsik * for netfilter/iptables. 13ca0f6a5cSJozsef Kadlecsik */ 14d956798dSJozsef Kadlecsik 15d956798dSJozsef Kadlecsik #include <linux/module.h> 16d956798dSJozsef Kadlecsik #include <linux/skbuff.h> 17d956798dSJozsef Kadlecsik 18d956798dSJozsef Kadlecsik #include <linux/netfilter/x_tables.h> 19a9756e6fSJozsef Kadlecsik #include <linux/netfilter/ipset/ip_set.h> 20a73f89a6SJozsef Kadlecsik #include <linux/netfilter/ipset/ip_set_timeout.h> 21a9756e6fSJozsef Kadlecsik #include <uapi/linux/netfilter/xt_set.h> 22d956798dSJozsef Kadlecsik 23d956798dSJozsef Kadlecsik MODULE_LICENSE("GPL"); 24d956798dSJozsef Kadlecsik MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); 25d956798dSJozsef Kadlecsik MODULE_DESCRIPTION("Xtables: IP set match and target module"); 26d956798dSJozsef Kadlecsik MODULE_ALIAS("xt_SET"); 27d956798dSJozsef Kadlecsik MODULE_ALIAS("ipt_set"); 28d956798dSJozsef Kadlecsik MODULE_ALIAS("ip6t_set"); 29d956798dSJozsef Kadlecsik MODULE_ALIAS("ipt_SET"); 30d956798dSJozsef Kadlecsik MODULE_ALIAS("ip6t_SET"); 31d956798dSJozsef Kadlecsik 32d956798dSJozsef Kadlecsik static inline int 33d956798dSJozsef Kadlecsik match_set(ip_set_id_t index, const struct sk_buff *skb, 34b66554cfSJozsef Kadlecsik const struct xt_action_param *par, 35075e64c0SJozsef Kadlecsik struct ip_set_adt_opt *opt, int inv) 36d956798dSJozsef Kadlecsik { 37b66554cfSJozsef Kadlecsik if (ip_set_test(index, skb, par, opt)) 38d956798dSJozsef Kadlecsik inv = !inv; 39d956798dSJozsef Kadlecsik return inv; 40d956798dSJozsef Kadlecsik } 41d956798dSJozsef Kadlecsik 42ac8cc925SJozsef Kadlecsik #define ADT_OPT(n, f, d, fs, cfs, t) \ 43127f5591SJozsef Kadlecsik struct ip_set_adt_opt n = { \ 44127f5591SJozsef Kadlecsik .family = f, \ 45127f5591SJozsef Kadlecsik .dim = d, \ 46127f5591SJozsef Kadlecsik .flags = fs, \ 47127f5591SJozsef Kadlecsik .cmdflags = cfs, \ 48075e64c0SJozsef Kadlecsik .ext.timeout = t, \ 49127f5591SJozsef Kadlecsik } 50ac8cc925SJozsef Kadlecsik 51d956798dSJozsef Kadlecsik /* Revision 0 interface: backward compatible with netfilter/iptables */ 52d956798dSJozsef Kadlecsik 53d956798dSJozsef Kadlecsik static bool 54d956798dSJozsef Kadlecsik set_match_v0(const struct sk_buff *skb, struct xt_action_param *par) 55d956798dSJozsef Kadlecsik { 56d956798dSJozsef Kadlecsik const struct xt_set_info_match_v0 *info = par->matchinfo; 57ca0f6a5cSJozsef Kadlecsik 58ac8cc925SJozsef Kadlecsik ADT_OPT(opt, par->family, info->match_set.u.compat.dim, 59ac8cc925SJozsef Kadlecsik info->match_set.u.compat.flags, 0, UINT_MAX); 60d956798dSJozsef Kadlecsik 61b66554cfSJozsef Kadlecsik return match_set(info->match_set.index, skb, par, &opt, 62d956798dSJozsef Kadlecsik info->match_set.u.compat.flags & IPSET_INV_MATCH); 63d956798dSJozsef Kadlecsik } 64d956798dSJozsef Kadlecsik 65d956798dSJozsef Kadlecsik static void 66d956798dSJozsef Kadlecsik compat_flags(struct xt_set_info_v0 *info) 67d956798dSJozsef Kadlecsik { 68d956798dSJozsef Kadlecsik u_int8_t i; 69d956798dSJozsef Kadlecsik 70d956798dSJozsef Kadlecsik /* Fill out compatibility data according to enum ip_set_kopt */ 71d956798dSJozsef Kadlecsik info->u.compat.dim = IPSET_DIM_ZERO; 72d956798dSJozsef Kadlecsik if (info->u.flags[0] & IPSET_MATCH_INV) 73d956798dSJozsef Kadlecsik info->u.compat.flags |= IPSET_INV_MATCH; 74d956798dSJozsef Kadlecsik for (i = 0; i < IPSET_DIM_MAX - 1 && info->u.flags[i]; i++) { 75d956798dSJozsef Kadlecsik info->u.compat.dim++; 76d956798dSJozsef Kadlecsik if (info->u.flags[i] & IPSET_SRC) 77d956798dSJozsef Kadlecsik info->u.compat.flags |= (1 << info->u.compat.dim); 78d956798dSJozsef Kadlecsik } 79d956798dSJozsef Kadlecsik } 80d956798dSJozsef Kadlecsik 81d956798dSJozsef Kadlecsik static int 82d956798dSJozsef Kadlecsik set_match_v0_checkentry(const struct xt_mtchk_param *par) 83d956798dSJozsef Kadlecsik { 84d956798dSJozsef Kadlecsik struct xt_set_info_match_v0 *info = par->matchinfo; 85d956798dSJozsef Kadlecsik ip_set_id_t index; 86d956798dSJozsef Kadlecsik 871785e8f4SVitaly Lavrov index = ip_set_nfnl_get_byindex(par->net, info->match_set.index); 88d956798dSJozsef Kadlecsik 89d956798dSJozsef Kadlecsik if (index == IPSET_INVALID_ID) { 90b167a37cSJoe Perches pr_warn("Cannot find set identified by id %u to match\n", 91d956798dSJozsef Kadlecsik info->match_set.index); 92d956798dSJozsef Kadlecsik return -ENOENT; 93d956798dSJozsef Kadlecsik } 94d956798dSJozsef Kadlecsik if (info->match_set.u.flags[IPSET_DIM_MAX - 1] != 0) { 95b167a37cSJoe Perches pr_warn("Protocol error: set match dimension is over the limit!\n"); 961785e8f4SVitaly Lavrov ip_set_nfnl_put(par->net, info->match_set.index); 97d956798dSJozsef Kadlecsik return -ERANGE; 98d956798dSJozsef Kadlecsik } 99d956798dSJozsef Kadlecsik 100d956798dSJozsef Kadlecsik /* Fill out compatibility data */ 101d956798dSJozsef Kadlecsik compat_flags(&info->match_set); 102d956798dSJozsef Kadlecsik 103d956798dSJozsef Kadlecsik return 0; 104d956798dSJozsef Kadlecsik } 105d956798dSJozsef Kadlecsik 106d956798dSJozsef Kadlecsik static void 107d956798dSJozsef Kadlecsik set_match_v0_destroy(const struct xt_mtdtor_param *par) 108d956798dSJozsef Kadlecsik { 109d956798dSJozsef Kadlecsik struct xt_set_info_match_v0 *info = par->matchinfo; 110d956798dSJozsef Kadlecsik 1111785e8f4SVitaly Lavrov ip_set_nfnl_put(par->net, info->match_set.index); 112d956798dSJozsef Kadlecsik } 113d956798dSJozsef Kadlecsik 114bd3129fcSJozsef Kadlecsik /* Revision 1 match */ 115bd3129fcSJozsef Kadlecsik 116bd3129fcSJozsef Kadlecsik static bool 117bd3129fcSJozsef Kadlecsik set_match_v1(const struct sk_buff *skb, struct xt_action_param *par) 118bd3129fcSJozsef Kadlecsik { 119bd3129fcSJozsef Kadlecsik const struct xt_set_info_match_v1 *info = par->matchinfo; 120ca0f6a5cSJozsef Kadlecsik 121bd3129fcSJozsef Kadlecsik ADT_OPT(opt, par->family, info->match_set.dim, 122bd3129fcSJozsef Kadlecsik info->match_set.flags, 0, UINT_MAX); 123bd3129fcSJozsef Kadlecsik 124bd3129fcSJozsef Kadlecsik if (opt.flags & IPSET_RETURN_NOMATCH) 125bd3129fcSJozsef Kadlecsik opt.cmdflags |= IPSET_FLAG_RETURN_NOMATCH; 126bd3129fcSJozsef Kadlecsik 127bd3129fcSJozsef Kadlecsik return match_set(info->match_set.index, skb, par, &opt, 128bd3129fcSJozsef Kadlecsik info->match_set.flags & IPSET_INV_MATCH); 129bd3129fcSJozsef Kadlecsik } 130bd3129fcSJozsef Kadlecsik 131bd3129fcSJozsef Kadlecsik static int 132bd3129fcSJozsef Kadlecsik set_match_v1_checkentry(const struct xt_mtchk_param *par) 133bd3129fcSJozsef Kadlecsik { 134bd3129fcSJozsef Kadlecsik struct xt_set_info_match_v1 *info = par->matchinfo; 135bd3129fcSJozsef Kadlecsik ip_set_id_t index; 136bd3129fcSJozsef Kadlecsik 1371785e8f4SVitaly Lavrov index = ip_set_nfnl_get_byindex(par->net, info->match_set.index); 138bd3129fcSJozsef Kadlecsik 139bd3129fcSJozsef Kadlecsik if (index == IPSET_INVALID_ID) { 140b167a37cSJoe Perches pr_warn("Cannot find set identified by id %u to match\n", 141bd3129fcSJozsef Kadlecsik info->match_set.index); 142bd3129fcSJozsef Kadlecsik return -ENOENT; 143bd3129fcSJozsef Kadlecsik } 144bd3129fcSJozsef Kadlecsik if (info->match_set.dim > IPSET_DIM_MAX) { 145b167a37cSJoe Perches pr_warn("Protocol error: set match dimension is over the limit!\n"); 1461785e8f4SVitaly Lavrov ip_set_nfnl_put(par->net, info->match_set.index); 147bd3129fcSJozsef Kadlecsik return -ERANGE; 148bd3129fcSJozsef Kadlecsik } 149bd3129fcSJozsef Kadlecsik 150bd3129fcSJozsef Kadlecsik return 0; 151bd3129fcSJozsef Kadlecsik } 152bd3129fcSJozsef Kadlecsik 153bd3129fcSJozsef Kadlecsik static void 154bd3129fcSJozsef Kadlecsik set_match_v1_destroy(const struct xt_mtdtor_param *par) 155bd3129fcSJozsef Kadlecsik { 156bd3129fcSJozsef Kadlecsik struct xt_set_info_match_v1 *info = par->matchinfo; 157bd3129fcSJozsef Kadlecsik 1581785e8f4SVitaly Lavrov ip_set_nfnl_put(par->net, info->match_set.index); 159bd3129fcSJozsef Kadlecsik } 160bd3129fcSJozsef Kadlecsik 161bd3129fcSJozsef Kadlecsik /* Revision 3 match */ 162bd3129fcSJozsef Kadlecsik 163bd3129fcSJozsef Kadlecsik static bool 164a51b9199SJozsef Kadlecsik match_counter0(u64 counter, const struct ip_set_counter_match0 *info) 165bd3129fcSJozsef Kadlecsik { 166bd3129fcSJozsef Kadlecsik switch (info->op) { 167bd3129fcSJozsef Kadlecsik case IPSET_COUNTER_NONE: 168bd3129fcSJozsef Kadlecsik return true; 169bd3129fcSJozsef Kadlecsik case IPSET_COUNTER_EQ: 170bd3129fcSJozsef Kadlecsik return counter == info->value; 171bd3129fcSJozsef Kadlecsik case IPSET_COUNTER_NE: 172bd3129fcSJozsef Kadlecsik return counter != info->value; 173bd3129fcSJozsef Kadlecsik case IPSET_COUNTER_LT: 174bd3129fcSJozsef Kadlecsik return counter < info->value; 175bd3129fcSJozsef Kadlecsik case IPSET_COUNTER_GT: 176bd3129fcSJozsef Kadlecsik return counter > info->value; 177bd3129fcSJozsef Kadlecsik } 178bd3129fcSJozsef Kadlecsik return false; 179bd3129fcSJozsef Kadlecsik } 180bd3129fcSJozsef Kadlecsik 181bd3129fcSJozsef Kadlecsik static bool 182bd3129fcSJozsef Kadlecsik set_match_v3(const struct sk_buff *skb, struct xt_action_param *par) 183bd3129fcSJozsef Kadlecsik { 184bd3129fcSJozsef Kadlecsik const struct xt_set_info_match_v3 *info = par->matchinfo; 185ca0f6a5cSJozsef Kadlecsik int ret; 186ca0f6a5cSJozsef Kadlecsik 187bd3129fcSJozsef Kadlecsik ADT_OPT(opt, par->family, info->match_set.dim, 188bd3129fcSJozsef Kadlecsik info->match_set.flags, info->flags, UINT_MAX); 189bd3129fcSJozsef Kadlecsik 190bd3129fcSJozsef Kadlecsik if (info->packets.op != IPSET_COUNTER_NONE || 191bd3129fcSJozsef Kadlecsik info->bytes.op != IPSET_COUNTER_NONE) 192bd3129fcSJozsef Kadlecsik opt.cmdflags |= IPSET_FLAG_MATCH_COUNTERS; 193bd3129fcSJozsef Kadlecsik 194bd3129fcSJozsef Kadlecsik ret = match_set(info->match_set.index, skb, par, &opt, 195bd3129fcSJozsef Kadlecsik info->match_set.flags & IPSET_INV_MATCH); 196bd3129fcSJozsef Kadlecsik 197bd3129fcSJozsef Kadlecsik if (!(ret && opt.cmdflags & IPSET_FLAG_MATCH_COUNTERS)) 198bd3129fcSJozsef Kadlecsik return ret; 199bd3129fcSJozsef Kadlecsik 200a51b9199SJozsef Kadlecsik if (!match_counter0(opt.ext.packets, &info->packets)) 2017f73b9f1SWu Fengguang return false; 202a51b9199SJozsef Kadlecsik return match_counter0(opt.ext.bytes, &info->bytes); 203a51b9199SJozsef Kadlecsik } 204a51b9199SJozsef Kadlecsik 205a51b9199SJozsef Kadlecsik #define set_match_v3_checkentry set_match_v1_checkentry 206a51b9199SJozsef Kadlecsik #define set_match_v3_destroy set_match_v1_destroy 207a51b9199SJozsef Kadlecsik 208a51b9199SJozsef Kadlecsik /* Revision 4 match */ 209a51b9199SJozsef Kadlecsik 210a51b9199SJozsef Kadlecsik static bool 211a51b9199SJozsef Kadlecsik match_counter(u64 counter, const struct ip_set_counter_match *info) 212a51b9199SJozsef Kadlecsik { 213a51b9199SJozsef Kadlecsik switch (info->op) { 214a51b9199SJozsef Kadlecsik case IPSET_COUNTER_NONE: 215a51b9199SJozsef Kadlecsik return true; 216a51b9199SJozsef Kadlecsik case IPSET_COUNTER_EQ: 217a51b9199SJozsef Kadlecsik return counter == info->value; 218a51b9199SJozsef Kadlecsik case IPSET_COUNTER_NE: 219a51b9199SJozsef Kadlecsik return counter != info->value; 220a51b9199SJozsef Kadlecsik case IPSET_COUNTER_LT: 221a51b9199SJozsef Kadlecsik return counter < info->value; 222a51b9199SJozsef Kadlecsik case IPSET_COUNTER_GT: 223a51b9199SJozsef Kadlecsik return counter > info->value; 224a51b9199SJozsef Kadlecsik } 225a51b9199SJozsef Kadlecsik return false; 226a51b9199SJozsef Kadlecsik } 227a51b9199SJozsef Kadlecsik 228a51b9199SJozsef Kadlecsik static bool 229a51b9199SJozsef Kadlecsik set_match_v4(const struct sk_buff *skb, struct xt_action_param *par) 230a51b9199SJozsef Kadlecsik { 231a51b9199SJozsef Kadlecsik const struct xt_set_info_match_v4 *info = par->matchinfo; 232ca0f6a5cSJozsef Kadlecsik int ret; 233ca0f6a5cSJozsef Kadlecsik 234a51b9199SJozsef Kadlecsik ADT_OPT(opt, par->family, info->match_set.dim, 235a51b9199SJozsef Kadlecsik info->match_set.flags, info->flags, UINT_MAX); 236a51b9199SJozsef Kadlecsik 237a51b9199SJozsef Kadlecsik if (info->packets.op != IPSET_COUNTER_NONE || 238a51b9199SJozsef Kadlecsik info->bytes.op != IPSET_COUNTER_NONE) 239a51b9199SJozsef Kadlecsik opt.cmdflags |= IPSET_FLAG_MATCH_COUNTERS; 240a51b9199SJozsef Kadlecsik 241a51b9199SJozsef Kadlecsik ret = match_set(info->match_set.index, skb, par, &opt, 242a51b9199SJozsef Kadlecsik info->match_set.flags & IPSET_INV_MATCH); 243a51b9199SJozsef Kadlecsik 244a51b9199SJozsef Kadlecsik if (!(ret && opt.cmdflags & IPSET_FLAG_MATCH_COUNTERS)) 245a51b9199SJozsef Kadlecsik return ret; 246a51b9199SJozsef Kadlecsik 247bd3129fcSJozsef Kadlecsik if (!match_counter(opt.ext.packets, &info->packets)) 2487f73b9f1SWu Fengguang return false; 249bd3129fcSJozsef Kadlecsik return match_counter(opt.ext.bytes, &info->bytes); 250bd3129fcSJozsef Kadlecsik } 251bd3129fcSJozsef Kadlecsik 252a51b9199SJozsef Kadlecsik #define set_match_v4_checkentry set_match_v1_checkentry 253a51b9199SJozsef Kadlecsik #define set_match_v4_destroy set_match_v1_destroy 254bd3129fcSJozsef Kadlecsik 255bd3129fcSJozsef Kadlecsik /* Revision 0 interface: backward compatible with netfilter/iptables */ 256bd3129fcSJozsef Kadlecsik 257d956798dSJozsef Kadlecsik static unsigned int 258d956798dSJozsef Kadlecsik set_target_v0(struct sk_buff *skb, const struct xt_action_param *par) 259d956798dSJozsef Kadlecsik { 260d956798dSJozsef Kadlecsik const struct xt_set_info_target_v0 *info = par->targinfo; 261ca0f6a5cSJozsef Kadlecsik 262ac8cc925SJozsef Kadlecsik ADT_OPT(add_opt, par->family, info->add_set.u.compat.dim, 263ac8cc925SJozsef Kadlecsik info->add_set.u.compat.flags, 0, UINT_MAX); 264ac8cc925SJozsef Kadlecsik ADT_OPT(del_opt, par->family, info->del_set.u.compat.dim, 265ac8cc925SJozsef Kadlecsik info->del_set.u.compat.flags, 0, UINT_MAX); 266d956798dSJozsef Kadlecsik 267d956798dSJozsef Kadlecsik if (info->add_set.index != IPSET_INVALID_ID) 268b66554cfSJozsef Kadlecsik ip_set_add(info->add_set.index, skb, par, &add_opt); 269d956798dSJozsef Kadlecsik if (info->del_set.index != IPSET_INVALID_ID) 270b66554cfSJozsef Kadlecsik ip_set_del(info->del_set.index, skb, par, &del_opt); 271d956798dSJozsef Kadlecsik 272d956798dSJozsef Kadlecsik return XT_CONTINUE; 273d956798dSJozsef Kadlecsik } 274d956798dSJozsef Kadlecsik 275d956798dSJozsef Kadlecsik static int 276d956798dSJozsef Kadlecsik set_target_v0_checkentry(const struct xt_tgchk_param *par) 277d956798dSJozsef Kadlecsik { 278d956798dSJozsef Kadlecsik struct xt_set_info_target_v0 *info = par->targinfo; 279d956798dSJozsef Kadlecsik ip_set_id_t index; 280d956798dSJozsef Kadlecsik 281d956798dSJozsef Kadlecsik if (info->add_set.index != IPSET_INVALID_ID) { 2821785e8f4SVitaly Lavrov index = ip_set_nfnl_get_byindex(par->net, info->add_set.index); 283d956798dSJozsef Kadlecsik if (index == IPSET_INVALID_ID) { 284b167a37cSJoe Perches pr_warn("Cannot find add_set index %u as target\n", 285d956798dSJozsef Kadlecsik info->add_set.index); 286d956798dSJozsef Kadlecsik return -ENOENT; 287d956798dSJozsef Kadlecsik } 288d956798dSJozsef Kadlecsik } 289d956798dSJozsef Kadlecsik 290d956798dSJozsef Kadlecsik if (info->del_set.index != IPSET_INVALID_ID) { 2911785e8f4SVitaly Lavrov index = ip_set_nfnl_get_byindex(par->net, info->del_set.index); 292d956798dSJozsef Kadlecsik if (index == IPSET_INVALID_ID) { 293b167a37cSJoe Perches pr_warn("Cannot find del_set index %u as target\n", 294d956798dSJozsef Kadlecsik info->del_set.index); 295eafbd3fdSJozsef Kadlecsik if (info->add_set.index != IPSET_INVALID_ID) 2961785e8f4SVitaly Lavrov ip_set_nfnl_put(par->net, info->add_set.index); 297d956798dSJozsef Kadlecsik return -ENOENT; 298d956798dSJozsef Kadlecsik } 299d956798dSJozsef Kadlecsik } 300d956798dSJozsef Kadlecsik if (info->add_set.u.flags[IPSET_DIM_MAX - 1] != 0 || 301d956798dSJozsef Kadlecsik info->del_set.u.flags[IPSET_DIM_MAX - 1] != 0) { 302b167a37cSJoe Perches pr_warn("Protocol error: SET target dimension is over the limit!\n"); 303eafbd3fdSJozsef Kadlecsik if (info->add_set.index != IPSET_INVALID_ID) 3041785e8f4SVitaly Lavrov ip_set_nfnl_put(par->net, info->add_set.index); 305eafbd3fdSJozsef Kadlecsik if (info->del_set.index != IPSET_INVALID_ID) 3061785e8f4SVitaly Lavrov ip_set_nfnl_put(par->net, info->del_set.index); 307d956798dSJozsef Kadlecsik return -ERANGE; 308d956798dSJozsef Kadlecsik } 309d956798dSJozsef Kadlecsik 310d956798dSJozsef Kadlecsik /* Fill out compatibility data */ 311d956798dSJozsef Kadlecsik compat_flags(&info->add_set); 312d956798dSJozsef Kadlecsik compat_flags(&info->del_set); 313d956798dSJozsef Kadlecsik 314d956798dSJozsef Kadlecsik return 0; 315d956798dSJozsef Kadlecsik } 316d956798dSJozsef Kadlecsik 317d956798dSJozsef Kadlecsik static void 318d956798dSJozsef Kadlecsik set_target_v0_destroy(const struct xt_tgdtor_param *par) 319d956798dSJozsef Kadlecsik { 320d956798dSJozsef Kadlecsik const struct xt_set_info_target_v0 *info = par->targinfo; 321d956798dSJozsef Kadlecsik 322d956798dSJozsef Kadlecsik if (info->add_set.index != IPSET_INVALID_ID) 3231785e8f4SVitaly Lavrov ip_set_nfnl_put(par->net, info->add_set.index); 324d956798dSJozsef Kadlecsik if (info->del_set.index != IPSET_INVALID_ID) 3251785e8f4SVitaly Lavrov ip_set_nfnl_put(par->net, info->del_set.index); 326d956798dSJozsef Kadlecsik } 327d956798dSJozsef Kadlecsik 328bd3129fcSJozsef Kadlecsik /* Revision 1 target */ 329d956798dSJozsef Kadlecsik 330d956798dSJozsef Kadlecsik static unsigned int 331ac8cc925SJozsef Kadlecsik set_target_v1(struct sk_buff *skb, const struct xt_action_param *par) 332d956798dSJozsef Kadlecsik { 333ac8cc925SJozsef Kadlecsik const struct xt_set_info_target_v1 *info = par->targinfo; 334ca0f6a5cSJozsef Kadlecsik 335ac8cc925SJozsef Kadlecsik ADT_OPT(add_opt, par->family, info->add_set.dim, 336ac8cc925SJozsef Kadlecsik info->add_set.flags, 0, UINT_MAX); 337ac8cc925SJozsef Kadlecsik ADT_OPT(del_opt, par->family, info->del_set.dim, 338ac8cc925SJozsef Kadlecsik info->del_set.flags, 0, UINT_MAX); 339d956798dSJozsef Kadlecsik 340d956798dSJozsef Kadlecsik if (info->add_set.index != IPSET_INVALID_ID) 341b66554cfSJozsef Kadlecsik ip_set_add(info->add_set.index, skb, par, &add_opt); 342d956798dSJozsef Kadlecsik if (info->del_set.index != IPSET_INVALID_ID) 343b66554cfSJozsef Kadlecsik ip_set_del(info->del_set.index, skb, par, &del_opt); 344d956798dSJozsef Kadlecsik 345d956798dSJozsef Kadlecsik return XT_CONTINUE; 346d956798dSJozsef Kadlecsik } 347d956798dSJozsef Kadlecsik 348d956798dSJozsef Kadlecsik static int 349ac8cc925SJozsef Kadlecsik set_target_v1_checkentry(const struct xt_tgchk_param *par) 350d956798dSJozsef Kadlecsik { 351ac8cc925SJozsef Kadlecsik const struct xt_set_info_target_v1 *info = par->targinfo; 352d956798dSJozsef Kadlecsik ip_set_id_t index; 353d956798dSJozsef Kadlecsik 354d956798dSJozsef Kadlecsik if (info->add_set.index != IPSET_INVALID_ID) { 3551785e8f4SVitaly Lavrov index = ip_set_nfnl_get_byindex(par->net, info->add_set.index); 356d956798dSJozsef Kadlecsik if (index == IPSET_INVALID_ID) { 357b167a37cSJoe Perches pr_warn("Cannot find add_set index %u as target\n", 358d956798dSJozsef Kadlecsik info->add_set.index); 359d956798dSJozsef Kadlecsik return -ENOENT; 360d956798dSJozsef Kadlecsik } 361d956798dSJozsef Kadlecsik } 362d956798dSJozsef Kadlecsik 363d956798dSJozsef Kadlecsik if (info->del_set.index != IPSET_INVALID_ID) { 3641785e8f4SVitaly Lavrov index = ip_set_nfnl_get_byindex(par->net, info->del_set.index); 365d956798dSJozsef Kadlecsik if (index == IPSET_INVALID_ID) { 366b167a37cSJoe Perches pr_warn("Cannot find del_set index %u as target\n", 367d956798dSJozsef Kadlecsik info->del_set.index); 368eafbd3fdSJozsef Kadlecsik if (info->add_set.index != IPSET_INVALID_ID) 3691785e8f4SVitaly Lavrov ip_set_nfnl_put(par->net, info->add_set.index); 370d956798dSJozsef Kadlecsik return -ENOENT; 371d956798dSJozsef Kadlecsik } 372d956798dSJozsef Kadlecsik } 373d956798dSJozsef Kadlecsik if (info->add_set.dim > IPSET_DIM_MAX || 374eafbd3fdSJozsef Kadlecsik info->del_set.dim > IPSET_DIM_MAX) { 375b167a37cSJoe Perches pr_warn("Protocol error: SET target dimension is over the limit!\n"); 376eafbd3fdSJozsef Kadlecsik if (info->add_set.index != IPSET_INVALID_ID) 3771785e8f4SVitaly Lavrov ip_set_nfnl_put(par->net, info->add_set.index); 378eafbd3fdSJozsef Kadlecsik if (info->del_set.index != IPSET_INVALID_ID) 3791785e8f4SVitaly Lavrov ip_set_nfnl_put(par->net, info->del_set.index); 380d956798dSJozsef Kadlecsik return -ERANGE; 381d956798dSJozsef Kadlecsik } 382d956798dSJozsef Kadlecsik 383d956798dSJozsef Kadlecsik return 0; 384d956798dSJozsef Kadlecsik } 385d956798dSJozsef Kadlecsik 386d956798dSJozsef Kadlecsik static void 387ac8cc925SJozsef Kadlecsik set_target_v1_destroy(const struct xt_tgdtor_param *par) 388d956798dSJozsef Kadlecsik { 389ac8cc925SJozsef Kadlecsik const struct xt_set_info_target_v1 *info = par->targinfo; 390d956798dSJozsef Kadlecsik 391d956798dSJozsef Kadlecsik if (info->add_set.index != IPSET_INVALID_ID) 3921785e8f4SVitaly Lavrov ip_set_nfnl_put(par->net, info->add_set.index); 393d956798dSJozsef Kadlecsik if (info->del_set.index != IPSET_INVALID_ID) 3941785e8f4SVitaly Lavrov ip_set_nfnl_put(par->net, info->del_set.index); 395d956798dSJozsef Kadlecsik } 396d956798dSJozsef Kadlecsik 397ac8cc925SJozsef Kadlecsik /* Revision 2 target */ 398ac8cc925SJozsef Kadlecsik 399ac8cc925SJozsef Kadlecsik static unsigned int 400ac8cc925SJozsef Kadlecsik set_target_v2(struct sk_buff *skb, const struct xt_action_param *par) 401ac8cc925SJozsef Kadlecsik { 402ac8cc925SJozsef Kadlecsik const struct xt_set_info_target_v2 *info = par->targinfo; 403ca0f6a5cSJozsef Kadlecsik 404075e64c0SJozsef Kadlecsik ADT_OPT(add_opt, par->family, info->add_set.dim, 405ac8cc925SJozsef Kadlecsik info->add_set.flags, info->flags, info->timeout); 406ac8cc925SJozsef Kadlecsik ADT_OPT(del_opt, par->family, info->del_set.dim, 407ac8cc925SJozsef Kadlecsik info->del_set.flags, 0, UINT_MAX); 408ac8cc925SJozsef Kadlecsik 409127f5591SJozsef Kadlecsik /* Normalize to fit into jiffies */ 410075e64c0SJozsef Kadlecsik if (add_opt.ext.timeout != IPSET_NO_TIMEOUT && 411075e64c0SJozsef Kadlecsik add_opt.ext.timeout > UINT_MAX / MSEC_PER_SEC) 412075e64c0SJozsef Kadlecsik add_opt.ext.timeout = UINT_MAX / MSEC_PER_SEC; 413ac8cc925SJozsef Kadlecsik if (info->add_set.index != IPSET_INVALID_ID) 414b66554cfSJozsef Kadlecsik ip_set_add(info->add_set.index, skb, par, &add_opt); 415ac8cc925SJozsef Kadlecsik if (info->del_set.index != IPSET_INVALID_ID) 416b66554cfSJozsef Kadlecsik ip_set_del(info->del_set.index, skb, par, &del_opt); 417ac8cc925SJozsef Kadlecsik 418ac8cc925SJozsef Kadlecsik return XT_CONTINUE; 419ac8cc925SJozsef Kadlecsik } 420ac8cc925SJozsef Kadlecsik 421ac8cc925SJozsef Kadlecsik #define set_target_v2_checkentry set_target_v1_checkentry 422ac8cc925SJozsef Kadlecsik #define set_target_v2_destroy set_target_v1_destroy 423ac8cc925SJozsef Kadlecsik 42476cea410SAnton Danilov /* Revision 3 target */ 42576cea410SAnton Danilov 42676cea410SAnton Danilov static unsigned int 42776cea410SAnton Danilov set_target_v3(struct sk_buff *skb, const struct xt_action_param *par) 42876cea410SAnton Danilov { 42976cea410SAnton Danilov const struct xt_set_info_target_v3 *info = par->targinfo; 430ca0f6a5cSJozsef Kadlecsik int ret; 431ca0f6a5cSJozsef Kadlecsik 43276cea410SAnton Danilov ADT_OPT(add_opt, par->family, info->add_set.dim, 43376cea410SAnton Danilov info->add_set.flags, info->flags, info->timeout); 43476cea410SAnton Danilov ADT_OPT(del_opt, par->family, info->del_set.dim, 43576cea410SAnton Danilov info->del_set.flags, 0, UINT_MAX); 43676cea410SAnton Danilov ADT_OPT(map_opt, par->family, info->map_set.dim, 43776cea410SAnton Danilov info->map_set.flags, 0, UINT_MAX); 43876cea410SAnton Danilov 43976cea410SAnton Danilov /* Normalize to fit into jiffies */ 44076cea410SAnton Danilov if (add_opt.ext.timeout != IPSET_NO_TIMEOUT && 44176cea410SAnton Danilov add_opt.ext.timeout > UINT_MAX / MSEC_PER_SEC) 44276cea410SAnton Danilov add_opt.ext.timeout = UINT_MAX / MSEC_PER_SEC; 44376cea410SAnton Danilov if (info->add_set.index != IPSET_INVALID_ID) 44476cea410SAnton Danilov ip_set_add(info->add_set.index, skb, par, &add_opt); 44576cea410SAnton Danilov if (info->del_set.index != IPSET_INVALID_ID) 44676cea410SAnton Danilov ip_set_del(info->del_set.index, skb, par, &del_opt); 44776cea410SAnton Danilov if (info->map_set.index != IPSET_INVALID_ID) { 44876cea410SAnton Danilov map_opt.cmdflags |= info->flags & (IPSET_FLAG_MAP_SKBMARK | 44976cea410SAnton Danilov IPSET_FLAG_MAP_SKBPRIO | 45076cea410SAnton Danilov IPSET_FLAG_MAP_SKBQUEUE); 45176cea410SAnton Danilov ret = match_set(info->map_set.index, skb, par, &map_opt, 45276cea410SAnton Danilov info->map_set.flags & IPSET_INV_MATCH); 45376cea410SAnton Danilov if (!ret) 45476cea410SAnton Danilov return XT_CONTINUE; 45576cea410SAnton Danilov if (map_opt.cmdflags & IPSET_FLAG_MAP_SKBMARK) 45676cea410SAnton Danilov skb->mark = (skb->mark & ~(map_opt.ext.skbmarkmask)) 45776cea410SAnton Danilov ^ (map_opt.ext.skbmark); 45876cea410SAnton Danilov if (map_opt.cmdflags & IPSET_FLAG_MAP_SKBPRIO) 45976cea410SAnton Danilov skb->priority = map_opt.ext.skbprio; 46076cea410SAnton Danilov if ((map_opt.cmdflags & IPSET_FLAG_MAP_SKBQUEUE) && 46176cea410SAnton Danilov skb->dev && 46276cea410SAnton Danilov skb->dev->real_num_tx_queues > map_opt.ext.skbqueue) 46376cea410SAnton Danilov skb_set_queue_mapping(skb, map_opt.ext.skbqueue); 46476cea410SAnton Danilov } 46576cea410SAnton Danilov return XT_CONTINUE; 46676cea410SAnton Danilov } 46776cea410SAnton Danilov 46876cea410SAnton Danilov static int 46976cea410SAnton Danilov set_target_v3_checkentry(const struct xt_tgchk_param *par) 47076cea410SAnton Danilov { 47176cea410SAnton Danilov const struct xt_set_info_target_v3 *info = par->targinfo; 47276cea410SAnton Danilov ip_set_id_t index; 47376cea410SAnton Danilov 47476cea410SAnton Danilov if (info->add_set.index != IPSET_INVALID_ID) { 47576cea410SAnton Danilov index = ip_set_nfnl_get_byindex(par->net, 47676cea410SAnton Danilov info->add_set.index); 47776cea410SAnton Danilov if (index == IPSET_INVALID_ID) { 47876cea410SAnton Danilov pr_warn("Cannot find add_set index %u as target\n", 47976cea410SAnton Danilov info->add_set.index); 48076cea410SAnton Danilov return -ENOENT; 48176cea410SAnton Danilov } 48276cea410SAnton Danilov } 48376cea410SAnton Danilov 48476cea410SAnton Danilov if (info->del_set.index != IPSET_INVALID_ID) { 48576cea410SAnton Danilov index = ip_set_nfnl_get_byindex(par->net, 48676cea410SAnton Danilov info->del_set.index); 48776cea410SAnton Danilov if (index == IPSET_INVALID_ID) { 48876cea410SAnton Danilov pr_warn("Cannot find del_set index %u as target\n", 48976cea410SAnton Danilov info->del_set.index); 49076cea410SAnton Danilov if (info->add_set.index != IPSET_INVALID_ID) 49176cea410SAnton Danilov ip_set_nfnl_put(par->net, 49276cea410SAnton Danilov info->add_set.index); 49376cea410SAnton Danilov return -ENOENT; 49476cea410SAnton Danilov } 49576cea410SAnton Danilov } 49676cea410SAnton Danilov 49776cea410SAnton Danilov if (info->map_set.index != IPSET_INVALID_ID) { 49876cea410SAnton Danilov if (strncmp(par->table, "mangle", 7)) { 49976cea410SAnton Danilov pr_warn("--map-set only usable from mangle table\n"); 50076cea410SAnton Danilov return -EINVAL; 50176cea410SAnton Danilov } 50276cea410SAnton Danilov if (((info->flags & IPSET_FLAG_MAP_SKBPRIO) | 50376cea410SAnton Danilov (info->flags & IPSET_FLAG_MAP_SKBQUEUE)) && 50476cea410SAnton Danilov !(par->hook_mask & (1 << NF_INET_FORWARD | 50576cea410SAnton Danilov 1 << NF_INET_LOCAL_OUT | 50676cea410SAnton Danilov 1 << NF_INET_POST_ROUTING))) { 507ca0f6a5cSJozsef Kadlecsik pr_warn("mapping of prio or/and queue is allowed only from OUTPUT/FORWARD/POSTROUTING chains\n"); 50876cea410SAnton Danilov return -EINVAL; 50976cea410SAnton Danilov } 51076cea410SAnton Danilov index = ip_set_nfnl_get_byindex(par->net, 51176cea410SAnton Danilov info->map_set.index); 51276cea410SAnton Danilov if (index == IPSET_INVALID_ID) { 51376cea410SAnton Danilov pr_warn("Cannot find map_set index %u as target\n", 51476cea410SAnton Danilov info->map_set.index); 51576cea410SAnton Danilov if (info->add_set.index != IPSET_INVALID_ID) 51676cea410SAnton Danilov ip_set_nfnl_put(par->net, 51776cea410SAnton Danilov info->add_set.index); 51876cea410SAnton Danilov if (info->del_set.index != IPSET_INVALID_ID) 51976cea410SAnton Danilov ip_set_nfnl_put(par->net, 52076cea410SAnton Danilov info->del_set.index); 52176cea410SAnton Danilov return -ENOENT; 52276cea410SAnton Danilov } 52376cea410SAnton Danilov } 52476cea410SAnton Danilov 52576cea410SAnton Danilov if (info->add_set.dim > IPSET_DIM_MAX || 52676cea410SAnton Danilov info->del_set.dim > IPSET_DIM_MAX || 52776cea410SAnton Danilov info->map_set.dim > IPSET_DIM_MAX) { 528ca0f6a5cSJozsef Kadlecsik pr_warn("Protocol error: SET target dimension is over the limit!\n"); 52976cea410SAnton Danilov if (info->add_set.index != IPSET_INVALID_ID) 53076cea410SAnton Danilov ip_set_nfnl_put(par->net, info->add_set.index); 53176cea410SAnton Danilov if (info->del_set.index != IPSET_INVALID_ID) 53276cea410SAnton Danilov ip_set_nfnl_put(par->net, info->del_set.index); 53376cea410SAnton Danilov if (info->map_set.index != IPSET_INVALID_ID) 53476cea410SAnton Danilov ip_set_nfnl_put(par->net, info->map_set.index); 53576cea410SAnton Danilov return -ERANGE; 53676cea410SAnton Danilov } 53776cea410SAnton Danilov 53876cea410SAnton Danilov return 0; 53976cea410SAnton Danilov } 54076cea410SAnton Danilov 54176cea410SAnton Danilov static void 54276cea410SAnton Danilov set_target_v3_destroy(const struct xt_tgdtor_param *par) 54376cea410SAnton Danilov { 54476cea410SAnton Danilov const struct xt_set_info_target_v3 *info = par->targinfo; 54576cea410SAnton Danilov 54676cea410SAnton Danilov if (info->add_set.index != IPSET_INVALID_ID) 54776cea410SAnton Danilov ip_set_nfnl_put(par->net, info->add_set.index); 54876cea410SAnton Danilov if (info->del_set.index != IPSET_INVALID_ID) 54976cea410SAnton Danilov ip_set_nfnl_put(par->net, info->del_set.index); 55076cea410SAnton Danilov if (info->map_set.index != IPSET_INVALID_ID) 55176cea410SAnton Danilov ip_set_nfnl_put(par->net, info->map_set.index); 55276cea410SAnton Danilov } 55376cea410SAnton Danilov 554d956798dSJozsef Kadlecsik static struct xt_match set_matches[] __read_mostly = { 555d956798dSJozsef Kadlecsik { 556d956798dSJozsef Kadlecsik .name = "set", 557d956798dSJozsef Kadlecsik .family = NFPROTO_IPV4, 558d956798dSJozsef Kadlecsik .revision = 0, 559d956798dSJozsef Kadlecsik .match = set_match_v0, 560d956798dSJozsef Kadlecsik .matchsize = sizeof(struct xt_set_info_match_v0), 561d956798dSJozsef Kadlecsik .checkentry = set_match_v0_checkentry, 562d956798dSJozsef Kadlecsik .destroy = set_match_v0_destroy, 563d956798dSJozsef Kadlecsik .me = THIS_MODULE 564d956798dSJozsef Kadlecsik }, 565d956798dSJozsef Kadlecsik { 566d956798dSJozsef Kadlecsik .name = "set", 567d956798dSJozsef Kadlecsik .family = NFPROTO_IPV4, 568d956798dSJozsef Kadlecsik .revision = 1, 569ac8cc925SJozsef Kadlecsik .match = set_match_v1, 570ac8cc925SJozsef Kadlecsik .matchsize = sizeof(struct xt_set_info_match_v1), 571ac8cc925SJozsef Kadlecsik .checkentry = set_match_v1_checkentry, 572ac8cc925SJozsef Kadlecsik .destroy = set_match_v1_destroy, 573d956798dSJozsef Kadlecsik .me = THIS_MODULE 574d956798dSJozsef Kadlecsik }, 575d956798dSJozsef Kadlecsik { 576d956798dSJozsef Kadlecsik .name = "set", 577d956798dSJozsef Kadlecsik .family = NFPROTO_IPV6, 578d956798dSJozsef Kadlecsik .revision = 1, 579ac8cc925SJozsef Kadlecsik .match = set_match_v1, 580ac8cc925SJozsef Kadlecsik .matchsize = sizeof(struct xt_set_info_match_v1), 581ac8cc925SJozsef Kadlecsik .checkentry = set_match_v1_checkentry, 582ac8cc925SJozsef Kadlecsik .destroy = set_match_v1_destroy, 583d956798dSJozsef Kadlecsik .me = THIS_MODULE 584d956798dSJozsef Kadlecsik }, 5853e0304a5SJozsef Kadlecsik /* --return-nomatch flag support */ 5863e0304a5SJozsef Kadlecsik { 5873e0304a5SJozsef Kadlecsik .name = "set", 5883e0304a5SJozsef Kadlecsik .family = NFPROTO_IPV4, 5893e0304a5SJozsef Kadlecsik .revision = 2, 5903e0304a5SJozsef Kadlecsik .match = set_match_v1, 5913e0304a5SJozsef Kadlecsik .matchsize = sizeof(struct xt_set_info_match_v1), 5923e0304a5SJozsef Kadlecsik .checkentry = set_match_v1_checkentry, 5933e0304a5SJozsef Kadlecsik .destroy = set_match_v1_destroy, 5943e0304a5SJozsef Kadlecsik .me = THIS_MODULE 5953e0304a5SJozsef Kadlecsik }, 5963e0304a5SJozsef Kadlecsik { 5973e0304a5SJozsef Kadlecsik .name = "set", 5983e0304a5SJozsef Kadlecsik .family = NFPROTO_IPV6, 5993e0304a5SJozsef Kadlecsik .revision = 2, 6003e0304a5SJozsef Kadlecsik .match = set_match_v1, 6013e0304a5SJozsef Kadlecsik .matchsize = sizeof(struct xt_set_info_match_v1), 6023e0304a5SJozsef Kadlecsik .checkentry = set_match_v1_checkentry, 6033e0304a5SJozsef Kadlecsik .destroy = set_match_v1_destroy, 6043e0304a5SJozsef Kadlecsik .me = THIS_MODULE 6053e0304a5SJozsef Kadlecsik }, 6066e01781dSJozsef Kadlecsik /* counters support: update, match */ 6076e01781dSJozsef Kadlecsik { 6086e01781dSJozsef Kadlecsik .name = "set", 6096e01781dSJozsef Kadlecsik .family = NFPROTO_IPV4, 6106e01781dSJozsef Kadlecsik .revision = 3, 6116e01781dSJozsef Kadlecsik .match = set_match_v3, 6126e01781dSJozsef Kadlecsik .matchsize = sizeof(struct xt_set_info_match_v3), 6136e01781dSJozsef Kadlecsik .checkentry = set_match_v3_checkentry, 6146e01781dSJozsef Kadlecsik .destroy = set_match_v3_destroy, 6156e01781dSJozsef Kadlecsik .me = THIS_MODULE 6166e01781dSJozsef Kadlecsik }, 6176e01781dSJozsef Kadlecsik { 6186e01781dSJozsef Kadlecsik .name = "set", 6196e01781dSJozsef Kadlecsik .family = NFPROTO_IPV6, 6206e01781dSJozsef Kadlecsik .revision = 3, 6216e01781dSJozsef Kadlecsik .match = set_match_v3, 6226e01781dSJozsef Kadlecsik .matchsize = sizeof(struct xt_set_info_match_v3), 6236e01781dSJozsef Kadlecsik .checkentry = set_match_v3_checkentry, 6246e01781dSJozsef Kadlecsik .destroy = set_match_v3_destroy, 6256e01781dSJozsef Kadlecsik .me = THIS_MODULE 6266e01781dSJozsef Kadlecsik }, 627a51b9199SJozsef Kadlecsik /* new revision for counters support: update, match */ 628a51b9199SJozsef Kadlecsik { 629a51b9199SJozsef Kadlecsik .name = "set", 630a51b9199SJozsef Kadlecsik .family = NFPROTO_IPV4, 631a51b9199SJozsef Kadlecsik .revision = 4, 632a51b9199SJozsef Kadlecsik .match = set_match_v4, 633a51b9199SJozsef Kadlecsik .matchsize = sizeof(struct xt_set_info_match_v4), 634a51b9199SJozsef Kadlecsik .checkentry = set_match_v4_checkentry, 635a51b9199SJozsef Kadlecsik .destroy = set_match_v4_destroy, 636a51b9199SJozsef Kadlecsik .me = THIS_MODULE 637a51b9199SJozsef Kadlecsik }, 638a51b9199SJozsef Kadlecsik { 639a51b9199SJozsef Kadlecsik .name = "set", 640a51b9199SJozsef Kadlecsik .family = NFPROTO_IPV6, 641a51b9199SJozsef Kadlecsik .revision = 4, 642a51b9199SJozsef Kadlecsik .match = set_match_v4, 643a51b9199SJozsef Kadlecsik .matchsize = sizeof(struct xt_set_info_match_v4), 644a51b9199SJozsef Kadlecsik .checkentry = set_match_v4_checkentry, 645a51b9199SJozsef Kadlecsik .destroy = set_match_v4_destroy, 646a51b9199SJozsef Kadlecsik .me = THIS_MODULE 647a51b9199SJozsef Kadlecsik }, 648d956798dSJozsef Kadlecsik }; 649d956798dSJozsef Kadlecsik 650d956798dSJozsef Kadlecsik static struct xt_target set_targets[] __read_mostly = { 651d956798dSJozsef Kadlecsik { 652d956798dSJozsef Kadlecsik .name = "SET", 653d956798dSJozsef Kadlecsik .revision = 0, 654d956798dSJozsef Kadlecsik .family = NFPROTO_IPV4, 655d956798dSJozsef Kadlecsik .target = set_target_v0, 656d956798dSJozsef Kadlecsik .targetsize = sizeof(struct xt_set_info_target_v0), 657d956798dSJozsef Kadlecsik .checkentry = set_target_v0_checkentry, 658d956798dSJozsef Kadlecsik .destroy = set_target_v0_destroy, 659d956798dSJozsef Kadlecsik .me = THIS_MODULE 660d956798dSJozsef Kadlecsik }, 661d956798dSJozsef Kadlecsik { 662d956798dSJozsef Kadlecsik .name = "SET", 663d956798dSJozsef Kadlecsik .revision = 1, 664d956798dSJozsef Kadlecsik .family = NFPROTO_IPV4, 665ac8cc925SJozsef Kadlecsik .target = set_target_v1, 666ac8cc925SJozsef Kadlecsik .targetsize = sizeof(struct xt_set_info_target_v1), 667ac8cc925SJozsef Kadlecsik .checkentry = set_target_v1_checkentry, 668ac8cc925SJozsef Kadlecsik .destroy = set_target_v1_destroy, 669d956798dSJozsef Kadlecsik .me = THIS_MODULE 670d956798dSJozsef Kadlecsik }, 671d956798dSJozsef Kadlecsik { 672d956798dSJozsef Kadlecsik .name = "SET", 673d956798dSJozsef Kadlecsik .revision = 1, 674d956798dSJozsef Kadlecsik .family = NFPROTO_IPV6, 675ac8cc925SJozsef Kadlecsik .target = set_target_v1, 676ac8cc925SJozsef Kadlecsik .targetsize = sizeof(struct xt_set_info_target_v1), 677ac8cc925SJozsef Kadlecsik .checkentry = set_target_v1_checkentry, 678ac8cc925SJozsef Kadlecsik .destroy = set_target_v1_destroy, 679ac8cc925SJozsef Kadlecsik .me = THIS_MODULE 680ac8cc925SJozsef Kadlecsik }, 6813e0304a5SJozsef Kadlecsik /* --timeout and --exist flags support */ 682ac8cc925SJozsef Kadlecsik { 683ac8cc925SJozsef Kadlecsik .name = "SET", 684ac8cc925SJozsef Kadlecsik .revision = 2, 685ac8cc925SJozsef Kadlecsik .family = NFPROTO_IPV4, 686ac8cc925SJozsef Kadlecsik .target = set_target_v2, 687ac8cc925SJozsef Kadlecsik .targetsize = sizeof(struct xt_set_info_target_v2), 688ac8cc925SJozsef Kadlecsik .checkentry = set_target_v2_checkentry, 689ac8cc925SJozsef Kadlecsik .destroy = set_target_v2_destroy, 690ac8cc925SJozsef Kadlecsik .me = THIS_MODULE 691ac8cc925SJozsef Kadlecsik }, 692ac8cc925SJozsef Kadlecsik { 693ac8cc925SJozsef Kadlecsik .name = "SET", 694ac8cc925SJozsef Kadlecsik .revision = 2, 695ac8cc925SJozsef Kadlecsik .family = NFPROTO_IPV6, 696ac8cc925SJozsef Kadlecsik .target = set_target_v2, 697ac8cc925SJozsef Kadlecsik .targetsize = sizeof(struct xt_set_info_target_v2), 698ac8cc925SJozsef Kadlecsik .checkentry = set_target_v2_checkentry, 699ac8cc925SJozsef Kadlecsik .destroy = set_target_v2_destroy, 700d956798dSJozsef Kadlecsik .me = THIS_MODULE 701d956798dSJozsef Kadlecsik }, 70276cea410SAnton Danilov /* --map-set support */ 70376cea410SAnton Danilov { 70476cea410SAnton Danilov .name = "SET", 70576cea410SAnton Danilov .revision = 3, 70676cea410SAnton Danilov .family = NFPROTO_IPV4, 70776cea410SAnton Danilov .target = set_target_v3, 70876cea410SAnton Danilov .targetsize = sizeof(struct xt_set_info_target_v3), 70976cea410SAnton Danilov .checkentry = set_target_v3_checkentry, 71076cea410SAnton Danilov .destroy = set_target_v3_destroy, 71176cea410SAnton Danilov .me = THIS_MODULE 71276cea410SAnton Danilov }, 71376cea410SAnton Danilov { 71476cea410SAnton Danilov .name = "SET", 71576cea410SAnton Danilov .revision = 3, 71676cea410SAnton Danilov .family = NFPROTO_IPV6, 71776cea410SAnton Danilov .target = set_target_v3, 71876cea410SAnton Danilov .targetsize = sizeof(struct xt_set_info_target_v3), 71976cea410SAnton Danilov .checkentry = set_target_v3_checkentry, 72076cea410SAnton Danilov .destroy = set_target_v3_destroy, 72176cea410SAnton Danilov .me = THIS_MODULE 72276cea410SAnton Danilov }, 723d956798dSJozsef Kadlecsik }; 724d956798dSJozsef Kadlecsik 725d956798dSJozsef Kadlecsik static int __init xt_set_init(void) 726d956798dSJozsef Kadlecsik { 727d956798dSJozsef Kadlecsik int ret = xt_register_matches(set_matches, ARRAY_SIZE(set_matches)); 728d956798dSJozsef Kadlecsik 729d956798dSJozsef Kadlecsik if (!ret) { 730d956798dSJozsef Kadlecsik ret = xt_register_targets(set_targets, 731d956798dSJozsef Kadlecsik ARRAY_SIZE(set_targets)); 732d956798dSJozsef Kadlecsik if (ret) 733d956798dSJozsef Kadlecsik xt_unregister_matches(set_matches, 734d956798dSJozsef Kadlecsik ARRAY_SIZE(set_matches)); 735d956798dSJozsef Kadlecsik } 736d956798dSJozsef Kadlecsik return ret; 737d956798dSJozsef Kadlecsik } 738d956798dSJozsef Kadlecsik 739d956798dSJozsef Kadlecsik static void __exit xt_set_fini(void) 740d956798dSJozsef Kadlecsik { 741d956798dSJozsef Kadlecsik xt_unregister_matches(set_matches, ARRAY_SIZE(set_matches)); 742d956798dSJozsef Kadlecsik xt_unregister_targets(set_targets, ARRAY_SIZE(set_targets)); 743d956798dSJozsef Kadlecsik } 744d956798dSJozsef Kadlecsik 745d956798dSJozsef Kadlecsik module_init(xt_set_init); 746d956798dSJozsef Kadlecsik module_exit(xt_set_fini); 747