Blame view
net/netfilter/xt_limit.c
5.94 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> |
f229f6ce4 netfilter: add my... |
3 |
* (C) 2006-2012 Patrick McHardy <kaber@trash.net> |
1da177e4c Linux-2.6.12-rc2 |
4 5 6 7 8 |
* * 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... |
9 |
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
1da177e4c Linux-2.6.12-rc2 |
10 |
|
5a0e3ad6a include cleanup: ... |
11 |
#include <linux/slab.h> |
1da177e4c Linux-2.6.12-rc2 |
12 13 14 15 |
#include <linux/module.h> #include <linux/skbuff.h> #include <linux/spinlock.h> #include <linux/interrupt.h> |
2e4e6a17a [NETFILTER] x_tab... |
16 17 |
#include <linux/netfilter/x_tables.h> #include <linux/netfilter/xt_limit.h> |
1da177e4c Linux-2.6.12-rc2 |
18 |
|
acc738fec netfilter: xtable... |
19 |
struct xt_limit_priv { |
2cb4bbd75 netfilter: limit:... |
20 |
spinlock_t lock; |
acc738fec netfilter: xtable... |
21 22 23 |
unsigned long prev; uint32_t credit; }; |
1da177e4c Linux-2.6.12-rc2 |
24 25 |
MODULE_LICENSE("GPL"); MODULE_AUTHOR("Herve Eychenne <rv@wallfire.org>"); |
2ae15b64e [NETFILTER]: Upda... |
26 |
MODULE_DESCRIPTION("Xtables: rate-limit match"); |
2e4e6a17a [NETFILTER] x_tab... |
27 28 |
MODULE_ALIAS("ipt_limit"); MODULE_ALIAS("ip6t_limit"); |
1da177e4c Linux-2.6.12-rc2 |
29 30 31 32 |
/* The algorithm used is the Simple Token Bucket Filter (TBF) * see net/sched/sch_tbf.c in the linux source tree */ |
1da177e4c Linux-2.6.12-rc2 |
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 |
/* 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... |
63 |
static bool |
62fc80510 netfilter: xtable... |
64 |
limit_mt(const struct sk_buff *skb, struct xt_action_param *par) |
1da177e4c Linux-2.6.12-rc2 |
65 |
{ |
acc738fec netfilter: xtable... |
66 67 |
const struct xt_rateinfo *r = par->matchinfo; struct xt_limit_priv *priv = r->master; |
1da177e4c Linux-2.6.12-rc2 |
68 |
unsigned long now = jiffies; |
2cb4bbd75 netfilter: limit:... |
69 |
spin_lock_bh(&priv->lock); |
acc738fec netfilter: xtable... |
70 71 72 |
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 |
73 |
|
acc738fec netfilter: xtable... |
74 |
if (priv->credit >= r->cost) { |
1da177e4c Linux-2.6.12-rc2 |
75 |
/* We're not limited. */ |
acc738fec netfilter: xtable... |
76 |
priv->credit -= r->cost; |
2cb4bbd75 netfilter: limit:... |
77 |
spin_unlock_bh(&priv->lock); |
1d93a9cba [NETFILTER]: x_ta... |
78 |
return true; |
1da177e4c Linux-2.6.12-rc2 |
79 |
} |
2cb4bbd75 netfilter: limit:... |
80 |
spin_unlock_bh(&priv->lock); |
1d93a9cba [NETFILTER]: x_ta... |
81 |
return false; |
1da177e4c Linux-2.6.12-rc2 |
82 83 84 |
} /* Precision saver. */ |
7a909ac70 netfilter: limit,... |
85 |
static u32 user2credits(u32 user) |
1da177e4c Linux-2.6.12-rc2 |
86 87 88 89 |
{ /* If multiplying would overflow... */ if (user > 0xFFFFFFFF / (HZ*CREDITS_PER_JIFFY)) /* Divide first. */ |
2e4e6a17a [NETFILTER] x_tab... |
90 |
return (user / XT_LIMIT_SCALE) * HZ * CREDITS_PER_JIFFY; |
1da177e4c Linux-2.6.12-rc2 |
91 |
|
2e4e6a17a [NETFILTER] x_tab... |
92 |
return (user * HZ * CREDITS_PER_JIFFY) / XT_LIMIT_SCALE; |
1da177e4c Linux-2.6.12-rc2 |
93 |
} |
b0f38452f netfilter: xtable... |
94 |
static int limit_mt_check(const struct xt_mtchk_param *par) |
1da177e4c Linux-2.6.12-rc2 |
95 |
{ |
9b4fce7a3 netfilter: xtable... |
96 |
struct xt_rateinfo *r = par->matchinfo; |
acc738fec netfilter: xtable... |
97 |
struct xt_limit_priv *priv; |
1da177e4c Linux-2.6.12-rc2 |
98 |
|
1da177e4c Linux-2.6.12-rc2 |
99 100 101 |
/* Check for overflow. */ if (r->burst == 0 || user2credits(r->avg * r->burst) < user2credits(r->avg)) { |
8bee4bad0 netfilter: xt ext... |
102 103 104 |
pr_info("Overflow, try lower: %u/%u ", r->avg, r->burst); |
4a5a5c73b netfilter: xtable... |
105 |
return -ERANGE; |
1da177e4c Linux-2.6.12-rc2 |
106 |
} |
acc738fec netfilter: xtable... |
107 108 |
priv = kmalloc(sizeof(*priv), GFP_KERNEL); if (priv == NULL) |
4a5a5c73b netfilter: xtable... |
109 |
return -ENOMEM; |
acc738fec netfilter: xtable... |
110 111 112 |
/* For SMP, we only want to use one set of state. */ r->master = priv; |
82e6bfe2f netfilter: xt_lim... |
113 114 115 116 |
/* User avg in seconds * XT_LIMIT_SCALE: convert to jiffies * 128. */ priv->prev = jiffies; priv->credit = user2credits(r->avg * r->burst); /* Credits full. */ |
57dab5d0b [NETFILTER]: xt_l... |
117 |
if (r->cost == 0) { |
7a909ac70 netfilter: limit,... |
118 |
r->credit_cap = priv->credit; /* Credits full. */ |
57dab5d0b [NETFILTER]: xt_l... |
119 120 |
r->cost = user2credits(r->avg); } |
2cb4bbd75 netfilter: limit:... |
121 |
spin_lock_init(&priv->lock); |
bd414ee60 netfilter: xtable... |
122 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
123 |
} |
acc738fec netfilter: xtable... |
124 125 126 127 128 129 |
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... |
130 131 132 133 134 135 136 137 138 139 140 141 142 143 |
#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... |
144 |
static void limit_mt_compat_from_user(void *dst, const void *src) |
02c63cf77 [NETFILTER]: xt_l... |
145 |
{ |
a47362a22 [NETFILTER]: add ... |
146 |
const struct compat_xt_rateinfo *cm = src; |
02c63cf77 [NETFILTER]: xt_l... |
147 148 149 150 151 152 153 154 155 156 |
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... |
157 |
static int limit_mt_compat_to_user(void __user *dst, const void *src) |
02c63cf77 [NETFILTER]: xt_l... |
158 |
{ |
a47362a22 [NETFILTER]: add ... |
159 |
const struct xt_rateinfo *m = src; |
02c63cf77 [NETFILTER]: xt_l... |
160 161 162 163 164 165 166 167 168 169 170 171 |
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... |
172 173 174 175 176 177 |
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... |
178 |
.destroy = limit_mt_destroy, |
55b69e910 netfilter: implem... |
179 |
.matchsize = sizeof(struct xt_rateinfo), |
02c63cf77 [NETFILTER]: xt_l... |
180 |
#ifdef CONFIG_COMPAT |
55b69e910 netfilter: implem... |
181 182 183 |
.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... |
184 |
#endif |
ad10785a7 netfilter: x_tabl... |
185 |
.usersize = offsetof(struct xt_rateinfo, prev), |
55b69e910 netfilter: implem... |
186 |
.me = THIS_MODULE, |
1da177e4c Linux-2.6.12-rc2 |
187 |
}; |
d3c5ee6d5 [NETFILTER]: x_ta... |
188 |
static int __init limit_mt_init(void) |
1da177e4c Linux-2.6.12-rc2 |
189 |
{ |
55b69e910 netfilter: implem... |
190 |
return xt_register_match(&limit_mt_reg); |
1da177e4c Linux-2.6.12-rc2 |
191 |
} |
d3c5ee6d5 [NETFILTER]: x_ta... |
192 |
static void __exit limit_mt_exit(void) |
1da177e4c Linux-2.6.12-rc2 |
193 |
{ |
55b69e910 netfilter: implem... |
194 |
xt_unregister_match(&limit_mt_reg); |
1da177e4c Linux-2.6.12-rc2 |
195 |
} |
d3c5ee6d5 [NETFILTER]: x_ta... |
196 197 |
module_init(limit_mt_init); module_exit(limit_mt_exit); |