2 * RTSP extension for TCP NAT alteration
3 * (C) 2003 by Tom Marshall <tmarshall@real.com>
4 * based on ip_nat_irc.c
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.
12 * insmod ip_nat_rtsp.o ports=port1,port2,...port<MAX_PORTS>
14 * destaction=[auto|strip|none]
16 * If no ports are specified, the default will be port 554 only.
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
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).
33 #include <linux/module.h>
34 #include <linux/netfilter_ipv4.h>
36 #include <linux/tcp.h>
37 #include <linux/udp.h>
38 #include <linux/kernel.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>
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>
58 * To enable debugging, replace the line below with #define IP_NF_RTSP_DEBUG 1
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__); \
67 #define DEBUGP(args...)
72 #define DSTACT_STRIP 1
74 #define MAX_NAT_PORTS 16
76 static int ports[MAX_PORTS];
77 static char* stunaddr = NULL;
78 static char* destaction = NULL;
80 static int num_ports = 0;
81 static u_int32_t extip = 0;
82 static int dstact = 0;
84 MODULE_AUTHOR("Tom Marshall <tmarshall@real.com>");
85 MODULE_DESCRIPTION("RTSP network address translation module");
86 MODULE_LICENSE("GPL");
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)");
96 /* protects rtsp part of conntracks */
97 DECLARE_LOCK_EXTERN(ip_rtsp_lock);
99 #define SKIP_WSPACE(ptr,len,off) while(off < len && isspace(*(ptr+off))) { off++; }
101 /*** helper functions ***/
104 rtsp_nat_find_char(void *str, int ch, size_t len)
106 unsigned char *pStr = NULL;
112 return ((void *)(pStr - 1));
114 } while (--len != 0);
119 ** OUT pptcpdata: point to offset of rtsp headers
120 ** OUT ptcpdatalen: set the length of rtsp headers
123 get_skb_tcpdata(struct sk_buff* skb, char** pptcpdata, uint* ptcpdatalen)
125 struct iphdr* iph = (struct iphdr*)skb->nh.iph;
126 struct tcphdr* tcph = (struct tcphdr*)((char*)iph + iph->ihl*4);
128 *pptcpdata = (char*)tcph + tcph->doff*4;
129 *ptcpdatalen = ((char*)skb->h.raw + skb->len) - *pptcpdata;
132 /*** nat functions ***/
135 rtsp_parse_message(char* ptcp, uint tcplen, uint* ptcpoff,
136 uint* phdrsoff, uint* phdrslen,
137 uint* pcseqoff, uint* pcseqlen)
143 if (!nf_nextline(ptcp, tcplen, ptcpoff, &lineoff, &linelen))
148 *phdrsoff = *ptcpoff;
149 while (nf_mime_nextline(ptcp, tcplen, ptcpoff, &lineoff, &linelen))
155 *ptcpoff += min(entitylen, tcplen - *ptcpoff);
159 if (lineoff+linelen > tcplen)
161 INFOP("!! overrun !!\n");
165 if (nf_strncasecmp(ptcp+lineoff, "CSeq:", 5) == 0)
170 if (nf_strncasecmp(ptcp+lineoff, "Content-Length:", 15) == 0)
172 uint off = lineoff+15;
173 SKIP_WSPACE(ptcp+lineoff, linelen, off);
174 nf_strtou32(ptcp+off, &entitylen);
177 *phdrslen = (*ptcpoff) - (*phdrsoff);
183 * Mangle the "Transport:" header:
184 * - Replace all occurences of "client_port=<spec>"
185 * - Handle destination parameter
188 * ct, ctinfo = conntrack context
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)
195 * Returns packet size difference.
197 * Assumes that a complete transport header is present, ending with CR or LF
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)
204 int dir = CTINFO2DIR(ctinfo);
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) */
213 u_int16_t loport, hiport;
215 uint diff; /* Number of bytes we removed */
217 struct ip_ct_rtsp_expect* prtspexp = &exp->help.exp_rtsp_info;
218 struct ip_conntrack_tuple t;
220 char szextaddr[15+1];
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);
228 if (tranoff+tranlen > tcplen || tcplen-tranoff < tranlen || tranlen < 10
229 || !iseol(ptran[tranlen-1]) || nf_strncasecmp(ptran, "Transport:", 10) != 0)
231 INFOP("sanity check failed\n");
235 SKIP_WSPACE(ptcp+tranoff, tranlen, off);
237 if (dir == IP_CT_DIR_ORIGINAL)
238 newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
240 newip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
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);
249 rbuf1len = rbufalen = 0;
250 switch (prtspexp->pbtype)
253 loport = prtspexp->loport;
254 DEBUGP("PB_SINGLE: LO_PORT %hu\n", loport);
257 rbuf1len = sprintf(rbuf1, "%hu", loport);
258 rbufalen = sprintf(rbufa, "%hu", loport);
262 loport = prtspexp->loport;
263 DEBUGP("PB_RANGE: LO_PORT %hu\n", loport);
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,
273 DEBUGP("PB_DISCON:n");
274 for (loport = prtspexp->loport; loport != 0; loport++) /* XXX: improper wrap? */
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)
283 DEBUGP("using port %hu (1 of 2)\n", loport);
287 for (hiport = prtspexp->hiport; hiport != 0; hiport++) /* XXX: improper wrap? */
289 t.dst.u.udp.port = htons(hiport);
290 if (ip_conntrack_change_expect(exp, &t) == 0)
292 DEBUGP("using port %hu (2 of 2)\n", hiport);
296 if (loport != 0 && hiport != 0)
298 rbuf1len = sprintf(rbuf1, "%hu", loport);
299 if (hiport == loport+1)
301 rbufalen = sprintf(rbufa, "%hu-%hu", loport, hiport);
302 DEBUGP("Ports %hu-%hu\n", loport, hiport);
306 rbufalen = sprintf(rbufa, "%hu/%hu", loport, hiport);
307 DEBUGP("ports %hu-%hu\n", loport, hiport);
318 DEBUGP("Cannot get replacement ports\n");
319 return 0; /* cannot get replacement port(s) */
322 /* Transport: tran;field;field=val,tran;field;field=val,... */
323 while (off < tranlen)
326 const char* pparamend;
329 pparamend = rtsp_nat_find_char(ptran+off, ',', tranlen-off);
330 pparamend = (pparamend == NULL) ? ptran+tranlen : pparamend+1;
331 nextparamoff = pparamend-ptcp;
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.
341 while (off < nextparamoff)
343 const char* pfieldend;
346 pfieldend = rtsp_nat_find_char(ptran+off, ';', nextparamoff-off);
347 nextfieldoff = (pfieldend == NULL) ? nextparamoff : pfieldend-ptran+1;
349 if (dstact != DSTACT_NONE && strncmp(ptran+off, "destination=", 12) == 0)
351 if (strncmp(ptran+off+12, szextaddr, extaddrlen) == 0)
355 if (dstact == DSTACT_STRIP || (dstact == DSTACT_AUTO && !is_stun))
357 uint origoff_des = 0;
358 uint origlen_des = 0;
360 origoff_des = (ptran-ptcp)+off;//original destination ip offset
362 origlen_des = (nextfieldoff-off)-1;//original destination ip length
364 origlen_des = (nextfieldoff-origoff_des)-2;
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))
373 /* mangle failed, all we can do is bail */
374 DEBUGP("mangle failed bailing out now\n");
377 get_skb_tcpdata(*pskb, &ptcp, &tcplen);
378 ptran = ptcp+tranoff;
380 nextparamoff -= diff;
381 nextfieldoff -= diff;
392 while (off < nextparamoff)
394 const char* pfieldend;
397 pfieldend = rtsp_nat_find_char(ptran+off, ';', nextparamoff-off);
398 nextfieldoff = (pfieldend == NULL) ? nextparamoff : pfieldend-ptran+1;
400 DEBUGP("off %d nextparamoff %d %s\n", off, nextparamoff, ptran+off);
401 if (strncmp(ptran+off, "client_port=", 12) == 0)
408 uint rbuflen = rbuf1len;
411 origoff = (ptran-ptcp)+off;
413 numlen = nf_strtou16(ptran+off, &port);
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] == '/')
422 numlen = nf_strtou16(ptran+off, &port);
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.
434 * parameter 4 below is offset from start of tcp data.
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))
441 /* mangle failed, all we can do is bail */
442 DEBUGP("MANGLE Failed\n");
445 get_skb_tcpdata(*pskb, &ptcp, &tcplen);
446 ptran = ptcp+tranoff;
448 nextparamoff -= diff;
449 nextfieldoff -= diff;
450 DEBUGP("After mangle nextparamoff %d nextfieldoff %d ptran %s\n",
451 nextparamoff, nextfieldoff, ptran);
464 expected(struct sk_buff** pskb, uint hooknum,
465 struct ip_conntrack* ct, struct ip_nat_info* info)
467 struct ip_nat_multi_range mr;
468 u_int32_t newdstip, newsrcip, newip;
470 struct ip_conntrack *master = master_ct(ct);
472 IP_NF_ASSERT(master);
474 IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum))));
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;
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);
489 * We don't want to manip the per-protocol, just the IPs. Actually we
490 * did manipulate the UDP ports
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);
500 help_out(struct ip_conntrack* ct, enum ip_conntrack_info ctinfo,
501 struct ip_conntrack_expect* exp, struct sk_buff** pskb)
511 struct iphdr* iph = (struct iphdr*)(*pskb)->nh.iph;
512 struct tcphdr* tcph = (struct tcphdr*)((void*)iph + iph->ihl*4);
514 struct ip_ct_rtsp_expect* prtspexp = &exp->help.exp_rtsp_info;
516 get_skb_tcpdata(*pskb, &ptcp, &tcplen);
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;
525 if ((exp->seq - ntohl(tcph->seq)) != tcplen - prtspexp->len){
526 //printk("is wan to lan expenation\n");
531 DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
532 DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
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,
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))
546 if (off > hdrsoff+hdrslen)
548 INFOP("!! overrun !!\n");
551 DEBUGP("hdr: len=%u, %.*s", linelen, (int)linelen, ptcp+lineoff);
553 if (nf_strncasecmp(ptcp+lineoff, "Transport:", 10) == 0)
555 uint oldtcplen = tcplen;
556 if (!rtsp_mangle_tran(ct, ctinfo, exp, pskb, lineoff, linelen))
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);
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);
575 help_in(struct ip_conntrack* ct, enum ip_conntrack_info ctinfo,
576 struct ip_conntrack_expect* exp, struct sk_buff** pskb)
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;
587 uint mangle_hdrsoff=0;
588 uint mangle_hdrslen=0;
591 DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
592 DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
595 if (prtspexp->cseq == 0)
597 /* Not whole TCP header? */
598 if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &tcph, sizeof(tcph)) != 0){
602 dataoff = skb->nh.iph->ihl*4 + tcph.doff*4;
603 if ( skb->nh.iph->ihl*4 + tcph.doff*4 >= skb->len)
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);
611 mangle_hdrsoff = dataoff;
612 mangle_hdrslen = datalen;
613 mangle_off = mangle_hdrsoff;
615 while (dataoff < datalen){
616 uint cmdoff = dataoff;
625 if (!rtsp_parse_message(ptcp, datalen, &dataoff,
627 &cseqoff, &cseqlen)){
628 break; /* not a valid message */
630 if (strncmp(ptcp+cmdoff, "RTSP/1.0 200 OK", 15) != 0)
632 continue; /* not a RTSP/1.0 200 OK message */
634 //printk("found a RTSP/1.0 200 OK message\n");
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)){
646 if (off > hdrsoff+hdrslen){
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");
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);
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);
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)
697 struct iphdr* iph = (struct iphdr*)(*pskb)->nh.iph;
698 struct tcphdr* tcph = (struct tcphdr*)((char*)iph + iph->ihl * 4);
701 struct ip_ct_rtsp_expect* ct_rtsp_info;
704 if (ct == NULL || exp == NULL || info == NULL || pskb == NULL)
709 ct_rtsp_info = &exp->help.exp_rtsp_info;
712 * Only mangle things once: original direction in POST_ROUTING
713 * and reply direction on PRE_ROUTING.
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)))
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" : "???");
726 DEBUGP("got beyond not touching\n");
728 datalen = (*pskb)->len - iph->ihl * 4 - tcph->doff * 4;
729 LOCK_BH(&ip_rtsp_lock);
733 case IP_CT_DIR_ORIGINAL:
734 rc = help_out(ct, ctinfo, exp, pskb);
736 case IP_CT_DIR_REPLY:
737 rc = help_in(ct, ctinfo, exp, pskb);
743 UNLOCK_BH(&ip_rtsp_lock);
748 static struct ip_nat_helper ip_nat_rtsp_helpers[MAX_PORTS];
749 static char rtsp_names[MAX_PORTS][10];
751 /* This function is intentionally _NOT_ defined as __exit */
757 for (i = 0; i < num_ports; i++)
759 DEBUGP("unregistering helper for port %d\n", ports[i]);
760 ip_nat_helper_unregister(&ip_nat_rtsp_helpers[i]);
769 struct ip_nat_helper* hlpr;
772 printk("ip_nat_rtsp v" IP_NF_RTSP_VERSION " loading\n");
776 ports[0] = RTSP_PORT;
779 for (i = 0; (i < MAX_PORTS) && ports[i] != 0; i++)
781 hlpr = &ip_nat_rtsp_helpers[i];
782 memset(hlpr, 0, sizeof(struct ip_nat_helper));
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;
789 hlpr->flags = IP_NAT_HELPER_F_ALWAYS;
790 hlpr->me = THIS_MODULE;
791 hlpr->expect = expected;
793 tmpname = &rtsp_names[i][0];
794 if (ports[i] == RTSP_PORT)
796 sprintf(tmpname, "rtsp");
800 sprintf(tmpname, "rtsp-%d", i);
802 hlpr->name = tmpname;
804 DEBUGP("registering helper for port %d: name %s\n", ports[i], hlpr->name);
805 ret = ip_nat_helper_register(hlpr);
809 printk("ip_nat_rtsp: error registering helper for port %d\n", ports[i]);
815 if (stunaddr != NULL)
817 extip = in_aton(stunaddr);
819 if (destaction != NULL)
821 if (strcmp(destaction, "auto") == 0)
823 dstact = DSTACT_AUTO;
825 if (strcmp(destaction, "strip") == 0)
827 dstact = DSTACT_STRIP;
829 if (strcmp(destaction, "none") == 0)
831 dstact = DSTACT_NONE;
837 NEEDS_CONNTRACK(rtsp);