Blame view
net/netfilter/xt_limit.c
5.86 KB
db955170d more UTF-8 conver... |
1 2 |
/* (C) 1999 Jérôme de Vivie <devivie@info.enserb.u-bordeaux.fr> * (C) 1999 Hervé Eychenne <eychenne@info.enserb.u-bordeaux.fr> |
1da177e4c Linux-2.6.12-rc2 |
3 4 5 6 7 |
* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ |
8bee4bad0 netfilter: xt ext... |
8 |
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
1da177e4c Linux-2.6.12-rc2 |
9 |
|
5a0e3ad6a include cleanup: ... |
10 |
#include <linux/slab.h> |
1da177e4c Linux-2.6.12-rc2 |
11 12 13 14 |
#include <linux/module.h> #include <linux/skbuff.h> #include <linux/spinlock.h> #include <linux/interrupt.h> |
2e4e6a17a [NETFILTER] x_tab... |
15 16 |
#include <linux/netfilter/x_tables.h> #include <linux/netfilter/xt_limit.h> |
1da177e4c Linux-2.6.12-rc2 |
17 |
|
acc738fec netfilter: xtable... |
18 19 20 21 |
struct xt_limit_priv { unsigned long prev; uint32_t credit; }; |
1da177e4c Linux-2.6.12-rc2 |
22 23 |
MODULE_LICENSE("GPL"); MODULE_AUTHOR("Herve Eychenne <rv@wallfire.org>"); |
2ae15b64e [NETFILTER]: Upda... |
24 |
MODULE_DESCRIPTION("Xtables: rate-limit match"); |
2e4e6a17a [NETFILTER] x_tab... |
25 26 |
MODULE_ALIAS("ipt_limit"); MODULE_ALIAS("ip6t_limit"); |
1da177e4c Linux-2.6.12-rc2 |
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
/* The algorithm used is the Simple Token Bucket Filter (TBF) * see net/sched/sch_tbf.c in the linux source tree */ static DEFINE_SPINLOCK(limit_lock); /* Rusty: This is my (non-mathematically-inclined) understanding of this algorithm. The `average rate' in jiffies becomes your initial amount of credit `credit' and the most credit you can ever have `credit_cap'. The `peak rate' becomes the cost of passing the test, `cost'. `prev' tracks the last packet hit: you gain one credit per jiffy. If you get credit balance more than this, the extra credit is discarded. Every time the match passes, you lose `cost' credits; if you don't have that many, the test fails. See Alexey's formal explanation in net/sched/sch_tbf.c. To get the maxmum range, we multiply by this factor (ie. you get N credits per jiffy). We want to allow a rate as low as 1 per day (slowest userspace tool allows), which means CREDITS_PER_JIFFY*HZ*60*60*24 < 2^32. ie. */ #define MAX_CPJ (0xFFFFFFFF / (HZ*60*60*24)) /* Repeated shift and or gives us all 1s, final shift and add 1 gives * us the power of 2 below the theoretical max, so GCC simply does a * shift. */ #define _POW2_BELOW2(x) ((x)|((x)>>1)) #define _POW2_BELOW4(x) (_POW2_BELOW2(x)|_POW2_BELOW2((x)>>2)) #define _POW2_BELOW8(x) (_POW2_BELOW4(x)|_POW2_BELOW4((x)>>4)) #define _POW2_BELOW16(x) (_POW2_BELOW8(x)|_POW2_BELOW8((x)>>8)) #define _POW2_BELOW32(x) (_POW2_BELOW16(x)|_POW2_BELOW16((x)>>16)) #define POW2_BELOW32(x) ((_POW2_BELOW32(x)>>1) + 1) #define CREDITS_PER_JIFFY POW2_BELOW32(MAX_CPJ) |
1d93a9cba [NETFILTER]: x_ta... |
64 |
static bool |
62fc80510 netfilter: xtable... |
65 |
limit_mt(const struct sk_buff *skb, struct xt_action_param *par) |
1da177e4c Linux-2.6.12-rc2 |
66 |
{ |
acc738fec netfilter: xtable... |
67 68 |
const struct xt_rateinfo *r = par->matchinfo; struct xt_limit_priv *priv = r->master; |
1da177e4c Linux-2.6.12-rc2 |
69 70 71 |
unsigned long now = jiffies; spin_lock_bh(&limit_lock); |
acc738fec netfilter: xtable... |
72 73 74 |
priv->credit += (now - xchg(&priv->prev, now)) * CREDITS_PER_JIFFY; if (priv->credit > r->credit_cap) priv->credit = r->credit_cap; |
1da177e4c Linux-2.6.12-rc2 |
75 |
|
acc738fec netfilter: xtable... |
76 |
if (priv->credit >= r->cost) { |
1da177e4c Linux-2.6.12-rc2 |
77 |
/* We're not limited. */ |
acc738fec netfilter: xtable... |
78 |
priv->credit -= r->cost; |
1da177e4c Linux-2.6.12-rc2 |
79 |
spin_unlock_bh(&limit_lock); |
1d93a9cba [NETFILTER]: x_ta... |
80 |
return true; |
1da177e4c Linux-2.6.12-rc2 |
81 |
} |
601e68e10 [NETFILTER]: Fix ... |
82 |
spin_unlock_bh(&limit_lock); |
1d93a9cba [NETFILTER]: x_ta... |
83 |
return false; |
1da177e4c Linux-2.6.12-rc2 |
84 85 86 87 88 89 90 91 92 |
} /* Precision saver. */ static u_int32_t user2credits(u_int32_t user) { /* If multiplying would overflow... */ if (user > 0xFFFFFFFF / (HZ*CREDITS_PER_JIFFY)) /* Divide first. */ |
2e4e6a17a [NETFILTER] x_tab... |
93 |
return (user / XT_LIMIT_SCALE) * HZ * CREDITS_PER_JIFFY; |
1da177e4c Linux-2.6.12-rc2 |
94 |
|
2e4e6a17a [NETFILTER] x_tab... |
95 |
return (user * HZ * CREDITS_PER_JIFFY) / XT_LIMIT_SCALE; |
1da177e4c Linux-2.6.12-rc2 |
96 |
} |
b0f38452f netfilter: xtable... |
97 |
static int limit_mt_check(const struct xt_mtchk_param *par) |
1da177e4c Linux-2.6.12-rc2 |
98 |
{ |
9b4fce7a3 netfilter: xtable... |
99 |
struct xt_rateinfo *r = par->matchinfo; |
acc738fec netfilter: xtable... |
100 |
struct xt_limit_priv *priv; |
1da177e4c Linux-2.6.12-rc2 |
101 |
|
1da177e4c Linux-2.6.12-rc2 |
102 103 104 |
/* Check for overflow. */ if (r->burst == 0 || user2credits(r->avg * r->burst) < user2credits(r->avg)) { |
8bee4bad0 netfilter: xt ext... |
105 106 107 |
pr_info("Overflow, try lower: %u/%u ", r->avg, r->burst); |
4a5a5c73b netfilter: xtable... |
108 |
return -ERANGE; |
1da177e4c Linux-2.6.12-rc2 |
109 |
} |
acc738fec netfilter: xtable... |
110 111 |
priv = kmalloc(sizeof(*priv), GFP_KERNEL); if (priv == NULL) |
4a5a5c73b netfilter: xtable... |
112 |
return -ENOMEM; |
acc738fec netfilter: xtable... |
113 114 115 |
/* For SMP, we only want to use one set of state. */ r->master = priv; |
57dab5d0b [NETFILTER]: xt_l... |
116 117 118 |
if (r->cost == 0) { /* User avg in seconds * XT_LIMIT_SCALE: convert to jiffies * 128. */ |
acc738fec netfilter: xtable... |
119 120 |
priv->prev = jiffies; priv->credit = user2credits(r->avg * r->burst); /* Credits full. */ |
57dab5d0b [NETFILTER]: xt_l... |
121 122 123 |
r->credit_cap = user2credits(r->avg * r->burst); /* Credits full. */ r->cost = user2credits(r->avg); } |
bd414ee60 netfilter: xtable... |
124 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
125 |
} |
acc738fec netfilter: xtable... |
126 127 128 129 130 131 |
static void limit_mt_destroy(const struct xt_mtdtor_param *par) { const struct xt_rateinfo *info = par->matchinfo; kfree(info->master); } |
02c63cf77 [NETFILTER]: xt_l... |
132 133 134 135 136 137 138 139 140 141 142 143 144 145 |
#ifdef CONFIG_COMPAT struct compat_xt_rateinfo { u_int32_t avg; u_int32_t burst; compat_ulong_t prev; u_int32_t credit; u_int32_t credit_cap, cost; u_int32_t master; }; /* To keep the full "prev" timestamp, the upper 32 bits are stored in the * master pointer, which does not need to be preserved. */ |
739674fb7 netfilter: xtable... |
146 |
static void limit_mt_compat_from_user(void *dst, const void *src) |
02c63cf77 [NETFILTER]: xt_l... |
147 |
{ |
a47362a22 [NETFILTER]: add ... |
148 |
const struct compat_xt_rateinfo *cm = src; |
02c63cf77 [NETFILTER]: xt_l... |
149 150 151 152 153 154 155 156 157 158 |
struct xt_rateinfo m = { .avg = cm->avg, .burst = cm->burst, .prev = cm->prev | (unsigned long)cm->master << 32, .credit = cm->credit, .credit_cap = cm->credit_cap, .cost = cm->cost, }; memcpy(dst, &m, sizeof(m)); } |
739674fb7 netfilter: xtable... |
159 |
static int limit_mt_compat_to_user(void __user *dst, const void *src) |
02c63cf77 [NETFILTER]: xt_l... |
160 |
{ |
a47362a22 [NETFILTER]: add ... |
161 |
const struct xt_rateinfo *m = src; |
02c63cf77 [NETFILTER]: xt_l... |
162 163 164 165 166 167 168 169 170 171 172 173 |
struct compat_xt_rateinfo cm = { .avg = m->avg, .burst = m->burst, .prev = m->prev, .credit = m->credit, .credit_cap = m->credit_cap, .cost = m->cost, .master = m->prev >> 32, }; return copy_to_user(dst, &cm, sizeof(cm)) ? -EFAULT : 0; } #endif /* CONFIG_COMPAT */ |
55b69e910 netfilter: implem... |
174 175 176 177 178 179 |
static struct xt_match limit_mt_reg __read_mostly = { .name = "limit", .revision = 0, .family = NFPROTO_UNSPEC, .match = limit_mt, .checkentry = limit_mt_check, |
acc738fec netfilter: xtable... |
180 |
.destroy = limit_mt_destroy, |
55b69e910 netfilter: implem... |
181 |
.matchsize = sizeof(struct xt_rateinfo), |
02c63cf77 [NETFILTER]: xt_l... |
182 |
#ifdef CONFIG_COMPAT |
55b69e910 netfilter: implem... |
183 184 185 |
.compatsize = sizeof(struct compat_xt_rateinfo), .compat_from_user = limit_mt_compat_from_user, .compat_to_user = limit_mt_compat_to_user, |
02c63cf77 [NETFILTER]: xt_l... |
186 |
#endif |
55b69e910 netfilter: implem... |
187 |
.me = THIS_MODULE, |
1da177e4c Linux-2.6.12-rc2 |
188 |
}; |
d3c5ee6d5 [NETFILTER]: x_ta... |
189 |
static int __init limit_mt_init(void) |
1da177e4c Linux-2.6.12-rc2 |
190 |
{ |
55b69e910 netfilter: implem... |
191 |
return xt_register_match(&limit_mt_reg); |
1da177e4c Linux-2.6.12-rc2 |
192 |
} |
d3c5ee6d5 [NETFILTER]: x_ta... |
193 |
static void __exit limit_mt_exit(void) |
1da177e4c Linux-2.6.12-rc2 |
194 |
{ |
55b69e910 netfilter: implem... |
195 |
xt_unregister_match(&limit_mt_reg); |
1da177e4c Linux-2.6.12-rc2 |
196 |
} |
d3c5ee6d5 [NETFILTER]: x_ta... |
197 198 |
module_init(limit_mt_init); module_exit(limit_mt_exit); |