aboutsummaryrefslogtreecommitdiffstats
path: root/net/netfilter
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2008-03-25 23:26:43 -0400
committerDavid S. Miller <davem@davemloft.net>2008-03-25 23:26:43 -0400
commitc7f485abd618e0d249bdd1abdc586bd10fee1954 (patch)
tree618ad078a96c0f7c641efaa38f0d363ee2775e42 /net/netfilter
parent0d0ab0378d67517a4f4ae3497706c13d9dd24af1 (diff)
[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: Patrick McHardy <kaber@trash.net> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/netfilter')
-rw-r--r--net/netfilter/nf_conntrack_sip.c59
1 files changed, 49 insertions, 10 deletions
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
index f40a525732d1..57de22c770a3 100644
--- a/net/netfilter/nf_conntrack_sip.c
+++ b/net/netfilter/nf_conntrack_sip.c
@@ -70,6 +70,14 @@ unsigned int (*nf_nat_sdp_addr_hook)(struct sk_buff *skb,
70 __read_mostly; 70 __read_mostly;
71EXPORT_SYMBOL_GPL(nf_nat_sdp_addr_hook); 71EXPORT_SYMBOL_GPL(nf_nat_sdp_addr_hook);
72 72
73unsigned int (*nf_nat_sdp_port_hook)(struct sk_buff *skb,
74 const char **dptr,
75 unsigned int *datalen,
76 unsigned int matchoff,
77 unsigned int matchlen,
78 u_int16_t port) __read_mostly;
79EXPORT_SYMBOL_GPL(nf_nat_sdp_port_hook);
80
73unsigned int (*nf_nat_sdp_session_hook)(struct sk_buff *skb, 81unsigned int (*nf_nat_sdp_session_hook)(struct sk_buff *skb,
74 const char **dptr, 82 const char **dptr,
75 unsigned int dataoff, 83 unsigned int dataoff,
@@ -730,9 +738,10 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb,
730 union nf_inet_addr *saddr; 738 union nf_inet_addr *saddr;
731 struct nf_conntrack_tuple tuple; 739 struct nf_conntrack_tuple tuple;
732 int family = ct->tuplehash[!dir].tuple.src.l3num; 740 int family = ct->tuplehash[!dir].tuple.src.l3num;
733 int skip_expect = 0, ret = NF_DROP; 741 int direct_rtp = 0, skip_expect = 0, ret = NF_DROP;
734 u_int16_t base_port; 742 u_int16_t base_port;
735 __be16 rtp_port, rtcp_port; 743 __be16 rtp_port, rtcp_port;
744 typeof(nf_nat_sdp_port_hook) nf_nat_sdp_port;
736 typeof(nf_nat_sdp_media_hook) nf_nat_sdp_media; 745 typeof(nf_nat_sdp_media_hook) nf_nat_sdp_media;
737 746
738 saddr = NULL; 747 saddr = NULL;
@@ -746,6 +755,14 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb,
746 * to register it since we can see the same media description multiple 755 * to register it since we can see the same media description multiple
747 * times on different connections in case multiple endpoints receive 756 * times on different connections in case multiple endpoints receive
748 * the same call. 757 * the same call.
758 *
759 * RTP optimization: if we find a matching media channel expectation
760 * and both the expectation and this connection are SNATed, we assume
761 * both sides can reach each other directly and use the final
762 * destination address from the expectation. We still need to keep
763 * the NATed expectations for media that might arrive from the
764 * outside, and additionally need to expect the direct RTP stream
765 * in case it passes through us even without NAT.
749 */ 766 */
750 memset(&tuple, 0, sizeof(tuple)); 767 memset(&tuple, 0, sizeof(tuple));
751 if (saddr) 768 if (saddr)
@@ -756,20 +773,42 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb,
756 tuple.dst.u.udp.port = port; 773 tuple.dst.u.udp.port = port;
757 774
758 rcu_read_lock(); 775 rcu_read_lock();
759 exp = __nf_ct_expect_find(&tuple); 776 do {
760 if (exp && exp->master != ct && 777 exp = __nf_ct_expect_find(&tuple);
761 nfct_help(exp->master)->helper == nfct_help(ct)->helper &&
762 exp->class == class)
763 skip_expect = 1;
764 rcu_read_unlock();
765 778
766 if (skip_expect) 779 if (!exp || exp->master == ct ||
767 return NF_ACCEPT; 780 nfct_help(exp->master)->helper != nfct_help(ct)->helper ||
781 exp->class != class)
782 break;
783
784 if (exp->tuple.src.l3num == AF_INET && !direct_rtp &&
785 (exp->saved_ip != exp->tuple.dst.u3.ip ||
786 exp->saved_proto.udp.port != exp->tuple.dst.u.udp.port) &&
787 ct->status & IPS_NAT_MASK) {
788 daddr->ip = exp->saved_ip;
789 tuple.dst.u3.ip = exp->saved_ip;
790 tuple.dst.u.udp.port = exp->saved_proto.udp.port;
791 direct_rtp = 1;
792 } else
793 skip_expect = 1;
794 } while (!skip_expect);
795 rcu_read_unlock();
768 796
769 base_port = ntohs(tuple.dst.u.udp.port) & ~1; 797 base_port = ntohs(tuple.dst.u.udp.port) & ~1;
770 rtp_port = htons(base_port); 798 rtp_port = htons(base_port);
771 rtcp_port = htons(base_port + 1); 799 rtcp_port = htons(base_port + 1);
772 800
801 if (direct_rtp) {
802 nf_nat_sdp_port = rcu_dereference(nf_nat_sdp_port_hook);
803 if (nf_nat_sdp_port &&
804 !nf_nat_sdp_port(skb, dptr, datalen,
805 mediaoff, medialen, ntohs(rtp_port)))
806 goto err1;
807 }
808
809 if (skip_expect)
810 return NF_ACCEPT;
811
773 rtp_exp = nf_ct_expect_alloc(ct); 812 rtp_exp = nf_ct_expect_alloc(ct);
774 if (rtp_exp == NULL) 813 if (rtp_exp == NULL)
775 goto err1; 814 goto err1;
@@ -783,7 +822,7 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb,
783 IPPROTO_UDP, NULL, &rtcp_port); 822 IPPROTO_UDP, NULL, &rtcp_port);
784 823
785 nf_nat_sdp_media = rcu_dereference(nf_nat_sdp_media_hook); 824 nf_nat_sdp_media = rcu_dereference(nf_nat_sdp_media_hook);
786 if (nf_nat_sdp_media && ct->status & IPS_NAT_MASK) 825 if (nf_nat_sdp_media && ct->status & IPS_NAT_MASK && !direct_rtp)
787 ret = nf_nat_sdp_media(skb, dptr, datalen, rtp_exp, rtcp_exp, 826 ret = nf_nat_sdp_media(skb, dptr, datalen, rtp_exp, rtcp_exp,
788 mediaoff, medialen, daddr); 827 mediaoff, medialen, daddr);
789 else { 828 else {