Root/target/linux/generic/patches-3.1/605-netfilter_rtsp.patch

1--- /dev/null
2+++ b/include/linux/netfilter/nf_conntrack_rtsp.h
3@@ -0,0 +1,63 @@
4+/*
5+ * RTSP extension for IP connection tracking.
6+ * (C) 2003 by Tom Marshall <tmarshall at real.com>
7+ * based on ip_conntrack_irc.h
8+ *
9+ * This program is free software; you can redistribute it and/or
10+ * modify it under the terms of the GNU General Public License
11+ * as published by the Free Software Foundation; either version
12+ * 2 of the License, or (at your option) any later version.
13+ */
14+#ifndef _IP_CONNTRACK_RTSP_H
15+#define _IP_CONNTRACK_RTSP_H
16+
17+//#define IP_NF_RTSP_DEBUG 1
18+#define IP_NF_RTSP_VERSION "0.6.21"
19+
20+#ifdef __KERNEL__
21+/* port block types */
22+typedef enum {
23+ pb_single, /* client_port=x */
24+ pb_range, /* client_port=x-y */
25+ pb_discon /* client_port=x/y (rtspbis) */
26+} portblock_t;
27+
28+/* We record seq number and length of rtsp headers here, all in host order. */
29+
30+/*
31+ * This structure is per expected connection. It is a member of struct
32+ * ip_conntrack_expect. The TCP SEQ for the conntrack expect is stored
33+ * there and we are expected to only store the length of the data which
34+ * needs replaced. If a packet contains multiple RTSP messages, we create
35+ * one expected connection per message.
36+ *
37+ * We use these variables to mark the entire header block. This may seem
38+ * like overkill, but the nature of RTSP requires it. A header may appear
39+ * multiple times in a message. We must treat two Transport headers the
40+ * same as one Transport header with two entries.
41+ */
42+struct ip_ct_rtsp_expect
43+{
44+ u_int32_t len; /* length of header block */
45+ portblock_t pbtype; /* Type of port block that was requested */
46+ u_int16_t loport; /* Port that was requested, low or first */
47+ u_int16_t hiport; /* Port that was requested, high or second */
48+#if 0
49+ uint method; /* RTSP method */
50+ uint cseq; /* CSeq from request */
51+#endif
52+};
53+
54+extern unsigned int (*nf_nat_rtsp_hook)(struct sk_buff *skb,
55+ enum ip_conntrack_info ctinfo,
56+ unsigned int matchoff, unsigned int matchlen,
57+ struct ip_ct_rtsp_expect *prtspexp,
58+ struct nf_conntrack_expect *exp);
59+
60+extern void (*nf_nat_rtsp_hook_expectfn)(struct nf_conn *ct, struct nf_conntrack_expect *exp);
61+
62+#define RTSP_PORT 554
63+
64+#endif /* __KERNEL__ */
65+
66+#endif /* _IP_CONNTRACK_RTSP_H */
67--- /dev/null
68+++ b/include/linux/netfilter_helpers.h
69@@ -0,0 +1,133 @@
70+/*
71+ * Helpers for netfiler modules. This file provides implementations for basic
72+ * functions such as strncasecmp(), etc.
73+ *
74+ * gcc will warn for defined but unused functions, so we only include the
75+ * functions requested. The following macros are used:
76+ * NF_NEED_STRNCASECMP nf_strncasecmp()
77+ * NF_NEED_STRTOU16 nf_strtou16()
78+ * NF_NEED_STRTOU32 nf_strtou32()
79+ */
80+#ifndef _NETFILTER_HELPERS_H
81+#define _NETFILTER_HELPERS_H
82+
83+/* Only include these functions for kernel code. */
84+#ifdef __KERNEL__
85+
86+#include <linux/ctype.h>
87+#define iseol(c) ( (c) == '\r' || (c) == '\n' )
88+
89+/*
90+ * The standard strncasecmp()
91+ */
92+#ifdef NF_NEED_STRNCASECMP
93+static int
94+nf_strncasecmp(const char* s1, const char* s2, u_int32_t len)
95+{
96+ if (s1 == NULL || s2 == NULL)
97+ {
98+ if (s1 == NULL && s2 == NULL)
99+ {
100+ return 0;
101+ }
102+ return (s1 == NULL) ? -1 : 1;
103+ }
104+ while (len > 0 && tolower(*s1) == tolower(*s2))
105+ {
106+ len--;
107+ s1++;
108+ s2++;
109+ }
110+ return ( (len == 0) ? 0 : (tolower(*s1) - tolower(*s2)) );
111+}
112+#endif /* NF_NEED_STRNCASECMP */
113+
114+/*
115+ * Parse a string containing a 16-bit unsigned integer.
116+ * Returns the number of chars used, or zero if no number is found.
117+ */
118+#ifdef NF_NEED_STRTOU16
119+static int
120+nf_strtou16(const char* pbuf, u_int16_t* pval)
121+{
122+ int n = 0;
123+
124+ *pval = 0;
125+ while (isdigit(pbuf[n]))
126+ {
127+ *pval = (*pval * 10) + (pbuf[n] - '0');
128+ n++;
129+ }
130+
131+ return n;
132+}
133+#endif /* NF_NEED_STRTOU16 */
134+
135+/*
136+ * Parse a string containing a 32-bit unsigned integer.
137+ * Returns the number of chars used, or zero if no number is found.
138+ */
139+#ifdef NF_NEED_STRTOU32
140+static int
141+nf_strtou32(const char* pbuf, u_int32_t* pval)
142+{
143+ int n = 0;
144+
145+ *pval = 0;
146+ while (pbuf[n] >= '0' && pbuf[n] <= '9')
147+ {
148+ *pval = (*pval * 10) + (pbuf[n] - '0');
149+ n++;
150+ }
151+
152+ return n;
153+}
154+#endif /* NF_NEED_STRTOU32 */
155+
156+/*
157+ * Given a buffer and length, advance to the next line and mark the current
158+ * line.
159+ */
160+#ifdef NF_NEED_NEXTLINE
161+static int
162+nf_nextline(char* p, uint len, uint* poff, uint* plineoff, uint* plinelen)
163+{
164+ uint off = *poff;
165+ uint physlen = 0;
166+
167+ if (off >= len)
168+ {
169+ return 0;
170+ }
171+
172+ while (p[off] != '\n')
173+ {
174+ if (len-off <= 1)
175+ {
176+ return 0;
177+ }
178+
179+ physlen++;
180+ off++;
181+ }
182+
183+ /* if we saw a crlf, physlen needs adjusted */
184+ if (physlen > 0 && p[off] == '\n' && p[off-1] == '\r')
185+ {
186+ physlen--;
187+ }
188+
189+ /* advance past the newline */
190+ off++;
191+
192+ *plineoff = *poff;
193+ *plinelen = physlen;
194+ *poff = off;
195+
196+ return 1;
197+}
198+#endif /* NF_NEED_NEXTLINE */
199+
200+#endif /* __KERNEL__ */
201+
202+#endif /* _NETFILTER_HELPERS_H */
203--- /dev/null
204+++ b/include/linux/netfilter_mime.h
205@@ -0,0 +1,89 @@
206+/*
207+ * MIME functions for netfilter modules. This file provides implementations
208+ * for basic MIME parsing. MIME headers are used in many protocols, such as
209+ * HTTP, RTSP, SIP, etc.
210+ *
211+ * gcc will warn for defined but unused functions, so we only include the
212+ * functions requested. The following macros are used:
213+ * NF_NEED_MIME_NEXTLINE nf_mime_nextline()
214+ */
215+#ifndef _NETFILTER_MIME_H
216+#define _NETFILTER_MIME_H
217+
218+/* Only include these functions for kernel code. */
219+#ifdef __KERNEL__
220+
221+#include <linux/ctype.h>
222+
223+/*
224+ * Given a buffer and length, advance to the next line and mark the current
225+ * line. If the current line is empty, *plinelen will be set to zero. If
226+ * not, it will be set to the actual line length (including CRLF).
227+ *
228+ * 'line' in this context means logical line (includes LWS continuations).
229+ * Returns 1 on success, 0 on failure.
230+ */
231+#ifdef NF_NEED_MIME_NEXTLINE
232+static int
233+nf_mime_nextline(char* p, uint len, uint* poff, uint* plineoff, uint* plinelen)
234+{
235+ uint off = *poff;
236+ uint physlen = 0;
237+ int is_first_line = 1;
238+
239+ if (off >= len)
240+ {
241+ return 0;
242+ }
243+
244+ do
245+ {
246+ while (p[off] != '\n')
247+ {
248+ if (len-off <= 1)
249+ {
250+ return 0;
251+ }
252+
253+ physlen++;
254+ off++;
255+ }
256+
257+ /* if we saw a crlf, physlen needs adjusted */
258+ if (physlen > 0 && p[off] == '\n' && p[off-1] == '\r')
259+ {
260+ physlen--;
261+ }
262+
263+ /* advance past the newline */
264+ off++;
265+
266+ /* check for an empty line */
267+ if (physlen == 0)
268+ {
269+ break;
270+ }
271+
272+ /* check for colon on the first physical line */
273+ if (is_first_line)
274+ {
275+ is_first_line = 0;
276+ if (memchr(p+(*poff), ':', physlen) == NULL)
277+ {
278+ return 0;
279+ }
280+ }
281+ }
282+ while (p[off] == ' ' || p[off] == '\t');
283+
284+ *plineoff = *poff;
285+ *plinelen = (physlen == 0) ? 0 : (off - *poff);
286+ *poff = off;
287+
288+ return 1;
289+}
290+#endif /* NF_NEED_MIME_NEXTLINE */
291+
292+#endif /* __KERNEL__ */
293+
294+#endif /* _NETFILTER_MIME_H */
295--- a/net/ipv4/netfilter/Makefile
296+++ b/net/ipv4/netfilter/Makefile
297@@ -26,6 +26,7 @@ obj-$(CONFIG_NF_NAT_AMANDA) += nf_nat_am
298 obj-$(CONFIG_NF_NAT_FTP) += nf_nat_ftp.o
299 obj-$(CONFIG_NF_NAT_H323) += nf_nat_h323.o
300 obj-$(CONFIG_NF_NAT_IRC) += nf_nat_irc.o
301+obj-$(CONFIG_NF_NAT_RTSP) += nf_nat_rtsp.o
302 obj-$(CONFIG_NF_NAT_PPTP) += nf_nat_pptp.o
303 obj-$(CONFIG_NF_NAT_SIP) += nf_nat_sip.o
304 obj-$(CONFIG_NF_NAT_SNMP_BASIC) += nf_nat_snmp_basic.o
305--- a/net/netfilter/Kconfig
306+++ b/net/netfilter/Kconfig
307@@ -289,6 +289,16 @@ config NF_CONNTRACK_TFTP
308 
309       To compile it as a module, choose M here. If unsure, say N.
310 
311+config NF_CONNTRACK_RTSP
312+ tristate "RTSP protocol support"
313+ depends on NF_CONNTRACK
314+ help
315+ Support the RTSP protocol. This allows UDP transports to be setup
316+ properly, including RTP and RDT.
317+
318+ If you want to compile it as a module, say 'M' here and read
319+ Documentation/modules.txt. If unsure, say 'Y'.
320+
321 config NF_CT_NETLINK
322     tristate 'Connection tracking netlink interface'
323     select NETFILTER_NETLINK
324--- a/net/netfilter/Makefile
325+++ b/net/netfilter/Makefile
326@@ -36,6 +36,7 @@ obj-$(CONFIG_NF_CONNTRACK_PPTP) += nf_co
327 obj-$(CONFIG_NF_CONNTRACK_SANE) += nf_conntrack_sane.o
328 obj-$(CONFIG_NF_CONNTRACK_SIP) += nf_conntrack_sip.o
329 obj-$(CONFIG_NF_CONNTRACK_TFTP) += nf_conntrack_tftp.o
330+obj-$(CONFIG_NF_CONNTRACK_RTSP) += nf_conntrack_rtsp.o
331 
332 # transparent proxy support
333 obj-$(CONFIG_NETFILTER_TPROXY) += nf_tproxy_core.o
334--- a/net/ipv4/netfilter/Kconfig
335+++ b/net/ipv4/netfilter/Kconfig
336@@ -248,6 +248,11 @@ config NF_NAT_IRC
337     depends on NF_CONNTRACK && NF_NAT
338     default NF_NAT && NF_CONNTRACK_IRC
339 
340+config NF_NAT_RTSP
341+ tristate
342+ depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT
343+ default NF_NAT && NF_CONNTRACK_RTSP
344+
345 config NF_NAT_TFTP
346     tristate
347     depends on NF_CONNTRACK && NF_NAT
348--- /dev/null
349+++ b/net/netfilter/nf_conntrack_rtsp.c
350@@ -0,0 +1,517 @@
351+/*
352+ * RTSP extension for IP connection tracking
353+ * (C) 2003 by Tom Marshall <tmarshall at real.com>
354+ * based on ip_conntrack_irc.c
355+ *
356+ * This program is free software; you can redistribute it and/or
357+ * modify it under the terms of the GNU General Public License
358+ * as published by the Free Software Foundation; either version
359+ * 2 of the License, or (at your option) any later version.
360+ *
361+ * Module load syntax:
362+ * insmod nf_conntrack_rtsp.o ports=port1,port2,...port<MAX_PORTS>
363+ * max_outstanding=n setup_timeout=secs
364+ *
365+ * If no ports are specified, the default will be port 554.
366+ *
367+ * With max_outstanding you can define the maximum number of not yet
368+ * answered SETUP requests per RTSP session (default 8).
369+ * With setup_timeout you can specify how long the system waits for
370+ * an expected data channel (default 300 seconds).
371+ *
372+ * 2005-02-13: Harald Welte <laforge at netfilter.org>
373+ * - port to 2.6
374+ * - update to recent post-2.6.11 api changes
375+ * 2006-09-14: Steven Van Acker <deepstar at singularity.be>
376+ * - removed calls to NAT code from conntrack helper: NAT no longer needed to use rtsp-conntrack
377+ * 2007-04-18: Michael Guntsche <mike at it-loops.com>
378+ * - Port to new NF API
379+ */
380+
381+#include <linux/module.h>
382+#include <linux/netfilter.h>
383+#include <linux/ip.h>
384+#include <linux/inet.h>
385+#include <net/tcp.h>
386+
387+#include <net/netfilter/nf_conntrack.h>
388+#include <net/netfilter/nf_conntrack_expect.h>
389+#include <net/netfilter/nf_conntrack_helper.h>
390+#include <linux/netfilter/nf_conntrack_rtsp.h>
391+
392+#define NF_NEED_STRNCASECMP
393+#define NF_NEED_STRTOU16
394+#define NF_NEED_STRTOU32
395+#define NF_NEED_NEXTLINE
396+#include <linux/netfilter_helpers.h>
397+#define NF_NEED_MIME_NEXTLINE
398+#include <linux/netfilter_mime.h>
399+
400+#include <linux/ctype.h>
401+#define MAX_SIMUL_SETUP 8 /* XXX: use max_outstanding */
402+#define INFOP(fmt, args...) printk(KERN_INFO "%s: %s: " fmt, __FILE__, __FUNCTION__ , ## args)
403+#if 0
404+#define DEBUGP(fmt, args...) printk(KERN_DEBUG "%s: %s: " fmt, __FILE__, __FUNCTION__ , ## args)
405+#else
406+#define DEBUGP(fmt, args...)
407+#endif
408+
409+#define MAX_PORTS 8
410+static int ports[MAX_PORTS];
411+static int num_ports = 0;
412+static int max_outstanding = 8;
413+static unsigned int setup_timeout = 300;
414+
415+MODULE_AUTHOR("Tom Marshall <tmarshall at real.com>");
416+MODULE_DESCRIPTION("RTSP connection tracking module");
417+MODULE_LICENSE("GPL");
418+module_param_array(ports, int, &num_ports, 0400);
419+MODULE_PARM_DESC(ports, "port numbers of RTSP servers");
420+module_param(max_outstanding, int, 0400);
421+MODULE_PARM_DESC(max_outstanding, "max number of outstanding SETUP requests per RTSP session");
422+module_param(setup_timeout, int, 0400);
423+MODULE_PARM_DESC(setup_timeout, "timeout on for unestablished data channels");
424+
425+static char *rtsp_buffer;
426+static DEFINE_SPINLOCK(rtsp_buffer_lock);
427+
428+unsigned int (*nf_nat_rtsp_hook)(struct sk_buff *skb,
429+ enum ip_conntrack_info ctinfo,
430+ unsigned int matchoff, unsigned int matchlen,struct ip_ct_rtsp_expect* prtspexp,
431+ struct nf_conntrack_expect *exp);
432+void (*nf_nat_rtsp_hook_expectfn)(struct nf_conn *ct, struct nf_conntrack_expect *exp);
433+
434+EXPORT_SYMBOL_GPL(nf_nat_rtsp_hook);
435+
436+/*
437+ * Max mappings we will allow for one RTSP connection (for RTP, the number
438+ * of allocated ports is twice this value). Note that SMIL burns a lot of
439+ * ports so keep this reasonably high. If this is too low, you will see a
440+ * lot of "no free client map entries" messages.
441+ */
442+#define MAX_PORT_MAPS 16
443+
444+/*** default port list was here in the masq code: 554, 3030, 4040 ***/
445+
446+#define SKIP_WSPACE(ptr,len,off) while(off < len && isspace(*(ptr+off))) { off++; }
447+
448+/*
449+ * Parse an RTSP packet.
450+ *
451+ * Returns zero if parsing failed.
452+ *
453+ * Parameters:
454+ * IN ptcp tcp data pointer
455+ * IN tcplen tcp data len
456+ * IN/OUT ptcpoff points to current tcp offset
457+ * OUT phdrsoff set to offset of rtsp headers
458+ * OUT phdrslen set to length of rtsp headers
459+ * OUT pcseqoff set to offset of CSeq header
460+ * OUT pcseqlen set to length of CSeq header
461+ */
462+static int
463+rtsp_parse_message(char* ptcp, uint tcplen, uint* ptcpoff,
464+ uint* phdrsoff, uint* phdrslen,
465+ uint* pcseqoff, uint* pcseqlen,
466+ uint* transoff, uint* translen)
467+{
468+ uint entitylen = 0;
469+ uint lineoff;
470+ uint linelen;
471+
472+ if (!nf_nextline(ptcp, tcplen, ptcpoff, &lineoff, &linelen))
473+ return 0;
474+
475+ *phdrsoff = *ptcpoff;
476+ while (nf_mime_nextline(ptcp, tcplen, ptcpoff, &lineoff, &linelen)) {
477+ if (linelen == 0) {
478+ if (entitylen > 0)
479+ *ptcpoff += min(entitylen, tcplen - *ptcpoff);
480+ break;
481+ }
482+ if (lineoff+linelen > tcplen) {
483+ INFOP("!! overrun !!\n");
484+ break;
485+ }
486+
487+ if (nf_strncasecmp(ptcp+lineoff, "CSeq:", 5) == 0) {
488+ *pcseqoff = lineoff;
489+ *pcseqlen = linelen;
490+ }
491+
492+ if (nf_strncasecmp(ptcp+lineoff, "Transport:", 10) == 0) {
493+ *transoff = lineoff;
494+ *translen = linelen;
495+ }
496+
497+ if (nf_strncasecmp(ptcp+lineoff, "Content-Length:", 15) == 0) {
498+ uint off = lineoff+15;
499+ SKIP_WSPACE(ptcp+lineoff, linelen, off);
500+ nf_strtou32(ptcp+off, &entitylen);
501+ }
502+ }
503+ *phdrslen = (*ptcpoff) - (*phdrsoff);
504+
505+ return 1;
506+}
507+
508+/*
509+ * Find lo/hi client ports (if any) in transport header
510+ * In:
511+ * ptcp, tcplen = packet
512+ * tranoff, tranlen = buffer to search
513+ *
514+ * Out:
515+ * pport_lo, pport_hi = lo/hi ports (host endian)
516+ *
517+ * Returns nonzero if any client ports found
518+ *
519+ * Note: it is valid (and expected) for the client to request multiple
520+ * transports, so we need to parse the entire line.
521+ */
522+static int
523+rtsp_parse_transport(char* ptran, uint tranlen,
524+ struct ip_ct_rtsp_expect* prtspexp)
525+{
526+ int rc = 0;
527+ uint off = 0;
528+
529+ if (tranlen < 10 || !iseol(ptran[tranlen-1]) ||
530+ nf_strncasecmp(ptran, "Transport:", 10) != 0) {
531+ INFOP("sanity check failed\n");
532+ return 0;
533+ }
534+
535+ DEBUGP("tran='%.*s'\n", (int)tranlen, ptran);
536+ off += 10;
537+ SKIP_WSPACE(ptran, tranlen, off);
538+
539+ /* Transport: tran;field;field=val,tran;field;field=val,... */
540+ while (off < tranlen) {
541+ const char* pparamend;
542+ uint nextparamoff;
543+
544+ pparamend = memchr(ptran+off, ',', tranlen-off);
545+ pparamend = (pparamend == NULL) ? ptran+tranlen : pparamend+1;
546+ nextparamoff = pparamend-ptran;
547+
548+ while (off < nextparamoff) {
549+ const char* pfieldend;
550+ uint nextfieldoff;
551+
552+ pfieldend = memchr(ptran+off, ';', nextparamoff-off);
553+ nextfieldoff = (pfieldend == NULL) ? nextparamoff : pfieldend-ptran+1;
554+
555+ if (strncmp(ptran+off, "client_port=", 12) == 0) {
556+ u_int16_t port;
557+ uint numlen;
558+
559+ off += 12;
560+ numlen = nf_strtou16(ptran+off, &port);
561+ off += numlen;
562+ if (prtspexp->loport != 0 && prtspexp->loport != port)
563+ DEBUGP("multiple ports found, port %hu ignored\n", port);
564+ else {
565+ DEBUGP("lo port found : %hu\n", port);
566+ prtspexp->loport = prtspexp->hiport = port;
567+ if (ptran[off] == '-') {
568+ off++;
569+ numlen = nf_strtou16(ptran+off, &port);
570+ off += numlen;
571+ prtspexp->pbtype = pb_range;
572+ prtspexp->hiport = port;
573+
574+ // If we have a range, assume rtp:
575+ // loport must be even, hiport must be loport+1
576+ if ((prtspexp->loport & 0x0001) != 0 ||
577+ prtspexp->hiport != prtspexp->loport+1) {
578+ DEBUGP("incorrect range: %hu-%hu, correcting\n",
579+ prtspexp->loport, prtspexp->hiport);
580+ prtspexp->loport &= 0xfffe;
581+ prtspexp->hiport = prtspexp->loport+1;
582+ }
583+ } else if (ptran[off] == '/') {
584+ off++;
585+ numlen = nf_strtou16(ptran+off, &port);
586+ off += numlen;
587+ prtspexp->pbtype = pb_discon;
588+ prtspexp->hiport = port;
589+ }
590+ rc = 1;
591+ }
592+ }
593+
594+ /*
595+ * Note we don't look for the destination parameter here.
596+ * If we are using NAT, the NAT module will handle it. If not,
597+ * and the client is sending packets elsewhere, the expectation
598+ * will quietly time out.
599+ */
600+
601+ off = nextfieldoff;
602+ }
603+
604+ off = nextparamoff;
605+ }
606+
607+ return rc;
608+}
609+
610+void expected(struct nf_conn *ct, struct nf_conntrack_expect *exp)
611+{
612+ if(nf_nat_rtsp_hook_expectfn) {
613+ nf_nat_rtsp_hook_expectfn(ct,exp);
614+ }
615+}
616+
617+/*** conntrack functions ***/
618+
619+/* outbound packet: client->server */
620+
621+static inline int
622+help_out(struct sk_buff *skb, unsigned char *rb_ptr, unsigned int datalen,
623+ struct nf_conn *ct, enum ip_conntrack_info ctinfo)
624+{
625+ struct ip_ct_rtsp_expect expinfo;
626+
627+ int dir = CTINFO2DIR(ctinfo); /* = IP_CT_DIR_ORIGINAL */
628+ //struct tcphdr* tcph = (void*)iph + iph->ihl * 4;
629+ //uint tcplen = pktlen - iph->ihl * 4;
630+ char* pdata = rb_ptr;
631+ //uint datalen = tcplen - tcph->doff * 4;
632+ uint dataoff = 0;
633+ int ret = NF_ACCEPT;
634+
635+ struct nf_conntrack_expect *exp;
636+
637+ __be16 be_loport;
638+
639+ memset(&expinfo, 0, sizeof(expinfo));
640+
641+ while (dataoff < datalen) {
642+ uint cmdoff = dataoff;
643+ uint hdrsoff = 0;
644+ uint hdrslen = 0;
645+ uint cseqoff = 0;
646+ uint cseqlen = 0;
647+ uint transoff = 0;
648+ uint translen = 0;
649+ uint off;
650+
651+ if (!rtsp_parse_message(pdata, datalen, &dataoff,
652+ &hdrsoff, &hdrslen,
653+ &cseqoff, &cseqlen,
654+ &transoff, &translen))
655+ break; /* not a valid message */
656+
657+ if (strncmp(pdata+cmdoff, "SETUP ", 6) != 0)
658+ continue; /* not a SETUP message */
659+ DEBUGP("found a setup message\n");
660+
661+ off = 0;
662+ if(translen) {
663+ rtsp_parse_transport(pdata+transoff, translen, &expinfo);
664+ }
665+
666+ if (expinfo.loport == 0) {
667+ DEBUGP("no udp transports found\n");
668+ continue; /* no udp transports found */
669+ }
670+
671+ DEBUGP("udp transport found, ports=(%d,%hu,%hu)\n",
672+ (int)expinfo.pbtype, expinfo.loport, expinfo.hiport);
673+
674+ exp = nf_ct_expect_alloc(ct);
675+ if (!exp) {
676+ ret = NF_DROP;
677+ goto out;
678+ }
679+
680+ be_loport = htons(expinfo.loport);
681+
682+ nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT,
683+ ct->tuplehash[!dir].tuple.src.l3num,
684+ &ct->tuplehash[!dir].tuple.src.u3, &ct->tuplehash[!dir].tuple.dst.u3,
685+ IPPROTO_UDP, NULL, &be_loport);
686+
687+ exp->master = ct;
688+
689+ exp->expectfn = expected;
690+ exp->flags = 0;
691+
692+ if (expinfo.pbtype == pb_range) {
693+ DEBUGP("Changing expectation mask to handle multiple ports\n");
694+ exp->mask.src.u.udp.port = 0xfffe;
695+ }
696+
697+ DEBUGP("expect_related %u.%u.%u.%u:%u-%u.%u.%u.%u:%u\n",
698+ NIPQUAD(exp->tuple.src.u3.ip),
699+ ntohs(exp->tuple.src.u.udp.port),
700+ NIPQUAD(exp->tuple.dst.u3.ip),
701+ ntohs(exp->tuple.dst.u.udp.port));
702+
703+ if (nf_nat_rtsp_hook)
704+ /* pass the request off to the nat helper */
705+ ret = nf_nat_rtsp_hook(skb, ctinfo, hdrsoff, hdrslen, &expinfo, exp);
706+ else if (nf_ct_expect_related(exp) != 0) {
707+ INFOP("nf_ct_expect_related failed\n");
708+ ret = NF_DROP;
709+ }
710+ nf_ct_expect_put(exp);
711+ goto out;
712+ }
713+out:
714+
715+ return ret;
716+}
717+
718+
719+static inline int
720+help_in(struct sk_buff *skb, size_t pktlen,
721+ struct nf_conn* ct, enum ip_conntrack_info ctinfo)
722+{
723+ return NF_ACCEPT;
724+}
725+
726+static int help(struct sk_buff *skb, unsigned int protoff,
727+ struct nf_conn *ct, enum ip_conntrack_info ctinfo)
728+{
729+ struct tcphdr _tcph, *th;
730+ unsigned int dataoff, datalen;
731+ char *rb_ptr;
732+ int ret = NF_DROP;
733+
734+ /* Until there's been traffic both ways, don't look in packets. */
735+ if (ctinfo != IP_CT_ESTABLISHED &&
736+ ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) {
737+ DEBUGP("conntrackinfo = %u\n", ctinfo);
738+ return NF_ACCEPT;
739+ }
740+
741+ /* Not whole TCP header? */
742+ th = skb_header_pointer(skb, protoff, sizeof(_tcph), &_tcph);
743+
744+ if (!th)
745+ return NF_ACCEPT;
746+
747+ /* No data ? */
748+ dataoff = protoff + th->doff*4;
749+ datalen = skb->len - dataoff;
750+ if (dataoff >= skb->len)
751+ return NF_ACCEPT;
752+
753+ spin_lock_bh(&rtsp_buffer_lock);
754+ rb_ptr = skb_header_pointer(skb, dataoff,
755+ skb->len - dataoff, rtsp_buffer);
756+ BUG_ON(rb_ptr == NULL);
757+
758+#if 0
759+ /* Checksum invalid? Ignore. */
760+ /* FIXME: Source route IP option packets --RR */
761+ if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr,
762+ csum_partial((char*)tcph, tcplen, 0)))
763+ {
764+ DEBUGP("bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n",
765+ tcph, tcplen, NIPQUAD(iph->saddr), NIPQUAD(iph->daddr));
766+ return NF_ACCEPT;
767+ }
768+#endif
769+
770+ switch (CTINFO2DIR(ctinfo)) {
771+ case IP_CT_DIR_ORIGINAL:
772+ ret = help_out(skb, rb_ptr, datalen, ct, ctinfo);
773+ break;
774+ case IP_CT_DIR_REPLY:
775+ DEBUGP("IP_CT_DIR_REPLY\n");
776+ /* inbound packet: server->client */
777+ ret = NF_ACCEPT;
778+ break;
779+ }
780+
781+ spin_unlock_bh(&rtsp_buffer_lock);
782+
783+ return ret;
784+}
785+
786+static struct nf_conntrack_helper rtsp_helpers[MAX_PORTS];
787+static char rtsp_names[MAX_PORTS][10];
788+static struct nf_conntrack_expect_policy rtsp_expect_policy;
789+
790+/* This function is intentionally _NOT_ defined as __exit */
791+static void
792+fini(void)
793+{
794+ int i;
795+ for (i = 0; i < num_ports; i++) {
796+ DEBUGP("unregistering port %d\n", ports[i]);
797+ nf_conntrack_helper_unregister(&rtsp_helpers[i]);
798+ }
799+ kfree(rtsp_buffer);
800+}
801+
802+static int __init
803+init(void)
804+{
805+ int i, ret;
806+ struct nf_conntrack_helper *hlpr;
807+ char *tmpname;
808+
809+ printk("nf_conntrack_rtsp v" IP_NF_RTSP_VERSION " loading\n");
810+
811+ if (max_outstanding < 1) {
812+ printk("nf_conntrack_rtsp: max_outstanding must be a positive integer\n");
813+ return -EBUSY;
814+ }
815+ if (setup_timeout < 0) {
816+ printk("nf_conntrack_rtsp: setup_timeout must be a positive integer\n");
817+ return -EBUSY;
818+ }
819+
820+ rtsp_expect_policy.max_expected = max_outstanding;
821+ rtsp_expect_policy.timeout = setup_timeout;
822+
823+ rtsp_buffer = kmalloc(65536, GFP_KERNEL);
824+ if (!rtsp_buffer)
825+ return -ENOMEM;
826+
827+ /* If no port given, default to standard rtsp port */
828+ if (ports[0] == 0) {
829+ ports[0] = RTSP_PORT;
830+ }
831+
832+ for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
833+ hlpr = &rtsp_helpers[i];
834+ memset(hlpr, 0, sizeof(struct nf_conntrack_helper));
835+ hlpr->tuple.src.u.tcp.port = htons(ports[i]);
836+ hlpr->tuple.dst.protonum = IPPROTO_TCP;
837+ hlpr->expect_policy = &rtsp_expect_policy;
838+ hlpr->me = THIS_MODULE;
839+ hlpr->help = help;
840+
841+ tmpname = &rtsp_names[i][0];
842+ if (ports[i] == RTSP_PORT) {
843+ sprintf(tmpname, "rtsp");
844+ } else {
845+ sprintf(tmpname, "rtsp-%d", i);
846+ }
847+ hlpr->name = tmpname;
848+
849+ DEBUGP("port #%d: %d\n", i, ports[i]);
850+
851+ ret = nf_conntrack_helper_register(hlpr);
852+
853+ if (ret) {
854+ printk("nf_conntrack_rtsp: ERROR registering port %d\n", ports[i]);
855+ fini();
856+ return -EBUSY;
857+ }
858+ num_ports++;
859+ }
860+ return 0;
861+}
862+
863+module_init(init);
864+module_exit(fini);
865+
866+EXPORT_SYMBOL(nf_nat_rtsp_hook_expectfn);
867+
868--- /dev/null
869+++ b/net/ipv4/netfilter/nf_nat_rtsp.c
870@@ -0,0 +1,496 @@
871+/*
872+ * RTSP extension for TCP NAT alteration
873+ * (C) 2003 by Tom Marshall <tmarshall at real.com>
874+ * based on ip_nat_irc.c
875+ *
876+ * This program is free software; you can redistribute it and/or
877+ * modify it under the terms of the GNU General Public License
878+ * as published by the Free Software Foundation; either version
879+ * 2 of the License, or (at your option) any later version.
880+ *
881+ * Module load syntax:
882+ * insmod nf_nat_rtsp.o ports=port1,port2,...port<MAX_PORTS>
883+ * stunaddr=<address>
884+ * destaction=[auto|strip|none]
885+ *
886+ * If no ports are specified, the default will be port 554 only.
887+ *
888+ * stunaddr specifies the address used to detect that a client is using STUN.
889+ * If this address is seen in the destination parameter, it is assumed that
890+ * the client has already punched a UDP hole in the firewall, so we don't
891+ * mangle the client_port. If none is specified, it is autodetected. It
892+ * only needs to be set if you have multiple levels of NAT. It should be
893+ * set to the external address that the STUN clients detect. Note that in
894+ * this case, it will not be possible for clients to use UDP with servers
895+ * between the NATs.
896+ *
897+ * If no destaction is specified, auto is used.
898+ * destaction=auto: strip destination parameter if it is not stunaddr.
899+ * destaction=strip: always strip destination parameter (not recommended).
900+ * destaction=none: do not touch destination parameter (not recommended).
901+ */
902+
903+#include <linux/module.h>
904+#include <net/tcp.h>
905+#include <net/netfilter/nf_nat_helper.h>
906+#include <net/netfilter/nf_nat_rule.h>
907+#include <linux/netfilter/nf_conntrack_rtsp.h>
908+#include <net/netfilter/nf_conntrack_expect.h>
909+
910+#include <linux/inet.h>
911+#include <linux/ctype.h>
912+#define NF_NEED_STRNCASECMP
913+#define NF_NEED_STRTOU16
914+#include <linux/netfilter_helpers.h>
915+#define NF_NEED_MIME_NEXTLINE
916+#include <linux/netfilter_mime.h>
917+
918+#define INFOP(fmt, args...) printk(KERN_INFO "%s: %s: " fmt, __FILE__, __FUNCTION__ , ## args)
919+#if 0
920+#define DEBUGP(fmt, args...) printk(KERN_DEBUG "%s: %s: " fmt, __FILE__, __FUNCTION__ , ## args)
921+#else
922+#define DEBUGP(fmt, args...)
923+#endif
924+
925+#define MAX_PORTS 8
926+#define DSTACT_AUTO 0
927+#define DSTACT_STRIP 1
928+#define DSTACT_NONE 2
929+
930+static char* stunaddr = NULL;
931+static char* destaction = NULL;
932+
933+static u_int32_t extip = 0;
934+static int dstact = 0;
935+
936+MODULE_AUTHOR("Tom Marshall <tmarshall at real.com>");
937+MODULE_DESCRIPTION("RTSP network address translation module");
938+MODULE_LICENSE("GPL");
939+module_param(stunaddr, charp, 0644);
940+MODULE_PARM_DESC(stunaddr, "Address for detecting STUN");
941+module_param(destaction, charp, 0644);
942+MODULE_PARM_DESC(destaction, "Action for destination parameter (auto/strip/none)");
943+
944+#define SKIP_WSPACE(ptr,len,off) while(off < len && isspace(*(ptr+off))) { off++; }
945+
946+/*** helper functions ***/
947+
948+static void
949+get_skb_tcpdata(struct sk_buff* skb, char** pptcpdata, uint* ptcpdatalen)
950+{
951+ struct iphdr* iph = ip_hdr(skb);
952+ struct tcphdr* tcph = (void *)iph + ip_hdrlen(skb);
953+
954+ *pptcpdata = (char*)tcph + tcph->doff*4;
955+ *ptcpdatalen = ((char*)skb_transport_header(skb) + skb->len) - *pptcpdata;
956+}
957+
958+/*** nat functions ***/
959+
960+/*
961+ * Mangle the "Transport:" header:
962+ * - Replace all occurences of "client_port=<spec>"
963+ * - Handle destination parameter
964+ *
965+ * In:
966+ * ct, ctinfo = conntrack context
967+ * skb = packet
968+ * tranoff = Transport header offset from TCP data
969+ * tranlen = Transport header length (incl. CRLF)
970+ * rport_lo = replacement low port (host endian)
971+ * rport_hi = replacement high port (host endian)
972+ *
973+ * Returns packet size difference.
974+ *
975+ * Assumes that a complete transport header is present, ending with CR or LF
976+ */
977+static int
978+rtsp_mangle_tran(enum ip_conntrack_info ctinfo,
979+ struct nf_conntrack_expect* exp,
980+ struct ip_ct_rtsp_expect* prtspexp,
981+ struct sk_buff* skb, uint tranoff, uint tranlen)
982+{
983+ char* ptcp;
984+ uint tcplen;
985+ char* ptran;
986+ char rbuf1[16]; /* Replacement buffer (one port) */
987+ uint rbuf1len; /* Replacement len (one port) */
988+ char rbufa[16]; /* Replacement buffer (all ports) */
989+ uint rbufalen; /* Replacement len (all ports) */
990+ u_int32_t newip;
991+ u_int16_t loport, hiport;
992+ uint off = 0;
993+ uint diff; /* Number of bytes we removed */
994+
995+ struct nf_conn *ct = exp->master;
996+ struct nf_conntrack_tuple *t;
997+
998+ char szextaddr[15+1];
999+ uint extaddrlen;
1000+ int is_stun;
1001+
1002+ get_skb_tcpdata(skb, &ptcp, &tcplen);
1003+ ptran = ptcp+tranoff;
1004+
1005+ if (tranoff+tranlen > tcplen || tcplen-tranoff < tranlen ||
1006+ tranlen < 10 || !iseol(ptran[tranlen-1]) ||
1007+ nf_strncasecmp(ptran, "Transport:", 10) != 0)
1008+ {
1009+ INFOP("sanity check failed\n");
1010+ return 0;
1011+ }
1012+ off += 10;
1013+ SKIP_WSPACE(ptcp+tranoff, tranlen, off);
1014+
1015+ newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip;
1016+ t = &exp->tuple;
1017+ t->dst.u3.ip = newip;
1018+
1019+ extaddrlen = extip ? sprintf(szextaddr, "%u.%u.%u.%u", &extip)
1020+ : sprintf(szextaddr, "%u.%u.%u.%u", &newip);
1021+ DEBUGP("stunaddr=%s (%s)\n", szextaddr, (extip?"forced":"auto"));
1022+
1023+ rbuf1len = rbufalen = 0;
1024+ switch (prtspexp->pbtype)
1025+ {
1026+ case pb_single:
1027+ for (loport = prtspexp->loport; loport != 0; loport++) /* XXX: improper wrap? */
1028+ {
1029+ t->dst.u.udp.port = htons(loport);
1030+ if (nf_ct_expect_related(exp) == 0)
1031+ {
1032+ DEBUGP("using port %hu\n", loport);
1033+ break;
1034+ }
1035+ }
1036+ if (loport != 0)
1037+ {
1038+ rbuf1len = sprintf(rbuf1, "%hu", loport);
1039+ rbufalen = sprintf(rbufa, "%hu", loport);
1040+ }
1041+ break;
1042+ case pb_range:
1043+ for (loport = prtspexp->loport; loport != 0; loport += 2) /* XXX: improper wrap? */
1044+ {
1045+ t->dst.u.udp.port = htons(loport);
1046+ if (nf_ct_expect_related(exp) == 0)
1047+ {
1048+ hiport = loport + ~exp->mask.src.u.udp.port;
1049+ DEBUGP("using ports %hu-%hu\n", loport, hiport);
1050+ break;
1051+ }
1052+ }
1053+ if (loport != 0)
1054+ {
1055+ rbuf1len = sprintf(rbuf1, "%hu", loport);
1056+ rbufalen = sprintf(rbufa, "%hu-%hu", loport, loport+1);
1057+ }
1058+ break;
1059+ case pb_discon:
1060+ for (loport = prtspexp->loport; loport != 0; loport++) /* XXX: improper wrap? */
1061+ {
1062+ t->dst.u.udp.port = htons(loport);
1063+ if (nf_ct_expect_related(exp) == 0)
1064+ {
1065+ DEBUGP("using port %hu (1 of 2)\n", loport);
1066+ break;
1067+ }
1068+ }
1069+ for (hiport = prtspexp->hiport; hiport != 0; hiport++) /* XXX: improper wrap? */
1070+ {
1071+ t->dst.u.udp.port = htons(hiport);
1072+ if (nf_ct_expect_related(exp) == 0)
1073+ {
1074+ DEBUGP("using port %hu (2 of 2)\n", hiport);
1075+ break;
1076+ }
1077+ }
1078+ if (loport != 0 && hiport != 0)
1079+ {
1080+ rbuf1len = sprintf(rbuf1, "%hu", loport);
1081+ if (hiport == loport+1)
1082+ {
1083+ rbufalen = sprintf(rbufa, "%hu-%hu", loport, hiport);
1084+ }
1085+ else
1086+ {
1087+ rbufalen = sprintf(rbufa, "%hu/%hu", loport, hiport);
1088+ }
1089+ }
1090+ break;
1091+ }
1092+
1093+ if (rbuf1len == 0)
1094+ {
1095+ return 0; /* cannot get replacement port(s) */
1096+ }
1097+
1098+ /* Transport: tran;field;field=val,tran;field;field=val,... */
1099+ while (off < tranlen)
1100+ {
1101+ uint saveoff;
1102+ const char* pparamend;
1103+ uint nextparamoff;
1104+
1105+ pparamend = memchr(ptran+off, ',', tranlen-off);
1106+ pparamend = (pparamend == NULL) ? ptran+tranlen : pparamend+1;
1107+ nextparamoff = pparamend-ptcp;
1108+
1109+ /*
1110+ * We pass over each param twice. On the first pass, we look for a
1111+ * destination= field. It is handled by the security policy. If it
1112+ * is present, allowed, and equal to our external address, we assume
1113+ * that STUN is being used and we leave the client_port= field alone.
1114+ */
1115+ is_stun = 0;
1116+ saveoff = off;
1117+ while (off < nextparamoff)
1118+ {
1119+ const char* pfieldend;
1120+ uint nextfieldoff;
1121+
1122+ pfieldend = memchr(ptran+off, ';', nextparamoff-off);
1123+ nextfieldoff = (pfieldend == NULL) ? nextparamoff : pfieldend-ptran+1;
1124+
1125+ if (dstact != DSTACT_NONE && strncmp(ptran+off, "destination=", 12) == 0)
1126+ {
1127+ if (strncmp(ptran+off+12, szextaddr, extaddrlen) == 0)
1128+ {
1129+ is_stun = 1;
1130+ }
1131+ if (dstact == DSTACT_STRIP || (dstact == DSTACT_AUTO && !is_stun))
1132+ {
1133+ diff = nextfieldoff-off;
1134+ if (!nf_nat_mangle_tcp_packet(skb, ct, ctinfo,
1135+ off, diff, NULL, 0))
1136+ {
1137+ /* mangle failed, all we can do is bail */
1138+ nf_ct_unexpect_related(exp);
1139+ return 0;
1140+ }
1141+ get_skb_tcpdata(skb, &ptcp, &tcplen);
1142+ ptran = ptcp+tranoff;
1143+ tranlen -= diff;
1144+ nextparamoff -= diff;
1145+ nextfieldoff -= diff;
1146+ }
1147+ }
1148+
1149+ off = nextfieldoff;
1150+ }
1151+ if (is_stun)
1152+ {
1153+ continue;
1154+ }
1155+ off = saveoff;
1156+ while (off < nextparamoff)
1157+ {
1158+ const char* pfieldend;
1159+ uint nextfieldoff;
1160+
1161+ pfieldend = memchr(ptran+off, ';', nextparamoff-off);
1162+ nextfieldoff = (pfieldend == NULL) ? nextparamoff : pfieldend-ptran+1;
1163+
1164+ if (strncmp(ptran+off, "client_port=", 12) == 0)
1165+ {
1166+ u_int16_t port;
1167+ uint numlen;
1168+ uint origoff;
1169+ uint origlen;
1170+ char* rbuf = rbuf1;
1171+ uint rbuflen = rbuf1len;
1172+
1173+ off += 12;
1174+ origoff = (ptran-ptcp)+off;
1175+ origlen = 0;
1176+ numlen = nf_strtou16(ptran+off, &port);
1177+ off += numlen;
1178+ origlen += numlen;
1179+ if (port != prtspexp->loport)
1180+ {
1181+ DEBUGP("multiple ports found, port %hu ignored\n", port);
1182+ }
1183+ else
1184+ {
1185+ if (ptran[off] == '-' || ptran[off] == '/')
1186+ {
1187+ off++;
1188+ origlen++;
1189+ numlen = nf_strtou16(ptran+off, &port);
1190+ off += numlen;
1191+ origlen += numlen;
1192+ rbuf = rbufa;
1193+ rbuflen = rbufalen;
1194+ }
1195+
1196+ /*
1197+ * note we cannot just memcpy() if the sizes are the same.
1198+ * the mangle function does skb resizing, checks for a
1199+ * cloned skb, and updates the checksums.
1200+ *
1201+ * parameter 4 below is offset from start of tcp data.
1202+ */
1203+ diff = origlen-rbuflen;
1204+ if (!nf_nat_mangle_tcp_packet(skb, ct, ctinfo,
1205+ origoff, origlen, rbuf, rbuflen))
1206+ {
1207+ /* mangle failed, all we can do is bail */
1208+ nf_ct_unexpect_related(exp);
1209+ return 0;
1210+ }
1211+ get_skb_tcpdata(skb, &ptcp, &tcplen);
1212+ ptran = ptcp+tranoff;
1213+ tranlen -= diff;
1214+ nextparamoff -= diff;
1215+ nextfieldoff -= diff;
1216+ }
1217+ }
1218+
1219+ off = nextfieldoff;
1220+ }
1221+
1222+ off = nextparamoff;
1223+ }
1224+
1225+ return 1;
1226+}
1227+
1228+static uint
1229+help_out(struct sk_buff *skb, enum ip_conntrack_info ctinfo,
1230+ unsigned int matchoff, unsigned int matchlen, struct ip_ct_rtsp_expect* prtspexp,
1231+ struct nf_conntrack_expect* exp)
1232+{
1233+ char* ptcp;
1234+ uint tcplen;
1235+ uint hdrsoff;
1236+ uint hdrslen;
1237+ uint lineoff;
1238+ uint linelen;
1239+ uint off;
1240+
1241+ //struct iphdr* iph = (struct iphdr*)skb->nh.iph;
1242+ //struct tcphdr* tcph = (struct tcphdr*)((void*)iph + iph->ihl*4);
1243+
1244+ get_skb_tcpdata(skb, &ptcp, &tcplen);
1245+ hdrsoff = matchoff;//exp->seq - ntohl(tcph->seq);
1246+ hdrslen = matchlen;
1247+ off = hdrsoff;
1248+ DEBUGP("NAT rtsp help_out\n");
1249+
1250+ while (nf_mime_nextline(ptcp, hdrsoff+hdrslen, &off, &lineoff, &linelen))
1251+ {
1252+ if (linelen == 0)
1253+ {
1254+ break;
1255+ }
1256+ if (off > hdrsoff+hdrslen)
1257+ {
1258+ INFOP("!! overrun !!");
1259+ break;
1260+ }
1261+ DEBUGP("hdr: len=%u, %.*s", linelen, (int)linelen, ptcp+lineoff);
1262+
1263+ if (nf_strncasecmp(ptcp+lineoff, "Transport:", 10) == 0)
1264+ {
1265+ uint oldtcplen = tcplen;
1266+ DEBUGP("hdr: Transport\n");
1267+ if (!rtsp_mangle_tran(ctinfo, exp, prtspexp, skb, lineoff, linelen))
1268+ {
1269+ DEBUGP("hdr: Transport mangle failed");
1270+ break;
1271+ }
1272+ get_skb_tcpdata(skb, &ptcp, &tcplen);
1273+ hdrslen -= (oldtcplen-tcplen);
1274+ off -= (oldtcplen-tcplen);
1275+ lineoff -= (oldtcplen-tcplen);
1276+ linelen -= (oldtcplen-tcplen);
1277+ DEBUGP("rep: len=%u, %.*s", linelen, (int)linelen, ptcp+lineoff);
1278+ }
1279+ }
1280+
1281+ return NF_ACCEPT;
1282+}
1283+
1284+static unsigned int
1285+help(struct sk_buff *skb, enum ip_conntrack_info ctinfo,
1286+ unsigned int matchoff, unsigned int matchlen, struct ip_ct_rtsp_expect* prtspexp,
1287+ struct nf_conntrack_expect* exp)
1288+{
1289+ int dir = CTINFO2DIR(ctinfo);
1290+ int rc = NF_ACCEPT;
1291+
1292+ switch (dir)
1293+ {
1294+ case IP_CT_DIR_ORIGINAL:
1295+ rc = help_out(skb, ctinfo, matchoff, matchlen, prtspexp, exp);
1296+ break;
1297+ case IP_CT_DIR_REPLY:
1298+ DEBUGP("unmangle ! %u\n", ctinfo);
1299+ /* XXX: unmangle */
1300+ rc = NF_ACCEPT;
1301+ break;
1302+ }
1303+ //UNLOCK_BH(&ip_rtsp_lock);
1304+
1305+ return rc;
1306+}
1307+
1308+static void expected(struct nf_conn* ct, struct nf_conntrack_expect *exp)
1309+{
1310+ struct nf_nat_multi_range_compat mr;
1311+ u_int32_t newdstip, newsrcip, newip;
1312+
1313+ struct nf_conn *master = ct->master;
1314+
1315+ newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip;
1316+ newsrcip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip;
1317+ //FIXME (how to port that ?)
1318+ //code from 2.4 : newip = (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC) ? newsrcip : newdstip;
1319+ newip = newdstip;
1320+
1321+ DEBUGP("newsrcip=%u.%u.%u.%u, newdstip=%u.%u.%u.%u, newip=%u.%u.%u.%u\n",
1322+ &newsrcip, &newdstip, &newip);
1323+
1324+ mr.rangesize = 1;
1325+ // We don't want to manip the per-protocol, just the IPs.
1326+ mr.range[0].flags = IP_NAT_RANGE_MAP_IPS;
1327+ mr.range[0].min_ip = mr.range[0].max_ip = newip;
1328+
1329+ nf_nat_setup_info(ct, &mr.range[0], IP_NAT_MANIP_DST);
1330+}
1331+
1332+
1333+static void __exit fini(void)
1334+{
1335+ nf_nat_rtsp_hook = NULL;
1336+ nf_nat_rtsp_hook_expectfn = NULL;
1337+ synchronize_net();
1338+}
1339+
1340+static int __init init(void)
1341+{
1342+ printk("nf_nat_rtsp v" IP_NF_RTSP_VERSION " loading\n");
1343+
1344+ BUG_ON(nf_nat_rtsp_hook);
1345+ nf_nat_rtsp_hook = help;
1346+ nf_nat_rtsp_hook_expectfn = &expected;
1347+
1348+ if (stunaddr != NULL)
1349+ extip = in_aton(stunaddr);
1350+
1351+ if (destaction != NULL) {
1352+ if (strcmp(destaction, "auto") == 0)
1353+ dstact = DSTACT_AUTO;
1354+
1355+ if (strcmp(destaction, "strip") == 0)
1356+ dstact = DSTACT_STRIP;
1357+
1358+ if (strcmp(destaction, "none") == 0)
1359+ dstact = DSTACT_NONE;
1360+ }
1361+
1362+ return 0;
1363+}
1364+
1365+module_init(init);
1366+module_exit(fini);
1367

Archive Download this file



interactive