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