aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2008-03-25 23:22:20 -0400
committerDavid S. Miller <davem@davemloft.net>2008-03-25 23:22:20 -0400
commit30f33e6dee80c6ded917f978e4f377d1069d519d (patch)
tree95bd9e8356d37aa3f7c7edc6f6637fc05d8b3b8d
parent7d3dd043b69b10f5abe9c785ab82cc6627898fcd (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.h20
-rw-r--r--net/netfilter/nf_conntrack_sip.c107
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
8struct 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
8struct sip_header { 27struct 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
37enum sip_header_types { 56enum 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 */
214static const struct sip_header ct_sip_hdrs[] = { 214static 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
568static int process_sdp(struct sk_buff *skb, 569static 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}
605static 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
616static 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
627static 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
632static 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
667static 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
604static int sip_help(struct sk_buff *skb, 696static 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
648static struct nf_conntrack_helper sip[MAX_PORTS][2] __read_mostly; 735static struct nf_conntrack_helper sip[MAX_PORTS][2] __read_mostly;