0001
0002 #include <linux/kernel.h>
0003 #include <linux/init.h>
0004 #include <linux/module.h>
0005 #include <linux/spinlock.h>
0006 #include <linux/netlink.h>
0007 #include <linux/netfilter.h>
0008 #include <linux/netfilter/nf_tables.h>
0009 #include <net/netfilter/nf_tables.h>
0010 #include <net/netfilter/nf_conntrack.h>
0011 #include <net/netfilter/nf_conntrack_count.h>
0012 #include <net/netfilter/nf_conntrack_core.h>
0013 #include <net/netfilter/nf_conntrack_tuple.h>
0014 #include <net/netfilter/nf_conntrack_zones.h>
0015
0016 struct nft_connlimit {
0017 struct nf_conncount_list *list;
0018 u32 limit;
0019 bool invert;
0020 };
0021
0022 static inline void nft_connlimit_do_eval(struct nft_connlimit *priv,
0023 struct nft_regs *regs,
0024 const struct nft_pktinfo *pkt,
0025 const struct nft_set_ext *ext)
0026 {
0027 const struct nf_conntrack_zone *zone = &nf_ct_zone_dflt;
0028 const struct nf_conntrack_tuple *tuple_ptr;
0029 struct nf_conntrack_tuple tuple;
0030 enum ip_conntrack_info ctinfo;
0031 const struct nf_conn *ct;
0032 unsigned int count;
0033
0034 tuple_ptr = &tuple;
0035
0036 ct = nf_ct_get(pkt->skb, &ctinfo);
0037 if (ct != NULL) {
0038 tuple_ptr = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
0039 zone = nf_ct_zone(ct);
0040 } else if (!nf_ct_get_tuplepr(pkt->skb, skb_network_offset(pkt->skb),
0041 nft_pf(pkt), nft_net(pkt), &tuple)) {
0042 regs->verdict.code = NF_DROP;
0043 return;
0044 }
0045
0046 if (nf_conncount_add(nft_net(pkt), priv->list, tuple_ptr, zone)) {
0047 regs->verdict.code = NF_DROP;
0048 return;
0049 }
0050
0051 count = priv->list->count;
0052
0053 if ((count > priv->limit) ^ priv->invert) {
0054 regs->verdict.code = NFT_BREAK;
0055 return;
0056 }
0057 }
0058
0059 static int nft_connlimit_do_init(const struct nft_ctx *ctx,
0060 const struct nlattr * const tb[],
0061 struct nft_connlimit *priv)
0062 {
0063 bool invert = false;
0064 u32 flags, limit;
0065 int err;
0066
0067 if (!tb[NFTA_CONNLIMIT_COUNT])
0068 return -EINVAL;
0069
0070 limit = ntohl(nla_get_be32(tb[NFTA_CONNLIMIT_COUNT]));
0071
0072 if (tb[NFTA_CONNLIMIT_FLAGS]) {
0073 flags = ntohl(nla_get_be32(tb[NFTA_CONNLIMIT_FLAGS]));
0074 if (flags & ~NFT_CONNLIMIT_F_INV)
0075 return -EOPNOTSUPP;
0076 if (flags & NFT_CONNLIMIT_F_INV)
0077 invert = true;
0078 }
0079
0080 priv->list = kmalloc(sizeof(*priv->list), GFP_KERNEL_ACCOUNT);
0081 if (!priv->list)
0082 return -ENOMEM;
0083
0084 nf_conncount_list_init(priv->list);
0085 priv->limit = limit;
0086 priv->invert = invert;
0087
0088 err = nf_ct_netns_get(ctx->net, ctx->family);
0089 if (err < 0)
0090 goto err_netns;
0091
0092 return 0;
0093 err_netns:
0094 kfree(priv->list);
0095
0096 return err;
0097 }
0098
0099 static void nft_connlimit_do_destroy(const struct nft_ctx *ctx,
0100 struct nft_connlimit *priv)
0101 {
0102 nf_ct_netns_put(ctx->net, ctx->family);
0103 nf_conncount_cache_free(priv->list);
0104 kfree(priv->list);
0105 }
0106
0107 static int nft_connlimit_do_dump(struct sk_buff *skb,
0108 struct nft_connlimit *priv)
0109 {
0110 if (nla_put_be32(skb, NFTA_CONNLIMIT_COUNT, htonl(priv->limit)))
0111 goto nla_put_failure;
0112 if (priv->invert &&
0113 nla_put_be32(skb, NFTA_CONNLIMIT_FLAGS, htonl(NFT_CONNLIMIT_F_INV)))
0114 goto nla_put_failure;
0115
0116 return 0;
0117
0118 nla_put_failure:
0119 return -1;
0120 }
0121
0122 static inline void nft_connlimit_obj_eval(struct nft_object *obj,
0123 struct nft_regs *regs,
0124 const struct nft_pktinfo *pkt)
0125 {
0126 struct nft_connlimit *priv = nft_obj_data(obj);
0127
0128 nft_connlimit_do_eval(priv, regs, pkt, NULL);
0129 }
0130
0131 static int nft_connlimit_obj_init(const struct nft_ctx *ctx,
0132 const struct nlattr * const tb[],
0133 struct nft_object *obj)
0134 {
0135 struct nft_connlimit *priv = nft_obj_data(obj);
0136
0137 return nft_connlimit_do_init(ctx, tb, priv);
0138 }
0139
0140 static void nft_connlimit_obj_destroy(const struct nft_ctx *ctx,
0141 struct nft_object *obj)
0142 {
0143 struct nft_connlimit *priv = nft_obj_data(obj);
0144
0145 nft_connlimit_do_destroy(ctx, priv);
0146 }
0147
0148 static int nft_connlimit_obj_dump(struct sk_buff *skb,
0149 struct nft_object *obj, bool reset)
0150 {
0151 struct nft_connlimit *priv = nft_obj_data(obj);
0152
0153 return nft_connlimit_do_dump(skb, priv);
0154 }
0155
0156 static const struct nla_policy nft_connlimit_policy[NFTA_CONNLIMIT_MAX + 1] = {
0157 [NFTA_CONNLIMIT_COUNT] = { .type = NLA_U32 },
0158 [NFTA_CONNLIMIT_FLAGS] = { .type = NLA_U32 },
0159 };
0160
0161 static struct nft_object_type nft_connlimit_obj_type;
0162 static const struct nft_object_ops nft_connlimit_obj_ops = {
0163 .type = &nft_connlimit_obj_type,
0164 .size = sizeof(struct nft_connlimit),
0165 .eval = nft_connlimit_obj_eval,
0166 .init = nft_connlimit_obj_init,
0167 .destroy = nft_connlimit_obj_destroy,
0168 .dump = nft_connlimit_obj_dump,
0169 };
0170
0171 static struct nft_object_type nft_connlimit_obj_type __read_mostly = {
0172 .type = NFT_OBJECT_CONNLIMIT,
0173 .ops = &nft_connlimit_obj_ops,
0174 .maxattr = NFTA_CONNLIMIT_MAX,
0175 .policy = nft_connlimit_policy,
0176 .owner = THIS_MODULE,
0177 };
0178
0179 static void nft_connlimit_eval(const struct nft_expr *expr,
0180 struct nft_regs *regs,
0181 const struct nft_pktinfo *pkt)
0182 {
0183 struct nft_connlimit *priv = nft_expr_priv(expr);
0184
0185 nft_connlimit_do_eval(priv, regs, pkt, NULL);
0186 }
0187
0188 static int nft_connlimit_dump(struct sk_buff *skb, const struct nft_expr *expr)
0189 {
0190 struct nft_connlimit *priv = nft_expr_priv(expr);
0191
0192 return nft_connlimit_do_dump(skb, priv);
0193 }
0194
0195 static int nft_connlimit_init(const struct nft_ctx *ctx,
0196 const struct nft_expr *expr,
0197 const struct nlattr * const tb[])
0198 {
0199 struct nft_connlimit *priv = nft_expr_priv(expr);
0200
0201 return nft_connlimit_do_init(ctx, tb, priv);
0202 }
0203
0204 static void nft_connlimit_destroy(const struct nft_ctx *ctx,
0205 const struct nft_expr *expr)
0206 {
0207 struct nft_connlimit *priv = nft_expr_priv(expr);
0208
0209 nft_connlimit_do_destroy(ctx, priv);
0210 }
0211
0212 static int nft_connlimit_clone(struct nft_expr *dst, const struct nft_expr *src)
0213 {
0214 struct nft_connlimit *priv_dst = nft_expr_priv(dst);
0215 struct nft_connlimit *priv_src = nft_expr_priv(src);
0216
0217 priv_dst->list = kmalloc(sizeof(*priv_dst->list), GFP_ATOMIC);
0218 if (!priv_dst->list)
0219 return -ENOMEM;
0220
0221 nf_conncount_list_init(priv_dst->list);
0222 priv_dst->limit = priv_src->limit;
0223 priv_dst->invert = priv_src->invert;
0224
0225 return 0;
0226 }
0227
0228 static void nft_connlimit_destroy_clone(const struct nft_ctx *ctx,
0229 const struct nft_expr *expr)
0230 {
0231 struct nft_connlimit *priv = nft_expr_priv(expr);
0232
0233 nf_conncount_cache_free(priv->list);
0234 kfree(priv->list);
0235 }
0236
0237 static bool nft_connlimit_gc(struct net *net, const struct nft_expr *expr)
0238 {
0239 struct nft_connlimit *priv = nft_expr_priv(expr);
0240 bool ret;
0241
0242 local_bh_disable();
0243 ret = nf_conncount_gc_list(net, priv->list);
0244 local_bh_enable();
0245
0246 return ret;
0247 }
0248
0249 static struct nft_expr_type nft_connlimit_type;
0250 static const struct nft_expr_ops nft_connlimit_ops = {
0251 .type = &nft_connlimit_type,
0252 .size = NFT_EXPR_SIZE(sizeof(struct nft_connlimit)),
0253 .eval = nft_connlimit_eval,
0254 .init = nft_connlimit_init,
0255 .destroy = nft_connlimit_destroy,
0256 .clone = nft_connlimit_clone,
0257 .destroy_clone = nft_connlimit_destroy_clone,
0258 .dump = nft_connlimit_dump,
0259 .gc = nft_connlimit_gc,
0260 .reduce = NFT_REDUCE_READONLY,
0261 };
0262
0263 static struct nft_expr_type nft_connlimit_type __read_mostly = {
0264 .name = "connlimit",
0265 .ops = &nft_connlimit_ops,
0266 .policy = nft_connlimit_policy,
0267 .maxattr = NFTA_CONNLIMIT_MAX,
0268 .flags = NFT_EXPR_STATEFUL | NFT_EXPR_GC,
0269 .owner = THIS_MODULE,
0270 };
0271
0272 static int __init nft_connlimit_module_init(void)
0273 {
0274 int err;
0275
0276 err = nft_register_obj(&nft_connlimit_obj_type);
0277 if (err < 0)
0278 return err;
0279
0280 err = nft_register_expr(&nft_connlimit_type);
0281 if (err < 0)
0282 goto err1;
0283
0284 return 0;
0285 err1:
0286 nft_unregister_obj(&nft_connlimit_obj_type);
0287 return err;
0288 }
0289
0290 static void __exit nft_connlimit_module_exit(void)
0291 {
0292 nft_unregister_expr(&nft_connlimit_type);
0293 nft_unregister_obj(&nft_connlimit_obj_type);
0294 }
0295
0296 module_init(nft_connlimit_module_init);
0297 module_exit(nft_connlimit_module_exit);
0298
0299 MODULE_LICENSE("GPL");
0300 MODULE_AUTHOR("Pablo Neira Ayuso");
0301 MODULE_ALIAS_NFT_EXPR("connlimit");
0302 MODULE_ALIAS_NFT_OBJ(NFT_OBJECT_CONNLIMIT);
0303 MODULE_DESCRIPTION("nftables connlimit rule support");