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);
/* 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;
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,
spin_unlock_bh(&nf_conntrack_lock);
}
-static int set_expected_rtp(struct sk_buff *skb,
- const char **dptr, unsigned int *datalen,
- union nf_inet_addr *daddr, __be16 port)
+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;
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;
- else
- ret = NF_ACCEPT;
+ 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;
}
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,
.timeout = 3 * 60,
},
[SIP_EXPECT_AUDIO] = {
- .max_expected = IP_CT_DIR_MAX,
+ .max_expected = 2 * IP_CT_DIR_MAX,
.timeout = 3 * 60,
},
};