[NETFILTER]: nf_conntrack_sip: support method specific request/response handling
[safe/jmp/linux-2.6] / net / netfilter / nf_conntrack_sip.c
1 /* SIP extension for IP connection tracking.
2  *
3  * (C) 2005 by Christian Hentschel <chentschel@arnet.com.ar>
4  * based on RR's ip_conntrack_ftp.c and other modules.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  */
10
11 #include <linux/module.h>
12 #include <linux/ctype.h>
13 #include <linux/skbuff.h>
14 #include <linux/inet.h>
15 #include <linux/in.h>
16 #include <linux/udp.h>
17 #include <linux/netfilter.h>
18
19 #include <net/netfilter/nf_conntrack.h>
20 #include <net/netfilter/nf_conntrack_expect.h>
21 #include <net/netfilter/nf_conntrack_helper.h>
22 #include <linux/netfilter/nf_conntrack_sip.h>
23
24 MODULE_LICENSE("GPL");
25 MODULE_AUTHOR("Christian Hentschel <chentschel@arnet.com.ar>");
26 MODULE_DESCRIPTION("SIP connection tracking helper");
27 MODULE_ALIAS("ip_conntrack_sip");
28
29 #define MAX_PORTS       8
30 static unsigned short ports[MAX_PORTS];
31 static unsigned int ports_c;
32 module_param_array(ports, ushort, &ports_c, 0400);
33 MODULE_PARM_DESC(ports, "port numbers of SIP servers");
34
35 static unsigned int sip_timeout __read_mostly = SIP_TIMEOUT;
36 module_param(sip_timeout, uint, 0600);
37 MODULE_PARM_DESC(sip_timeout, "timeout for the master SIP session");
38
39 unsigned int (*nf_nat_sip_hook)(struct sk_buff *skb,
40                                 const char **dptr,
41                                 unsigned int *datalen) __read_mostly;
42 EXPORT_SYMBOL_GPL(nf_nat_sip_hook);
43
44 unsigned int (*nf_nat_sdp_hook)(struct sk_buff *skb,
45                                 const char **dptr,
46                                 unsigned int *datalen,
47                                 struct nf_conntrack_expect *exp) __read_mostly;
48 EXPORT_SYMBOL_GPL(nf_nat_sdp_hook);
49
50 static int string_len(const struct nf_conn *ct, const char *dptr,
51                       const char *limit, int *shift)
52 {
53         int len = 0;
54
55         while (dptr < limit && isalpha(*dptr)) {
56                 dptr++;
57                 len++;
58         }
59         return len;
60 }
61
62 static int digits_len(const struct nf_conn *ct, const char *dptr,
63                       const char *limit, int *shift)
64 {
65         int len = 0;
66         while (dptr < limit && isdigit(*dptr)) {
67                 dptr++;
68                 len++;
69         }
70         return len;
71 }
72
73 static int parse_addr(const struct nf_conn *ct, const char *cp,
74                       const char **endp, union nf_inet_addr *addr,
75                       const char *limit)
76 {
77         const char *end;
78         int family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num;
79         int ret = 0;
80
81         switch (family) {
82         case AF_INET:
83                 ret = in4_pton(cp, limit - cp, (u8 *)&addr->ip, -1, &end);
84                 break;
85         case AF_INET6:
86                 ret = in6_pton(cp, limit - cp, (u8 *)&addr->ip6, -1, &end);
87                 break;
88         default:
89                 BUG();
90         }
91
92         if (ret == 0 || end == cp)
93                 return 0;
94         if (endp)
95                 *endp = end;
96         return 1;
97 }
98
99 /* skip ip address. returns its length. */
100 static int epaddr_len(const struct nf_conn *ct, const char *dptr,
101                       const char *limit, int *shift)
102 {
103         union nf_inet_addr addr;
104         const char *aux = dptr;
105
106         if (!parse_addr(ct, dptr, &dptr, &addr, limit)) {
107                 pr_debug("ip: %s parse failed.!\n", dptr);
108                 return 0;
109         }
110
111         /* Port number */
112         if (*dptr == ':') {
113                 dptr++;
114                 dptr += digits_len(ct, dptr, limit, shift);
115         }
116         return dptr - aux;
117 }
118
119 /* get address length, skiping user info. */
120 static int skp_epaddr_len(const struct nf_conn *ct, const char *dptr,
121                           const char *limit, int *shift)
122 {
123         const char *start = dptr;
124         int s = *shift;
125
126         /* Search for @, but stop at the end of the line.
127          * We are inside a sip: URI, so we don't need to worry about
128          * continuation lines. */
129         while (dptr < limit &&
130                *dptr != '@' && *dptr != '\r' && *dptr != '\n') {
131                 (*shift)++;
132                 dptr++;
133         }
134
135         if (dptr < limit && *dptr == '@') {
136                 dptr++;
137                 (*shift)++;
138         } else {
139                 dptr = start;
140                 *shift = s;
141         }
142
143         return epaddr_len(ct, dptr, limit, shift);
144 }
145
146 /* Parse a SIP request line of the form:
147  *
148  * Request-Line = Method SP Request-URI SP SIP-Version CRLF
149  *
150  * and return the offset and length of the address contained in the Request-URI.
151  */
152 int ct_sip_parse_request(const struct nf_conn *ct,
153                          const char *dptr, unsigned int datalen,
154                          unsigned int *matchoff, unsigned int *matchlen,
155                          union nf_inet_addr *addr, __be16 *port)
156 {
157         const char *start = dptr, *limit = dptr + datalen, *end;
158         unsigned int mlen;
159         unsigned int p;
160         int shift = 0;
161
162         /* Skip method and following whitespace */
163         mlen = string_len(ct, dptr, limit, NULL);
164         if (!mlen)
165                 return 0;
166         dptr += mlen;
167         if (++dptr >= limit)
168                 return 0;
169
170         /* Find SIP URI */
171         limit -= strlen("sip:");
172         for (; dptr < limit; dptr++) {
173                 if (*dptr == '\r' || *dptr == '\n')
174                         return -1;
175                 if (strnicmp(dptr, "sip:", strlen("sip:")) == 0)
176                         break;
177         }
178         if (!skp_epaddr_len(ct, dptr, limit, &shift))
179                 return 0;
180         dptr += shift;
181
182         if (!parse_addr(ct, dptr, &end, addr, limit))
183                 return -1;
184         if (end < limit && *end == ':') {
185                 end++;
186                 p = simple_strtoul(end, (char **)&end, 10);
187                 if (p < 1024 || p > 65535)
188                         return -1;
189                 *port = htons(p);
190         } else
191                 *port = htons(SIP_PORT);
192
193         if (end == dptr)
194                 return 0;
195         *matchoff = dptr - start;
196         *matchlen = end - dptr;
197         return 1;
198 }
199 EXPORT_SYMBOL_GPL(ct_sip_parse_request);
200
201 /* SIP header parsing: SIP headers are located at the beginning of a line, but
202  * may span several lines, in which case the continuation lines begin with a
203  * whitespace character. RFC 2543 allows lines to be terminated with CR, LF or
204  * CRLF, RFC 3261 allows only CRLF, we support both.
205  *
206  * Headers are followed by (optionally) whitespace, a colon, again (optionally)
207  * whitespace and the values. Whitespace in this context means any amount of
208  * tabs, spaces and continuation lines, which are treated as a single whitespace
209  * character.
210  *
211  * Some headers may appear multiple times. A comma seperated list of values is
212  * equivalent to multiple headers.
213  */
214 static const struct sip_header ct_sip_hdrs[] = {
215         [SIP_HDR_CSEQ]                  = SIP_HDR("CSeq", NULL, NULL, digits_len),
216         [SIP_HDR_FROM]                  = SIP_HDR("From", "f", "sip:", skp_epaddr_len),
217         [SIP_HDR_TO]                    = SIP_HDR("To", "t", "sip:", skp_epaddr_len),
218         [SIP_HDR_CONTACT]               = SIP_HDR("Contact", "m", "sip:", skp_epaddr_len),
219         [SIP_HDR_VIA]                   = SIP_HDR("Via", "v", "UDP ", epaddr_len),
220         [SIP_HDR_CONTENT_LENGTH]        = SIP_HDR("Content-Length", "l", NULL, digits_len),
221 };
222
223 static const char *sip_follow_continuation(const char *dptr, const char *limit)
224 {
225         /* Walk past newline */
226         if (++dptr >= limit)
227                 return NULL;
228
229         /* Skip '\n' in CR LF */
230         if (*(dptr - 1) == '\r' && *dptr == '\n') {
231                 if (++dptr >= limit)
232                         return NULL;
233         }
234
235         /* Continuation line? */
236         if (*dptr != ' ' && *dptr != '\t')
237                 return NULL;
238
239         /* skip leading whitespace */
240         for (; dptr < limit; dptr++) {
241                 if (*dptr != ' ' && *dptr != '\t')
242                         break;
243         }
244         return dptr;
245 }
246
247 static const char *sip_skip_whitespace(const char *dptr, const char *limit)
248 {
249         for (; dptr < limit; dptr++) {
250                 if (*dptr == ' ')
251                         continue;
252                 if (*dptr != '\r' && *dptr != '\n')
253                         break;
254                 dptr = sip_follow_continuation(dptr, limit);
255                 if (dptr == NULL)
256                         return NULL;
257         }
258         return dptr;
259 }
260
261 /* Search within a SIP header value, dealing with continuation lines */
262 static const char *ct_sip_header_search(const char *dptr, const char *limit,
263                                         const char *needle, unsigned int len)
264 {
265         for (limit -= len; dptr < limit; dptr++) {
266                 if (*dptr == '\r' || *dptr == '\n') {
267                         dptr = sip_follow_continuation(dptr, limit);
268                         if (dptr == NULL)
269                                 break;
270                         continue;
271                 }
272
273                 if (strnicmp(dptr, needle, len) == 0)
274                         return dptr;
275         }
276         return NULL;
277 }
278
279 int ct_sip_get_header(const struct nf_conn *ct, const char *dptr,
280                       unsigned int dataoff, unsigned int datalen,
281                       enum sip_header_types type,
282                       unsigned int *matchoff, unsigned int *matchlen)
283 {
284         const struct sip_header *hdr = &ct_sip_hdrs[type];
285         const char *start = dptr, *limit = dptr + datalen;
286         int shift = 0;
287
288         for (dptr += dataoff; dptr < limit; dptr++) {
289                 /* Find beginning of line */
290                 if (*dptr != '\r' && *dptr != '\n')
291                         continue;
292                 if (++dptr >= limit)
293                         break;
294                 if (*(dptr - 1) == '\r' && *dptr == '\n') {
295                         if (++dptr >= limit)
296                                 break;
297                 }
298
299                 /* Skip continuation lines */
300                 if (*dptr == ' ' || *dptr == '\t')
301                         continue;
302
303                 /* Find header. Compact headers must be followed by a
304                  * non-alphabetic character to avoid mismatches. */
305                 if (limit - dptr >= hdr->len &&
306                     strnicmp(dptr, hdr->name, hdr->len) == 0)
307                         dptr += hdr->len;
308                 else if (hdr->cname && limit - dptr >= hdr->clen + 1 &&
309                          strnicmp(dptr, hdr->cname, hdr->clen) == 0 &&
310                          !isalpha(*(dptr + hdr->clen + 1)))
311                         dptr += hdr->clen;
312                 else
313                         continue;
314
315                 /* Find and skip colon */
316                 dptr = sip_skip_whitespace(dptr, limit);
317                 if (dptr == NULL)
318                         break;
319                 if (*dptr != ':' || ++dptr >= limit)
320                         break;
321
322                 /* Skip whitespace after colon */
323                 dptr = sip_skip_whitespace(dptr, limit);
324                 if (dptr == NULL)
325                         break;
326
327                 *matchoff = dptr - start;
328                 if (hdr->search) {
329                         dptr = ct_sip_header_search(dptr, limit, hdr->search,
330                                                     hdr->slen);
331                         if (!dptr)
332                                 return -1;
333                         dptr += hdr->slen;
334                 }
335
336                 *matchlen = hdr->match_len(ct, dptr, limit, &shift);
337                 if (!*matchlen)
338                         return -1;
339                 *matchoff = dptr - start + shift;
340                 return 1;
341         }
342         return 0;
343 }
344 EXPORT_SYMBOL_GPL(ct_sip_get_header);
345
346 /* Get next header field in a list of comma seperated values */
347 static int ct_sip_next_header(const struct nf_conn *ct, const char *dptr,
348                               unsigned int dataoff, unsigned int datalen,
349                               enum sip_header_types type,
350                               unsigned int *matchoff, unsigned int *matchlen)
351 {
352         const struct sip_header *hdr = &ct_sip_hdrs[type];
353         const char *start = dptr, *limit = dptr + datalen;
354         int shift = 0;
355
356         dptr += dataoff;
357
358         dptr = ct_sip_header_search(dptr, limit, ",", strlen(","));
359         if (!dptr)
360                 return 0;
361
362         dptr = ct_sip_header_search(dptr, limit, hdr->search, hdr->slen);
363         if (!dptr)
364                 return 0;
365         dptr += hdr->slen;
366
367         *matchoff = dptr - start;
368         *matchlen = hdr->match_len(ct, dptr, limit, &shift);
369         if (!*matchlen)
370                 return -1;
371         *matchoff += shift;
372         return 1;
373 }
374
375 /* Walk through headers until a parsable one is found or no header of the
376  * given type is left. */
377 static int ct_sip_walk_headers(const struct nf_conn *ct, const char *dptr,
378                                unsigned int dataoff, unsigned int datalen,
379                                enum sip_header_types type, int *in_header,
380                                unsigned int *matchoff, unsigned int *matchlen)
381 {
382         int ret;
383
384         if (in_header && *in_header) {
385                 while (1) {
386                         ret = ct_sip_next_header(ct, dptr, dataoff, datalen,
387                                                  type, matchoff, matchlen);
388                         if (ret > 0)
389                                 return ret;
390                         if (ret == 0)
391                                 break;
392                         dataoff += *matchoff;
393                 }
394                 *in_header = 0;
395         }
396
397         while (1) {
398                 ret = ct_sip_get_header(ct, dptr, dataoff, datalen,
399                                         type, matchoff, matchlen);
400                 if (ret > 0)
401                         break;
402                 if (ret == 0)
403                         return ret;
404                 dataoff += *matchoff;
405         }
406
407         if (in_header)
408                 *in_header = 1;
409         return 1;
410 }
411
412 /* Locate a SIP header, parse the URI and return the offset and length of
413  * the address as well as the address and port themselves. A stream of
414  * headers can be parsed by handing in a non-NULL datalen and in_header
415  * pointer.
416  */
417 int ct_sip_parse_header_uri(const struct nf_conn *ct, const char *dptr,
418                             unsigned int *dataoff, unsigned int datalen,
419                             enum sip_header_types type, int *in_header,
420                             unsigned int *matchoff, unsigned int *matchlen,
421                             union nf_inet_addr *addr, __be16 *port)
422 {
423         const char *c, *limit = dptr + datalen;
424         unsigned int p;
425         int ret;
426
427         ret = ct_sip_walk_headers(ct, dptr, dataoff ? *dataoff : 0, datalen,
428                                   type, in_header, matchoff, matchlen);
429         WARN_ON(ret < 0);
430         if (ret == 0)
431                 return ret;
432
433         if (!parse_addr(ct, dptr + *matchoff, &c, addr, limit))
434                 return -1;
435         if (*c == ':') {
436                 c++;
437                 p = simple_strtoul(c, (char **)&c, 10);
438                 if (p < 1024 || p > 65535)
439                         return -1;
440                 *port = htons(p);
441         } else
442                 *port = htons(SIP_PORT);
443
444         if (dataoff)
445                 *dataoff = c - dptr;
446         return 1;
447 }
448 EXPORT_SYMBOL_GPL(ct_sip_parse_header_uri);
449
450 /* SDP header parsing: a SDP session description contains an ordered set of
451  * headers, starting with a section containing general session parameters,
452  * optionally followed by multiple media descriptions.
453  *
454  * SDP headers always start at the beginning of a line. According to RFC 2327:
455  * "The sequence CRLF (0x0d0a) is used to end a record, although parsers should
456  * be tolerant and also accept records terminated with a single newline
457  * character". We handle both cases.
458  */
459 static const struct sip_header ct_sdp_hdrs[] = {
460         [SDP_HDR_VERSION]               = SDP_HDR("v=", NULL, digits_len),
461         [SDP_HDR_OWNER_IP4]             = SDP_HDR("o=", "IN IP4 ", epaddr_len),
462         [SDP_HDR_CONNECTION_IP4]        = SDP_HDR("c=", "IN IP4 ", epaddr_len),
463         [SDP_HDR_OWNER_IP6]             = SDP_HDR("o=", "IN IP6 ", epaddr_len),
464         [SDP_HDR_CONNECTION_IP6]        = SDP_HDR("c=", "IN IP6 ", epaddr_len),
465         [SDP_HDR_MEDIA]                 = SDP_HDR("m=", "audio ", digits_len),
466 };
467
468 /* Linear string search within SDP header values */
469 static const char *ct_sdp_header_search(const char *dptr, const char *limit,
470                                         const char *needle, unsigned int len)
471 {
472         for (limit -= len; dptr < limit; dptr++) {
473                 if (*dptr == '\r' || *dptr == '\n')
474                         break;
475                 if (strncmp(dptr, needle, len) == 0)
476                         return dptr;
477         }
478         return NULL;
479 }
480
481 /* Locate a SDP header (optionally a substring within the header value),
482  * optionally stopping at the first occurence of the term header, parse
483  * it and return the offset and length of the data we're interested in.
484  */
485 int ct_sip_get_sdp_header(const struct nf_conn *ct, const char *dptr,
486                           unsigned int dataoff, unsigned int datalen,
487                           enum sdp_header_types type,
488                           enum sdp_header_types term,
489                           unsigned int *matchoff, unsigned int *matchlen)
490 {
491         const struct sip_header *hdr = &ct_sdp_hdrs[type];
492         const struct sip_header *thdr = &ct_sdp_hdrs[term];
493         const char *start = dptr, *limit = dptr + datalen;
494         int shift = 0;
495
496         for (dptr += dataoff; dptr < limit; dptr++) {
497                 /* Find beginning of line */
498                 if (*dptr != '\r' && *dptr != '\n')
499                         continue;
500                 if (++dptr >= limit)
501                         break;
502                 if (*(dptr - 1) == '\r' && *dptr == '\n') {
503                         if (++dptr >= limit)
504                                 break;
505                 }
506
507                 if (term != SDP_HDR_UNSPEC &&
508                     limit - dptr >= thdr->len &&
509                     strnicmp(dptr, thdr->name, thdr->len) == 0)
510                         break;
511                 else if (limit - dptr >= hdr->len &&
512                          strnicmp(dptr, hdr->name, hdr->len) == 0)
513                         dptr += hdr->len;
514                 else
515                         continue;
516
517                 *matchoff = dptr - start;
518                 if (hdr->search) {
519                         dptr = ct_sdp_header_search(dptr, limit, hdr->search,
520                                                     hdr->slen);
521                         if (!dptr)
522                                 return -1;
523                         dptr += hdr->slen;
524                 }
525
526                 *matchlen = hdr->match_len(ct, dptr, limit, &shift);
527                 if (!*matchlen)
528                         return -1;
529                 *matchoff = dptr - start + shift;
530                 return 1;
531         }
532         return 0;
533 }
534 EXPORT_SYMBOL_GPL(ct_sip_get_sdp_header);
535
536 static int set_expected_rtp(struct sk_buff *skb,
537                             const char **dptr, unsigned int *datalen,
538                             union nf_inet_addr *addr, __be16 port)
539 {
540         struct nf_conntrack_expect *exp;
541         enum ip_conntrack_info ctinfo;
542         struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
543         enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
544         int family = ct->tuplehash[!dir].tuple.src.l3num;
545         int ret;
546         typeof(nf_nat_sdp_hook) nf_nat_sdp;
547
548         exp = nf_ct_expect_alloc(ct);
549         if (exp == NULL)
550                 return NF_DROP;
551         nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, family,
552                           &ct->tuplehash[!dir].tuple.src.u3, addr,
553                           IPPROTO_UDP, NULL, &port);
554
555         nf_nat_sdp = rcu_dereference(nf_nat_sdp_hook);
556         if (nf_nat_sdp && ct->status & IPS_NAT_MASK)
557                 ret = nf_nat_sdp(skb, dptr, datalen, exp);
558         else {
559                 if (nf_ct_expect_related(exp) != 0)
560                         ret = NF_DROP;
561                 else
562                         ret = NF_ACCEPT;
563         }
564         nf_ct_expect_put(exp);
565
566         return ret;
567 }
568
569 static int process_sdp(struct sk_buff *skb,
570                        const char **dptr, unsigned int *datalen,
571                        unsigned int cseq)
572 {
573         enum ip_conntrack_info ctinfo;
574         struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
575         int family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num;
576         unsigned int matchoff, matchlen;
577         union nf_inet_addr addr;
578         unsigned int port;
579         enum sdp_header_types type;
580
581         /* Get address and port from SDP packet. */
582         type = family == AF_INET ? SDP_HDR_CONNECTION_IP4 :
583                                    SDP_HDR_CONNECTION_IP6;
584
585         if (ct_sip_get_sdp_header(ct, *dptr, 0, *datalen,
586                                   type, SDP_HDR_UNSPEC,
587                                   &matchoff, &matchlen) <= 0)
588                 return NF_ACCEPT;
589
590         /* We'll drop only if there are parse problems. */
591         if (!parse_addr(ct, *dptr + matchoff, NULL, &addr, *dptr + *datalen))
592                 return NF_DROP;
593
594         if (ct_sip_get_sdp_header(ct, *dptr, 0, *datalen,
595                                   SDP_HDR_MEDIA, SDP_HDR_UNSPEC,
596                                   &matchoff, &matchlen) <= 0)
597                 return NF_ACCEPT;
598
599         port = simple_strtoul(*dptr + matchoff, NULL, 10);
600         if (port < 1024 || port > 65535)
601                 return NF_DROP;
602
603         return set_expected_rtp(skb, dptr, datalen, &addr, htons(port));
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 }
695
696 static int sip_help(struct sk_buff *skb,
697                     unsigned int protoff,
698                     struct nf_conn *ct,
699                     enum ip_conntrack_info ctinfo)
700 {
701         unsigned int dataoff, datalen;
702         const char *dptr;
703         typeof(nf_nat_sip_hook) nf_nat_sip;
704
705         /* No Data ? */
706         dataoff = protoff + sizeof(struct udphdr);
707         if (dataoff >= skb->len)
708                 return NF_ACCEPT;
709
710         nf_ct_refresh(ct, skb, sip_timeout * HZ);
711
712         if (!skb_is_nonlinear(skb))
713                 dptr = skb->data + dataoff;
714         else {
715                 pr_debug("Copy of skbuff not supported yet.\n");
716                 return NF_ACCEPT;
717         }
718
719         nf_nat_sip = rcu_dereference(nf_nat_sip_hook);
720         if (nf_nat_sip && ct->status & IPS_NAT_MASK) {
721                 if (!nf_nat_sip(skb, &dptr, &datalen))
722                         return NF_DROP;
723         }
724
725         datalen = skb->len - dataoff;
726         if (datalen < strlen("SIP/2.0 200"))
727                 return NF_ACCEPT;
728
729         if (strnicmp(dptr, "SIP/2.0 ", strlen("SIP/2.0 ")) != 0)
730                 return process_sip_request(skb, &dptr, &datalen);
731         else
732                 return process_sip_response(skb, &dptr, &datalen);
733 }
734
735 static struct nf_conntrack_helper sip[MAX_PORTS][2] __read_mostly;
736 static char sip_names[MAX_PORTS][2][sizeof("sip-65535")] __read_mostly;
737
738 static const struct nf_conntrack_expect_policy sip_exp_policy = {
739         .max_expected   = 2,
740         .timeout        = 3 * 60,
741 };
742
743 static void nf_conntrack_sip_fini(void)
744 {
745         int i, j;
746
747         for (i = 0; i < ports_c; i++) {
748                 for (j = 0; j < 2; j++) {
749                         if (sip[i][j].me == NULL)
750                                 continue;
751                         nf_conntrack_helper_unregister(&sip[i][j]);
752                 }
753         }
754 }
755
756 static int __init nf_conntrack_sip_init(void)
757 {
758         int i, j, ret;
759         char *tmpname;
760
761         if (ports_c == 0)
762                 ports[ports_c++] = SIP_PORT;
763
764         for (i = 0; i < ports_c; i++) {
765                 memset(&sip[i], 0, sizeof(sip[i]));
766
767                 sip[i][0].tuple.src.l3num = AF_INET;
768                 sip[i][1].tuple.src.l3num = AF_INET6;
769                 for (j = 0; j < 2; j++) {
770                         sip[i][j].tuple.dst.protonum = IPPROTO_UDP;
771                         sip[i][j].tuple.src.u.udp.port = htons(ports[i]);
772                         sip[i][j].expect_policy = &sip_exp_policy;
773                         sip[i][j].me = THIS_MODULE;
774                         sip[i][j].help = sip_help;
775
776                         tmpname = &sip_names[i][j][0];
777                         if (ports[i] == SIP_PORT)
778                                 sprintf(tmpname, "sip");
779                         else
780                                 sprintf(tmpname, "sip-%u", i);
781                         sip[i][j].name = tmpname;
782
783                         pr_debug("port #%u: %u\n", i, ports[i]);
784
785                         ret = nf_conntrack_helper_register(&sip[i][j]);
786                         if (ret) {
787                                 printk("nf_ct_sip: failed to register helper "
788                                        "for pf: %u port: %u\n",
789                                        sip[i][j].tuple.src.l3num, ports[i]);
790                                 nf_conntrack_sip_fini();
791                                 return ret;
792                         }
793                 }
794         }
795         return 0;
796 }
797
798 module_init(nf_conntrack_sip_init);
799 module_exit(nf_conntrack_sip_fini);