diff options
author | Patrick McHardy <kaber@trash.net> | 2008-03-25 23:22:20 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-03-25 23:22:20 -0400 |
commit | 30f33e6dee80c6ded917f978e4f377d1069d519d (patch) | |
tree | 95bd9e8356d37aa3f7c7edc6f6637fc05d8b3b8d | |
parent | 7d3dd043b69b10f5abe9c785ab82cc6627898fcd (diff) |
[NETFILTER]: nf_conntrack_sip: support method specific request/response handling
Add support for per-method request/response handlers and perform SDP
parsing for INVITE/UPDATE requests and for all informational and
successful responses.
Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/linux/netfilter/nf_conntrack_sip.h | 20 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_sip.c | 107 |
2 files changed, 117 insertions, 10 deletions
diff --git a/include/linux/netfilter/nf_conntrack_sip.h b/include/linux/netfilter/nf_conntrack_sip.h index 68a0d6a41733..da93e80804c2 100644 --- a/include/linux/netfilter/nf_conntrack_sip.h +++ b/include/linux/netfilter/nf_conntrack_sip.h | |||
@@ -5,6 +5,25 @@ | |||
5 | #define SIP_PORT 5060 | 5 | #define SIP_PORT 5060 |
6 | #define SIP_TIMEOUT 3600 | 6 | #define SIP_TIMEOUT 3600 |
7 | 7 | ||
8 | struct sip_handler { | ||
9 | const char *method; | ||
10 | unsigned int len; | ||
11 | int (*request)(struct sk_buff *skb, | ||
12 | const char **dptr, unsigned int *datalen, | ||
13 | unsigned int cseq); | ||
14 | int (*response)(struct sk_buff *skb, | ||
15 | const char **dptr, unsigned int *datalen, | ||
16 | unsigned int cseq, unsigned int code); | ||
17 | }; | ||
18 | |||
19 | #define SIP_HANDLER(__method, __request, __response) \ | ||
20 | { \ | ||
21 | .method = (__method), \ | ||
22 | .len = sizeof(__method) - 1, \ | ||
23 | .request = (__request), \ | ||
24 | .response = (__response), \ | ||
25 | } | ||
26 | |||
8 | struct sip_header { | 27 | struct sip_header { |
9 | const char *name; | 28 | const char *name; |
10 | const char *cname; | 29 | const char *cname; |
@@ -35,6 +54,7 @@ struct sip_header { | |||
35 | __SIP_HDR(__name, NULL, __search, __match) | 54 | __SIP_HDR(__name, NULL, __search, __match) |
36 | 55 | ||
37 | enum sip_header_types { | 56 | enum sip_header_types { |
57 | SIP_HDR_CSEQ, | ||
38 | SIP_HDR_FROM, | 58 | SIP_HDR_FROM, |
39 | SIP_HDR_TO, | 59 | SIP_HDR_TO, |
40 | SIP_HDR_CONTACT, | 60 | SIP_HDR_CONTACT, |
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index 96bedb52bd4b..1be949febab7 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c | |||
@@ -212,6 +212,7 @@ EXPORT_SYMBOL_GPL(ct_sip_parse_request); | |||
212 | * equivalent to multiple headers. | 212 | * equivalent to multiple headers. |
213 | */ | 213 | */ |
214 | static const struct sip_header ct_sip_hdrs[] = { | 214 | static const struct sip_header ct_sip_hdrs[] = { |
215 | [SIP_HDR_CSEQ] = SIP_HDR("CSeq", NULL, NULL, digits_len), | ||
215 | [SIP_HDR_FROM] = SIP_HDR("From", "f", "sip:", skp_epaddr_len), | 216 | [SIP_HDR_FROM] = SIP_HDR("From", "f", "sip:", skp_epaddr_len), |
216 | [SIP_HDR_TO] = SIP_HDR("To", "t", "sip:", skp_epaddr_len), | 217 | [SIP_HDR_TO] = SIP_HDR("To", "t", "sip:", skp_epaddr_len), |
217 | [SIP_HDR_CONTACT] = SIP_HDR("Contact", "m", "sip:", skp_epaddr_len), | 218 | [SIP_HDR_CONTACT] = SIP_HDR("Contact", "m", "sip:", skp_epaddr_len), |
@@ -566,7 +567,8 @@ static int set_expected_rtp(struct sk_buff *skb, | |||
566 | } | 567 | } |
567 | 568 | ||
568 | static int process_sdp(struct sk_buff *skb, | 569 | static int process_sdp(struct sk_buff *skb, |
569 | const char **dptr, unsigned int *datalen) | 570 | const char **dptr, unsigned int *datalen, |
571 | unsigned int cseq) | ||
570 | { | 572 | { |
571 | enum ip_conntrack_info ctinfo; | 573 | enum ip_conntrack_info ctinfo; |
572 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); | 574 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); |
@@ -600,6 +602,96 @@ static int process_sdp(struct sk_buff *skb, | |||
600 | 602 | ||
601 | return set_expected_rtp(skb, dptr, datalen, &addr, htons(port)); | 603 | return set_expected_rtp(skb, dptr, datalen, &addr, htons(port)); |
602 | } | 604 | } |
605 | static int process_invite_response(struct sk_buff *skb, | ||
606 | const char **dptr, unsigned int *datalen, | ||
607 | unsigned int cseq, unsigned int code) | ||
608 | { | ||
609 | if ((code >= 100 && code <= 199) || | ||
610 | (code >= 200 && code <= 299)) | ||
611 | return process_sdp(skb, dptr, datalen, cseq); | ||
612 | |||
613 | return NF_ACCEPT; | ||
614 | } | ||
615 | |||
616 | static int process_update_response(struct sk_buff *skb, | ||
617 | const char **dptr, unsigned int *datalen, | ||
618 | unsigned int cseq, unsigned int code) | ||
619 | { | ||
620 | if ((code >= 100 && code <= 199) || | ||
621 | (code >= 200 && code <= 299)) | ||
622 | return process_sdp(skb, dptr, datalen, cseq); | ||
623 | |||
624 | return NF_ACCEPT; | ||
625 | } | ||
626 | |||
627 | static const struct sip_handler sip_handlers[] = { | ||
628 | SIP_HANDLER("INVITE", process_sdp, process_invite_response), | ||
629 | SIP_HANDLER("UPDATE", process_sdp, process_update_response), | ||
630 | }; | ||
631 | |||
632 | static int process_sip_response(struct sk_buff *skb, | ||
633 | const char **dptr, unsigned int *datalen) | ||
634 | { | ||
635 | static const struct sip_handler *handler; | ||
636 | enum ip_conntrack_info ctinfo; | ||
637 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); | ||
638 | unsigned int matchoff, matchlen; | ||
639 | unsigned int code, cseq, dataoff, i; | ||
640 | |||
641 | if (*datalen < strlen("SIP/2.0 200")) | ||
642 | return NF_ACCEPT; | ||
643 | code = simple_strtoul(*dptr + strlen("SIP/2.0 "), NULL, 10); | ||
644 | if (!code) | ||
645 | return NF_DROP; | ||
646 | |||
647 | if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_CSEQ, | ||
648 | &matchoff, &matchlen) <= 0) | ||
649 | return NF_DROP; | ||
650 | cseq = simple_strtoul(*dptr + matchoff, NULL, 10); | ||
651 | if (!cseq) | ||
652 | return NF_DROP; | ||
653 | dataoff = matchoff + matchlen + 1; | ||
654 | |||
655 | for (i = 0; i < ARRAY_SIZE(sip_handlers); i++) { | ||
656 | handler = &sip_handlers[i]; | ||
657 | if (handler->response == NULL) | ||
658 | continue; | ||
659 | if (*datalen < dataoff + handler->len || | ||
660 | strnicmp(*dptr + dataoff, handler->method, handler->len)) | ||
661 | continue; | ||
662 | return handler->response(skb, dptr, datalen, cseq, code); | ||
663 | } | ||
664 | return NF_ACCEPT; | ||
665 | } | ||
666 | |||
667 | static int process_sip_request(struct sk_buff *skb, | ||
668 | const char **dptr, unsigned int *datalen) | ||
669 | { | ||
670 | static const struct sip_handler *handler; | ||
671 | enum ip_conntrack_info ctinfo; | ||
672 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); | ||
673 | unsigned int matchoff, matchlen; | ||
674 | unsigned int cseq, i; | ||
675 | |||
676 | for (i = 0; i < ARRAY_SIZE(sip_handlers); i++) { | ||
677 | handler = &sip_handlers[i]; | ||
678 | if (handler->request == NULL) | ||
679 | continue; | ||
680 | if (*datalen < handler->len || | ||
681 | strnicmp(*dptr, handler->method, handler->len)) | ||
682 | continue; | ||
683 | |||
684 | if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_CSEQ, | ||
685 | &matchoff, &matchlen) <= 0) | ||
686 | return NF_DROP; | ||
687 | cseq = simple_strtoul(*dptr + matchoff, NULL, 10); | ||
688 | if (!cseq) | ||
689 | return NF_DROP; | ||
690 | |||
691 | return handler->request(skb, dptr, datalen, cseq); | ||
692 | } | ||
693 | return NF_ACCEPT; | ||
694 | } | ||
603 | 695 | ||
604 | static int sip_help(struct sk_buff *skb, | 696 | static int sip_help(struct sk_buff *skb, |
605 | unsigned int protoff, | 697 | unsigned int protoff, |
@@ -634,15 +726,10 @@ static int sip_help(struct sk_buff *skb, | |||
634 | if (datalen < strlen("SIP/2.0 200")) | 726 | if (datalen < strlen("SIP/2.0 200")) |
635 | return NF_ACCEPT; | 727 | return NF_ACCEPT; |
636 | 728 | ||
637 | /* RTP info only in some SDP pkts */ | 729 | if (strnicmp(dptr, "SIP/2.0 ", strlen("SIP/2.0 ")) != 0) |
638 | if (strnicmp(dptr, "INVITE", strlen("INVITE")) != 0 && | 730 | return process_sip_request(skb, &dptr, &datalen); |
639 | strnicmp(dptr, "UPDATE", strlen("UPDATE")) != 0 && | 731 | else |
640 | strnicmp(dptr, "SIP/2.0 180", strlen("SIP/2.0 180")) != 0 && | 732 | return process_sip_response(skb, &dptr, &datalen); |
641 | strnicmp(dptr, "SIP/2.0 183", strlen("SIP/2.0 183")) != 0 && | ||
642 | strnicmp(dptr, "SIP/2.0 200", strlen("SIP/2.0 200")) != 0) | ||
643 | return NF_ACCEPT; | ||
644 | |||
645 | return process_sdp(skb, &dptr, &datalen); | ||
646 | } | 733 | } |
647 | 734 | ||
648 | static struct nf_conntrack_helper sip[MAX_PORTS][2] __read_mostly; | 735 | static struct nf_conntrack_helper sip[MAX_PORTS][2] __read_mostly; |