diff options
-rw-r--r-- | net/netfilter/nf_conntrack_sip.c | 84 |
1 files changed, 43 insertions, 41 deletions
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index f20fa2d94c0a..96bedb52bd4b 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c | |||
@@ -565,19 +565,49 @@ static int set_expected_rtp(struct sk_buff *skb, | |||
565 | return ret; | 565 | return ret; |
566 | } | 566 | } |
567 | 567 | ||
568 | static int process_sdp(struct sk_buff *skb, | ||
569 | const char **dptr, unsigned int *datalen) | ||
570 | { | ||
571 | enum ip_conntrack_info ctinfo; | ||
572 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); | ||
573 | int family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num; | ||
574 | unsigned int matchoff, matchlen; | ||
575 | union nf_inet_addr addr; | ||
576 | unsigned int port; | ||
577 | enum sdp_header_types type; | ||
578 | |||
579 | /* Get address and port from SDP packet. */ | ||
580 | type = family == AF_INET ? SDP_HDR_CONNECTION_IP4 : | ||
581 | SDP_HDR_CONNECTION_IP6; | ||
582 | |||
583 | if (ct_sip_get_sdp_header(ct, *dptr, 0, *datalen, | ||
584 | type, SDP_HDR_UNSPEC, | ||
585 | &matchoff, &matchlen) <= 0) | ||
586 | return NF_ACCEPT; | ||
587 | |||
588 | /* We'll drop only if there are parse problems. */ | ||
589 | if (!parse_addr(ct, *dptr + matchoff, NULL, &addr, *dptr + *datalen)) | ||
590 | return NF_DROP; | ||
591 | |||
592 | if (ct_sip_get_sdp_header(ct, *dptr, 0, *datalen, | ||
593 | SDP_HDR_MEDIA, SDP_HDR_UNSPEC, | ||
594 | &matchoff, &matchlen) <= 0) | ||
595 | return NF_ACCEPT; | ||
596 | |||
597 | port = simple_strtoul(*dptr + matchoff, NULL, 10); | ||
598 | if (port < 1024 || port > 65535) | ||
599 | return NF_DROP; | ||
600 | |||
601 | return set_expected_rtp(skb, dptr, datalen, &addr, htons(port)); | ||
602 | } | ||
603 | |||
568 | static int sip_help(struct sk_buff *skb, | 604 | static int sip_help(struct sk_buff *skb, |
569 | unsigned int protoff, | 605 | unsigned int protoff, |
570 | struct nf_conn *ct, | 606 | struct nf_conn *ct, |
571 | enum ip_conntrack_info ctinfo) | 607 | enum ip_conntrack_info ctinfo) |
572 | { | 608 | { |
573 | int family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num; | ||
574 | union nf_inet_addr addr; | ||
575 | unsigned int dataoff, datalen; | 609 | unsigned int dataoff, datalen; |
576 | const char *dptr; | 610 | const char *dptr; |
577 | int ret = NF_ACCEPT; | ||
578 | unsigned int matchoff, matchlen; | ||
579 | u_int16_t port; | ||
580 | enum sdp_header_types type; | ||
581 | typeof(nf_nat_sip_hook) nf_nat_sip; | 611 | typeof(nf_nat_sip_hook) nf_nat_sip; |
582 | 612 | ||
583 | /* No Data ? */ | 613 | /* No Data ? */ |
@@ -591,56 +621,28 @@ static int sip_help(struct sk_buff *skb, | |||
591 | dptr = skb->data + dataoff; | 621 | dptr = skb->data + dataoff; |
592 | else { | 622 | else { |
593 | pr_debug("Copy of skbuff not supported yet.\n"); | 623 | pr_debug("Copy of skbuff not supported yet.\n"); |
594 | goto out; | 624 | return NF_ACCEPT; |
595 | } | 625 | } |
596 | 626 | ||
597 | nf_nat_sip = rcu_dereference(nf_nat_sip_hook); | 627 | nf_nat_sip = rcu_dereference(nf_nat_sip_hook); |
598 | if (nf_nat_sip && ct->status & IPS_NAT_MASK) { | 628 | if (nf_nat_sip && ct->status & IPS_NAT_MASK) { |
599 | if (!nf_nat_sip(skb, &dptr, &datalen)) { | 629 | if (!nf_nat_sip(skb, &dptr, &datalen)) |
600 | ret = NF_DROP; | 630 | return NF_DROP; |
601 | goto out; | ||
602 | } | ||
603 | } | 631 | } |
604 | 632 | ||
605 | datalen = skb->len - dataoff; | 633 | datalen = skb->len - dataoff; |
606 | if (datalen < strlen("SIP/2.0 200")) | 634 | if (datalen < strlen("SIP/2.0 200")) |
607 | goto out; | 635 | return NF_ACCEPT; |
608 | 636 | ||
609 | /* RTP info only in some SDP pkts */ | 637 | /* RTP info only in some SDP pkts */ |
610 | if (strnicmp(dptr, "INVITE", strlen("INVITE")) != 0 && | 638 | if (strnicmp(dptr, "INVITE", strlen("INVITE")) != 0 && |
611 | strnicmp(dptr, "UPDATE", strlen("UPDATE")) != 0 && | 639 | strnicmp(dptr, "UPDATE", strlen("UPDATE")) != 0 && |
612 | strnicmp(dptr, "SIP/2.0 180", strlen("SIP/2.0 180")) != 0 && | 640 | strnicmp(dptr, "SIP/2.0 180", strlen("SIP/2.0 180")) != 0 && |
613 | strnicmp(dptr, "SIP/2.0 183", strlen("SIP/2.0 183")) != 0 && | 641 | strnicmp(dptr, "SIP/2.0 183", strlen("SIP/2.0 183")) != 0 && |
614 | strnicmp(dptr, "SIP/2.0 200", strlen("SIP/2.0 200")) != 0) { | 642 | strnicmp(dptr, "SIP/2.0 200", strlen("SIP/2.0 200")) != 0) |
615 | goto out; | 643 | return NF_ACCEPT; |
616 | } | ||
617 | /* Get address and port from SDP packet. */ | ||
618 | type = family == AF_INET ? SDP_HDR_CONNECTION_IP4 : | ||
619 | SDP_HDR_CONNECTION_IP6; | ||
620 | if (ct_sip_get_sdp_header(ct, dptr, 0, datalen, type, SDP_HDR_UNSPEC, | ||
621 | &matchoff, &matchlen) > 0) { | ||
622 | 644 | ||
623 | /* We'll drop only if there are parse problems. */ | 645 | return process_sdp(skb, &dptr, &datalen); |
624 | if (!parse_addr(ct, dptr + matchoff, NULL, &addr, | ||
625 | dptr + datalen)) { | ||
626 | ret = NF_DROP; | ||
627 | goto out; | ||
628 | } | ||
629 | if (ct_sip_get_sdp_header(ct, dptr, 0, datalen, | ||
630 | SDP_HDR_MEDIA, SDP_HDR_UNSPEC, | ||
631 | &matchoff, &matchlen) > 0) { | ||
632 | |||
633 | port = simple_strtoul(dptr + matchoff, NULL, 10); | ||
634 | if (port < 1024) { | ||
635 | ret = NF_DROP; | ||
636 | goto out; | ||
637 | } | ||
638 | ret = set_expected_rtp(skb, &dptr, &datalen, | ||
639 | &addr, htons(port)); | ||
640 | } | ||
641 | } | ||
642 | out: | ||
643 | return ret; | ||
644 | } | 646 | } |
645 | 647 | ||
646 | static struct nf_conntrack_helper sip[MAX_PORTS][2] __read_mostly; | 648 | static struct nf_conntrack_helper sip[MAX_PORTS][2] __read_mostly; |