aboutsummaryrefslogtreecommitdiffstats
path: root/package
diff options
context:
space:
mode:
authorJohn Crispin <blogic@openwrt.org>2014-11-19 09:21:12 +0000
committerJohn Crispin <blogic@openwrt.org>2014-11-19 09:21:12 +0000
commit41436967c385df182a7ce8df9c310f977161def5 (patch)
treeb550b87605e18dc6eff3a98af924a42f1d907ab6 /package
parent0c07215e8de1a1755bbe5de036ca111f9e6fd247 (diff)
downloadupstream-41436967c385df182a7ce8df9c310f977161def5.tar.gz
upstream-41436967c385df182a7ce8df9c310f977161def5.tar.bz2
upstream-41436967c385df182a7ce8df9c310f977161def5.zip
nf_conntrack_rtsp: update to latest version
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@gmail.com> git-svn-id: svn://svn.openwrt.org/openwrt/trunk@43311 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'package')
-rw-r--r--package/network/utils/xtables-addons/patches/100-add-rtsp-conntrack.patch1060
-rw-r--r--package/network/utils/xtables-addons/patches/101-rtsp-linux-3.6-compat.patch22
-rw-r--r--package/network/utils/xtables-addons/patches/102-rtsp-linux-3.7-compat.patch155
3 files changed, 626 insertions, 611 deletions
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 ef7917a9eb..6c169ee82c 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 b8e08b3a32..0000000000
--- 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 0fe7917cff..0000000000
--- 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);
- }
-
-