1 diff -NurpP --minimal linux-2.6.19-pom-ng/include/linux/netfilter_helpers.h linux-2.6.19/include/linux/netfilter_helpers.h
2 --- linux-2.6.19-pom-ng/include/linux/netfilter_helpers.h 1970-01-01 01:00:00.000000000 +0100
3 +++ linux-2.6.19/include/linux/netfilter_helpers.h 2006-12-14 11:39:01.000000000 +0100
6 + * Helpers for netfiler modules. This file provides implementations for basic
7 + * functions such as strncasecmp(), etc.
9 + * gcc will warn for defined but unused functions, so we only include the
10 + * functions requested. The following macros are used:
11 + * NF_NEED_STRNCASECMP nf_strncasecmp()
12 + * NF_NEED_STRTOU16 nf_strtou16()
13 + * NF_NEED_STRTOU32 nf_strtou32()
15 +#ifndef _NETFILTER_HELPERS_H
16 +#define _NETFILTER_HELPERS_H
18 +/* Only include these functions for kernel code. */
21 +#include <linux/ctype.h>
22 +#define iseol(c) ( (c) == '\r' || (c) == '\n' )
25 + * The standard strncasecmp()
27 +#ifdef NF_NEED_STRNCASECMP
29 +nf_strncasecmp(const char* s1, const char* s2, u_int32_t len)
31 + if (s1 == NULL || s2 == NULL)
33 + if (s1 == NULL && s2 == NULL)
37 + return (s1 == NULL) ? -1 : 1;
39 + while (len > 0 && tolower(*s1) == tolower(*s2))
45 + return ( (len == 0) ? 0 : (tolower(*s1) - tolower(*s2)) );
47 +#endif /* NF_NEED_STRNCASECMP */
50 + * Parse a string containing a 16-bit unsigned integer.
51 + * Returns the number of chars used, or zero if no number is found.
53 +#ifdef NF_NEED_STRTOU16
55 +nf_strtou16(const char* pbuf, u_int16_t* pval)
60 + while (isdigit(pbuf[n]))
62 + *pval = (*pval * 10) + (pbuf[n] - '0');
68 +#endif /* NF_NEED_STRTOU16 */
71 + * Parse a string containing a 32-bit unsigned integer.
72 + * Returns the number of chars used, or zero if no number is found.
74 +#ifdef NF_NEED_STRTOU32
76 +nf_strtou32(const char* pbuf, u_int32_t* pval)
81 + while (pbuf[n] >= '0' && pbuf[n] <= '9')
83 + *pval = (*pval * 10) + (pbuf[n] - '0');
89 +#endif /* NF_NEED_STRTOU32 */
92 + * Given a buffer and length, advance to the next line and mark the current
95 +#ifdef NF_NEED_NEXTLINE
97 +nf_nextline(char* p, uint len, uint* poff, uint* plineoff, uint* plinelen)
107 + while (p[off] != '\n')
118 + /* if we saw a crlf, physlen needs adjusted */
119 + if (physlen > 0 && p[off] == '\n' && p[off-1] == '\r')
124 + /* advance past the newline */
128 + *plinelen = physlen;
133 +#endif /* NF_NEED_NEXTLINE */
135 +#endif /* __KERNEL__ */
137 +#endif /* _NETFILTER_HELPERS_H */
138 diff -NurpP --minimal linux-2.6.19-pom-ng/include/linux/netfilter_ipv4/ip_conntrack_rtsp.h linux-2.6.19/include/linux/netfilter_ipv4/ip_conntrack_rtsp.h
139 --- linux-2.6.19-pom-ng/include/linux/netfilter_ipv4/ip_conntrack_rtsp.h 1970-01-01 01:00:00.000000000 +0100
140 +++ linux-2.6.19/include/linux/netfilter_ipv4/ip_conntrack_rtsp.h 2006-12-14 11:39:01.000000000 +0100
143 + * RTSP extension for IP connection tracking.
144 + * (C) 2003 by Tom Marshall <tmarshall@real.com>
145 + * based on ip_conntrack_irc.h
147 + * This program is free software; you can redistribute it and/or
148 + * modify it under the terms of the GNU General Public License
149 + * as published by the Free Software Foundation; either version
150 + * 2 of the License, or (at your option) any later version.
152 +#ifndef _IP_CONNTRACK_RTSP_H
153 +#define _IP_CONNTRACK_RTSP_H
155 +/* #define IP_NF_RTSP_DEBUG */
156 +#define IP_NF_RTSP_VERSION "0.6.21"
158 +/* port block types */
160 + pb_single, /* client_port=x */
161 + pb_range, /* client_port=x-y */
162 + pb_discon /* client_port=x/y (rtspbis) */
165 +/* We record seq number and length of rtsp headers here, all in host order. */
168 + * This structure is per expected connection. It is a member of struct
169 + * ip_conntrack_expect. The TCP SEQ for the conntrack expect is stored
170 + * there and we are expected to only store the length of the data which
171 + * needs replaced. If a packet contains multiple RTSP messages, we create
172 + * one expected connection per message.
174 + * We use these variables to mark the entire header block. This may seem
175 + * like overkill, but the nature of RTSP requires it. A header may appear
176 + * multiple times in a message. We must treat two Transport headers the
177 + * same as one Transport header with two entries.
179 +struct ip_ct_rtsp_expect
181 + u_int32_t len; /* length of header block */
182 + portblock_t pbtype; /* Type of port block that was requested */
183 + u_int16_t loport; /* Port that was requested, low or first */
184 + u_int16_t hiport; /* Port that was requested, high or second */
186 + uint method; /* RTSP method */
187 + uint cseq; /* CSeq from request */
193 +#define RTSP_PORT 554
195 +#endif /* __KERNEL__ */
197 +#endif /* _IP_CONNTRACK_RTSP_H */
198 diff -NurpP --minimal linux-2.6.19-pom-ng/include/linux/netfilter_mime.h linux-2.6.19/include/linux/netfilter_mime.h
199 --- linux-2.6.19-pom-ng/include/linux/netfilter_mime.h 1970-01-01 01:00:00.000000000 +0100
200 +++ linux-2.6.19/include/linux/netfilter_mime.h 2006-12-14 11:39:01.000000000 +0100
203 + * MIME functions for netfilter modules. This file provides implementations
204 + * for basic MIME parsing. MIME headers are used in many protocols, such as
205 + * HTTP, RTSP, SIP, etc.
207 + * gcc will warn for defined but unused functions, so we only include the
208 + * functions requested. The following macros are used:
209 + * NF_NEED_MIME_NEXTLINE nf_mime_nextline()
211 +#ifndef _NETFILTER_MIME_H
212 +#define _NETFILTER_MIME_H
214 +/* Only include these functions for kernel code. */
217 +#include <linux/ctype.h>
220 + * Given a buffer and length, advance to the next line and mark the current
221 + * line. If the current line is empty, *plinelen will be set to zero. If
222 + * not, it will be set to the actual line length (including CRLF).
224 + * 'line' in this context means logical line (includes LWS continuations).
225 + * Returns 1 on success, 0 on failure.
227 +#ifdef NF_NEED_MIME_NEXTLINE
229 +nf_mime_nextline(char* p, uint len, uint* poff, uint* plineoff, uint* plinelen)
233 + int is_first_line = 1;
242 + while (p[off] != '\n')
253 + /* if we saw a crlf, physlen needs adjusted */
254 + if (physlen > 0 && p[off] == '\n' && p[off-1] == '\r')
259 + /* advance past the newline */
262 + /* check for an empty line */
268 + /* check for colon on the first physical line */
272 + if (memchr(p+(*poff), ':', physlen) == NULL)
278 + while (p[off] == ' ' || p[off] == '\t');
281 + *plinelen = (physlen == 0) ? 0 : (off - *poff);
286 +#endif /* NF_NEED_MIME_NEXTLINE */
288 +#endif /* __KERNEL__ */
290 +#endif /* _NETFILTER_MIME_H */
291 diff -NurpP --minimal linux-2.6.19-pom-ng/net/ipv4/netfilter/Kconfig linux-2.6.19/net/ipv4/netfilter/Kconfig
292 --- linux-2.6.19-pom-ng/net/ipv4/netfilter/Kconfig 2006-12-14 11:38:12.000000000 +0100
293 +++ linux-2.6.19/net/ipv4/netfilter/Kconfig 2006-12-14 11:39:01.000000000 +0100
294 @@ -893,5 +893,21 @@ config IP_NF_RSH
295 If you want to compile it as a module, say M here and read
296 <file:Documentation/modules.txt>. If unsure, say `N'.
298 +config IP_NF_NAT_RTSP
300 + depends on IP_NF_CONNTRACK!=n && IP_NF_NAT!=n
301 + default IP_NF_NAT if IP_NF_RTSP=y
302 + default m if IP_NF_RTSP=m
305 + tristate ' RTSP protocol support'
306 + depends on IP_NF_CONNTRACK
308 + Support the RTSP protocol. This allows UDP transports to be setup
309 + properly, including RTP and RDT.
311 + If you want to compile it as a module, say 'M' here and read
312 + Documentation/modules.txt. If unsure, say 'Y'.
316 diff -NurpP --minimal linux-2.6.19-pom-ng/net/ipv4/netfilter/Makefile linux-2.6.19/net/ipv4/netfilter/Makefile
317 --- linux-2.6.19-pom-ng/net/ipv4/netfilter/Makefile 2006-12-14 11:38:12.000000000 +0100
318 +++ linux-2.6.19/net/ipv4/netfilter/Makefile 2006-12-14 11:39:01.000000000 +0100
319 @@ -25,6 +25,11 @@ obj-$(CONFIG_IP_NF_CONNTRACK_NETLINK) +=
320 obj-$(CONFIG_IP_NF_CT_PROTO_SCTP) += ip_conntrack_proto_sctp.o
322 # connection tracking helpers
324 +# rtsp protocol support
325 +obj-$(CONFIG_IP_NF_RTSP) += ip_conntrack_rtsp.o
326 +obj-$(CONFIG_IP_NF_NAT_RTSP) += ip_nat_rtsp.o
328 obj-$(CONFIG_IP_NF_RSH) += ip_conntrack_rsh.o
329 obj-$(CONFIG_IP_NF_QUAKE3) += ip_conntrack_quake3.o
330 obj-$(CONFIG_IP_NF_MMS) += ip_conntrack_mms.o
331 diff -NurpP --minimal linux-2.6.19-pom-ng/net/ipv4/netfilter/ip_conntrack_rtsp.c linux-2.6.19/net/ipv4/netfilter/ip_conntrack_rtsp.c
332 --- linux-2.6.19-pom-ng/net/ipv4/netfilter/ip_conntrack_rtsp.c 1970-01-01 01:00:00.000000000 +0100
333 +++ linux-2.6.19/net/ipv4/netfilter/ip_conntrack_rtsp.c 2006-12-14 11:39:01.000000000 +0100
336 + * RTSP extension for IP connection tracking
337 + * (C) 2003 by Tom Marshall <tmarshall@real.com>
338 + * based on ip_conntrack_irc.c
340 + * This program is free software; you can redistribute it and/or
341 + * modify it under the terms of the GNU General Public License
342 + * as published by the Free Software Foundation; either version
343 + * 2 of the License, or (at your option) any later version.
345 + * Module load syntax:
346 + * insmod ip_conntrack_rtsp.o ports=port1,port2,...port<MAX_PORTS>
347 + * max_outstanding=n setup_timeout=secs
349 + * If no ports are specified, the default will be port 554.
351 + * With max_outstanding you can define the maximum number of not yet
352 + * answered SETUP requests per RTSP session (default 8).
353 + * With setup_timeout you can specify how long the system waits for
354 + * an expected data channel (default 300 seconds).
356 + * 2005-02-13: Harald Welte <laforge@netfilter.org>
358 + * - update to recent post-2.6.11 api changes
361 +#include <linux/config.h>
362 +#include <linux/module.h>
363 +#include <linux/netfilter.h>
364 +#include <linux/ip.h>
365 +#include <net/checksum.h>
366 +#include <net/tcp.h>
368 +#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
369 +#include <linux/netfilter_ipv4/ip_conntrack_rtsp.h>
371 +#include <linux/ctype.h>
372 +#define NF_NEED_STRNCASECMP
373 +#define NF_NEED_STRTOU16
374 +#define NF_NEED_STRTOU32
375 +#define NF_NEED_NEXTLINE
376 +#include <linux/netfilter_helpers.h>
377 +#define NF_NEED_MIME_NEXTLINE
378 +#include <linux/netfilter_mime.h>
380 +#define MAX_SIMUL_SETUP 8 /* XXX: use max_outstanding */
382 +#define INFOP(fmt, args...) printk(KERN_INFO "%s: %s: " fmt, __FILE__, __FUNCTION__ , ## args)
383 +#ifdef IP_NF_RTSP_DEBUG
384 +#define DEBUGP(fmt, args...) printk(KERN_DEBUG "%s: %s: " fmt, __FILE__, __FUNCTION__ , ## args)
386 +#define DEBUGP(fmt, args...)
390 +static int ports[MAX_PORTS];
391 +static int num_ports = 0;
392 +static int max_outstanding = 8;
393 +static unsigned int setup_timeout = 300;
395 +MODULE_AUTHOR("Tom Marshall <tmarshall@real.com>");
396 +MODULE_DESCRIPTION("RTSP connection tracking module");
397 +MODULE_LICENSE("GPL");
398 +module_param_array(ports, int, &num_ports, 0400);
399 +MODULE_PARM_DESC(ports, "port numbers of RTSP servers");
400 +module_param(max_outstanding, int, 0400);
401 +MODULE_PARM_DESC(max_outstanding, "max number of outstanding SETUP requests per RTSP session");
402 +module_param(setup_timeout, int, 0400);
403 +MODULE_PARM_DESC(setup_timeout, "timeout on for unestablished data channels");
405 +static char rtsp_buffer[65536];
406 +static DEFINE_SPINLOCK(rtsp_buffer_lock);
408 +unsigned int (*ip_nat_rtsp_hook)(struct sk_buff **pskb,
409 + enum ip_conntrack_info ctinfo,
410 + struct ip_ct_rtsp_expect *expinfo,
411 + struct ip_conntrack_expect *exp);
412 +EXPORT_SYMBOL_GPL(ip_nat_rtsp_hook);
415 + * Max mappings we will allow for one RTSP connection (for RTP, the number
416 + * of allocated ports is twice this value). Note that SMIL burns a lot of
417 + * ports so keep this reasonably high. If this is too low, you will see a
418 + * lot of "no free client map entries" messages.
420 +#define MAX_PORT_MAPS 16
422 +/*** default port list was here in the masq code: 554, 3030, 4040 ***/
424 +#define SKIP_WSPACE(ptr,len,off) while(off < len && isspace(*(ptr+off))) { off++; }
427 + * Parse an RTSP packet.
429 + * Returns zero if parsing failed.
432 + * IN ptcp tcp data pointer
433 + * IN tcplen tcp data len
434 + * IN/OUT ptcpoff points to current tcp offset
435 + * OUT phdrsoff set to offset of rtsp headers
436 + * OUT phdrslen set to length of rtsp headers
437 + * OUT pcseqoff set to offset of CSeq header
438 + * OUT pcseqlen set to length of CSeq header
441 +rtsp_parse_message(char* ptcp, uint tcplen, uint* ptcpoff,
442 + uint* phdrsoff, uint* phdrslen,
443 + uint* pcseqoff, uint* pcseqlen)
445 + uint entitylen = 0;
449 + if (!nf_nextline(ptcp, tcplen, ptcpoff, &lineoff, &linelen))
454 + *phdrsoff = *ptcpoff;
455 + while (nf_mime_nextline(ptcp, tcplen, ptcpoff, &lineoff, &linelen))
461 + *ptcpoff += min(entitylen, tcplen - *ptcpoff);
465 + if (lineoff+linelen > tcplen)
467 + INFOP("!! overrun !!\n");
471 + if (nf_strncasecmp(ptcp+lineoff, "CSeq:", 5) == 0)
473 + *pcseqoff = lineoff;
474 + *pcseqlen = linelen;
476 + if (nf_strncasecmp(ptcp+lineoff, "Content-Length:", 15) == 0)
478 + uint off = lineoff+15;
479 + SKIP_WSPACE(ptcp+lineoff, linelen, off);
480 + nf_strtou32(ptcp+off, &entitylen);
483 + *phdrslen = (*ptcpoff) - (*phdrsoff);
489 + * Find lo/hi client ports (if any) in transport header
491 + * ptcp, tcplen = packet
492 + * tranoff, tranlen = buffer to search
495 + * pport_lo, pport_hi = lo/hi ports (host endian)
497 + * Returns nonzero if any client ports found
499 + * Note: it is valid (and expected) for the client to request multiple
500 + * transports, so we need to parse the entire line.
503 +rtsp_parse_transport(char* ptran, uint tranlen,
504 + struct ip_ct_rtsp_expect* prtspexp)
509 + if (tranlen < 10 || !iseol(ptran[tranlen-1]) ||
510 + nf_strncasecmp(ptran, "Transport:", 10) != 0)
512 + INFOP("sanity check failed\n");
515 + DEBUGP("tran='%.*s'\n", (int)tranlen, ptran);
517 + SKIP_WSPACE(ptran, tranlen, off);
519 + /* Transport: tran;field;field=val,tran;field;field=val,... */
520 + while (off < tranlen)
522 + const char* pparamend;
525 + pparamend = memchr(ptran+off, ',', tranlen-off);
526 + pparamend = (pparamend == NULL) ? ptran+tranlen : pparamend+1;
527 + nextparamoff = pparamend-ptran;
529 + while (off < nextparamoff)
531 + const char* pfieldend;
534 + pfieldend = memchr(ptran+off, ';', nextparamoff-off);
535 + nextfieldoff = (pfieldend == NULL) ? nextparamoff : pfieldend-ptran+1;
537 + if (strncmp(ptran+off, "client_port=", 12) == 0)
543 + numlen = nf_strtou16(ptran+off, &port);
545 + if (prtspexp->loport != 0 && prtspexp->loport != port)
547 + DEBUGP("multiple ports found, port %hu ignored\n", port);
551 + prtspexp->loport = prtspexp->hiport = port;
552 + if (ptran[off] == '-')
555 + numlen = nf_strtou16(ptran+off, &port);
557 + prtspexp->pbtype = pb_range;
558 + prtspexp->hiport = port;
560 + // If we have a range, assume rtp:
561 + // loport must be even, hiport must be loport+1
562 + if ((prtspexp->loport & 0x0001) != 0 ||
563 + prtspexp->hiport != prtspexp->loport+1)
565 + DEBUGP("incorrect range: %hu-%hu, correcting\n",
566 + prtspexp->loport, prtspexp->hiport);
567 + prtspexp->loport &= 0xfffe;
568 + prtspexp->hiport = prtspexp->loport+1;
571 + else if (ptran[off] == '/')
574 + numlen = nf_strtou16(ptran+off, &port);
576 + prtspexp->pbtype = pb_discon;
577 + prtspexp->hiport = port;
584 + * Note we don't look for the destination parameter here.
585 + * If we are using NAT, the NAT module will handle it. If not,
586 + * and the client is sending packets elsewhere, the expectation
587 + * will quietly time out.
590 + off = nextfieldoff;
593 + off = nextparamoff;
599 +/*** conntrack functions ***/
601 +/* outbound packet: client->server */
603 +help_out(struct sk_buff **pskb, unsigned char *rb_ptr, unsigned int datalen,
604 + struct ip_conntrack* ct, enum ip_conntrack_info ctinfo)
606 + struct ip_ct_rtsp_expect expinfo;
607 + int dir = CTINFO2DIR(ctinfo); /* = IP_CT_DIR_ORIGINAL */
608 + //struct tcphdr* tcph = (void*)iph + iph->ihl * 4;
609 + //uint tcplen = pktlen - iph->ihl * 4;
610 + char* pdata = rb_ptr;
611 + //uint datalen = tcplen - tcph->doff * 4;
613 + int ret = NF_ACCEPT;
615 + struct ip_conntrack_expect *exp;
617 + memset(&expinfo, 0, sizeof(expinfo));
619 + while (dataoff < datalen)
621 + uint cmdoff = dataoff;
630 + if (!rtsp_parse_message(pdata, datalen, &dataoff,
631 + &hdrsoff, &hdrslen,
632 + &cseqoff, &cseqlen))
634 + break; /* not a valid message */
637 + if (strncmp(pdata+cmdoff, "SETUP ", 6) != 0)
639 + continue; /* not a SETUP message */
641 + DEBUGP("found a setup message\n");
644 + while (nf_mime_nextline(pdata+hdrsoff, hdrslen, &off,
645 + &lineoff, &linelen))
651 + if (off > hdrsoff+hdrslen)
653 + INFOP("!! overrun !!");
657 + if (nf_strncasecmp(pdata+hdrsoff+lineoff, "Transport:", 10) == 0)
659 + rtsp_parse_transport(pdata+hdrsoff+lineoff, linelen, &expinfo);
663 + if (expinfo.loport == 0)
665 + DEBUGP("no udp transports found\n");
666 + continue; /* no udp transports found */
669 + DEBUGP("udp transport found, ports=(%d,%hu,%hu)\n",
670 + (int)expinfo.pbtype,
674 + exp = ip_conntrack_expect_alloc();
680 + //exp->seq = ntohl(tcph->seq) + hdrsoff; /* mark all the headers */
682 + //exp.help.exp_rtsp_info.len = hdrslen;
684 + exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip;
685 + exp->mask.src.ip = 0xffffffff;
686 + exp->tuple.dst.ip = ct->tuplehash[dir].tuple.src.ip;
687 + exp->mask.dst.ip = 0xffffffff;
688 + exp->tuple.dst.u.udp.port = expinfo.loport;
689 + exp->mask.dst.u.udp.port =
690 + (expinfo.pbtype == pb_range) ? 0xfffe : 0xffff;
691 + exp->tuple.dst.protonum = IPPROTO_UDP;
692 + exp->mask.dst.protonum = 0xff;
694 + DEBUGP("expect_related %u.%u.%u.%u:%u-%u.%u.%u.%u:%u\n",
695 + NIPQUAD(exp->tuple.src.ip),
696 + ntohs(exp->tuple.src.u.tcp.port),
697 + NIPQUAD(exp->tuple.dst.ip),
698 + ntohs(exp->tuple.dst.u.tcp.port));
700 + if (ip_nat_rtsp_hook)
701 + /* pass the request off to the nat helper */
702 + ret = ip_nat_rtsp_hook(pskb, ctinfo, &expinfo, exp);
703 + else if (ip_conntrack_expect_related(exp) != 0) {
704 + INFOP("ip_conntrack_expect_related failed\n");
705 + ip_conntrack_expect_free(exp);
715 +/* inbound packet: server->client */
717 +help_in(struct sk_buff **pskb, size_t pktlen,
718 + struct ip_conntrack* ct, enum ip_conntrack_info ctinfo)
723 +static int help(struct sk_buff **pskb, struct ip_conntrack* ct, enum
724 + ip_conntrack_info ctinfo)
726 + struct tcphdr _tcph, *th;
727 + unsigned int dataoff, datalen;
731 + /* Until there's been traffic both ways, don't look in packets. */
732 + if (ctinfo != IP_CT_ESTABLISHED &&
733 + ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY)
735 + DEBUGP("conntrackinfo = %u\n", ctinfo);
739 + /* Not whole TCP header? */
740 + th = skb_header_pointer(*pskb, (*pskb)->nh.iph->ihl*4,
741 + sizeof(_tcph), &_tcph);
746 + dataoff = (*pskb)->nh.iph->ihl*4 + th->doff*4;
747 + datalen = (*pskb)->len - dataoff;
748 + if (dataoff >= (*pskb)->len)
751 + spin_lock_bh(&rtsp_buffer_lock);
752 + rb_ptr = skb_header_pointer(*pskb, dataoff,
753 + (*pskb)->len - dataoff, rtsp_buffer);
754 + BUG_ON(rb_ptr == NULL);
757 + /* Checksum invalid? Ignore. */
758 + /* FIXME: Source route IP option packets --RR */
759 + if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr,
760 + csum_partial((char*)tcph, tcplen, 0)))
762 + DEBUGP("bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n",
763 + tcph, tcplen, NIPQUAD(iph->saddr), NIPQUAD(iph->daddr));
768 + switch (CTINFO2DIR(ctinfo))
770 + case IP_CT_DIR_ORIGINAL:
771 + ret = help_out(pskb, rb_ptr, datalen, ct, ctinfo);
773 + case IP_CT_DIR_REPLY:
774 + /* inbound packet: server->client */
779 + spin_unlock_bh(&rtsp_buffer_lock);
784 +static struct ip_conntrack_helper rtsp_helpers[MAX_PORTS];
785 +static char rtsp_names[MAX_PORTS][10];
787 +/* This function is intentionally _NOT_ defined as __exit */
792 + for (i = 0; i < num_ports; i++)
794 + DEBUGP("unregistering port %d\n", ports[i]);
795 + ip_conntrack_helper_unregister(&rtsp_helpers[i]);
803 + struct ip_conntrack_helper *hlpr;
806 + printk("ip_conntrack_rtsp v" IP_NF_RTSP_VERSION " loading\n");
808 + if (max_outstanding < 1)
810 + printk("ip_conntrack_rtsp: max_outstanding must be a positive integer\n");
813 + if (setup_timeout < 0)
815 + printk("ip_conntrack_rtsp: setup_timeout must be a positive integer\n");
819 + /* If no port given, default to standard rtsp port */
822 + ports[0] = RTSP_PORT;
825 + for (i = 0; (i < MAX_PORTS) && ports[i]; i++)
827 + hlpr = &rtsp_helpers[i];
828 + memset(hlpr, 0, sizeof(struct ip_conntrack_helper));
829 + hlpr->tuple.src.u.tcp.port = htons(ports[i]);
830 + hlpr->tuple.dst.protonum = IPPROTO_TCP;
831 + hlpr->mask.src.u.tcp.port = 0xFFFF;
832 + hlpr->mask.dst.protonum = 0xFF;
833 + hlpr->max_expected = max_outstanding;
834 + hlpr->timeout = setup_timeout;
835 + hlpr->me = THIS_MODULE;
838 + tmpname = &rtsp_names[i][0];
839 + if (ports[i] == RTSP_PORT)
841 + sprintf(tmpname, "rtsp");
845 + sprintf(tmpname, "rtsp-%d", i);
847 + hlpr->name = tmpname;
849 + DEBUGP("port #%d: %d\n", i, ports[i]);
851 + ret = ip_conntrack_helper_register(hlpr);
855 + printk("ip_conntrack_rtsp: ERROR registering port %d\n", ports[i]);
866 diff -NurpP --minimal linux-2.6.19-pom-ng/net/ipv4/netfilter/ip_nat_rtsp.c linux-2.6.19/net/ipv4/netfilter/ip_nat_rtsp.c
867 --- linux-2.6.19-pom-ng/net/ipv4/netfilter/ip_nat_rtsp.c 1970-01-01 01:00:00.000000000 +0100
868 +++ linux-2.6.19/net/ipv4/netfilter/ip_nat_rtsp.c 2006-12-14 11:39:01.000000000 +0100
871 + * RTSP extension for TCP NAT alteration
872 + * (C) 2003 by Tom Marshall <tmarshall@real.com>
873 + * based on ip_nat_irc.c
875 + * This program is free software; you can redistribute it and/or
876 + * modify it under the terms of the GNU General Public License
877 + * as published by the Free Software Foundation; either version
878 + * 2 of the License, or (at your option) any later version.
880 + * Module load syntax:
881 + * insmod ip_nat_rtsp.o ports=port1,port2,...port<MAX_PORTS>
882 + * stunaddr=<address>
883 + * destaction=[auto|strip|none]
885 + * If no ports are specified, the default will be port 554 only.
887 + * stunaddr specifies the address used to detect that a client is using STUN.
888 + * If this address is seen in the destination parameter, it is assumed that
889 + * the client has already punched a UDP hole in the firewall, so we don't
890 + * mangle the client_port. If none is specified, it is autodetected. It
891 + * only needs to be set if you have multiple levels of NAT. It should be
892 + * set to the external address that the STUN clients detect. Note that in
893 + * this case, it will not be possible for clients to use UDP with servers
894 + * between the NATs.
896 + * If no destaction is specified, auto is used.
897 + * destaction=auto: strip destination parameter if it is not stunaddr.
898 + * destaction=strip: always strip destination parameter (not recommended).
899 + * destaction=none: do not touch destination parameter (not recommended).
902 +#include <linux/module.h>
903 +#include <linux/netfilter_ipv4.h>
904 +#include <linux/ip.h>
905 +#include <linux/tcp.h>
906 +#include <linux/kernel.h>
907 +#include <net/tcp.h>
908 +#include <linux/netfilter_ipv4/ip_nat.h>
909 +#include <linux/netfilter_ipv4/ip_nat_helper.h>
910 +#include <linux/netfilter_ipv4/ip_nat_rule.h>
911 +#include <linux/netfilter_ipv4/ip_conntrack_rtsp.h>
912 +#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
914 +#include <linux/inet.h>
915 +#include <linux/ctype.h>
916 +#define NF_NEED_STRNCASECMP
917 +#define NF_NEED_STRTOU16
918 +#include <linux/netfilter_helpers.h>
919 +#define NF_NEED_MIME_NEXTLINE
920 +#include <linux/netfilter_mime.h>
922 +#define INFOP(fmt, args...) printk(KERN_INFO "%s: %s: " fmt, __FILE__, __FUNCTION__ , ## args)
923 +#ifdef IP_NF_RTSP_DEBUG
924 +#define DEBUGP(fmt, args...) printk(KERN_DEBUG "%s: %s: " fmt, __FILE__, __FUNCTION__ , ## args)
926 +#define DEBUGP(fmt, args...)
930 +#define DSTACT_AUTO 0
931 +#define DSTACT_STRIP 1
932 +#define DSTACT_NONE 2
934 +static int ports[MAX_PORTS];
935 +static char* stunaddr = NULL;
936 +static char* destaction = NULL;
938 +static int num_ports = 0;
939 +static u_int32_t extip = 0;
940 +static int dstact = 0;
942 +MODULE_AUTHOR("Tom Marshall <tmarshall@real.com>");
943 +MODULE_DESCRIPTION("RTSP network address translation module");
944 +MODULE_LICENSE("GPL");
945 +module_param(stunaddr, charp, 0644);
946 +MODULE_PARM_DESC(stunaddr, "Address for detecting STUN");
947 +module_param(destaction, charp, 0644);
948 +MODULE_PARM_DESC(destaction, "Action for destination parameter (auto/strip/none)");
950 +#define SKIP_WSPACE(ptr,len,off) while(off < len && isspace(*(ptr+off))) { off++; }
952 +/*** helper functions ***/
955 +get_skb_tcpdata(struct sk_buff* skb, char** pptcpdata, uint* ptcpdatalen)
957 + struct iphdr* iph = (struct iphdr*)skb->nh.iph;
958 + struct tcphdr* tcph = (struct tcphdr*)((char*)iph + iph->ihl*4);
960 + *pptcpdata = (char*)tcph + tcph->doff*4;
961 + *ptcpdatalen = ((char*)skb->h.raw + skb->len) - *pptcpdata;
964 +/*** nat functions ***/
967 + * Mangle the "Transport:" header:
968 + * - Replace all occurences of "client_port=<spec>"
969 + * - Handle destination parameter
972 + * ct, ctinfo = conntrack context
974 + * tranoff = Transport header offset from TCP data
975 + * tranlen = Transport header length (incl. CRLF)
976 + * rport_lo = replacement low port (host endian)
977 + * rport_hi = replacement high port (host endian)
979 + * Returns packet size difference.
981 + * Assumes that a complete transport header is present, ending with CR or LF
984 +rtsp_mangle_tran(enum ip_conntrack_info ctinfo,
985 + struct ip_conntrack_expect* exp,
986 + struct ip_ct_rtsp_expect* prtspexp,
987 + struct sk_buff** pskb, uint tranoff, uint tranlen)
992 + char rbuf1[16]; /* Replacement buffer (one port) */
993 + uint rbuf1len; /* Replacement len (one port) */
994 + char rbufa[16]; /* Replacement buffer (all ports) */
995 + uint rbufalen; /* Replacement len (all ports) */
997 + u_int16_t loport, hiport;
999 + uint diff; /* Number of bytes we removed */
1001 + struct ip_conntrack *ct = exp->master;
1002 + struct ip_conntrack_tuple t;
1004 + char szextaddr[15+1];
1008 + get_skb_tcpdata(*pskb, &ptcp, &tcplen);
1009 + ptran = ptcp+tranoff;
1011 + if (tranoff+tranlen > tcplen || tcplen-tranoff < tranlen ||
1012 + tranlen < 10 || !iseol(ptran[tranlen-1]) ||
1013 + nf_strncasecmp(ptran, "Transport:", 10) != 0)
1015 + INFOP("sanity check failed\n");
1019 + SKIP_WSPACE(ptcp+tranoff, tranlen, off);
1021 + newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
1025 + extaddrlen = extip ? sprintf(szextaddr, "%u.%u.%u.%u", NIPQUAD(extip))
1026 + : sprintf(szextaddr, "%u.%u.%u.%u", NIPQUAD(newip));
1027 + DEBUGP("stunaddr=%s (%s)\n", szextaddr, (extip?"forced":"auto"));
1029 + rbuf1len = rbufalen = 0;
1030 + switch (prtspexp->pbtype)
1033 + for (loport = prtspexp->loport; loport != 0; loport++) /* XXX: improper wrap? */
1035 + t.dst.u.udp.port = htons(loport);
1036 + if (ip_conntrack_change_expect(exp, &t) == 0)
1038 + DEBUGP("using port %hu\n", loport);
1044 + rbuf1len = sprintf(rbuf1, "%hu", loport);
1045 + rbufalen = sprintf(rbufa, "%hu", loport);
1049 + for (loport = prtspexp->loport; loport != 0; loport += 2) /* XXX: improper wrap? */
1051 + t.dst.u.udp.port = htons(loport);
1052 + if (ip_conntrack_change_expect(exp, &t) == 0)
1054 + hiport = loport + ~exp->mask.dst.u.udp.port;
1055 + DEBUGP("using ports %hu-%hu\n", loport, hiport);
1061 + rbuf1len = sprintf(rbuf1, "%hu", loport);
1062 + rbufalen = sprintf(rbufa, "%hu-%hu", loport, loport+1);
1066 + for (loport = prtspexp->loport; loport != 0; loport++) /* XXX: improper wrap? */
1068 + t.dst.u.udp.port = htons(loport);
1069 + if (ip_conntrack_change_expect(exp, &t) == 0)
1071 + DEBUGP("using port %hu (1 of 2)\n", loport);
1075 + for (hiport = prtspexp->hiport; hiport != 0; hiport++) /* XXX: improper wrap? */
1077 + t.dst.u.udp.port = htons(hiport);
1078 + if (ip_conntrack_change_expect(exp, &t) == 0)
1080 + DEBUGP("using port %hu (2 of 2)\n", hiport);
1084 + if (loport != 0 && hiport != 0)
1086 + rbuf1len = sprintf(rbuf1, "%hu", loport);
1087 + if (hiport == loport+1)
1089 + rbufalen = sprintf(rbufa, "%hu-%hu", loport, hiport);
1093 + rbufalen = sprintf(rbufa, "%hu/%hu", loport, hiport);
1099 + if (rbuf1len == 0)
1101 + return 0; /* cannot get replacement port(s) */
1104 + /* Transport: tran;field;field=val,tran;field;field=val,... */
1105 + while (off < tranlen)
1108 + const char* pparamend;
1109 + uint nextparamoff;
1111 + pparamend = memchr(ptran+off, ',', tranlen-off);
1112 + pparamend = (pparamend == NULL) ? ptran+tranlen : pparamend+1;
1113 + nextparamoff = pparamend-ptcp;
1116 + * We pass over each param twice. On the first pass, we look for a
1117 + * destination= field. It is handled by the security policy. If it
1118 + * is present, allowed, and equal to our external address, we assume
1119 + * that STUN is being used and we leave the client_port= field alone.
1123 + while (off < nextparamoff)
1125 + const char* pfieldend;
1126 + uint nextfieldoff;
1128 + pfieldend = memchr(ptran+off, ';', nextparamoff-off);
1129 + nextfieldoff = (pfieldend == NULL) ? nextparamoff : pfieldend-ptran+1;
1131 + if (dstact != DSTACT_NONE && strncmp(ptran+off, "destination=", 12) == 0)
1133 + if (strncmp(ptran+off+12, szextaddr, extaddrlen) == 0)
1137 + if (dstact == DSTACT_STRIP || (dstact == DSTACT_AUTO && !is_stun))
1139 + diff = nextfieldoff-off;
1140 + if (!ip_nat_mangle_tcp_packet(pskb, ct, ctinfo,
1141 + off, diff, NULL, 0))
1143 + /* mangle failed, all we can do is bail */
1144 + ip_conntrack_unexpect_related(exp);
1147 + get_skb_tcpdata(*pskb, &ptcp, &tcplen);
1148 + ptran = ptcp+tranoff;
1150 + nextparamoff -= diff;
1151 + nextfieldoff -= diff;
1155 + off = nextfieldoff;
1162 + while (off < nextparamoff)
1164 + const char* pfieldend;
1165 + uint nextfieldoff;
1167 + pfieldend = memchr(ptran+off, ';', nextparamoff-off);
1168 + nextfieldoff = (pfieldend == NULL) ? nextparamoff : pfieldend-ptran+1;
1170 + if (strncmp(ptran+off, "client_port=", 12) == 0)
1176 + char* rbuf = rbuf1;
1177 + uint rbuflen = rbuf1len;
1180 + origoff = (ptran-ptcp)+off;
1182 + numlen = nf_strtou16(ptran+off, &port);
1184 + origlen += numlen;
1185 + if (port != prtspexp->loport)
1187 + DEBUGP("multiple ports found, port %hu ignored\n", port);
1191 + if (ptran[off] == '-' || ptran[off] == '/')
1195 + numlen = nf_strtou16(ptran+off, &port);
1197 + origlen += numlen;
1199 + rbuflen = rbufalen;
1203 + * note we cannot just memcpy() if the sizes are the same.
1204 + * the mangle function does skb resizing, checks for a
1205 + * cloned skb, and updates the checksums.
1207 + * parameter 4 below is offset from start of tcp data.
1209 + diff = origlen-rbuflen;
1210 + if (!ip_nat_mangle_tcp_packet(pskb, ct, ctinfo,
1211 + origoff, origlen, rbuf, rbuflen))
1213 + /* mangle failed, all we can do is bail */
1214 + ip_conntrack_unexpect_related(exp);
1217 + get_skb_tcpdata(*pskb, &ptcp, &tcplen);
1218 + ptran = ptcp+tranoff;
1220 + nextparamoff -= diff;
1221 + nextfieldoff -= diff;
1225 + off = nextfieldoff;
1228 + off = nextparamoff;
1234 +static unsigned int
1235 +expected(struct sk_buff **pskb, uint hooknum, struct ip_conntrack* ct, struct ip_nat_info* info)
1237 + struct ip_nat_multi_range mr;
1238 + u_int32_t newdstip, newsrcip, newip;
1240 + struct ip_conntrack *master = master_ct(ct);
1242 + IP_NF_ASSERT(info);
1243 + IP_NF_ASSERT(master);
1245 + IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum))));
1247 + newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
1248 + newsrcip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
1249 + newip = (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC) ? newsrcip : newdstip;
1251 + DEBUGP("newsrcip=%u.%u.%u.%u, newdstip=%u.%u.%u.%u, newip=%u.%u.%u.%u\n",
1252 + NIPQUAD(newsrcip), NIPQUAD(newdstip), NIPQUAD(newip));
1255 + /* We don't want to manip the per-protocol, just the IPs. */
1256 + mr.range[0].flags = IP_NAT_RANGE_MAP_IPS;
1257 + mr.range[0].min_ip = mr.range[0].max_ip = newip;
1259 + return ip_nat_setup_info(ct, &mr, hooknum);
1263 +help_out(struct sk_buff **pskb, enum ip_conntrack_info ctinfo,
1264 + struct ip_ct_rtsp_expect *prtspexp,
1265 + struct ip_conntrack_expect* exp)
1275 + struct iphdr* iph = (struct iphdr*)(*pskb)->nh.iph;
1276 + struct tcphdr* tcph = (struct tcphdr*)((void*)iph + iph->ihl*4);
1278 + get_skb_tcpdata(*pskb, &ptcp, &tcplen);
1280 + hdrsoff = exp->seq - ntohl(tcph->seq);
1281 + hdrslen = prtspexp->len;
1284 + while (nf_mime_nextline(ptcp, hdrsoff+hdrslen, &off, &lineoff, &linelen))
1290 + if (off > hdrsoff+hdrslen)
1292 + INFOP("!! overrun !!");
1295 + DEBUGP("hdr: len=%u, %.*s", linelen, (int)linelen, ptcp+lineoff);
1297 + if (nf_strncasecmp(ptcp+lineoff, "Transport:", 10) == 0)
1299 + uint oldtcplen = tcplen;
1300 + if (!rtsp_mangle_tran(ct, ctinfo, exp, prtspexp, pskb, lineoff, linelen))
1304 + get_skb_tcpdata(*pskb, &ptcp, &tcplen);
1305 + hdrslen -= (oldtcplen-tcplen);
1306 + off -= (oldtcplen-tcplen);
1307 + lineoff -= (oldtcplen-tcplen);
1308 + linelen -= (oldtcplen-tcplen);
1309 + DEBUGP("rep: len=%u, %.*s", linelen, (int)linelen, ptcp+lineoff);
1317 +help(struct sk_buff **pskb,
1318 + enum ip_conntrack_info ctinfo,
1319 + struct ip_ct_rtsp_expect *ct_rtsp_info;
1320 + struct ip_conntrack_expect* exp)
1322 + struct iphdr* iph = (struct iphdr*)(*pskb)->nh.iph;
1323 + struct tcphdr* tcph = (struct tcphdr*)((char*)iph + iph->ihl * 4);
1325 + int dir = CTINFO2DIR(ctinfo);
1326 + int rc = NF_ACCEPT;
1330 + case IP_CT_DIR_ORIGINAL:
1331 + rc = help_out(pskb, ctinfo, ct_rtsp_info, exp, pskb);
1333 + case IP_CT_DIR_REPLY:
1334 + /* XXX: unmangle */
1342 +static void __exit fini(void)
1344 + ip_nat_rtsp_hook = NULL;
1345 + synchronize_net();
1348 +static int __init init(void)
1350 + printk("ip_nat_rtsp v" IP_NF_RTSP_VERSION " loading\n");
1352 + BUG_ON(ip_nat_rtsp_hook);
1353 + ip_nat_rtsp_hook = help;
1355 + if (stunaddr != NULL)
1356 + extip = in_aton(stunaddr);
1358 + if (destaction != NULL) {
1359 + if (strcmp(destaction, "auto") == 0)
1360 + dstact = DSTACT_AUTO;
1362 + if (strcmp(destaction, "strip") == 0)
1363 + dstact = DSTACT_STRIP;
1365 + if (strcmp(destaction, "none") == 0)
1366 + dstact = DSTACT_NONE;