nf_conntrack_rtsp: update to latest version
authorJohn Crispin <john@openwrt.org>
Wed, 19 Nov 2014 09:21:12 +0000 (09:21 +0000)
committerJohn Crispin <john@openwrt.org>
Wed, 19 Nov 2014 09:21:12 +0000 (09:21 +0000)
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>
SVN-Revision: 43311

package/network/utils/xtables-addons/patches/100-add-rtsp-conntrack.patch
package/network/utils/xtables-addons/patches/101-rtsp-linux-3.6-compat.patch [deleted file]
package/network/utils/xtables-addons/patches/102-rtsp-linux-3.7-compat.patch [deleted file]

index ef7917a9eb80b3027d08f55a5cc69a1bfea651b6..6c169ee82c0c698587dcc01683de96fe84f22298 100644 (file)
 +#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
 + * 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>
 +#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];
 +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);
 +
 + */
 +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;
 +                      pr_info("!! overrun !!\n");
 +                      break;
 +              }
-+              
++
 +              if (nf_strncasecmp(ptcp+lineoff, "CSeq:", 5) == 0) {
 +                      *pcseqoff = lineoff;
 +                      *pcseqlen = linelen;
 + */
 +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) {
 +                      if (strncmp(ptran+off, "client_port=", 12) == 0) {
 +                              u_int16_t   port;
 +                              uint        numlen;
-+                  
++
 +                              off += 12;
 +                              numlen = nf_strtou16(ptran+off, &port);
 +                              off += numlen;
 +      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 ***/
 +
 +
 +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;
 +      
 +      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");
 +              }
 +
 +              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:
 +
 +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,
 +      } 
 +
 +      /* 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;
 +
 +      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");
 +              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) 
 +      /* 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++) {
 +              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;
 +              } 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);
 +                      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>
 + *      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 */
 +};
 +
 +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
 +
 +#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.
 + *
 + */
 +
 +#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>
 +
 +#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");
 +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 ***/
 +
 +/*
 + */
 +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();
 +}
 +
 +      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 (file)
index b8e08b3..0000000
+++ /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 (file)
index 0fe7917..0000000
+++ /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);
- }