aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2008-03-25 23:26:24 -0400
committerDavid S. Miller <davem@davemloft.net>2008-03-25 23:26:24 -0400
commit0d0ab0378d67517a4f4ae3497706c13d9dd24af1 (patch)
treec2fbd60d9b524fefa1ec96aef95db7942025c427 /net
parent4ab9e64e5e3c0516577818804aaf13a630d67bc9 (diff)
[NETFILTER]: nf_conntrack_sip: support multiple media channels
Add support for multiple media channels and use it to create expectations for video streams when present. Signed-off-by: Patrick McHardy <kaber@trash.net> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/netfilter/nf_conntrack_sip.c121
1 files changed, 90 insertions, 31 deletions
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
index f929add324f3..f40a525732d1 100644
--- a/net/netfilter/nf_conntrack_sip.c
+++ b/net/netfilter/nf_conntrack_sip.c
@@ -112,6 +112,21 @@ static int digits_len(const struct nf_conn *ct, const char *dptr,
112 return len; 112 return len;
113} 113}
114 114
115/* get media type + port length */
116static int media_len(const struct nf_conn *ct, const char *dptr,
117 const char *limit, int *shift)
118{
119 int len = string_len(ct, dptr, limit, shift);
120
121 dptr += len;
122 if (dptr >= limit || *dptr != ' ')
123 return 0;
124 len++;
125 dptr++;
126
127 return len + digits_len(ct, dptr, limit, shift);
128}
129
115static int parse_addr(const struct nf_conn *ct, const char *cp, 130static int parse_addr(const struct nf_conn *ct, const char *cp,
116 const char **endp, union nf_inet_addr *addr, 131 const char **endp, union nf_inet_addr *addr,
117 const char *limit) 132 const char *limit)
@@ -563,7 +578,7 @@ static const struct sip_header ct_sdp_hdrs[] = {
563 [SDP_HDR_CONNECTION_IP4] = SDP_HDR("c=", "IN IP4 ", epaddr_len), 578 [SDP_HDR_CONNECTION_IP4] = SDP_HDR("c=", "IN IP4 ", epaddr_len),
564 [SDP_HDR_OWNER_IP6] = SDP_HDR("o=", "IN IP6 ", epaddr_len), 579 [SDP_HDR_OWNER_IP6] = SDP_HDR("o=", "IN IP6 ", epaddr_len),
565 [SDP_HDR_CONNECTION_IP6] = SDP_HDR("c=", "IN IP6 ", epaddr_len), 580 [SDP_HDR_CONNECTION_IP6] = SDP_HDR("c=", "IN IP6 ", epaddr_len),
566 [SDP_HDR_MEDIA] = SDP_HDR("m=", "audio ", digits_len), 581 [SDP_HDR_MEDIA] = SDP_HDR("m=", NULL, media_len),
567}; 582};
568 583
569/* Linear string search within SDP header values */ 584/* Linear string search within SDP header values */
@@ -705,6 +720,7 @@ static void flush_expectations(struct nf_conn *ct, bool media)
705static int set_expected_rtp_rtcp(struct sk_buff *skb, 720static int set_expected_rtp_rtcp(struct sk_buff *skb,
706 const char **dptr, unsigned int *datalen, 721 const char **dptr, unsigned int *datalen,
707 union nf_inet_addr *daddr, __be16 port, 722 union nf_inet_addr *daddr, __be16 port,
723 enum sip_expectation_classes class,
708 unsigned int mediaoff, unsigned int medialen) 724 unsigned int mediaoff, unsigned int medialen)
709{ 725{
710 struct nf_conntrack_expect *exp, *rtp_exp, *rtcp_exp; 726 struct nf_conntrack_expect *exp, *rtp_exp, *rtcp_exp;
@@ -743,7 +759,7 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb,
743 exp = __nf_ct_expect_find(&tuple); 759 exp = __nf_ct_expect_find(&tuple);
744 if (exp && exp->master != ct && 760 if (exp && exp->master != ct &&
745 nfct_help(exp->master)->helper == nfct_help(ct)->helper && 761 nfct_help(exp->master)->helper == nfct_help(ct)->helper &&
746 exp->class == SIP_EXPECT_AUDIO) 762 exp->class == class)
747 skip_expect = 1; 763 skip_expect = 1;
748 rcu_read_unlock(); 764 rcu_read_unlock();
749 765
@@ -757,13 +773,13 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb,
757 rtp_exp = nf_ct_expect_alloc(ct); 773 rtp_exp = nf_ct_expect_alloc(ct);
758 if (rtp_exp == NULL) 774 if (rtp_exp == NULL)
759 goto err1; 775 goto err1;
760 nf_ct_expect_init(rtp_exp, SIP_EXPECT_AUDIO, family, saddr, daddr, 776 nf_ct_expect_init(rtp_exp, class, family, saddr, daddr,
761 IPPROTO_UDP, NULL, &rtp_port); 777 IPPROTO_UDP, NULL, &rtp_port);
762 778
763 rtcp_exp = nf_ct_expect_alloc(ct); 779 rtcp_exp = nf_ct_expect_alloc(ct);
764 if (rtcp_exp == NULL) 780 if (rtcp_exp == NULL)
765 goto err2; 781 goto err2;
766 nf_ct_expect_init(rtcp_exp, SIP_EXPECT_AUDIO, family, saddr, daddr, 782 nf_ct_expect_init(rtcp_exp, class, family, saddr, daddr,
767 IPPROTO_UDP, NULL, &rtcp_port); 783 IPPROTO_UDP, NULL, &rtcp_port);
768 784
769 nf_nat_sdp_media = rcu_dereference(nf_nat_sdp_media_hook); 785 nf_nat_sdp_media = rcu_dereference(nf_nat_sdp_media_hook);
@@ -785,6 +801,28 @@ err1:
785 return ret; 801 return ret;
786} 802}
787 803
804static const struct sdp_media_type sdp_media_types[] = {
805 SDP_MEDIA_TYPE("audio ", SIP_EXPECT_AUDIO),
806 SDP_MEDIA_TYPE("video ", SIP_EXPECT_VIDEO),
807};
808
809static const struct sdp_media_type *sdp_media_type(const char *dptr,
810 unsigned int matchoff,
811 unsigned int matchlen)
812{
813 const struct sdp_media_type *t;
814 unsigned int i;
815
816 for (i = 0; i < ARRAY_SIZE(sdp_media_types); i++) {
817 t = &sdp_media_types[i];
818 if (matchlen < t->len ||
819 strncmp(dptr + matchoff, t->name, t->len))
820 continue;
821 return t;
822 }
823 return NULL;
824}
825
788static int process_sdp(struct sk_buff *skb, 826static int process_sdp(struct sk_buff *skb,
789 const char **dptr, unsigned int *datalen, 827 const char **dptr, unsigned int *datalen,
790 unsigned int cseq) 828 unsigned int cseq)
@@ -796,13 +834,16 @@ static int process_sdp(struct sk_buff *skb,
796 unsigned int mediaoff, medialen; 834 unsigned int mediaoff, medialen;
797 unsigned int sdpoff; 835 unsigned int sdpoff;
798 unsigned int caddr_len, maddr_len; 836 unsigned int caddr_len, maddr_len;
837 unsigned int i;
799 union nf_inet_addr caddr, maddr, rtp_addr; 838 union nf_inet_addr caddr, maddr, rtp_addr;
800 unsigned int port; 839 unsigned int port;
801 enum sdp_header_types c_hdr; 840 enum sdp_header_types c_hdr;
802 int ret; 841 const struct sdp_media_type *t;
842 int ret = NF_ACCEPT;
803 typeof(nf_nat_sdp_addr_hook) nf_nat_sdp_addr; 843 typeof(nf_nat_sdp_addr_hook) nf_nat_sdp_addr;
804 typeof(nf_nat_sdp_session_hook) nf_nat_sdp_session; 844 typeof(nf_nat_sdp_session_hook) nf_nat_sdp_session;
805 845
846 nf_nat_sdp_addr = rcu_dereference(nf_nat_sdp_addr_hook);
806 c_hdr = family == AF_INET ? SDP_HDR_CONNECTION_IP4 : 847 c_hdr = family == AF_INET ? SDP_HDR_CONNECTION_IP4 :
807 SDP_HDR_CONNECTION_IP6; 848 SDP_HDR_CONNECTION_IP6;
808 849
@@ -822,41 +863,55 @@ static int process_sdp(struct sk_buff *skb,
822 &matchoff, &matchlen, &caddr) > 0) 863 &matchoff, &matchlen, &caddr) > 0)
823 caddr_len = matchlen; 864 caddr_len = matchlen;
824 865
825 if (ct_sip_get_sdp_header(ct, *dptr, sdpoff, *datalen, 866 mediaoff = sdpoff;
826 SDP_HDR_MEDIA, SDP_HDR_UNSPEC, 867 for (i = 0; i < ARRAY_SIZE(sdp_media_types); ) {
827 &mediaoff, &medialen) <= 0) 868 if (ct_sip_get_sdp_header(ct, *dptr, mediaoff, *datalen,
828 return NF_ACCEPT; 869 SDP_HDR_MEDIA, SDP_HDR_UNSPEC,
870 &mediaoff, &medialen) <= 0)
871 break;
829 872
830 port = simple_strtoul(*dptr + mediaoff, NULL, 10); 873 /* Get media type and port number. A media port value of zero
831 if (port < 1024 || port > 65535) 874 * indicates an inactive stream. */
832 return NF_DROP; 875 t = sdp_media_type(*dptr, mediaoff, medialen);
876 if (!t) {
877 mediaoff += medialen;
878 continue;
879 }
880 mediaoff += t->len;
881 medialen -= t->len;
833 882
834 /* The media description overrides the session description. */ 883 port = simple_strtoul(*dptr + mediaoff, NULL, 10);
835 maddr_len = 0; 884 if (port == 0)
836 if (ct_sip_parse_sdp_addr(ct, *dptr, mediaoff, *datalen, 885 continue;
837 c_hdr, SDP_HDR_MEDIA, 886 if (port < 1024 || port > 65535)
838 &matchoff, &matchlen, &maddr) > 0) { 887 return NF_DROP;
839 maddr_len = matchlen;
840 memcpy(&rtp_addr, &maddr, sizeof(rtp_addr));
841 } else if (caddr_len)
842 memcpy(&rtp_addr, &caddr, sizeof(rtp_addr));
843 else
844 return NF_DROP;
845 888
846 ret = set_expected_rtp_rtcp(skb, dptr, datalen, &rtp_addr, htons(port), 889 /* The media description overrides the session description. */
847 mediaoff, medialen); 890 maddr_len = 0;
848 if (ret != NF_ACCEPT) 891 if (ct_sip_parse_sdp_addr(ct, *dptr, mediaoff, *datalen,
849 return ret; 892 c_hdr, SDP_HDR_MEDIA,
893 &matchoff, &matchlen, &maddr) > 0) {
894 maddr_len = matchlen;
895 memcpy(&rtp_addr, &maddr, sizeof(rtp_addr));
896 } else if (caddr_len)
897 memcpy(&rtp_addr, &caddr, sizeof(rtp_addr));
898 else
899 return NF_DROP;
900
901 ret = set_expected_rtp_rtcp(skb, dptr, datalen,
902 &rtp_addr, htons(port), t->class,
903 mediaoff, medialen);
904 if (ret != NF_ACCEPT)
905 return ret;
850 906
851 /* Update media connection address if present */ 907 /* Update media connection address if present */
852 if (maddr_len) { 908 if (maddr_len && nf_nat_sdp_addr && ct->status & IPS_NAT_MASK) {
853 nf_nat_sdp_addr = rcu_dereference(nf_nat_sdp_addr_hook);
854 if (nf_nat_sdp_addr && ct->status & IPS_NAT_MASK) {
855 ret = nf_nat_sdp_addr(skb, dptr, mediaoff, datalen, 909 ret = nf_nat_sdp_addr(skb, dptr, mediaoff, datalen,
856 c_hdr, SDP_HDR_MEDIA, &rtp_addr); 910 c_hdr, SDP_HDR_MEDIA, &rtp_addr);
857 if (ret != NF_ACCEPT) 911 if (ret != NF_ACCEPT)
858 return ret; 912 return ret;
859 } 913 }
914 i++;
860 } 915 }
861 916
862 /* Update session connection and owner addresses */ 917 /* Update session connection and owner addresses */
@@ -1210,6 +1265,10 @@ static const struct nf_conntrack_expect_policy sip_exp_policy[SIP_EXPECT_MAX + 1
1210 .max_expected = 2 * IP_CT_DIR_MAX, 1265 .max_expected = 2 * IP_CT_DIR_MAX,
1211 .timeout = 3 * 60, 1266 .timeout = 3 * 60,
1212 }, 1267 },
1268 [SIP_EXPECT_VIDEO] = {
1269 .max_expected = 2 * IP_CT_DIR_MAX,
1270 .timeout = 3 * 60,
1271 },
1213}; 1272};
1214 1273
1215static void nf_conntrack_sip_fini(void) 1274static void nf_conntrack_sip_fini(void)