diff options
-rw-r--r-- | mk/modules.mk | 8 | ||||
-rw-r--r-- | package/Config.in | 1 | ||||
-rw-r--r-- | package/nand/src/nand.c | 2 | ||||
-rw-r--r-- | package/rtsp/Makefile | 6 | ||||
-rw-r--r-- | package/rtsp/src/nf_conntrack_rtsp.c | 30 | ||||
-rw-r--r-- | package/rtsp/src/nf_nat_rtsp.c | 48 | ||||
-rw-r--r-- | target/linux/config/Config.in.netfilter | 1 | ||||
-rw-r--r-- | target/linux/config/Config.in.netfilter.core | 10 | ||||
-rw-r--r-- | target/linux/patches/2.6.33/rtsp.patch | 2316 |
9 files changed, 88 insertions, 2334 deletions
diff --git a/mk/modules.mk b/mk/modules.mk index 7ab35b74d..fce15c190 100644 --- a/mk/modules.mk +++ b/mk/modules.mk @@ -394,10 +394,10 @@ $(eval $(call KMOD_template,NF_CONNTRACK_TFTP,nf-conntrack-tftp,\ $(MODULES_DIR)/kernel/net/ipv4/netfilter/nf_nat_tftp \ ,55)) -$(eval $(call KMOD_template,NF_CONNTRACK_RTSP,nf-conntrack-rtsp,\ - $(MODULES_DIR)/kernel/net/netfilter/nf_conntrack_rtsp \ - $(MODULES_DIR)/kernel/net/ipv4/netfilter/nf_nat_rtsp \ -,55)) +#$(eval $(call KMOD_template,NF_CONNTRACK_RTSP,nf-conntrack-rtsp,\ +# $(MODULES_DIR)/kernel/net/netfilter/nf_conntrack_rtsp \ +# $(MODULES_DIR)/kernel/net/ipv4/netfilter/nf_nat_rtsp \ +#,55)) # broken #$(eval $(call KMOD_template,NF_CONNTRACK_AMANDA,nf-conntrack-amanda,\ diff --git a/package/Config.in b/package/Config.in index 37f1e4e92..5f1a0bdd4 100644 --- a/package/Config.in +++ b/package/Config.in @@ -693,4 +693,5 @@ endmenu menu "Kernel configuration" source "target/linux/Config.in" +source "package/rtsp/Config.in" endmenu diff --git a/package/nand/src/nand.c b/package/nand/src/nand.c index 0d5d7f0e4..225e866e2 100644 --- a/package/nand/src/nand.c +++ b/package/nand/src/nand.c @@ -494,7 +494,7 @@ usage(void) " -q quiet mode\n" " -r reboot after successful command\n" "Example: To write linux.img to mtd partition labeled as linux\n" - " mtd write linux.img linux\n\n"); + " nand write linux.img linux\n\n"); exit(1); } diff --git a/package/rtsp/Makefile b/package/rtsp/Makefile index c28467b9b..994852f04 100644 --- a/package/rtsp/Makefile +++ b/package/rtsp/Makefile @@ -22,10 +22,10 @@ BUILD_STYLE:= manual INSTALL_STYLE:= manual pre-build: - V=1 ARCH=${ARCH} KERNELDIR=${LINUX_DIR} \ + ARCH=${ARCH} KERNELDIR=${LINUX_DIR} \ PREFIX=/usr CROSS_COMPILE="${TARGET_CROSS}" \ - LD=$(TARGET_CROSS)gcc LDFLAGS="" \ - $(MAKE) -C ${WRKBUILD} debug + LD=$(TARGET_CROSS)gcc LDFLAGS="" CFLAGS="-Wall" \ + $(MAKE) -C ${WRKBUILD} debug V=1 do-install: ${INSTALL_DIR} ${IDIR_KMOD_RTSP}/etc/modules.d/ diff --git a/package/rtsp/src/nf_conntrack_rtsp.c b/package/rtsp/src/nf_conntrack_rtsp.c index c1002aca9..7b5d2be67 100644 --- a/package/rtsp/src/nf_conntrack_rtsp.c +++ b/package/rtsp/src/nf_conntrack_rtsp.c @@ -177,14 +177,15 @@ rtsp_parse_transport(char* ptran, uint tranlen, pr_info("sanity check failed\n"); return 0; } - - pr_debug("tran='%.*s'\n", (int)tranlen, ptran); + + pr_debug("t='%.*s'\n", (int)tranlen-2, ptran); off += 10; SKIP_WSPACE(ptran, tranlen, off); /* Transport: tran;field;field=val,tran;field;field=val,... */ while (off < tranlen) { const char* pparamend; + const char* pdestport; uint nextparamoff; pparamend = memchr(ptran+off, ',', tranlen-off); @@ -236,6 +237,31 @@ rtsp_parse_transport(char* ptran, uint tranlen, rc = 1; } } + else if ((strncmp(ptran+off, "destination=",12) == 0) && + ((pdestport = memchr(ptran+off, ':', nextparamoff-off)) != NULL)) + { + u_int16_t port; + uint numlen; + + off += 12; + pdestport++; + + off = pdestport - ptran; + numlen = nf_strtou16(ptran + off, &port); + off += numlen + 1; + + if (prtspexp->loport != 0 && prtspexp->loport != port) + { + pr_debug("multiple ports found, port %hu ignored\n", port); + } + else + { + prtspexp->pbtype = pb_single; + prtspexp->loport = port; + prtspexp->hiport = port; + rc = 1; + } + } /* * Note we don't look for the destination parameter here. diff --git a/package/rtsp/src/nf_nat_rtsp.c b/package/rtsp/src/nf_nat_rtsp.c index 6ec6aa4f8..adb44d0ae 100644 --- a/package/rtsp/src/nf_nat_rtsp.c +++ b/package/rtsp/src/nf_nat_rtsp.c @@ -129,7 +129,7 @@ rtsp_mangle_tran(enum ip_conntrack_info ctinfo, tranlen < 10 || !iseol(ptran[tranlen-1]) || nf_strncasecmp(ptran, "Transport:", 10) != 0) { - pr_info("sanity check failed\n"); + pr_debug("sanity check failed\n"); return 0; } off += 10; @@ -245,6 +245,7 @@ rtsp_mangle_tran(enum ip_conntrack_info ctinfo, 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) @@ -257,7 +258,6 @@ rtsp_mangle_tran(enum ip_conntrack_info ctinfo, if (!nf_nat_mangle_tcp_packet(skb, ct, ctinfo, off, diff, NULL, 0)) { - /* mangle failed, all we can do is bail */ nf_ct_unexpect_related(exp); return 0; } @@ -268,6 +268,7 @@ rtsp_mangle_tran(enum ip_conntrack_info ctinfo, nextfieldoff -= diff; } } + */ off = nextfieldoff; } @@ -279,6 +280,7 @@ rtsp_mangle_tran(enum ip_conntrack_info ctinfo, while (off < nextparamoff) { const char* pfieldend; + const char* pdestport; uint nextfieldoff; pfieldend = memchr(ptran+off, ';', nextparamoff-off); @@ -338,6 +340,46 @@ rtsp_mangle_tran(enum ip_conntrack_info ctinfo, nextfieldoff -= diff; } } + else if ((strncmp(ptran+off, "destination=", 12) == 0) && ((pdestport = memchr(ptran+off+12, ':', nextparamoff-(off + 12))) != NULL)) + { + u_int16_t port; + uint numlen; + uint origoff; + uint origlen; + char rbuf[32]; + uint rbuflen = sprintf(rbuf, "%s:%s",szextaddr,rbuf1); + + pdestport++; + + off += 12; + origoff = (ptran + off) - ptcp; + origlen = pdestport - (ptran + off); + off += origlen; + numlen = nf_strtou16(ptran+off, &port); + off += numlen; + origlen += numlen; + + if (port != prtspexp->loport) + { + pr_debug("multiple ports found, port %hu ignored\n", port); + } + else + { + diff = origlen-rbuflen; + if (!nf_nat_mangle_tcp_packet(skb, ct, ctinfo, + origoff, origlen, rbuf, rbuflen)) + { + /* mangle failed, all we can do is bail */ + nf_ct_unexpect_related(exp); + return 0; + } + get_skb_tcpdata(skb, &ptcp, &tcplen); + ptran = ptcp+tranoff; + tranlen -= diff; + nextparamoff -= diff; + nextfieldoff -= diff; + } + } off = nextfieldoff; } @@ -378,7 +420,7 @@ help_out(struct sk_buff *skb, enum ip_conntrack_info ctinfo, } if (off > hdrsoff+hdrslen) { - pr_info("!! overrun !!"); + pr_debug("!! overrun !!"); break; } pr_debug("hdr: len=%u, %.*s", linelen, (int)linelen, ptcp+lineoff); diff --git a/target/linux/config/Config.in.netfilter b/target/linux/config/Config.in.netfilter index cb71b6551..dbc686b0a 100644 --- a/target/linux/config/Config.in.netfilter +++ b/target/linux/config/Config.in.netfilter @@ -156,6 +156,7 @@ endmenu menu "Netfilter Addons" source package/ipset/Config.in.kmod +source package/rtsp/Config.in.kmod endmenu endmenu diff --git a/target/linux/config/Config.in.netfilter.core b/target/linux/config/Config.in.netfilter.core index 0231b2d13..e2e9a2bbb 100644 --- a/target/linux/config/Config.in.netfilter.core +++ b/target/linux/config/Config.in.netfilter.core @@ -82,11 +82,11 @@ config ADK_KPACKAGE_KMOD_NF_CONNTRACK_FTP required for tracking them, and doing masquerading and other forms of Network Address Translation on them. -config ADK_KPACKAGE_KMOD_NF_CONNTRACK_RTSP - tristate 'RTSP protocol support' - depends on ADK_KPACKAGE_KMOD_NF_CONNTRACK - help - Tracking RTSP connections might be required for IPTV. +#config ADK_KPACKAGE_KMOD_NF_CONNTRACK_RTSP +# tristate 'RTSP protocol support' +# depends on ADK_KPACKAGE_KMOD_NF_CONNTRACK +# help +# Tracking RTSP connections might be required for IPTV. config ADK_KPACKAGE_KMOD_NF_CONNTRACK_IRC tristate 'IRC protocol support' diff --git a/target/linux/patches/2.6.33/rtsp.patch b/target/linux/patches/2.6.33/rtsp.patch deleted file mode 100644 index 317c06d8e..000000000 --- a/target/linux/patches/2.6.33/rtsp.patch +++ /dev/null @@ -1,2316 +0,0 @@ -diff -Nur linux-2.6.33.orig/include/linux/netfilter/nf_conntrack_rtsp.h linux-2.6.33/include/linux/netfilter/nf_conntrack_rtsp.h ---- linux-2.6.33.orig/include/linux/netfilter/nf_conntrack_rtsp.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33/include/linux/netfilter/nf_conntrack_rtsp.h 2010-04-25 01:09:20.000000000 +0200 -@@ -0,0 +1,63 @@ -+/* -+ * RTSP extension for IP connection tracking. -+ * (C) 2003 by Tom Marshall <tmarshall at 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 1 -+#define IP_NF_RTSP_VERSION "0.6.21" -+ -+#ifdef __KERNEL__ -+/* 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 -+}; -+ -+extern unsigned int (*nf_nat_rtsp_hook)(struct sk_buff *skb, -+ enum ip_conntrack_info ctinfo, -+ unsigned int matchoff, unsigned int matchlen, -+ struct ip_ct_rtsp_expect *prtspexp, -+ struct nf_conntrack_expect *exp); -+ -+extern void (*nf_nat_rtsp_hook_expectfn)(struct nf_conn *ct, struct nf_conntrack_expect *exp); -+ -+#define RTSP_PORT 554 -+ -+#endif /* __KERNEL__ */ -+ -+#endif /* _IP_CONNTRACK_RTSP_H */ -diff -Nur linux-2.6.33.orig/include/linux/netfilter_helpers.h linux-2.6.33/include/linux/netfilter_helpers.h ---- linux-2.6.33.orig/include/linux/netfilter_helpers.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33/include/linux/netfilter_helpers.h 2010-04-25 01:09:20.000000000 +0200 -@@ -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 -Nur linux-2.6.33.orig/include/linux/netfilter_mime.h linux-2.6.33/include/linux/netfilter_mime.h ---- linux-2.6.33.orig/include/linux/netfilter_mime.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33/include/linux/netfilter_mime.h 2010-04-25 01:09:20.000000000 +0200 -@@ -0,0 +1,89 @@ -+/* -+ * 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/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 -Nur linux-2.6.33.orig/net/ipv4/netfilter/Kconfig linux-2.6.33/net/ipv4/netfilter/Kconfig ---- linux-2.6.33.orig/net/ipv4/netfilter/Kconfig 2010-02-24 19:52:17.000000000 +0100 -+++ linux-2.6.33/net/ipv4/netfilter/Kconfig 2010-04-25 01:09:20.000000000 +0200 -@@ -257,6 +257,11 @@ - depends on NF_CONNTRACK && NF_NAT - default NF_NAT && NF_CONNTRACK_IRC - -+config NF_NAT_RTSP -+ tristate -+ depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT -+ default NF_NAT && NF_CONNTRACK_RTSP -+ - config NF_NAT_TFTP - tristate - depends on NF_CONNTRACK && NF_NAT -diff -Nur linux-2.6.33.orig/net/ipv4/netfilter/Makefile linux-2.6.33/net/ipv4/netfilter/Makefile ---- linux-2.6.33.orig/net/ipv4/netfilter/Makefile 2010-02-24 19:52:17.000000000 +0100 -+++ linux-2.6.33/net/ipv4/netfilter/Makefile 2010-04-25 01:09:20.000000000 +0200 -@@ -26,6 +26,7 @@ - obj-$(CONFIG_NF_NAT_FTP) += nf_nat_ftp.o - obj-$(CONFIG_NF_NAT_H323) += nf_nat_h323.o - obj-$(CONFIG_NF_NAT_IRC) += nf_nat_irc.o -+obj-$(CONFIG_NF_NAT_RTSP) += nf_nat_rtsp.o - obj-$(CONFIG_NF_NAT_PPTP) += nf_nat_pptp.o - obj-$(CONFIG_NF_NAT_SIP) += nf_nat_sip.o - obj-$(CONFIG_NF_NAT_SNMP_BASIC) += nf_nat_snmp_basic.o -diff -Nur linux-2.6.33.orig/net/ipv4/netfilter/nf_nat_rtsp.c linux-2.6.33/net/ipv4/netfilter/nf_nat_rtsp.c ---- linux-2.6.33.orig/net/ipv4/netfilter/nf_nat_rtsp.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.33/net/ipv4/netfilter/nf_nat_rtsp.c 2010-04-25 01:09:20.000000000 +0200 -@@ -0,0 +1,496 @@ -+/* -+ * RTSP extension for TCP NAT alteration -+ * (C) 2003 by Tom Marshall <tmarshall at 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 nf_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 <net/tcp.h> -+#include <net/netfilter/nf_nat_helper.h> -+#include <net/netfilter/nf_nat_rule.h> -+#include <linux/netfilter/nf_conntrack_rtsp.h> -+#include <net/netfilter/nf_conntrack_expect.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) -+#if 0 -+#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 char* stunaddr = NULL; -+static char* destaction = NULL; -+ -+static u_int32_t extip = 0; -+static int dstact = 0; -+ -+MODULE_AUTHOR("Tom Marshall <tmarshall at real.com>"); -+MODULE_DESCRIPTION("RTSP network address translation module"); -+MODULE_LICENSE("GPL"); -+module_param(stunaddr, charp, 0644); -+MODULE_PARM_DESC(stunaddr, "Address for detecting STUN"); -+module_param(destaction, charp, 0644); -+MODULE_PARM_DESC(destaction, "Action for destination parameter (auto/strip/none)"); -+ -+#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 = ip_hdr(skb); -+ struct tcphdr* tcph = (void *)iph + ip_hdrlen(skb); -+ -+ *pptcpdata = (char*)tcph + tcph->doff*4; -+ *ptcpdatalen = ((char*)skb_transport_header(skb) + skb->len) - *pptcpdata; -+} -+ -+/*** nat functions ***/ -+ -+/* -+ * Mangle the "Transport:" header: -+ * - Replace all occurences of "client_port=<spec>" -+ * - Handle destination parameter -+ * -+ * In: -+ * ct, ctinfo = conntrack context -+ * skb = 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(enum ip_conntrack_info ctinfo, -+ struct nf_conntrack_expect* exp, -+ struct ip_ct_rtsp_expect* prtspexp, -+ struct sk_buff* skb, 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 nf_conn *ct = exp->master; -+ struct nf_conntrack_tuple *t; -+ -+ char szextaddr[15+1]; -+ uint extaddrlen; -+ int is_stun; -+ -+ get_skb_tcpdata(skb, &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.u3.ip; -+ t = &exp->tuple; -+ t->dst.u3.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 (nf_ct_expect_related(exp) == 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 (nf_ct_expect_related(exp) == 0) -+ { -+ hiport = loport + ~exp->mask.src.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 (nf_ct_expect_related(exp) == 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 (nf_ct_expect_related(exp) == 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 (!nf_nat_mangle_tcp_packet(skb, ct, ctinfo, -+ off, diff, NULL, 0)) -+ { -+ /* mangle failed, all we can do is bail */ -+ nf_ct_unexpect_related(exp); -+ return 0; -+ } -+ get_skb_tcpdata(skb, &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 (!nf_nat_mangle_tcp_packet(skb, ct, ctinfo, -+ origoff, origlen, rbuf, rbuflen)) -+ { -+ /* mangle failed, all we can do is bail */ -+ nf_ct_unexpect_related(exp); -+ return 0; -+ } -+ get_skb_tcpdata(skb, &ptcp, &tcplen); -+ ptran = ptcp+tranoff; -+ tranlen -= diff; -+ nextparamoff -= diff; -+ nextfieldoff -= diff; -+ } -+ } -+ -+ off = nextfieldoff; -+ } -+ -+ off = nextparamoff; -+ } -+ -+ return 1; -+} -+ -+static uint -+help_out(struct sk_buff *skb, enum ip_conntrack_info ctinfo, -+ unsigned int matchoff, unsigned int matchlen, struct ip_ct_rtsp_expect* prtspexp, -+ struct nf_conntrack_expect* exp) -+{ -+ char* ptcp; -+ uint tcplen; -+ uint hdrsoff; -+ uint hdrslen; -+ uint lineoff; -+ uint linelen; -+ uint off; -+ -+ //struct iphdr* iph = (struct iphdr*)skb->nh.iph; -+ //struct tcphdr* tcph = (struct tcphdr*)((void*)iph + iph->ihl*4); -+ -+ get_skb_tcpdata(skb, &ptcp, &tcplen); -+ hdrsoff = matchoff;//exp->seq - ntohl(tcph->seq); -+ hdrslen = matchlen; -+ off = hdrsoff; -+ DEBUGP("NAT rtsp help_out\n"); -+ -+ 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; -+ DEBUGP("hdr: Transport\n"); -+ if (!rtsp_mangle_tran(ctinfo, exp, prtspexp, skb, lineoff, linelen)) -+ { -+ DEBUGP("hdr: Transport mangle failed"); -+ break; -+ } -+ get_skb_tcpdata(skb, &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 unsigned int -+help(struct sk_buff *skb, enum ip_conntrack_info ctinfo, |