0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/init.h>
0009 #include <linux/spinlock.h>
0010 #include <linux/skbuff.h>
0011 #include <linux/net.h>
0012 #include <linux/slab.h>
0013
0014 #include <linux/netfilter/xt_statistic.h>
0015 #include <linux/netfilter/x_tables.h>
0016 #include <linux/module.h>
0017
0018 struct xt_statistic_priv {
0019 atomic_t count;
0020 } ____cacheline_aligned_in_smp;
0021
0022 MODULE_LICENSE("GPL");
0023 MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
0024 MODULE_DESCRIPTION("Xtables: statistics-based matching (\"Nth\", random)");
0025 MODULE_ALIAS("ipt_statistic");
0026 MODULE_ALIAS("ip6t_statistic");
0027
0028 static bool
0029 statistic_mt(const struct sk_buff *skb, struct xt_action_param *par)
0030 {
0031 const struct xt_statistic_info *info = par->matchinfo;
0032 bool ret = info->flags & XT_STATISTIC_INVERT;
0033 int nval, oval;
0034
0035 switch (info->mode) {
0036 case XT_STATISTIC_MODE_RANDOM:
0037 if ((prandom_u32() & 0x7FFFFFFF) < info->u.random.probability)
0038 ret = !ret;
0039 break;
0040 case XT_STATISTIC_MODE_NTH:
0041 do {
0042 oval = atomic_read(&info->master->count);
0043 nval = (oval == info->u.nth.every) ? 0 : oval + 1;
0044 } while (atomic_cmpxchg(&info->master->count, oval, nval) != oval);
0045 if (nval == 0)
0046 ret = !ret;
0047 break;
0048 }
0049
0050 return ret;
0051 }
0052
0053 static int statistic_mt_check(const struct xt_mtchk_param *par)
0054 {
0055 struct xt_statistic_info *info = par->matchinfo;
0056
0057 if (info->mode > XT_STATISTIC_MODE_MAX ||
0058 info->flags & ~XT_STATISTIC_MASK)
0059 return -EINVAL;
0060
0061 info->master = kzalloc(sizeof(*info->master), GFP_KERNEL);
0062 if (info->master == NULL)
0063 return -ENOMEM;
0064 atomic_set(&info->master->count, info->u.nth.count);
0065
0066 return 0;
0067 }
0068
0069 static void statistic_mt_destroy(const struct xt_mtdtor_param *par)
0070 {
0071 const struct xt_statistic_info *info = par->matchinfo;
0072
0073 kfree(info->master);
0074 }
0075
0076 static struct xt_match xt_statistic_mt_reg __read_mostly = {
0077 .name = "statistic",
0078 .revision = 0,
0079 .family = NFPROTO_UNSPEC,
0080 .match = statistic_mt,
0081 .checkentry = statistic_mt_check,
0082 .destroy = statistic_mt_destroy,
0083 .matchsize = sizeof(struct xt_statistic_info),
0084 .usersize = offsetof(struct xt_statistic_info, master),
0085 .me = THIS_MODULE,
0086 };
0087
0088 static int __init statistic_mt_init(void)
0089 {
0090 return xt_register_match(&xt_statistic_mt_reg);
0091 }
0092
0093 static void __exit statistic_mt_exit(void)
0094 {
0095 xt_unregister_match(&xt_statistic_mt_reg);
0096 }
0097
0098 module_init(statistic_mt_init);
0099 module_exit(statistic_mt_exit);