Skip to content

Commit 69894e5

Browse files
ffmanceraummakynes
authored andcommitted
netfilter: nft_connlimit: update the count if add was skipped
Connlimit expression can be used for all kind of packets and not only for packets with connection state new. See this ruleset as example: table ip filter { chain input { type filter hook input priority filter; policy accept; tcp dport 22 ct count over 4 counter } } Currently, if the connection count goes over the limit the counter will count the packets. When a connection is closed, the connection count won't decrement as it should because it is only updated for new connections due to an optimization on __nf_conncount_add() that prevents updating the list if the connection is duplicated. To solve this problem, check whether the connection was skipped and if so, update the list. Adjust count_tree() too so the same fix is applied for xt_connlimit. Fixes: 976afca ("netfilter: nf_conncount: Early exit in nf_conncount_lookup() and cleanup") Closes: https://lore.kernel.org/netfilter/trinity-85c72a88-d762-46c3-be97-36f10e5d9796-1761173693813@3c-app-mailcom-bs12/ Signed-off-by: Fernando Fernandez Mancera <fmancera@suse.de> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
1 parent c0362b5 commit 69894e5

2 files changed

Lines changed: 19 additions & 6 deletions

File tree

net/netfilter/nf_conncount.c

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ static int __nf_conncount_add(struct net *net,
179179
if (ct && nf_ct_is_confirmed(ct)) {
180180
if (refcounted)
181181
nf_ct_put(ct);
182-
return 0;
182+
return -EEXIST;
183183
}
184184

185185
if ((u32)jiffies == list->last_gc)
@@ -408,7 +408,7 @@ insert_tree(struct net *net,
408408
int ret;
409409

410410
ret = nf_conncount_add_skb(net, skb, l3num, &rbconn->list);
411-
if (ret)
411+
if (ret && ret != -EEXIST)
412412
count = 0; /* hotdrop */
413413
else
414414
count = rbconn->list.count;
@@ -511,10 +511,14 @@ count_tree(struct net *net,
511511
/* same source network -> be counted! */
512512
ret = __nf_conncount_add(net, skb, l3num, &rbconn->list);
513513
spin_unlock_bh(&rbconn->list.list_lock);
514-
if (ret)
514+
if (ret && ret != -EEXIST) {
515515
return 0; /* hotdrop */
516-
else
516+
} else {
517+
/* -EEXIST means add was skipped, update the list */
518+
if (ret == -EEXIST)
519+
nf_conncount_gc_list(net, &rbconn->list);
517520
return rbconn->list.count;
521+
}
518522
}
519523
}
520524

net/netfilter/nft_connlimit.c

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,17 @@ static inline void nft_connlimit_do_eval(struct nft_connlimit *priv,
2929

3030
err = nf_conncount_add_skb(nft_net(pkt), pkt->skb, nft_pf(pkt), priv->list);
3131
if (err) {
32-
regs->verdict.code = NF_DROP;
33-
return;
32+
if (err == -EEXIST) {
33+
/* Call gc to update the list count if any connection has
34+
* been closed already. This is useful for softlimit
35+
* connections like limiting bandwidth based on a number
36+
* of open connections.
37+
*/
38+
nf_conncount_gc_list(nft_net(pkt), priv->list);
39+
} else {
40+
regs->verdict.code = NF_DROP;
41+
return;
42+
}
3443
}
3544

3645
count = READ_ONCE(priv->list->count);

0 commit comments

Comments
 (0)