diff options
author | Patrick McHardy <kaber@trash.net> | 2008-03-25 23:26:43 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-03-25 23:26:43 -0400 |
commit | c7f485abd618e0d249bdd1abdc586bd10fee1954 (patch) | |
tree | 618ad078a96c0f7c641efaa38f0d363ee2775e42 /net/netfilter | |
parent | 0d0ab0378d67517a4f4ae3497706c13d9dd24af1 (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.c | 59 |
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; |
71 | EXPORT_SYMBOL_GPL(nf_nat_sdp_addr_hook); | 71 | EXPORT_SYMBOL_GPL(nf_nat_sdp_addr_hook); |
72 | 72 | ||
73 | unsigned 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; | ||
79 | EXPORT_SYMBOL_GPL(nf_nat_sdp_port_hook); | ||
80 | |||
73 | unsigned int (*nf_nat_sdp_session_hook)(struct sk_buff *skb, | 81 | unsigned 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 { |