0001
0002
0003
0004
0005
0006 #include <linux/kernel.h>
0007 #include <linux/init.h>
0008 #include <linux/module.h>
0009 #include <linux/atomic.h>
0010 #include <linux/netlink.h>
0011 #include <linux/netfilter.h>
0012 #include <linux/netfilter/nf_tables.h>
0013 #include <net/netfilter/nf_tables.h>
0014
0015 struct nft_quota {
0016 atomic64_t quota;
0017 unsigned long flags;
0018 atomic64_t *consumed;
0019 };
0020
0021 static inline bool nft_overquota(struct nft_quota *priv,
0022 const struct sk_buff *skb)
0023 {
0024 return atomic64_add_return(skb->len, priv->consumed) >=
0025 atomic64_read(&priv->quota);
0026 }
0027
0028 static inline bool nft_quota_invert(struct nft_quota *priv)
0029 {
0030 return priv->flags & NFT_QUOTA_F_INV;
0031 }
0032
0033 static inline void nft_quota_do_eval(struct nft_quota *priv,
0034 struct nft_regs *regs,
0035 const struct nft_pktinfo *pkt)
0036 {
0037 if (nft_overquota(priv, pkt->skb) ^ nft_quota_invert(priv))
0038 regs->verdict.code = NFT_BREAK;
0039 }
0040
0041 static const struct nla_policy nft_quota_policy[NFTA_QUOTA_MAX + 1] = {
0042 [NFTA_QUOTA_BYTES] = { .type = NLA_U64 },
0043 [NFTA_QUOTA_FLAGS] = { .type = NLA_U32 },
0044 [NFTA_QUOTA_CONSUMED] = { .type = NLA_U64 },
0045 };
0046
0047 #define NFT_QUOTA_DEPLETED_BIT 1
0048
0049 static void nft_quota_obj_eval(struct nft_object *obj,
0050 struct nft_regs *regs,
0051 const struct nft_pktinfo *pkt)
0052 {
0053 struct nft_quota *priv = nft_obj_data(obj);
0054 bool overquota;
0055
0056 overquota = nft_overquota(priv, pkt->skb);
0057 if (overquota ^ nft_quota_invert(priv))
0058 regs->verdict.code = NFT_BREAK;
0059
0060 if (overquota &&
0061 !test_and_set_bit(NFT_QUOTA_DEPLETED_BIT, &priv->flags))
0062 nft_obj_notify(nft_net(pkt), obj->key.table, obj, 0, 0,
0063 NFT_MSG_NEWOBJ, 0, nft_pf(pkt), 0, GFP_ATOMIC);
0064 }
0065
0066 static int nft_quota_do_init(const struct nlattr * const tb[],
0067 struct nft_quota *priv)
0068 {
0069 unsigned long flags = 0;
0070 u64 quota, consumed = 0;
0071
0072 if (!tb[NFTA_QUOTA_BYTES])
0073 return -EINVAL;
0074
0075 quota = be64_to_cpu(nla_get_be64(tb[NFTA_QUOTA_BYTES]));
0076 if (quota > S64_MAX)
0077 return -EOVERFLOW;
0078
0079 if (tb[NFTA_QUOTA_CONSUMED]) {
0080 consumed = be64_to_cpu(nla_get_be64(tb[NFTA_QUOTA_CONSUMED]));
0081 if (consumed > quota)
0082 return -EINVAL;
0083 }
0084
0085 if (tb[NFTA_QUOTA_FLAGS]) {
0086 flags = ntohl(nla_get_be32(tb[NFTA_QUOTA_FLAGS]));
0087 if (flags & ~NFT_QUOTA_F_INV)
0088 return -EINVAL;
0089 if (flags & NFT_QUOTA_F_DEPLETED)
0090 return -EOPNOTSUPP;
0091 }
0092
0093 priv->consumed = kmalloc(sizeof(*priv->consumed), GFP_KERNEL_ACCOUNT);
0094 if (!priv->consumed)
0095 return -ENOMEM;
0096
0097 atomic64_set(&priv->quota, quota);
0098 priv->flags = flags;
0099 atomic64_set(priv->consumed, consumed);
0100
0101 return 0;
0102 }
0103
0104 static void nft_quota_do_destroy(const struct nft_ctx *ctx,
0105 struct nft_quota *priv)
0106 {
0107 kfree(priv->consumed);
0108 }
0109
0110 static int nft_quota_obj_init(const struct nft_ctx *ctx,
0111 const struct nlattr * const tb[],
0112 struct nft_object *obj)
0113 {
0114 struct nft_quota *priv = nft_obj_data(obj);
0115
0116 return nft_quota_do_init(tb, priv);
0117 }
0118
0119 static void nft_quota_obj_update(struct nft_object *obj,
0120 struct nft_object *newobj)
0121 {
0122 struct nft_quota *newpriv = nft_obj_data(newobj);
0123 struct nft_quota *priv = nft_obj_data(obj);
0124 u64 newquota;
0125
0126 newquota = atomic64_read(&newpriv->quota);
0127 atomic64_set(&priv->quota, newquota);
0128 priv->flags = newpriv->flags;
0129 }
0130
0131 static int nft_quota_do_dump(struct sk_buff *skb, struct nft_quota *priv,
0132 bool reset)
0133 {
0134 u64 consumed, consumed_cap, quota;
0135 u32 flags = priv->flags;
0136
0137
0138
0139
0140
0141 consumed = atomic64_read(priv->consumed);
0142 quota = atomic64_read(&priv->quota);
0143 if (consumed >= quota) {
0144 consumed_cap = quota;
0145 flags |= NFT_QUOTA_F_DEPLETED;
0146 } else {
0147 consumed_cap = consumed;
0148 }
0149
0150 if (nla_put_be64(skb, NFTA_QUOTA_BYTES, cpu_to_be64(quota),
0151 NFTA_QUOTA_PAD) ||
0152 nla_put_be64(skb, NFTA_QUOTA_CONSUMED, cpu_to_be64(consumed_cap),
0153 NFTA_QUOTA_PAD) ||
0154 nla_put_be32(skb, NFTA_QUOTA_FLAGS, htonl(flags)))
0155 goto nla_put_failure;
0156
0157 if (reset) {
0158 atomic64_sub(consumed, priv->consumed);
0159 clear_bit(NFT_QUOTA_DEPLETED_BIT, &priv->flags);
0160 }
0161 return 0;
0162
0163 nla_put_failure:
0164 return -1;
0165 }
0166
0167 static int nft_quota_obj_dump(struct sk_buff *skb, struct nft_object *obj,
0168 bool reset)
0169 {
0170 struct nft_quota *priv = nft_obj_data(obj);
0171
0172 return nft_quota_do_dump(skb, priv, reset);
0173 }
0174
0175 static void nft_quota_obj_destroy(const struct nft_ctx *ctx,
0176 struct nft_object *obj)
0177 {
0178 struct nft_quota *priv = nft_obj_data(obj);
0179
0180 return nft_quota_do_destroy(ctx, priv);
0181 }
0182
0183 static struct nft_object_type nft_quota_obj_type;
0184 static const struct nft_object_ops nft_quota_obj_ops = {
0185 .type = &nft_quota_obj_type,
0186 .size = sizeof(struct nft_quota),
0187 .init = nft_quota_obj_init,
0188 .destroy = nft_quota_obj_destroy,
0189 .eval = nft_quota_obj_eval,
0190 .dump = nft_quota_obj_dump,
0191 .update = nft_quota_obj_update,
0192 };
0193
0194 static struct nft_object_type nft_quota_obj_type __read_mostly = {
0195 .type = NFT_OBJECT_QUOTA,
0196 .ops = &nft_quota_obj_ops,
0197 .maxattr = NFTA_QUOTA_MAX,
0198 .policy = nft_quota_policy,
0199 .owner = THIS_MODULE,
0200 };
0201
0202 static void nft_quota_eval(const struct nft_expr *expr,
0203 struct nft_regs *regs,
0204 const struct nft_pktinfo *pkt)
0205 {
0206 struct nft_quota *priv = nft_expr_priv(expr);
0207
0208 nft_quota_do_eval(priv, regs, pkt);
0209 }
0210
0211 static int nft_quota_init(const struct nft_ctx *ctx,
0212 const struct nft_expr *expr,
0213 const struct nlattr * const tb[])
0214 {
0215 struct nft_quota *priv = nft_expr_priv(expr);
0216
0217 return nft_quota_do_init(tb, priv);
0218 }
0219
0220 static int nft_quota_dump(struct sk_buff *skb, const struct nft_expr *expr)
0221 {
0222 struct nft_quota *priv = nft_expr_priv(expr);
0223
0224 return nft_quota_do_dump(skb, priv, false);
0225 }
0226
0227 static void nft_quota_destroy(const struct nft_ctx *ctx,
0228 const struct nft_expr *expr)
0229 {
0230 struct nft_quota *priv = nft_expr_priv(expr);
0231
0232 return nft_quota_do_destroy(ctx, priv);
0233 }
0234
0235 static int nft_quota_clone(struct nft_expr *dst, const struct nft_expr *src)
0236 {
0237 struct nft_quota *priv_dst = nft_expr_priv(dst);
0238
0239 priv_dst->consumed = kmalloc(sizeof(*priv_dst->consumed), GFP_ATOMIC);
0240 if (!priv_dst->consumed)
0241 return -ENOMEM;
0242
0243 atomic64_set(priv_dst->consumed, 0);
0244
0245 return 0;
0246 }
0247
0248 static struct nft_expr_type nft_quota_type;
0249 static const struct nft_expr_ops nft_quota_ops = {
0250 .type = &nft_quota_type,
0251 .size = NFT_EXPR_SIZE(sizeof(struct nft_quota)),
0252 .eval = nft_quota_eval,
0253 .init = nft_quota_init,
0254 .destroy = nft_quota_destroy,
0255 .clone = nft_quota_clone,
0256 .dump = nft_quota_dump,
0257 .reduce = NFT_REDUCE_READONLY,
0258 };
0259
0260 static struct nft_expr_type nft_quota_type __read_mostly = {
0261 .name = "quota",
0262 .ops = &nft_quota_ops,
0263 .policy = nft_quota_policy,
0264 .maxattr = NFTA_QUOTA_MAX,
0265 .flags = NFT_EXPR_STATEFUL,
0266 .owner = THIS_MODULE,
0267 };
0268
0269 static int __init nft_quota_module_init(void)
0270 {
0271 int err;
0272
0273 err = nft_register_obj(&nft_quota_obj_type);
0274 if (err < 0)
0275 return err;
0276
0277 err = nft_register_expr(&nft_quota_type);
0278 if (err < 0)
0279 goto err1;
0280
0281 return 0;
0282 err1:
0283 nft_unregister_obj(&nft_quota_obj_type);
0284 return err;
0285 }
0286
0287 static void __exit nft_quota_module_exit(void)
0288 {
0289 nft_unregister_expr(&nft_quota_type);
0290 nft_unregister_obj(&nft_quota_obj_type);
0291 }
0292
0293 module_init(nft_quota_module_init);
0294 module_exit(nft_quota_module_exit);
0295
0296 MODULE_LICENSE("GPL");
0297 MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>");
0298 MODULE_ALIAS_NFT_EXPR("quota");
0299 MODULE_ALIAS_NFT_OBJ(NFT_OBJECT_QUOTA);
0300 MODULE_DESCRIPTION("Netfilter nftables quota module");