1 /* SPDX-License-Identifier: GPL-2.0 */
2 #include <linux/kernel.h>
3 #include <linux/init.h>
4 #include <linux/module.h>
5 #include <linux/spinlock.h>
6 #include <linux/netlink.h>
7 #include <linux/netfilter.h>
8 #include <linux/netfilter/nf_tables.h>
9 #include <net/netfilter/nf_tables.h>
10 #include <net/netfilter/nf_conntrack.h>
11 #include <net/netfilter/nf_conntrack_count.h>
12 #include <net/netfilter/nf_conntrack_core.h>
13 #include <net/netfilter/nf_conntrack_tuple.h>
14 #include <net/netfilter/nf_conntrack_zones.h>
16 struct nft_connlimit
{
17 struct nf_conncount_list list
;
22 static inline void nft_connlimit_do_eval(struct nft_connlimit
*priv
,
23 struct nft_regs
*regs
,
24 const struct nft_pktinfo
*pkt
,
25 const struct nft_set_ext
*ext
)
27 const struct nf_conntrack_zone
*zone
= &nf_ct_zone_dflt
;
28 const struct nf_conntrack_tuple
*tuple_ptr
;
29 struct nf_conntrack_tuple tuple
;
30 enum ip_conntrack_info ctinfo
;
31 const struct nf_conn
*ct
;
37 ct
= nf_ct_get(pkt
->skb
, &ctinfo
);
39 tuple_ptr
= &ct
->tuplehash
[IP_CT_DIR_ORIGINAL
].tuple
;
40 zone
= nf_ct_zone(ct
);
41 } else if (!nf_ct_get_tuplepr(pkt
->skb
, skb_network_offset(pkt
->skb
),
42 nft_pf(pkt
), nft_net(pkt
), &tuple
)) {
43 regs
->verdict
.code
= NF_DROP
;
47 nf_conncount_lookup(nft_net(pkt
), &priv
->list
, tuple_ptr
, zone
,
49 count
= priv
->list
.count
;
54 if (nf_conncount_add(&priv
->list
, tuple_ptr
, zone
) == NF_CONNCOUNT_ERR
) {
55 regs
->verdict
.code
= NF_DROP
;
61 if ((count
> priv
->limit
) ^ priv
->invert
) {
62 regs
->verdict
.code
= NFT_BREAK
;
67 static int nft_connlimit_do_init(const struct nft_ctx
*ctx
,
68 const struct nlattr
* const tb
[],
69 struct nft_connlimit
*priv
)
74 if (!tb
[NFTA_CONNLIMIT_COUNT
])
77 limit
= ntohl(nla_get_be32(tb
[NFTA_CONNLIMIT_COUNT
]));
79 if (tb
[NFTA_CONNLIMIT_FLAGS
]) {
80 flags
= ntohl(nla_get_be32(tb
[NFTA_CONNLIMIT_FLAGS
]));
81 if (flags
& ~NFT_CONNLIMIT_F_INV
)
83 if (flags
& NFT_CONNLIMIT_F_INV
)
87 nf_conncount_list_init(&priv
->list
);
89 priv
->invert
= invert
;
91 return nf_ct_netns_get(ctx
->net
, ctx
->family
);
94 static void nft_connlimit_do_destroy(const struct nft_ctx
*ctx
,
95 struct nft_connlimit
*priv
)
97 nf_ct_netns_put(ctx
->net
, ctx
->family
);
98 nf_conncount_cache_free(&priv
->list
);
101 static int nft_connlimit_do_dump(struct sk_buff
*skb
,
102 struct nft_connlimit
*priv
)
104 if (nla_put_be32(skb
, NFTA_CONNLIMIT_COUNT
, htonl(priv
->limit
)))
105 goto nla_put_failure
;
107 nla_put_be32(skb
, NFTA_CONNLIMIT_FLAGS
, htonl(NFT_CONNLIMIT_F_INV
)))
108 goto nla_put_failure
;
116 static inline void nft_connlimit_obj_eval(struct nft_object
*obj
,
117 struct nft_regs
*regs
,
118 const struct nft_pktinfo
*pkt
)
120 struct nft_connlimit
*priv
= nft_obj_data(obj
);
122 nft_connlimit_do_eval(priv
, regs
, pkt
, NULL
);
125 static int nft_connlimit_obj_init(const struct nft_ctx
*ctx
,
126 const struct nlattr
* const tb
[],
127 struct nft_object
*obj
)
129 struct nft_connlimit
*priv
= nft_obj_data(obj
);
131 return nft_connlimit_do_init(ctx
, tb
, priv
);
134 static void nft_connlimit_obj_destroy(const struct nft_ctx
*ctx
,
135 struct nft_object
*obj
)
137 struct nft_connlimit
*priv
= nft_obj_data(obj
);
139 nft_connlimit_do_destroy(ctx
, priv
);
142 static int nft_connlimit_obj_dump(struct sk_buff
*skb
,
143 struct nft_object
*obj
, bool reset
)
145 struct nft_connlimit
*priv
= nft_obj_data(obj
);
147 return nft_connlimit_do_dump(skb
, priv
);
150 static const struct nla_policy nft_connlimit_policy
[NFTA_CONNLIMIT_MAX
+ 1] = {
151 [NFTA_CONNLIMIT_COUNT
] = { .type
= NLA_U32
},
152 [NFTA_CONNLIMIT_FLAGS
] = { .type
= NLA_U32
},
155 static struct nft_object_type nft_connlimit_obj_type
;
156 static const struct nft_object_ops nft_connlimit_obj_ops
= {
157 .type
= &nft_connlimit_obj_type
,
158 .size
= sizeof(struct nft_connlimit
),
159 .eval
= nft_connlimit_obj_eval
,
160 .init
= nft_connlimit_obj_init
,
161 .destroy
= nft_connlimit_obj_destroy
,
162 .dump
= nft_connlimit_obj_dump
,
165 static struct nft_object_type nft_connlimit_obj_type __read_mostly
= {
166 .type
= NFT_OBJECT_CONNLIMIT
,
167 .ops
= &nft_connlimit_obj_ops
,
168 .maxattr
= NFTA_CONNLIMIT_MAX
,
169 .policy
= nft_connlimit_policy
,
170 .owner
= THIS_MODULE
,
173 static void nft_connlimit_eval(const struct nft_expr
*expr
,
174 struct nft_regs
*regs
,
175 const struct nft_pktinfo
*pkt
)
177 struct nft_connlimit
*priv
= nft_expr_priv(expr
);
179 nft_connlimit_do_eval(priv
, regs
, pkt
, NULL
);
182 static int nft_connlimit_dump(struct sk_buff
*skb
, const struct nft_expr
*expr
)
184 struct nft_connlimit
*priv
= nft_expr_priv(expr
);
186 return nft_connlimit_do_dump(skb
, priv
);
189 static int nft_connlimit_init(const struct nft_ctx
*ctx
,
190 const struct nft_expr
*expr
,
191 const struct nlattr
* const tb
[])
193 struct nft_connlimit
*priv
= nft_expr_priv(expr
);
195 return nft_connlimit_do_init(ctx
, tb
, priv
);
198 static void nft_connlimit_destroy(const struct nft_ctx
*ctx
,
199 const struct nft_expr
*expr
)
201 struct nft_connlimit
*priv
= nft_expr_priv(expr
);
203 nft_connlimit_do_destroy(ctx
, priv
);
206 static int nft_connlimit_clone(struct nft_expr
*dst
, const struct nft_expr
*src
)
208 struct nft_connlimit
*priv_dst
= nft_expr_priv(dst
);
209 struct nft_connlimit
*priv_src
= nft_expr_priv(src
);
211 nf_conncount_list_init(&priv_dst
->list
);
212 priv_dst
->limit
= priv_src
->limit
;
213 priv_dst
->invert
= priv_src
->invert
;
218 static void nft_connlimit_destroy_clone(const struct nft_ctx
*ctx
,
219 const struct nft_expr
*expr
)
221 struct nft_connlimit
*priv
= nft_expr_priv(expr
);
223 nf_conncount_cache_free(&priv
->list
);
226 static bool nft_connlimit_gc(struct net
*net
, const struct nft_expr
*expr
)
228 struct nft_connlimit
*priv
= nft_expr_priv(expr
);
230 return nf_conncount_gc_list(net
, &priv
->list
);
233 static struct nft_expr_type nft_connlimit_type
;
234 static const struct nft_expr_ops nft_connlimit_ops
= {
235 .type
= &nft_connlimit_type
,
236 .size
= NFT_EXPR_SIZE(sizeof(struct nft_connlimit
)),
237 .eval
= nft_connlimit_eval
,
238 .init
= nft_connlimit_init
,
239 .destroy
= nft_connlimit_destroy
,
240 .clone
= nft_connlimit_clone
,
241 .destroy_clone
= nft_connlimit_destroy_clone
,
242 .dump
= nft_connlimit_dump
,
243 .gc
= nft_connlimit_gc
,
246 static struct nft_expr_type nft_connlimit_type __read_mostly
= {
248 .ops
= &nft_connlimit_ops
,
249 .policy
= nft_connlimit_policy
,
250 .maxattr
= NFTA_CONNLIMIT_MAX
,
251 .flags
= NFT_EXPR_STATEFUL
| NFT_EXPR_GC
,
252 .owner
= THIS_MODULE
,
255 static int __init
nft_connlimit_module_init(void)
259 err
= nft_register_obj(&nft_connlimit_obj_type
);
263 err
= nft_register_expr(&nft_connlimit_type
);
269 nft_unregister_obj(&nft_connlimit_obj_type
);
273 static void __exit
nft_connlimit_module_exit(void)
275 nft_unregister_expr(&nft_connlimit_type
);
276 nft_unregister_obj(&nft_connlimit_obj_type
);
279 module_init(nft_connlimit_module_init
);
280 module_exit(nft_connlimit_module_exit
);
282 MODULE_LICENSE("GPL");
283 MODULE_AUTHOR("Pablo Neira Ayuso");
284 MODULE_ALIAS_NFT_EXPR("connlimit");
285 MODULE_ALIAS_NFT_OBJ(NFT_OBJECT_CONNLIMIT
);