[NETFILTER]: nf_conntrack_sip: create RTCP expectations
Create expectations for the RTCP connections in addition to RTP connections. Signed-off-by: Patrick McHardy <kaber@trash.net> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
committed by
David S. Miller
parent
d901a9369e
commit
a9c1d35917
@@ -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,
|
extern unsigned int (*nf_nat_sdp_hook)(struct sk_buff *skb,
|
||||||
const char **dptr,
|
const char **dptr,
|
||||||
unsigned int *datalen,
|
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,
|
extern int ct_sip_parse_request(const struct nf_conn *ct,
|
||||||
const char *dptr, unsigned int datalen,
|
const char *dptr, unsigned int datalen,
|
||||||
|
@@ -364,7 +364,8 @@ static unsigned int mangle_sdp(struct sk_buff *skb,
|
|||||||
Mangle it, and change the expectation to match the new version. */
|
Mangle it, and change the expectation to match the new version. */
|
||||||
static unsigned int ip_nat_sdp(struct sk_buff *skb,
|
static unsigned int ip_nat_sdp(struct sk_buff *skb,
|
||||||
const char **dptr, unsigned int *datalen,
|
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;
|
enum ip_conntrack_info ctinfo;
|
||||||
struct nf_conn *ct = nf_ct_get(skb, &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 */
|
/* Connection will come from reply */
|
||||||
if (ct->tuplehash[dir].tuple.src.u3.ip ==
|
if (ct->tuplehash[dir].tuple.src.u3.ip ==
|
||||||
ct->tuplehash[!dir].tuple.dst.u3.ip)
|
ct->tuplehash[!dir].tuple.dst.u3.ip)
|
||||||
newip = exp->tuple.dst.u3.ip;
|
newip = rtp_exp->tuple.dst.u3.ip;
|
||||||
else
|
else
|
||||||
newip = ct->tuplehash[!dir].tuple.dst.u3.ip;
|
newip = ct->tuplehash[!dir].tuple.dst.u3.ip;
|
||||||
|
|
||||||
exp->saved_ip = exp->tuple.dst.u3.ip;
|
rtp_exp->saved_ip = rtp_exp->tuple.dst.u3.ip;
|
||||||
exp->tuple.dst.u3.ip = newip;
|
rtp_exp->tuple.dst.u3.ip = newip;
|
||||||
exp->saved_proto.udp.port = exp->tuple.dst.u.udp.port;
|
rtp_exp->saved_proto.udp.port = rtp_exp->tuple.dst.u.udp.port;
|
||||||
exp->dir = !dir;
|
rtp_exp->dir = !dir;
|
||||||
|
rtp_exp->expectfn = ip_nat_sip_expected;
|
||||||
|
|
||||||
/* When you see the packet, we need to NAT it the same as the
|
rtcp_exp->saved_ip = rtcp_exp->tuple.dst.u3.ip;
|
||||||
this one. */
|
rtcp_exp->tuple.dst.u3.ip = newip;
|
||||||
exp->expectfn = ip_nat_sip_expected;
|
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 port: if not, try to change it. */
|
/* Try to get same pair of ports: if not, try to change them. */
|
||||||
for (port = ntohs(exp->saved_proto.udp.port); port != 0; port++) {
|
for (port = ntohs(rtp_exp->tuple.dst.u.udp.port);
|
||||||
exp->tuple.dst.u.udp.port = htons(port);
|
port != 0; port += 2) {
|
||||||
if (nf_ct_expect_related(exp) == 0)
|
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;
|
break;
|
||||||
|
nf_ct_unexpect_related(rtp_exp);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (port == 0)
|
if (port == 0)
|
||||||
return NF_DROP;
|
return NF_DROP;
|
||||||
|
|
||||||
if (!mangle_sdp(skb, ctinfo, ct, newip, port, dptr, datalen)) {
|
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_DROP;
|
||||||
}
|
}
|
||||||
return NF_ACCEPT;
|
return NF_ACCEPT;
|
||||||
|
@@ -63,7 +63,9 @@ EXPORT_SYMBOL_GPL(nf_nat_sip_expect_hook);
|
|||||||
unsigned int (*nf_nat_sdp_hook)(struct sk_buff *skb,
|
unsigned int (*nf_nat_sdp_hook)(struct sk_buff *skb,
|
||||||
const char **dptr,
|
const char **dptr,
|
||||||
unsigned int *datalen,
|
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);
|
EXPORT_SYMBOL_GPL(nf_nat_sdp_hook);
|
||||||
|
|
||||||
static int string_len(const struct nf_conn *ct, const char *dptr,
|
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);
|
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,
|
const char **dptr, unsigned int *datalen,
|
||||||
union nf_inet_addr *daddr, __be16 port)
|
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;
|
enum ip_conntrack_info ctinfo;
|
||||||
struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
|
struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
|
||||||
enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
|
enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
|
||||||
union nf_inet_addr *saddr;
|
union nf_inet_addr *saddr;
|
||||||
struct nf_conntrack_tuple tuple;
|
struct nf_conntrack_tuple tuple;
|
||||||
int family = ct->tuplehash[!dir].tuple.src.l3num;
|
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;
|
typeof(nf_nat_sdp_hook) nf_nat_sdp;
|
||||||
|
|
||||||
saddr = NULL;
|
saddr = NULL;
|
||||||
@@ -704,23 +708,37 @@ static int set_expected_rtp(struct sk_buff *skb,
|
|||||||
if (skip_expect)
|
if (skip_expect)
|
||||||
return NF_ACCEPT;
|
return NF_ACCEPT;
|
||||||
|
|
||||||
exp = nf_ct_expect_alloc(ct);
|
base_port = ntohs(tuple.dst.u.udp.port) & ~1;
|
||||||
if (exp == NULL)
|
rtp_port = htons(base_port);
|
||||||
return NF_DROP;
|
rtcp_port = htons(base_port + 1);
|
||||||
nf_ct_expect_init(exp, SIP_EXPECT_AUDIO, family, saddr, daddr,
|
|
||||||
IPPROTO_UDP, NULL, &port);
|
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);
|
nf_nat_sdp = rcu_dereference(nf_nat_sdp_hook);
|
||||||
if (nf_nat_sdp && ct->status & IPS_NAT_MASK)
|
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 {
|
else {
|
||||||
if (nf_ct_expect_related(exp) != 0)
|
if (nf_ct_expect_related(rtp_exp) == 0) {
|
||||||
ret = NF_DROP;
|
if (nf_ct_expect_related(rtcp_exp) != 0)
|
||||||
else
|
nf_ct_unexpect_related(rtp_exp);
|
||||||
ret = NF_ACCEPT;
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -758,7 +776,7 @@ static int process_sdp(struct sk_buff *skb,
|
|||||||
if (port < 1024 || port > 65535)
|
if (port < 1024 || port > 65535)
|
||||||
return NF_DROP;
|
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,
|
static int process_invite_response(struct sk_buff *skb,
|
||||||
const char **dptr, unsigned int *datalen,
|
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,
|
.timeout = 3 * 60,
|
||||||
},
|
},
|
||||||
[SIP_EXPECT_AUDIO] = {
|
[SIP_EXPECT_AUDIO] = {
|
||||||
.max_expected = IP_CT_DIR_MAX,
|
.max_expected = 2 * IP_CT_DIR_MAX,
|
||||||
.timeout = 3 * 60,
|
.timeout = 3 * 60,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user