diff options
Diffstat (limited to 'target')
| -rw-r--r-- | target/linux/linux-2.4/config/ar531x | 2 | ||||
| -rw-r--r-- | target/linux/linux-2.4/config/ar7 | 2 | ||||
| -rw-r--r-- | target/linux/linux-2.4/config/brcm | 2 | ||||
| -rw-r--r-- | target/linux/linux-2.4/config/x86 | 4 | ||||
| -rw-r--r-- | target/linux/linux-2.4/patches/generic/617-netfilter_nat_rtsp.patch | 1538 | ||||
| -rw-r--r-- | target/linux/netfilter.mk | 2 | 
6 files changed, 1549 insertions, 1 deletions
| diff --git a/target/linux/linux-2.4/config/ar531x b/target/linux/linux-2.4/config/ar531x index 3db1f57c3..5a9137de3 100644 --- a/target/linux/linux-2.4/config/ar531x +++ b/target/linux/linux-2.4/config/ar531x @@ -346,6 +346,7 @@ CONFIG_IP_NF_PPTP=m  CONFIG_IP_NF_SIP=m  CONFIG_IP_NF_H323=m  CONFIG_IP_NF_MMS=m +CONFIG_IP_NF_RTSP=m  CONFIG_IP_NF_QUEUE=m  CONFIG_IP_NF_IPTABLES=y  CONFIG_IP_NF_MATCH_LIMIT=m @@ -398,6 +399,7 @@ CONFIG_IP_NF_NAT_PROTO_GRE=m  CONFIG_IP_NF_NAT_SIP=m  CONFIG_IP_NF_NAT_H323=m  CONFIG_IP_NF_NAT_MMS=m +CONFIG_IP_NF_NAT_RTSP=m  CONFIG_IP_NF_NAT_AMANDA=m  CONFIG_IP_NF_NAT_SNMP_BASIC=m  CONFIG_IP_NF_NAT_IRC=y diff --git a/target/linux/linux-2.4/config/ar7 b/target/linux/linux-2.4/config/ar7 index fab2bf32a..829c0551e 100644 --- a/target/linux/linux-2.4/config/ar7 +++ b/target/linux/linux-2.4/config/ar7 @@ -350,6 +350,7 @@ CONFIG_IP_NF_PPTP=m  CONFIG_IP_NF_SIP=m  CONFIG_IP_NF_H323=m  CONFIG_IP_NF_MMS=m +CONFIG_IP_NF_RTSP=m  CONFIG_IP_NF_QUEUE=m  CONFIG_IP_NF_IPTABLES=y  CONFIG_IP_NF_MATCH_LIMIT=m @@ -402,6 +403,7 @@ CONFIG_IP_NF_NAT_PROTO_GRE=m  CONFIG_IP_NF_NAT_SIP=m  CONFIG_IP_NF_NAT_H323=m  CONFIG_IP_NF_NAT_MMS=m +CONFIG_IP_NF_NAT_RTSP=m  CONFIG_IP_NF_NAT_AMANDA=m  CONFIG_IP_NF_NAT_SNMP_BASIC=m  CONFIG_IP_NF_NAT_IRC=y diff --git a/target/linux/linux-2.4/config/brcm b/target/linux/linux-2.4/config/brcm index 4abc8b1aa..a8636a7ba 100644 --- a/target/linux/linux-2.4/config/brcm +++ b/target/linux/linux-2.4/config/brcm @@ -365,6 +365,7 @@ CONFIG_IP_NF_PPTP=m  CONFIG_IP_NF_SIP=m  CONFIG_IP_NF_H323=m  CONFIG_IP_NF_MMS=m +CONFIG_IP_NF_NAT_RTSP=m  CONFIG_IP_NF_QUEUE=m  CONFIG_IP_NF_IPTABLES=y  CONFIG_IP_NF_MATCH_LIMIT=m @@ -416,6 +417,7 @@ CONFIG_IP_NF_NAT_PPTP=m  CONFIG_IP_NF_NAT_SIP=m  CONFIG_IP_NF_NAT_H323=m  CONFIG_IP_NF_NAT_MMS=m +CONFIG_IP_NF_NAT_RTSP=m  CONFIG_IP_NF_NAT_PROTO_GRE=m  CONFIG_IP_NF_NAT_AMANDA=m  CONFIG_IP_NF_NAT_SNMP_BASIC=m diff --git a/target/linux/linux-2.4/config/x86 b/target/linux/linux-2.4/config/x86 index 6da4f94aa..728613c4a 100644 --- a/target/linux/linux-2.4/config/x86 +++ b/target/linux/linux-2.4/config/x86 @@ -276,7 +276,6 @@ CONFIG_NET_IPGRE=m  #  #   IP: Netfilter Configuration  # -CONFIG_IP_NF_MMS=m  CONFIG_IP_NF_CONNTRACK=y  CONFIG_IP_NF_CONNTRACK_MARK=y  CONFIG_IP_NF_FTP=y @@ -289,6 +288,8 @@ CONFIG_IP_NF_CT_PROTO_GRE=m  CONFIG_IP_NF_PPTP=m  CONFIG_IP_NF_SIP=m  CONFIG_IP_NF_H323=m +CONFIG_IP_NF_MMS=m +CONFIG_IP_NF_RTSP=m  CONFIG_IP_NF_QUEUE=m  CONFIG_IP_NF_IPTABLES=y  CONFIG_IP_NF_MATCH_LIMIT=m @@ -341,6 +342,7 @@ CONFIG_IP_NF_NAT_SIP=m  CONFIG_IP_NF_NAT_H323=m  CONFIG_IP_NF_NAT_PROTO_GRE=m  CONFIG_IP_NF_NAT_MMS=m +CONFIG_IP_NF_NAT_RTSP=m  CONFIG_IP_NF_NAT_AMANDA=m  CONFIG_IP_NF_NAT_SNMP_BASIC=m  CONFIG_IP_NF_NAT_IRC=y diff --git a/target/linux/linux-2.4/patches/generic/617-netfilter_nat_rtsp.patch b/target/linux/linux-2.4/patches/generic/617-netfilter_nat_rtsp.patch new file mode 100644 index 000000000..28bf66442 --- /dev/null +++ b/target/linux/linux-2.4/patches/generic/617-netfilter_nat_rtsp.patch @@ -0,0 +1,1538 @@ +diff -urN linux-2.4.32.orig/arch/mips/kernel/mips_ksyms.c linux-2.4.32/arch/mips/kernel/mips_ksyms.c +--- linux-2.4.32.orig/arch/mips/kernel/mips_ksyms.c	2005-12-29 12:17:49.000000000 +0100 ++++ linux-2.4.32/arch/mips/kernel/mips_ksyms.c	2005-12-29 12:18:26.000000000 +0100 +@@ -52,6 +52,7 @@ + /* +  * String functions +  */ ++EXPORT_SYMBOL_NOVERS(memchr); + EXPORT_SYMBOL_NOVERS(memcmp); + EXPORT_SYMBOL_NOVERS(memset); + EXPORT_SYMBOL_NOVERS(memcpy); +diff -urN linux-2.4.32.orig/Documentation/Configure.help linux-2.4.32/Documentation/Configure.help +--- linux-2.4.32.orig/Documentation/Configure.help	2005-12-29 12:17:55.000000000 +0100 ++++ linux-2.4.32/Documentation/Configure.help	2005-12-29 12:18:26.000000000 +0100 +@@ -2817,6 +2817,14 @@ +   Documentation/modules.txt.  If unsure, say `N'. +  +  ++RTSP protocol support ++CONFIG_IP_NF_RTSP ++  Support the RTSP protocol.  This allows UDP transports to be setup ++  properly, including RTP and RDT. ++ ++  If you want to compile it as a module, say 'M' here and read ++  Documentation/modules.txt.  If unsure, say 'Y'. ++ + IRC Send/Chat protocol support + CONFIG_IP_NF_IRC +   There is a commonly-used extension to IRC called +diff -urN linux-2.4.32.orig/include/linux/netfilter_helpers.h linux-2.4.32/include/linux/netfilter_helpers.h +--- linux-2.4.32.orig/include/linux/netfilter_helpers.h	1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.32/include/linux/netfilter_helpers.h	2005-12-29 12:18:26.000000000 +0100 +@@ -0,0 +1,133 @@ ++/* ++ * Helpers for netfiler modules.  This file provides implementations for basic ++ * functions such as strncasecmp(), etc. ++ * ++ * gcc will warn for defined but unused functions, so we only include the ++ * functions requested.  The following macros are used: ++ *   NF_NEED_STRNCASECMP        nf_strncasecmp() ++ *   NF_NEED_STRTOU16           nf_strtou16() ++ *   NF_NEED_STRTOU32           nf_strtou32() ++ */ ++#ifndef _NETFILTER_HELPERS_H ++#define _NETFILTER_HELPERS_H ++ ++/* Only include these functions for kernel code. */ ++#ifdef __KERNEL__ ++ ++#include <linux/ctype.h> ++#define iseol(c) ( (c) == '\r' || (c) == '\n' ) ++ ++/* ++ * The standard strncasecmp() ++ */ ++#ifdef NF_NEED_STRNCASECMP ++static int ++nf_strncasecmp(const char* s1, const char* s2, u_int32_t len) ++{ ++    if (s1 == NULL || s2 == NULL) ++    { ++        if (s1 == NULL && s2 == NULL) ++        { ++            return 0; ++        } ++        return (s1 == NULL) ? -1 : 1; ++    } ++    while (len > 0 && tolower(*s1) == tolower(*s2)) ++    { ++        len--; ++        s1++; ++        s2++; ++    } ++    return ( (len == 0) ? 0 : (tolower(*s1) - tolower(*s2)) ); ++} ++#endif /* NF_NEED_STRNCASECMP */ ++ ++/* ++ * Parse a string containing a 16-bit unsigned integer. ++ * Returns the number of chars used, or zero if no number is found. ++ */ ++#ifdef NF_NEED_STRTOU16 ++static int ++nf_strtou16(const char* pbuf, u_int16_t* pval) ++{ ++    int n = 0; ++ ++    *pval = 0; ++    while (isdigit(pbuf[n])) ++    { ++        *pval = (*pval * 10) + (pbuf[n] - '0'); ++        n++; ++    } ++ ++    return n; ++} ++#endif /* NF_NEED_STRTOU16 */ ++ ++/* ++ * Parse a string containing a 32-bit unsigned integer. ++ * Returns the number of chars used, or zero if no number is found. ++ */ ++#ifdef NF_NEED_STRTOU32 ++static int ++nf_strtou32(const char* pbuf, u_int32_t* pval) ++{ ++    int n = 0; ++ ++    *pval = 0; ++    while (pbuf[n] >= '0' && pbuf[n] <= '9') ++    { ++        *pval = (*pval * 10) + (pbuf[n] - '0'); ++        n++; ++    } ++ ++    return n; ++} ++#endif /* NF_NEED_STRTOU32 */ ++ ++/* ++ * Given a buffer and length, advance to the next line and mark the current ++ * line. ++ */ ++#ifdef NF_NEED_NEXTLINE ++static int ++nf_nextline(char* p, uint len, uint* poff, uint* plineoff, uint* plinelen) ++{ ++    uint    off = *poff; ++    uint    physlen = 0; ++ ++    if (off >= len) ++    { ++        return 0; ++    } ++ ++    while (p[off] != '\n') ++    { ++        if (len-off <= 1) ++        { ++            return 0; ++        } ++ ++        physlen++; ++        off++; ++    } ++ ++    /* if we saw a crlf, physlen needs adjusted */ ++    if (physlen > 0 && p[off] == '\n' && p[off-1] == '\r') ++    { ++        physlen--; ++    } ++ ++    /* advance past the newline */ ++    off++; ++ ++    *plineoff = *poff; ++    *plinelen = physlen; ++    *poff = off; ++ ++    return 1; ++} ++#endif /* NF_NEED_NEXTLINE */ ++ ++#endif /* __KERNEL__ */ ++ ++#endif /* _NETFILTER_HELPERS_H */ +diff -urN linux-2.4.32.orig/include/linux/netfilter_ipv4/ip_conntrack.h linux-2.4.32/include/linux/netfilter_ipv4/ip_conntrack.h +--- linux-2.4.32.orig/include/linux/netfilter_ipv4/ip_conntrack.h	2005-12-29 12:17:55.000000000 +0100 ++++ linux-2.4.32/include/linux/netfilter_ipv4/ip_conntrack.h	2005-12-29 12:18:26.000000000 +0100 +@@ -66,6 +66,7 @@ + }; +  + /* Add protocol helper include file here */ ++#include <linux/netfilter_ipv4/ip_conntrack_rtsp.h> + #include <linux/netfilter_ipv4/ip_conntrack_amanda.h> +  + #include <linux/netfilter_ipv4/ip_conntrack_ftp.h> +@@ -78,6 +79,7 @@ + /* per expectation: application helper private data */ + union ip_conntrack_expect_help { + 	/* insert conntrack helper private data (expect) here */ ++	struct ip_ct_rtsp_expect exp_rtsp_info; + 	struct ip_ct_amanda_expect exp_amanda_info; + 	struct ip_ct_ftp_expect exp_ftp_info; + 	struct ip_ct_irc_expect exp_irc_info; +@@ -96,6 +98,7 @@ + /* per conntrack: application helper private data */ + union ip_conntrack_help { + 	/* insert conntrack helper private data (master) here */ ++	struct ip_ct_rtsp_master ct_rtsp_info; + 	struct ip_ct_ftp_master ct_ftp_info; + 	struct ip_ct_irc_master ct_irc_info; + 	struct ip_ct_pptp_master ct_pptp_info; +diff -urN linux-2.4.32.orig/include/linux/netfilter_ipv4/ip_conntrack_rtsp.h linux-2.4.32/include/linux/netfilter_ipv4/ip_conntrack_rtsp.h +--- linux-2.4.32.orig/include/linux/netfilter_ipv4/ip_conntrack_rtsp.h	1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.32/include/linux/netfilter_ipv4/ip_conntrack_rtsp.h	2005-12-29 12:18:26.000000000 +0100 +@@ -0,0 +1,68 @@ ++/* ++ * RTSP extension for IP connection tracking. ++ * (C) 2003 by Tom Marshall <tmarshall@real.com> ++ * based on ip_conntrack_irc.h ++ * ++ *      This program is free software; you can redistribute it and/or ++ *      modify it under the terms of the GNU General Public License ++ *      as published by the Free Software Foundation; either version ++ *      2 of the License, or (at your option) any later version. ++ */ ++#ifndef _IP_CONNTRACK_RTSP_H ++#define _IP_CONNTRACK_RTSP_H ++ ++/* #define IP_NF_RTSP_DEBUG */ ++#define IP_NF_RTSP_VERSION "0.01" ++ ++/* port block types */ ++typedef enum { ++    pb_single,  /* client_port=x */ ++    pb_range,   /* client_port=x-y */ ++    pb_discon   /* client_port=x/y (rtspbis) */ ++} portblock_t; ++ ++/* We record seq number and length of rtsp headers here, all in host order. */ ++ ++/* ++ * This structure is per expected connection.  It is a member of struct ++ * ip_conntrack_expect.  The TCP SEQ for the conntrack expect is stored ++ * there and we are expected to only store the length of the data which ++ * needs replaced.  If a packet contains multiple RTSP messages, we create ++ * one expected connection per message. ++ * ++ * We use these variables to mark the entire header block.  This may seem ++ * like overkill, but the nature of RTSP requires it.  A header may appear ++ * multiple times in a message.  We must treat two Transport headers the ++ * same as one Transport header with two entries. ++ */ ++struct ip_ct_rtsp_expect ++{ ++    u_int32_t   len;        /* length of header block */ ++    portblock_t pbtype;     /* Type of port block that was requested */ ++    u_int16_t   loport;     /* Port that was requested, low or first */ ++    u_int16_t   hiport;     /* Port that was requested, high or second */ ++#if 0 ++    uint        method;     /* RTSP method */ ++    uint        cseq;       /* CSeq from request */ ++#endif ++}; ++ ++/* This structure exists only once per master */ ++struct ip_ct_rtsp_master ++{ ++    /* Empty (?) */ ++}; ++ ++ ++#ifdef __KERNEL__ ++ ++#include <linux/netfilter_ipv4/lockhelp.h> ++ ++#define RTSP_PORT   554 ++ ++/* Protects rtsp part of conntracks */ ++DECLARE_LOCK_EXTERN(ip_rtsp_lock); ++ ++#endif /* __KERNEL__ */ ++ ++#endif /* _IP_CONNTRACK_RTSP_H */ +diff -urN linux-2.4.32.orig/include/linux/netfilter_mime.h linux-2.4.32/include/linux/netfilter_mime.h +--- linux-2.4.32.orig/include/linux/netfilter_mime.h	1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.32/include/linux/netfilter_mime.h	2005-12-29 12:18:26.000000000 +0100 +@@ -0,0 +1,90 @@ ++/* ++ * MIME functions for netfilter modules.  This file provides implementations ++ * for basic MIME parsing.  MIME headers are used in many protocols, such as ++ * HTTP, RTSP, SIP, etc. ++ * ++ * gcc will warn for defined but unused functions, so we only include the ++ * functions requested.  The following macros are used: ++ *   NF_NEED_MIME_NEXTLINE      nf_mime_nextline() ++ */ ++#ifndef _NETFILTER_MIME_H ++#define _NETFILTER_MIME_H ++ ++/* Only include these functions for kernel code. */ ++#ifdef __KERNEL__ ++ ++#include <linux/kernel.h> ++#include <linux/ctype.h> ++ ++/* ++ * Given a buffer and length, advance to the next line and mark the current ++ * line.  If the current line is empty, *plinelen will be set to zero.  If ++ * not, it will be set to the actual line length (including CRLF). ++ * ++ * 'line' in this context means logical line (includes LWS continuations). ++ * Returns 1 on success, 0 on failure. ++ */ ++#ifdef NF_NEED_MIME_NEXTLINE ++static int ++nf_mime_nextline(char* p, uint len, uint* poff, uint* plineoff, uint* plinelen) ++{ ++    uint    off = *poff; ++    uint    physlen = 0; ++    int     is_first_line = 1; ++ ++    if (off >= len) ++    { ++        return 0; ++    } ++ ++    do ++    { ++        while (p[off] != '\n') ++        { ++            if (len-off <= 1) ++            { ++                return 0; ++            } ++ ++            physlen++; ++            off++; ++        } ++ ++        /* if we saw a crlf, physlen needs adjusted */ ++        if (physlen > 0 && p[off] == '\n' && p[off-1] == '\r') ++        { ++            physlen--; ++        } ++ ++        /* advance past the newline */ ++        off++; ++ ++        /* check for an empty line */ ++        if (physlen == 0) ++        { ++            break; ++        } ++ ++        /* check for colon on the first physical line */ ++        if (is_first_line) ++        { ++            is_first_line = 0; ++            if (memchr(p+(*poff), ':', physlen) == NULL) ++            { ++                return 0; ++            } ++        } ++    } ++    while (p[off] == ' ' || p[off] == '\t'); ++ ++    *plineoff = *poff; ++    *plinelen = (physlen == 0) ? 0 : (off - *poff); ++    *poff = off; ++ ++    return 1; ++} ++#endif /* NF_NEED_MIME_NEXTLINE */ ++ ++#endif /* __KERNEL__ */ ++ ++#endif /* _NETFILTER_MIME_H */ +diff -urN linux-2.4.32.orig/net/ipv4/netfilter/Config.in linux-2.4.32/net/ipv4/netfilter/Config.in +--- linux-2.4.32.orig/net/ipv4/netfilter/Config.in	2005-12-29 12:17:55.000000000 +0100 ++++ linux-2.4.32/net/ipv4/netfilter/Config.in	2005-12-29 12:20:42.000000000 +0100 +@@ -18,6 +18,7 @@ +   dep_tristate '  SIP protocol support' CONFIG_IP_NF_SIP $CONFIG_IP_NF_CONNTRACK +   dep_tristate '  H.323 (netmeeting) support' CONFIG_IP_NF_H323 $CONFIG_IP_NF_CONNTRACK +   dep_tristate '  MMS protocol support' CONFIG_IP_NF_MMS $CONFIG_IP_NF_CONNTRACK ++  dep_tristate '  RTSP protocol support' CONFIG_IP_NF_RTSP $CONFIG_IP_NF_CONNTRACK + fi +  + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then +@@ -128,6 +129,13 @@ + 	  define_tristate CONFIG_IP_NF_NAT_MMS $CONFIG_IP_NF_NAT + 	fi +       fi ++      if [ "$CONFIG_IP_NF_RTSP" = "m" ]; then ++        define_tristate CONFIG_IP_NF_NAT_RTSP m ++      else ++	if [ "$CONFIG_IP_NF_RTSP" = "y" ]; then ++	  define_tristate CONFIG_IP_NF_NAT_RTSP $CONFIG_IP_NF_NAT ++	fi ++      fi +       if [ "$CONFIG_IP_NF_AMANDA" = "m" ]; then +         define_tristate CONFIG_IP_NF_NAT_AMANDA m +       else +diff -urN linux-2.4.32.orig/net/ipv4/netfilter/ip_conntrack_rtsp.c linux-2.4.32/net/ipv4/netfilter/ip_conntrack_rtsp.c +--- linux-2.4.32.orig/net/ipv4/netfilter/ip_conntrack_rtsp.c	1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.32/net/ipv4/netfilter/ip_conntrack_rtsp.c	2005-12-29 12:18:26.000000000 +0100 +@@ -0,0 +1,507 @@ ++/* ++ * RTSP extension for IP connection tracking ++ * (C) 2003 by Tom Marshall <tmarshall@real.com> ++ * based on ip_conntrack_irc.c ++ * ++ *      This program is free software; you can redistribute it and/or ++ *      modify it under the terms of the GNU General Public License ++ *      as published by the Free Software Foundation; either version ++ *      2 of the License, or (at your option) any later version. ++ * ++ * Module load syntax: ++ *   insmod ip_conntrack_rtsp.o ports=port1,port2,...port<MAX_PORTS> ++ *                              max_outstanding=n setup_timeout=secs ++ * ++ * If no ports are specified, the default will be port 554. ++ * ++ * With max_outstanding you can define the maximum number of not yet ++ * answered SETUP requests per RTSP session (default 8). ++ * With setup_timeout you can specify how long the system waits for ++ * an expected data channel (default 300 seconds). ++ */ ++ ++#include <linux/config.h> ++#include <linux/module.h> ++#include <linux/netfilter.h> ++#include <linux/ip.h> ++#include <net/checksum.h> ++#include <net/tcp.h> ++ ++#include <linux/netfilter_ipv4/lockhelp.h> ++#include <linux/netfilter_ipv4/ip_conntrack_helper.h> ++#include <linux/netfilter_ipv4/ip_conntrack_rtsp.h> ++ ++#include <linux/ctype.h> ++#define NF_NEED_STRNCASECMP ++#define NF_NEED_STRTOU16 ++#define NF_NEED_STRTOU32 ++#define NF_NEED_NEXTLINE ++#include <linux/netfilter_helpers.h> ++#define NF_NEED_MIME_NEXTLINE ++#include <linux/netfilter_mime.h> ++ ++#define MAX_SIMUL_SETUP 8 /* XXX: use max_outstanding */ ++ ++#define INFOP(fmt, args...) printk(KERN_INFO "%s: %s: " fmt, __FILE__, __FUNCTION__ , ## args) ++#ifdef IP_NF_RTSP_DEBUG ++#define DEBUGP(fmt, args...) printk(KERN_DEBUG "%s: %s: " fmt, __FILE__, __FUNCTION__ , ## args) ++#else ++#define DEBUGP(fmt, args...) ++#endif ++ ++#define MAX_PORTS 8 ++static int ports[MAX_PORTS]; ++static int num_ports = 0; ++static int max_outstanding = 8; ++static unsigned int setup_timeout = 300; ++ ++MODULE_AUTHOR("Tom Marshall <tmarshall@real.com>"); ++MODULE_DESCRIPTION("RTSP connection tracking module"); ++MODULE_LICENSE("GPL"); ++#ifdef MODULE_PARM ++MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i"); ++MODULE_PARM_DESC(ports, "port numbers of RTSP servers"); ++MODULE_PARM(max_outstanding, "i"); ++MODULE_PARM_DESC(max_outstanding, "max number of outstanding SETUP requests per RTSP session"); ++MODULE_PARM(setup_timeout, "i"); ++MODULE_PARM_DESC(setup_timeout, "timeout on for unestablished data channels"); ++#endif ++ ++DECLARE_LOCK(ip_rtsp_lock); ++struct module* ip_conntrack_rtsp = THIS_MODULE; ++ ++/* ++ * Max mappings we will allow for one RTSP connection (for RTP, the number ++ * of allocated ports is twice this value).  Note that SMIL burns a lot of ++ * ports so keep this reasonably high.  If this is too low, you will see a ++ * lot of "no free client map entries" messages. ++ */ ++#define MAX_PORT_MAPS 16 ++ ++/*** default port list was here in the masq code: 554, 3030, 4040 ***/ ++ ++#define SKIP_WSPACE(ptr,len,off) while(off < len && isspace(*(ptr+off))) { off++; } ++ ++/* ++ * Parse an RTSP packet. ++ * ++ * Returns zero if parsing failed. ++ * ++ * Parameters: ++ *  IN      ptcp        tcp data pointer ++ *  IN      tcplen      tcp data len ++ *  IN/OUT  ptcpoff     points to current tcp offset ++ *  OUT     phdrsoff    set to offset of rtsp headers ++ *  OUT     phdrslen    set to length of rtsp headers ++ *  OUT     pcseqoff    set to offset of CSeq header ++ *  OUT     pcseqlen    set to length of CSeq header ++ */ ++static int ++rtsp_parse_message(char* ptcp, uint tcplen, uint* ptcpoff, ++                   uint* phdrsoff, uint* phdrslen, ++                   uint* pcseqoff, uint* pcseqlen) ++{ ++    uint    entitylen = 0; ++    uint    lineoff; ++    uint    linelen; ++ ++    if (!nf_nextline(ptcp, tcplen, ptcpoff, &lineoff, &linelen)) ++    { ++        return 0; ++    } ++ ++    *phdrsoff = *ptcpoff; ++    while (nf_mime_nextline(ptcp, tcplen, ptcpoff, &lineoff, &linelen)) ++    { ++        if (linelen == 0) ++        { ++            if (entitylen > 0) ++            { ++                *ptcpoff += min(entitylen, tcplen - *ptcpoff); ++            } ++            break; ++        } ++        if (lineoff+linelen > tcplen) ++        { ++            INFOP("!! overrun !!\n"); ++            break; ++        } ++ ++        if (nf_strncasecmp(ptcp+lineoff, "CSeq:", 5) == 0) ++        { ++            *pcseqoff = lineoff; ++            *pcseqlen = linelen; ++        } ++        if (nf_strncasecmp(ptcp+lineoff, "Content-Length:", 15) == 0) ++        { ++            uint off = lineoff+15; ++            SKIP_WSPACE(ptcp+lineoff, linelen, off); ++            nf_strtou32(ptcp+off, &entitylen); ++        } ++    } ++    *phdrslen = (*ptcpoff) - (*phdrsoff); ++ ++    return 1; ++} ++ ++/* ++ * Find lo/hi client ports (if any) in transport header ++ * In: ++ *   ptcp, tcplen = packet ++ *   tranoff, tranlen = buffer to search ++ * ++ * Out: ++ *   pport_lo, pport_hi = lo/hi ports (host endian) ++ * ++ * Returns nonzero if any client ports found ++ * ++ * Note: it is valid (and expected) for the client to request multiple ++ * transports, so we need to parse the entire line. ++ */ ++static int ++rtsp_parse_transport(char* ptran, uint tranlen, ++                     struct ip_ct_rtsp_expect* prtspexp) ++{ ++    int     rc = 0; ++    uint    off = 0; ++ ++    if (tranlen < 10 || !iseol(ptran[tranlen-1]) || ++        nf_strncasecmp(ptran, "Transport:", 10) != 0) ++    { ++        INFOP("sanity check failed\n"); ++        return 0; ++    } ++    DEBUGP("tran='%.*s'\n", (int)tranlen, ptran); ++    off += 10; ++    SKIP_WSPACE(ptran, tranlen, off); ++ ++    /* Transport: tran;field;field=val,tran;field;field=val,... */ ++    while (off < tranlen) ++    { ++        const char* pparamend; ++        uint        nextparamoff; ++ ++        pparamend = memchr(ptran+off, ',', tranlen-off); ++        pparamend = (pparamend == NULL) ? ptran+tranlen : pparamend+1; ++        nextparamoff = pparamend-ptran; ++ ++        while (off < nextparamoff) ++        { ++            const char* pfieldend; ++            uint        nextfieldoff; ++ ++            pfieldend = memchr(ptran+off, ';', nextparamoff-off); ++            nextfieldoff = (pfieldend == NULL) ? nextparamoff : pfieldend-ptran+1; ++ ++            if (strncmp(ptran+off, "client_port=", 12) == 0) ++            { ++                u_int16_t   port; ++                uint        numlen; ++ ++                off += 12; ++                numlen = nf_strtou16(ptran+off, &port); ++                off += numlen; ++                if (prtspexp->loport != 0 && prtspexp->loport != port) ++                { ++                    DEBUGP("multiple ports found, port %hu ignored\n", port); ++                } ++                else ++                { ++                    prtspexp->loport = prtspexp->hiport = port; ++                    if (ptran[off] == '-') ++                    { ++                        off++; ++                        numlen = nf_strtou16(ptran+off, &port); ++                        off += numlen; ++                        prtspexp->pbtype = pb_range; ++                        prtspexp->hiport = port; ++ ++                        // If we have a range, assume rtp: ++                        // loport must be even, hiport must be loport+1 ++                        if ((prtspexp->loport & 0x0001) != 0 || ++                            prtspexp->hiport != prtspexp->loport+1) ++                        { ++                            DEBUGP("incorrect range: %hu-%hu, correcting\n", ++                                   prtspexp->loport, prtspexp->hiport); ++                            prtspexp->loport &= 0xfffe; ++                            prtspexp->hiport = prtspexp->loport+1; ++                        } ++                    } ++                    else if (ptran[off] == '/') ++                    { ++                        off++; ++                        numlen = nf_strtou16(ptran+off, &port); ++                        off += numlen; ++                        prtspexp->pbtype = pb_discon; ++                        prtspexp->hiport = port; ++                    } ++                    rc = 1; ++                } ++            } ++ ++            /* ++             * Note we don't look for the destination parameter here. ++             * If we are using NAT, the NAT module will handle it.  If not, ++             * and the client is sending packets elsewhere, the expectation ++             * will quietly time out. ++             */ ++ ++            off = nextfieldoff; ++        } ++ ++        off = nextparamoff; ++    } ++ ++    return rc; ++} ++ ++/*** conntrack functions ***/ ++ ++/* outbound packet: client->server */ ++static int ++help_out(const struct iphdr* iph, size_t pktlen, ++                struct ip_conntrack* ct, enum ip_conntrack_info ctinfo) ++{ ++    int dir = CTINFO2DIR(ctinfo);   /* = IP_CT_DIR_ORIGINAL */ ++    struct  tcphdr* tcph = (void*)iph + iph->ihl * 4; ++    uint    tcplen = pktlen - iph->ihl * 4; ++    char*   pdata = (char*)tcph + tcph->doff * 4; ++    uint    datalen = tcplen - tcph->doff * 4; ++    uint    dataoff = 0; ++ ++    struct ip_conntrack_expect exp; ++ ++    while (dataoff < datalen) ++    { ++        uint    cmdoff = dataoff; ++        uint    hdrsoff = 0; ++        uint    hdrslen = 0; ++        uint    cseqoff = 0; ++        uint    cseqlen = 0; ++        uint    lineoff = 0; ++        uint    linelen = 0; ++        uint    off; ++        int     rc; ++ ++        if (!rtsp_parse_message(pdata, datalen, &dataoff, ++                                &hdrsoff, &hdrslen, ++                                &cseqoff, &cseqlen)) ++        { ++            break;      /* not a valid message */ ++        } ++ ++        if (strncmp(pdata+cmdoff, "SETUP ", 6) != 0) ++        { ++            continue;   /* not a SETUP message */ ++        } ++        DEBUGP("found a setup message\n"); ++ ++        memset(&exp, 0, sizeof(exp)); ++ ++        off = 0; ++        while (nf_mime_nextline(pdata+hdrsoff, hdrslen, &off, ++                                &lineoff, &linelen)) ++        { ++            if (linelen == 0) ++            { ++                break; ++            } ++            if (off > hdrsoff+hdrslen) ++            { ++                INFOP("!! overrun !!"); ++                break; ++            } ++ ++            if (nf_strncasecmp(pdata+hdrsoff+lineoff, "Transport:", 10) == 0) ++            { ++                rtsp_parse_transport(pdata+hdrsoff+lineoff, linelen, ++                                     &exp.help.exp_rtsp_info); ++            } ++        } ++ ++        if (exp.help.exp_rtsp_info.loport == 0) ++        { ++            DEBUGP("no udp transports found\n"); ++            continue;   /* no udp transports found */ ++        } ++ ++        DEBUGP("udp transport found, ports=(%d,%hu,%hu)\n", ++              (int)exp.help.exp_rtsp_info.pbtype, ++              exp.help.exp_rtsp_info.loport, ++              exp.help.exp_rtsp_info.hiport); ++ ++        LOCK_BH(&ip_rtsp_lock); ++        exp.seq = ntohl(tcph->seq) + hdrsoff; /* mark all the headers */ ++        exp.help.exp_rtsp_info.len = hdrslen; ++ ++        exp.tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip; ++        exp.mask.src.ip  = 0xffffffff; ++        exp.tuple.dst.ip = ct->tuplehash[dir].tuple.src.ip; ++        exp.mask.dst.ip  = 0xffffffff; ++        exp.tuple.dst.u.udp.port = exp.help.exp_rtsp_info.loport; ++        exp.mask.dst.u.udp.port  = (exp.help.exp_rtsp_info.pbtype == pb_range) ? 0xfffe : 0xffff; ++        exp.tuple.dst.protonum = IPPROTO_UDP; ++        exp.mask.dst.protonum  = 0xffff; ++ ++        DEBUGP("expect_related %u.%u.%u.%u:%u-%u.%u.%u.%u:%u\n", ++                NIPQUAD(exp.tuple.src.ip), ++                ntohs(exp.tuple.src.u.tcp.port), ++                NIPQUAD(exp.tuple.dst.ip), ++                ntohs(exp.tuple.dst.u.tcp.port)); ++ ++        /* pass the request off to the nat helper */ ++        rc = ip_conntrack_expect_related(ct, &exp); ++        UNLOCK_BH(&ip_rtsp_lock); ++        if (rc == 0) ++        { ++            DEBUGP("ip_conntrack_expect_related succeeded\n"); ++        } ++        else ++        { ++            INFOP("ip_conntrack_expect_related failed (%d)\n", rc); ++        } ++    } ++ ++    return NF_ACCEPT; ++} ++ ++/* inbound packet: server->client */ ++static int ++help_in(const struct iphdr* iph, size_t pktlen, ++                struct ip_conntrack* ct, enum ip_conntrack_info ctinfo) ++{ ++    return NF_ACCEPT; ++} ++ ++static int ++help(const struct iphdr* iph, size_t pktlen, ++                struct ip_conntrack* ct, enum ip_conntrack_info ctinfo) ++{ ++    /* tcplen not negative guarenteed by ip_conntrack_tcp.c */ ++    struct tcphdr* tcph = (void*)iph + iph->ihl * 4; ++    u_int32_t tcplen = pktlen - iph->ihl * 4; ++ ++    /* Until there's been traffic both ways, don't look in packets. */ ++    if (ctinfo != IP_CT_ESTABLISHED && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) ++    { ++        DEBUGP("conntrackinfo = %u\n", ctinfo); ++        return NF_ACCEPT; ++    } ++ ++    /* Not whole TCP header? */ ++    if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4) ++    { ++        DEBUGP("tcplen = %u\n", (unsigned)tcplen); ++        return NF_ACCEPT; ++    } ++ ++    /* Checksum invalid?  Ignore. */ ++    /* FIXME: Source route IP option packets --RR */ ++    if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr, ++                     csum_partial((char*)tcph, tcplen, 0))) ++    { ++        DEBUGP("bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n", ++               tcph, tcplen, NIPQUAD(iph->saddr), NIPQUAD(iph->daddr)); ++        return NF_ACCEPT; ++    } ++ ++    switch (CTINFO2DIR(ctinfo)) ++    { ++    case IP_CT_DIR_ORIGINAL: ++        help_out(iph, pktlen, ct, ctinfo); ++        break; ++    case IP_CT_DIR_REPLY: ++        help_in(iph, pktlen, ct, ctinfo); ++        break; ++    } ++ ++    return NF_ACCEPT; ++} ++ ++static struct ip_conntrack_helper rtsp_helpers[MAX_PORTS]; ++static char rtsp_names[MAX_PORTS][10]; ++ ++/* This function is intentionally _NOT_ defined as __exit */ ++static void ++fini(void) ++{ ++    int i; ++    for (i = 0; i < num_ports; i++) ++    { ++        DEBUGP("unregistering port %d\n", ports[i]); ++        ip_conntrack_helper_unregister(&rtsp_helpers[i]); ++    } ++} ++ ++static int __init ++init(void) ++{ ++    int i, ret; ++    struct ip_conntrack_helper *hlpr; ++    char *tmpname; ++ ++    printk("ip_conntrack_rtsp v" IP_NF_RTSP_VERSION " loading\n"); ++ ++    if (max_outstanding < 1) ++    { ++        printk("ip_conntrack_rtsp: max_outstanding must be a positive integer\n"); ++        return -EBUSY; ++    } ++    if (setup_timeout < 0) ++    { ++        printk("ip_conntrack_rtsp: setup_timeout must be a positive integer\n"); ++        return -EBUSY; ++    } ++ ++    /* If no port given, default to standard rtsp port */ ++    if (ports[0] == 0) ++    { ++        ports[0] = RTSP_PORT; ++    } ++ ++    for (i = 0; (i < MAX_PORTS) && ports[i]; i++) ++    { ++        hlpr = &rtsp_helpers[i]; ++        memset(hlpr, 0, sizeof(struct ip_conntrack_helper)); ++        hlpr->tuple.src.u.tcp.port = htons(ports[i]); ++        hlpr->tuple.dst.protonum = IPPROTO_TCP; ++        hlpr->mask.src.u.tcp.port = 0xFFFF; ++        hlpr->mask.dst.protonum = 0xFFFF; ++        hlpr->max_expected = max_outstanding; ++        hlpr->timeout = setup_timeout; ++        hlpr->flags = IP_CT_HELPER_F_REUSE_EXPECT; ++        hlpr->me = ip_conntrack_rtsp; ++        hlpr->help = help; ++ ++        tmpname = &rtsp_names[i][0]; ++        if (ports[i] == RTSP_PORT) ++        { ++            sprintf(tmpname, "rtsp"); ++        } ++        else ++        { ++            sprintf(tmpname, "rtsp-%d", i); ++        } ++        hlpr->name = tmpname; ++ ++        DEBUGP("port #%d: %d\n", i, ports[i]); ++ ++        ret = ip_conntrack_helper_register(hlpr); ++ ++        if (ret) ++        { ++            printk("ip_conntrack_rtsp: ERROR registering port %d\n", ports[i]); ++            fini(); ++            return -EBUSY; ++        } ++        num_ports++; ++    } ++    return 0; ++} ++ ++#ifdef CONFIG_IP_NF_NAT_NEEDED ++EXPORT_SYMBOL(ip_rtsp_lock); ++#endif ++ ++module_init(init); ++module_exit(fini); +diff -urN linux-2.4.32.orig/net/ipv4/netfilter/ip_nat_rtsp.c linux-2.4.32/net/ipv4/netfilter/ip_nat_rtsp.c +--- linux-2.4.32.orig/net/ipv4/netfilter/ip_nat_rtsp.c	1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.32/net/ipv4/netfilter/ip_nat_rtsp.c	2005-12-29 12:18:26.000000000 +0100 +@@ -0,0 +1,621 @@ ++/* ++ * RTSP extension for TCP NAT alteration ++ * (C) 2003 by Tom Marshall <tmarshall@real.com> ++ * based on ip_nat_irc.c ++ * ++ *      This program is free software; you can redistribute it and/or ++ *      modify it under the terms of the GNU General Public License ++ *      as published by the Free Software Foundation; either version ++ *      2 of the License, or (at your option) any later version. ++ * ++ * Module load syntax: ++ *      insmod ip_nat_rtsp.o ports=port1,port2,...port<MAX_PORTS> ++ *                           stunaddr=<address> ++ *                           destaction=[auto|strip|none] ++ * ++ * If no ports are specified, the default will be port 554 only. ++ * ++ * stunaddr specifies the address used to detect that a client is using STUN. ++ * If this address is seen in the destination parameter, it is assumed that ++ * the client has already punched a UDP hole in the firewall, so we don't ++ * mangle the client_port.  If none is specified, it is autodetected.  It ++ * only needs to be set if you have multiple levels of NAT.  It should be ++ * set to the external address that the STUN clients detect.  Note that in ++ * this case, it will not be possible for clients to use UDP with servers ++ * between the NATs. ++ * ++ * If no destaction is specified, auto is used. ++ *   destaction=auto:  strip destination parameter if it is not stunaddr. ++ *   destaction=strip: always strip destination parameter (not recommended). ++ *   destaction=none:  do not touch destination parameter (not recommended). ++ */ ++ ++#include <linux/module.h> ++#include <linux/netfilter_ipv4.h> ++#include <linux/ip.h> ++#include <linux/tcp.h> ++#include <linux/kernel.h> ++#include <net/tcp.h> ++#include <linux/netfilter_ipv4/ip_nat.h> ++#include <linux/netfilter_ipv4/ip_nat_helper.h> ++#include <linux/netfilter_ipv4/ip_nat_rule.h> ++#include <linux/netfilter_ipv4/ip_conntrack_rtsp.h> ++#include <linux/netfilter_ipv4/ip_conntrack_helper.h> ++ ++#include <linux/inet.h> ++#include <linux/ctype.h> ++#define NF_NEED_STRNCASECMP ++#define NF_NEED_STRTOU16 ++#include <linux/netfilter_helpers.h> ++#define NF_NEED_MIME_NEXTLINE ++#include <linux/netfilter_mime.h> ++ ++#define INFOP(fmt, args...) printk(KERN_INFO "%s: %s: " fmt, __FILE__, __FUNCTION__ , ## args) ++#ifdef IP_NF_RTSP_DEBUG ++#define DEBUGP(fmt, args...) printk(KERN_DEBUG "%s: %s: " fmt, __FILE__, __FUNCTION__ , ## args) ++#else ++#define DEBUGP(fmt, args...) ++#endif ++ ++#define MAX_PORTS       8 ++#define DSTACT_AUTO     0 ++#define DSTACT_STRIP    1 ++#define DSTACT_NONE     2 ++ ++static int      ports[MAX_PORTS]; ++static char*    stunaddr = NULL; ++static char*    destaction = NULL; ++ ++static int       num_ports = 0; ++static u_int32_t extip = 0; ++static int       dstact = 0; ++ ++MODULE_AUTHOR("Tom Marshall <tmarshall@real.com>"); ++MODULE_DESCRIPTION("RTSP network address translation module"); ++MODULE_LICENSE("GPL"); ++#ifdef MODULE_PARM ++MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i"); ++MODULE_PARM_DESC(ports, "port numbers of RTSP servers"); ++MODULE_PARM(stunaddr, "s"); ++MODULE_PARM_DESC(stunaddr, "Address for detecting STUN"); ++MODULE_PARM(destaction, "s"); ++MODULE_PARM_DESC(destaction, "Action for destination parameter (auto/strip/none)"); ++#endif ++ ++/* protects rtsp part of conntracks */ ++DECLARE_LOCK_EXTERN(ip_rtsp_lock); ++ ++#define SKIP_WSPACE(ptr,len,off) while(off < len && isspace(*(ptr+off))) { off++; } ++ ++/*** helper functions ***/ ++ ++static void ++get_skb_tcpdata(struct sk_buff* skb, char** pptcpdata, uint* ptcpdatalen) ++{ ++    struct iphdr*   iph  = (struct iphdr*)skb->nh.iph; ++    struct tcphdr*  tcph = (struct tcphdr*)((char*)iph + iph->ihl*4); ++ ++    *pptcpdata = (char*)tcph + tcph->doff*4; ++    *ptcpdatalen = ((char*)skb->h.raw + skb->len) - *pptcpdata; ++} ++ ++/*** nat functions ***/ ++ ++/* ++ * Mangle the "Transport:" header: ++ *   - Replace all occurences of "client_port=<spec>" ++ *   - Handle destination parameter ++ * ++ * In: ++ *   ct, ctinfo = conntrack context ++ *   pskb       = packet ++ *   tranoff    = Transport header offset from TCP data ++ *   tranlen    = Transport header length (incl. CRLF) ++ *   rport_lo   = replacement low  port (host endian) ++ *   rport_hi   = replacement high port (host endian) ++ * ++ * Returns packet size difference. ++ * ++ * Assumes that a complete transport header is present, ending with CR or LF ++ */ ++static int ++rtsp_mangle_tran(struct ip_conntrack* ct, enum ip_conntrack_info ctinfo, ++                 struct ip_conntrack_expect* exp, ++                 struct sk_buff** pskb, uint tranoff, uint tranlen) ++{ ++    char*       ptcp; ++    uint        tcplen; ++    char*       ptran; ++    char        rbuf1[16];      /* Replacement buffer (one port) */ ++    uint        rbuf1len;       /* Replacement len (one port) */ ++    char        rbufa[16];      /* Replacement buffer (all ports) */ ++    uint        rbufalen;       /* Replacement len (all ports) */ ++    u_int32_t   newip; ++    u_int16_t   loport, hiport; ++    uint        off = 0; ++    uint        diff;           /* Number of bytes we removed */ ++ ++    struct ip_ct_rtsp_expect* prtspexp = &exp->help.exp_rtsp_info; ++    struct ip_conntrack_tuple t; ++ ++    char    szextaddr[15+1]; ++    uint    extaddrlen; ++    int     is_stun; ++ ++    get_skb_tcpdata(*pskb, &ptcp, &tcplen); ++    ptran = ptcp+tranoff; ++ ++    if (tranoff+tranlen > tcplen || tcplen-tranoff < tranlen || ++        tranlen < 10 || !iseol(ptran[tranlen-1]) || ++        nf_strncasecmp(ptran, "Transport:", 10) != 0) ++    { ++        INFOP("sanity check failed\n"); ++        return 0; ++    } ++    off += 10; ++    SKIP_WSPACE(ptcp+tranoff, tranlen, off); ++ ++    newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; ++    t = exp->tuple; ++    t.dst.ip = newip; ++ ++    extaddrlen = extip ? sprintf(szextaddr, "%u.%u.%u.%u", NIPQUAD(extip)) ++                       : sprintf(szextaddr, "%u.%u.%u.%u", NIPQUAD(newip)); ++    DEBUGP("stunaddr=%s (%s)\n", szextaddr, (extip?"forced":"auto")); ++ ++    rbuf1len = rbufalen = 0; ++    switch (prtspexp->pbtype) ++    { ++    case pb_single: ++        for (loport = prtspexp->loport; loport != 0; loport++) /* XXX: improper wrap? */ ++        { ++            t.dst.u.udp.port = htons(loport); ++            if (ip_conntrack_change_expect(exp, &t) == 0) ++            { ++                DEBUGP("using port %hu\n", loport); ++                break; ++            } ++        } ++        if (loport != 0) ++        { ++            rbuf1len = sprintf(rbuf1, "%hu", loport); ++            rbufalen = sprintf(rbufa, "%hu", loport); ++        } ++        break; ++    case pb_range: ++        for (loport = prtspexp->loport; loport != 0; loport += 2) /* XXX: improper wrap? */ ++        { ++            t.dst.u.udp.port = htons(loport); ++            if (ip_conntrack_change_expect(exp, &t) == 0) ++            { ++                hiport = loport + ~exp->mask.dst.u.udp.port; ++                DEBUGP("using ports %hu-%hu\n", loport, hiport); ++                break; ++            } ++        } ++        if (loport != 0) ++        { ++            rbuf1len = sprintf(rbuf1, "%hu", loport); ++            rbufalen = sprintf(rbufa, "%hu-%hu", loport, loport+1); ++        } ++        break; ++    case pb_discon: ++        for (loport = prtspexp->loport; loport != 0; loport++) /* XXX: improper wrap? */ ++        { ++            t.dst.u.udp.port = htons(loport); ++            if (ip_conntrack_change_expect(exp, &t) == 0) ++            { ++                DEBUGP("using port %hu (1 of 2)\n", loport); ++                break; ++            } ++        } ++        for (hiport = prtspexp->hiport; hiport != 0; hiport++) /* XXX: improper wrap? */ ++        { ++            t.dst.u.udp.port = htons(hiport); ++            if (ip_conntrack_change_expect(exp, &t) == 0) ++            { ++                DEBUGP("using port %hu (2 of 2)\n", hiport); ++                break; ++            } ++        } ++        if (loport != 0 && hiport != 0) ++        { ++            rbuf1len = sprintf(rbuf1, "%hu", loport); ++            if (hiport == loport+1) ++            { ++                rbufalen = sprintf(rbufa, "%hu-%hu", loport, hiport); ++            } ++            else ++            { ++                rbufalen = sprintf(rbufa, "%hu/%hu", loport, hiport); ++            } ++        } ++        break; ++    } ++ ++    if (rbuf1len == 0) ++    { ++        return 0;   /* cannot get replacement port(s) */ ++    } ++ ++    /* Transport: tran;field;field=val,tran;field;field=val,... */ ++    while (off < tranlen) ++    { ++        uint        saveoff; ++        const char* pparamend; ++        uint        nextparamoff; ++ ++        pparamend = memchr(ptran+off, ',', tranlen-off); ++        pparamend = (pparamend == NULL) ? ptran+tranlen : pparamend+1; ++        nextparamoff = pparamend-ptcp; ++ ++        /* ++         * We pass over each param twice.  On the first pass, we look for a ++         * destination= field.  It is handled by the security policy.  If it ++         * is present, allowed, and equal to our external address, we assume ++         * that STUN is being used and we leave the client_port= field alone. ++         */ ++        is_stun = 0; ++        saveoff = off; ++        while (off < nextparamoff) ++        { ++            const char* pfieldend; ++            uint        nextfieldoff; ++ ++            pfieldend = memchr(ptran+off, ';', nextparamoff-off); ++            nextfieldoff = (pfieldend == NULL) ? nextparamoff : pfieldend-ptran+1; ++ ++            if (dstact != DSTACT_NONE && strncmp(ptran+off, "destination=", 12) == 0) ++            { ++                if (strncmp(ptran+off+12, szextaddr, extaddrlen) == 0) ++                { ++                    is_stun = 1; ++                } ++                if (dstact == DSTACT_STRIP || (dstact == DSTACT_AUTO && !is_stun)) ++                { ++                    diff = nextfieldoff-off; ++                    if (!ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, ++                                                         off, diff, NULL, 0)) ++                    { ++                        /* mangle failed, all we can do is bail */ ++                        return 0; ++                    } ++                    get_skb_tcpdata(*pskb, &ptcp, &tcplen); ++                    ptran = ptcp+tranoff; ++                    tranlen -= diff; ++                    nextparamoff -= diff; ++                    nextfieldoff -= diff; ++                } ++            } ++ ++            off = nextfieldoff; ++        } ++        if (is_stun) ++        { ++            continue; ++        } ++        off = saveoff; ++        while (off < nextparamoff) ++        { ++            const char* pfieldend; ++            uint        nextfieldoff; ++ ++            pfieldend = memchr(ptran+off, ';', nextparamoff-off); ++            nextfieldoff = (pfieldend == NULL) ? nextparamoff : pfieldend-ptran+1; ++ ++            if (strncmp(ptran+off, "client_port=", 12) == 0) ++            { ++                u_int16_t   port; ++                uint        numlen; ++                uint        origoff; ++                uint        origlen; ++                char*       rbuf    = rbuf1; ++                uint        rbuflen = rbuf1len; ++ ++                off += 12; ++                origoff = (ptran-ptcp)+off; ++                origlen = 0; ++                numlen = nf_strtou16(ptran+off, &port); ++                off += numlen; ++                origlen += numlen; ++                if (port != prtspexp->loport) ++                { ++                    DEBUGP("multiple ports found, port %hu ignored\n", port); ++                } ++                else ++                { ++                    if (ptran[off] == '-' || ptran[off] == '/') ++                    { ++                        off++; ++                        origlen++; ++                        numlen = nf_strtou16(ptran+off, &port); ++                        off += numlen; ++                        origlen += numlen; ++                        rbuf = rbufa; ++                        rbuflen = rbufalen; ++                    } ++ ++                    /* ++                     * note we cannot just memcpy() if the sizes are the same. ++                     * the mangle function does skb resizing, checks for a ++                     * cloned skb, and updates the checksums. ++                     * ++                     * parameter 4 below is offset from start of tcp data. ++                     */ ++                    diff = origlen-rbuflen; ++                    if (!ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, ++                                              origoff, origlen, rbuf, rbuflen)) ++                    { ++                        /* mangle failed, all we can do is bail */ ++                        return 0; ++                    } ++                    get_skb_tcpdata(*pskb, &ptcp, &tcplen); ++                    ptran = ptcp+tranoff; ++                    tranlen -= diff; ++                    nextparamoff -= diff; ++                    nextfieldoff -= diff; ++                } ++            } ++ ++            off = nextfieldoff; ++        } ++ ++        off = nextparamoff; ++    } ++ ++    return 1; ++} ++ ++static unsigned int ++expected(struct sk_buff **pskb, uint hooknum, struct ip_conntrack* ct, struct ip_nat_info* info) ++{ ++    struct ip_nat_multi_range mr; ++    u_int32_t newdstip, newsrcip, newip; ++ ++    struct ip_conntrack *master = master_ct(ct); ++ ++    IP_NF_ASSERT(info); ++    IP_NF_ASSERT(master); ++ ++    IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum)))); ++ ++    newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; ++    newsrcip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; ++    newip = (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC) ? newsrcip : newdstip; ++ ++    DEBUGP("newsrcip=%u.%u.%u.%u, newdstip=%u.%u.%u.%u, newip=%u.%u.%u.%u\n", ++           NIPQUAD(newsrcip), NIPQUAD(newdstip), NIPQUAD(newip)); ++ ++    mr.rangesize = 1; ++    /* We don't want to manip the per-protocol, just the IPs. */ ++    mr.range[0].flags = IP_NAT_RANGE_MAP_IPS; ++    mr.range[0].min_ip = mr.range[0].max_ip = newip; ++ ++    return ip_nat_setup_info(ct, &mr, hooknum); ++} ++ ++static uint ++help_out(struct ip_conntrack* ct, enum ip_conntrack_info ctinfo, ++         struct ip_conntrack_expect* exp, struct sk_buff** pskb) ++{ ++    char*   ptcp; ++    uint    tcplen; ++    uint    hdrsoff; ++    uint    hdrslen; ++    uint    lineoff; ++    uint    linelen; ++    uint    off; ++ ++    struct iphdr* iph = (struct iphdr*)(*pskb)->nh.iph; ++    struct tcphdr* tcph = (struct tcphdr*)((void*)iph + iph->ihl*4); ++ ++    struct ip_ct_rtsp_expect* prtspexp = &exp->help.exp_rtsp_info; ++ ++    get_skb_tcpdata(*pskb, &ptcp, &tcplen); ++ ++    hdrsoff = exp->seq - ntohl(tcph->seq); ++    hdrslen = prtspexp->len; ++    off = hdrsoff; ++ ++    while (nf_mime_nextline(ptcp, hdrsoff+hdrslen, &off, &lineoff, &linelen)) ++    { ++        if (linelen == 0) ++        { ++            break; ++        } ++        if (off > hdrsoff+hdrslen) ++        { ++            INFOP("!! overrun !!"); ++            break; ++        } ++        DEBUGP("hdr: len=%u, %.*s", linelen, (int)linelen, ptcp+lineoff); ++ ++        if (nf_strncasecmp(ptcp+lineoff, "Transport:", 10) == 0) ++        { ++            uint oldtcplen = tcplen; ++            if (!rtsp_mangle_tran(ct, ctinfo, exp, pskb, lineoff, linelen)) ++            { ++                break; ++            } ++            get_skb_tcpdata(*pskb, &ptcp, &tcplen); ++            hdrslen -= (oldtcplen-tcplen); ++            off -= (oldtcplen-tcplen); ++            lineoff -= (oldtcplen-tcplen); ++            linelen -= (oldtcplen-tcplen); ++            DEBUGP("rep: len=%u, %.*s", linelen, (int)linelen, ptcp+lineoff); ++        } ++    } ++ ++    return NF_ACCEPT; ++} ++ ++static uint ++help_in(struct ip_conntrack* ct, enum ip_conntrack_info ctinfo, ++         struct ip_conntrack_expect* exp, struct sk_buff** pskb) ++{ ++    /* XXX: unmangle */ ++    return NF_ACCEPT; ++} ++ ++static uint ++help(struct ip_conntrack* ct, ++     struct ip_conntrack_expect* exp, ++     struct ip_nat_info* info, ++     enum ip_conntrack_info ctinfo, ++     unsigned int hooknum, ++     struct sk_buff** pskb) ++{ ++    struct iphdr*  iph  = (struct iphdr*)(*pskb)->nh.iph; ++    struct tcphdr* tcph = (struct tcphdr*)((char*)iph + iph->ihl * 4); ++    uint datalen; ++    int dir; ++    struct ip_ct_rtsp_expect* ct_rtsp_info; ++    int rc = NF_ACCEPT; ++ ++    if (ct == NULL || exp == NULL || info == NULL || pskb == NULL) ++    { ++        DEBUGP("!! null ptr (%p,%p,%p,%p) !!\n", ct, exp, info, pskb); ++        return NF_ACCEPT; ++    } ++ ++    ct_rtsp_info = &exp->help.exp_rtsp_info; ++ ++    /* ++     * Only mangle things once: original direction in POST_ROUTING ++     * and reply direction on PRE_ROUTING. ++     */ ++    dir = CTINFO2DIR(ctinfo); ++    if (!((hooknum == NF_IP_POST_ROUTING && dir == IP_CT_DIR_ORIGINAL) ++          || (hooknum == NF_IP_PRE_ROUTING && dir == IP_CT_DIR_REPLY))) ++    { ++        DEBUGP("Not touching dir %s at hook %s\n", ++               dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY", ++               hooknum == NF_IP_POST_ROUTING ? "POSTROUTING" ++               : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING" ++               : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???"); ++        return NF_ACCEPT; ++    } ++    DEBUGP("got beyond not touching\n"); ++ ++    datalen = (*pskb)->len - iph->ihl * 4 - tcph->doff * 4; ++ ++    LOCK_BH(&ip_rtsp_lock); ++    /* Ensure the packet contains all of the marked data */ ++    if (!between(exp->seq + ct_rtsp_info->len, ++                 ntohl(tcph->seq), ntohl(tcph->seq) + datalen)) ++    { ++        /* Partial retransmission?  Probably a hacker. */ ++        if (net_ratelimit()) ++        { ++            INFOP("partial packet %u/%u in %u/%u\n", ++                   exp->seq, ct_rtsp_info->len, ntohl(tcph->seq), ntohl(tcph->seq) + datalen); ++        } ++        UNLOCK_BH(&ip_rtsp_lock); ++        return NF_DROP; ++    } ++ ++    switch (dir) ++    { ++    case IP_CT_DIR_ORIGINAL: ++        rc = help_out(ct, ctinfo, exp, pskb); ++        break; ++    case IP_CT_DIR_REPLY: ++        rc = help_in(ct, ctinfo, exp, pskb); ++        break; ++    } ++    UNLOCK_BH(&ip_rtsp_lock); ++ ++    return rc; ++} ++ ++static struct ip_nat_helper ip_nat_rtsp_helpers[MAX_PORTS]; ++static char rtsp_names[MAX_PORTS][10]; ++ ++/* This function is intentionally _NOT_ defined as  __exit */ ++static void ++fini(void) ++{ ++    int i; ++ ++    for (i = 0; i < num_ports; i++) ++    { ++        DEBUGP("unregistering helper for port %d\n", ports[i]); ++        ip_nat_helper_unregister(&ip_nat_rtsp_helpers[i]); ++    } ++} ++ ++static int __init ++init(void) ++{ ++    int ret = 0; ++    int i; ++    struct ip_nat_helper* hlpr; ++    char* tmpname; ++ ++    printk("ip_nat_rtsp v" IP_NF_RTSP_VERSION " loading\n"); ++ ++    if (ports[0] == 0) ++    { ++        ports[0] = RTSP_PORT; ++    } ++ ++    for (i = 0; (i < MAX_PORTS) && ports[i] != 0; i++) ++    { ++        hlpr = &ip_nat_rtsp_helpers[i]; ++        memset(hlpr, 0, sizeof(struct ip_nat_helper)); ++ ++        hlpr->tuple.dst.protonum = IPPROTO_TCP; ++        hlpr->tuple.src.u.tcp.port = htons(ports[i]); ++        hlpr->mask.src.u.tcp.port = 0xFFFF; ++        hlpr->mask.dst.protonum = 0xFFFF; ++        hlpr->help = help; ++        hlpr->flags = 0; ++        hlpr->me = THIS_MODULE; ++        hlpr->expect = expected; ++ ++        tmpname = &rtsp_names[i][0]; ++        if (ports[i] == RTSP_PORT) ++        { ++                sprintf(tmpname, "rtsp"); ++        } ++        else ++        { ++                sprintf(tmpname, "rtsp-%d", i); ++        } ++        hlpr->name = tmpname; ++ ++        DEBUGP("registering helper for port %d: name %s\n", ports[i], hlpr->name); ++        ret = ip_nat_helper_register(hlpr); ++ ++        if (ret) ++        { ++            printk("ip_nat_rtsp: error registering helper for port %d\n", ports[i]); ++            fini(); ++            return 1; ++        } ++        num_ports++; ++    } ++    if (stunaddr != NULL) ++    { ++        extip = in_aton(stunaddr); ++    } ++    if (destaction != NULL) ++    { ++        if (strcmp(destaction, "auto") == 0) ++        { ++            dstact = DSTACT_AUTO; ++        } ++        if (strcmp(destaction, "strip") == 0) ++        { ++            dstact = DSTACT_STRIP; ++        } ++        if (strcmp(destaction, "none") == 0) ++        { ++            dstact = DSTACT_NONE; ++        } ++    } ++    return ret; ++} ++ ++module_init(init); ++module_exit(fini); +diff -urN linux-2.4.32.orig/net/ipv4/netfilter/Makefile linux-2.4.32/net/ipv4/netfilter/Makefile +--- linux-2.4.32.orig/net/ipv4/netfilter/Makefile	2005-12-29 12:17:55.000000000 +0100 ++++ linux-2.4.32/net/ipv4/netfilter/Makefile	2005-12-29 12:18:26.000000000 +0100 +@@ -32,6 +32,14 @@ + obj-$(CONFIG_IP_NF_CONNTRACK) += ip_conntrack.o +  + # connection tracking helpers ++ ++# rtsp protocol support ++obj-$(CONFIG_IP_NF_RTSP) += ip_conntrack_rtsp.o ++ifdef CONFIG_IP_NF_NAT_RTSP ++       export-objs += ip_conntrack_rtsp.o ++endif ++obj-$(CONFIG_IP_NF_NAT_RTSP) += ip_nat_rtsp.o ++ + obj-$(CONFIG_IP_NF_AMANDA) += ip_conntrack_amanda.o + ifdef CONFIG_IP_NF_AMANDA + 	export-objs += ip_conntrack_amanda.o diff --git a/target/linux/netfilter.mk b/target/linux/netfilter.mk index 401632033..f272a8548 100644 --- a/target/linux/netfilter.mk +++ b/target/linux/netfilter.mk @@ -62,6 +62,8 @@ IPT_NAT_EXTRA-$(CONFIG_IP_NF_H323) += ip_conntrack_h323  IPT_NAT_EXTRA-$(CONFIG_IP_NF_NAT_H323) += ip_nat_h323  IPT_NAT_EXTRA-$(CONFIG_IP_NF_MMS) += ip_conntrack_mms  IPT_NAT_EXTRA-$(CONFIG_IP_NF_NAT_MMS) += ip_nat_mms +IPT_NAT_EXTRA-$(CONFIG_IP_NF_RTSP) += ip_conntrack_rtsp +IPT_NAT_EXTRA-$(CONFIG_IP_NF_NAT_RTSP) += ip_nat_rtsp  IPT_NAT_EXTRA-$(CONFIG_IP_NF_PPTP) += ip_conntrack_pptp  IPT_NAT_EXTRA-$(CONFIG_IP_NF_NAT_PPTP) += ip_nat_pptp  IPT_NAT_EXTRA-$(CONFIG_IP_NF_NAT_SNMP_BASIC) += ip_nat_snmp_basic | 
