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
;
36 ct
= nf_ct_get(pkt
->skb
, &ctinfo
);
38 tuple_ptr
= &ct
->tuplehash
[IP_CT_DIR_ORIGINAL
].tuple
;
39 zone
= nf_ct_zone(ct
);
40 } else if (!nf_ct_get_tuplepr(pkt
->skb
, skb_network_offset(pkt
->skb
),
41 nft_pf(pkt
), nft_net(pkt
), &tuple
)) {
42 regs
->verdict
.code
= NF_DROP
;
46 if (nf_conncount_add(nft_net(pkt
), priv
->list
, tuple_ptr
, zone
)) {
47 regs
->verdict
.code
= NF_DROP
;
51 count
= priv
->list
->count
;
53 if ((count
> priv
->limit
) ^ priv
->invert
) {
54 regs
->verdict
.code
= NFT_BREAK
;
59 static int nft_connlimit_do_init(const struct nft_ctx
*ctx
,
60 const struct nlattr
* const tb
[],
61 struct nft_connlimit
*priv
)
67 if (!tb
[NFTA_CONNLIMIT_COUNT
])
70 limit
= ntohl(nla_get_be32(tb
[NFTA_CONNLIMIT_COUNT
]));
72 if (tb
[NFTA_CONNLIMIT_FLAGS
]) {
73 flags
= ntohl(nla_get_be32(tb
[NFTA_CONNLIMIT_FLAGS
]));
74 if (flags
& ~NFT_CONNLIMIT_F_INV
)
76 if (flags
& NFT_CONNLIMIT_F_INV
)
80 priv
->list
= kmalloc(sizeof(*priv
->list
), GFP_KERNEL_ACCOUNT
);
84 nf_conncount_list_init(priv
->list
);
86 priv
->invert
= invert
;
88 err
= nf_ct_netns_get(ctx
->net
, ctx
->family
);
99 static void nft_connlimit_do_destroy(const struct nft_ctx
*ctx
,
100 struct nft_connlimit
*priv
)
102 nf_ct_netns_put(ctx
->net
, ctx
->family
);
103 nf_conncount_cache_free(priv
->list
);
107 static int nft_connlimit_do_dump(struct sk_buff
*skb
,
108 struct nft_connlimit
*priv
)
110 if (nla_put_be32(skb
, NFTA_CONNLIMIT_COUNT
, htonl(priv
->limit
)))
111 goto nla_put_failure
;
113 nla_put_be32(skb
, NFTA_CONNLIMIT_FLAGS
, htonl(NFT_CONNLIMIT_F_INV
)))
114 goto nla_put_failure
;
122 static inline void nft_connlimit_obj_eval(struct nft_object
*obj
,
123 struct nft_regs
*regs
,
124 const struct nft_pktinfo
*pkt
)
126 struct nft_connlimit
*priv
= nft_obj_data(obj
);
128 nft_connlimit_do_eval(priv
, regs
, pkt
, NULL
);
131 static int nft_connlimit_obj_init(const struct nft_ctx
*ctx
,
132 const struct nlattr
* const tb
[],
133 struct nft_object
*obj
)
135 struct nft_connlimit
*priv
= nft_obj_data(obj
);
137 return nft_connlimit_do_init(ctx
, tb
, priv
);
140 static void nft_connlimit_obj_destroy(const struct nft_ctx
*ctx
,
141 struct nft_object
*obj
)
143 struct nft_connlimit
*priv
= nft_obj_data(obj
);
145 nft_connlimit_do_destroy(ctx
, priv
);
148 static int nft_connlimit_obj_dump(struct sk_buff
*skb
,
149 struct nft_object
*obj
, bool reset
)
151 struct nft_connlimit
*priv
= nft_obj_data(obj
);
153 return nft_connlimit_do_dump(skb
, priv
);
156 static const struct nla_policy nft_connlimit_policy
[NFTA_CONNLIMIT_MAX
+ 1] = {
157 [NFTA_CONNLIMIT_COUNT
] = { .type
= NLA_U32
},
158 [NFTA_CONNLIMIT_FLAGS
] = { .type
= NLA_U32
},
161 static struct nft_object_type nft_connlimit_obj_type
;
162 static const struct nft_object_ops nft_connlimit_obj_ops
= {
163 .type
= &nft_connlimit_obj_type
,
164 .size
= sizeof(struct nft_connlimit
),
165 .eval
= nft_connlimit_obj_eval
,
166 .init
= nft_connlimit_obj_init
,
167 .destroy
= nft_connlimit_obj_destroy
,
168 .dump
= nft_connlimit_obj_dump
,
171 static struct nft_object_type nft_connlimit_obj_type __read_mostly
= {
172 .type
= NFT_OBJECT_CONNLIMIT
,
173 .ops
= &nft_connlimit_obj_ops
,
174 .maxattr
= NFTA_CONNLIMIT_MAX
,
175 .policy
= nft_connlimit_policy
,
176 .owner
= THIS_MODULE
,
179 static void nft_connlimit_eval(const struct nft_expr
*expr
,
180 struct nft_regs
*regs
,
181 const struct nft_pktinfo
*pkt
)
183 struct nft_connlimit
*priv
= nft_expr_priv(expr
);
185 nft_connlimit_do_eval(priv
, regs
, pkt
, NULL
);
188 static int nft_connlimit_dump(struct sk_buff
*skb
,
189 const struct nft_expr
*expr
, bool reset
)
191 struct nft_connlimit
*priv
= nft_expr_priv(expr
);
193 return nft_connlimit_do_dump(skb
, priv
);
196 static int nft_connlimit_init(const struct nft_ctx
*ctx
,
197 const struct nft_expr
*expr
,
198 const struct nlattr
* const tb
[])
200 struct nft_connlimit
*priv
= nft_expr_priv(expr
);
202 return nft_connlimit_do_init(ctx
, tb
, priv
);
205 static void nft_connlimit_destroy(const struct nft_ctx
*ctx
,
206 const struct nft_expr
*expr
)
208 struct nft_connlimit
*priv
= nft_expr_priv(expr
);
210 nft_connlimit_do_destroy(ctx
, priv
);
213 static int nft_connlimit_clone(struct nft_expr
*dst
, const struct nft_expr
*src
, gfp_t gfp
)
215 struct nft_connlimit
*priv_dst
= nft_expr_priv(dst
);
216 struct nft_connlimit
*priv_src
= nft_expr_priv(src
);
218 priv_dst
->list
= kmalloc(sizeof(*priv_dst
->list
), gfp
);
222 nf_conncount_list_init(priv_dst
->list
);
223 priv_dst
->limit
= priv_src
->limit
;
224 priv_dst
->invert
= priv_src
->invert
;
229 static void nft_connlimit_destroy_clone(const struct nft_ctx
*ctx
,
230 const struct nft_expr
*expr
)
232 struct nft_connlimit
*priv
= nft_expr_priv(expr
);
234 nf_conncount_cache_free(priv
->list
);
238 static bool nft_connlimit_gc(struct net
*net
, const struct nft_expr
*expr
)
240 struct nft_connlimit
*priv
= nft_expr_priv(expr
);
244 ret
= nf_conncount_gc_list(net
, priv
->list
);
250 static struct nft_expr_type nft_connlimit_type
;
251 static const struct nft_expr_ops nft_connlimit_ops
= {
252 .type
= &nft_connlimit_type
,
253 .size
= NFT_EXPR_SIZE(sizeof(struct nft_connlimit
)),
254 .eval
= nft_connlimit_eval
,
255 .init
= nft_connlimit_init
,
256 .destroy
= nft_connlimit_destroy
,
257 .clone
= nft_connlimit_clone
,
258 .destroy_clone
= nft_connlimit_destroy_clone
,
259 .dump
= nft_connlimit_dump
,
260 .gc
= nft_connlimit_gc
,
261 .reduce
= NFT_REDUCE_READONLY
,
264 static struct nft_expr_type nft_connlimit_type __read_mostly
= {
266 .ops
= &nft_connlimit_ops
,
267 .policy
= nft_connlimit_policy
,
268 .maxattr
= NFTA_CONNLIMIT_MAX
,
269 .flags
= NFT_EXPR_STATEFUL
| NFT_EXPR_GC
,
270 .owner
= THIS_MODULE
,
273 static int __init
nft_connlimit_module_init(void)
277 err
= nft_register_obj(&nft_connlimit_obj_type
);
281 err
= nft_register_expr(&nft_connlimit_type
);
287 nft_unregister_obj(&nft_connlimit_obj_type
);
291 static void __exit
nft_connlimit_module_exit(void)
293 nft_unregister_expr(&nft_connlimit_type
);
294 nft_unregister_obj(&nft_connlimit_obj_type
);
297 module_init(nft_connlimit_module_init
);
298 module_exit(nft_connlimit_module_exit
);
300 MODULE_LICENSE("GPL");
301 MODULE_AUTHOR("Pablo Neira Ayuso");
302 MODULE_ALIAS_NFT_EXPR("connlimit");
303 MODULE_ALIAS_NFT_OBJ(NFT_OBJECT_CONNLIMIT
);
304 MODULE_DESCRIPTION("nftables connlimit rule support");