Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (c) 2006 Patrick McHardy <kaber@trash.net>
0004  *
0005  * Based on ipt_random and ipt_nth by Fabrice MARIE <fabrice@netfilter.org>.
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);