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 12d956798dSJozsef Kadlecsik * for netfilter/iptables. */ 13d956798dSJozsef Kadlecsik 14d956798dSJozsef Kadlecsik #include <linux/module.h> 15d956798dSJozsef Kadlecsik #include <linux/skbuff.h> 16d956798dSJozsef Kadlecsik 17d956798dSJozsef Kadlecsik #include <linux/netfilter/x_tables.h> 18d956798dSJozsef Kadlecsik #include <linux/netfilter/xt_set.h> 19a73f89a6SJozsef Kadlecsik #include <linux/netfilter/ipset/ip_set_timeout.h> 20d956798dSJozsef Kadlecsik 21d956798dSJozsef Kadlecsik MODULE_LICENSE("GPL"); 22d956798dSJozsef Kadlecsik MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); 23d956798dSJozsef Kadlecsik MODULE_DESCRIPTION("Xtables: IP set match and target module"); 24d956798dSJozsef Kadlecsik MODULE_ALIAS("xt_SET"); 25d956798dSJozsef Kadlecsik MODULE_ALIAS("ipt_set"); 26d956798dSJozsef Kadlecsik MODULE_ALIAS("ip6t_set"); 27d956798dSJozsef Kadlecsik MODULE_ALIAS("ipt_SET"); 28d956798dSJozsef Kadlecsik MODULE_ALIAS("ip6t_SET"); 29d956798dSJozsef Kadlecsik 30d956798dSJozsef Kadlecsik static inline int 31d956798dSJozsef Kadlecsik match_set(ip_set_id_t index, const struct sk_buff *skb, 32b66554cfSJozsef Kadlecsik const struct xt_action_param *par, 33075e64c0SJozsef Kadlecsik struct ip_set_adt_opt *opt, int inv) 34d956798dSJozsef Kadlecsik { 35b66554cfSJozsef Kadlecsik if (ip_set_test(index, skb, par, opt)) 36d956798dSJozsef Kadlecsik inv = !inv; 37d956798dSJozsef Kadlecsik return inv; 38d956798dSJozsef Kadlecsik } 39d956798dSJozsef Kadlecsik 40ac8cc925SJozsef Kadlecsik #define ADT_OPT(n, f, d, fs, cfs, t) \ 41127f5591SJozsef Kadlecsik struct ip_set_adt_opt n = { \ 42127f5591SJozsef Kadlecsik .family = f, \ 43127f5591SJozsef Kadlecsik .dim = d, \ 44127f5591SJozsef Kadlecsik .flags = fs, \ 45127f5591SJozsef Kadlecsik .cmdflags = cfs, \ 46075e64c0SJozsef Kadlecsik .ext.timeout = t, \ 47127f5591SJozsef Kadlecsik } 48ac8cc925SJozsef Kadlecsik 49d956798dSJozsef Kadlecsik /* Revision 0 interface: backward compatible with netfilter/iptables */ 50d956798dSJozsef Kadlecsik 51d956798dSJozsef Kadlecsik static bool 52d956798dSJozsef Kadlecsik set_match_v0(const struct sk_buff *skb, struct xt_action_param *par) 53d956798dSJozsef Kadlecsik { 54d956798dSJozsef Kadlecsik const struct xt_set_info_match_v0 *info = par->matchinfo; 55ac8cc925SJozsef Kadlecsik ADT_OPT(opt, par->family, info->match_set.u.compat.dim, 56ac8cc925SJozsef Kadlecsik info->match_set.u.compat.flags, 0, UINT_MAX); 57d956798dSJozsef Kadlecsik 58b66554cfSJozsef Kadlecsik return match_set(info->match_set.index, skb, par, &opt, 59d956798dSJozsef Kadlecsik info->match_set.u.compat.flags & IPSET_INV_MATCH); 60d956798dSJozsef Kadlecsik } 61d956798dSJozsef Kadlecsik 62d956798dSJozsef Kadlecsik static void 63d956798dSJozsef Kadlecsik compat_flags(struct xt_set_info_v0 *info) 64d956798dSJozsef Kadlecsik { 65d956798dSJozsef Kadlecsik u_int8_t i; 66d956798dSJozsef Kadlecsik 67d956798dSJozsef Kadlecsik /* Fill out compatibility data according to enum ip_set_kopt */ 68d956798dSJozsef Kadlecsik info->u.compat.dim = IPSET_DIM_ZERO; 69d956798dSJozsef Kadlecsik if (info->u.flags[0] & IPSET_MATCH_INV) 70d956798dSJozsef Kadlecsik info->u.compat.flags |= IPSET_INV_MATCH; 71d956798dSJozsef Kadlecsik for (i = 0; i < IPSET_DIM_MAX-1 && info->u.flags[i]; i++) { 72d956798dSJozsef Kadlecsik info->u.compat.dim++; 73d956798dSJozsef Kadlecsik if (info->u.flags[i] & IPSET_SRC) 74d956798dSJozsef Kadlecsik info->u.compat.flags |= (1<<info->u.compat.dim); 75d956798dSJozsef Kadlecsik } 76d956798dSJozsef Kadlecsik } 77d956798dSJozsef Kadlecsik 78d956798dSJozsef Kadlecsik static int 79d956798dSJozsef Kadlecsik set_match_v0_checkentry(const struct xt_mtchk_param *par) 80d956798dSJozsef Kadlecsik { 81d956798dSJozsef Kadlecsik struct xt_set_info_match_v0 *info = par->matchinfo; 82d956798dSJozsef Kadlecsik ip_set_id_t index; 83d956798dSJozsef Kadlecsik 84d956798dSJozsef Kadlecsik index = ip_set_nfnl_get_byindex(info->match_set.index); 85d956798dSJozsef Kadlecsik 86d956798dSJozsef Kadlecsik if (index == IPSET_INVALID_ID) { 87d956798dSJozsef Kadlecsik pr_warning("Cannot find set indentified by id %u to match\n", 88d956798dSJozsef Kadlecsik info->match_set.index); 89d956798dSJozsef Kadlecsik return -ENOENT; 90d956798dSJozsef Kadlecsik } 91d956798dSJozsef Kadlecsik if (info->match_set.u.flags[IPSET_DIM_MAX-1] != 0) { 92d956798dSJozsef Kadlecsik pr_warning("Protocol error: set match dimension " 93d956798dSJozsef Kadlecsik "is over the limit!\n"); 94eafbd3fdSJozsef Kadlecsik ip_set_nfnl_put(info->match_set.index); 95d956798dSJozsef Kadlecsik return -ERANGE; 96d956798dSJozsef Kadlecsik } 97d956798dSJozsef Kadlecsik 98d956798dSJozsef Kadlecsik /* Fill out compatibility data */ 99d956798dSJozsef Kadlecsik compat_flags(&info->match_set); 100d956798dSJozsef Kadlecsik 101d956798dSJozsef Kadlecsik return 0; 102d956798dSJozsef Kadlecsik } 103d956798dSJozsef Kadlecsik 104d956798dSJozsef Kadlecsik static void 105d956798dSJozsef Kadlecsik set_match_v0_destroy(const struct xt_mtdtor_param *par) 106d956798dSJozsef Kadlecsik { 107d956798dSJozsef Kadlecsik struct xt_set_info_match_v0 *info = par->matchinfo; 108d956798dSJozsef Kadlecsik 109d956798dSJozsef Kadlecsik ip_set_nfnl_put(info->match_set.index); 110d956798dSJozsef Kadlecsik } 111d956798dSJozsef Kadlecsik 112bd3129fcSJozsef Kadlecsik /* Revision 1 match */ 113bd3129fcSJozsef Kadlecsik 114bd3129fcSJozsef Kadlecsik static bool 115bd3129fcSJozsef Kadlecsik set_match_v1(const struct sk_buff *skb, struct xt_action_param *par) 116bd3129fcSJozsef Kadlecsik { 117bd3129fcSJozsef Kadlecsik const struct xt_set_info_match_v1 *info = par->matchinfo; 118bd3129fcSJozsef Kadlecsik ADT_OPT(opt, par->family, info->match_set.dim, 119bd3129fcSJozsef Kadlecsik info->match_set.flags, 0, UINT_MAX); 120bd3129fcSJozsef Kadlecsik 121bd3129fcSJozsef Kadlecsik if (opt.flags & IPSET_RETURN_NOMATCH) 122bd3129fcSJozsef Kadlecsik opt.cmdflags |= IPSET_FLAG_RETURN_NOMATCH; 123bd3129fcSJozsef Kadlecsik 124bd3129fcSJozsef Kadlecsik return match_set(info->match_set.index, skb, par, &opt, 125bd3129fcSJozsef Kadlecsik info->match_set.flags & IPSET_INV_MATCH); 126bd3129fcSJozsef Kadlecsik } 127bd3129fcSJozsef Kadlecsik 128bd3129fcSJozsef Kadlecsik static int 129bd3129fcSJozsef Kadlecsik set_match_v1_checkentry(const struct xt_mtchk_param *par) 130bd3129fcSJozsef Kadlecsik { 131bd3129fcSJozsef Kadlecsik struct xt_set_info_match_v1 *info = par->matchinfo; 132bd3129fcSJozsef Kadlecsik ip_set_id_t index; 133bd3129fcSJozsef Kadlecsik 134bd3129fcSJozsef Kadlecsik index = ip_set_nfnl_get_byindex(info->match_set.index); 135bd3129fcSJozsef Kadlecsik 136bd3129fcSJozsef Kadlecsik if (index == IPSET_INVALID_ID) { 137bd3129fcSJozsef Kadlecsik pr_warning("Cannot find set indentified by id %u to match\n", 138bd3129fcSJozsef Kadlecsik info->match_set.index); 139bd3129fcSJozsef Kadlecsik return -ENOENT; 140bd3129fcSJozsef Kadlecsik } 141bd3129fcSJozsef Kadlecsik if (info->match_set.dim > IPSET_DIM_MAX) { 142bd3129fcSJozsef Kadlecsik pr_warning("Protocol error: set match dimension " 143bd3129fcSJozsef Kadlecsik "is over the limit!\n"); 144bd3129fcSJozsef Kadlecsik ip_set_nfnl_put(info->match_set.index); 145bd3129fcSJozsef Kadlecsik return -ERANGE; 146bd3129fcSJozsef Kadlecsik } 147bd3129fcSJozsef Kadlecsik 148bd3129fcSJozsef Kadlecsik return 0; 149bd3129fcSJozsef Kadlecsik } 150bd3129fcSJozsef Kadlecsik 151bd3129fcSJozsef Kadlecsik static void 152bd3129fcSJozsef Kadlecsik set_match_v1_destroy(const struct xt_mtdtor_param *par) 153bd3129fcSJozsef Kadlecsik { 154bd3129fcSJozsef Kadlecsik struct xt_set_info_match_v1 *info = par->matchinfo; 155bd3129fcSJozsef Kadlecsik 156bd3129fcSJozsef Kadlecsik ip_set_nfnl_put(info->match_set.index); 157bd3129fcSJozsef Kadlecsik } 158bd3129fcSJozsef Kadlecsik 159bd3129fcSJozsef Kadlecsik /* Revision 3 match */ 160bd3129fcSJozsef Kadlecsik 161bd3129fcSJozsef Kadlecsik static bool 162bd3129fcSJozsef Kadlecsik match_counter(u64 counter, const struct ip_set_counter_match *info) 163bd3129fcSJozsef Kadlecsik { 164bd3129fcSJozsef Kadlecsik switch (info->op) { 165bd3129fcSJozsef Kadlecsik case IPSET_COUNTER_NONE: 166bd3129fcSJozsef Kadlecsik return true; 167bd3129fcSJozsef Kadlecsik case IPSET_COUNTER_EQ: 168bd3129fcSJozsef Kadlecsik return counter == info->value; 169bd3129fcSJozsef Kadlecsik case IPSET_COUNTER_NE: 170bd3129fcSJozsef Kadlecsik return counter != info->value; 171bd3129fcSJozsef Kadlecsik case IPSET_COUNTER_LT: 172bd3129fcSJozsef Kadlecsik return counter < info->value; 173bd3129fcSJozsef Kadlecsik case IPSET_COUNTER_GT: 174bd3129fcSJozsef Kadlecsik return counter > info->value; 175bd3129fcSJozsef Kadlecsik } 176bd3129fcSJozsef Kadlecsik return false; 177bd3129fcSJozsef Kadlecsik } 178bd3129fcSJozsef Kadlecsik 179bd3129fcSJozsef Kadlecsik static bool 180bd3129fcSJozsef Kadlecsik set_match_v3(const struct sk_buff *skb, struct xt_action_param *par) 181bd3129fcSJozsef Kadlecsik { 182bd3129fcSJozsef Kadlecsik const struct xt_set_info_match_v3 *info = par->matchinfo; 183bd3129fcSJozsef Kadlecsik ADT_OPT(opt, par->family, info->match_set.dim, 184bd3129fcSJozsef Kadlecsik info->match_set.flags, info->flags, UINT_MAX); 185bd3129fcSJozsef Kadlecsik int ret; 186bd3129fcSJozsef Kadlecsik 187bd3129fcSJozsef Kadlecsik if (info->packets.op != IPSET_COUNTER_NONE || 188bd3129fcSJozsef Kadlecsik info->bytes.op != IPSET_COUNTER_NONE) 189bd3129fcSJozsef Kadlecsik opt.cmdflags |= IPSET_FLAG_MATCH_COUNTERS; 190bd3129fcSJozsef Kadlecsik 191bd3129fcSJozsef Kadlecsik ret = match_set(info->match_set.index, skb, par, &opt, 192bd3129fcSJozsef Kadlecsik info->match_set.flags & IPSET_INV_MATCH); 193bd3129fcSJozsef Kadlecsik 194bd3129fcSJozsef Kadlecsik if (!(ret && opt.cmdflags & IPSET_FLAG_MATCH_COUNTERS)) 195bd3129fcSJozsef Kadlecsik return ret; 196bd3129fcSJozsef Kadlecsik 197bd3129fcSJozsef Kadlecsik if (!match_counter(opt.ext.packets, &info->packets)) 198bd3129fcSJozsef Kadlecsik return 0; 199bd3129fcSJozsef Kadlecsik return match_counter(opt.ext.bytes, &info->bytes); 200bd3129fcSJozsef Kadlecsik } 201bd3129fcSJozsef Kadlecsik 202bd3129fcSJozsef Kadlecsik #define set_match_v3_checkentry set_match_v1_checkentry 203bd3129fcSJozsef Kadlecsik #define set_match_v3_destroy set_match_v1_destroy 204bd3129fcSJozsef Kadlecsik 205bd3129fcSJozsef Kadlecsik /* Revision 0 interface: backward compatible with netfilter/iptables */ 206bd3129fcSJozsef Kadlecsik 207d956798dSJozsef Kadlecsik static unsigned int 208d956798dSJozsef Kadlecsik set_target_v0(struct sk_buff *skb, const struct xt_action_param *par) 209d956798dSJozsef Kadlecsik { 210d956798dSJozsef Kadlecsik const struct xt_set_info_target_v0 *info = par->targinfo; 211ac8cc925SJozsef Kadlecsik ADT_OPT(add_opt, par->family, info->add_set.u.compat.dim, 212ac8cc925SJozsef Kadlecsik info->add_set.u.compat.flags, 0, UINT_MAX); 213ac8cc925SJozsef Kadlecsik ADT_OPT(del_opt, par->family, info->del_set.u.compat.dim, 214ac8cc925SJozsef Kadlecsik info->del_set.u.compat.flags, 0, UINT_MAX); 215d956798dSJozsef Kadlecsik 216d956798dSJozsef Kadlecsik if (info->add_set.index != IPSET_INVALID_ID) 217b66554cfSJozsef Kadlecsik ip_set_add(info->add_set.index, skb, par, &add_opt); 218d956798dSJozsef Kadlecsik if (info->del_set.index != IPSET_INVALID_ID) 219b66554cfSJozsef Kadlecsik ip_set_del(info->del_set.index, skb, par, &del_opt); 220d956798dSJozsef Kadlecsik 221d956798dSJozsef Kadlecsik return XT_CONTINUE; 222d956798dSJozsef Kadlecsik } 223d956798dSJozsef Kadlecsik 224d956798dSJozsef Kadlecsik static int 225d956798dSJozsef Kadlecsik set_target_v0_checkentry(const struct xt_tgchk_param *par) 226d956798dSJozsef Kadlecsik { 227d956798dSJozsef Kadlecsik struct xt_set_info_target_v0 *info = par->targinfo; 228d956798dSJozsef Kadlecsik ip_set_id_t index; 229d956798dSJozsef Kadlecsik 230d956798dSJozsef Kadlecsik if (info->add_set.index != IPSET_INVALID_ID) { 231d956798dSJozsef Kadlecsik index = ip_set_nfnl_get_byindex(info->add_set.index); 232d956798dSJozsef Kadlecsik if (index == IPSET_INVALID_ID) { 233d956798dSJozsef Kadlecsik pr_warning("Cannot find add_set index %u as target\n", 234d956798dSJozsef Kadlecsik info->add_set.index); 235d956798dSJozsef Kadlecsik return -ENOENT; 236d956798dSJozsef Kadlecsik } 237d956798dSJozsef Kadlecsik } 238d956798dSJozsef Kadlecsik 239d956798dSJozsef Kadlecsik if (info->del_set.index != IPSET_INVALID_ID) { 240d956798dSJozsef Kadlecsik index = ip_set_nfnl_get_byindex(info->del_set.index); 241d956798dSJozsef Kadlecsik if (index == IPSET_INVALID_ID) { 242d956798dSJozsef Kadlecsik pr_warning("Cannot find del_set index %u as target\n", 243d956798dSJozsef Kadlecsik info->del_set.index); 244eafbd3fdSJozsef Kadlecsik if (info->add_set.index != IPSET_INVALID_ID) 245eafbd3fdSJozsef Kadlecsik ip_set_nfnl_put(info->add_set.index); 246d956798dSJozsef Kadlecsik return -ENOENT; 247d956798dSJozsef Kadlecsik } 248d956798dSJozsef Kadlecsik } 249d956798dSJozsef Kadlecsik if (info->add_set.u.flags[IPSET_DIM_MAX-1] != 0 || 250d956798dSJozsef Kadlecsik info->del_set.u.flags[IPSET_DIM_MAX-1] != 0) { 251d956798dSJozsef Kadlecsik pr_warning("Protocol error: SET target dimension " 252d956798dSJozsef Kadlecsik "is over the limit!\n"); 253eafbd3fdSJozsef Kadlecsik if (info->add_set.index != IPSET_INVALID_ID) 254eafbd3fdSJozsef Kadlecsik ip_set_nfnl_put(info->add_set.index); 255eafbd3fdSJozsef Kadlecsik if (info->del_set.index != IPSET_INVALID_ID) 256eafbd3fdSJozsef Kadlecsik ip_set_nfnl_put(info->del_set.index); 257d956798dSJozsef Kadlecsik return -ERANGE; 258d956798dSJozsef Kadlecsik } 259d956798dSJozsef Kadlecsik 260d956798dSJozsef Kadlecsik /* Fill out compatibility data */ 261d956798dSJozsef Kadlecsik compat_flags(&info->add_set); 262d956798dSJozsef Kadlecsik compat_flags(&info->del_set); 263d956798dSJozsef Kadlecsik 264d956798dSJozsef Kadlecsik return 0; 265d956798dSJozsef Kadlecsik } 266d956798dSJozsef Kadlecsik 267d956798dSJozsef Kadlecsik static void 268d956798dSJozsef Kadlecsik set_target_v0_destroy(const struct xt_tgdtor_param *par) 269d956798dSJozsef Kadlecsik { 270d956798dSJozsef Kadlecsik const struct xt_set_info_target_v0 *info = par->targinfo; 271d956798dSJozsef Kadlecsik 272d956798dSJozsef Kadlecsik if (info->add_set.index != IPSET_INVALID_ID) 273d956798dSJozsef Kadlecsik ip_set_nfnl_put(info->add_set.index); 274d956798dSJozsef Kadlecsik if (info->del_set.index != IPSET_INVALID_ID) 275d956798dSJozsef Kadlecsik ip_set_nfnl_put(info->del_set.index); 276d956798dSJozsef Kadlecsik } 277d956798dSJozsef Kadlecsik 278bd3129fcSJozsef Kadlecsik /* Revision 1 target */ 279d956798dSJozsef Kadlecsik 280d956798dSJozsef Kadlecsik static unsigned int 281ac8cc925SJozsef Kadlecsik set_target_v1(struct sk_buff *skb, const struct xt_action_param *par) 282d956798dSJozsef Kadlecsik { 283ac8cc925SJozsef Kadlecsik const struct xt_set_info_target_v1 *info = par->targinfo; 284ac8cc925SJozsef Kadlecsik ADT_OPT(add_opt, par->family, info->add_set.dim, 285ac8cc925SJozsef Kadlecsik info->add_set.flags, 0, UINT_MAX); 286ac8cc925SJozsef Kadlecsik ADT_OPT(del_opt, par->family, info->del_set.dim, 287ac8cc925SJozsef Kadlecsik info->del_set.flags, 0, UINT_MAX); 288d956798dSJozsef Kadlecsik 289d956798dSJozsef Kadlecsik if (info->add_set.index != IPSET_INVALID_ID) 290b66554cfSJozsef Kadlecsik ip_set_add(info->add_set.index, skb, par, &add_opt); 291d956798dSJozsef Kadlecsik if (info->del_set.index != IPSET_INVALID_ID) 292b66554cfSJozsef Kadlecsik ip_set_del(info->del_set.index, skb, par, &del_opt); 293d956798dSJozsef Kadlecsik 294d956798dSJozsef Kadlecsik return XT_CONTINUE; 295d956798dSJozsef Kadlecsik } 296d956798dSJozsef Kadlecsik 297d956798dSJozsef Kadlecsik static int 298ac8cc925SJozsef Kadlecsik set_target_v1_checkentry(const struct xt_tgchk_param *par) 299d956798dSJozsef Kadlecsik { 300ac8cc925SJozsef Kadlecsik const struct xt_set_info_target_v1 *info = par->targinfo; 301d956798dSJozsef Kadlecsik ip_set_id_t index; 302d956798dSJozsef Kadlecsik 303d956798dSJozsef Kadlecsik if (info->add_set.index != IPSET_INVALID_ID) { 304d956798dSJozsef Kadlecsik index = ip_set_nfnl_get_byindex(info->add_set.index); 305d956798dSJozsef Kadlecsik if (index == IPSET_INVALID_ID) { 306d956798dSJozsef Kadlecsik pr_warning("Cannot find add_set index %u as target\n", 307d956798dSJozsef Kadlecsik info->add_set.index); 308d956798dSJozsef Kadlecsik return -ENOENT; 309d956798dSJozsef Kadlecsik } 310d956798dSJozsef Kadlecsik } 311d956798dSJozsef Kadlecsik 312d956798dSJozsef Kadlecsik if (info->del_set.index != IPSET_INVALID_ID) { 313d956798dSJozsef Kadlecsik index = ip_set_nfnl_get_byindex(info->del_set.index); 314d956798dSJozsef Kadlecsik if (index == IPSET_INVALID_ID) { 315d956798dSJozsef Kadlecsik pr_warning("Cannot find del_set index %u as target\n", 316d956798dSJozsef Kadlecsik info->del_set.index); 317eafbd3fdSJozsef Kadlecsik if (info->add_set.index != IPSET_INVALID_ID) 318eafbd3fdSJozsef Kadlecsik ip_set_nfnl_put(info->add_set.index); 319d956798dSJozsef Kadlecsik return -ENOENT; 320d956798dSJozsef Kadlecsik } 321d956798dSJozsef Kadlecsik } 322d956798dSJozsef Kadlecsik if (info->add_set.dim > IPSET_DIM_MAX || 323eafbd3fdSJozsef Kadlecsik info->del_set.dim > IPSET_DIM_MAX) { 324d956798dSJozsef Kadlecsik pr_warning("Protocol error: SET target dimension " 325d956798dSJozsef Kadlecsik "is over the limit!\n"); 326eafbd3fdSJozsef Kadlecsik if (info->add_set.index != IPSET_INVALID_ID) 327eafbd3fdSJozsef Kadlecsik ip_set_nfnl_put(info->add_set.index); 328eafbd3fdSJozsef Kadlecsik if (info->del_set.index != IPSET_INVALID_ID) 329eafbd3fdSJozsef Kadlecsik ip_set_nfnl_put(info->del_set.index); 330d956798dSJozsef Kadlecsik return -ERANGE; 331d956798dSJozsef Kadlecsik } 332d956798dSJozsef Kadlecsik 333d956798dSJozsef Kadlecsik return 0; 334d956798dSJozsef Kadlecsik } 335d956798dSJozsef Kadlecsik 336d956798dSJozsef Kadlecsik static void 337ac8cc925SJozsef Kadlecsik set_target_v1_destroy(const struct xt_tgdtor_param *par) 338d956798dSJozsef Kadlecsik { 339ac8cc925SJozsef Kadlecsik const struct xt_set_info_target_v1 *info = par->targinfo; 340d956798dSJozsef Kadlecsik 341d956798dSJozsef Kadlecsik if (info->add_set.index != IPSET_INVALID_ID) 342d956798dSJozsef Kadlecsik ip_set_nfnl_put(info->add_set.index); 343d956798dSJozsef Kadlecsik if (info->del_set.index != IPSET_INVALID_ID) 344d956798dSJozsef Kadlecsik ip_set_nfnl_put(info->del_set.index); 345d956798dSJozsef Kadlecsik } 346d956798dSJozsef Kadlecsik 347ac8cc925SJozsef Kadlecsik /* Revision 2 target */ 348ac8cc925SJozsef Kadlecsik 349ac8cc925SJozsef Kadlecsik static unsigned int 350ac8cc925SJozsef Kadlecsik set_target_v2(struct sk_buff *skb, const struct xt_action_param *par) 351ac8cc925SJozsef Kadlecsik { 352ac8cc925SJozsef Kadlecsik const struct xt_set_info_target_v2 *info = par->targinfo; 353075e64c0SJozsef Kadlecsik ADT_OPT(add_opt, par->family, info->add_set.dim, 354ac8cc925SJozsef Kadlecsik info->add_set.flags, info->flags, info->timeout); 355ac8cc925SJozsef Kadlecsik ADT_OPT(del_opt, par->family, info->del_set.dim, 356ac8cc925SJozsef Kadlecsik info->del_set.flags, 0, UINT_MAX); 357ac8cc925SJozsef Kadlecsik 358127f5591SJozsef Kadlecsik /* Normalize to fit into jiffies */ 359075e64c0SJozsef Kadlecsik if (add_opt.ext.timeout != IPSET_NO_TIMEOUT && 360075e64c0SJozsef Kadlecsik add_opt.ext.timeout > UINT_MAX/MSEC_PER_SEC) 361075e64c0SJozsef Kadlecsik add_opt.ext.timeout = UINT_MAX/MSEC_PER_SEC; 362ac8cc925SJozsef Kadlecsik if (info->add_set.index != IPSET_INVALID_ID) 363b66554cfSJozsef Kadlecsik ip_set_add(info->add_set.index, skb, par, &add_opt); 364ac8cc925SJozsef Kadlecsik if (info->del_set.index != IPSET_INVALID_ID) 365b66554cfSJozsef Kadlecsik ip_set_del(info->del_set.index, skb, par, &del_opt); 366ac8cc925SJozsef Kadlecsik 367ac8cc925SJozsef Kadlecsik return XT_CONTINUE; 368ac8cc925SJozsef Kadlecsik } 369ac8cc925SJozsef Kadlecsik 370ac8cc925SJozsef Kadlecsik #define set_target_v2_checkentry set_target_v1_checkentry 371ac8cc925SJozsef Kadlecsik #define set_target_v2_destroy set_target_v1_destroy 372ac8cc925SJozsef Kadlecsik 373d956798dSJozsef Kadlecsik static struct xt_match set_matches[] __read_mostly = { 374d956798dSJozsef Kadlecsik { 375d956798dSJozsef Kadlecsik .name = "set", 376d956798dSJozsef Kadlecsik .family = NFPROTO_IPV4, 377d956798dSJozsef Kadlecsik .revision = 0, 378d956798dSJozsef Kadlecsik .match = set_match_v0, 379d956798dSJozsef Kadlecsik .matchsize = sizeof(struct xt_set_info_match_v0), 380d956798dSJozsef Kadlecsik .checkentry = set_match_v0_checkentry, 381d956798dSJozsef Kadlecsik .destroy = set_match_v0_destroy, 382d956798dSJozsef Kadlecsik .me = THIS_MODULE 383d956798dSJozsef Kadlecsik }, 384d956798dSJozsef Kadlecsik { 385d956798dSJozsef Kadlecsik .name = "set", 386d956798dSJozsef Kadlecsik .family = NFPROTO_IPV4, 387d956798dSJozsef Kadlecsik .revision = 1, 388ac8cc925SJozsef Kadlecsik .match = set_match_v1, 389ac8cc925SJozsef Kadlecsik .matchsize = sizeof(struct xt_set_info_match_v1), 390ac8cc925SJozsef Kadlecsik .checkentry = set_match_v1_checkentry, 391ac8cc925SJozsef Kadlecsik .destroy = set_match_v1_destroy, 392d956798dSJozsef Kadlecsik .me = THIS_MODULE 393d956798dSJozsef Kadlecsik }, 394d956798dSJozsef Kadlecsik { 395d956798dSJozsef Kadlecsik .name = "set", 396d956798dSJozsef Kadlecsik .family = NFPROTO_IPV6, 397d956798dSJozsef Kadlecsik .revision = 1, 398ac8cc925SJozsef Kadlecsik .match = set_match_v1, 399ac8cc925SJozsef Kadlecsik .matchsize = sizeof(struct xt_set_info_match_v1), 400ac8cc925SJozsef Kadlecsik .checkentry = set_match_v1_checkentry, 401ac8cc925SJozsef Kadlecsik .destroy = set_match_v1_destroy, 402d956798dSJozsef Kadlecsik .me = THIS_MODULE 403d956798dSJozsef Kadlecsik }, 4043e0304a5SJozsef Kadlecsik /* --return-nomatch flag support */ 4053e0304a5SJozsef Kadlecsik { 4063e0304a5SJozsef Kadlecsik .name = "set", 4073e0304a5SJozsef Kadlecsik .family = NFPROTO_IPV4, 4083e0304a5SJozsef Kadlecsik .revision = 2, 4093e0304a5SJozsef Kadlecsik .match = set_match_v1, 4103e0304a5SJozsef Kadlecsik .matchsize = sizeof(struct xt_set_info_match_v1), 4113e0304a5SJozsef Kadlecsik .checkentry = set_match_v1_checkentry, 4123e0304a5SJozsef Kadlecsik .destroy = set_match_v1_destroy, 4133e0304a5SJozsef Kadlecsik .me = THIS_MODULE 4143e0304a5SJozsef Kadlecsik }, 4153e0304a5SJozsef Kadlecsik { 4163e0304a5SJozsef Kadlecsik .name = "set", 4173e0304a5SJozsef Kadlecsik .family = NFPROTO_IPV6, 4183e0304a5SJozsef Kadlecsik .revision = 2, 4193e0304a5SJozsef Kadlecsik .match = set_match_v1, 4203e0304a5SJozsef Kadlecsik .matchsize = sizeof(struct xt_set_info_match_v1), 4213e0304a5SJozsef Kadlecsik .checkentry = set_match_v1_checkentry, 4223e0304a5SJozsef Kadlecsik .destroy = set_match_v1_destroy, 4233e0304a5SJozsef Kadlecsik .me = THIS_MODULE 4243e0304a5SJozsef Kadlecsik }, 4256e01781dSJozsef Kadlecsik /* counters support: update, match */ 4266e01781dSJozsef Kadlecsik { 4276e01781dSJozsef Kadlecsik .name = "set", 4286e01781dSJozsef Kadlecsik .family = NFPROTO_IPV4, 4296e01781dSJozsef Kadlecsik .revision = 3, 4306e01781dSJozsef Kadlecsik .match = set_match_v3, 4316e01781dSJozsef Kadlecsik .matchsize = sizeof(struct xt_set_info_match_v3), 4326e01781dSJozsef Kadlecsik .checkentry = set_match_v3_checkentry, 4336e01781dSJozsef Kadlecsik .destroy = set_match_v3_destroy, 4346e01781dSJozsef Kadlecsik .me = THIS_MODULE 4356e01781dSJozsef Kadlecsik }, 4366e01781dSJozsef Kadlecsik { 4376e01781dSJozsef Kadlecsik .name = "set", 4386e01781dSJozsef Kadlecsik .family = NFPROTO_IPV6, 4396e01781dSJozsef Kadlecsik .revision = 3, 4406e01781dSJozsef Kadlecsik .match = set_match_v3, 4416e01781dSJozsef Kadlecsik .matchsize = sizeof(struct xt_set_info_match_v3), 4426e01781dSJozsef Kadlecsik .checkentry = set_match_v3_checkentry, 4436e01781dSJozsef Kadlecsik .destroy = set_match_v3_destroy, 4446e01781dSJozsef Kadlecsik .me = THIS_MODULE 4456e01781dSJozsef Kadlecsik }, 446d956798dSJozsef Kadlecsik }; 447d956798dSJozsef Kadlecsik 448d956798dSJozsef Kadlecsik static struct xt_target set_targets[] __read_mostly = { 449d956798dSJozsef Kadlecsik { 450d956798dSJozsef Kadlecsik .name = "SET", 451d956798dSJozsef Kadlecsik .revision = 0, 452d956798dSJozsef Kadlecsik .family = NFPROTO_IPV4, 453d956798dSJozsef Kadlecsik .target = set_target_v0, 454d956798dSJozsef Kadlecsik .targetsize = sizeof(struct xt_set_info_target_v0), 455d956798dSJozsef Kadlecsik .checkentry = set_target_v0_checkentry, 456d956798dSJozsef Kadlecsik .destroy = set_target_v0_destroy, 457d956798dSJozsef Kadlecsik .me = THIS_MODULE 458d956798dSJozsef Kadlecsik }, 459d956798dSJozsef Kadlecsik { 460d956798dSJozsef Kadlecsik .name = "SET", 461d956798dSJozsef Kadlecsik .revision = 1, 462d956798dSJozsef Kadlecsik .family = NFPROTO_IPV4, 463ac8cc925SJozsef Kadlecsik .target = set_target_v1, 464ac8cc925SJozsef Kadlecsik .targetsize = sizeof(struct xt_set_info_target_v1), 465ac8cc925SJozsef Kadlecsik .checkentry = set_target_v1_checkentry, 466ac8cc925SJozsef Kadlecsik .destroy = set_target_v1_destroy, 467d956798dSJozsef Kadlecsik .me = THIS_MODULE 468d956798dSJozsef Kadlecsik }, 469d956798dSJozsef Kadlecsik { 470d956798dSJozsef Kadlecsik .name = "SET", 471d956798dSJozsef Kadlecsik .revision = 1, 472d956798dSJozsef Kadlecsik .family = NFPROTO_IPV6, 473ac8cc925SJozsef Kadlecsik .target = set_target_v1, 474ac8cc925SJozsef Kadlecsik .targetsize = sizeof(struct xt_set_info_target_v1), 475ac8cc925SJozsef Kadlecsik .checkentry = set_target_v1_checkentry, 476ac8cc925SJozsef Kadlecsik .destroy = set_target_v1_destroy, 477ac8cc925SJozsef Kadlecsik .me = THIS_MODULE 478ac8cc925SJozsef Kadlecsik }, 4793e0304a5SJozsef Kadlecsik /* --timeout and --exist flags support */ 480ac8cc925SJozsef Kadlecsik { 481ac8cc925SJozsef Kadlecsik .name = "SET", 482ac8cc925SJozsef Kadlecsik .revision = 2, 483ac8cc925SJozsef Kadlecsik .family = NFPROTO_IPV4, 484ac8cc925SJozsef Kadlecsik .target = set_target_v2, 485ac8cc925SJozsef Kadlecsik .targetsize = sizeof(struct xt_set_info_target_v2), 486ac8cc925SJozsef Kadlecsik .checkentry = set_target_v2_checkentry, 487ac8cc925SJozsef Kadlecsik .destroy = set_target_v2_destroy, 488ac8cc925SJozsef Kadlecsik .me = THIS_MODULE 489ac8cc925SJozsef Kadlecsik }, 490ac8cc925SJozsef Kadlecsik { 491ac8cc925SJozsef Kadlecsik .name = "SET", 492ac8cc925SJozsef Kadlecsik .revision = 2, 493ac8cc925SJozsef Kadlecsik .family = NFPROTO_IPV6, 494ac8cc925SJozsef Kadlecsik .target = set_target_v2, 495ac8cc925SJozsef Kadlecsik .targetsize = sizeof(struct xt_set_info_target_v2), 496ac8cc925SJozsef Kadlecsik .checkentry = set_target_v2_checkentry, 497ac8cc925SJozsef Kadlecsik .destroy = set_target_v2_destroy, 498d956798dSJozsef Kadlecsik .me = THIS_MODULE 499d956798dSJozsef Kadlecsik }, 500d956798dSJozsef Kadlecsik }; 501d956798dSJozsef Kadlecsik 502d956798dSJozsef Kadlecsik static int __init xt_set_init(void) 503d956798dSJozsef Kadlecsik { 504d956798dSJozsef Kadlecsik int ret = xt_register_matches(set_matches, ARRAY_SIZE(set_matches)); 505d956798dSJozsef Kadlecsik 506d956798dSJozsef Kadlecsik if (!ret) { 507d956798dSJozsef Kadlecsik ret = xt_register_targets(set_targets, 508d956798dSJozsef Kadlecsik ARRAY_SIZE(set_targets)); 509d956798dSJozsef Kadlecsik if (ret) 510d956798dSJozsef Kadlecsik xt_unregister_matches(set_matches, 511d956798dSJozsef Kadlecsik ARRAY_SIZE(set_matches)); 512d956798dSJozsef Kadlecsik } 513d956798dSJozsef Kadlecsik return ret; 514d956798dSJozsef Kadlecsik } 515d956798dSJozsef Kadlecsik 516d956798dSJozsef Kadlecsik static void __exit xt_set_fini(void) 517d956798dSJozsef Kadlecsik { 518d956798dSJozsef Kadlecsik xt_unregister_matches(set_matches, ARRAY_SIZE(set_matches)); 519d956798dSJozsef Kadlecsik xt_unregister_targets(set_targets, ARRAY_SIZE(set_targets)); 520d956798dSJozsef Kadlecsik } 521d956798dSJozsef Kadlecsik 522d956798dSJozsef Kadlecsik module_init(xt_set_init); 523d956798dSJozsef Kadlecsik module_exit(xt_set_fini); 524