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

[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
...@@ -96,7 +96,8 @@ extern unsigned int (*nf_nat_sip_expect_hook)(struct sk_buff *skb, ...@@ -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, ...@@ -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, ...@@ -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
this one. */ rtcp_exp->saved_ip = rtcp_exp->tuple.dst.u3.ip;
exp->expectfn = ip_nat_sip_expected; rtcp_exp->tuple.dst.u3.ip = newip;
rtcp_exp->saved_proto.udp.port = rtcp_exp->tuple.dst.u.udp.port;
/* Try to get same port: if not, try to change it. */ rtcp_exp->dir = !dir;
for (port = ntohs(exp->saved_proto.udp.port); port != 0; port++) { rtcp_exp->expectfn = ip_nat_sip_expected;
exp->tuple.dst.u.udp.port = htons(port);
if (nf_ct_expect_related(exp) == 0) /* 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; 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); ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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 ...@@ -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,
}, },
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment