Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (c) 2016 Pablo Neira Ayuso <pablo@netfilter.org>
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   /* From NFT_QUOTA_F_DEPLETED. */
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     /* Since we inconditionally increment consumed quota for each packet
0138      * that we see, don't go over the quota boundary in what we send to
0139      * userspace.
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");