aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/netfilter/nf_conntrack_sip.h6
-rw-r--r--net/ipv4/netfilter/nf_nat_sip.c3
-rw-r--r--net/netfilter/nf_conntrack_sip.c59
3 files changed, 58 insertions, 10 deletions
diff --git a/include/linux/netfilter/nf_conntrack_sip.h b/include/linux/netfilter/nf_conntrack_sip.h
index 71fa3eb5f485..5da04e586a3f 100644
--- a/include/linux/netfilter/nf_conntrack_sip.h
+++ b/include/linux/netfilter/nf_conntrack_sip.h
@@ -114,6 +114,12 @@ extern unsigned int (*nf_nat_sdp_addr_hook)(struct sk_buff *skb,
114 enum sdp_header_types type, 114 enum sdp_header_types type,
115 enum sdp_header_types term, 115 enum sdp_header_types term,
116 const union nf_inet_addr *addr); 116 const union nf_inet_addr *addr);
117extern unsigned int (*nf_nat_sdp_port_hook)(struct sk_buff *skb,
118 const char **dptr,
119 unsigned int *datalen,
120 unsigned int matchoff,
121 unsigned int matchlen,
122 u_int16_t port);
117extern unsigned int (*nf_nat_sdp_session_hook)(struct sk_buff *skb, 123extern unsigned int (*nf_nat_sdp_session_hook)(struct sk_buff *skb,
118 const char **dptr, 124 const char **dptr,
119 unsigned int dataoff, 125 unsigned int dataoff,
diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c
index 4429069d9b42..bcddccddf768 100644
--- a/net/ipv4/netfilter/nf_nat_sip.c
+++ b/net/ipv4/netfilter/nf_nat_sip.c
@@ -461,6 +461,7 @@ static void __exit nf_nat_sip_fini(void)
461 rcu_assign_pointer(nf_nat_sip_hook, NULL); 461 rcu_assign_pointer(nf_nat_sip_hook, NULL);
462 rcu_assign_pointer(nf_nat_sip_expect_hook, NULL); 462 rcu_assign_pointer(nf_nat_sip_expect_hook, NULL);
463 rcu_assign_pointer(nf_nat_sdp_addr_hook, NULL); 463 rcu_assign_pointer(nf_nat_sdp_addr_hook, NULL);
464 rcu_assign_pointer(nf_nat_sdp_port_hook, NULL);
464 rcu_assign_pointer(nf_nat_sdp_session_hook, NULL); 465 rcu_assign_pointer(nf_nat_sdp_session_hook, NULL);
465 rcu_assign_pointer(nf_nat_sdp_media_hook, NULL); 466 rcu_assign_pointer(nf_nat_sdp_media_hook, NULL);
466 synchronize_rcu(); 467 synchronize_rcu();
@@ -471,11 +472,13 @@ static int __init nf_nat_sip_init(void)
471 BUG_ON(nf_nat_sip_hook != NULL); 472 BUG_ON(nf_nat_sip_hook != NULL);
472 BUG_ON(nf_nat_sip_expect_hook != NULL); 473 BUG_ON(nf_nat_sip_expect_hook != NULL);
473 BUG_ON(nf_nat_sdp_addr_hook != NULL); 474 BUG_ON(nf_nat_sdp_addr_hook != NULL);
475 BUG_ON(nf_nat_sdp_port_hook != NULL);
474 BUG_ON(nf_nat_sdp_session_hook != NULL); 476 BUG_ON(nf_nat_sdp_session_hook != NULL);
475 BUG_ON(nf_nat_sdp_media_hook != NULL); 477 BUG_ON(nf_nat_sdp_media_hook != NULL);
476 rcu_assign_pointer(nf_nat_sip_hook, ip_nat_sip); 478 rcu_assign_pointer(nf_nat_sip_hook, ip_nat_sip);
477 rcu_assign_pointer(nf_nat_sip_expect_hook, ip_nat_sip_expect); 479 rcu_assign_pointer(nf_nat_sip_expect_hook, ip_nat_sip_expect);
478 rcu_assign_pointer(nf_nat_sdp_addr_hook, ip_nat_sdp_addr); 480 rcu_assign_pointer(nf_nat_sdp_addr_hook, ip_nat_sdp_addr);
481 rcu_assign_pointer(nf_nat_sdp_port_hook, ip_nat_sdp_port);
479 rcu_assign_pointer(nf_nat_sdp_session_hook, ip_nat_sdp_session); 482 rcu_assign_pointer(nf_nat_sdp_session_hook, ip_nat_sdp_session);
480 rcu_assign_pointer(nf_nat_sdp_media_hook, ip_nat_sdp_media); 483 rcu_assign_pointer(nf_nat_sdp_media_hook, ip_nat_sdp_media);
481 return 0; 484 return 0;
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 {