Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a9c1d359 authored by Patrick McHardy's avatar Patrick McHardy Committed by David S. Miller
Browse files

[NETFILTER]: nf_conntrack_sip: create RTCP expectations



Create expectations for the RTCP connections in addition to RTP connections.

Signed-off-by: default avatarPatrick McHardy <kaber@trash.net>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent d901a936
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -96,7 +96,8 @@ extern unsigned int (*nf_nat_sip_expect_hook)(struct sk_buff *skb,
extern unsigned int (*nf_nat_sdp_hook)(struct sk_buff *skb,
				       const char **dptr,
				       unsigned int *datalen,
				       struct nf_conntrack_expect *exp);
				       struct nf_conntrack_expect *rtp_exp,
				       struct nf_conntrack_expect *rtcp_exp);

extern int ct_sip_parse_request(const struct nf_conn *ct,
				const char *dptr, unsigned int datalen,
+26 −16
Original line number Diff line number Diff line
@@ -364,7 +364,8 @@ static unsigned int mangle_sdp(struct sk_buff *skb,
   Mangle it, and change the expectation to match the new version. */
static unsigned int ip_nat_sdp(struct sk_buff *skb,
			       const char **dptr, unsigned int *datalen,
			       struct nf_conntrack_expect *exp)
			       struct nf_conntrack_expect *rtp_exp,
			       struct nf_conntrack_expect *rtcp_exp)
{
	enum ip_conntrack_info ctinfo;
	struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
@@ -375,31 +376,40 @@ static unsigned int ip_nat_sdp(struct sk_buff *skb,
	/* Connection will come from reply */
	if (ct->tuplehash[dir].tuple.src.u3.ip ==
	    ct->tuplehash[!dir].tuple.dst.u3.ip)
		newip = exp->tuple.dst.u3.ip;
		newip = rtp_exp->tuple.dst.u3.ip;
	else
		newip = ct->tuplehash[!dir].tuple.dst.u3.ip;

	exp->saved_ip = exp->tuple.dst.u3.ip;
	exp->tuple.dst.u3.ip = newip;
	exp->saved_proto.udp.port = exp->tuple.dst.u.udp.port;
	exp->dir = !dir;

	/* When you see the packet, we need to NAT it the same as the
	   this one. */
	exp->expectfn = ip_nat_sip_expected;

	/* Try to get same port: if not, try to change it. */
	for (port = ntohs(exp->saved_proto.udp.port); port != 0; port++) {
		exp->tuple.dst.u.udp.port = htons(port);
		if (nf_ct_expect_related(exp) == 0)
	rtp_exp->saved_ip = rtp_exp->tuple.dst.u3.ip;
	rtp_exp->tuple.dst.u3.ip = newip;
	rtp_exp->saved_proto.udp.port = rtp_exp->tuple.dst.u.udp.port;
	rtp_exp->dir = !dir;
	rtp_exp->expectfn = ip_nat_sip_expected;

	rtcp_exp->saved_ip = rtcp_exp->tuple.dst.u3.ip;
	rtcp_exp->tuple.dst.u3.ip = newip;
	rtcp_exp->saved_proto.udp.port = rtcp_exp->tuple.dst.u.udp.port;
	rtcp_exp->dir = !dir;
	rtcp_exp->expectfn = ip_nat_sip_expected;

	/* Try to get same pair of ports: if not, try to change them. */
	for (port = ntohs(rtp_exp->tuple.dst.u.udp.port);
	     port != 0; port += 2) {
		rtp_exp->tuple.dst.u.udp.port = htons(port);
		if (nf_ct_expect_related(rtp_exp) != 0)
			continue;
		rtcp_exp->tuple.dst.u.udp.port = htons(port + 1);
		if (nf_ct_expect_related(rtcp_exp) == 0)
			break;
		nf_ct_unexpect_related(rtp_exp);
	}

	if (port == 0)
		return NF_DROP;

	if (!mangle_sdp(skb, ctinfo, ct, newip, port, dptr, datalen)) {
		nf_ct_unexpect_related(exp);
		nf_ct_unexpect_related(rtp_exp);
		nf_ct_unexpect_related(rtcp_exp);
		return NF_DROP;
	}
	return NF_ACCEPT;
+38 −20
Original line number Diff line number Diff line
@@ -63,7 +63,9 @@ EXPORT_SYMBOL_GPL(nf_nat_sip_expect_hook);
unsigned int (*nf_nat_sdp_hook)(struct sk_buff *skb,
				const char **dptr,
				unsigned int *datalen,
				struct nf_conntrack_expect *exp) __read_mostly;
				struct nf_conntrack_expect *rtp_exp,
				struct nf_conntrack_expect *rtcp_exp)
				__read_mostly;
EXPORT_SYMBOL_GPL(nf_nat_sdp_hook);

static int string_len(const struct nf_conn *ct, const char *dptr,
@@ -659,18 +661,20 @@ static void flush_expectations(struct nf_conn *ct, bool media)
	spin_unlock_bh(&nf_conntrack_lock);
}

static int set_expected_rtp(struct sk_buff *skb,
static int set_expected_rtp_rtcp(struct sk_buff *skb,
				 const char **dptr, unsigned int *datalen,
				 union nf_inet_addr *daddr, __be16 port)
{
	struct nf_conntrack_expect *exp;
	struct nf_conntrack_expect *exp, *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);
	union nf_inet_addr *saddr;
	struct nf_conntrack_tuple tuple;
	int family = ct->tuplehash[!dir].tuple.src.l3num;
	int skip_expect = 0, ret;
	int skip_expect = 0, ret = NF_DROP;
	u_int16_t base_port;
	__be16 rtp_port, rtcp_port;
	typeof(nf_nat_sdp_hook) nf_nat_sdp;

	saddr = NULL;
@@ -704,23 +708,37 @@ static int set_expected_rtp(struct sk_buff *skb,
	if (skip_expect)
		return NF_ACCEPT;

	exp = nf_ct_expect_alloc(ct);
	if (exp == NULL)
		return NF_DROP;
	nf_ct_expect_init(exp, SIP_EXPECT_AUDIO, family, saddr, daddr,
			  IPPROTO_UDP, NULL, &port);
	base_port = ntohs(tuple.dst.u.udp.port) & ~1;
	rtp_port = htons(base_port);
	rtcp_port = htons(base_port + 1);

	rtp_exp = nf_ct_expect_alloc(ct);
	if (rtp_exp == NULL)
		goto err1;
	nf_ct_expect_init(rtp_exp, SIP_EXPECT_AUDIO, family, saddr, daddr,
			  IPPROTO_UDP, NULL, &rtp_port);

	rtcp_exp = nf_ct_expect_alloc(ct);
	if (rtcp_exp == NULL)
		goto err2;
	nf_ct_expect_init(rtcp_exp, SIP_EXPECT_AUDIO, family, saddr, daddr,
			  IPPROTO_UDP, NULL, &rtcp_port);

	nf_nat_sdp = rcu_dereference(nf_nat_sdp_hook);
	if (nf_nat_sdp && ct->status & IPS_NAT_MASK)
		ret = nf_nat_sdp(skb, dptr, datalen, exp);
		ret = nf_nat_sdp(skb, dptr, datalen, rtp_exp, rtcp_exp);
	else {
		if (nf_ct_expect_related(exp) != 0)
			ret = NF_DROP;
		if (nf_ct_expect_related(rtp_exp) == 0) {
			if (nf_ct_expect_related(rtcp_exp) != 0)
				nf_ct_unexpect_related(rtp_exp);
			else
				ret = NF_ACCEPT;
		}
	nf_ct_expect_put(exp);

	}
	nf_ct_expect_put(rtcp_exp);
err2:
	nf_ct_expect_put(rtp_exp);
err1:
	return ret;
}

@@ -758,7 +776,7 @@ static int process_sdp(struct sk_buff *skb,
	if (port < 1024 || port > 65535)
		return NF_DROP;

	return set_expected_rtp(skb, dptr, datalen, &addr, htons(port));
	return set_expected_rtp_rtcp(skb, dptr, datalen, &addr, htons(port));
}
static int process_invite_response(struct sk_buff *skb,
				   const char **dptr, unsigned int *datalen,
@@ -1101,7 +1119,7 @@ static const struct nf_conntrack_expect_policy sip_exp_policy[SIP_EXPECT_MAX + 1
		.timeout	= 3 * 60,
	},
	[SIP_EXPECT_AUDIO] = {
		.max_expected	= IP_CT_DIR_MAX,
		.max_expected	= 2 * IP_CT_DIR_MAX,
		.timeout	= 3 * 60,
	},
};