From: John Crispin Date: Wed, 19 Nov 2014 09:21:12 +0000 (+0000) Subject: nf_conntrack_rtsp: update to latest version X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=2d09efcd26be6ba4d004691fce1db1e382501d26;p=openwrt%2Fstaging%2Fluka.git 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 SVN-Revision: 43311 --- 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 ++ * ++ * 2005-02-13: Harald Welte ++ * - port to 2.6 ++ * - update to recent post-2.6.11 api changes ++ * 2006-09-14: Steven Van Acker ++ * - removed calls to NAT code from conntrack helper: NAT no longer needed to use rtsp-conntrack ++ * 2007-04-18: Michael Guntsche ++ * - Port to new NF API ++ * 2013-03-04: Il'inykh Sergey . 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 -+ * - port to 2.6 -+ * - update to recent post-2.6.11 api changes -+ * 2006-09-14: Steven Van Acker -+ * - removed calls to NAT code from conntrack helper: NAT no longer needed to use rtsp-conntrack -+ * 2007-04-18: Michael Guntsche -+ * - Port to new NF API + */ + +#include @@ -286,7 +292,6 @@ +#include "netfilter_mime.h" + +#include -+#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 @@ -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 . Inango Systems Ltd ++ * - conditional compilation for kernel 3.7 ++ * - port mapping improvements ++*/ +#ifndef _IP_CONNTRACK_RTSP_H +#define _IP_CONNTRACK_RTSP_H + ++#include ++ +//#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 ++ * ++ * 2013-03-04: Il'inykh Sergey . 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 -+ * stunaddr=
-+ * destaction=[auto|strip|none] ++ * insmod nf_nat_rtsp.o ports=port1,port2,...port ++ * stunaddr=
++ * destaction=[auto|strip|none] + * + * If no ports are specified, the default will be port 554 only. + * @@ -857,9 +929,14 @@ + */ + +#include ++#include +#include ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0) ++# include ++#else ++# include ++#endif +#include -+#include +#include "nf_conntrack_rtsp.h" +#include + @@ -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 "); +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 - #include - #include - #include -@@ -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 - #include -+#include - #include --#include -+#include - #include "nf_conntrack_rtsp.h" --#include - - #include - #include -@@ -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); - } - -