http://downloads.netgear.com/files/GPL/GPL_Source_V361j_DM111PSP_series_consumer_rele...
[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 #define NF_NEED_STRTOU32
52 #define NF_NEED_NEXTLINE
53 #include <linux/netfilter_helpers.h>
54 #define NF_NEED_MIME_NEXTLINE
55 #include <linux/netfilter_mime.h>
56
57 /*
58  * To enable debugging, replace the line below with #define IP_NF_RTSP_DEBUG 1
59  */
60 #undef IP_NF_RTSP_DEBUG
61 #define INFOP(args...) printk(args)
62 #ifdef IP_NF_RTSP_DEBUG
63 #define DUMP_TUPLE(args...)
64 #define DEBUGP(args...) printk(KERN_DEBUG "%s:%s ", __FILE__, __FUNCTION__); \
65                         printk(args)
66 #else
67 #define DEBUGP(args...)
68 #endif
69
70 #define MAX_PORTS       8
71 #define DSTACT_AUTO     0
72 #define DSTACT_STRIP    1
73 #define DSTACT_NONE     2
74 #define MAX_NAT_PORTS   16
75
76 static int          ports[MAX_PORTS];
77 static char*        stunaddr = NULL;
78 static char*        destaction = NULL;
79
80 static int          num_ports = 0;
81 static u_int32_t    extip = 0;
82 static int          dstact = 0;
83
84 MODULE_AUTHOR("Tom Marshall <tmarshall@real.com>");
85 MODULE_DESCRIPTION("RTSP network address translation module");
86 MODULE_LICENSE("GPL");
87 #ifdef MODULE_PARM
88 MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i");
89 MODULE_PARM_DESC(ports, "port numbers of RTSP servers");
90 MODULE_PARM(stunaddr, "s");
91 MODULE_PARM_DESC(stunaddr, "Address for detecting STUN");
92 MODULE_PARM(destaction, "s");
93 MODULE_PARM_DESC(destaction, "Action for destination parameter (auto/strip/none)");
94 #endif
95
96 /* protects rtsp part of conntracks */
97 DECLARE_LOCK_EXTERN(ip_rtsp_lock);
98
99 #define SKIP_WSPACE(ptr,len,off) while(off < len && isspace(*(ptr+off))) { off++; }
100
101 /*** helper functions ***/
102
103 static void *
104 rtsp_nat_find_char(void *str, int ch, size_t len)
105 {
106     unsigned char *pStr = NULL;
107     if (len != 0) {
108         pStr = str;
109     }
110     do {
111         if (*pStr++ == ch) {
112             return ((void *)(pStr - 1));
113         }
114     } while (--len != 0);
115     return (NULL);
116 }
117
118 /*
119 ** OUT  pptcpdata: point to offset of rtsp headers
120 ** OUT  ptcpdatalen: set the length of rtsp headers 
121 */
122 static void
123 get_skb_tcpdata(struct sk_buff* skb, char** pptcpdata, uint* ptcpdatalen)
124 {
125     struct iphdr*   iph  = (struct iphdr*)skb->nh.iph;
126     struct tcphdr*  tcph = (struct tcphdr*)((char*)iph + iph->ihl*4);
127
128     *pptcpdata = (char*)tcph + tcph->doff*4;
129     *ptcpdatalen = ((char*)skb->h.raw + skb->len) - *pptcpdata;
130 }
131
132 /*** nat functions ***/
133
134 static int
135 rtsp_parse_message(char* ptcp, uint tcplen, uint* ptcpoff,
136                    uint* phdrsoff, uint* phdrslen,
137                    uint* pcseqoff, uint* pcseqlen)
138 {
139     uint    entitylen = 0;
140     uint    lineoff;
141     uint    linelen;
142
143     if (!nf_nextline(ptcp, tcplen, ptcpoff, &lineoff, &linelen))
144     {
145         return 0;
146     }
147
148     *phdrsoff = *ptcpoff;
149     while (nf_mime_nextline(ptcp, tcplen, ptcpoff, &lineoff, &linelen))
150     {
151         if (linelen == 0)
152         {
153             if (entitylen > 0)
154             {
155                 *ptcpoff += min(entitylen, tcplen - *ptcpoff);
156             }
157             break;
158         }
159         if (lineoff+linelen > tcplen)
160         {
161             INFOP("!! overrun !!\n");
162             break;
163         }
164
165         if (nf_strncasecmp(ptcp+lineoff, "CSeq:", 5) == 0)
166         {
167             *pcseqoff = lineoff;
168             *pcseqlen = linelen;
169         }
170         if (nf_strncasecmp(ptcp+lineoff, "Content-Length:", 15) == 0)
171         {
172             uint off = lineoff+15;
173             SKIP_WSPACE(ptcp+lineoff, linelen, off);
174             nf_strtou32(ptcp+off, &entitylen);
175         }
176     }
177     *phdrslen = (*ptcpoff) - (*phdrsoff);
178
179     return 1;
180 }
181
182 /*
183  * Mangle the "Transport:" header:
184  *   - Replace all occurences of "client_port=<spec>"
185  *   - Handle destination parameter
186  *
187  * In:
188  *   ct, ctinfo = conntrack context
189  *   pskb       = packet
190  *   tranoff    = Transport header offset from TCP data
191  *   tranlen    = Transport header length (incl. CRLF)
192  *   rport_lo   = replacement low  port (host endian)
193  *   rport_hi   = replacement high port (host endian)
194  *
195  * Returns packet size difference.
196  *
197  * Assumes that a complete transport header is present, ending with CR or LF
198  */
199 static int
200 rtsp_mangle_tran(struct ip_conntrack* ct, enum ip_conntrack_info ctinfo,
201                  struct ip_conntrack_expect* exp,
202                  struct sk_buff** pskb, uint tranoff, uint tranlen)
203 {
204     int dir = CTINFO2DIR(ctinfo);
205     char*       ptcp;
206     uint        tcplen;
207     char*       ptran;
208     char        rbuf1[16];      /* Replacement buffer (one port) */
209     uint        rbuf1len;       /* Replacement len (one port) */
210     char        rbufa[16];      /* Replacement buffer (all ports) */
211     uint        rbufalen;       /* Replacement len (all ports) */
212     u_int32_t   newip;
213     u_int16_t   loport, hiport;
214     uint        off = 0;
215     uint        diff;           /* Number of bytes we removed */
216
217     struct ip_ct_rtsp_expect* prtspexp = &exp->help.exp_rtsp_info;
218     struct ip_conntrack_tuple t;
219
220     char        szextaddr[15+1];
221     uint        extaddrlen;
222     int         is_stun;
223
224     get_skb_tcpdata(*pskb, &ptcp, &tcplen);
225     ptran = ptcp+tranoff;
226     //printk("rtsp_mangle_tran(): tcplen=[%u], tranoff=[%u], tranlen=[%u]\n",tcplen, tranoff, tranlen);
227
228     if (tranoff+tranlen > tcplen || tcplen-tranoff < tranlen || tranlen < 10 
229         || !iseol(ptran[tranlen-1]) || nf_strncasecmp(ptran, "Transport:", 10) != 0)
230     {
231         INFOP("sanity check failed\n");
232         return 0;
233     }
234     off += 10;
235     SKIP_WSPACE(ptcp+tranoff, tranlen, off);
236
237         if (dir == IP_CT_DIR_ORIGINAL)
238     newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
239     else
240         newip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; 
241     t = exp->tuple;
242     t.dst.ip = newip;
243
244     extaddrlen = extip ? sprintf(szextaddr, "%u.%u.%u.%u", NIPQUAD(extip))
245                        : sprintf(szextaddr, "%u.%u.%u.%u", NIPQUAD(newip));
246     DEBUGP("stunaddr=%s (%s)\n", szextaddr, (extip?"forced":"auto"));
247     DEBUGP("Found Transport message %s\n", ptran);
248
249     rbuf1len = rbufalen = 0;
250     switch (prtspexp->pbtype)
251     {
252     case pb_single:
253         loport = prtspexp->loport;
254         DEBUGP("PB_SINGLE: LO_PORT %hu\n", loport);
255         if (loport != 0)
256         {
257             rbuf1len = sprintf(rbuf1, "%hu", loport);
258             rbufalen = sprintf(rbufa, "%hu", loport);
259         }
260         break;
261     case pb_range:
262         loport = prtspexp->loport;
263         DEBUGP("PB_RANGE: LO_PORT %hu\n", loport);
264         if (loport != 0)
265         {
266             rbuf1len = sprintf(rbuf1, "%hu", loport);
267             rbufalen = sprintf(rbufa, "%hu-%hu", loport, loport+1);
268             DEBUGP("MANGLING to ports (%hu-%hu) rbuf1 %s rbufa %s\n", prtspexp->loport, prtspexp->loport+1,
269                     rbuf1, rbufa);
270         }
271         break;
272     case pb_discon:
273         DEBUGP("PB_DISCON:n");
274         for (loport = prtspexp->loport; loport != 0; loport++) /* XXX: improper wrap? */
275         {
276             DEBUGP("Original UDP PORT value is %hu exp loport %hu hiport %hu\n", t.dst.u.udp.port,
277                     prtspexp->loport, prtspexp->hiport);
278             // Do not transpose the ports yet. If you do, you better register a helper
279             // to mangle them correctly when you receive packets on those ports.
280             //t.dst.u.udp.port = htons(loport);
281             if (ip_conntrack_change_expect(exp, &t) == 0)
282             {
283                 DEBUGP("using port %hu (1 of 2)\n", loport);
284                 break;
285             }
286         }
287         for (hiport = prtspexp->hiport; hiport != 0; hiport++) /* XXX: improper wrap? */
288         {
289             t.dst.u.udp.port = htons(hiport);
290             if (ip_conntrack_change_expect(exp, &t) == 0)
291             {
292                 DEBUGP("using port %hu (2 of 2)\n", hiport);
293                 break;
294             }
295         }
296         if (loport != 0 && hiport != 0)
297         {
298             rbuf1len = sprintf(rbuf1, "%hu", loport);
299             if (hiport == loport+1)
300             {
301                 rbufalen = sprintf(rbufa, "%hu-%hu", loport, hiport);
302                 DEBUGP("Ports %hu-%hu\n", loport, hiport);
303             }
304             else
305             {
306                 rbufalen = sprintf(rbufa, "%hu/%hu", loport, hiport);
307                 DEBUGP("ports %hu-%hu\n", loport, hiport);
308             }
309         }
310         break;
311     default:
312         /* oops */
313         break;
314     }
315
316     if (rbuf1len == 0)
317     {
318         DEBUGP("Cannot get replacement ports\n");
319         return 0;   /* cannot get replacement port(s) */
320     }
321
322     /* Transport: tran;field;field=val,tran;field;field=val,... */
323     while (off < tranlen)
324     {
325         uint        saveoff;
326         const char* pparamend;
327         uint        nextparamoff;
328
329         pparamend = rtsp_nat_find_char(ptran+off, ',', tranlen-off);
330         pparamend = (pparamend == NULL) ? ptran+tranlen : pparamend+1;
331         nextparamoff = pparamend-ptcp;
332
333         /*
334          * We pass over each param twice.  On the first pass, we look for a
335          * destination= field.  It is handled by the security policy.  If it
336          * is present, allowed, and equal to our external address, we assume
337          * that STUN is being used and we leave the client_port= field alone.
338          */
339         is_stun = 0;
340         saveoff = off;
341         while (off < nextparamoff)
342         {
343             const char* pfieldend;
344             uint        nextfieldoff;
345
346             pfieldend = rtsp_nat_find_char(ptran+off, ';', nextparamoff-off);
347             nextfieldoff = (pfieldend == NULL) ? nextparamoff : pfieldend-ptran+1;
348
349             if (dstact != DSTACT_NONE && strncmp(ptran+off, "destination=", 12) == 0)
350             {
351                 if (strncmp(ptran+off+12, szextaddr, extaddrlen) == 0)
352                 {
353                     is_stun = 1;
354                 }
355                 if (dstact == DSTACT_STRIP || (dstact == DSTACT_AUTO && !is_stun))
356                 {
357                     uint  origoff_des = 0;
358                     uint  origlen_des = 0;
359                     off += 12;
360                     origoff_des = (ptran-ptcp)+off;//original destination ip offset
361                     if (pfieldend)
362                         origlen_des = (nextfieldoff-off)-1;//original destination ip length
363                     else
364                         origlen_des = (nextfieldoff-origoff_des)-2;
365                     off += origlen_des;
366                     //diff = nextfieldoff-off;
367                     diff = origlen_des-extaddrlen;
368                     //if (!ip_nat_mangle_tcp_packet(pskb, ct, ctinfo,off, diff, NULL, 0))
369                     //printk("origoff_des=[%d], origlen_des=[%d], szextaddr=[%s], extaddrlen=[%d]\n", origoff_des, origlen_des, szextaddr, extaddrlen);
370                     //printk("andy_diff=[%d]\n",diff);
371                     if (!ip_nat_mangle_tcp_packet(pskb, ct, ctinfo,origoff_des, origlen_des, szextaddr, extaddrlen))
372                     {
373                         /* mangle failed, all we can do is bail */
374                         DEBUGP("mangle failed bailing out now\n");
375                         return 0;
376                     }
377                     get_skb_tcpdata(*pskb, &ptcp, &tcplen);
378                     ptran = ptcp+tranoff;
379                     tranlen -= diff;
380                     nextparamoff -= diff;
381                     nextfieldoff -= diff;
382                 }
383             }
384
385             off = nextfieldoff;
386         }
387         if (is_stun)
388         {
389             continue;
390         }
391         off = saveoff;
392         while (off < nextparamoff)
393         {
394             const char* pfieldend;
395             uint        nextfieldoff;
396
397             pfieldend = rtsp_nat_find_char(ptran+off, ';', nextparamoff-off);
398             nextfieldoff = (pfieldend == NULL) ? nextparamoff : pfieldend-ptran+1;
399
400             DEBUGP("off %d nextparamoff %d %s\n", off, nextparamoff, ptran+off);
401             if (strncmp(ptran+off, "client_port=", 12) == 0)
402             {
403                 u_int16_t   port;
404                 uint        numlen;
405                 uint        origoff;
406                 uint        origlen;
407                 char*       rbuf    = rbuf1;
408                 uint        rbuflen = rbuf1len;
409
410                 off += 12;
411                 origoff = (ptran-ptcp)+off;
412                 origlen = 0;
413                 numlen = nf_strtou16(ptran+off, &port);
414                 off += numlen;
415                 origlen += numlen;
416                 DEBUGP("Checking port %hu expec port %hu rbufa %s rbufalen %d\n",
417                        port, prtspexp->loport, rbufa, rbufalen);
418                 if (ptran[off] == '-' || ptran[off] == '/')
419                 {
420                     off++;
421                     origlen++;
422                     numlen = nf_strtou16(ptran+off, &port);
423                     off += numlen;
424                     origlen += numlen;
425                     rbuf = rbufa;
426                     rbuflen = rbufalen;
427                 }
428
429                 /*
430                  * note we cannot just memcpy() if the sizes are the same.
431                  * the mangle function does skb resizing, checks for a
432                  * cloned skb, and updates the checksums.
433                  *
434                  * parameter 4 below is offset from start of tcp data.
435                  */
436                 diff = origlen-rbuflen;
437                 DEBUGP("Before mangle rbuf %s diff %d ptran %s\n", rbuf, diff, ptran+off);
438                 if (!ip_nat_mangle_tcp_packet(pskb, ct, ctinfo,
439                                           origoff, origlen, rbuf, rbuflen))
440                 {
441                     /* mangle failed, all we can do is bail */
442                     DEBUGP("MANGLE Failed\n");
443                     return 0;
444                 }
445                 get_skb_tcpdata(*pskb, &ptcp, &tcplen);
446                 ptran = ptcp+tranoff;
447                 tranlen -= diff;
448                 nextparamoff -= diff;
449                 nextfieldoff -= diff;
450                 DEBUGP("After mangle nextparamoff %d nextfieldoff %d ptran %s\n",
451                        nextparamoff, nextfieldoff, ptran);
452                 break;
453             }
454             off = nextfieldoff;
455         }
456
457             off = nextparamoff;
458     }
459
460     return 1;
461 }
462
463 static unsigned int
464 expected(struct sk_buff** pskb, uint hooknum,
465                 struct ip_conntrack* ct, struct ip_nat_info* info)
466 {
467     struct ip_nat_multi_range mr;
468     u_int32_t newdstip, newsrcip, newip;
469
470     struct ip_conntrack *master = master_ct(ct);
471     IP_NF_ASSERT(info);
472     IP_NF_ASSERT(master);
473
474     IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum))));
475
476     newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
477     newsrcip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
478     newip = (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC) ? newsrcip : newdstip;
479
480     DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
481     DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
482     //printk("newsrcip=%u.%u.%u.%u, newdstip=%u.%u.%u.%u, newip=%u.%u.%u.%u CLIENT PORT %hu\n",
483     //       NIPQUAD(newsrcip), NIPQUAD(newdstip), NIPQUAD(newip), ct->nat.rtsp_info.orig_port);
484     DUMP_TUPLE(&master->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
485     DUMP_TUPLE(&master->tuplehash[IP_CT_DIR_REPLY].tuple);
486
487     mr.rangesize = 1;
488     /*
489      * We don't want to manip the per-protocol, just the IPs. Actually we
490      * did manipulate the UDP ports
491      */
492     mr.range[0].flags = IP_NAT_RANGE_MAP_IPS;
493     mr.range[0].min_ip = mr.range[0].max_ip = newip;
494     mr.range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
495     mr.range[0].min.udp.port = mr.range[0].max.udp.port = ct->nat.rtsp_info.orig_port;
496     return ip_nat_setup_info(ct, &mr, hooknum);
497 }
498
499 static uint
500 help_out(struct ip_conntrack* ct, enum ip_conntrack_info ctinfo,
501                 struct ip_conntrack_expect* exp, struct sk_buff** pskb)
502 {
503     char*   ptcp;
504     uint    tcplen;
505     uint    hdrsoff;
506     uint    hdrslen;
507     uint    lineoff=0;
508     uint    linelen=0;
509     uint    off;
510
511     struct iphdr* iph = (struct iphdr*)(*pskb)->nh.iph;
512     struct tcphdr* tcph = (struct tcphdr*)((void*)iph + iph->ihl*4);
513
514     struct ip_ct_rtsp_expect* prtspexp = &exp->help.exp_rtsp_info;
515
516     get_skb_tcpdata(*pskb, &ptcp, &tcplen);
517
518     hdrsoff = exp->seq - ntohl(tcph->seq);
519         //printk("ip_nat_rtsp.c==>help_out(): tcplen=[%u]\n", tcplen);
520         //printk("ip_nat_rtsp.c==>help_out(): exp->seq=[%u], tcph->seq=[%u], prtspexp->len=[%u], hdrsoff=[%u]\n",
521         //              exp->seq, tcph->seq, prtspexp->len, hdrsoff);    
522     hdrslen = prtspexp->len;
523     off = hdrsoff;
524
525         if ((exp->seq - ntohl(tcph->seq)) != tcplen - prtspexp->len){
526                 //printk("is wan to lan expenation\n");
527                 return NF_ACCEPT;
528         }
529
530
531     DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
532     DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
533
534     DEBUGP("SRC IP %u.%u.%u.%u DST IP %u.%u.%u.%u PORTS %hu-%hu\n",
535            NIPQUAD(iph->saddr), NIPQUAD(iph->daddr), prtspexp->loport,
536            prtspexp->hiport);
537     //printk("help_out():SRC IP %u.%u.%u.%u DST IP %u.%u.%u.%u PORTS %hu-%hu\n",
538     //      NIPQUAD(iph->saddr), NIPQUAD(iph->daddr), prtspexp->loport,
539     //       prtspexp->hiport);       
540     while (nf_mime_nextline(ptcp, hdrsoff+hdrslen, &off, &lineoff, &linelen))
541     {
542         if (linelen == 0)
543         {
544             break;
545         }
546         if (off > hdrsoff+hdrslen)
547         {
548             INFOP("!! overrun !!\n");
549             break;
550         }
551         DEBUGP("hdr: len=%u, %.*s", linelen, (int)linelen, ptcp+lineoff);
552
553         if (nf_strncasecmp(ptcp+lineoff, "Transport:", 10) == 0)
554         {
555             uint oldtcplen = tcplen;
556             if (!rtsp_mangle_tran(ct, ctinfo, exp, pskb, lineoff, linelen))
557             {
558                 break;
559             }
560             get_skb_tcpdata(*pskb, &ptcp, &tcplen);
561             hdrslen -= (oldtcplen-tcplen);
562             off -= (oldtcplen-tcplen);
563             lineoff -= (oldtcplen-tcplen);
564             linelen -= (oldtcplen-tcplen);
565             DEBUGP("rep: len=%u, %.*s", linelen, (int)linelen, ptcp+lineoff);
566         }
567     }
568     DEBUGP("SRC IP %u.%u.%u.%u DST IP %u.%u.%u.%u PORTS (%hu-%hu)\n",
569            NIPQUAD(iph->saddr), NIPQUAD(iph->daddr), tcph->source, tcph->dest);
570
571     return NF_ACCEPT;
572 }
573
574 static uint
575 help_in(struct ip_conntrack* ct, enum ip_conntrack_info ctinfo,
576                 struct ip_conntrack_expect* exp, struct sk_buff** pskb)
577 {
578     struct sk_buff* skb = (struct sk_buff*)(*pskb);
579     struct iphdr*  iph  = (struct iphdr*)(*pskb)->nh.iph;
580     struct ip_ct_rtsp_expect* prtspexp = &exp->help.exp_rtsp_info;
581         uint    dataoff = 0;
582         uint    datalen = 0;
583         struct tcphdr tcph;
584         char*   ptcp;
585     uint    tcplen=0;
586     char temp[32];
587     uint    mangle_hdrsoff=0;
588     uint    mangle_hdrslen=0;
589     uint    mangle_off=0;
590
591     DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
592     DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
593         
594
595         if (prtspexp->cseq == 0)
596                 return NF_ACCEPT;
597         /* Not whole TCP header? */
598     if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &tcph, sizeof(tcph)) != 0){
599         return NF_ACCEPT;
600     }
601     /* No data? */
602     dataoff = skb->nh.iph->ihl*4 + tcph.doff*4;
603     if ( skb->nh.iph->ihl*4 + tcph.doff*4 >= skb->len)
604     {
605         return NF_ACCEPT;
606     }   
607         datalen = skb->len - dataoff;
608         //printk("ip_nat_rtsp.c help_in(): dataoff=[%u], datalen=[%u]\n",dataoff, datalen);     
609         get_skb_tcpdata(*pskb, &ptcp, &tcplen);
610         
611         mangle_hdrsoff = dataoff;
612         mangle_hdrslen = datalen;
613         mangle_off = mangle_hdrsoff;
614         dataoff = 0;
615         while (dataoff < datalen){
616                 uint    cmdoff = dataoff;
617                 uint    hdrsoff = 0;
618         uint    hdrslen = 0;
619         uint    cseqoff = 0;
620         uint    cseqlen = 0;
621         uint    lineoff = 0;
622         uint    linelen = 0;
623         uint    rtspcseq = 0;
624         uint    off =0;
625                 if (!rtsp_parse_message(ptcp, datalen, &dataoff,
626                                 &hdrsoff, &hdrslen,
627                                 &cseqoff, &cseqlen)){
628             break;      /* not a valid message */
629         }
630         if (strncmp(ptcp+cmdoff, "RTSP/1.0 200 OK", 15) != 0)
631         {
632             continue;   /* not a RTSP/1.0 200 OK message */
633         }
634         //printk("found a RTSP/1.0 200 OK message\n");
635         memset(temp, 0, 32);
636         memcpy(temp, ptcp+cseqoff+6, cseqlen-6);
637         nf_strtou32(temp, &rtspcseq);
638         //printk("rtspcseq=[%u], prtspexp->cseq=[%u]\n", rtspcseq, prtspexp->cseq);
639                 if (rtspcseq == prtspexp->cseq){//Mangle the "Transport:" field of the packet from wan to lan
640                         //printk("Do mangle packet from wan to lan\n");
641                         //printk("hdrsoff=[%u], hdrslen=[%u]\n",hdrsoff, hdrslen);
642                         while (nf_mime_nextline(ptcp+hdrsoff, hdrslen, &off, &lineoff, &linelen)){
643                                 if (linelen == 0){
644                                 break;
645                         }
646                         if (off > hdrsoff+hdrslen){
647                                 break;
648                         }
649                         if (nf_strncasecmp(ptcp+hdrsoff+lineoff, "Transport:", 10) == 0){
650                         //printk("ip_nat_rtsp.c: get Transport field\n");
651                         //printk("prtspexp->pbtype=[%d], prtspexp->loport=[%u],prtspexp->hiport=[%u]\n",prtspexp->pbtype,prtspexp->loport,prtspexp->hiport);
652                         //printk("iph->saddr=[%u.%u.%u.%u], tcph.source=[%u]\n", NIPQUAD(iph->saddr),tcph.source);      
653                         if(andy_rtsp_nat_to_client_pmap(prtspexp, iph)){
654                                 //printk("ip_nat_rtsp==>hdr: len=[%u, %.*s]\n", linelen, (int)linelen, ptcp+hdrsoff+lineoff);
655                                 //printk("Do mangle packet from wan to lan\n");
656                                 uint oldtcplen = tcplen;
657                                 //printk("lineoff=[%u], linelen=[%u]\n", hdrsoff+lineoff, linelen);
658                                 if (!rtsp_mangle_tran(ct, ctinfo, exp, pskb, hdrsoff+lineoff, linelen)){
659                                         //printk("mangle packet from wan to lan fail\n");
660                                         break;
661                                 }
662                                 get_skb_tcpdata(*pskb, &ptcp, &tcplen);
663                                 hdrslen -= (oldtcplen-tcplen);
664                                 off -= (oldtcplen-tcplen);
665                                 lineoff -= (oldtcplen-tcplen);
666                                 linelen -= (oldtcplen-tcplen);
667                                 //printk("rep: len=%u, %.*s", linelen, (int)linelen, ptcp+hdrsoff+lineoff);
668                                 
669                                 //printk("unexpect related exp[%p]\n",exp);
670                                 u_int32_t srcip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
671                                 u_int32_t dstip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
672                                 u_int16_t dstport = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.tcp.port;
673                                 //printk("unexpect related srcip=[%u.%u.%u.%u], dstip=[%u.%u.%u.%u], dstport=[%u]\n", NIPQUAD(srcip),NIPQUAD(dstip),dstport);
674                                 struct ip_conntrack_expect *expo = expect_find_tcp(ct, srcip, dstip, dstport);
675                                 if(expo && ct != expo->expectant){
676                                         ip_conntrack_unexpect_related(expo);
677                                 }
678                         }
679                         break;
680                 }
681                         }       
682                         break;
683                 }
684         }
685
686     return NF_ACCEPT;
687 }
688
689 static uint
690 help(struct ip_conntrack* ct,
691      struct ip_conntrack_expect* exp,
692      struct ip_nat_info* info,
693      enum ip_conntrack_info ctinfo,
694      unsigned int hooknum,
695      struct sk_buff** pskb)
696 {
697     struct iphdr*  iph  = (struct iphdr*)(*pskb)->nh.iph;
698     struct tcphdr* tcph = (struct tcphdr*)((char*)iph + iph->ihl * 4);
699     uint datalen;
700     int dir;
701     struct ip_ct_rtsp_expect* ct_rtsp_info;
702     int rc = NF_ACCEPT;
703
704     if (ct == NULL || exp == NULL || info == NULL || pskb == NULL)
705     {
706         return NF_ACCEPT;
707     }
708
709     ct_rtsp_info = &exp->help.exp_rtsp_info;
710
711     /*
712      * Only mangle things once: original direction in POST_ROUTING
713      * and reply direction on PRE_ROUTING.
714      */
715     dir = CTINFO2DIR(ctinfo);
716     if (!((hooknum == NF_IP_POST_ROUTING && dir == IP_CT_DIR_ORIGINAL)
717           || (hooknum == NF_IP_PRE_ROUTING && dir == IP_CT_DIR_REPLY)))
718     {
719         DEBUGP("Not touching dir %s at hook %s\n",
720                dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY",
721                hooknum == NF_IP_POST_ROUTING ? "POSTROUTING"
722                : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING"
723                : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???");
724         return NF_ACCEPT;
725     }
726     DEBUGP("got beyond not touching\n");
727
728     datalen = (*pskb)->len - iph->ihl * 4 - tcph->doff * 4;
729     LOCK_BH(&ip_rtsp_lock);
730
731     switch (dir)
732     {
733     case IP_CT_DIR_ORIGINAL:
734         rc = help_out(ct, ctinfo, exp, pskb);
735         break;
736     case IP_CT_DIR_REPLY:
737         rc = help_in(ct, ctinfo, exp, pskb);
738         break;
739     default:
740         /* oops */
741         break;
742     }
743     UNLOCK_BH(&ip_rtsp_lock);
744
745     return rc;
746 }
747
748 static struct ip_nat_helper ip_nat_rtsp_helpers[MAX_PORTS];
749 static char rtsp_names[MAX_PORTS][10];
750
751 /* This function is intentionally _NOT_ defined as  __exit */
752 static void
753 fini(void)
754 {
755     int i;
756
757     for (i = 0; i < num_ports; i++)
758     {
759         DEBUGP("unregistering helper for port %d\n", ports[i]);
760         ip_nat_helper_unregister(&ip_nat_rtsp_helpers[i]);
761     }
762 }
763
764 static int __init
765 init(void)
766 {
767     int ret = 0;
768     int i;
769     struct ip_nat_helper* hlpr;
770     char* tmpname;
771
772     printk("ip_nat_rtsp v" IP_NF_RTSP_VERSION " loading\n");
773
774     if (ports[0] == 0)
775     {
776         ports[0] = RTSP_PORT;
777     }
778
779     for (i = 0; (i < MAX_PORTS) && ports[i] != 0; i++)
780     {
781         hlpr = &ip_nat_rtsp_helpers[i];
782         memset(hlpr, 0, sizeof(struct ip_nat_helper));
783
784         hlpr->tuple.dst.protonum = IPPROTO_TCP;
785         hlpr->tuple.src.u.tcp.port = htons(ports[i]);
786         hlpr->mask.src.u.tcp.port = 0xFFFF;
787         hlpr->mask.dst.protonum = 0xFFFF;
788         hlpr->help = help;
789         hlpr->flags = IP_NAT_HELPER_F_ALWAYS;
790         hlpr->me = THIS_MODULE;
791         hlpr->expect = expected;
792
793         tmpname = &rtsp_names[i][0];
794         if (ports[i] == RTSP_PORT)
795         {
796             sprintf(tmpname, "rtsp");
797         }
798         else
799         {
800             sprintf(tmpname, "rtsp-%d", i);
801         }
802         hlpr->name = tmpname;
803
804         DEBUGP("registering helper for port %d: name %s\n", ports[i], hlpr->name);
805         ret = ip_nat_helper_register(hlpr);
806
807         if (ret)
808         {
809             printk("ip_nat_rtsp: error registering helper for port %d\n", ports[i]);
810             fini();
811             return 1;
812         }
813         num_ports++;
814     }
815     if (stunaddr != NULL)
816     {
817         extip = in_aton(stunaddr);
818     }
819     if (destaction != NULL)
820     {
821         if (strcmp(destaction, "auto") == 0)
822         {
823             dstact = DSTACT_AUTO;
824         }
825         if (strcmp(destaction, "strip") == 0)
826         {
827             dstact = DSTACT_STRIP;
828         }
829         if (strcmp(destaction, "none") == 0)
830         {
831             dstact = DSTACT_NONE;
832         }
833     }
834     return ret;
835 }
836
837 NEEDS_CONNTRACK(rtsp);
838
839 module_init(init);
840 module_exit(fini);