0001
0002
0003
0004
0005
0006 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0007
0008 #include <linux/slab.h>
0009 #include <linux/module.h>
0010 #include <linux/skbuff.h>
0011 #include <linux/interrupt.h>
0012
0013 #include <linux/netfilter/x_tables.h>
0014 #include <linux/netfilter/xt_limit.h>
0015
0016 struct xt_limit_priv {
0017 unsigned long prev;
0018 u32 credit;
0019 };
0020
0021 MODULE_LICENSE("GPL");
0022 MODULE_AUTHOR("Herve Eychenne <rv@wallfire.org>");
0023 MODULE_DESCRIPTION("Xtables: rate-limit match");
0024 MODULE_ALIAS("ipt_limit");
0025 MODULE_ALIAS("ip6t_limit");
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048 #define MAX_CPJ (0xFFFFFFFF / (HZ*60*60*24))
0049
0050
0051
0052
0053 #define _POW2_BELOW2(x) ((x)|((x)>>1))
0054 #define _POW2_BELOW4(x) (_POW2_BELOW2(x)|_POW2_BELOW2((x)>>2))
0055 #define _POW2_BELOW8(x) (_POW2_BELOW4(x)|_POW2_BELOW4((x)>>4))
0056 #define _POW2_BELOW16(x) (_POW2_BELOW8(x)|_POW2_BELOW8((x)>>8))
0057 #define _POW2_BELOW32(x) (_POW2_BELOW16(x)|_POW2_BELOW16((x)>>16))
0058 #define POW2_BELOW32(x) ((_POW2_BELOW32(x)>>1) + 1)
0059
0060 #define CREDITS_PER_JIFFY POW2_BELOW32(MAX_CPJ)
0061
0062 static bool
0063 limit_mt(const struct sk_buff *skb, struct xt_action_param *par)
0064 {
0065 const struct xt_rateinfo *r = par->matchinfo;
0066 struct xt_limit_priv *priv = r->master;
0067 unsigned long now;
0068 u32 old_credit, new_credit, credit_increase = 0;
0069 bool ret;
0070
0071
0072 if ((READ_ONCE(priv->credit) < r->cost) && (READ_ONCE(priv->prev) == jiffies))
0073 return false;
0074
0075 do {
0076 now = jiffies;
0077 credit_increase += (now - xchg(&priv->prev, now)) * CREDITS_PER_JIFFY;
0078 old_credit = READ_ONCE(priv->credit);
0079 new_credit = old_credit;
0080 new_credit += credit_increase;
0081 if (new_credit > r->credit_cap)
0082 new_credit = r->credit_cap;
0083 if (new_credit >= r->cost) {
0084 ret = true;
0085 new_credit -= r->cost;
0086 } else {
0087 ret = false;
0088 }
0089 } while (cmpxchg(&priv->credit, old_credit, new_credit) != old_credit);
0090
0091 return ret;
0092 }
0093
0094
0095 static u32 user2credits(u32 user)
0096 {
0097
0098 if (user > 0xFFFFFFFF / (HZ*CREDITS_PER_JIFFY))
0099
0100 return (user / XT_LIMIT_SCALE) * HZ * CREDITS_PER_JIFFY;
0101
0102 return (user * HZ * CREDITS_PER_JIFFY) / XT_LIMIT_SCALE;
0103 }
0104
0105 static int limit_mt_check(const struct xt_mtchk_param *par)
0106 {
0107 struct xt_rateinfo *r = par->matchinfo;
0108 struct xt_limit_priv *priv;
0109
0110
0111 if (r->burst == 0
0112 || user2credits(r->avg * r->burst) < user2credits(r->avg)) {
0113 pr_info_ratelimited("Overflow, try lower: %u/%u\n",
0114 r->avg, r->burst);
0115 return -ERANGE;
0116 }
0117
0118 priv = kmalloc(sizeof(*priv), GFP_KERNEL);
0119 if (priv == NULL)
0120 return -ENOMEM;
0121
0122
0123 r->master = priv;
0124
0125
0126 priv->prev = jiffies;
0127 priv->credit = user2credits(r->avg * r->burst);
0128 if (r->cost == 0) {
0129 r->credit_cap = priv->credit;
0130 r->cost = user2credits(r->avg);
0131 }
0132
0133 return 0;
0134 }
0135
0136 static void limit_mt_destroy(const struct xt_mtdtor_param *par)
0137 {
0138 const struct xt_rateinfo *info = par->matchinfo;
0139
0140 kfree(info->master);
0141 }
0142
0143 #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
0144 struct compat_xt_rateinfo {
0145 u_int32_t avg;
0146 u_int32_t burst;
0147
0148 compat_ulong_t prev;
0149 u_int32_t credit;
0150 u_int32_t credit_cap, cost;
0151
0152 u_int32_t master;
0153 };
0154
0155
0156
0157 static void limit_mt_compat_from_user(void *dst, const void *src)
0158 {
0159 const struct compat_xt_rateinfo *cm = src;
0160 struct xt_rateinfo m = {
0161 .avg = cm->avg,
0162 .burst = cm->burst,
0163 .prev = cm->prev | (unsigned long)cm->master << 32,
0164 .credit = cm->credit,
0165 .credit_cap = cm->credit_cap,
0166 .cost = cm->cost,
0167 };
0168 memcpy(dst, &m, sizeof(m));
0169 }
0170
0171 static int limit_mt_compat_to_user(void __user *dst, const void *src)
0172 {
0173 const struct xt_rateinfo *m = src;
0174 struct compat_xt_rateinfo cm = {
0175 .avg = m->avg,
0176 .burst = m->burst,
0177 .prev = m->prev,
0178 .credit = m->credit,
0179 .credit_cap = m->credit_cap,
0180 .cost = m->cost,
0181 .master = m->prev >> 32,
0182 };
0183 return copy_to_user(dst, &cm, sizeof(cm)) ? -EFAULT : 0;
0184 }
0185 #endif
0186
0187 static struct xt_match limit_mt_reg __read_mostly = {
0188 .name = "limit",
0189 .revision = 0,
0190 .family = NFPROTO_UNSPEC,
0191 .match = limit_mt,
0192 .checkentry = limit_mt_check,
0193 .destroy = limit_mt_destroy,
0194 .matchsize = sizeof(struct xt_rateinfo),
0195 #ifdef CONFIG_NETFILTER_XTABLES_COMPAT
0196 .compatsize = sizeof(struct compat_xt_rateinfo),
0197 .compat_from_user = limit_mt_compat_from_user,
0198 .compat_to_user = limit_mt_compat_to_user,
0199 #endif
0200 .usersize = offsetof(struct xt_rateinfo, prev),
0201 .me = THIS_MODULE,
0202 };
0203
0204 static int __init limit_mt_init(void)
0205 {
0206 return xt_register_match(&limit_mt_reg);
0207 }
0208
0209 static void __exit limit_mt_exit(void)
0210 {
0211 xt_unregister_match(&limit_mt_reg);
0212 }
0213
0214 module_init(limit_mt_init);
0215 module_exit(limit_mt_exit);