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
{
18 struct hlist_head hhead
;
23 static inline void nft_connlimit_do_eval(struct nft_connlimit
*priv
,
24 struct nft_regs
*regs
,
25 const struct nft_pktinfo
*pkt
,
26 const struct nft_set_ext
*ext
)
28 const struct nf_conntrack_zone
*zone
= &nf_ct_zone_dflt
;
29 const struct nf_conntrack_tuple
*tuple_ptr
;
30 struct nf_conntrack_tuple tuple
;
31 enum ip_conntrack_info ctinfo
;
32 const struct nf_conn
*ct
;
38 ct
= nf_ct_get(pkt
->skb
, &ctinfo
);
40 tuple_ptr
= &ct
->tuplehash
[IP_CT_DIR_ORIGINAL
].tuple
;
41 zone
= nf_ct_zone(ct
);
42 } else if (!nf_ct_get_tuplepr(pkt
->skb
, skb_network_offset(pkt
->skb
),
43 nft_pf(pkt
), nft_net(pkt
), &tuple
)) {
44 regs
->verdict
.code
= NF_DROP
;
48 spin_lock_bh(&priv
->lock
);
49 count
= nf_conncount_lookup(nft_net(pkt
), &priv
->hhead
, tuple_ptr
, zone
,
55 if (!nf_conncount_add(&priv
->hhead
, tuple_ptr
, zone
)) {
56 regs
->verdict
.code
= NF_DROP
;
57 spin_unlock_bh(&priv
->lock
);
62 spin_unlock_bh(&priv
->lock
);
64 if ((count
> priv
->limit
) ^ priv
->invert
) {
65 regs
->verdict
.code
= NFT_BREAK
;
70 static int nft_connlimit_do_init(const struct nft_ctx
*ctx
,
71 const struct nlattr
* const tb
[],
72 struct nft_connlimit
*priv
)
77 if (!tb
[NFTA_CONNLIMIT_COUNT
])
80 limit
= ntohl(nla_get_be32(tb
[NFTA_CONNLIMIT_COUNT
]));
82 if (tb
[NFTA_CONNLIMIT_FLAGS
]) {
83 flags
= ntohl(nla_get_be32(tb
[NFTA_CONNLIMIT_FLAGS
]));
84 if (flags
& ~NFT_CONNLIMIT_F_INV
)
86 if (flags
& NFT_CONNLIMIT_F_INV
)
90 spin_lock_init(&priv
->lock
);
91 INIT_HLIST_HEAD(&priv
->hhead
);
93 priv
->invert
= invert
;
95 return nf_ct_netns_get(ctx
->net
, ctx
->family
);
98 static void nft_connlimit_do_destroy(const struct nft_ctx
*ctx
,
99 struct nft_connlimit
*priv
)
101 nf_ct_netns_put(ctx
->net
, ctx
->family
);
102 nf_conncount_cache_free(&priv
->hhead
);
105 static int nft_connlimit_do_dump(struct sk_buff
*skb
,
106 struct nft_connlimit
*priv
)
108 if (nla_put_be32(skb
, NFTA_CONNLIMIT_COUNT
, htonl(priv
->limit
)))
109 goto nla_put_failure
;
111 nla_put_be32(skb
, NFTA_CONNLIMIT_FLAGS
, htonl(NFT_CONNLIMIT_F_INV
)))
112 goto nla_put_failure
;
120 static inline void nft_connlimit_obj_eval(struct nft_object
*obj
,
121 struct nft_regs
*regs
,
122 const struct nft_pktinfo
*pkt
)
124 struct nft_connlimit
*priv
= nft_obj_data(obj
);
126 nft_connlimit_do_eval(priv
, regs
, pkt
, NULL
);
129 static int nft_connlimit_obj_init(const struct nft_ctx
*ctx
,
130 const struct nlattr
* const tb
[],
131 struct nft_object
*obj
)
133 struct nft_connlimit
*priv
= nft_obj_data(obj
);
135 return nft_connlimit_do_init(ctx
, tb
, priv
);
138 static void nft_connlimit_obj_destroy(const struct nft_ctx
*ctx
,
139 struct nft_object
*obj
)
141 struct nft_connlimit
*priv
= nft_obj_data(obj
);
143 nft_connlimit_do_destroy(ctx
, priv
);
146 static int nft_connlimit_obj_dump(struct sk_buff
*skb
,
147 struct nft_object
*obj
, bool reset
)
149 struct nft_connlimit
*priv
= nft_obj_data(obj
);
151 return nft_connlimit_do_dump(skb
, priv
);
154 static const struct nla_policy nft_connlimit_policy
[NFTA_CONNLIMIT_MAX
+ 1] = {
155 [NFTA_CONNLIMIT_COUNT
] = { .type
= NLA_U32
},
156 [NFTA_CONNLIMIT_FLAGS
] = { .type
= NLA_U32
},
159 static struct nft_object_type nft_connlimit_obj_type
;
160 static const struct nft_object_ops nft_connlimit_obj_ops
= {
161 .type
= &nft_connlimit_obj_type
,
162 .size
= sizeof(struct nft_connlimit
),
163 .eval
= nft_connlimit_obj_eval
,
164 .init
= nft_connlimit_obj_init
,
165 .destroy
= nft_connlimit_obj_destroy
,
166 .dump
= nft_connlimit_obj_dump
,
169 static struct nft_object_type nft_connlimit_obj_type __read_mostly
= {
170 .type
= NFT_OBJECT_CONNLIMIT
,
171 .ops
= &nft_connlimit_obj_ops
,
172 .maxattr
= NFTA_CONNLIMIT_MAX
,
173 .policy
= nft_connlimit_policy
,
174 .owner
= THIS_MODULE
,
177 static void nft_connlimit_eval(const struct nft_expr
*expr
,
178 struct nft_regs
*regs
,
179 const struct nft_pktinfo
*pkt
)
181 struct nft_connlimit
*priv
= nft_expr_priv(expr
);
183 nft_connlimit_do_eval(priv
, regs
, pkt
, NULL
);
186 static int nft_connlimit_dump(struct sk_buff
*skb
, const struct nft_expr
*expr
)
188 struct nft_connlimit
*priv
= nft_expr_priv(expr
);
190 return nft_connlimit_do_dump(skb
, priv
);
193 static int nft_connlimit_init(const struct nft_ctx
*ctx
,
194 const struct nft_expr
*expr
,
195 const struct nlattr
* const tb
[])
197 struct nft_connlimit
*priv
= nft_expr_priv(expr
);
199 return nft_connlimit_do_init(ctx
, tb
, priv
);
202 static void nft_connlimit_destroy(const struct nft_ctx
*ctx
,
203 const struct nft_expr
*expr
)
205 struct nft_connlimit
*priv
= nft_expr_priv(expr
);
207 nft_connlimit_do_destroy(ctx
, priv
);
210 static int nft_connlimit_clone(struct nft_expr
*dst
, const struct nft_expr
*src
)
212 struct nft_connlimit
*priv_dst
= nft_expr_priv(dst
);
213 struct nft_connlimit
*priv_src
= nft_expr_priv(src
);
215 spin_lock_init(&priv_dst
->lock
);
216 INIT_HLIST_HEAD(&priv_dst
->hhead
);
217 priv_dst
->limit
= priv_src
->limit
;
218 priv_dst
->invert
= priv_src
->invert
;
223 static void nft_connlimit_destroy_clone(const struct nft_ctx
*ctx
,
224 const struct nft_expr
*expr
)
226 struct nft_connlimit
*priv
= nft_expr_priv(expr
);
228 nf_conncount_cache_free(&priv
->hhead
);
231 static bool nft_connlimit_gc(struct net
*net
, const struct nft_expr
*expr
)
233 struct nft_connlimit
*priv
= nft_expr_priv(expr
);
236 spin_lock_bh(&priv
->lock
);
237 nf_conncount_lookup(net
, &priv
->hhead
, NULL
, &nf_ct_zone_dflt
, &addit
);
239 ret
= hlist_empty(&priv
->hhead
);
240 spin_unlock_bh(&priv
->lock
);
245 static struct nft_expr_type nft_connlimit_type
;
246 static const struct nft_expr_ops nft_connlimit_ops
= {
247 .type
= &nft_connlimit_type
,
248 .size
= NFT_EXPR_SIZE(sizeof(struct nft_connlimit
)),
249 .eval
= nft_connlimit_eval
,
250 .init
= nft_connlimit_init
,
251 .destroy
= nft_connlimit_destroy
,
252 .clone
= nft_connlimit_clone
,
253 .destroy_clone
= nft_connlimit_destroy_clone
,
254 .dump
= nft_connlimit_dump
,
255 .gc
= nft_connlimit_gc
,
258 static struct nft_expr_type nft_connlimit_type __read_mostly
= {
260 .ops
= &nft_connlimit_ops
,
261 .policy
= nft_connlimit_policy
,
262 .maxattr
= NFTA_CONNLIMIT_MAX
,
263 .flags
= NFT_EXPR_STATEFUL
| NFT_EXPR_GC
,
264 .owner
= THIS_MODULE
,
267 static int __init
nft_connlimit_module_init(void)
271 err
= nft_register_obj(&nft_connlimit_obj_type
);
275 err
= nft_register_expr(&nft_connlimit_type
);
281 nft_unregister_obj(&nft_connlimit_obj_type
);
285 static void __exit
nft_connlimit_module_exit(void)
287 nft_unregister_expr(&nft_connlimit_type
);
288 nft_unregister_obj(&nft_connlimit_obj_type
);
291 module_init(nft_connlimit_module_init
);
292 module_exit(nft_connlimit_module_exit
);
294 MODULE_LICENSE("GPL");
295 MODULE_AUTHOR("Pablo Neira Ayuso");
296 MODULE_ALIAS_NFT_EXPR("connlimit");
297 MODULE_ALIAS_NFT_OBJ(NFT_OBJECT_CONNLIMIT
);