[NETFILTER]: nf_conntrack_sip: add seperate SDP header parsing function
[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 digits_len(const struct nf_conn *, const char *, const char *, int *);
51 static int epaddr_len(const struct nf_conn *, const char *, const char *, int *);
52 static int skp_digits_len(const struct nf_conn *, const char *, const char *, int *);
53 static int skp_epaddr_len(const struct nf_conn *, const char *, const char *, int *);
54
55 struct sip_header_nfo {
56         const char      *lname;
57         const char      *sname;
58         const char      *ln_str;
59         size_t          lnlen;
60         size_t          snlen;
61         size_t          ln_strlen;
62         int             case_sensitive;
63         int             (*match_len)(const struct nf_conn *, const char *,
64                                      const char *, int *);
65 };
66
67 static const struct sip_header_nfo ct_sip_hdrs[] = {
68         [POS_REG_REQ_URI] = {   /* SIP REGISTER request URI */
69                 .lname          = "sip:",
70                 .lnlen          = sizeof("sip:") - 1,
71                 .ln_str         = ":",
72                 .ln_strlen      = sizeof(":") - 1,
73                 .match_len      = epaddr_len,
74         },
75         [POS_REQ_URI] = {       /* SIP request URI */
76                 .lname          = "sip:",
77                 .lnlen          = sizeof("sip:") - 1,
78                 .ln_str         = "@",
79                 .ln_strlen      = sizeof("@") - 1,
80                 .match_len      = epaddr_len,
81         },
82         [POS_FROM] = {          /* SIP From header */
83                 .lname          = "From:",
84                 .lnlen          = sizeof("From:") - 1,
85                 .sname          = "\r\nf:",
86                 .snlen          = sizeof("\r\nf:") - 1,
87                 .ln_str         = "sip:",
88                 .ln_strlen      = sizeof("sip:") - 1,
89                 .match_len      = skp_epaddr_len,
90         },
91         [POS_TO] = {            /* SIP To header */
92                 .lname          = "To:",
93                 .lnlen          = sizeof("To:") - 1,
94                 .sname          = "\r\nt:",
95                 .snlen          = sizeof("\r\nt:") - 1,
96                 .ln_str         = "sip:",
97                 .ln_strlen      = sizeof("sip:") - 1,
98                 .match_len      = skp_epaddr_len
99         },
100         [POS_VIA] = {           /* SIP Via header */
101                 .lname          = "Via:",
102                 .lnlen          = sizeof("Via:") - 1,
103                 .sname          = "\r\nv:",
104                 .snlen          = sizeof("\r\nv:") - 1, /* rfc3261 "\r\n" */
105                 .ln_str         = "UDP ",
106                 .ln_strlen      = sizeof("UDP ") - 1,
107                 .match_len      = epaddr_len,
108         },
109         [POS_CONTACT] = {       /* SIP Contact header */
110                 .lname          = "Contact:",
111                 .lnlen          = sizeof("Contact:") - 1,
112                 .sname          = "\r\nm:",
113                 .snlen          = sizeof("\r\nm:") - 1,
114                 .ln_str         = "sip:",
115                 .ln_strlen      = sizeof("sip:") - 1,
116                 .match_len      = skp_epaddr_len
117         },
118         [POS_CONTENT] = {       /* SIP Content length header */
119                 .lname          = "Content-Length:",
120                 .lnlen          = sizeof("Content-Length:") - 1,
121                 .sname          = "\r\nl:",
122                 .snlen          = sizeof("\r\nl:") - 1,
123                 .ln_str         = ":",
124                 .ln_strlen      = sizeof(":") - 1,
125                 .match_len      = skp_digits_len
126         },
127 };
128
129 /* get line length until first CR or LF seen. */
130 int ct_sip_lnlen(const char *line, const char *limit)
131 {
132         const char *k = line;
133
134         while ((line < limit) && (*line == '\r' || *line == '\n'))
135                 line++;
136
137         while (line < limit) {
138                 if (*line == '\r' || *line == '\n')
139                         break;
140                 line++;
141         }
142         return line - k;
143 }
144 EXPORT_SYMBOL_GPL(ct_sip_lnlen);
145
146 /* Linear string search, case sensitive. */
147 const char *ct_sip_search(const char *needle, const char *haystack,
148                           size_t needle_len, size_t haystack_len,
149                           int case_sensitive)
150 {
151         const char *limit = haystack + (haystack_len - needle_len);
152
153         while (haystack < limit) {
154                 if (case_sensitive) {
155                         if (strncmp(haystack, needle, needle_len) == 0)
156                                 return haystack;
157                 } else {
158                         if (strnicmp(haystack, needle, needle_len) == 0)
159                                 return haystack;
160                 }
161                 haystack++;
162         }
163         return NULL;
164 }
165 EXPORT_SYMBOL_GPL(ct_sip_search);
166
167 static int digits_len(const struct nf_conn *ct, const char *dptr,
168                       const char *limit, int *shift)
169 {
170         int len = 0;
171         while (dptr < limit && isdigit(*dptr)) {
172                 dptr++;
173                 len++;
174         }
175         return len;
176 }
177
178 /* get digits length, skipping blank spaces. */
179 static int skp_digits_len(const struct nf_conn *ct, const char *dptr,
180                           const char *limit, int *shift)
181 {
182         for (; dptr < limit && *dptr == ' '; dptr++)
183                 (*shift)++;
184
185         return digits_len(ct, dptr, limit, shift);
186 }
187
188 static int parse_addr(const struct nf_conn *ct, const char *cp,
189                       const char **endp, union nf_inet_addr *addr,
190                       const char *limit)
191 {
192         const char *end;
193         int family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num;
194         int ret = 0;
195
196         switch (family) {
197         case AF_INET:
198                 ret = in4_pton(cp, limit - cp, (u8 *)&addr->ip, -1, &end);
199                 break;
200         case AF_INET6:
201                 ret = in6_pton(cp, limit - cp, (u8 *)&addr->ip6, -1, &end);
202                 break;
203         default:
204                 BUG();
205         }
206
207         if (ret == 0 || end == cp)
208                 return 0;
209         if (endp)
210                 *endp = end;
211         return 1;
212 }
213
214 /* skip ip address. returns its length. */
215 static int epaddr_len(const struct nf_conn *ct, const char *dptr,
216                       const char *limit, int *shift)
217 {
218         union nf_inet_addr addr;
219         const char *aux = dptr;
220
221         if (!parse_addr(ct, dptr, &dptr, &addr, limit)) {
222                 pr_debug("ip: %s parse failed.!\n", dptr);
223                 return 0;
224         }
225
226         /* Port number */
227         if (*dptr == ':') {
228                 dptr++;
229                 dptr += digits_len(ct, dptr, limit, shift);
230         }
231         return dptr - aux;
232 }
233
234 /* get address length, skiping user info. */
235 static int skp_epaddr_len(const struct nf_conn *ct, const char *dptr,
236                           const char *limit, int *shift)
237 {
238         const char *start = dptr;
239         int s = *shift;
240
241         /* Search for @, but stop at the end of the line.
242          * We are inside a sip: URI, so we don't need to worry about
243          * continuation lines. */
244         while (dptr < limit &&
245                *dptr != '@' && *dptr != '\r' && *dptr != '\n') {
246                 (*shift)++;
247                 dptr++;
248         }
249
250         if (dptr < limit && *dptr == '@') {
251                 dptr++;
252                 (*shift)++;
253         } else {
254                 dptr = start;
255                 *shift = s;
256         }
257
258         return epaddr_len(ct, dptr, limit, shift);
259 }
260
261 /* Returns 0 if not found, -1 error parsing. */
262 int ct_sip_get_info(const struct nf_conn *ct,
263                     const char *dptr, size_t dlen,
264                     unsigned int *matchoff,
265                     unsigned int *matchlen,
266                     enum sip_header_pos pos)
267 {
268         const struct sip_header_nfo *hnfo = &ct_sip_hdrs[pos];
269         const char *limit, *aux, *k = dptr;
270         int shift = 0;
271
272         limit = dptr + (dlen - hnfo->lnlen);
273
274         while (dptr < limit) {
275                 if ((strncmp(dptr, hnfo->lname, hnfo->lnlen) != 0) &&
276                     (hnfo->sname == NULL ||
277                      strncmp(dptr, hnfo->sname, hnfo->snlen) != 0)) {
278                         dptr++;
279                         continue;
280                 }
281                 aux = ct_sip_search(hnfo->ln_str, dptr, hnfo->ln_strlen,
282                                     ct_sip_lnlen(dptr, limit),
283                                     hnfo->case_sensitive);
284                 if (!aux) {
285                         pr_debug("'%s' not found in '%s'.\n", hnfo->ln_str,
286                                  hnfo->lname);
287                         return -1;
288                 }
289                 aux += hnfo->ln_strlen;
290
291                 *matchlen = hnfo->match_len(ct, aux, limit, &shift);
292                 if (!*matchlen)
293                         return -1;
294
295                 *matchoff = (aux - k) + shift;
296
297                 pr_debug("%s match succeeded! - len: %u\n", hnfo->lname,
298                          *matchlen);
299                 return 1;
300         }
301         pr_debug("%s header not found.\n", hnfo->lname);
302         return 0;
303 }
304 EXPORT_SYMBOL_GPL(ct_sip_get_info);
305
306 /* SDP header parsing: a SDP session description contains an ordered set of
307  * headers, starting with a section containing general session parameters,
308  * optionally followed by multiple media descriptions.
309  *
310  * SDP headers always start at the beginning of a line. According to RFC 2327:
311  * "The sequence CRLF (0x0d0a) is used to end a record, although parsers should
312  * be tolerant and also accept records terminated with a single newline
313  * character". We handle both cases.
314  */
315 static const struct sip_header ct_sdp_hdrs[] = {
316         [SDP_HDR_VERSION]               = SDP_HDR("v=", NULL, digits_len),
317         [SDP_HDR_OWNER_IP4]             = SDP_HDR("o=", "IN IP4 ", epaddr_len),
318         [SDP_HDR_CONNECTION_IP4]        = SDP_HDR("c=", "IN IP4 ", epaddr_len),
319         [SDP_HDR_OWNER_IP6]             = SDP_HDR("o=", "IN IP6 ", epaddr_len),
320         [SDP_HDR_CONNECTION_IP6]        = SDP_HDR("c=", "IN IP6 ", epaddr_len),
321         [SDP_HDR_MEDIA]                 = SDP_HDR("m=", "audio ", digits_len),
322 };
323
324 /* Linear string search within SDP header values */
325 static const char *ct_sdp_header_search(const char *dptr, const char *limit,
326                                         const char *needle, unsigned int len)
327 {
328         for (limit -= len; dptr < limit; dptr++) {
329                 if (*dptr == '\r' || *dptr == '\n')
330                         break;
331                 if (strncmp(dptr, needle, len) == 0)
332                         return dptr;
333         }
334         return NULL;
335 }
336
337 /* Locate a SDP header (optionally a substring within the header value),
338  * optionally stopping at the first occurence of the term header, parse
339  * it and return the offset and length of the data we're interested in.
340  */
341 int ct_sip_get_sdp_header(const struct nf_conn *ct, const char *dptr,
342                           unsigned int dataoff, unsigned int datalen,
343                           enum sdp_header_types type,
344                           enum sdp_header_types term,
345                           unsigned int *matchoff, unsigned int *matchlen)
346 {
347         const struct sip_header *hdr = &ct_sdp_hdrs[type];
348         const struct sip_header *thdr = &ct_sdp_hdrs[term];
349         const char *start = dptr, *limit = dptr + datalen;
350         int shift = 0;
351
352         for (dptr += dataoff; dptr < limit; dptr++) {
353                 /* Find beginning of line */
354                 if (*dptr != '\r' && *dptr != '\n')
355                         continue;
356                 if (++dptr >= limit)
357                         break;
358                 if (*(dptr - 1) == '\r' && *dptr == '\n') {
359                         if (++dptr >= limit)
360                                 break;
361                 }
362
363                 if (term != SDP_HDR_UNSPEC &&
364                     limit - dptr >= thdr->len &&
365                     strnicmp(dptr, thdr->name, thdr->len) == 0)
366                         break;
367                 else if (limit - dptr >= hdr->len &&
368                          strnicmp(dptr, hdr->name, hdr->len) == 0)
369                         dptr += hdr->len;
370                 else
371                         continue;
372
373                 *matchoff = dptr - start;
374                 if (hdr->search) {
375                         dptr = ct_sdp_header_search(dptr, limit, hdr->search,
376                                                     hdr->slen);
377                         if (!dptr)
378                                 return -1;
379                         dptr += hdr->slen;
380                 }
381
382                 *matchlen = hdr->match_len(ct, dptr, limit, &shift);
383                 if (!*matchlen)
384                         return -1;
385                 *matchoff = dptr - start + shift;
386                 return 1;
387         }
388         return 0;
389 }
390 EXPORT_SYMBOL_GPL(ct_sip_get_sdp_header);
391
392 static int set_expected_rtp(struct sk_buff *skb,
393                             const char **dptr, unsigned int *datalen,
394                             union nf_inet_addr *addr, __be16 port)
395 {
396         struct nf_conntrack_expect *exp;
397         enum ip_conntrack_info ctinfo;
398         struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
399         enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
400         int family = ct->tuplehash[!dir].tuple.src.l3num;
401         int ret;
402         typeof(nf_nat_sdp_hook) nf_nat_sdp;
403
404         exp = nf_ct_expect_alloc(ct);
405         if (exp == NULL)
406                 return NF_DROP;
407         nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, family,
408                           &ct->tuplehash[!dir].tuple.src.u3, addr,
409                           IPPROTO_UDP, NULL, &port);
410
411         nf_nat_sdp = rcu_dereference(nf_nat_sdp_hook);
412         if (nf_nat_sdp && ct->status & IPS_NAT_MASK)
413                 ret = nf_nat_sdp(skb, dptr, datalen, exp);
414         else {
415                 if (nf_ct_expect_related(exp) != 0)
416                         ret = NF_DROP;
417                 else
418                         ret = NF_ACCEPT;
419         }
420         nf_ct_expect_put(exp);
421
422         return ret;
423 }
424
425 static int sip_help(struct sk_buff *skb,
426                     unsigned int protoff,
427                     struct nf_conn *ct,
428                     enum ip_conntrack_info ctinfo)
429 {
430         int family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num;
431         union nf_inet_addr addr;
432         unsigned int dataoff, datalen;
433         const char *dptr;
434         int ret = NF_ACCEPT;
435         unsigned int matchoff, matchlen;
436         u_int16_t port;
437         enum sdp_header_types type;
438         typeof(nf_nat_sip_hook) nf_nat_sip;
439
440         /* No Data ? */
441         dataoff = protoff + sizeof(struct udphdr);
442         if (dataoff >= skb->len)
443                 return NF_ACCEPT;
444
445         nf_ct_refresh(ct, skb, sip_timeout * HZ);
446
447         if (!skb_is_nonlinear(skb))
448                 dptr = skb->data + dataoff;
449         else {
450                 pr_debug("Copy of skbuff not supported yet.\n");
451                 goto out;
452         }
453
454         nf_nat_sip = rcu_dereference(nf_nat_sip_hook);
455         if (nf_nat_sip && ct->status & IPS_NAT_MASK) {
456                 if (!nf_nat_sip(skb, &dptr, &datalen)) {
457                         ret = NF_DROP;
458                         goto out;
459                 }
460         }
461
462         datalen = skb->len - dataoff;
463         if (datalen < strlen("SIP/2.0 200"))
464                 goto out;
465
466         /* RTP info only in some SDP pkts */
467         if (strnicmp(dptr, "INVITE", strlen("INVITE")) != 0 &&
468             strnicmp(dptr, "UPDATE", strlen("UPDATE")) != 0 &&
469             strnicmp(dptr, "SIP/2.0 180", strlen("SIP/2.0 180")) != 0 &&
470             strnicmp(dptr, "SIP/2.0 183", strlen("SIP/2.0 183")) != 0 &&
471             strnicmp(dptr, "SIP/2.0 200", strlen("SIP/2.0 200")) != 0) {
472                 goto out;
473         }
474         /* Get address and port from SDP packet. */
475         type = family == AF_INET ? SDP_HDR_CONNECTION_IP4 :
476                                    SDP_HDR_CONNECTION_IP6;
477         if (ct_sip_get_sdp_header(ct, dptr, 0, datalen, type, SDP_HDR_UNSPEC,
478                                   &matchoff, &matchlen) > 0) {
479
480                 /* We'll drop only if there are parse problems. */
481                 if (!parse_addr(ct, dptr + matchoff, NULL, &addr,
482                                 dptr + datalen)) {
483                         ret = NF_DROP;
484                         goto out;
485                 }
486                 if (ct_sip_get_sdp_header(ct, dptr, 0, datalen,
487                                           SDP_HDR_MEDIA, SDP_HDR_UNSPEC,
488                                           &matchoff, &matchlen) > 0) {
489
490                         port = simple_strtoul(dptr + matchoff, NULL, 10);
491                         if (port < 1024) {
492                                 ret = NF_DROP;
493                                 goto out;
494                         }
495                         ret = set_expected_rtp(skb, &dptr, &datalen,
496                                                &addr, htons(port));
497                 }
498         }
499 out:
500         return ret;
501 }
502
503 static struct nf_conntrack_helper sip[MAX_PORTS][2] __read_mostly;
504 static char sip_names[MAX_PORTS][2][sizeof("sip-65535")] __read_mostly;
505
506 static const struct nf_conntrack_expect_policy sip_exp_policy = {
507         .max_expected   = 2,
508         .timeout        = 3 * 60,
509 };
510
511 static void nf_conntrack_sip_fini(void)
512 {
513         int i, j;
514
515         for (i = 0; i < ports_c; i++) {
516                 for (j = 0; j < 2; j++) {
517                         if (sip[i][j].me == NULL)
518                                 continue;
519                         nf_conntrack_helper_unregister(&sip[i][j]);
520                 }
521         }
522 }
523
524 static int __init nf_conntrack_sip_init(void)
525 {
526         int i, j, ret;
527         char *tmpname;
528
529         if (ports_c == 0)
530                 ports[ports_c++] = SIP_PORT;
531
532         for (i = 0; i < ports_c; i++) {
533                 memset(&sip[i], 0, sizeof(sip[i]));
534
535                 sip[i][0].tuple.src.l3num = AF_INET;
536                 sip[i][1].tuple.src.l3num = AF_INET6;
537                 for (j = 0; j < 2; j++) {
538                         sip[i][j].tuple.dst.protonum = IPPROTO_UDP;
539                         sip[i][j].tuple.src.u.udp.port = htons(ports[i]);
540                         sip[i][j].expect_policy = &sip_exp_policy;
541                         sip[i][j].me = THIS_MODULE;
542                         sip[i][j].help = sip_help;
543
544                         tmpname = &sip_names[i][j][0];
545                         if (ports[i] == SIP_PORT)
546                                 sprintf(tmpname, "sip");
547                         else
548                                 sprintf(tmpname, "sip-%u", i);
549                         sip[i][j].name = tmpname;
550
551                         pr_debug("port #%u: %u\n", i, ports[i]);
552
553                         ret = nf_conntrack_helper_register(&sip[i][j]);
554                         if (ret) {
555                                 printk("nf_ct_sip: failed to register helper "
556                                        "for pf: %u port: %u\n",
557                                        sip[i][j].tuple.src.l3num, ports[i]);
558                                 nf_conntrack_sip_fini();
559                                 return ret;
560                         }
561                 }
562         }
563         return 0;
564 }
565
566 module_init(nf_conntrack_sip_init);
567 module_exit(nf_conntrack_sip_fini);