1f3389805e53a13bd969ee1c8fc5a4137b7c6c167Patrick McHardy/*
2f3389805e53a13bd969ee1c8fc5a4137b7c6c167Patrick McHardy * Copyright (c) 2006 Patrick McHardy <kaber@trash.net>
3f3389805e53a13bd969ee1c8fc5a4137b7c6c167Patrick McHardy *
4f3389805e53a13bd969ee1c8fc5a4137b7c6c167Patrick McHardy * This program is free software; you can redistribute it and/or modify
5f3389805e53a13bd969ee1c8fc5a4137b7c6c167Patrick McHardy * it under the terms of the GNU General Public License version 2 as
6f3389805e53a13bd969ee1c8fc5a4137b7c6c167Patrick McHardy * published by the Free Software Foundation.
7f3389805e53a13bd969ee1c8fc5a4137b7c6c167Patrick McHardy *
8f3389805e53a13bd969ee1c8fc5a4137b7c6c167Patrick McHardy * Based on ipt_random and ipt_nth by Fabrice MARIE <fabrice@netfilter.org>.
9f3389805e53a13bd969ee1c8fc5a4137b7c6c167Patrick McHardy */
10f3389805e53a13bd969ee1c8fc5a4137b7c6c167Patrick McHardy
11f3389805e53a13bd969ee1c8fc5a4137b7c6c167Patrick McHardy#include <linux/init.h>
12f3389805e53a13bd969ee1c8fc5a4137b7c6c167Patrick McHardy#include <linux/spinlock.h>
13f3389805e53a13bd969ee1c8fc5a4137b7c6c167Patrick McHardy#include <linux/skbuff.h>
14f3389805e53a13bd969ee1c8fc5a4137b7c6c167Patrick McHardy#include <linux/net.h>
155a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
16f3389805e53a13bd969ee1c8fc5a4137b7c6c167Patrick McHardy
17f3389805e53a13bd969ee1c8fc5a4137b7c6c167Patrick McHardy#include <linux/netfilter/xt_statistic.h>
18f3389805e53a13bd969ee1c8fc5a4137b7c6c167Patrick McHardy#include <linux/netfilter/x_tables.h>
193a9a231d977222eea36eae091df2c358e03ac839Paul Gortmaker#include <linux/module.h>
20f3389805e53a13bd969ee1c8fc5a4137b7c6c167Patrick McHardy
21acc738fec03bdaa5b77340c32a82fbfedaaabef0Jan Engelhardtstruct xt_statistic_priv {
22fabf3a85ab88063c10f367cccba7b3a1e59df996Eric Dumazet	atomic_t count;
23fabf3a85ab88063c10f367cccba7b3a1e59df996Eric Dumazet} ____cacheline_aligned_in_smp;
24acc738fec03bdaa5b77340c32a82fbfedaaabef0Jan Engelhardt
25f3389805e53a13bd969ee1c8fc5a4137b7c6c167Patrick McHardyMODULE_LICENSE("GPL");
26f3389805e53a13bd969ee1c8fc5a4137b7c6c167Patrick McHardyMODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
272ae15b64e6a1608c840c60df38e8e5eef7b2b8c3Jan EngelhardtMODULE_DESCRIPTION("Xtables: statistics-based matching (\"Nth\", random)");
28f3389805e53a13bd969ee1c8fc5a4137b7c6c167Patrick McHardyMODULE_ALIAS("ipt_statistic");
29f3389805e53a13bd969ee1c8fc5a4137b7c6c167Patrick McHardyMODULE_ALIAS("ip6t_statistic");
30f3389805e53a13bd969ee1c8fc5a4137b7c6c167Patrick McHardy
311d93a9cbad608f6398ba6c5b588c504ccd35a2caJan Engelhardtstatic bool
3262fc8051083a334578c3f4b3488808f210b4565fJan Engelhardtstatistic_mt(const struct sk_buff *skb, struct xt_action_param *par)
33f3389805e53a13bd969ee1c8fc5a4137b7c6c167Patrick McHardy{
34acc738fec03bdaa5b77340c32a82fbfedaaabef0Jan Engelhardt	const struct xt_statistic_info *info = par->matchinfo;
351d93a9cbad608f6398ba6c5b588c504ccd35a2caJan Engelhardt	bool ret = info->flags & XT_STATISTIC_INVERT;
36fabf3a85ab88063c10f367cccba7b3a1e59df996Eric Dumazet	int nval, oval;
37f3389805e53a13bd969ee1c8fc5a4137b7c6c167Patrick McHardy
38f3389805e53a13bd969ee1c8fc5a4137b7c6c167Patrick McHardy	switch (info->mode) {
39f3389805e53a13bd969ee1c8fc5a4137b7c6c167Patrick McHardy	case XT_STATISTIC_MODE_RANDOM:
4063862b5bef7349dd1137e4c70702c67d77565785Aruna-Hewapathirane		if ((prandom_u32() & 0x7FFFFFFF) < info->u.random.probability)
411d93a9cbad608f6398ba6c5b588c504ccd35a2caJan Engelhardt			ret = !ret;
42f3389805e53a13bd969ee1c8fc5a4137b7c6c167Patrick McHardy		break;
43f3389805e53a13bd969ee1c8fc5a4137b7c6c167Patrick McHardy	case XT_STATISTIC_MODE_NTH:
44fabf3a85ab88063c10f367cccba7b3a1e59df996Eric Dumazet		do {
45fabf3a85ab88063c10f367cccba7b3a1e59df996Eric Dumazet			oval = atomic_read(&info->master->count);
46fabf3a85ab88063c10f367cccba7b3a1e59df996Eric Dumazet			nval = (oval == info->u.nth.every) ? 0 : oval + 1;
47fabf3a85ab88063c10f367cccba7b3a1e59df996Eric Dumazet		} while (atomic_cmpxchg(&info->master->count, oval, nval) != oval);
48fabf3a85ab88063c10f367cccba7b3a1e59df996Eric Dumazet		if (nval == 0)
491d93a9cbad608f6398ba6c5b588c504ccd35a2caJan Engelhardt			ret = !ret;
50f3389805e53a13bd969ee1c8fc5a4137b7c6c167Patrick McHardy		break;
51f3389805e53a13bd969ee1c8fc5a4137b7c6c167Patrick McHardy	}
52f3389805e53a13bd969ee1c8fc5a4137b7c6c167Patrick McHardy
53f3389805e53a13bd969ee1c8fc5a4137b7c6c167Patrick McHardy	return ret;
54f3389805e53a13bd969ee1c8fc5a4137b7c6c167Patrick McHardy}
55f3389805e53a13bd969ee1c8fc5a4137b7c6c167Patrick McHardy
56b0f38452ff73da7e9e0ddc68cd5c6b93c897ca0dJan Engelhardtstatic int statistic_mt_check(const struct xt_mtchk_param *par)
57f3389805e53a13bd969ee1c8fc5a4137b7c6c167Patrick McHardy{
589b4fce7a3508a9776534188b6065b206a9608ccfJan Engelhardt	struct xt_statistic_info *info = par->matchinfo;
59f3389805e53a13bd969ee1c8fc5a4137b7c6c167Patrick McHardy
60f3389805e53a13bd969ee1c8fc5a4137b7c6c167Patrick McHardy	if (info->mode > XT_STATISTIC_MODE_MAX ||
61f3389805e53a13bd969ee1c8fc5a4137b7c6c167Patrick McHardy	    info->flags & ~XT_STATISTIC_MASK)
62bd414ee605ff3ac5fcd79f57269a897879ee4cdeJan Engelhardt		return -EINVAL;
63acc738fec03bdaa5b77340c32a82fbfedaaabef0Jan Engelhardt
64acc738fec03bdaa5b77340c32a82fbfedaaabef0Jan Engelhardt	info->master = kzalloc(sizeof(*info->master), GFP_KERNEL);
6585bc3f38147c5d3fb1eb9ca2236536389b592caeJan Engelhardt	if (info->master == NULL)
664a5a5c73b7cfee46a0b1411903cfa0dea532deecJan Engelhardt		return -ENOMEM;
67fabf3a85ab88063c10f367cccba7b3a1e59df996Eric Dumazet	atomic_set(&info->master->count, info->u.nth.count);
68acc738fec03bdaa5b77340c32a82fbfedaaabef0Jan Engelhardt
69bd414ee605ff3ac5fcd79f57269a897879ee4cdeJan Engelhardt	return 0;
70f3389805e53a13bd969ee1c8fc5a4137b7c6c167Patrick McHardy}
71f3389805e53a13bd969ee1c8fc5a4137b7c6c167Patrick McHardy
72acc738fec03bdaa5b77340c32a82fbfedaaabef0Jan Engelhardtstatic void statistic_mt_destroy(const struct xt_mtdtor_param *par)
73acc738fec03bdaa5b77340c32a82fbfedaaabef0Jan Engelhardt{
74acc738fec03bdaa5b77340c32a82fbfedaaabef0Jan Engelhardt	const struct xt_statistic_info *info = par->matchinfo;
75acc738fec03bdaa5b77340c32a82fbfedaaabef0Jan Engelhardt
76acc738fec03bdaa5b77340c32a82fbfedaaabef0Jan Engelhardt	kfree(info->master);
77acc738fec03bdaa5b77340c32a82fbfedaaabef0Jan Engelhardt}
78acc738fec03bdaa5b77340c32a82fbfedaaabef0Jan Engelhardt
7955b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardtstatic struct xt_match xt_statistic_mt_reg __read_mostly = {
8055b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt	.name       = "statistic",
8155b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt	.revision   = 0,
8255b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt	.family     = NFPROTO_UNSPEC,
8355b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt	.match      = statistic_mt,
8455b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt	.checkentry = statistic_mt_check,
85acc738fec03bdaa5b77340c32a82fbfedaaabef0Jan Engelhardt	.destroy    = statistic_mt_destroy,
8655b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt	.matchsize  = sizeof(struct xt_statistic_info),
8755b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt	.me         = THIS_MODULE,
88f3389805e53a13bd969ee1c8fc5a4137b7c6c167Patrick McHardy};
89f3389805e53a13bd969ee1c8fc5a4137b7c6c167Patrick McHardy
90d3c5ee6d545b5372fd525ebe16988a5b6efeceb0Jan Engelhardtstatic int __init statistic_mt_init(void)
91f3389805e53a13bd969ee1c8fc5a4137b7c6c167Patrick McHardy{
9255b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt	return xt_register_match(&xt_statistic_mt_reg);
93f3389805e53a13bd969ee1c8fc5a4137b7c6c167Patrick McHardy}
94f3389805e53a13bd969ee1c8fc5a4137b7c6c167Patrick McHardy
95d3c5ee6d545b5372fd525ebe16988a5b6efeceb0Jan Engelhardtstatic void __exit statistic_mt_exit(void)
96f3389805e53a13bd969ee1c8fc5a4137b7c6c167Patrick McHardy{
9755b69e91040c685a064198bd76e59885b7ad26c6Jan Engelhardt	xt_unregister_match(&xt_statistic_mt_reg);
98f3389805e53a13bd969ee1c8fc5a4137b7c6c167Patrick McHardy}
99f3389805e53a13bd969ee1c8fc5a4137b7c6c167Patrick McHardy
100d3c5ee6d545b5372fd525ebe16988a5b6efeceb0Jan Engelhardtmodule_init(statistic_mt_init);
101d3c5ee6d545b5372fd525ebe16988a5b6efeceb0Jan Engelhardtmodule_exit(statistic_mt_exit);
102