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
)
66 if (!tb
[NFTA_CONNLIMIT_COUNT
])
69 limit
= ntohl(nla_get_be32(tb
[NFTA_CONNLIMIT_COUNT
]));
71 if (tb
[NFTA_CONNLIMIT_FLAGS
]) {
72 flags
= ntohl(nla_get_be32(tb
[NFTA_CONNLIMIT_FLAGS
]));
73 if (flags
& ~NFT_CONNLIMIT_F_INV
)
75 if (flags
& NFT_CONNLIMIT_F_INV
)
79 nf_conncount_list_init(&priv
->list
);
81 priv
->invert
= invert
;
83 return nf_ct_netns_get(ctx
->net
, ctx
->family
);
86 static void nft_connlimit_do_destroy(const struct nft_ctx
*ctx
,
87 struct nft_connlimit
*priv
)
89 nf_ct_netns_put(ctx
->net
, ctx
->family
);
90 nf_conncount_cache_free(&priv
->list
);
93 static int nft_connlimit_do_dump(struct sk_buff
*skb
,
94 struct nft_connlimit
*priv
)
96 if (nla_put_be32(skb
, NFTA_CONNLIMIT_COUNT
, htonl(priv
->limit
)))
99 nla_put_be32(skb
, NFTA_CONNLIMIT_FLAGS
, htonl(NFT_CONNLIMIT_F_INV
)))
100 goto nla_put_failure
;
108 static inline void nft_connlimit_obj_eval(struct nft_object
*obj
,
109 struct nft_regs
*regs
,
110 const struct nft_pktinfo
*pkt
)
112 struct nft_connlimit
*priv
= nft_obj_data(obj
);
114 nft_connlimit_do_eval(priv
, regs
, pkt
, NULL
);
117 static int nft_connlimit_obj_init(const struct nft_ctx
*ctx
,
118 const struct nlattr
* const tb
[],
119 struct nft_object
*obj
)
121 struct nft_connlimit
*priv
= nft_obj_data(obj
);
123 return nft_connlimit_do_init(ctx
, tb
, priv
);
126 static void nft_connlimit_obj_destroy(const struct nft_ctx
*ctx
,
127 struct nft_object
*obj
)
129 struct nft_connlimit
*priv
= nft_obj_data(obj
);
131 nft_connlimit_do_destroy(ctx
, priv
);
134 static int nft_connlimit_obj_dump(struct sk_buff
*skb
,
135 struct nft_object
*obj
, bool reset
)
137 struct nft_connlimit
*priv
= nft_obj_data(obj
);
139 return nft_connlimit_do_dump(skb
, priv
);
142 static const struct nla_policy nft_connlimit_policy
[NFTA_CONNLIMIT_MAX
+ 1] = {
143 [NFTA_CONNLIMIT_COUNT
] = { .type
= NLA_U32
},
144 [NFTA_CONNLIMIT_FLAGS
] = { .type
= NLA_U32
},
147 static struct nft_object_type nft_connlimit_obj_type
;
148 static const struct nft_object_ops nft_connlimit_obj_ops
= {
149 .type
= &nft_connlimit_obj_type
,
150 .size
= sizeof(struct nft_connlimit
),
151 .eval
= nft_connlimit_obj_eval
,
152 .init
= nft_connlimit_obj_init
,
153 .destroy
= nft_connlimit_obj_destroy
,
154 .dump
= nft_connlimit_obj_dump
,
157 static struct nft_object_type nft_connlimit_obj_type __read_mostly
= {
158 .type
= NFT_OBJECT_CONNLIMIT
,
159 .ops
= &nft_connlimit_obj_ops
,
160 .maxattr
= NFTA_CONNLIMIT_MAX
,
161 .policy
= nft_connlimit_policy
,
162 .owner
= THIS_MODULE
,
165 static void nft_connlimit_eval(const struct nft_expr
*expr
,
166 struct nft_regs
*regs
,
167 const struct nft_pktinfo
*pkt
)
169 struct nft_connlimit
*priv
= nft_expr_priv(expr
);
171 nft_connlimit_do_eval(priv
, regs
, pkt
, NULL
);
174 static int nft_connlimit_dump(struct sk_buff
*skb
, const struct nft_expr
*expr
)
176 struct nft_connlimit
*priv
= nft_expr_priv(expr
);
178 return nft_connlimit_do_dump(skb
, priv
);
181 static int nft_connlimit_init(const struct nft_ctx
*ctx
,
182 const struct nft_expr
*expr
,
183 const struct nlattr
* const tb
[])
185 struct nft_connlimit
*priv
= nft_expr_priv(expr
);
187 return nft_connlimit_do_init(ctx
, tb
, priv
);
190 static void nft_connlimit_destroy(const struct nft_ctx
*ctx
,
191 const struct nft_expr
*expr
)
193 struct nft_connlimit
*priv
= nft_expr_priv(expr
);
195 nft_connlimit_do_destroy(ctx
, priv
);
198 static int nft_connlimit_clone(struct nft_expr
*dst
, const struct nft_expr
*src
)
200 struct nft_connlimit
*priv_dst
= nft_expr_priv(dst
);
201 struct nft_connlimit
*priv_src
= nft_expr_priv(src
);
203 nf_conncount_list_init(&priv_dst
->list
);
204 priv_dst
->limit
= priv_src
->limit
;
205 priv_dst
->invert
= priv_src
->invert
;
210 static void nft_connlimit_destroy_clone(const struct nft_ctx
*ctx
,
211 const struct nft_expr
*expr
)
213 struct nft_connlimit
*priv
= nft_expr_priv(expr
);
215 nf_conncount_cache_free(&priv
->list
);
218 static bool nft_connlimit_gc(struct net
*net
, const struct nft_expr
*expr
)
220 struct nft_connlimit
*priv
= nft_expr_priv(expr
);
222 return nf_conncount_gc_list(net
, &priv
->list
);
225 static struct nft_expr_type nft_connlimit_type
;
226 static const struct nft_expr_ops nft_connlimit_ops
= {
227 .type
= &nft_connlimit_type
,
228 .size
= NFT_EXPR_SIZE(sizeof(struct nft_connlimit
)),
229 .eval
= nft_connlimit_eval
,
230 .init
= nft_connlimit_init
,
231 .destroy
= nft_connlimit_destroy
,
232 .clone
= nft_connlimit_clone
,
233 .destroy_clone
= nft_connlimit_destroy_clone
,
234 .dump
= nft_connlimit_dump
,
235 .gc
= nft_connlimit_gc
,
238 static struct nft_expr_type nft_connlimit_type __read_mostly
= {
240 .ops
= &nft_connlimit_ops
,
241 .policy
= nft_connlimit_policy
,
242 .maxattr
= NFTA_CONNLIMIT_MAX
,
243 .flags
= NFT_EXPR_STATEFUL
| NFT_EXPR_GC
,
244 .owner
= THIS_MODULE
,
247 static int __init
nft_connlimit_module_init(void)
251 err
= nft_register_obj(&nft_connlimit_obj_type
);
255 err
= nft_register_expr(&nft_connlimit_type
);
261 nft_unregister_obj(&nft_connlimit_obj_type
);
265 static void __exit
nft_connlimit_module_exit(void)
267 nft_unregister_expr(&nft_connlimit_type
);
268 nft_unregister_obj(&nft_connlimit_obj_type
);
271 module_init(nft_connlimit_module_init
);
272 module_exit(nft_connlimit_module_exit
);
274 MODULE_LICENSE("GPL");
275 MODULE_AUTHOR("Pablo Neira Ayuso");
276 MODULE_ALIAS_NFT_EXPR("connlimit");
277 MODULE_ALIAS_NFT_OBJ(NFT_OBJECT_CONNLIMIT
);