]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
netfilter: nf_conntrack_expect: add and use nf_ct_expect_related_pair()
authorPablo Neira Ayuso <pablo@netfilter.org>
Sun, 12 Jul 2026 22:26:04 +0000 (00:26 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Wed, 22 Jul 2026 18:34:28 +0000 (20:34 +0200)
Add a new function to insert a pair of expectations, this is required by
the SIP and H323 NAT helpers. The spinlock is held to check if there is
a slot for both expectations, in such case, insert them.

This removes the need for nf_ct_unexpect_related() inside the loop to
find a pair of consecutive ports, otherwise inserting expectations whose
dead flag is already set on can happen.

Bump master_help->expecting for the expectation class after checking if
the expectation fits in the master expectation list, which is needed for
this new _pair() function variant to run the eviction routine including
the preallocated slot for the first expectation in the pair.

Fixes: b8b09dc2bf35 ("netfilter: nf_conntrack_expect: use conntrack GC to reap expectations")
Reported-by: Jaeyeong Lee <iostreampy@proton.me>
Link: https://patch.msgid.link/178377968720.33756.12204817361601593230@proton.me/
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
include/net/netfilter/nf_conntrack_expect.h
net/ipv4/netfilter/nf_nat_h323.c
net/netfilter/nf_conntrack_expect.c
net/netfilter/nf_nat_sip.c

index c024345c9bd862f5fa8e0d1e480a8ce220293c9e..26d6babd92fcd7c5b0c4313b60ad8d769c26726b 100644 (file)
@@ -161,6 +161,9 @@ static inline int nf_ct_expect_related(struct nf_conntrack_expect *expect,
        return nf_ct_expect_related_report(expect, 0, 0, flags);
 }
 
+int nf_ct_expect_related_pair(struct nf_conntrack_expect *expect[],
+                             unsigned int flag);
+
 struct nf_conn_help;
 void nf_ct_expectation_gc(struct nf_conn_help *master_help);
 
index 183e8a3ff2babd519906bc8dfe1722c4b9b8dc46..6bcd6734769b593b40054bcbf6c6b3a51ed3c709 100644 (file)
@@ -182,6 +182,7 @@ static int nat_rtp_rtcp(struct sk_buff *skb, struct nf_conn *ct,
                        struct nf_conntrack_expect *rtp_exp,
                        struct nf_conntrack_expect *rtcp_exp)
 {
+       struct nf_conntrack_expect *rtp_pair[2] = { rtp_exp, rtcp_exp };
        struct nf_ct_h323_master *info = nfct_help_data(ct);
        int dir = CTINFO2DIR(ctinfo);
        int i;
@@ -227,22 +228,13 @@ static int nat_rtp_rtcp(struct sk_buff *skb, struct nf_conn *ct,
                int ret;
 
                rtp_exp->tuple.dst.u.udp.port = htons(nated_port);
-               ret = nf_ct_expect_related(rtp_exp, 0);
+               rtcp_exp->tuple.dst.u.udp.port = htons(nated_port + 1);
+               ret = nf_ct_expect_related_pair(rtp_pair, 0);
                if (ret == 0) {
-                       rtcp_exp->tuple.dst.u.udp.port =
-                           htons(nated_port + 1);
-                       ret = nf_ct_expect_related(rtcp_exp, 0);
-                       if (ret == 0)
-                               break;
-                       else if (ret == -EBUSY) {
-                               nf_ct_unexpect_related(rtp_exp);
-                               continue;
-                       } else if (ret < 0) {
-                               nf_ct_unexpect_related(rtp_exp);
-                               nated_port = 0;
-                               break;
-                       }
-               } else if (ret != -EBUSY) {
+                       break;
+               } else if (ret == -EBUSY) {
+                       continue;
+               } else if (ret < 0) {
                        nated_port = 0;
                        break;
                }
index 7ae68d60586a23a62599d6b77ef1458758e29113..8a3b9e33e94f77e0129e2154a7442bede4c91094 100644 (file)
@@ -427,7 +427,6 @@ static void nf_ct_expect_insert(struct nf_conntrack_expect *exp,
                exp->timeout += helper->expect_policy[exp->class].timeout * HZ;
 
        hlist_add_head_rcu(&exp->lnode, &master_help->expectations);
-       master_help->expecting[exp->class]++;
 
        hlist_add_head_rcu(&exp->hnode, &nf_ct_expect_hash[h]);
        cnet = nf_ct_pernet(net);
@@ -534,6 +533,7 @@ int nf_ct_expect_related_report(struct nf_conntrack_expect *expect,
        if (ret < 0)
                goto out;
 
+       master_help->expecting[expect->class]++;
        nf_ct_expect_insert(expect, master_help);
 
        nf_ct_expect_event_report(IPEXP_NEW, expect, portid, report);
@@ -546,6 +546,39 @@ out:
 }
 EXPORT_SYMBOL_GPL(nf_ct_expect_related_report);
 
+int nf_ct_expect_related_pair(struct nf_conntrack_expect *expect[],
+                             unsigned int flags)
+{
+       struct nf_conn_help *master_help;
+       int i, ret;
+
+       spin_lock_bh(&nf_conntrack_expect_lock);
+       master_help = nfct_help(expect[0]->master);
+       if (!master_help || master_help != nfct_help(expect[1]->master)) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       for (i = 0; i < 2; i++) {
+               ret = __nf_ct_expect_check(expect[i], master_help, flags);
+               if (ret < 0) {
+                       if (i == 1)
+                               master_help->expecting[expect[0]->class]--;
+                       goto out;
+               }
+               master_help->expecting[expect[i]->class]++;
+       }
+
+       for (i = 0; i < 2; i++) {
+               nf_ct_expect_insert(expect[i], master_help);
+               nf_ct_expect_event_report(IPEXP_NEW, expect[i], 0, 0);
+       }
+out:
+       spin_unlock_bh(&nf_conntrack_expect_lock);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(nf_ct_expect_related_pair);
+
 void nf_ct_expect_iterate_destroy(bool (*iter)(struct nf_conntrack_expect *e, void *data),
                                  void *data)
 {
index a93eaf0f7d305e0828bec7323354ed1438c4f0df..133bd713fe0c29ca6670b1121b46c39aefb6c64b 100644 (file)
@@ -592,6 +592,7 @@ static unsigned int nf_nat_sdp_media(struct sk_buff *skb, unsigned int protoff,
                                     unsigned int medialen,
                                     union nf_inet_addr *rtp_addr)
 {
+       struct nf_conntrack_expect *rtp_pair[2] = { rtp_exp, rtcp_exp };
        enum ip_conntrack_info ctinfo;
        struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
        enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
@@ -622,24 +623,15 @@ static unsigned int nf_nat_sdp_media(struct sk_buff *skb, unsigned int protoff,
                int ret;
 
                rtp_exp->tuple.dst.u.udp.port = htons(port);
-               ret = nf_ct_expect_related(rtp_exp,
-                                          NF_CT_EXP_F_SKIP_MASTER);
-               if (ret == -EBUSY)
-                       continue;
-               else if (ret < 0) {
-                       port = 0;
-                       break;
-               }
                rtcp_exp->tuple.dst.u.udp.port = htons(port + 1);
-               ret = nf_ct_expect_related(rtcp_exp,
-                                          NF_CT_EXP_F_SKIP_MASTER);
+
+               ret = nf_ct_expect_related_pair(rtp_pair,
+                                               NF_CT_EXP_F_SKIP_MASTER);
                if (ret == 0)
                        break;
-               else if (ret == -EBUSY) {
-                       nf_ct_unexpect_related(rtp_exp);
+               else if (ret == -EBUSY)
                        continue;
-               } else if (ret < 0) {
-                       nf_ct_unexpect_related(rtp_exp);
+               else if (ret < 0) {
                        port = 0;
                        break;
                }