[OpenWrt-Devel] [PATCH] nf_conntrack_rtsp: update to latest version

Álvaro Fernández Rojas noltari at gmail.com
Tue Nov 4 14:30:59 EST 2014


Update nf_conntrack_rtsp to latest version based on http://mike.it-loops.com/rtsp/ (rtsp-module-3.7-v2.tar.gz).

Signed-off-by: Álvaro Fernández Rojas <noltari at gmail.com>
---
diff --git a/package/network/utils/xtables-addons/patches/100-add-rtsp-conntrack.patch b/package/network/utils/xtables-addons/patches/100-add-rtsp-conntrack.patch
index ef7917a..6c169ee 100644
--- a/package/network/utils/xtables-addons/patches/100-add-rtsp-conntrack.patch
+++ b/package/network/utils/xtables-addons/patches/100-add-rtsp-conntrack.patch
@@ -235,10 +235,23 @@
 +#endif /* _NETFILTER_MIME_H */
 --- /dev/null
 +++ b/extensions/rtsp/nf_conntrack_rtsp.c
-@@ -0,0 +1,519 @@
+@@ -0,0 +1,576 @@
 +/*
 + * RTSP extension for IP connection tracking
 + * (C) 2003 by Tom Marshall <tmarshall at real.com>
++ *
++ * 2005-02-13: Harald Welte <laforge at netfilter.org>
++ * 	- port to 2.6
++ * 	- update to recent post-2.6.11 api changes
++ * 2006-09-14: Steven Van Acker <deepstar at singularity.be>
++ *	- removed calls to NAT code from conntrack helper: NAT no longer needed to use rtsp-conntrack
++ * 2007-04-18: Michael Guntsche <mike at it-loops.com>
++ * 			- Port to new NF API
++ * 2013-03-04: Il'inykh Sergey <sergeyi at inango-sw.com>. Inango Systems Ltd
++ *	- fixed rtcp nat mapping and other port mapping fixes
++ *	- simple TEARDOWN request handling
++ *	- codestyle fixes and other less significant bug fixes 
++ *
 + * based on ip_conntrack_irc.c
 + *
 + *      This program is free software; you can redistribute it and/or
@@ -257,13 +270,6 @@
 + * With setup_timeout you can specify how long the system waits for
 + * an expected data channel (default 300 seconds).
 + *
-+ * 2005-02-13: Harald Welte <laforge at netfilter.org>
-+ * 	- port to 2.6
-+ * 	- update to recent post-2.6.11 api changes
-+ * 2006-09-14: Steven Van Acker <deepstar at singularity.be>
-+ *      - removed calls to NAT code from conntrack helper: NAT no longer needed to use rtsp-conntrack
-+ * 2007-04-18: Michael Guntsche <mike at it-loops.com>
-+ * 			- Port to new NF API
 + */
 +
 +#include <linux/module.h>
@@ -286,7 +292,6 @@
 +#include "netfilter_mime.h"
 +
 +#include <linux/ctype.h>
-+#define MAX_SIMUL_SETUP 8 /* XXX: use max_outstanding */
 +
 +#define MAX_PORTS 8
 +static int ports[MAX_PORTS];
@@ -307,13 +312,17 @@
 +static char *rtsp_buffer;
 +static DEFINE_SPINLOCK(rtsp_buffer_lock);
 +
-+static struct nf_conntrack_expect_policy rtsp_exp_policy; 
++static struct nf_conntrack_expect_policy rtsp_exp_policy;
 +
 +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);
-+void (*nf_nat_rtsp_hook_expectfn)(struct nf_conn *ct, struct nf_conntrack_expect *exp);
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
++				 unsigned int protoff,
++#endif
++				 unsigned int matchoff, unsigned int matchlen,
++				 struct ip_ct_rtsp_expect* prtspexp,
++				 struct nf_conntrack_expect *rtp_exp,
++				 struct nf_conntrack_expect *rtcp_exp);
 +
 +EXPORT_SYMBOL_GPL(nf_nat_rtsp_hook);
 +
@@ -345,13 +354,13 @@
 + */
 +static int
 +rtsp_parse_message(char* ptcp, uint tcplen, uint* ptcpoff,
-+                   uint* phdrsoff, uint* phdrslen,
-+                   uint* pcseqoff, uint* pcseqlen,
-+                   uint* transoff, uint* translen)
++		   uint* phdrsoff, uint* phdrslen,
++		   uint* pcseqoff, uint* pcseqlen,
++		   uint* transoff, uint* translen)
 +{
-+	uint    entitylen = 0;
-+	uint    lineoff;
-+	uint    linelen;
++	uint	entitylen = 0;
++	uint	lineoff;
++	uint	linelen;
 +	
 +	if (!nf_nextline(ptcp, tcplen, ptcpoff, &lineoff, &linelen))
 +		return 0;
@@ -367,7 +376,7 @@
 +			pr_info("!! overrun !!\n");
 +			break;
 +		}
-+		
++
 +		if (nf_strncasecmp(ptcp+lineoff, "CSeq:", 5) == 0) {
 +			*pcseqoff = lineoff;
 +			*pcseqlen = linelen;
@@ -405,10 +414,10 @@
 + */
 +static int
 +rtsp_parse_transport(char* ptran, uint tranlen,
-+                     struct ip_ct_rtsp_expect* prtspexp)
++		     struct ip_ct_rtsp_expect* prtspexp)
 +{
-+	int     rc = 0;
-+	uint    off = 0;
++	int  rc = 0;
++	uint off = 0;
 +	
 +	if (tranlen < 10 || !iseol(ptran[tranlen-1]) ||
 +	    nf_strncasecmp(ptran, "Transport:", 10) != 0) {
@@ -439,7 +448,7 @@
 +			if (strncmp(ptran+off, "client_port=", 12) == 0) {
 +				u_int16_t   port;
 +				uint        numlen;
-+		    
++
 +				off += 12;
 +				numlen = nf_strtou16(ptran+off, &port);
 +				off += numlen;
@@ -491,14 +500,6 @@
 +	return rc;
 +}
 +
-+void expected(struct nf_conn *ct, struct nf_conntrack_expect *exp)
-+{
-+		typeof(nf_nat_rtsp_hook_expectfn) nf_nat_rtsp_expectfn;
-+		nf_nat_rtsp_expectfn = rcu_dereference(nf_nat_rtsp_hook_expectfn);
-+    if(nf_nat_rtsp_expectfn && ct->master->status & IPS_NAT_MASK) {
-+        nf_nat_rtsp_expectfn(ct,exp);
-+    }
-+}
 +
 +/*** conntrack functions ***/
 +
@@ -506,7 +507,12 @@
 +
 +static inline int
 +help_out(struct sk_buff *skb, unsigned char *rb_ptr, unsigned int datalen,
-+                struct nf_conn *ct, enum ip_conntrack_info ctinfo)
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
++	 struct nf_conn *ct, enum ip_conntrack_info ctinfo,
++	 unsigned int protoff)
++#else
++	 struct nf_conn *ct, enum ip_conntrack_info ctinfo)
++#endif
 +{
 +	struct ip_ct_rtsp_expect expinfo;
 +	
@@ -518,38 +524,46 @@
 +	uint    dataoff = 0;
 +	int ret = NF_ACCEPT;
 +	
-+	struct nf_conntrack_expect *exp;
++	struct nf_conntrack_expect *rtp_exp;
++	struct nf_conntrack_expect *rtcp_exp = NULL;
 +	
 +	__be16 be_loport;
++	__be16 be_hiport;
 +	
 +	typeof(nf_nat_rtsp_hook) nf_nat_rtsp;
 +
 +	memset(&expinfo, 0, sizeof(expinfo));
 +	
 +	while (dataoff < datalen) {
-+		uint    cmdoff = dataoff;
-+		uint    hdrsoff = 0;
-+		uint    hdrslen = 0;
-+		uint    cseqoff = 0;
-+		uint    cseqlen = 0;
-+		uint    transoff = 0;
-+		uint    translen = 0;
-+		uint    off;
++		uint cmdoff = dataoff;
++		uint hdrsoff = 0;
++		uint hdrslen = 0;
++		uint cseqoff = 0;
++		uint cseqlen = 0;
++		uint transoff = 0;
++		uint translen = 0;
++		uint off;
 +		
 +		if (!rtsp_parse_message(pdata, datalen, &dataoff,
 +					&hdrsoff, &hdrslen,
 +					&cseqoff, &cseqlen,
 +					&transoff, &translen))
 +			break;      /* not a valid message */
-+		
++
++		if (strncmp(pdata+cmdoff, "TEARDOWN ", 9) == 0) {
++			pr_debug("teardown handled\n");
++			nf_ct_remove_expectations(ct); /* FIXME must be session id aware */
++			break;
++		}
++
 +		if (strncmp(pdata+cmdoff, "SETUP ", 6) != 0)
 +			continue;   /* not a SETUP message */
++
 +		pr_debug("found a setup message\n");
 +
 +		off = 0;
-+		if(translen) {
++		if(translen)
 +			rtsp_parse_transport(pdata+transoff, translen, &expinfo);
-+		}
 +
 +		if (expinfo.loport == 0) {
 +			pr_debug("no udp transports found\n");
@@ -557,45 +571,85 @@
 +		}
 +
 +		pr_debug("udp transport found, ports=(%d,%hu,%hu)\n",
-+		       (int)expinfo.pbtype, expinfo.loport, expinfo.hiport);
++			 (int)expinfo.pbtype, expinfo.loport, expinfo.hiport);
 +
-+		exp = nf_ct_expect_alloc(ct);
-+		if (!exp) {
++
++		be_loport = htons(expinfo.loport);
++
++		rtp_exp = nf_ct_expect_alloc(ct);
++		if (rtp_exp == NULL) {
 +			ret = NF_DROP;
 +			goto out;
 +		}
 +
-+		be_loport = htons(expinfo.loport);
++		nf_ct_expect_init(rtp_exp, NF_CT_EXPECT_CLASS_DEFAULT,
++				  nf_ct_l3num(ct),
++				  NULL, /* &ct->tuplehash[!dir].tuple.src.u3, */
++				  &ct->tuplehash[!dir].tuple.dst.u3,
++				  IPPROTO_UDP, NULL, &be_loport);
 +
-+		nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, nf_ct_l3num(ct),
-+			&ct->tuplehash[!dir].tuple.src.u3, &ct->tuplehash[!dir].tuple.dst.u3,
-+			IPPROTO_UDP, NULL, &be_loport); 
++		rtp_exp->flags = 0;
 +
-+		exp->master = ct;
++		if (expinfo.pbtype == pb_range) {
++			pr_debug("setup expectation for rtcp\n");
 +
-+		exp->expectfn = expected;
-+		exp->flags = 0;
++			be_hiport = htons(expinfo.hiport);
++			rtcp_exp = nf_ct_expect_alloc(ct);
++			if (rtcp_exp == NULL) {
++				ret = NF_DROP;
++				goto out1;
++			}
 +
-+		if (expinfo.pbtype == pb_range) {
-+			pr_debug("Changing expectation mask to handle multiple ports\n");
-+			//exp->mask.dst.u.udp.port  = 0xfffe;
++			nf_ct_expect_init(rtcp_exp, NF_CT_EXPECT_CLASS_DEFAULT,
++					  nf_ct_l3num(ct),
++					  NULL, /* &ct->tuplehash[!dir].tuple.src.u3, */
++					  &ct->tuplehash[!dir].tuple.dst.u3,
++					  IPPROTO_UDP, NULL, &be_hiport);
++
++			rtcp_exp->flags = 0;
++
++			pr_debug("expect_related %pI4:%u-%u-%pI4:%u-%u\n",
++				   &rtp_exp->tuple.src.u3.ip,
++				   ntohs(rtp_exp->tuple.src.u.udp.port),
++				   ntohs(rtcp_exp->tuple.src.u.udp.port),
++				   &rtp_exp->tuple.dst.u3.ip,
++				   ntohs(rtp_exp->tuple.dst.u.udp.port),
++				   ntohs(rtcp_exp->tuple.dst.u.udp.port));
++		} else {
++			pr_debug("expect_related %pI4:%u-%pI4:%u\n",
++					&rtp_exp->tuple.src.u3.ip,
++					ntohs(rtp_exp->tuple.src.u.udp.port),
++					&rtp_exp->tuple.dst.u3.ip,
++					ntohs(rtp_exp->tuple.dst.u.udp.port));
 +		}
 +
-+		pr_debug("expect_related %pI4:%u-%pI4:%u\n",
-+		       &exp->tuple.src.u3.ip,
-+		       ntohs(exp->tuple.src.u.udp.port),
-+		       &exp->tuple.dst.u3.ip,
-+		       ntohs(exp->tuple.dst.u.udp.port));
-+
 +		nf_nat_rtsp = rcu_dereference(nf_nat_rtsp_hook);
 +		if (nf_nat_rtsp && ct->status & IPS_NAT_MASK)
 +			/* pass the request off to the nat helper */
-+			ret = nf_nat_rtsp(skb, ctinfo, hdrsoff, hdrslen, &expinfo, exp);
-+		else if (nf_ct_expect_related(exp) != 0) {
-+			pr_info("nf_conntrack_expect_related failed\n");
-+			ret  = NF_DROP;
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
++			ret = nf_nat_rtsp(skb, ctinfo, protoff, hdrsoff, hdrslen,
++					  &expinfo, rtp_exp, rtcp_exp);
++#else
++			ret = nf_nat_rtsp(skb, ctinfo, hdrsoff, hdrslen,
++					  &expinfo, rtp_exp, rtcp_exp);
++#endif
++		else {
++			if (nf_ct_expect_related(rtp_exp) == 0) {
++				if (rtcp_exp && nf_ct_expect_related(rtcp_exp) != 0) {
++					nf_ct_unexpect_related(rtp_exp);
++					pr_info("nf_conntrack_expect_related failed for rtcp\n");
++					ret = NF_DROP;
++				}
++			} else {
++				pr_info("nf_conntrack_expect_related failed for rtp\n");
++				ret = NF_DROP;
++			}
 +		}
-+		nf_ct_expect_put(exp);
++		if (rtcp_exp) {
++			nf_ct_expect_put(rtcp_exp);
++		}
++out1:
++		nf_ct_expect_put(rtp_exp);
 +		goto out;
 +	}
 +out:
@@ -606,9 +660,9 @@
 +
 +static inline int
 +help_in(struct sk_buff *skb, size_t pktlen,
-+ struct nf_conn* ct, enum ip_conntrack_info ctinfo)
++	struct nf_conn* ct, enum ip_conntrack_info ctinfo)
 +{
-+ return NF_ACCEPT;
++	return NF_ACCEPT;
 +}
 +
 +static int help(struct sk_buff *skb, unsigned int protoff,
@@ -627,7 +681,7 @@
 +	} 
 +
 +	/* Not whole TCP header? */
-+	th = skb_header_pointer(skb,protoff, sizeof(_tcph), &_tcph);
++	th = skb_header_pointer(skb, protoff, sizeof(_tcph), &_tcph);
 +
 +	if (!th)
 +		return NF_ACCEPT;
@@ -657,7 +711,11 @@
 +
 +	switch (CTINFO2DIR(ctinfo)) {
 +	case IP_CT_DIR_ORIGINAL:
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
++		ret = help_out(skb, rb_ptr, datalen, ct, ctinfo, protoff);
++#else
 +		ret = help_out(skb, rb_ptr, datalen, ct, ctinfo);
++#endif
 +		break;
 +	case IP_CT_DIR_REPLY:
 +		pr_debug("IP_CT_DIR_REPLY\n");
@@ -704,8 +762,8 @@
 +		return -EBUSY;
 +	}
 +
-+  rtsp_exp_policy.max_expected = max_outstanding;
-+  rtsp_exp_policy.timeout = setup_timeout;
++	rtsp_exp_policy.max_expected = max_outstanding;
++	rtsp_exp_policy.timeout = setup_timeout;
 +	
 +	rtsp_buffer = kmalloc(65536, GFP_KERNEL);
 +	if (!rtsp_buffer) 
@@ -714,6 +772,7 @@
 +	/* If no port given, default to standard rtsp port */
 +	if (ports[0] == 0) {
 +		ports[0] = RTSP_PORT;
++		num_ports = 1;
 +	}
 +
 +	for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
@@ -722,8 +781,6 @@
 +		hlpr->tuple.src.l3num = AF_INET;
 +		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 = 0xFF;
 +		hlpr->expect_policy = &rtsp_exp_policy;
 +		hlpr->me = THIS_MODULE;
 +		hlpr->help = help;
@@ -734,8 +791,12 @@
 +		} else {
 +			sprintf(tmpname, "rtsp-%d", i);
 +		}
-+		hlpr->name = tmpname;
 +
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0)
++		strlcpy(hlpr->name, tmpname, sizeof(hlpr->name));
++#else
++		hlpr->name = tmpname;
++#endif
 +		pr_debug("port #%d: %d\n", i, ports[i]);
 +
 +		ret = nf_conntrack_helper_register(hlpr);
@@ -745,19 +806,15 @@
 +			fini();
 +			return -EBUSY;
 +		}
-+		num_ports++;
 +	}
 +	return 0;
 +}
 +
 +module_init(init);
 +module_exit(fini);
-+
-+EXPORT_SYMBOL(nf_nat_rtsp_hook_expectfn);
-+
 --- /dev/null
 +++ b/extensions/rtsp/nf_conntrack_rtsp.h
-@@ -0,0 +1,63 @@
+@@ -0,0 +1,72 @@
 +/*
 + * RTSP extension for IP connection tracking.
 + * (C) 2003 by Tom Marshall <tmarshall at real.com>
@@ -767,12 +824,18 @@
 + *      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.
-+ */
++ *
++ * 2013-03-04: Il'inykh Sergey <sergeyi at inango-sw.com>. Inango Systems Ltd
++ *	- conditional compilation for kernel 3.7
++ *	- port mapping improvements
++*/
 +#ifndef _IP_CONNTRACK_RTSP_H
 +#define _IP_CONNTRACK_RTSP_H
 +
++#include <linux/version.h>
++
 +//#define IP_NF_RTSP_DEBUG 1
-+#define IP_NF_RTSP_VERSION "0.6.21"
++#define IP_NF_RTSP_VERSION "0.7"
 +
 +#ifdef __KERNEL__
 +/* port block types */
@@ -809,12 +872,15 @@
 +};
 +
 +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);
++					enum ip_conntrack_info ctinfo,
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
++					unsigned int protoff,
++#endif
++					unsigned int matchoff,
++					unsigned int matchlen,
++					struct ip_ct_rtsp_expect *prtspexp,
++					struct nf_conntrack_expect *rtp_exp,
++					struct nf_conntrack_expect *rtcp_exp);
 +
 +#define RTSP_PORT   554
 +
@@ -823,21 +889,27 @@
 +#endif /* _IP_CONNTRACK_RTSP_H */
 --- /dev/null
 +++ b/extensions/rtsp/nf_nat_rtsp.c
-@@ -0,0 +1,491 @@
+@@ -0,0 +1,617 @@
 +/*
 + * RTSP extension for TCP NAT alteration
 + * (C) 2003 by Tom Marshall <tmarshall at real.com>
++ *
++ * 2013-03-04: Il'inykh Sergey <sergeyi at inango-sw.com>. Inango Systems Ltd
++ *	- fixed rtcp nat mapping and other port mapping fixes
++ *	- fixed system hard lock because of bug in the parser
++ *	- codestyle fixes and less significant fixes
++ *
 + * 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.
++ *	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]
++ *	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.
 + *
@@ -857,9 +929,14 @@
 + */
 +
 +#include <linux/module.h>
++#include <linux/version.h>
 +#include <net/tcp.h>
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
++# include <net/netfilter/nf_nat.h>
++#else
++# include <net/netfilter/nf_nat_rule.h>
++#endif
 +#include <net/netfilter/nf_nat_helper.h>
-+#include <net/netfilter/nf_nat_rule.h>
 +#include "nf_conntrack_rtsp.h"
 +#include <net/netfilter/nf_conntrack_expect.h>
 +
@@ -871,19 +948,19 @@
 +#define NF_NEED_MIME_NEXTLINE
 +#include "netfilter_mime.h"
 +
-+#include "../compat_xtables.h"
-+
-+#define MAX_PORTS       8
-+#define DSTACT_AUTO     0
-+#define DSTACT_STRIP    1
-+#define DSTACT_NONE     2
++#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 char* stunaddr = NULL;
++static char* destaction = NULL;
 +
 +static u_int32_t extip = 0;
 +static int       dstact = 0;
 +
++static void nf_nat_rtsp_expected(struct nf_conn* ct, struct nf_conntrack_expect *exp);
++
 +MODULE_AUTHOR("Tom Marshall <tmarshall at real.com>");
 +MODULE_DESCRIPTION("RTSP network address translation module");
 +MODULE_LICENSE("GPL");
@@ -899,13 +976,29 @@
 +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);
++	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;
++	*pptcpdata = (char*)tcph +  tcph->doff*4;
++	*ptcpdatalen = ((char*)skb_transport_header(skb) + skb->len) - *pptcpdata;
 +}
 +
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
++/* copy of sip_sprintf_addr */
++static int rtsp_sprintf_addr(const struct nf_conn *ct, char *buffer,
++			     const union nf_inet_addr *addr, bool delim)
++{
++	if (nf_ct_l3num(ct) == NFPROTO_IPV4) {
++		return sprintf(buffer, "%pI4", &addr->ip);
++	} else {
++		if (delim)
++			return sprintf(buffer, "[%pI6c]", &addr->ip6);
++		else
++			return sprintf(buffer, "%pI6c", &addr->ip6);
++	}
++}
++#endif
++
 +/*** nat functions ***/
 +
 +/*
@@ -927,364 +1020,464 @@
 + */
 +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)
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
++		 unsigned int protoff,
++#endif
++		 struct nf_conntrack_expect* rtp_exp,
++		 struct nf_conntrack_expect* rtcp_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)
-+    {
-+        pr_info("sanity check failed\n");
-+        return 0;
-+    }
-+    off += 10;
-+    SKIP_WSPACE(ptcp+tranoff, tranlen, off);
++	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) */
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
++	union nf_inet_addr newip;
++#else
++	u_int32_t  newip;
++#endif
++	u_int16_t loport, hiport;
++	uint      off = 0;
++	uint      diff;		   /* Number of bytes we removed */
++
++	struct nf_conn *ct = rtp_exp->master;
++	/* struct nf_conn *ct = nf_ct_get(skb, &ctinfo); */
++	struct nf_conntrack_tuple *rtp_t;
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
++	char szextaddr[INET6_ADDRSTRLEN];
++#else
++	char szextaddr[INET_ADDRSTRLEN];
++#endif
++	uint extaddrlen;
++	int  is_stun;
 +
-+    newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip;
-+    t = &exp->tuple;
-+    t->dst.u3.ip = newip;
++	get_skb_tcpdata(skb, &ptcp, &tcplen);
++	ptran = ptcp+tranoff;
 +
-+    extaddrlen = extip ? sprintf(szextaddr, "%pI4", &extip)
-+                       : sprintf(szextaddr, "%pI4", &newip);
-+    pr_debug("stunaddr=%s (%s)\n", szextaddr, (extip?"forced":"auto"));
++	if (tranoff+tranlen > tcplen || tcplen-tranoff < tranlen ||
++	    tranlen < 10 || !iseol(ptran[tranlen-1]) ||
++	    nf_strncasecmp(ptran, "Transport:", 10) != 0) {
++		pr_info("sanity check failed\n");
++		return 0;
++	}
++	off += 10;
++	SKIP_WSPACE(ptcp+tranoff, tranlen, off);
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
++	newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3;
++	rtp_t = &rtp_exp->tuple;
++	rtp_t->dst.u3 = newip;
++	if (rtcp_exp) {
++		rtcp_exp->tuple.dst.u3 = newip;
++	}
++	extaddrlen = rtsp_sprintf_addr(ct, szextaddr, &newip, true); // FIXME handle extip
++	pr_debug("stunaddr=%s (auto)\n", szextaddr);
++#else
++	newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip;
++	rtp_t = &rtp_exp->tuple;
++	rtp_t->dst.u3.ip = newip;
++	if (rtcp_exp) {
++		rtcp_exp->tuple.dst.u3.ip = newip;
++	}
++	extaddrlen = extip ? sprintf(szextaddr, "%pI4", &extip)
++			   : sprintf(szextaddr, "%pI4", &newip);
++	pr_debug("stunaddr=%s (%s)\n", szextaddr, (extip?"forced":"auto"));
++#endif
++	hiport = 0;
++	rbuf1len = rbufalen = 0;
++	switch (prtspexp->pbtype) {
++	case pb_single:
++		for (loport = prtspexp->loport; loport != 0; loport++) { /* XXX: improper wrap? */
++			rtp_t->dst.u.udp.port = htons(loport);
++			if (nf_ct_expect_related(rtp_exp) == 0) {
++				pr_debug("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? */
++			rtp_t->dst.u.udp.port = htons(loport);
++			if (nf_ct_expect_related(rtp_exp) != 0) {
++				continue;
++			}
++			hiport = loport + 1;
++			rtcp_exp->tuple.dst.u.udp.port = htons(hiport);
++			if (nf_ct_expect_related(rtcp_exp) != 0) {
++				nf_ct_unexpect_related(rtp_exp);
++				continue;
++			}
 +
-+    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)
-+            {
-+                pr_debug("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 + 1; //~exp->mask.dst.u.udp.port;
-+                pr_debug("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)
-+            {
-+                pr_debug("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)
-+            {
-+                pr_debug("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;
-+    }
++			/* FIXME: invalid print in case of ipv6 */
++			pr_debug("nat expect_related %pI4:%u-%u-%pI4:%u-%u\n",
++				 &rtp_exp->tuple.src.u3.ip,
++				 ntohs(rtp_exp->tuple.src.u.udp.port),
++				 ntohs(rtcp_exp->tuple.src.u.udp.port),
++				 &rtp_exp->tuple.dst.u3.ip,
++				 ntohs(rtp_exp->tuple.dst.u.udp.port),
++				 ntohs(rtcp_exp->tuple.dst.u.udp.port));
++			break;
++		}
++		if (loport != 0) {
++			rbuf1len = sprintf(rbuf1, "%hu", loport);
++			rbufalen = sprintf(rbufa, "%hu-%hu", loport, hiport);
++		}
++		break;
++	case pb_discon:
++		for (loport = prtspexp->loport; loport != 0; loport++) { /* XXX: improper wrap? */
++			rtp_t->dst.u.udp.port = htons(loport);
++			if (nf_ct_expect_related(rtp_exp) == 0) {
++				pr_debug("using port %hu (1 of 2)\n", loport);
++				break;
++			}
++		}
++		for (hiport = prtspexp->hiport; hiport != 0; hiport++) { /* XXX: improper wrap? */
++			rtp_t->dst.u.udp.port = htons(hiport);
++			if (nf_ct_expect_related(rtp_exp) == 0) {
++				pr_debug("using port %hu (2 of 2)\n", hiport);
++				break;
++			}
++		}
++		if (loport != 0 && hiport != 0) {
++			rbuf1len = sprintf(rbuf1, "%hu", loport);
++			rbufalen = sprintf(rbufa, hiport == loport+1 ?
++					   "%hu-%hu":"%hu/%hu", loport, hiport);
++		}
++		break;
++	}
 +
-+    if (rbuf1len == 0)
-+    {
-+        return 0;   /* cannot get replacement port(s) */
-+    }
++	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;
++	/* Transport: tran;field;field=val,tran;field;field=val,...
++	   `off` is set to the start of Transport value from start of line
++	*/
++	while (off < tranlen) {
++		uint        saveoff;
++		const char* pparamend;
++		uint        nextparamoff;
 +
-+            pfieldend = memchr(ptran+off, ';', nextparamoff-off);
-+            nextfieldoff = (pfieldend == NULL) ? nextparamoff : pfieldend-ptran+1;
++		pparamend = memchr(ptran+off, ',', tranlen-off);
++		pparamend = (pparamend == NULL) ? ptran+tranlen : pparamend+1;
++		nextparamoff = pparamend-ptran;
 +
-+            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;
-+                }
-+            }
++		/*
++		 * 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;
 +
-+            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;
 +
-+            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)) {
++					uint dstoff = (ptran-ptcp)+off;
++					uint dstlen = nextfieldoff-off;
++					char* pdstrep = NULL;
++					uint dstreplen = 0;
++					diff = dstlen;
++					if (dstact == DSTACT_AUTO && !is_stun) {
++						pr_debug("RTSP: replace dst addr\n");
++						dstoff += 12;
++						dstlen -= 13;
++						pdstrep = szextaddr;
++						dstreplen = extaddrlen;
++						diff = nextfieldoff-off-13-extaddrlen;
++					}
 +
-+            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)
-+                {
-+                    pr_debug("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;
-+                }
-+            }
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
++					if (!nf_nat_mangle_tcp_packet(skb, ct, ctinfo, protoff,
++								      dstoff, dstlen, pdstrep, dstreplen)) {
++#else
++					if (!nf_nat_mangle_tcp_packet(skb, ct, ctinfo,
++								      dstoff, dstlen, pdstrep, dstreplen)) {
++#endif
++						/* mangle failed, all we can do is bail */
++						nf_ct_unexpect_related(rtp_exp);
++						if (rtcp_exp)
++							nf_ct_unexpect_related(rtcp_exp);
++						return 0;
++					}
++					get_skb_tcpdata(skb, &ptcp, &tcplen);
++					ptran = ptcp+tranoff;
++					tranlen -= diff;
++					nextparamoff -= diff;
++					nextfieldoff -= diff;
++				}
++			}
 +
-+            off = nextfieldoff;
-+        }
++			off = nextfieldoff;
++		}
 +
-+        off = nextparamoff;
-+    }
++		if (is_stun)
++			continue;
 +
-+    return 1;
++		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) {
++					pr_debug("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 LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
++					if (!nf_nat_mangle_tcp_packet(skb, ct, ctinfo, protoff,
++								      origoff, origlen, rbuf, rbuflen)) {
++#else
++					if (!nf_nat_mangle_tcp_packet(skb, ct, ctinfo,
++								      origoff, origlen, rbuf, rbuflen)) {
++#endif
++						/* mangle failed, all we can do is bail */
++						nf_ct_unexpect_related(rtp_exp);
++						if (rtcp_exp)
++							nf_ct_unexpect_related(rtcp_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)
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
++	 unsigned int protoff,
++#endif
++	 unsigned int matchoff, unsigned int matchlen,
++	 struct ip_ct_rtsp_expect* prtspexp,
++	 struct nf_conntrack_expect* rtp_exp,
++	 struct nf_conntrack_expect* rtcp_exp)
 +{
-+    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);
-+
-+    get_skb_tcpdata(skb, &ptcp, &tcplen);
-+    hdrsoff = matchoff;//exp->seq - ntohl(tcph->seq);
-+    hdrslen = matchlen;
-+    off = hdrsoff;
-+    pr_debug("NAT rtsp help_out\n");
-+
-+    while (nf_mime_nextline(ptcp, hdrsoff+hdrslen, &off, &lineoff, &linelen))
-+    {
-+        if (linelen == 0)
-+        {
-+            break;
-+        }
-+        if (off > hdrsoff+hdrslen)
-+        {
-+            pr_info("!! overrun !!");
-+            break;
-+        }
-+        pr_debug("hdr: len=%u, %.*s", linelen, (int)linelen, ptcp+lineoff);
++	char* ptcp;
++	uint  tcplen;
++	uint  hdrsoff;
++	uint  hdrslen;
++	uint  lineoff;
++	uint  linelen;
++	uint  off;
++	int   dir = CTINFO2DIR(ctinfo);
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
++	union nf_inet_addr saddr = rtp_exp->master->tuplehash[dir].tuple.src.u3;
++#else
++	__be32 saddr = rtp_exp->master->tuplehash[dir].tuple.src.u3.ip;
++#endif
 +
-+        if (nf_strncasecmp(ptcp+lineoff, "Transport:", 10) == 0)
-+        {
-+            uint oldtcplen = tcplen;
-+	    pr_debug("hdr: Transport\n");
-+            if (!rtsp_mangle_tran(ctinfo, exp, prtspexp, skb, lineoff, linelen))
-+            {
-+		pr_debug("hdr: Transport mangle failed");
-+                break;
-+            }
-+            get_skb_tcpdata(skb, &ptcp, &tcplen);
-+            hdrslen -= (oldtcplen-tcplen);
-+            off -= (oldtcplen-tcplen);
-+            lineoff -= (oldtcplen-tcplen);
-+            linelen -= (oldtcplen-tcplen);
-+            pr_debug("rep: len=%u, %.*s", linelen, (int)linelen, ptcp+lineoff);
-+        }
-+    }
++	//struct iphdr* iph = (struct iphdr*)(*pskb)->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;
++	pr_debug("NAT rtsp help_out\n");
 +
-+    return NF_ACCEPT;
++	while (nf_mime_nextline(ptcp, hdrsoff+hdrslen, &off, &lineoff, &linelen)) {
++		if (linelen == 0)
++			break;
++
++		if (off > hdrsoff+hdrslen) {
++			pr_info("!! overrun !!");
++			break;
++		}
++		pr_debug("hdr: len=%u, %.*s", linelen, (int)linelen, ptcp+lineoff);
++
++		if (nf_strncasecmp(ptcp+lineoff, "Transport:", 10) == 0) {
++			uint oldtcplen = tcplen;
++			pr_debug("hdr: Transport\n");
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
++			if (!rtsp_mangle_tran(ctinfo, protoff, rtp_exp, rtcp_exp,
++					      prtspexp, skb, lineoff, linelen)) {
++#else
++			if (!rtsp_mangle_tran(ctinfo, rtp_exp, rtcp_exp, prtspexp,
++					      skb, lineoff, linelen)) {
++#endif
++				pr_debug("hdr: Transport mangle failed");
++				break;
++			}
++			rtp_exp->expectfn = nf_nat_rtsp_expected;
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
++			rtp_exp->saved_addr = saddr;
++#else
++			rtp_exp->saved_ip = saddr;
++#endif
++			rtp_exp->saved_proto.udp.port = htons(prtspexp->loport);
++			rtp_exp->dir = !dir;
++			if (rtcp_exp) {
++				rtcp_exp->expectfn = nf_nat_rtsp_expected;
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
++				rtcp_exp->saved_addr = saddr;
++#else
++				rtcp_exp->saved_ip = saddr;
++#endif
++				rtcp_exp->saved_proto.udp.port = htons(prtspexp->hiport);
++				rtcp_exp->dir = !dir;
++			}
++			get_skb_tcpdata(skb, &ptcp, &tcplen);
++			hdrslen -= (oldtcplen-tcplen);
++			off -= (oldtcplen-tcplen);
++			lineoff -= (oldtcplen-tcplen);
++			linelen -= (oldtcplen-tcplen);
++			pr_debug("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, 
-+     unsigned int matchoff, unsigned int matchlen, struct ip_ct_rtsp_expect* prtspexp,
-+     struct nf_conntrack_expect* exp)
++nf_nat_rtsp(struct sk_buff *skb, enum ip_conntrack_info ctinfo,
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
++	    unsigned int protoff,
++#endif
++	    unsigned int matchoff, unsigned int matchlen,
++	    struct ip_ct_rtsp_expect* prtspexp,
++	    struct nf_conntrack_expect* rtp_exp,
++	    struct nf_conntrack_expect* rtcp_exp)
 +{
-+    int dir = CTINFO2DIR(ctinfo);
-+    int rc = NF_ACCEPT;
++	int dir = CTINFO2DIR(ctinfo);
++	int rc = NF_ACCEPT;
 +
-+    switch (dir)
-+    {
-+    case IP_CT_DIR_ORIGINAL:
-+        rc = help_out(skb, ctinfo, matchoff, matchlen, prtspexp, exp);
-+        break;
-+    case IP_CT_DIR_REPLY:
-+	pr_debug("unmangle ! %u\n", ctinfo);
-+    	/* XXX: unmangle */
-+	rc = NF_ACCEPT;
-+        break;
-+    }
-+    //UNLOCK_BH(&ip_rtsp_lock);
++	switch (dir) {
++	case IP_CT_DIR_ORIGINAL:
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
++		rc = help_out(skb, ctinfo, protoff, matchoff, matchlen, prtspexp,
++			      rtp_exp, rtcp_exp);
++#else
++		rc = help_out(skb, ctinfo, matchoff, matchlen, prtspexp,
++			      rtp_exp, rtcp_exp);
++#endif
++		break;
++	case IP_CT_DIR_REPLY:
++		pr_debug("unmangle ! %u\n", ctinfo);
++		/* XXX: unmangle */
++		rc = NF_ACCEPT;
++		break;
++	}
++	//UNLOCK_BH(&ip_rtsp_lock);
 +
-+    return rc;
++	return rc;
 +}
 +
-+static void expected(struct nf_conn* ct, struct nf_conntrack_expect *exp)
++static void nf_nat_rtsp_expected(struct nf_conn* ct, struct nf_conntrack_expect *exp)
 +{
-+    struct nf_nat_ipv4_multi_range_compat mr;
-+    u_int32_t newdstip, newsrcip, newip;
-+
-+    struct nf_conn *master = ct->master;
-+
-+    newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip;
-+    newsrcip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip;
-+    //FIXME (how to port that ?)
-+    //code from 2.4 : newip = (HOOK2MANIP(hooknum) == NF_NAT_MANIP_SRC) ? newsrcip : newdstip;
-+    newip = newdstip;
++#if LINUX_VERSION_CODE < KERNEL_VERSION(3,3,0) || LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
++	struct nf_nat_range range;
++#else
++	struct nf_nat_ipv4_range range;
++#endif
 +
-+    pr_debug("newsrcip=%pI4, newdstip=%pI4, newip=%pI4\n",
-+           &newsrcip, &newdstip, &newip);
++	/* This must be a fresh one. */
++	BUG_ON(ct->status & IPS_NAT_DONE_MASK);
 +
-+    mr.rangesize = 1;
-+    // We don't want to manip the per-protocol, just the IPs. 
-+    mr.range[0].flags = NF_NAT_RANGE_MAP_IPS;
-+    mr.range[0].min_ip = mr.range[0].max_ip = newip;
++	/* For DST manip, map port here to where it's expected. */
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
++	range.min_proto = range.max_proto = exp->saved_proto;
++	range.min_addr = range.max_addr = exp->saved_addr;
++#else
++	range.min = range.max = exp->saved_proto;
++	range.min_ip = range.max_ip = exp->saved_ip;
++#endif
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,3,0)
++	range.flags = (NF_NAT_RANGE_MAP_IPS | NF_NAT_RANGE_PROTO_SPECIFIED);
++	nf_nat_setup_info(ct, &range, NF_NAT_MANIP_DST);
++#else
++	range.flags = (IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED);
++	nf_nat_setup_info(ct, &range, IP_NAT_MANIP_DST);
++#endif
 +
-+    nf_nat_setup_info(ct, &mr.range[0], NF_NAT_MANIP_DST);
++	/* Change src to where master sends to, but only if the connection
++	 * actually came from the same source. */
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
++	if (nf_inet_addr_cmp(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3,
++			     &ct->master->tuplehash[exp->dir].tuple.src.u3)) {
++		range.min_addr = range.max_addr
++			= ct->master->tuplehash[!exp->dir].tuple.dst.u3;
++#else
++	if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip ==
++	    ct->master->tuplehash[exp->dir].tuple.src.u3.ip) {
++		range.min_ip = range.max_ip
++			= ct->master->tuplehash[!exp->dir].tuple.dst.u3.ip;
++#endif
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,3,0)
++		range.flags = NF_NAT_RANGE_MAP_IPS;
++		nf_nat_setup_info(ct, &range, NF_NAT_MANIP_SRC);
++#else
++		range.flags = IP_NAT_RANGE_MAP_IPS;
++		nf_nat_setup_info(ct, &range, IP_NAT_MANIP_SRC);
++#endif
++	}
 +}
 +
 +
 +static void __exit fini(void)
 +{
-+	nf_nat_rtsp_hook = NULL;
-+        nf_nat_rtsp_hook_expectfn = NULL;
++	rcu_assign_pointer(nf_nat_rtsp_hook, NULL);
 +	synchronize_net();
 +}
 +
@@ -1293,14 +1486,13 @@
 +	printk("nf_nat_rtsp v" IP_NF_RTSP_VERSION " loading\n");
 +
 +	BUG_ON(nf_nat_rtsp_hook);
-+	nf_nat_rtsp_hook = help;
-+        nf_nat_rtsp_hook_expectfn = &expected;
++	rcu_assign_pointer(nf_nat_rtsp_hook, nf_nat_rtsp);
 +
 +	if (stunaddr != NULL)
 +		extip = in_aton(stunaddr);
 +
 +	if (destaction != NULL) {
-+	        if (strcmp(destaction, "auto") == 0)
++		if (strcmp(destaction, "auto") == 0)
 +			dstact = DSTACT_AUTO;
 +
 +		if (strcmp(destaction, "strip") == 0)
diff --git a/package/network/utils/xtables-addons/patches/101-rtsp-linux-3.6-compat.patch b/package/network/utils/xtables-addons/patches/101-rtsp-linux-3.6-compat.patch
deleted file mode 100644
index b8e08b3..0000000
--- a/package/network/utils/xtables-addons/patches/101-rtsp-linux-3.6-compat.patch
+++ /dev/null
@@ -1,22 +0,0 @@
---- a/extensions/rtsp/nf_conntrack_rtsp.c
-+++ b/extensions/rtsp/nf_conntrack_rtsp.c
-@@ -28,6 +28,7 @@
-  * 			- Port to new NF API
-  */
- 
-+#include <linux/version.h>
- #include <linux/module.h>
- #include <linux/netfilter.h>
- #include <linux/ip.h>
-@@ -496,7 +497,11 @@ init(void)
- 		} else {
- 			sprintf(tmpname, "rtsp-%d", i);
- 		}
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0)
-+		strncpy(hlpr->name, tmpname, sizeof(hlpr->name));
-+#else
- 		hlpr->name = tmpname;
-+#endif
- 
- 		pr_debug("port #%d: %d\n", i, ports[i]);
- 
diff --git a/package/network/utils/xtables-addons/patches/102-rtsp-linux-3.7-compat.patch b/package/network/utils/xtables-addons/patches/102-rtsp-linux-3.7-compat.patch
deleted file mode 100644
index 0fe7917..0000000
--- a/package/network/utils/xtables-addons/patches/102-rtsp-linux-3.7-compat.patch
+++ /dev/null
@@ -1,155 +0,0 @@
---- a/extensions/rtsp/nf_conntrack_rtsp.c
-+++ b/extensions/rtsp/nf_conntrack_rtsp.c
-@@ -73,7 +73,7 @@ static DEFINE_SPINLOCK(rtsp_buffer_lock)
- static struct nf_conntrack_expect_policy rtsp_exp_policy; 
- 
- unsigned int (*nf_nat_rtsp_hook)(struct sk_buff *skb,
--				 enum ip_conntrack_info ctinfo,
-+				 enum ip_conntrack_info ctinfo, unsigned int protoff,
- 				 unsigned int matchoff, unsigned int matchlen,struct ip_ct_rtsp_expect* prtspexp,
- 				 struct nf_conntrack_expect *exp);
- void (*nf_nat_rtsp_hook_expectfn)(struct nf_conn *ct, struct nf_conntrack_expect *exp);
-@@ -269,7 +269,7 @@ void expected(struct nf_conn *ct, struct
- 
- static inline int
- help_out(struct sk_buff *skb, unsigned char *rb_ptr, unsigned int datalen,
--                struct nf_conn *ct, enum ip_conntrack_info ctinfo)
-+	 struct nf_conn *ct, enum ip_conntrack_info ctinfo, unsigned int protoff)
- {
- 	struct ip_ct_rtsp_expect expinfo;
- 	
-@@ -353,7 +353,7 @@ help_out(struct sk_buff *skb, unsigned c
- 		nf_nat_rtsp = rcu_dereference(nf_nat_rtsp_hook);
- 		if (nf_nat_rtsp && ct->status & IPS_NAT_MASK)
- 			/* pass the request off to the nat helper */
--			ret = nf_nat_rtsp(skb, ctinfo, hdrsoff, hdrslen, &expinfo, exp);
-+			ret = nf_nat_rtsp(skb, ctinfo, protoff, hdrsoff, hdrslen, &expinfo, exp);
- 		else if (nf_ct_expect_related(exp) != 0) {
- 			pr_info("nf_conntrack_expect_related failed\n");
- 			ret  = NF_DROP;
-@@ -420,7 +420,7 @@ static int help(struct sk_buff *skb, uns
- 
- 	switch (CTINFO2DIR(ctinfo)) {
- 	case IP_CT_DIR_ORIGINAL:
--		ret = help_out(skb, rb_ptr, datalen, ct, ctinfo);
-+		ret = help_out(skb, rb_ptr, datalen, ct, ctinfo, protoff);
- 		break;
- 	case IP_CT_DIR_REPLY:
- 		pr_debug("IP_CT_DIR_REPLY\n");
---- a/extensions/rtsp/nf_conntrack_rtsp.h
-+++ b/extensions/rtsp/nf_conntrack_rtsp.h
-@@ -50,6 +50,7 @@ struct ip_ct_rtsp_expect
- 
- extern unsigned int (*nf_nat_rtsp_hook)(struct sk_buff *skb,
- 				 enum ip_conntrack_info ctinfo,
-+				 unsigned int protoff,
- 				 unsigned int matchoff, unsigned int matchlen,
- 				 struct ip_ct_rtsp_expect *prtspexp,
- 				 struct nf_conntrack_expect *exp);
---- a/extensions/rtsp/nf_nat_rtsp.c
-+++ b/extensions/rtsp/nf_nat_rtsp.c
-@@ -32,10 +32,10 @@
- 
- #include <linux/module.h>
- #include <net/tcp.h>
-+#include <net/netfilter/nf_conntrack_expect.h>
- #include <net/netfilter/nf_nat_helper.h>
--#include <net/netfilter/nf_nat_rule.h>
-+#include <net/netfilter/nf_nat.h>
- #include "nf_conntrack_rtsp.h"
--#include <net/netfilter/nf_conntrack_expect.h>
- 
- #include <linux/inet.h>
- #include <linux/ctype.h>
-@@ -102,8 +102,8 @@ get_skb_tcpdata(struct sk_buff* skb, cha
- 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)
-+		 struct ip_ct_rtsp_expect* prtspexp,
-+                 struct sk_buff* skb, uint protoff, uint tranoff, uint tranlen)
- {
-     char*       ptcp;
-     uint        tcplen;
-@@ -256,7 +256,7 @@ rtsp_mangle_tran(enum ip_conntrack_info 
-                 if (dstact == DSTACT_STRIP || (dstact == DSTACT_AUTO && !is_stun))
-                 {
-                     diff = nextfieldoff-off;
--                    if (!nf_nat_mangle_tcp_packet(skb, ct, ctinfo,
-+                    if (!nf_nat_mangle_tcp_packet(skb, ct, ctinfo, protoff,
-                                                          off, diff, NULL, 0))
-                     {
-                         /* mangle failed, all we can do is bail */
-@@ -326,7 +326,7 @@ rtsp_mangle_tran(enum ip_conntrack_info 
-                      * parameter 4 below is offset from start of tcp data.
-                      */
-                     diff = origlen-rbuflen;
--                    if (!nf_nat_mangle_tcp_packet(skb, ct, ctinfo,
-+                    if (!nf_nat_mangle_tcp_packet(skb, ct, ctinfo, protoff,
-                                               origoff, origlen, rbuf, rbuflen))
-                     {
-                         /* mangle failed, all we can do is bail */
-@@ -351,7 +351,7 @@ rtsp_mangle_tran(enum ip_conntrack_info 
- }
- 
- static uint
--help_out(struct sk_buff *skb, enum ip_conntrack_info ctinfo,
-+help_out(struct sk_buff *skb, enum ip_conntrack_info ctinfo, unsigned int protoff,
- 	 unsigned int matchoff, unsigned int matchlen, struct ip_ct_rtsp_expect* prtspexp, 
- 	 struct nf_conntrack_expect* exp)
- {
-@@ -389,7 +389,7 @@ help_out(struct sk_buff *skb, enum ip_co
-         {
-             uint oldtcplen = tcplen;
- 	    pr_debug("hdr: Transport\n");
--            if (!rtsp_mangle_tran(ctinfo, exp, prtspexp, skb, lineoff, linelen))
-+            if (!rtsp_mangle_tran(ctinfo, exp, prtspexp, skb, protoff, lineoff, linelen))
-             {
- 		pr_debug("hdr: Transport mangle failed");
-                 break;
-@@ -407,7 +407,7 @@ help_out(struct sk_buff *skb, enum ip_co
- }
- 
- static unsigned int
--help(struct sk_buff *skb, enum ip_conntrack_info ctinfo, 
-+help(struct sk_buff *skb, enum ip_conntrack_info ctinfo, unsigned int protoff,
-      unsigned int matchoff, unsigned int matchlen, struct ip_ct_rtsp_expect* prtspexp,
-      struct nf_conntrack_expect* exp)
- {
-@@ -417,7 +417,7 @@ help(struct sk_buff *skb, enum ip_conntr
-     switch (dir)
-     {
-     case IP_CT_DIR_ORIGINAL:
--        rc = help_out(skb, ctinfo, matchoff, matchlen, prtspexp, exp);
-+	    rc = help_out(skb, ctinfo, protoff, matchoff, matchlen, prtspexp, exp);
-         break;
-     case IP_CT_DIR_REPLY:
- 	pr_debug("unmangle ! %u\n", ctinfo);
-@@ -432,7 +432,7 @@ help(struct sk_buff *skb, enum ip_conntr
- 
- static void expected(struct nf_conn* ct, struct nf_conntrack_expect *exp)
- {
--    struct nf_nat_ipv4_multi_range_compat mr;
-+    struct nf_nat_range nr;
-     u_int32_t newdstip, newsrcip, newip;
- 
-     struct nf_conn *master = ct->master;
-@@ -446,12 +446,13 @@ static void expected(struct nf_conn* ct,
-     pr_debug("newsrcip=%pI4, newdstip=%pI4, newip=%pI4\n",
-            &newsrcip, &newdstip, &newip);
- 
--    mr.rangesize = 1;
-+    memset(&nr, 0, sizeof(nr));
-+
-     // We don't want to manip the per-protocol, just the IPs. 
--    mr.range[0].flags = NF_NAT_RANGE_MAP_IPS;
--    mr.range[0].min_ip = mr.range[0].max_ip = newip;
-+    nr.flags = NF_NAT_RANGE_MAP_IPS;
-+    nr.min_addr.ip = nr.max_addr.ip = newip;
- 
--    nf_nat_setup_info(ct, &mr.range[0], NF_NAT_MANIP_DST);
-+    nf_nat_setup_info(ct, &nr, NF_NAT_MANIP_DST);
- }
- 
- 
_______________________________________________
openwrt-devel mailing list
openwrt-devel at lists.openwrt.org
https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel



More information about the openwrt-devel mailing list