[NETFILTER]: nf_conntrack_sip: introduce URI and header parameter parsing helpers
[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_core.h>
21 #include <net/netfilter/nf_conntrack_expect.h>
22 #include <net/netfilter/nf_conntrack_helper.h>
23 #include <linux/netfilter/nf_conntrack_sip.h>
24
25 MODULE_LICENSE("GPL");
26 MODULE_AUTHOR("Christian Hentschel <chentschel@arnet.com.ar>");
27 MODULE_DESCRIPTION("SIP connection tracking helper");
28 MODULE_ALIAS("ip_conntrack_sip");
29
30 #define MAX_PORTS       8
31 static unsigned short ports[MAX_PORTS];
32 static unsigned int ports_c;
33 module_param_array(ports, ushort, &ports_c, 0400);
34 MODULE_PARM_DESC(ports, "port numbers of SIP servers");
35
36 static unsigned int sip_timeout __read_mostly = SIP_TIMEOUT;
37 module_param(sip_timeout, uint, 0600);
38 MODULE_PARM_DESC(sip_timeout, "timeout for the master SIP session");
39
40 unsigned int (*nf_nat_sip_hook)(struct sk_buff *skb,
41                                 const char **dptr,
42                                 unsigned int *datalen) __read_mostly;
43 EXPORT_SYMBOL_GPL(nf_nat_sip_hook);
44
45 unsigned int (*nf_nat_sdp_hook)(struct sk_buff *skb,
46                                 const char **dptr,
47                                 unsigned int *datalen,
48                                 struct nf_conntrack_expect *exp) __read_mostly;
49 EXPORT_SYMBOL_GPL(nf_nat_sdp_hook);
50
51 static int string_len(const struct nf_conn *ct, const char *dptr,
52                       const char *limit, int *shift)
53 {
54         int len = 0;
55
56         while (dptr < limit && isalpha(*dptr)) {
57                 dptr++;
58                 len++;
59         }
60         return len;
61 }
62
63 static int digits_len(const struct nf_conn *ct, const char *dptr,
64                       const char *limit, int *shift)
65 {
66         int len = 0;
67         while (dptr < limit && isdigit(*dptr)) {
68                 dptr++;
69                 len++;
70         }
71         return len;
72 }
73
74 static int parse_addr(const struct nf_conn *ct, const char *cp,
75                       const char **endp, union nf_inet_addr *addr,
76                       const char *limit)
77 {
78         const char *end;
79         int family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num;
80         int ret = 0;
81
82         switch (family) {
83         case AF_INET:
84                 ret = in4_pton(cp, limit - cp, (u8 *)&addr->ip, -1, &end);
85                 break;
86         case AF_INET6:
87                 ret = in6_pton(cp, limit - cp, (u8 *)&addr->ip6, -1, &end);
88                 break;
89         default:
90                 BUG();
91         }
92
93         if (ret == 0 || end == cp)
94                 return 0;
95         if (endp)
96                 *endp = end;
97         return 1;
98 }
99
100 /* skip ip address. returns its length. */
101 static int epaddr_len(const struct nf_conn *ct, const char *dptr,
102                       const char *limit, int *shift)
103 {
104         union nf_inet_addr addr;
105         const char *aux = dptr;
106
107         if (!parse_addr(ct, dptr, &dptr, &addr, limit)) {
108                 pr_debug("ip: %s parse failed.!\n", dptr);
109                 return 0;
110         }
111
112         /* Port number */
113         if (*dptr == ':') {
114                 dptr++;
115                 dptr += digits_len(ct, dptr, limit, shift);
116         }
117         return dptr - aux;
118 }
119
120 /* get address length, skiping user info. */
121 static int skp_epaddr_len(const struct nf_conn *ct, const char *dptr,
122                           const char *limit, int *shift)
123 {
124         const char *start = dptr;
125         int s = *shift;
126
127         /* Search for @, but stop at the end of the line.
128          * We are inside a sip: URI, so we don't need to worry about
129          * continuation lines. */
130         while (dptr < limit &&
131                *dptr != '@' && *dptr != '\r' && *dptr != '\n') {
132                 (*shift)++;
133                 dptr++;
134         }
135
136         if (dptr < limit && *dptr == '@') {
137                 dptr++;
138                 (*shift)++;
139         } else {
140                 dptr = start;
141                 *shift = s;
142         }
143
144         return epaddr_len(ct, dptr, limit, shift);
145 }
146
147 /* Parse a SIP request line of the form:
148  *
149  * Request-Line = Method SP Request-URI SP SIP-Version CRLF
150  *
151  * and return the offset and length of the address contained in the Request-URI.
152  */
153 int ct_sip_parse_request(const struct nf_conn *ct,
154                          const char *dptr, unsigned int datalen,
155                          unsigned int *matchoff, unsigned int *matchlen,
156                          union nf_inet_addr *addr, __be16 *port)
157 {
158         const char *start = dptr, *limit = dptr + datalen, *end;
159         unsigned int mlen;
160         unsigned int p;
161         int shift = 0;
162
163         /* Skip method and following whitespace */
164         mlen = string_len(ct, dptr, limit, NULL);
165         if (!mlen)
166                 return 0;
167         dptr += mlen;
168         if (++dptr >= limit)
169                 return 0;
170
171         /* Find SIP URI */
172         limit -= strlen("sip:");
173         for (; dptr < limit; dptr++) {
174                 if (*dptr == '\r' || *dptr == '\n')
175                         return -1;
176                 if (strnicmp(dptr, "sip:", strlen("sip:")) == 0)
177                         break;
178         }
179         if (!skp_epaddr_len(ct, dptr, limit, &shift))
180                 return 0;
181         dptr += shift;
182
183         if (!parse_addr(ct, dptr, &end, addr, limit))
184                 return -1;
185         if (end < limit && *end == ':') {
186                 end++;
187                 p = simple_strtoul(end, (char **)&end, 10);
188                 if (p < 1024 || p > 65535)
189                         return -1;
190                 *port = htons(p);
191         } else
192                 *port = htons(SIP_PORT);
193
194         if (end == dptr)
195                 return 0;
196         *matchoff = dptr - start;
197         *matchlen = end - dptr;
198         return 1;
199 }
200 EXPORT_SYMBOL_GPL(ct_sip_parse_request);
201
202 /* SIP header parsing: SIP headers are located at the beginning of a line, but
203  * may span several lines, in which case the continuation lines begin with a
204  * whitespace character. RFC 2543 allows lines to be terminated with CR, LF or
205  * CRLF, RFC 3261 allows only CRLF, we support both.
206  *
207  * Headers are followed by (optionally) whitespace, a colon, again (optionally)
208  * whitespace and the values. Whitespace in this context means any amount of
209  * tabs, spaces and continuation lines, which are treated as a single whitespace
210  * character.
211  *
212  * Some headers may appear multiple times. A comma seperated list of values is
213  * equivalent to multiple headers.
214  */
215 static const struct sip_header ct_sip_hdrs[] = {
216         [SIP_HDR_CSEQ]                  = SIP_HDR("CSeq", NULL, NULL, digits_len),
217         [SIP_HDR_FROM]                  = SIP_HDR("From", "f", "sip:", skp_epaddr_len),
218         [SIP_HDR_TO]                    = SIP_HDR("To", "t", "sip:", skp_epaddr_len),
219         [SIP_HDR_CONTACT]               = SIP_HDR("Contact", "m", "sip:", skp_epaddr_len),
220         [SIP_HDR_VIA]                   = SIP_HDR("Via", "v", "UDP ", epaddr_len),
221         [SIP_HDR_CONTENT_LENGTH]        = SIP_HDR("Content-Length", "l", NULL, digits_len),
222 };
223
224 static const char *sip_follow_continuation(const char *dptr, const char *limit)
225 {
226         /* Walk past newline */
227         if (++dptr >= limit)
228                 return NULL;
229
230         /* Skip '\n' in CR LF */
231         if (*(dptr - 1) == '\r' && *dptr == '\n') {
232                 if (++dptr >= limit)
233                         return NULL;
234         }
235
236         /* Continuation line? */
237         if (*dptr != ' ' && *dptr != '\t')
238                 return NULL;
239
240         /* skip leading whitespace */
241         for (; dptr < limit; dptr++) {
242                 if (*dptr != ' ' && *dptr != '\t')
243                         break;
244         }
245         return dptr;
246 }
247
248 static const char *sip_skip_whitespace(const char *dptr, const char *limit)
249 {
250         for (; dptr < limit; dptr++) {
251                 if (*dptr == ' ')
252                         continue;
253                 if (*dptr != '\r' && *dptr != '\n')
254                         break;
255                 dptr = sip_follow_continuation(dptr, limit);
256                 if (dptr == NULL)
257                         return NULL;
258         }
259         return dptr;
260 }
261
262 /* Search within a SIP header value, dealing with continuation lines */
263 static const char *ct_sip_header_search(const char *dptr, const char *limit,
264                                         const char *needle, unsigned int len)
265 {
266         for (limit -= len; dptr < limit; dptr++) {
267                 if (*dptr == '\r' || *dptr == '\n') {
268                         dptr = sip_follow_continuation(dptr, limit);
269                         if (dptr == NULL)
270                                 break;
271                         continue;
272                 }
273
274                 if (strnicmp(dptr, needle, len) == 0)
275                         return dptr;
276         }
277         return NULL;
278 }
279
280 int ct_sip_get_header(const struct nf_conn *ct, const char *dptr,
281                       unsigned int dataoff, unsigned int datalen,
282                       enum sip_header_types type,
283                       unsigned int *matchoff, unsigned int *matchlen)
284 {
285         const struct sip_header *hdr = &ct_sip_hdrs[type];
286         const char *start = dptr, *limit = dptr + datalen;
287         int shift = 0;
288
289         for (dptr += dataoff; dptr < limit; dptr++) {
290                 /* Find beginning of line */
291                 if (*dptr != '\r' && *dptr != '\n')
292                         continue;
293                 if (++dptr >= limit)
294                         break;
295                 if (*(dptr - 1) == '\r' && *dptr == '\n') {
296                         if (++dptr >= limit)
297                                 break;
298                 }
299
300                 /* Skip continuation lines */
301                 if (*dptr == ' ' || *dptr == '\t')
302                         continue;
303
304                 /* Find header. Compact headers must be followed by a
305                  * non-alphabetic character to avoid mismatches. */
306                 if (limit - dptr >= hdr->len &&
307                     strnicmp(dptr, hdr->name, hdr->len) == 0)
308                         dptr += hdr->len;
309                 else if (hdr->cname && limit - dptr >= hdr->clen + 1 &&
310                          strnicmp(dptr, hdr->cname, hdr->clen) == 0 &&
311                          !isalpha(*(dptr + hdr->clen + 1)))
312                         dptr += hdr->clen;
313                 else
314                         continue;
315
316                 /* Find and skip colon */
317                 dptr = sip_skip_whitespace(dptr, limit);
318                 if (dptr == NULL)
319                         break;
320                 if (*dptr != ':' || ++dptr >= limit)
321                         break;
322
323                 /* Skip whitespace after colon */
324                 dptr = sip_skip_whitespace(dptr, limit);
325                 if (dptr == NULL)
326                         break;
327
328                 *matchoff = dptr - start;
329                 if (hdr->search) {
330                         dptr = ct_sip_header_search(dptr, limit, hdr->search,
331                                                     hdr->slen);
332                         if (!dptr)
333                                 return -1;
334                         dptr += hdr->slen;
335                 }
336
337                 *matchlen = hdr->match_len(ct, dptr, limit, &shift);
338                 if (!*matchlen)
339                         return -1;
340                 *matchoff = dptr - start + shift;
341                 return 1;
342         }
343         return 0;
344 }
345 EXPORT_SYMBOL_GPL(ct_sip_get_header);
346
347 /* Get next header field in a list of comma seperated values */
348 static int ct_sip_next_header(const struct nf_conn *ct, const char *dptr,
349                               unsigned int dataoff, unsigned int datalen,
350                               enum sip_header_types type,
351                               unsigned int *matchoff, unsigned int *matchlen)
352 {
353         const struct sip_header *hdr = &ct_sip_hdrs[type];
354         const char *start = dptr, *limit = dptr + datalen;
355         int shift = 0;
356
357         dptr += dataoff;
358
359         dptr = ct_sip_header_search(dptr, limit, ",", strlen(","));
360         if (!dptr)
361                 return 0;
362
363         dptr = ct_sip_header_search(dptr, limit, hdr->search, hdr->slen);
364         if (!dptr)
365                 return 0;
366         dptr += hdr->slen;
367
368         *matchoff = dptr - start;
369         *matchlen = hdr->match_len(ct, dptr, limit, &shift);
370         if (!*matchlen)
371                 return -1;
372         *matchoff += shift;
373         return 1;
374 }
375
376 /* Walk through headers until a parsable one is found or no header of the
377  * given type is left. */
378 static int ct_sip_walk_headers(const struct nf_conn *ct, const char *dptr,
379                                unsigned int dataoff, unsigned int datalen,
380                                enum sip_header_types type, int *in_header,
381                                unsigned int *matchoff, unsigned int *matchlen)
382 {
383         int ret;
384
385         if (in_header && *in_header) {
386                 while (1) {
387                         ret = ct_sip_next_header(ct, dptr, dataoff, datalen,
388                                                  type, matchoff, matchlen);
389                         if (ret > 0)
390                                 return ret;
391                         if (ret == 0)
392                                 break;
393                         dataoff += *matchoff;
394                 }
395                 *in_header = 0;
396         }
397
398         while (1) {
399                 ret = ct_sip_get_header(ct, dptr, dataoff, datalen,
400                                         type, matchoff, matchlen);
401                 if (ret > 0)
402                         break;
403                 if (ret == 0)
404                         return ret;
405                 dataoff += *matchoff;
406         }
407
408         if (in_header)
409                 *in_header = 1;
410         return 1;
411 }
412
413 /* Locate a SIP header, parse the URI and return the offset and length of
414  * the address as well as the address and port themselves. A stream of
415  * headers can be parsed by handing in a non-NULL datalen and in_header
416  * pointer.
417  */
418 int ct_sip_parse_header_uri(const struct nf_conn *ct, const char *dptr,
419                             unsigned int *dataoff, unsigned int datalen,
420                             enum sip_header_types type, int *in_header,
421                             unsigned int *matchoff, unsigned int *matchlen,
422                             union nf_inet_addr *addr, __be16 *port)
423 {
424         const char *c, *limit = dptr + datalen;
425         unsigned int p;
426         int ret;
427
428         ret = ct_sip_walk_headers(ct, dptr, dataoff ? *dataoff : 0, datalen,
429                                   type, in_header, matchoff, matchlen);
430         WARN_ON(ret < 0);
431         if (ret == 0)
432                 return ret;
433
434         if (!parse_addr(ct, dptr + *matchoff, &c, addr, limit))
435                 return -1;
436         if (*c == ':') {
437                 c++;
438                 p = simple_strtoul(c, (char **)&c, 10);
439                 if (p < 1024 || p > 65535)
440                         return -1;
441                 *port = htons(p);
442         } else
443                 *port = htons(SIP_PORT);
444
445         if (dataoff)
446                 *dataoff = c - dptr;
447         return 1;
448 }
449 EXPORT_SYMBOL_GPL(ct_sip_parse_header_uri);
450
451 /* Parse address from header parameter and return address, offset and length */
452 int ct_sip_parse_address_param(const struct nf_conn *ct, const char *dptr,
453                                unsigned int dataoff, unsigned int datalen,
454                                const char *name,
455                                unsigned int *matchoff, unsigned int *matchlen,
456                                union nf_inet_addr *addr)
457 {
458         const char *limit = dptr + datalen;
459         const char *start, *end;
460
461         limit = ct_sip_header_search(dptr + dataoff, limit, ",", strlen(","));
462         if (!limit)
463                 limit = dptr + datalen;
464
465         start = ct_sip_header_search(dptr + dataoff, limit, name, strlen(name));
466         if (!start)
467                 return 0;
468
469         start += strlen(name);
470         if (!parse_addr(ct, start, &end, addr, limit))
471                 return 0;
472         *matchoff = start - dptr;
473         *matchlen = end - start;
474         return 1;
475 }
476 EXPORT_SYMBOL_GPL(ct_sip_parse_address_param);
477
478 /* Parse numerical header parameter and return value, offset and length */
479 int ct_sip_parse_numerical_param(const struct nf_conn *ct, const char *dptr,
480                                  unsigned int dataoff, unsigned int datalen,
481                                  const char *name,
482                                  unsigned int *matchoff, unsigned int *matchlen,
483                                  unsigned int *val)
484 {
485         const char *limit = dptr + datalen;
486         const char *start;
487         char *end;
488
489         limit = ct_sip_header_search(dptr + dataoff, limit, ",", strlen(","));
490         if (!limit)
491                 limit = dptr + datalen;
492
493         start = ct_sip_header_search(dptr + dataoff, limit, name, strlen(name));
494         if (!start)
495                 return 0;
496
497         start += strlen(name);
498         *val = simple_strtoul(start, &end, 0);
499         if (start == end)
500                 return 0;
501         if (matchoff && matchlen) {
502                 *matchoff = start - dptr;
503                 *matchlen = end - start;
504         }
505         return 1;
506 }
507 EXPORT_SYMBOL_GPL(ct_sip_parse_numerical_param);
508
509 /* SDP header parsing: a SDP session description contains an ordered set of
510  * headers, starting with a section containing general session parameters,
511  * optionally followed by multiple media descriptions.
512  *
513  * SDP headers always start at the beginning of a line. According to RFC 2327:
514  * "The sequence CRLF (0x0d0a) is used to end a record, although parsers should
515  * be tolerant and also accept records terminated with a single newline
516  * character". We handle both cases.
517  */
518 static const struct sip_header ct_sdp_hdrs[] = {
519         [SDP_HDR_VERSION]               = SDP_HDR("v=", NULL, digits_len),
520         [SDP_HDR_OWNER_IP4]             = SDP_HDR("o=", "IN IP4 ", epaddr_len),
521         [SDP_HDR_CONNECTION_IP4]        = SDP_HDR("c=", "IN IP4 ", epaddr_len),
522         [SDP_HDR_OWNER_IP6]             = SDP_HDR("o=", "IN IP6 ", epaddr_len),
523         [SDP_HDR_CONNECTION_IP6]        = SDP_HDR("c=", "IN IP6 ", epaddr_len),
524         [SDP_HDR_MEDIA]                 = SDP_HDR("m=", "audio ", digits_len),
525 };
526
527 /* Linear string search within SDP header values */
528 static const char *ct_sdp_header_search(const char *dptr, const char *limit,
529                                         const char *needle, unsigned int len)
530 {
531         for (limit -= len; dptr < limit; dptr++) {
532                 if (*dptr == '\r' || *dptr == '\n')
533                         break;
534                 if (strncmp(dptr, needle, len) == 0)
535                         return dptr;
536         }
537         return NULL;
538 }
539
540 /* Locate a SDP header (optionally a substring within the header value),
541  * optionally stopping at the first occurence of the term header, parse
542  * it and return the offset and length of the data we're interested in.
543  */
544 int ct_sip_get_sdp_header(const struct nf_conn *ct, const char *dptr,
545                           unsigned int dataoff, unsigned int datalen,
546                           enum sdp_header_types type,
547                           enum sdp_header_types term,
548                           unsigned int *matchoff, unsigned int *matchlen)
549 {
550         const struct sip_header *hdr = &ct_sdp_hdrs[type];
551         const struct sip_header *thdr = &ct_sdp_hdrs[term];
552         const char *start = dptr, *limit = dptr + datalen;
553         int shift = 0;
554
555         for (dptr += dataoff; dptr < limit; dptr++) {
556                 /* Find beginning of line */
557                 if (*dptr != '\r' && *dptr != '\n')
558                         continue;
559                 if (++dptr >= limit)
560                         break;
561                 if (*(dptr - 1) == '\r' && *dptr == '\n') {
562                         if (++dptr >= limit)
563                                 break;
564                 }
565
566                 if (term != SDP_HDR_UNSPEC &&
567                     limit - dptr >= thdr->len &&
568                     strnicmp(dptr, thdr->name, thdr->len) == 0)
569                         break;
570                 else if (limit - dptr >= hdr->len &&
571                          strnicmp(dptr, hdr->name, hdr->len) == 0)
572                         dptr += hdr->len;
573                 else
574                         continue;
575
576                 *matchoff = dptr - start;
577                 if (hdr->search) {
578                         dptr = ct_sdp_header_search(dptr, limit, hdr->search,
579                                                     hdr->slen);
580                         if (!dptr)
581                                 return -1;
582                         dptr += hdr->slen;
583                 }
584
585                 *matchlen = hdr->match_len(ct, dptr, limit, &shift);
586                 if (!*matchlen)
587                         return -1;
588                 *matchoff = dptr - start + shift;
589                 return 1;
590         }
591         return 0;
592 }
593 EXPORT_SYMBOL_GPL(ct_sip_get_sdp_header);
594
595 static void flush_expectations(struct nf_conn *ct)
596 {
597         struct nf_conn_help *help = nfct_help(ct);
598         struct nf_conntrack_expect *exp;
599         struct hlist_node *n, *next;
600
601         spin_lock_bh(&nf_conntrack_lock);
602         hlist_for_each_entry_safe(exp, n, next, &help->expectations, lnode) {
603                 if (!del_timer(&exp->timeout))
604                         continue;
605                 nf_ct_unlink_expect(exp);
606                 nf_ct_expect_put(exp);
607         }
608         spin_unlock_bh(&nf_conntrack_lock);
609 }
610
611 static int set_expected_rtp(struct sk_buff *skb,
612                             const char **dptr, unsigned int *datalen,
613                             union nf_inet_addr *addr, __be16 port)
614 {
615         struct nf_conntrack_expect *exp;
616         enum ip_conntrack_info ctinfo;
617         struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
618         enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
619         int family = ct->tuplehash[!dir].tuple.src.l3num;
620         int ret;
621         typeof(nf_nat_sdp_hook) nf_nat_sdp;
622
623         exp = nf_ct_expect_alloc(ct);
624         if (exp == NULL)
625                 return NF_DROP;
626         nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, family,
627                           &ct->tuplehash[!dir].tuple.src.u3, addr,
628                           IPPROTO_UDP, NULL, &port);
629
630         nf_nat_sdp = rcu_dereference(nf_nat_sdp_hook);
631         if (nf_nat_sdp && ct->status & IPS_NAT_MASK)
632                 ret = nf_nat_sdp(skb, dptr, datalen, exp);
633         else {
634                 if (nf_ct_expect_related(exp) != 0)
635                         ret = NF_DROP;
636                 else
637                         ret = NF_ACCEPT;
638         }
639         nf_ct_expect_put(exp);
640
641         return ret;
642 }
643
644 static int process_sdp(struct sk_buff *skb,
645                        const char **dptr, unsigned int *datalen,
646                        unsigned int cseq)
647 {
648         enum ip_conntrack_info ctinfo;
649         struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
650         int family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num;
651         unsigned int matchoff, matchlen;
652         union nf_inet_addr addr;
653         unsigned int port;
654         enum sdp_header_types type;
655
656         /* Get address and port from SDP packet. */
657         type = family == AF_INET ? SDP_HDR_CONNECTION_IP4 :
658                                    SDP_HDR_CONNECTION_IP6;
659
660         if (ct_sip_get_sdp_header(ct, *dptr, 0, *datalen,
661                                   type, SDP_HDR_UNSPEC,
662                                   &matchoff, &matchlen) <= 0)
663                 return NF_ACCEPT;
664
665         /* We'll drop only if there are parse problems. */
666         if (!parse_addr(ct, *dptr + matchoff, NULL, &addr, *dptr + *datalen))
667                 return NF_DROP;
668
669         if (ct_sip_get_sdp_header(ct, *dptr, 0, *datalen,
670                                   SDP_HDR_MEDIA, SDP_HDR_UNSPEC,
671                                   &matchoff, &matchlen) <= 0)
672                 return NF_ACCEPT;
673
674         port = simple_strtoul(*dptr + matchoff, NULL, 10);
675         if (port < 1024 || port > 65535)
676                 return NF_DROP;
677
678         return set_expected_rtp(skb, dptr, datalen, &addr, htons(port));
679 }
680 static int process_invite_response(struct sk_buff *skb,
681                                    const char **dptr, unsigned int *datalen,
682                                    unsigned int cseq, unsigned int code)
683 {
684         enum ip_conntrack_info ctinfo;
685         struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
686
687         if ((code >= 100 && code <= 199) ||
688             (code >= 200 && code <= 299))
689                 return process_sdp(skb, dptr, datalen, cseq);
690         else {
691                 flush_expectations(ct);
692                 return NF_ACCEPT;
693         }
694 }
695
696 static int process_update_response(struct sk_buff *skb,
697                                    const char **dptr, unsigned int *datalen,
698                                    unsigned int cseq, unsigned int code)
699 {
700         enum ip_conntrack_info ctinfo;
701         struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
702
703         if ((code >= 100 && code <= 199) ||
704             (code >= 200 && code <= 299))
705                 return process_sdp(skb, dptr, datalen, cseq);
706         else {
707                 flush_expectations(ct);
708                 return NF_ACCEPT;
709         }
710 }
711
712 static int process_prack_response(struct sk_buff *skb,
713                                   const char **dptr, unsigned int *datalen,
714                                   unsigned int cseq, unsigned int code)
715 {
716         enum ip_conntrack_info ctinfo;
717         struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
718
719         if ((code >= 100 && code <= 199) ||
720             (code >= 200 && code <= 299))
721                 return process_sdp(skb, dptr, datalen, cseq);
722         else {
723                 flush_expectations(ct);
724                 return NF_ACCEPT;
725         }
726 }
727
728 static int process_bye_request(struct sk_buff *skb,
729                                const char **dptr, unsigned int *datalen,
730                                unsigned int cseq)
731 {
732         enum ip_conntrack_info ctinfo;
733         struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
734
735         flush_expectations(ct);
736         return NF_ACCEPT;
737 }
738
739 static const struct sip_handler sip_handlers[] = {
740         SIP_HANDLER("INVITE", process_sdp, process_invite_response),
741         SIP_HANDLER("UPDATE", process_sdp, process_update_response),
742         SIP_HANDLER("ACK", process_sdp, NULL),
743         SIP_HANDLER("PRACK", process_sdp, process_prack_response),
744         SIP_HANDLER("BYE", process_bye_request, NULL),
745 };
746
747 static int process_sip_response(struct sk_buff *skb,
748                                 const char **dptr, unsigned int *datalen)
749 {
750         static const struct sip_handler *handler;
751         enum ip_conntrack_info ctinfo;
752         struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
753         unsigned int matchoff, matchlen;
754         unsigned int code, cseq, dataoff, i;
755
756         if (*datalen < strlen("SIP/2.0 200"))
757                 return NF_ACCEPT;
758         code = simple_strtoul(*dptr + strlen("SIP/2.0 "), NULL, 10);
759         if (!code)
760                 return NF_DROP;
761
762         if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_CSEQ,
763                               &matchoff, &matchlen) <= 0)
764                 return NF_DROP;
765         cseq = simple_strtoul(*dptr + matchoff, NULL, 10);
766         if (!cseq)
767                 return NF_DROP;
768         dataoff = matchoff + matchlen + 1;
769
770         for (i = 0; i < ARRAY_SIZE(sip_handlers); i++) {
771                 handler = &sip_handlers[i];
772                 if (handler->response == NULL)
773                         continue;
774                 if (*datalen < dataoff + handler->len ||
775                     strnicmp(*dptr + dataoff, handler->method, handler->len))
776                         continue;
777                 return handler->response(skb, dptr, datalen, cseq, code);
778         }
779         return NF_ACCEPT;
780 }
781
782 static int process_sip_request(struct sk_buff *skb,
783                                const char **dptr, unsigned int *datalen)
784 {
785         static const struct sip_handler *handler;
786         enum ip_conntrack_info ctinfo;
787         struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
788         unsigned int matchoff, matchlen;
789         unsigned int cseq, i;
790
791         for (i = 0; i < ARRAY_SIZE(sip_handlers); i++) {
792                 handler = &sip_handlers[i];
793                 if (handler->request == NULL)
794                         continue;
795                 if (*datalen < handler->len ||
796                     strnicmp(*dptr, handler->method, handler->len))
797                         continue;
798
799                 if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_CSEQ,
800                                       &matchoff, &matchlen) <= 0)
801                         return NF_DROP;
802                 cseq = simple_strtoul(*dptr + matchoff, NULL, 10);
803                 if (!cseq)
804                         return NF_DROP;
805
806                 return handler->request(skb, dptr, datalen, cseq);
807         }
808         return NF_ACCEPT;
809 }
810
811 static int sip_help(struct sk_buff *skb,
812                     unsigned int protoff,
813                     struct nf_conn *ct,
814                     enum ip_conntrack_info ctinfo)
815 {
816         unsigned int dataoff, datalen;
817         const char *dptr;
818         int ret;
819         typeof(nf_nat_sip_hook) nf_nat_sip;
820
821         /* No Data ? */
822         dataoff = protoff + sizeof(struct udphdr);
823         if (dataoff >= skb->len)
824                 return NF_ACCEPT;
825
826         nf_ct_refresh(ct, skb, sip_timeout * HZ);
827
828         if (!skb_is_nonlinear(skb))
829                 dptr = skb->data + dataoff;
830         else {
831                 pr_debug("Copy of skbuff not supported yet.\n");
832                 return NF_ACCEPT;
833         }
834
835         datalen = skb->len - dataoff;
836         if (datalen < strlen("SIP/2.0 200"))
837                 return NF_ACCEPT;
838
839         if (strnicmp(dptr, "SIP/2.0 ", strlen("SIP/2.0 ")) != 0)
840                 ret = process_sip_request(skb, &dptr, &datalen);
841         else
842                 ret = process_sip_response(skb, &dptr, &datalen);
843
844         if (ret == NF_ACCEPT && ct->status & IPS_NAT_MASK) {
845                 nf_nat_sip = rcu_dereference(nf_nat_sip_hook);
846                 if (nf_nat_sip && !nf_nat_sip(skb, &dptr, &datalen))
847                         ret = NF_DROP;
848         }
849
850         return ret;
851 }
852
853 static struct nf_conntrack_helper sip[MAX_PORTS][2] __read_mostly;
854 static char sip_names[MAX_PORTS][2][sizeof("sip-65535")] __read_mostly;
855
856 static const struct nf_conntrack_expect_policy sip_exp_policy = {
857         .max_expected   = 2,
858         .timeout        = 3 * 60,
859 };
860
861 static void nf_conntrack_sip_fini(void)
862 {
863         int i, j;
864
865         for (i = 0; i < ports_c; i++) {
866                 for (j = 0; j < 2; j++) {
867                         if (sip[i][j].me == NULL)
868                                 continue;
869                         nf_conntrack_helper_unregister(&sip[i][j]);
870                 }
871         }
872 }
873
874 static int __init nf_conntrack_sip_init(void)
875 {
876         int i, j, ret;
877         char *tmpname;
878
879         if (ports_c == 0)
880                 ports[ports_c++] = SIP_PORT;
881
882         for (i = 0; i < ports_c; i++) {
883                 memset(&sip[i], 0, sizeof(sip[i]));
884
885                 sip[i][0].tuple.src.l3num = AF_INET;
886                 sip[i][1].tuple.src.l3num = AF_INET6;
887                 for (j = 0; j < 2; j++) {
888                         sip[i][j].tuple.dst.protonum = IPPROTO_UDP;
889                         sip[i][j].tuple.src.u.udp.port = htons(ports[i]);
890                         sip[i][j].expect_policy = &sip_exp_policy;
891                         sip[i][j].me = THIS_MODULE;
892                         sip[i][j].help = sip_help;
893
894                         tmpname = &sip_names[i][j][0];
895                         if (ports[i] == SIP_PORT)
896                                 sprintf(tmpname, "sip");
897                         else
898                                 sprintf(tmpname, "sip-%u", i);
899                         sip[i][j].name = tmpname;
900
901                         pr_debug("port #%u: %u\n", i, ports[i]);
902
903                         ret = nf_conntrack_helper_register(&sip[i][j]);
904                         if (ret) {
905                                 printk("nf_ct_sip: failed to register helper "
906                                        "for pf: %u port: %u\n",
907                                        sip[i][j].tuple.src.l3num, ports[i]);
908                                 nf_conntrack_sip_fini();
909                                 return ret;
910                         }
911                 }
912         }
913         return 0;
914 }
915
916 module_init(nf_conntrack_sip_init);
917 module_exit(nf_conntrack_sip_fini);