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

[NETFILTER]: nf_conntrack_sip: RTP routing optimization

Optimize call routing between NATed endpoints: when an external
registrar sends a media description that contains an existing RTP
expectation from a different SNATed connection, the gatekeeper
is trying to route the call directly between the two endpoints.

We assume both endpoints can reach each other directly and
"un-NAT" the addresses, which makes the media stream go between
the two endpoints directly.
Signed-off-by: default avatarPatrick McHardy <kaber@trash.net>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 0d0ab037
...@@ -114,6 +114,12 @@ extern unsigned int (*nf_nat_sdp_addr_hook)(struct sk_buff *skb, ...@@ -114,6 +114,12 @@ extern unsigned int (*nf_nat_sdp_addr_hook)(struct sk_buff *skb,
enum sdp_header_types type, enum sdp_header_types type,
enum sdp_header_types term, enum sdp_header_types term,
const union nf_inet_addr *addr); const union nf_inet_addr *addr);
extern unsigned int (*nf_nat_sdp_port_hook)(struct sk_buff *skb,
const char **dptr,
unsigned int *datalen,
unsigned int matchoff,
unsigned int matchlen,
u_int16_t port);
extern unsigned int (*nf_nat_sdp_session_hook)(struct sk_buff *skb, extern unsigned int (*nf_nat_sdp_session_hook)(struct sk_buff *skb,
const char **dptr, const char **dptr,
unsigned int dataoff, unsigned int dataoff,
......
...@@ -461,6 +461,7 @@ static void __exit nf_nat_sip_fini(void) ...@@ -461,6 +461,7 @@ static void __exit nf_nat_sip_fini(void)
rcu_assign_pointer(nf_nat_sip_hook, NULL); rcu_assign_pointer(nf_nat_sip_hook, NULL);
rcu_assign_pointer(nf_nat_sip_expect_hook, NULL); rcu_assign_pointer(nf_nat_sip_expect_hook, NULL);
rcu_assign_pointer(nf_nat_sdp_addr_hook, NULL); rcu_assign_pointer(nf_nat_sdp_addr_hook, NULL);
rcu_assign_pointer(nf_nat_sdp_port_hook, NULL);
rcu_assign_pointer(nf_nat_sdp_session_hook, NULL); rcu_assign_pointer(nf_nat_sdp_session_hook, NULL);
rcu_assign_pointer(nf_nat_sdp_media_hook, NULL); rcu_assign_pointer(nf_nat_sdp_media_hook, NULL);
synchronize_rcu(); synchronize_rcu();
...@@ -471,11 +472,13 @@ static int __init nf_nat_sip_init(void) ...@@ -471,11 +472,13 @@ static int __init nf_nat_sip_init(void)
BUG_ON(nf_nat_sip_hook != NULL); BUG_ON(nf_nat_sip_hook != NULL);
BUG_ON(nf_nat_sip_expect_hook != NULL); BUG_ON(nf_nat_sip_expect_hook != NULL);
BUG_ON(nf_nat_sdp_addr_hook != NULL); BUG_ON(nf_nat_sdp_addr_hook != NULL);
BUG_ON(nf_nat_sdp_port_hook != NULL);
BUG_ON(nf_nat_sdp_session_hook != NULL); BUG_ON(nf_nat_sdp_session_hook != NULL);
BUG_ON(nf_nat_sdp_media_hook != NULL); BUG_ON(nf_nat_sdp_media_hook != NULL);
rcu_assign_pointer(nf_nat_sip_hook, ip_nat_sip); rcu_assign_pointer(nf_nat_sip_hook, ip_nat_sip);
rcu_assign_pointer(nf_nat_sip_expect_hook, ip_nat_sip_expect); rcu_assign_pointer(nf_nat_sip_expect_hook, ip_nat_sip_expect);
rcu_assign_pointer(nf_nat_sdp_addr_hook, ip_nat_sdp_addr); rcu_assign_pointer(nf_nat_sdp_addr_hook, ip_nat_sdp_addr);
rcu_assign_pointer(nf_nat_sdp_port_hook, ip_nat_sdp_port);
rcu_assign_pointer(nf_nat_sdp_session_hook, ip_nat_sdp_session); rcu_assign_pointer(nf_nat_sdp_session_hook, ip_nat_sdp_session);
rcu_assign_pointer(nf_nat_sdp_media_hook, ip_nat_sdp_media); rcu_assign_pointer(nf_nat_sdp_media_hook, ip_nat_sdp_media);
return 0; return 0;
......
...@@ -70,6 +70,14 @@ unsigned int (*nf_nat_sdp_addr_hook)(struct sk_buff *skb, ...@@ -70,6 +70,14 @@ unsigned int (*nf_nat_sdp_addr_hook)(struct sk_buff *skb,
__read_mostly; __read_mostly;
EXPORT_SYMBOL_GPL(nf_nat_sdp_addr_hook); EXPORT_SYMBOL_GPL(nf_nat_sdp_addr_hook);
unsigned int (*nf_nat_sdp_port_hook)(struct sk_buff *skb,
const char **dptr,
unsigned int *datalen,
unsigned int matchoff,
unsigned int matchlen,
u_int16_t port) __read_mostly;
EXPORT_SYMBOL_GPL(nf_nat_sdp_port_hook);
unsigned int (*nf_nat_sdp_session_hook)(struct sk_buff *skb, unsigned int (*nf_nat_sdp_session_hook)(struct sk_buff *skb,
const char **dptr, const char **dptr,
unsigned int dataoff, unsigned int dataoff,
...@@ -730,9 +738,10 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb, ...@@ -730,9 +738,10 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb,
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 = NF_DROP; int direct_rtp = 0, skip_expect = 0, ret = NF_DROP;
u_int16_t base_port; u_int16_t base_port;
__be16 rtp_port, rtcp_port; __be16 rtp_port, rtcp_port;
typeof(nf_nat_sdp_port_hook) nf_nat_sdp_port;
typeof(nf_nat_sdp_media_hook) nf_nat_sdp_media; typeof(nf_nat_sdp_media_hook) nf_nat_sdp_media;
saddr = NULL; saddr = NULL;
...@@ -746,6 +755,14 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb, ...@@ -746,6 +755,14 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb,
* to register it since we can see the same media description multiple * to register it since we can see the same media description multiple
* times on different connections in case multiple endpoints receive * times on different connections in case multiple endpoints receive
* the same call. * the same call.
*
* RTP optimization: if we find a matching media channel expectation
* and both the expectation and this connection are SNATed, we assume
* both sides can reach each other directly and use the final
* destination address from the expectation. We still need to keep
* the NATed expectations for media that might arrive from the
* outside, and additionally need to expect the direct RTP stream
* in case it passes through us even without NAT.
*/ */
memset(&tuple, 0, sizeof(tuple)); memset(&tuple, 0, sizeof(tuple));
if (saddr) if (saddr)
...@@ -756,20 +773,42 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb, ...@@ -756,20 +773,42 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb,
tuple.dst.u.udp.port = port; tuple.dst.u.udp.port = port;
rcu_read_lock(); rcu_read_lock();
exp = __nf_ct_expect_find(&tuple); do {
if (exp && exp->master != ct && exp = __nf_ct_expect_find(&tuple);
nfct_help(exp->master)->helper == nfct_help(ct)->helper &&
exp->class == class)
skip_expect = 1;
rcu_read_unlock();
if (skip_expect) if (!exp || exp->master == ct ||
return NF_ACCEPT; nfct_help(exp->master)->helper != nfct_help(ct)->helper ||
exp->class != class)
break;
if (exp->tuple.src.l3num == AF_INET && !direct_rtp &&
(exp->saved_ip != exp->tuple.dst.u3.ip ||
exp->saved_proto.udp.port != exp->tuple.dst.u.udp.port) &&
ct->status & IPS_NAT_MASK) {
daddr->ip = exp->saved_ip;
tuple.dst.u3.ip = exp->saved_ip;
tuple.dst.u.udp.port = exp->saved_proto.udp.port;
direct_rtp = 1;
} else
skip_expect = 1;
} while (!skip_expect);
rcu_read_unlock();
base_port = ntohs(tuple.dst.u.udp.port) & ~1; base_port = ntohs(tuple.dst.u.udp.port) & ~1;
rtp_port = htons(base_port); rtp_port = htons(base_port);
rtcp_port = htons(base_port + 1); rtcp_port = htons(base_port + 1);
if (direct_rtp) {
nf_nat_sdp_port = rcu_dereference(nf_nat_sdp_port_hook);
if (nf_nat_sdp_port &&
!nf_nat_sdp_port(skb, dptr, datalen,
mediaoff, medialen, ntohs(rtp_port)))
goto err1;
}
if (skip_expect)
return NF_ACCEPT;
rtp_exp = nf_ct_expect_alloc(ct); rtp_exp = nf_ct_expect_alloc(ct);
if (rtp_exp == NULL) if (rtp_exp == NULL)
goto err1; goto err1;
...@@ -783,7 +822,7 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb, ...@@ -783,7 +822,7 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb,
IPPROTO_UDP, NULL, &rtcp_port); IPPROTO_UDP, NULL, &rtcp_port);
nf_nat_sdp_media = rcu_dereference(nf_nat_sdp_media_hook); nf_nat_sdp_media = rcu_dereference(nf_nat_sdp_media_hook);
if (nf_nat_sdp_media && ct->status & IPS_NAT_MASK) if (nf_nat_sdp_media && ct->status & IPS_NAT_MASK && !direct_rtp)
ret = nf_nat_sdp_media(skb, dptr, datalen, rtp_exp, rtcp_exp, ret = nf_nat_sdp_media(skb, dptr, datalen, rtp_exp, rtcp_exp,
mediaoff, medialen, daddr); mediaoff, medialen, daddr);
else { else {
......
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