mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-31 08:15:07 -04:00
netfilter: nf_conntrack_expect: add and use nf_ct_expect_related_pair()
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: b8b09dc2bf ("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>
This commit is contained in:
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 @@ int nf_ct_expect_related_report(struct nf_conntrack_expect *expect,
|
||||
}
|
||||
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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user