added files
[bcm963xx.git] / kernel / linux / net / ipv4 / netfilter / ip_nat_rtsp.c
1 /*
2  * RTSP extension for TCP NAT alteration
3  * (C) 2003 by Tom Marshall <tmarshall@real.com>
4  * based on ip_nat_irc.c
5  *
6  *      This program is free software; you can redistribute it and/or
7  *      modify it under the terms of the GNU General Public License
8  *      as published by the Free Software Foundation; either version
9  *      2 of the License, or (at your option) any later version.
10  *
11  * Module load syntax:
12  *      insmod ip_nat_rtsp.o ports=port1,port2,...port<MAX_PORTS>
13  *                           stunaddr=<address>
14  *                           destaction=[auto|strip|none]
15  *
16  * If no ports are specified, the default will be port 554 only.
17  *
18  * stunaddr specifies the address used to detect that a client is using STUN.
19  * If this address is seen in the destination parameter, it is assumed that
20  * the client has already punched a UDP hole in the firewall, so we don't
21  * mangle the client_port.  If none is specified, it is autodetected.  It
22  * only needs to be set if you have multiple levels of NAT.  It should be
23  * set to the external address that the STUN clients detect.  Note that in
24  * this case, it will not be possible for clients to use UDP with servers
25  * between the NATs.
26  *
27  * If no destaction is specified, auto is used.
28  *   destaction=auto:  strip destination parameter if it is not stunaddr.
29  *   destaction=strip: always strip destination parameter (not recommended).
30  *   destaction=none:  do not touch destination parameter (not recommended).
31  */
32
33 #include <linux/module.h>
34 #include <linux/netfilter_ipv4.h>
35 #include <linux/ip.h>
36 #include <linux/tcp.h>
37 #include <linux/udp.h>
38 #include <linux/kernel.h>
39 #include <net/tcp.h>
40 #include <linux/netfilter_ipv4/ip_nat.h>
41 #include <linux/netfilter_ipv4/ip_nat_helper.h>
42 #include <linux/netfilter_ipv4/ip_nat_rule.h>
43 #include <linux/netfilter_ipv4/ip_nat_rtsp.h>
44 #include <linux/netfilter_ipv4/ip_conntrack_rtsp.h>
45 #include <linux/netfilter_ipv4/ip_conntrack_helper.h>
46
47 #include <linux/inet.h>
48 #include <linux/ctype.h>
49 #define NF_NEED_STRNCASECMP
50 #define NF_NEED_STRTOU16
51 #include <linux/netfilter_helpers.h>
52 #define NF_NEED_MIME_NEXTLINE
53 #include <linux/netfilter_mime.h>
54
55 /*
56  * To enable debugging, replace the line below with #define IP_NF_RTSP_DEBUG 1
57  */
58 #undef IP_NF_RTSP_DEBUG
59 #define INFOP(args...) printk(args)
60 #ifdef IP_NF_RTSP_DEBUG
61 #define DUMP_TUPLE(args...)
62 #define DEBUGP(args...) printk(KERN_DEBUG "%s:%s ", __FILE__, __FUNCTION__); \
63                         printk(args)
64 #else
65 #define DEBUGP(args...)
66 #endif
67
68 #define MAX_PORTS       8
69 #define DSTACT_AUTO     0
70 #define DSTACT_STRIP    1
71 #define DSTACT_NONE     2
72 #define MAX_NAT_PORTS   16
73
74 static int          ports[MAX_PORTS];
75 static char*        stunaddr = NULL;
76 static char*        destaction = NULL;
77
78 static int          num_ports = 0;
79 static u_int32_t    extip = 0;
80 static int          dstact = 0;
81
82 MODULE_AUTHOR("Tom Marshall <tmarshall@real.com>");
83 MODULE_DESCRIPTION("RTSP network address translation module");
84 MODULE_LICENSE("GPL");
85 #ifdef MODULE_PARM
86 MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i");
87 MODULE_PARM_DESC(ports, "port numbers of RTSP servers");
88 MODULE_PARM(stunaddr, "s");
89 MODULE_PARM_DESC(stunaddr, "Address for detecting STUN");
90 MODULE_PARM(destaction, "s");
91 MODULE_PARM_DESC(destaction, "Action for destination parameter (auto/strip/none)");
92 #endif
93
94 /* protects rtsp part of conntracks */
95 DECLARE_LOCK_EXTERN(ip_rtsp_lock);
96
97 #define SKIP_WSPACE(ptr,len,off) while(off < len && isspace(*(ptr+off))) { off++; }
98
99 /*** helper functions ***/
100
101 static void *
102 rtsp_nat_find_char(void *str, int ch, size_t len)
103 {
104     unsigned char *pStr = NULL;
105     if (len != 0) {
106         pStr = str;
107     }
108     do {
109         if (*pStr++ == ch) {
110             return ((void *)(pStr - 1));
111         }
112     } while (--len != 0);
113     return (NULL);
114 }
115
116 static void
117 get_skb_tcpdata(struct sk_buff* skb, char** pptcpdata, uint* ptcpdatalen)
118 {
119     struct iphdr*   iph  = (struct iphdr*)skb->nh.iph;
120     struct tcphdr*  tcph = (struct tcphdr*)((char*)iph + iph->ihl*4);
121
122     *pptcpdata = (char*)tcph + tcph->doff*4;
123     *ptcpdatalen = ((char*)skb->h.raw + skb->len) - *pptcpdata;
124 }
125
126 /*** nat functions ***/
127
128 /*
129  * Mangle the "Transport:" header:
130  *   - Replace all occurences of "client_port=<spec>"
131  *   - Handle destination parameter
132  *
133  * In:
134  *   ct, ctinfo = conntrack context
135  *   pskb       = packet
136  *   tranoff    = Transport header offset from TCP data
137  *   tranlen    = Transport header length (incl. CRLF)
138  *   rport_lo   = replacement low  port (host endian)
139  *   rport_hi   = replacement high port (host endian)
140  *
141  * Returns packet size difference.
142  *
143  * Assumes that a complete transport header is present, ending with CR or LF
144  */
145 static int
146 rtsp_mangle_tran(struct ip_conntrack* ct, enum ip_conntrack_info ctinfo,
147                  struct ip_conntrack_expect* exp,
148                  struct sk_buff** pskb, uint tranoff, uint tranlen)
149 {
150     char*       ptcp;
151     uint        tcplen;
152     char*       ptran;
153     char        rbuf1[16];      /* Replacement buffer (one port) */
154     uint        rbuf1len;       /* Replacement len (one port) */
155     char        rbufa[16];      /* Replacement buffer (all ports) */
156     uint        rbufalen;       /* Replacement len (all ports) */
157     u_int32_t   newip;
158     u_int16_t   loport, hiport;
159     uint        off = 0;
160     uint        diff;           /* Number of bytes we removed */
161
162     struct ip_ct_rtsp_expect* prtspexp = &exp->help.exp_rtsp_info;
163     struct ip_conntrack_tuple t;
164
165     char        szextaddr[15+1];
166     uint        extaddrlen;
167     int         is_stun;
168
169     get_skb_tcpdata(*pskb, &ptcp, &tcplen);
170     ptran = ptcp+tranoff;
171
172     if (tranoff+tranlen > tcplen || tcplen-tranoff < tranlen ||
173         tranlen < 10 || !iseol(ptran[tranlen-1]) ||
174         nf_strncasecmp(ptran, "Transport:", 10) != 0)
175     {
176         INFOP("sanity check failed\n");
177         return 0;
178     }
179     off += 10;
180     SKIP_WSPACE(ptcp+tranoff, tranlen, off);
181
182     newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
183     t = exp->tuple;
184     t.dst.ip = newip;
185
186     extaddrlen = extip ? sprintf(szextaddr, "%u.%u.%u.%u", NIPQUAD(extip))
187                        : sprintf(szextaddr, "%u.%u.%u.%u", NIPQUAD(newip));
188     DEBUGP("stunaddr=%s (%s)\n", szextaddr, (extip?"forced":"auto"));
189     DEBUGP("Found Transport message %s\n", ptran);
190
191     rbuf1len = rbufalen = 0;
192     switch (prtspexp->pbtype)
193     {
194     case pb_single:
195         loport = prtspexp->loport;
196         DEBUGP("PB_SINGLE: LO_PORT %hu\n", loport);
197         if (loport != 0)
198         {
199             rbuf1len = sprintf(rbuf1, "%hu", loport);
200             rbufalen = sprintf(rbufa, "%hu", loport);
201         }
202         break;
203     case pb_range:
204         loport = prtspexp->loport;
205         DEBUGP("PB_RANGE: LO_PORT %hu\n", loport);
206         if (loport != 0)
207         {
208             rbuf1len = sprintf(rbuf1, "%hu", loport);
209             rbufalen = sprintf(rbufa, "%hu-%hu", loport, loport+1);
210             DEBUGP("MANGLING to ports (%hu-%hu) rbuf1 %s rbufa %s\n", prtspexp->loport, prtspexp->loport+1,
211                     rbuf1, rbufa);
212         }
213         break;
214     case pb_discon:
215         DEBUGP("PB_DISCON:n");
216         for (loport = prtspexp->loport; loport != 0; loport++) /* XXX: improper wrap? */
217         {
218             DEBUGP("Original UDP PORT value is %hu exp loport %hu hiport %hu\n", t.dst.u.udp.port,
219                     prtspexp->loport, prtspexp->hiport);
220             // Do not transpose the ports yet. If you do, you better register a helper
221             // to mangle them correctly when you receive packets on those ports.
222             //t.dst.u.udp.port = htons(loport);
223             if (ip_conntrack_change_expect(exp, &t) == 0)
224             {
225                 DEBUGP("using port %hu (1 of 2)\n", loport);
226                 break;
227             }
228         }
229         for (hiport = prtspexp->hiport; hiport != 0; hiport++) /* XXX: improper wrap? */
230         {
231             t.dst.u.udp.port = htons(hiport);
232             if (ip_conntrack_change_expect(exp, &t) == 0)
233             {
234                 DEBUGP("using port %hu (2 of 2)\n", hiport);
235                 break;
236             }
237         }
238         if (loport != 0 && hiport != 0)
239         {
240             rbuf1len = sprintf(rbuf1, "%hu", loport);
241             if (hiport == loport+1)
242             {
243                 rbufalen = sprintf(rbufa, "%hu-%hu", loport, hiport);
244                 DEBUGP("Ports %hu-%hu\n", loport, hiport);
245             }
246             else
247             {
248                 rbufalen = sprintf(rbufa, "%hu/%hu", loport, hiport);
249                 DEBUGP("ports %hu-%hu\n", loport, hiport);
250             }
251         }
252         break;
253     default:
254         /* oops */
255         break;
256     }
257
258     if (rbuf1len == 0)
259     {
260         DEBUGP("Cannot get replacement ports\n");
261         return 0;   /* cannot get replacement port(s) */
262     }
263
264     /* Transport: tran;field;field=val,tran;field;field=val,... */
265     while (off < tranlen)
266     {
267         uint        saveoff;
268         const char* pparamend;
269         uint        nextparamoff;
270
271         pparamend = rtsp_nat_find_char(ptran+off, ',', tranlen-off);
272         pparamend = (pparamend == NULL) ? ptran+tranlen : pparamend+1;
273         nextparamoff = pparamend-ptcp;
274
275         /*
276          * We pass over each param twice.  On the first pass, we look for a
277          * destination= field.  It is handled by the security policy.  If it
278          * is present, allowed, and equal to our external address, we assume
279          * that STUN is being used and we leave the client_port= field alone.
280          */
281         is_stun = 0;
282         saveoff = off;
283         while (off < nextparamoff)
284         {
285             const char* pfieldend;
286             uint        nextfieldoff;
287
288             pfieldend = rtsp_nat_find_char(ptran+off, ';', nextparamoff-off);
289             nextfieldoff = (pfieldend == NULL) ? nextparamoff : pfieldend-ptran+1;
290
291             if (dstact != DSTACT_NONE && strncmp(ptran+off, "destination=", 12) == 0)
292             {
293                 if (strncmp(ptran+off+12, szextaddr, extaddrlen) == 0)
294                 {
295                     is_stun = 1;
296                 }
297                 if (dstact == DSTACT_STRIP || (dstact == DSTACT_AUTO && !is_stun))
298                 {
299                     diff = nextfieldoff-off;
300                     if (!ip_nat_mangle_tcp_packet(pskb, ct, ctinfo,
301                                                          off, diff, NULL, 0))
302                     {
303                         /* mangle failed, all we can do is bail */
304                         DEBUGP("mangle failed bailing out now\n");
305                         return 0;
306                     }
307                     get_skb_tcpdata(*pskb, &ptcp, &tcplen);
308                     ptran = ptcp+tranoff;
309                     tranlen -= diff;
310                     nextparamoff -= diff;
311                     nextfieldoff -= diff;
312                 }
313             }
314
315             off = nextfieldoff;
316         }
317         if (is_stun)
318         {
319             continue;
320         }
321         off = saveoff;
322         while (off < nextparamoff)
323         {
324             const char* pfieldend;
325             uint        nextfieldoff;
326
327             pfieldend = rtsp_nat_find_char(ptran+off, ';', nextparamoff-off);
328             nextfieldoff = (pfieldend == NULL) ? nextparamoff : pfieldend-ptran+1;
329
330             DEBUGP("off %d nextparamoff %d %s\n", off, nextparamoff, ptran+off);
331             if (strncmp(ptran+off, "client_port=", 12) == 0)
332             {
333                 u_int16_t   port;
334                 uint        numlen;
335                 uint        origoff;
336                 uint        origlen;
337                 char*       rbuf    = rbuf1;
338                 uint        rbuflen = rbuf1len;
339
340                 off += 12;
341                 origoff = (ptran-ptcp)+off;
342                 origlen = 0;
343                 numlen = nf_strtou16(ptran+off, &port);
344                 off += numlen;
345                 origlen += numlen;
346                 DEBUGP("Checking port %hu expec port %hu rbufa %s rbufalen %d\n",
347                        port, prtspexp->loport, rbufa, rbufalen);
348                 if (ptran[off] == '-' || ptran[off] == '/')
349                 {
350                     off++;
351                     origlen++;
352                     numlen = nf_strtou16(ptran+off, &port);
353                     off += numlen;
354                     origlen += numlen;
355                     rbuf = rbufa;
356                     rbuflen = rbufalen;
357                 }
358
359                 /*
360                  * note we cannot just memcpy() if the sizes are the same.
361                  * the mangle function does skb resizing, checks for a
362                  * cloned skb, and updates the checksums.
363                  *
364                  * parameter 4 below is offset from start of tcp data.
365                  */
366                 diff = origlen-rbuflen;
367                 DEBUGP("Before mangle rbuf %s diff %d ptran %s\n", rbuf, diff, ptran+off);
368                 if (!ip_nat_mangle_tcp_packet(pskb, ct, ctinfo,
369                                           origoff, origlen, rbuf, rbuflen))
370                 {
371                     /* mangle failed, all we can do is bail */
372                     DEBUGP("MANGLE Failed\n");
373                     return 0;
374                 }
375                 get_skb_tcpdata(*pskb, &ptcp, &tcplen);
376                 ptran = ptcp+tranoff;
377                 tranlen -= diff;
378                 nextparamoff -= diff;
379                 nextfieldoff -= diff;
380                 DEBUGP("After mangle nextparamoff %d nextfieldoff %d ptran %s\n",
381                        nextparamoff, nextfieldoff, ptran);
382                 break;
383             }
384             off = nextfieldoff;
385         }
386
387             off = nextparamoff;
388     }
389
390     return 1;
391 }
392
393 static unsigned int
394 expected(struct sk_buff** pskb, uint hooknum,
395                 struct ip_conntrack* ct, struct ip_nat_info* info)
396 {
397     struct ip_nat_multi_range mr;
398     u_int32_t newdstip, newsrcip, newip;
399
400     struct ip_conntrack *master = master_ct(ct);
401
402     IP_NF_ASSERT(info);
403     IP_NF_ASSERT(master);
404
405     IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum))));
406
407     newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
408     newsrcip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
409     newip = (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC) ? newsrcip : newdstip;
410
411     DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
412     DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
413     DEBUGP("newsrcip=%u.%u.%u.%u, newdstip=%u.%u.%u.%u, newip=%u.%u.%u.%u CLIENT PORT %hu\n",
414            NIPQUAD(newsrcip), NIPQUAD(newdstip), NIPQUAD(newip), ct->nat.rtsp_info.orig_port);
415     DUMP_TUPLE(&master->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
416     DUMP_TUPLE(&master->tuplehash[IP_CT_DIR_REPLY].tuple);
417
418     mr.rangesize = 1;
419     /*
420      * We don't want to manip the per-protocol, just the IPs. Actually we
421      * did manipulate the UDP ports
422      */
423     mr.range[0].flags = IP_NAT_RANGE_MAP_IPS;
424     mr.range[0].min_ip = mr.range[0].max_ip = newip;
425     mr.range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
426     mr.range[0].min.udp.port = mr.range[0].max.udp.port = ct->nat.rtsp_info.orig_port;
427
428     return ip_nat_setup_info(ct, &mr, hooknum);
429 }
430
431 static uint
432 help_out(struct ip_conntrack* ct, enum ip_conntrack_info ctinfo,
433                 struct ip_conntrack_expect* exp, struct sk_buff** pskb)
434 {
435     char*   ptcp;
436     uint    tcplen;
437     uint    hdrsoff;
438     uint    hdrslen;
439     uint    lineoff;
440     uint    linelen;
441     uint    off;
442
443     struct iphdr* iph = (struct iphdr*)(*pskb)->nh.iph;
444     struct tcphdr* tcph = (struct tcphdr*)((void*)iph + iph->ihl*4);
445
446     struct ip_ct_rtsp_expect* prtspexp = &exp->help.exp_rtsp_info;
447
448     get_skb_tcpdata(*pskb, &ptcp, &tcplen);
449
450     hdrsoff = exp->seq - ntohl(tcph->seq);
451     hdrslen = prtspexp->len;
452     off = hdrsoff;
453
454     DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
455     DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
456
457     DEBUGP("SRC IP %u.%u.%u.%u DST IP %u.%u.%u.%u PORTS %hu-%hu\n",
458            NIPQUAD(iph->saddr), NIPQUAD(iph->daddr), prtspexp->loport,
459            prtspexp->hiport);
460     while (nf_mime_nextline(ptcp, hdrsoff+hdrslen, &off, &lineoff, &linelen))
461     {
462         if (linelen == 0)
463         {
464             break;
465         }
466         if (off > hdrsoff+hdrslen)
467         {
468             INFOP("!! overrun !!\n");
469             break;
470         }
471         DEBUGP("hdr: len=%u, %.*s", linelen, (int)linelen, ptcp+lineoff);
472
473         if (nf_strncasecmp(ptcp+lineoff, "Transport:", 10) == 0)
474         {
475             uint oldtcplen = tcplen;
476             if (!rtsp_mangle_tran(ct, ctinfo, exp, pskb, lineoff, linelen))
477             {
478                 break;
479             }
480             get_skb_tcpdata(*pskb, &ptcp, &tcplen);
481             hdrslen -= (oldtcplen-tcplen);
482             off -= (oldtcplen-tcplen);
483             lineoff -= (oldtcplen-tcplen);
484             linelen -= (oldtcplen-tcplen);
485             DEBUGP("rep: len=%u, %.*s", linelen, (int)linelen, ptcp+lineoff);
486         }
487     }
488     DEBUGP("SRC IP %u.%u.%u.%u DST IP %u.%u.%u.%u PORTS (%hu-%hu)\n",
489            NIPQUAD(iph->saddr), NIPQUAD(iph->daddr), tcph->source, tcph->dest);
490
491     return NF_ACCEPT;
492 }
493
494 static uint
495 help_in(struct ip_conntrack* ct, enum ip_conntrack_info ctinfo,
496                 struct ip_conntrack_expect* exp, struct sk_buff** pskb)
497 {
498     /* XXX: unmangle */
499     DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
500     DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
501     return NF_ACCEPT;
502 }
503
504 static uint
505 help(struct ip_conntrack* ct,
506      struct ip_conntrack_expect* exp,
507      struct ip_nat_info* info,
508      enum ip_conntrack_info ctinfo,
509      unsigned int hooknum,
510      struct sk_buff** pskb)
511 {
512     struct iphdr*  iph  = (struct iphdr*)(*pskb)->nh.iph;
513     struct tcphdr* tcph = (struct tcphdr*)((char*)iph + iph->ihl * 4);
514     uint datalen;
515     int dir;
516     struct ip_ct_rtsp_expect* ct_rtsp_info;
517     int rc = NF_ACCEPT;
518
519     DEBUGP("SRC IP %u.%u.%u.%u DST IP %u.%u.%u.%u PORTS %hu-%hu\n",
520            NIPQUAD(iph->saddr), NIPQUAD(iph->daddr), tcph->source,
521            tcph->dest);
522     if (ct == NULL || exp == NULL || info == NULL || pskb == NULL)
523     {
524         DEBUGP("!! null ptr (%p,%p,%p,%p) !!\n", ct, exp, info, pskb);
525         return NF_ACCEPT;
526     }
527
528     ct_rtsp_info = &exp->help.exp_rtsp_info;
529
530     /*
531      * Only mangle things once: original direction in POST_ROUTING
532      * and reply direction on PRE_ROUTING.
533      */
534     dir = CTINFO2DIR(ctinfo);
535     if (!((hooknum == NF_IP_POST_ROUTING && dir == IP_CT_DIR_ORIGINAL)
536           || (hooknum == NF_IP_PRE_ROUTING && dir == IP_CT_DIR_REPLY)))
537     {
538         DEBUGP("Not touching dir %s at hook %s\n",
539                dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY",
540                hooknum == NF_IP_POST_ROUTING ? "POSTROUTING"
541                : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING"
542                : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???");
543         return NF_ACCEPT;
544     }
545     DEBUGP("got beyond not touching\n");
546
547     datalen = (*pskb)->len - iph->ihl * 4 - tcph->doff * 4;
548
549     LOCK_BH(&ip_rtsp_lock);
550
551     switch (dir)
552     {
553     case IP_CT_DIR_ORIGINAL:
554         rc = help_out(ct, ctinfo, exp, pskb);
555         break;
556     case IP_CT_DIR_REPLY:
557         rc = help_in(ct, ctinfo, exp, pskb);
558         break;
559     default:
560         /* oops */
561         break;
562     }
563     UNLOCK_BH(&ip_rtsp_lock);
564
565     return rc;
566 }
567
568 static struct ip_nat_helper ip_nat_rtsp_helpers[MAX_PORTS];
569 static char rtsp_names[MAX_PORTS][10];
570
571 /* This function is intentionally _NOT_ defined as  __exit */
572 static void
573 fini(void)
574 {
575     int i;
576
577     for (i = 0; i < num_ports; i++)
578     {
579         DEBUGP("unregistering helper for port %d\n", ports[i]);
580         ip_nat_helper_unregister(&ip_nat_rtsp_helpers[i]);
581     }
582 }
583
584 static int __init
585 init(void)
586 {
587     int ret = 0;
588     int i;
589     struct ip_nat_helper* hlpr;
590     char* tmpname;
591
592     printk("ip_nat_rtsp v" IP_NF_RTSP_VERSION " loading\n");
593
594     if (ports[0] == 0)
595     {
596         ports[0] = RTSP_PORT;
597     }
598
599     for (i = 0; (i < MAX_PORTS) && ports[i] != 0; i++)
600     {
601         hlpr = &ip_nat_rtsp_helpers[i];
602         memset(hlpr, 0, sizeof(struct ip_nat_helper));
603
604         hlpr->tuple.dst.protonum = IPPROTO_TCP;
605         hlpr->tuple.src.u.tcp.port = htons(ports[i]);
606         hlpr->mask.src.u.tcp.port = 0xFFFF;
607         hlpr->mask.dst.protonum = 0xFFFF;
608         hlpr->help = help;
609         hlpr->flags = 0;
610         hlpr->me = THIS_MODULE;
611         hlpr->expect = expected;
612
613         tmpname = &rtsp_names[i][0];
614         if (ports[i] == RTSP_PORT)
615         {
616             sprintf(tmpname, "rtsp");
617         }
618         else
619         {
620             sprintf(tmpname, "rtsp-%d", i);
621         }
622         hlpr->name = tmpname;
623
624         DEBUGP("registering helper for port %d: name %s\n", ports[i], hlpr->name);
625         ret = ip_nat_helper_register(hlpr);
626
627         if (ret)
628         {
629             printk("ip_nat_rtsp: error registering helper for port %d\n", ports[i]);
630             fini();
631             return 1;
632         }
633         num_ports++;
634     }
635     if (stunaddr != NULL)
636     {
637         extip = in_aton(stunaddr);
638     }
639     if (destaction != NULL)
640     {
641         if (strcmp(destaction, "auto") == 0)
642         {
643             dstact = DSTACT_AUTO;
644         }
645         if (strcmp(destaction, "strip") == 0)
646         {
647             dstact = DSTACT_STRIP;
648         }
649         if (strcmp(destaction, "none") == 0)
650         {
651             dstact = DSTACT_NONE;
652         }
653     }
654     return ret;
655 }
656
657 NEEDS_CONNTRACK(rtsp);
658
659 module_init(init);
660 module_exit(fini);