[NETFILTER]: nf_conntrack_sip: remove redundant function arguments
[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         [POS_MEDIA] = {         /* SDP media info */
128                 .case_sensitive = 1,
129                 .lname          = "\nm=",
130                 .lnlen          = sizeof("\nm=") - 1,
131                 .sname          = "\rm=",
132                 .snlen          = sizeof("\rm=") - 1,
133                 .ln_str         = "audio ",
134                 .ln_strlen      = sizeof("audio ") - 1,
135                 .match_len      = digits_len
136         },
137         [POS_OWNER_IP4] = {     /* SDP owner address*/
138                 .case_sensitive = 1,
139                 .lname          = "\no=",
140                 .lnlen          = sizeof("\no=") - 1,
141                 .sname          = "\ro=",
142                 .snlen          = sizeof("\ro=") - 1,
143                 .ln_str         = "IN IP4 ",
144                 .ln_strlen      = sizeof("IN IP4 ") - 1,
145                 .match_len      = epaddr_len
146         },
147         [POS_CONNECTION_IP4] = {/* SDP connection info */
148                 .case_sensitive = 1,
149                 .lname          = "\nc=",
150                 .lnlen          = sizeof("\nc=") - 1,
151                 .sname          = "\rc=",
152                 .snlen          = sizeof("\rc=") - 1,
153                 .ln_str         = "IN IP4 ",
154                 .ln_strlen      = sizeof("IN IP4 ") - 1,
155                 .match_len      = epaddr_len
156         },
157         [POS_OWNER_IP6] = {     /* SDP owner address*/
158                 .case_sensitive = 1,
159                 .lname          = "\no=",
160                 .lnlen          = sizeof("\no=") - 1,
161                 .sname          = "\ro=",
162                 .snlen          = sizeof("\ro=") - 1,
163                 .ln_str         = "IN IP6 ",
164                 .ln_strlen      = sizeof("IN IP6 ") - 1,
165                 .match_len      = epaddr_len
166         },
167         [POS_CONNECTION_IP6] = {/* SDP connection info */
168                 .case_sensitive = 1,
169                 .lname          = "\nc=",
170                 .lnlen          = sizeof("\nc=") - 1,
171                 .sname          = "\rc=",
172                 .snlen          = sizeof("\rc=") - 1,
173                 .ln_str         = "IN IP6 ",
174                 .ln_strlen      = sizeof("IN IP6 ") - 1,
175                 .match_len      = epaddr_len
176         },
177         [POS_SDP_HEADER] = {    /* SDP version header */
178                 .case_sensitive = 1,
179                 .lname          = "\nv=",
180                 .lnlen          = sizeof("\nv=") - 1,
181                 .sname          = "\rv=",
182                 .snlen          = sizeof("\rv=") - 1,
183                 .ln_str         = "=",
184                 .ln_strlen      = sizeof("=") - 1,
185                 .match_len      = digits_len
186         }
187 };
188
189 /* get line length until first CR or LF seen. */
190 int ct_sip_lnlen(const char *line, const char *limit)
191 {
192         const char *k = line;
193
194         while ((line < limit) && (*line == '\r' || *line == '\n'))
195                 line++;
196
197         while (line < limit) {
198                 if (*line == '\r' || *line == '\n')
199                         break;
200                 line++;
201         }
202         return line - k;
203 }
204 EXPORT_SYMBOL_GPL(ct_sip_lnlen);
205
206 /* Linear string search, case sensitive. */
207 const char *ct_sip_search(const char *needle, const char *haystack,
208                           size_t needle_len, size_t haystack_len,
209                           int case_sensitive)
210 {
211         const char *limit = haystack + (haystack_len - needle_len);
212
213         while (haystack < limit) {
214                 if (case_sensitive) {
215                         if (strncmp(haystack, needle, needle_len) == 0)
216                                 return haystack;
217                 } else {
218                         if (strnicmp(haystack, needle, needle_len) == 0)
219                                 return haystack;
220                 }
221                 haystack++;
222         }
223         return NULL;
224 }
225 EXPORT_SYMBOL_GPL(ct_sip_search);
226
227 static int digits_len(const struct nf_conn *ct, const char *dptr,
228                       const char *limit, int *shift)
229 {
230         int len = 0;
231         while (dptr < limit && isdigit(*dptr)) {
232                 dptr++;
233                 len++;
234         }
235         return len;
236 }
237
238 /* get digits length, skipping blank spaces. */
239 static int skp_digits_len(const struct nf_conn *ct, const char *dptr,
240                           const char *limit, int *shift)
241 {
242         for (; dptr < limit && *dptr == ' '; dptr++)
243                 (*shift)++;
244
245         return digits_len(ct, dptr, limit, shift);
246 }
247
248 static int parse_addr(const struct nf_conn *ct, const char *cp,
249                       const char **endp, union nf_inet_addr *addr,
250                       const char *limit)
251 {
252         const char *end;
253         int family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num;
254         int ret = 0;
255
256         switch (family) {
257         case AF_INET:
258                 ret = in4_pton(cp, limit - cp, (u8 *)&addr->ip, -1, &end);
259                 break;
260         case AF_INET6:
261                 ret = in6_pton(cp, limit - cp, (u8 *)&addr->ip6, -1, &end);
262                 break;
263         default:
264                 BUG();
265         }
266
267         if (ret == 0 || end == cp)
268                 return 0;
269         if (endp)
270                 *endp = end;
271         return 1;
272 }
273
274 /* skip ip address. returns its length. */
275 static int epaddr_len(const struct nf_conn *ct, const char *dptr,
276                       const char *limit, int *shift)
277 {
278         union nf_inet_addr addr;
279         const char *aux = dptr;
280
281         if (!parse_addr(ct, dptr, &dptr, &addr, limit)) {
282                 pr_debug("ip: %s parse failed.!\n", dptr);
283                 return 0;
284         }
285
286         /* Port number */
287         if (*dptr == ':') {
288                 dptr++;
289                 dptr += digits_len(ct, dptr, limit, shift);
290         }
291         return dptr - aux;
292 }
293
294 /* get address length, skiping user info. */
295 static int skp_epaddr_len(const struct nf_conn *ct, const char *dptr,
296                           const char *limit, int *shift)
297 {
298         const char *start = dptr;
299         int s = *shift;
300
301         /* Search for @, but stop at the end of the line.
302          * We are inside a sip: URI, so we don't need to worry about
303          * continuation lines. */
304         while (dptr < limit &&
305                *dptr != '@' && *dptr != '\r' && *dptr != '\n') {
306                 (*shift)++;
307                 dptr++;
308         }
309
310         if (dptr < limit && *dptr == '@') {
311                 dptr++;
312                 (*shift)++;
313         } else {
314                 dptr = start;
315                 *shift = s;
316         }
317
318         return epaddr_len(ct, dptr, limit, shift);
319 }
320
321 /* Returns 0 if not found, -1 error parsing. */
322 int ct_sip_get_info(const struct nf_conn *ct,
323                     const char *dptr, size_t dlen,
324                     unsigned int *matchoff,
325                     unsigned int *matchlen,
326                     enum sip_header_pos pos)
327 {
328         const struct sip_header_nfo *hnfo = &ct_sip_hdrs[pos];
329         const char *limit, *aux, *k = dptr;
330         int shift = 0;
331
332         limit = dptr + (dlen - hnfo->lnlen);
333
334         while (dptr < limit) {
335                 if ((strncmp(dptr, hnfo->lname, hnfo->lnlen) != 0) &&
336                     (hnfo->sname == NULL ||
337                      strncmp(dptr, hnfo->sname, hnfo->snlen) != 0)) {
338                         dptr++;
339                         continue;
340                 }
341                 aux = ct_sip_search(hnfo->ln_str, dptr, hnfo->ln_strlen,
342                                     ct_sip_lnlen(dptr, limit),
343                                     hnfo->case_sensitive);
344                 if (!aux) {
345                         pr_debug("'%s' not found in '%s'.\n", hnfo->ln_str,
346                                  hnfo->lname);
347                         return -1;
348                 }
349                 aux += hnfo->ln_strlen;
350
351                 *matchlen = hnfo->match_len(ct, aux, limit, &shift);
352                 if (!*matchlen)
353                         return -1;
354
355                 *matchoff = (aux - k) + shift;
356
357                 pr_debug("%s match succeeded! - len: %u\n", hnfo->lname,
358                          *matchlen);
359                 return 1;
360         }
361         pr_debug("%s header not found.\n", hnfo->lname);
362         return 0;
363 }
364 EXPORT_SYMBOL_GPL(ct_sip_get_info);
365
366 static int set_expected_rtp(struct sk_buff *skb,
367                             const char **dptr, unsigned int *datalen,
368                             union nf_inet_addr *addr, __be16 port)
369 {
370         struct nf_conntrack_expect *exp;
371         enum ip_conntrack_info ctinfo;
372         struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
373         enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
374         int family = ct->tuplehash[!dir].tuple.src.l3num;
375         int ret;
376         typeof(nf_nat_sdp_hook) nf_nat_sdp;
377
378         exp = nf_ct_expect_alloc(ct);
379         if (exp == NULL)
380                 return NF_DROP;
381         nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, family,
382                           &ct->tuplehash[!dir].tuple.src.u3, addr,
383                           IPPROTO_UDP, NULL, &port);
384
385         nf_nat_sdp = rcu_dereference(nf_nat_sdp_hook);
386         if (nf_nat_sdp && ct->status & IPS_NAT_MASK)
387                 ret = nf_nat_sdp(skb, dptr, datalen, exp);
388         else {
389                 if (nf_ct_expect_related(exp) != 0)
390                         ret = NF_DROP;
391                 else
392                         ret = NF_ACCEPT;
393         }
394         nf_ct_expect_put(exp);
395
396         return ret;
397 }
398
399 static int sip_help(struct sk_buff *skb,
400                     unsigned int protoff,
401                     struct nf_conn *ct,
402                     enum ip_conntrack_info ctinfo)
403 {
404         int family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num;
405         union nf_inet_addr addr;
406         unsigned int dataoff, datalen;
407         const char *dptr;
408         int ret = NF_ACCEPT;
409         unsigned int matchoff, matchlen;
410         u_int16_t port;
411         enum sip_header_pos pos;
412         typeof(nf_nat_sip_hook) nf_nat_sip;
413
414         /* No Data ? */
415         dataoff = protoff + sizeof(struct udphdr);
416         if (dataoff >= skb->len)
417                 return NF_ACCEPT;
418
419         nf_ct_refresh(ct, skb, sip_timeout * HZ);
420
421         if (!skb_is_nonlinear(skb))
422                 dptr = skb->data + dataoff;
423         else {
424                 pr_debug("Copy of skbuff not supported yet.\n");
425                 goto out;
426         }
427
428         nf_nat_sip = rcu_dereference(nf_nat_sip_hook);
429         if (nf_nat_sip && ct->status & IPS_NAT_MASK) {
430                 if (!nf_nat_sip(skb, &dptr, &datalen)) {
431                         ret = NF_DROP;
432                         goto out;
433                 }
434         }
435
436         datalen = skb->len - dataoff;
437         if (datalen < sizeof("SIP/2.0 200") - 1)
438                 goto out;
439
440         /* RTP info only in some SDP pkts */
441         if (memcmp(dptr, "INVITE", sizeof("INVITE") - 1) != 0 &&
442             memcmp(dptr, "UPDATE", sizeof("UPDATE") - 1) != 0 &&
443             memcmp(dptr, "SIP/2.0 180", sizeof("SIP/2.0 180") - 1) != 0 &&
444             memcmp(dptr, "SIP/2.0 183", sizeof("SIP/2.0 183") - 1) != 0 &&
445             memcmp(dptr, "SIP/2.0 200", sizeof("SIP/2.0 200") - 1) != 0) {
446                 goto out;
447         }
448         /* Get address and port from SDP packet. */
449         pos = family == AF_INET ? POS_CONNECTION_IP4 : POS_CONNECTION_IP6;
450         if (ct_sip_get_info(ct, dptr, datalen, &matchoff, &matchlen, pos) > 0) {
451
452                 /* We'll drop only if there are parse problems. */
453                 if (!parse_addr(ct, dptr + matchoff, NULL, &addr,
454                                 dptr + datalen)) {
455                         ret = NF_DROP;
456                         goto out;
457                 }
458                 if (ct_sip_get_info(ct, dptr, datalen, &matchoff, &matchlen,
459                                     POS_MEDIA) > 0) {
460
461                         port = simple_strtoul(dptr + matchoff, NULL, 10);
462                         if (port < 1024) {
463                                 ret = NF_DROP;
464                                 goto out;
465                         }
466                         ret = set_expected_rtp(skb, &dptr, &datalen,
467                                                &addr, htons(port));
468                 }
469         }
470 out:
471         return ret;
472 }
473
474 static struct nf_conntrack_helper sip[MAX_PORTS][2] __read_mostly;
475 static char sip_names[MAX_PORTS][2][sizeof("sip-65535")] __read_mostly;
476
477 static const struct nf_conntrack_expect_policy sip_exp_policy = {
478         .max_expected   = 2,
479         .timeout        = 3 * 60,
480 };
481
482 static void nf_conntrack_sip_fini(void)
483 {
484         int i, j;
485
486         for (i = 0; i < ports_c; i++) {
487                 for (j = 0; j < 2; j++) {
488                         if (sip[i][j].me == NULL)
489                                 continue;
490                         nf_conntrack_helper_unregister(&sip[i][j]);
491                 }
492         }
493 }
494
495 static int __init nf_conntrack_sip_init(void)
496 {
497         int i, j, ret;
498         char *tmpname;
499
500         if (ports_c == 0)
501                 ports[ports_c++] = SIP_PORT;
502
503         for (i = 0; i < ports_c; i++) {
504                 memset(&sip[i], 0, sizeof(sip[i]));
505
506                 sip[i][0].tuple.src.l3num = AF_INET;
507                 sip[i][1].tuple.src.l3num = AF_INET6;
508                 for (j = 0; j < 2; j++) {
509                         sip[i][j].tuple.dst.protonum = IPPROTO_UDP;
510                         sip[i][j].tuple.src.u.udp.port = htons(ports[i]);
511                         sip[i][j].expect_policy = &sip_exp_policy;
512                         sip[i][j].me = THIS_MODULE;
513                         sip[i][j].help = sip_help;
514
515                         tmpname = &sip_names[i][j][0];
516                         if (ports[i] == SIP_PORT)
517                                 sprintf(tmpname, "sip");
518                         else
519                                 sprintf(tmpname, "sip-%u", i);
520                         sip[i][j].name = tmpname;
521
522                         pr_debug("port #%u: %u\n", i, ports[i]);
523
524                         ret = nf_conntrack_helper_register(&sip[i][j]);
525                         if (ret) {
526                                 printk("nf_ct_sip: failed to register helper "
527                                        "for pf: %u port: %u\n",
528                                        sip[i][j].tuple.src.l3num, ports[i]);
529                                 nf_conntrack_sip_fini();
530                                 return ret;
531                         }
532                 }
533         }
534         return 0;
535 }
536
537 module_init(nf_conntrack_sip_init);
538 module_exit(nf_conntrack_sip_fini);