diff options
-rw-r--r-- | net/netfilter/nf_conntrack_sip.c | 45 |
1 files changed, 41 insertions, 4 deletions
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index 043aa557e7a8..813aa8c67e4c 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c | |||
@@ -42,6 +42,11 @@ module_param(sip_direct_signalling, int, 0600); | |||
42 | MODULE_PARM_DESC(sip_direct_signalling, "expect incoming calls from registrar " | 42 | MODULE_PARM_DESC(sip_direct_signalling, "expect incoming calls from registrar " |
43 | "only (default 1)"); | 43 | "only (default 1)"); |
44 | 44 | ||
45 | static int sip_direct_media __read_mostly = 1; | ||
46 | module_param(sip_direct_media, int, 0600); | ||
47 | MODULE_PARM_DESC(sip_direct_media, "Expect Media streams between signalling " | ||
48 | "endpoints only (default 1)"); | ||
49 | |||
45 | unsigned int (*nf_nat_sip_hook)(struct sk_buff *skb, | 50 | unsigned int (*nf_nat_sip_hook)(struct sk_buff *skb, |
46 | const char **dptr, | 51 | const char **dptr, |
47 | unsigned int *datalen) __read_mostly; | 52 | unsigned int *datalen) __read_mostly; |
@@ -656,21 +661,53 @@ static void flush_expectations(struct nf_conn *ct, bool media) | |||
656 | 661 | ||
657 | static int set_expected_rtp(struct sk_buff *skb, | 662 | static int set_expected_rtp(struct sk_buff *skb, |
658 | const char **dptr, unsigned int *datalen, | 663 | const char **dptr, unsigned int *datalen, |
659 | union nf_inet_addr *addr, __be16 port) | 664 | union nf_inet_addr *daddr, __be16 port) |
660 | { | 665 | { |
661 | struct nf_conntrack_expect *exp; | 666 | struct nf_conntrack_expect *exp; |
662 | enum ip_conntrack_info ctinfo; | 667 | enum ip_conntrack_info ctinfo; |
663 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); | 668 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); |
664 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); | 669 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); |
670 | union nf_inet_addr *saddr; | ||
671 | struct nf_conntrack_tuple tuple; | ||
665 | int family = ct->tuplehash[!dir].tuple.src.l3num; | 672 | int family = ct->tuplehash[!dir].tuple.src.l3num; |
666 | int ret; | 673 | int skip_expect = 0, ret; |
667 | typeof(nf_nat_sdp_hook) nf_nat_sdp; | 674 | typeof(nf_nat_sdp_hook) nf_nat_sdp; |
668 | 675 | ||
676 | saddr = NULL; | ||
677 | if (sip_direct_media) { | ||
678 | if (!nf_inet_addr_cmp(daddr, &ct->tuplehash[dir].tuple.src.u3)) | ||
679 | return NF_ACCEPT; | ||
680 | saddr = &ct->tuplehash[!dir].tuple.src.u3; | ||
681 | } | ||
682 | |||
683 | /* We need to check whether the registration exists before attempting | ||
684 | * to register it since we can see the same media description multiple | ||
685 | * times on different connections in case multiple endpoints receive | ||
686 | * the same call. | ||
687 | */ | ||
688 | memset(&tuple, 0, sizeof(tuple)); | ||
689 | if (saddr) | ||
690 | tuple.src.u3 = *saddr; | ||
691 | tuple.src.l3num = family; | ||
692 | tuple.dst.protonum = IPPROTO_UDP; | ||
693 | tuple.dst.u3 = *daddr; | ||
694 | tuple.dst.u.udp.port = port; | ||
695 | |||
696 | rcu_read_lock(); | ||
697 | exp = __nf_ct_expect_find(&tuple); | ||
698 | if (exp && exp->master != ct && | ||
699 | nfct_help(exp->master)->helper == nfct_help(ct)->helper && | ||
700 | exp->class == SIP_EXPECT_AUDIO) | ||
701 | skip_expect = 1; | ||
702 | rcu_read_unlock(); | ||
703 | |||
704 | if (skip_expect) | ||
705 | return NF_ACCEPT; | ||
706 | |||
669 | exp = nf_ct_expect_alloc(ct); | 707 | exp = nf_ct_expect_alloc(ct); |
670 | if (exp == NULL) | 708 | if (exp == NULL) |
671 | return NF_DROP; | 709 | return NF_DROP; |
672 | nf_ct_expect_init(exp, SIP_EXPECT_AUDIO, family, | 710 | nf_ct_expect_init(exp, SIP_EXPECT_AUDIO, family, saddr, daddr, |
673 | &ct->tuplehash[!dir].tuple.src.u3, addr, | ||
674 | IPPROTO_UDP, NULL, &port); | 711 | IPPROTO_UDP, NULL, &port); |
675 | 712 | ||
676 | nf_nat_sdp = rcu_dereference(nf_nat_sdp_hook); | 713 | nf_nat_sdp = rcu_dereference(nf_nat_sdp_hook); |