From: Florian Fainelli Date: Wed, 1 Mar 2006 06:37:25 +0000 (+0000) Subject: Removed SIP connection tracking helper, licence unclear, unresolved symbols X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=3b8e92c0b46c53628d6d8e5f8d896a8946dddd3d;p=openwrt%2Fstaging%2Flinusw.git Removed SIP connection tracking helper, licence unclear, unresolved symbols SVN-Revision: 3292 --- diff --git a/openwrt/target/linux/ar531x-2.4/config b/openwrt/target/linux/ar531x-2.4/config index e9d8f8a54d..4a33791bfb 100644 --- a/openwrt/target/linux/ar531x-2.4/config +++ b/openwrt/target/linux/ar531x-2.4/config @@ -345,7 +345,6 @@ CONFIG_IP_NF_CT_ACCT=m CONFIG_IP_NF_MATCH_CONNBYTES=m CONFIG_IP_NF_CT_PROTO_GRE=m CONFIG_IP_NF_PPTP=m -CONFIG_IP_NF_SIP=m CONFIG_IP_NF_H323=m CONFIG_IP_NF_MMS=m CONFIG_IP_NF_RTSP=m @@ -399,7 +398,6 @@ CONFIG_IP_NF_TARGET_REDIRECT=m CONFIG_IP_NF_TARGET_NETMAP=m CONFIG_IP_NF_NAT_PPTP=m CONFIG_IP_NF_NAT_PROTO_GRE=m -CONFIG_IP_NF_NAT_SIP=m CONFIG_IP_NF_NAT_H323=m CONFIG_IP_NF_NAT_MMS=m CONFIG_IP_NF_NAT_RTSP=m diff --git a/openwrt/target/linux/ar7-2.4/config b/openwrt/target/linux/ar7-2.4/config index 06852c77cd..5f7a1513b7 100644 --- a/openwrt/target/linux/ar7-2.4/config +++ b/openwrt/target/linux/ar7-2.4/config @@ -347,7 +347,6 @@ CONFIG_IP_NF_CT_ACCT=m CONFIG_IP_NF_MATCH_CONNBYTES=m CONFIG_IP_NF_CT_PROTO_GRE=m CONFIG_IP_NF_PPTP=m -CONFIG_IP_NF_SIP=m CONFIG_IP_NF_H323=m CONFIG_IP_NF_MMS=m CONFIG_IP_NF_RTSP=m @@ -401,7 +400,6 @@ CONFIG_IP_NF_TARGET_REDIRECT=m CONFIG_IP_NF_TARGET_NETMAP=m CONFIG_IP_NF_NAT_PPTP=m CONFIG_IP_NF_NAT_PROTO_GRE=m -CONFIG_IP_NF_NAT_SIP=m CONFIG_IP_NF_NAT_H323=m CONFIG_IP_NF_NAT_MMS=m CONFIG_IP_NF_NAT_RTSP=m diff --git a/openwrt/target/linux/brcm-2.4/config b/openwrt/target/linux/brcm-2.4/config index 1ca20ab1ed..ca3e2735e0 100644 --- a/openwrt/target/linux/brcm-2.4/config +++ b/openwrt/target/linux/brcm-2.4/config @@ -353,7 +353,6 @@ CONFIG_IP_NF_CT_ACCT=m CONFIG_IP_NF_MATCH_CONNBYTES=m CONFIG_IP_NF_CT_PROTO_GRE=m CONFIG_IP_NF_PPTP=m -CONFIG_IP_NF_SIP=m CONFIG_IP_NF_H323=m CONFIG_IP_NF_MMS=m CONFIG_IP_NF_RTSP=m @@ -407,7 +406,6 @@ CONFIG_IP_NF_TARGET_REDIRECT=m CONFIG_IP_NF_TARGET_NETMAP=m CONFIG_IP_NF_NAT_PPTP=m CONFIG_IP_NF_NAT_PROTO_GRE=m -CONFIG_IP_NF_NAT_SIP=m CONFIG_IP_NF_NAT_H323=m CONFIG_IP_NF_NAT_MMS=m CONFIG_IP_NF_NAT_RTSP=m diff --git a/openwrt/target/linux/generic-2.4/patches/613-netfilter_nat_h323.patch b/openwrt/target/linux/generic-2.4/patches/613-netfilter_nat_h323.patch new file mode 100644 index 0000000000..983d4fef3a --- /dev/null +++ b/openwrt/target/linux/generic-2.4/patches/613-netfilter_nat_h323.patch @@ -0,0 +1,821 @@ +diff -urN linux-2.4.32/net/ipv4/netfilter/Config.in linux-2.4.32.new/net/ipv4/netfilter/Config.in +--- linux-2.4.32/net/ipv4/netfilter/Config.in 2006-03-01 00:49:36.652505800 +0100 ++++ linux-2.4.32.new/net/ipv4/netfilter/Config.in 2006-03-01 00:50:18.692114808 +0100 +@@ -15,6 +15,7 @@ + dep_tristate ' Connection byte counter support' CONFIG_IP_NF_MATCH_CONNBYTES $CONFIG_IP_NF_CT_ACCT $CONFIG_IP_NF_CONNTRACK $CONFIG_IP_NF_IPTABLES + dep_tristate ' GRE protocol support' CONFIG_IP_NF_CT_PROTO_GRE $CONFIG_IP_NF_CONNTRACK + dep_tristate ' PPTP protocol support' CONFIG_IP_NF_PPTP $CONFIG_IP_NF_CT_PROTO_GRE ++ dep_tristate ' H.323 (netmeeting) support' CONFIG_IP_NF_H323 $CONFIG_IP_NF_CONNTRACK + fi + + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then +@@ -111,6 +112,13 @@ + define_tristate CONFIG_IP_NF_NAT_AMANDA $CONFIG_IP_NF_NAT + fi + fi ++ if [ "$CONFIG_IP_NF_H323" = "m" ]; then ++ define_tristate CONFIG_IP_NF_NAT_H323 m ++ else ++ if [ "$CONFIG_IP_NF_H323" = "y" ]; then ++ define_tristate CONFIG_IP_NF_NAT_H323 $CONFIG_IP_NF_NAT ++ fi ++ fi + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + dep_tristate ' Basic SNMP-ALG support (EXPERIMENTAL)' CONFIG_IP_NF_NAT_SNMP_BASIC $CONFIG_IP_NF_NAT + fi +diff -urN linux-2.4.32/net/ipv4/netfilter/Makefile linux-2.4.32.new/net/ipv4/netfilter/Makefile +--- linux-2.4.32/net/ipv4/netfilter/Makefile 2006-03-01 00:49:36.654505496 +0100 ++++ linux-2.4.32.new/net/ipv4/netfilter/Makefile 2006-03-01 00:50:18.693114656 +0100 +@@ -53,6 +53,10 @@ + ifdef CONFIG_IP_NF_NAT_PPTP + export-objs += ip_conntrack_pptp.o + endif ++obj-$(CONFIG_IP_NF_H323) += ip_conntrack_h323.o ++ifdef CONFIG_IP_NF_NAT_H323 ++ export-objs += ip_conntrack_h323.o ++endif + + + # NAT helpers +@@ -62,6 +66,7 @@ + obj-$(CONFIG_IP_NF_NAT_IRC) += ip_nat_irc.o + obj-$(CONFIG_IP_NF_NAT_PROTO_GRE) += ip_nat_proto_gre.o + obj-$(CONFIG_IP_NF_NAT_PPTP) += ip_nat_pptp.o ++obj-$(CONFIG_IP_NF_NAT_H323) += ip_nat_h323.o + + # generic IP tables + obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o +diff -urN linux-2.4.32/net/ipv4/netfilter/ip_conntrack_h323.c linux-2.4.32.new/net/ipv4/netfilter/ip_conntrack_h323.c +--- linux-2.4.32/net/ipv4/netfilter/ip_conntrack_h323.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.32.new/net/ipv4/netfilter/ip_conntrack_h323.c 2006-03-01 00:50:18.694114504 +0100 +@@ -0,0 +1,302 @@ ++/* ++ * H.323 'brute force' extension for H.323 connection tracking. ++ * Jozsef Kadlecsik ++ * ++ * Based on ip_masq_h323.c for 2.2 kernels from CoRiTel, Sofia project. ++ * (http://www.coritel.it/projects/sofia/nat/) ++ * Uses Sampsa Ranta's excellent idea on using expectfn to 'bind' ++ * the unregistered helpers to the conntrack entries. ++ */ ++ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++MODULE_AUTHOR("Jozsef Kadlecsik "); ++MODULE_DESCRIPTION("H.323 'brute force' connection tracking module"); ++MODULE_LICENSE("GPL"); ++ ++DECLARE_LOCK(ip_h323_lock); ++struct module *ip_conntrack_h323 = THIS_MODULE; ++ ++#define DEBUGP(format, args...) ++ ++static int h245_help(const struct iphdr *iph, size_t len, ++ struct ip_conntrack *ct, ++ enum ip_conntrack_info ctinfo) ++{ ++ struct tcphdr *tcph = (void *)iph + iph->ihl * 4; ++ unsigned char *data = (unsigned char *) tcph + tcph->doff * 4; ++ unsigned char *data_limit; ++ u_int32_t tcplen = len - iph->ihl * 4; ++ u_int32_t datalen = tcplen - tcph->doff * 4; ++ int dir = CTINFO2DIR(ctinfo); ++ struct ip_ct_h225_master *info = &ct->help.ct_h225_info; ++ struct ip_conntrack_expect expect, *exp = &expect; ++ struct ip_ct_h225_expect *exp_info = &exp->help.exp_h225_info; ++ u_int16_t data_port; ++ u_int32_t data_ip; ++ unsigned int i; ++ ++ DEBUGP("ct_h245_help: help entered %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n", ++ NIPQUAD(iph->saddr), ntohs(tcph->source), ++ NIPQUAD(iph->daddr), ntohs(tcph->dest)); ++ ++ /* Can't track connections formed before we registered */ ++ if (!info) ++ return NF_ACCEPT; ++ ++ /* Until there's been traffic both ways, don't look in packets. */ ++ if (ctinfo != IP_CT_ESTABLISHED ++ && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) { ++ DEBUGP("ct_h245_help: Conntrackinfo = %u\n", ctinfo); ++ return NF_ACCEPT; ++ } ++ ++ /* Not whole TCP header or too short packet? */ ++ if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4 + 5) { ++ DEBUGP("ct_h245_help: tcplen = %u\n", (unsigned)tcplen); ++ return NF_ACCEPT; ++ } ++ ++ /* Checksum invalid? Ignore. */ ++ if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr, ++ csum_partial((char *)tcph, tcplen, 0))) { ++ DEBUGP("ct_h245_help: bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n", ++ tcph, tcplen, NIPQUAD(iph->saddr), ++ NIPQUAD(iph->daddr)); ++ return NF_ACCEPT; ++ } ++ ++ data_limit = (unsigned char *) data + datalen; ++ /* bytes: 0123 45 ++ ipadrr port */ ++ for (i = 0; data < (data_limit - 5); data++, i++) { ++ memcpy(&data_ip, data, sizeof(u_int32_t)); ++ if (data_ip == iph->saddr) { ++ memcpy(&data_port, data + 4, sizeof(u_int16_t)); ++ memset(&expect, 0, sizeof(expect)); ++ /* update the H.225 info */ ++ DEBUGP("ct_h245_help: new RTCP/RTP requested %u.%u.%u.%u:->%u.%u.%u.%u:%u\n", ++ NIPQUAD(ct->tuplehash[!dir].tuple.src.ip), ++ NIPQUAD(iph->saddr), ntohs(data_port)); ++ LOCK_BH(&ip_h323_lock); ++ info->is_h225 = H225_PORT + 1; ++ exp_info->port = data_port; ++ exp_info->dir = dir; ++ exp_info->offset = i; ++ ++ exp->seq = ntohl(tcph->seq) + i; ++ ++ exp->tuple = ((struct ip_conntrack_tuple) ++ { { ct->tuplehash[!dir].tuple.src.ip, ++ { 0 } }, ++ { data_ip, ++ { data_port }, ++ IPPROTO_UDP }}); ++ exp->mask = ((struct ip_conntrack_tuple) ++ { { 0xFFFFFFFF, { 0 } }, ++ { 0xFFFFFFFF, { 0xFFFF }, 0xFFFF }}); ++ ++ exp->expectfn = NULL; ++ ++ /* Ignore failure; should only happen with NAT */ ++ ip_conntrack_expect_related(ct, exp); ++ ++ UNLOCK_BH(&ip_h323_lock); ++ } ++ } ++ ++ return NF_ACCEPT; ++ ++} ++ ++/* H.245 helper is not registered! */ ++static struct ip_conntrack_helper h245 = ++ { { NULL, NULL }, ++ "H.245", /* name */ ++ IP_CT_HELPER_F_REUSE_EXPECT, /* flags */ ++ NULL, /* module */ ++ 8, /* max_ expected */ ++ 240, /* timeout */ ++ { { 0, { 0 } }, /* tuple */ ++ { 0, { 0 }, IPPROTO_TCP } }, ++ { { 0, { 0xFFFF } }, /* mask */ ++ { 0, { 0 }, 0xFFFF } }, ++ h245_help /* helper */ ++ }; ++ ++static int h225_expect(struct ip_conntrack *ct) ++{ ++ WRITE_LOCK(&ip_conntrack_lock); ++ ct->helper = &h245; ++ DEBUGP("h225_expect: helper for %p added\n", ct); ++ WRITE_UNLOCK(&ip_conntrack_lock); ++ ++ return NF_ACCEPT; /* unused */ ++} ++ ++static int h225_help(const struct iphdr *iph, size_t len, ++ struct ip_conntrack *ct, ++ enum ip_conntrack_info ctinfo) ++{ ++ struct tcphdr *tcph = (void *)iph + iph->ihl * 4; ++ unsigned char *data = (unsigned char *) tcph + tcph->doff * 4; ++ unsigned char *data_limit; ++ u_int32_t tcplen = len - iph->ihl * 4; ++ u_int32_t datalen = tcplen - tcph->doff * 4; ++ int dir = CTINFO2DIR(ctinfo); ++ struct ip_ct_h225_master *info = &ct->help.ct_h225_info; ++ struct ip_conntrack_expect expect, *exp = &expect; ++ struct ip_ct_h225_expect *exp_info = &exp->help.exp_h225_info; ++ u_int16_t data_port; ++ u_int32_t data_ip; ++ unsigned int i; ++ ++ DEBUGP("ct_h225_help: help entered %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n", ++ NIPQUAD(iph->saddr), ntohs(tcph->source), ++ NIPQUAD(iph->daddr), ntohs(tcph->dest)); ++ ++ /* Can't track connections formed before we registered */ ++ if (!info) ++ return NF_ACCEPT; ++ ++ /* Until there's been traffic both ways, don't look in packets. */ ++ if (ctinfo != IP_CT_ESTABLISHED ++ && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) { ++ DEBUGP("ct_h225_help: Conntrackinfo = %u\n", ctinfo); ++ return NF_ACCEPT; ++ } ++ ++ /* Not whole TCP header or too short packet? */ ++ if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4 + 5) { ++ DEBUGP("ct_h225_help: tcplen = %u\n", (unsigned)tcplen); ++ return NF_ACCEPT; ++ } ++ ++ /* Checksum invalid? Ignore. */ ++ if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr, ++ csum_partial((char *)tcph, tcplen, 0))) { ++ DEBUGP("ct_h225_help: bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n", ++ tcph, tcplen, NIPQUAD(iph->saddr), ++ NIPQUAD(iph->daddr)); ++ return NF_ACCEPT; ++ } ++ ++ data_limit = (unsigned char *) data + datalen; ++ /* bytes: 0123 45 ++ ipadrr port */ ++ for (i = 0; data < (data_limit - 5); data++, i++) { ++ memcpy(&data_ip, data, sizeof(u_int32_t)); ++ if (data_ip == iph->saddr) { ++ memcpy(&data_port, data + 4, sizeof(u_int16_t)); ++ if (data_port == tcph->source) { ++ /* Signal address */ ++ DEBUGP("ct_h225_help: sourceCallSignalAddress from %u.%u.%u.%u\n", ++ NIPQUAD(iph->saddr)); ++ /* Update the H.225 info so that NAT can mangle the address/port ++ even when we have no expected connection! */ ++#ifdef CONFIG_IP_NF_NAT_NEEDED ++ LOCK_BH(&ip_h323_lock); ++ info->dir = dir; ++ info->seq[IP_CT_DIR_ORIGINAL] = ntohl(tcph->seq) + i; ++ info->offset[IP_CT_DIR_ORIGINAL] = i; ++ UNLOCK_BH(&ip_h323_lock); ++#endif ++ } else { ++ memset(&expect, 0, sizeof(expect)); ++ ++ /* update the H.225 info */ ++ LOCK_BH(&ip_h323_lock); ++ info->is_h225 = H225_PORT; ++ exp_info->port = data_port; ++ exp_info->dir = dir; ++ exp_info->offset = i; ++ ++ exp->seq = ntohl(tcph->seq) + i; ++ ++ exp->tuple = ((struct ip_conntrack_tuple) ++ { { ct->tuplehash[!dir].tuple.src.ip, ++ { 0 } }, ++ { data_ip, ++ { data_port }, ++ IPPROTO_TCP }}); ++ exp->mask = ((struct ip_conntrack_tuple) ++ { { 0xFFFFFFFF, { 0 } }, ++ { 0xFFFFFFFF, { 0xFFFF }, 0xFFFF }}); ++ ++ exp->expectfn = h225_expect; ++ ++ /* Ignore failure */ ++ ip_conntrack_expect_related(ct, exp); ++ ++ DEBUGP("ct_h225_help: new H.245 requested %u.%u.%u.%u->%u.%u.%u.%u:%u\n", ++ NIPQUAD(ct->tuplehash[!dir].tuple.src.ip), ++ NIPQUAD(iph->saddr), ntohs(data_port)); ++ ++ UNLOCK_BH(&ip_h323_lock); ++ } ++#ifdef CONFIG_IP_NF_NAT_NEEDED ++ } else if (data_ip == iph->daddr) { ++ memcpy(&data_port, data + 4, sizeof(u_int16_t)); ++ if (data_port == tcph->dest) { ++ /* Signal address */ ++ DEBUGP("ct_h225_help: destCallSignalAddress %u.%u.%u.%u\n", ++ NIPQUAD(iph->daddr)); ++ /* Update the H.225 info so that NAT can mangle the address/port ++ even when we have no expected connection! */ ++ LOCK_BH(&ip_h323_lock); ++ info->dir = dir; ++ info->seq[IP_CT_DIR_REPLY] = ntohl(tcph->seq) + i; ++ info->offset[IP_CT_DIR_REPLY] = i; ++ UNLOCK_BH(&ip_h323_lock); ++ } ++#endif ++ } ++ } ++ ++ return NF_ACCEPT; ++ ++} ++ ++static struct ip_conntrack_helper h225 = ++ { { NULL, NULL }, ++ "H.225", /* name */ ++ IP_CT_HELPER_F_REUSE_EXPECT, /* flags */ ++ THIS_MODULE, /* module */ ++ 2, /* max_expected */ ++ 240, /* timeout */ ++ { { 0, { __constant_htons(H225_PORT) } }, /* tuple */ ++ { 0, { 0 }, IPPROTO_TCP } }, ++ { { 0, { 0xFFFF } }, /* mask */ ++ { 0, { 0 }, 0xFFFF } }, ++ h225_help /* helper */ ++ }; ++ ++static int __init init(void) ++{ ++ return ip_conntrack_helper_register(&h225); ++} ++ ++static void __exit fini(void) ++{ ++ /* Unregister H.225 helper */ ++ ip_conntrack_helper_unregister(&h225); ++} ++ ++#ifdef CONFIG_IP_NF_NAT_NEEDED ++EXPORT_SYMBOL(ip_h323_lock); ++#endif ++ ++module_init(init); ++module_exit(fini); +diff -urN linux-2.4.32/net/ipv4/netfilter/ip_nat_h323.c linux-2.4.32.new/net/ipv4/netfilter/ip_nat_h323.c +--- linux-2.4.32/net/ipv4/netfilter/ip_nat_h323.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.32.new/net/ipv4/netfilter/ip_nat_h323.c 2006-03-01 00:50:18.698113896 +0100 +@@ -0,0 +1,403 @@ ++/* ++ * H.323 'brute force' extension for NAT alteration. ++ * Jozsef Kadlecsik ++ * ++ * Based on ip_masq_h323.c for 2.2 kernels from CoRiTel, Sofia project. ++ * (http://www.coritel.it/projects/sofia/nat.html) ++ * Uses Sampsa Ranta's excellent idea on using expectfn to 'bind' ++ * the unregistered helpers to the conntrack entries. ++ */ ++ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++MODULE_AUTHOR("Jozsef Kadlecsik "); ++MODULE_DESCRIPTION("H.323 'brute force' connection tracking module"); ++MODULE_LICENSE("GPL"); ++ ++DECLARE_LOCK_EXTERN(ip_h323_lock); ++struct module *ip_nat_h323 = THIS_MODULE; ++ ++#define DEBUGP(format, args...) ++ ++ ++static unsigned int ++h225_nat_expected(struct sk_buff **pskb, ++ unsigned int hooknum, ++ struct ip_conntrack *ct, ++ struct ip_nat_info *info); ++ ++static unsigned int h225_nat_help(struct ip_conntrack *ct, ++ struct ip_conntrack_expect *exp, ++ struct ip_nat_info *info, ++ enum ip_conntrack_info ctinfo, ++ unsigned int hooknum, ++ struct sk_buff **pskb); ++ ++static struct ip_nat_helper h245 = ++ { { NULL, NULL }, ++ "H.245", /* name */ ++ 0, /* flags */ ++ NULL, /* module */ ++ { { 0, { 0 } }, /* tuple */ ++ { 0, { 0 }, IPPROTO_TCP } }, ++ { { 0, { 0xFFFF } }, /* mask */ ++ { 0, { 0 }, 0xFFFF } }, ++ h225_nat_help, /* helper */ ++ h225_nat_expected /* expectfn */ ++ }; ++ ++static unsigned int ++h225_nat_expected(struct sk_buff **pskb, ++ unsigned int hooknum, ++ struct ip_conntrack *ct, ++ struct ip_nat_info *info) ++{ ++ struct ip_nat_multi_range mr; ++ u_int32_t newdstip, newsrcip, newip; ++ u_int16_t port; ++ struct ip_ct_h225_expect *exp_info; ++ struct ip_ct_h225_master *master_info; ++ struct ip_conntrack *master = master_ct(ct); ++ unsigned int is_h225, ret; ++ ++ IP_NF_ASSERT(info); ++ IP_NF_ASSERT(master); ++ ++ IP_NF_ASSERT(!(info->initialized & (1<master->expectant->help.ct_h225_info; ++ exp_info = &ct->master->help.exp_h225_info; ++ ++ LOCK_BH(&ip_h323_lock); ++ ++ DEBUGP("master: "); ++ DUMP_TUPLE(&master->tuplehash[IP_CT_DIR_ORIGINAL].tuple); ++ DUMP_TUPLE(&master->tuplehash[IP_CT_DIR_REPLY].tuple); ++ DEBUGP("conntrack: "); ++ DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); ++ if (exp_info->dir == IP_CT_DIR_ORIGINAL) { ++ /* Make connection go to the client. */ ++ newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; ++ newsrcip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip; ++ DEBUGP("h225_nat_expected: %u.%u.%u.%u->%u.%u.%u.%u (to client)\n", ++ NIPQUAD(newsrcip), NIPQUAD(newdstip)); ++ } else { ++ /* Make the connection go to the server */ ++ newdstip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip; ++ newsrcip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; ++ DEBUGP("h225_nat_expected: %u.%u.%u.%u->%u.%u.%u.%u (to server)\n", ++ NIPQUAD(newsrcip), NIPQUAD(newdstip)); ++ } ++ port = exp_info->port; ++ is_h225 = master_info->is_h225 == H225_PORT; ++ UNLOCK_BH(&ip_h323_lock); ++ ++ if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC) ++ newip = newsrcip; ++ else ++ newip = newdstip; ++ ++ DEBUGP("h225_nat_expected: IP to %u.%u.%u.%u\n", NIPQUAD(newip)); ++ ++ mr.rangesize = 1; ++ /* We don't want to manip the per-protocol, just the IPs... */ ++ mr.range[0].flags = IP_NAT_RANGE_MAP_IPS; ++ mr.range[0].min_ip = mr.range[0].max_ip = newip; ++ ++ /* ... unless we're doing a MANIP_DST, in which case, make ++ sure we map to the correct port */ ++ if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST) { ++ mr.range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED; ++ mr.range[0].min = mr.range[0].max ++ = ((union ip_conntrack_manip_proto) ++ { port }); ++ } ++ ++ ret = ip_nat_setup_info(ct, &mr, hooknum); ++ ++ if (is_h225) { ++ DEBUGP("h225_nat_expected: H.225, setting NAT helper for %p\n", ct); ++ /* NAT expectfn called with ip_nat_lock write-locked */ ++ info->helper = &h245; ++ } ++ return ret; ++} ++ ++static int h323_signal_address_fixup(struct ip_conntrack *ct, ++ struct sk_buff **pskb, ++ enum ip_conntrack_info ctinfo) ++{ ++ struct iphdr *iph = (*pskb)->nh.iph; ++ struct tcphdr *tcph = (void *)iph + iph->ihl*4; ++ unsigned char *data; ++ u_int32_t tcplen = (*pskb)->len - iph->ihl*4; ++ u_int32_t datalen = tcplen - tcph->doff*4; ++ struct ip_ct_h225_master *info = &ct->help.ct_h225_info; ++ u_int32_t newip; ++ u_int16_t port; ++ u_int8_t buffer[6]; ++ int i; ++ ++ MUST_BE_LOCKED(&ip_h323_lock); ++ ++ DEBUGP("h323_signal_address_fixup: %s %s\n", ++ between(info->seq[IP_CT_DIR_ORIGINAL], ntohl(tcph->seq), ntohl(tcph->seq) + datalen) ++ ? "yes" : "no", ++ between(info->seq[IP_CT_DIR_REPLY], ntohl(tcph->seq), ntohl(tcph->seq) + datalen) ++ ? "yes" : "no"); ++ if (!(between(info->seq[IP_CT_DIR_ORIGINAL], ntohl(tcph->seq), ntohl(tcph->seq) + datalen) ++ || between(info->seq[IP_CT_DIR_REPLY], ntohl(tcph->seq), ntohl(tcph->seq) + datalen))) ++ return 1; ++ ++ DEBUGP("h323_signal_address_fixup: offsets %u + 6 and %u + 6 in %u\n", ++ info->offset[IP_CT_DIR_ORIGINAL], ++ info->offset[IP_CT_DIR_REPLY], ++ tcplen); ++ DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); ++ DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple); ++ ++ for (i = 0; i < IP_CT_DIR_MAX; i++) { ++ DEBUGP("h323_signal_address_fixup: %s %s\n", ++ info->dir == IP_CT_DIR_ORIGINAL ? "original" : "reply", ++ i == IP_CT_DIR_ORIGINAL ? "caller" : "callee"); ++ if (!between(info->seq[i], ntohl(tcph->seq), ++ ntohl(tcph->seq) + datalen)) ++ continue; ++ if (!between(info->seq[i] + 6, ntohl(tcph->seq), ++ ntohl(tcph->seq) + datalen)) { ++ /* Partial retransmisison. It's a cracker being funky. */ ++ if (net_ratelimit()) { ++ printk("H.323_NAT: partial packet %u/6 in %u/%u\n", ++ info->seq[i], ++ ntohl(tcph->seq), ++ ntohl(tcph->seq) + datalen); ++ } ++ return 0; ++ } ++ ++ /* Change address inside packet to match way we're mapping ++ this connection. */ ++ if (i == IP_CT_DIR_ORIGINAL) { ++ newip = ct->tuplehash[!info->dir].tuple.dst.ip; ++ port = ct->tuplehash[!info->dir].tuple.dst.u.tcp.port; ++ } else { ++ newip = ct->tuplehash[!info->dir].tuple.src.ip; ++ port = ct->tuplehash[!info->dir].tuple.src.u.tcp.port; ++ } ++ ++ data = (char *) tcph + tcph->doff * 4 + info->offset[i]; ++ ++ DEBUGP("h323_signal_address_fixup: orig %s IP:port %u.%u.%u.%u:%u\n", ++ i == IP_CT_DIR_ORIGINAL ? "source" : "dest ", ++ data[0], data[1], data[2], data[3], ++ (data[4] << 8 | data[5])); ++ ++ /* Modify the packet */ ++ memcpy(buffer, &newip, 4); ++ memcpy(buffer + 4, &port, 2); ++ if (!ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, info->offset[i], ++ 6, buffer, 6)) ++ return 0; ++ ++ DEBUGP("h323_signal_address_fixup: new %s IP:port %u.%u.%u.%u:%u\n", ++ i == IP_CT_DIR_ORIGINAL ? "source" : "dest ", ++ data[0], data[1], data[2], data[3], ++ (data[4] << 8 | data[5])); ++ } ++ ++ return 1; ++} ++ ++static int h323_data_fixup(struct ip_ct_h225_expect *info, ++ struct ip_conntrack *ct, ++ struct sk_buff **pskb, ++ enum ip_conntrack_info ctinfo, ++ struct ip_conntrack_expect *expect) ++{ ++ u_int32_t newip; ++ u_int16_t port; ++ u_int8_t buffer[6]; ++ struct ip_conntrack_tuple newtuple; ++ struct iphdr *iph = (*pskb)->nh.iph; ++ struct tcphdr *tcph = (void *)iph + iph->ihl*4; ++ unsigned char *data; ++ u_int32_t tcplen = (*pskb)->len - iph->ihl*4; ++ struct ip_ct_h225_master *master_info = &ct->help.ct_h225_info; ++ int is_h225; ++ ++ MUST_BE_LOCKED(&ip_h323_lock); ++ DEBUGP("h323_data_fixup: offset %u + 6 in %u\n", info->offset, tcplen); ++ DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); ++ DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple); ++ ++ if (!between(expect->seq + 6, ntohl(tcph->seq), ++ ntohl(tcph->seq) + tcplen - tcph->doff * 4)) { ++ /* Partial retransmisison. It's a cracker being funky. */ ++ if (net_ratelimit()) { ++ printk("H.323_NAT: partial packet %u/6 in %u/%u\n", ++ expect->seq, ++ ntohl(tcph->seq), ++ ntohl(tcph->seq) + tcplen - tcph->doff * 4); ++ } ++ return 0; ++ } ++ ++ /* Change address inside packet to match way we're mapping ++ this connection. */ ++ if (info->dir == IP_CT_DIR_REPLY) { ++ /* Must be where client thinks server is */ ++ newip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip; ++ /* Expect something from client->server */ ++ newtuple.src.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; ++ newtuple.dst.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip; ++ } else { ++ /* Must be where server thinks client is */ ++ newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; ++ /* Expect something from server->client */ ++ newtuple.src.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip; ++ newtuple.dst.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; ++ } ++ ++ is_h225 = (master_info->is_h225 == H225_PORT); ++ ++ if (is_h225) { ++ newtuple.dst.protonum = IPPROTO_TCP; ++ newtuple.src.u.tcp.port = expect->tuple.src.u.tcp.port; ++ } else { ++ newtuple.dst.protonum = IPPROTO_UDP; ++ newtuple.src.u.udp.port = expect->tuple.src.u.udp.port; ++ } ++ ++ /* Try to get same port: if not, try to change it. */ ++ for (port = ntohs(info->port); port != 0; port++) { ++ if (is_h225) ++ newtuple.dst.u.tcp.port = htons(port); ++ else ++ newtuple.dst.u.udp.port = htons(port); ++ ++ if (ip_conntrack_change_expect(expect, &newtuple) == 0) ++ break; ++ } ++ if (port == 0) { ++ DEBUGP("h323_data_fixup: no free port found!\n"); ++ return 0; ++ } ++ ++ port = htons(port); ++ ++ data = (char *) tcph + tcph->doff * 4 + info->offset; ++ ++ DEBUGP("h323_data_fixup: orig IP:port %u.%u.%u.%u:%u\n", ++ data[0], data[1], data[2], data[3], ++ (data[4] << 8 | data[5])); ++ ++ /* Modify the packet */ ++ memcpy(buffer, &newip, 4); ++ memcpy(buffer + 4, &port, 2); ++ if (!ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, info->offset, ++ 6, buffer, 6)) ++ return 0; ++ ++ DEBUGP("h323_data_fixup: new IP:port %u.%u.%u.%u:%u\n", ++ data[0], data[1], data[2], data[3], ++ (data[4] << 8 | data[5])); ++ ++ return 1; ++} ++ ++static unsigned int h225_nat_help(struct ip_conntrack *ct, ++ struct ip_conntrack_expect *exp, ++ struct ip_nat_info *info, ++ enum ip_conntrack_info ctinfo, ++ unsigned int hooknum, ++ struct sk_buff **pskb) ++{ ++ int dir; ++ struct ip_ct_h225_expect *exp_info; ++ ++ /* Only mangle things once: original direction in POST_ROUTING ++ and reply direction on PRE_ROUTING. */ ++ dir = CTINFO2DIR(ctinfo); ++ DEBUGP("nat_h323: dir %s at hook %s\n", ++ dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY", ++ hooknum == NF_IP_POST_ROUTING ? "POSTROUTING" ++ : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING" ++ : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???"); ++ if (!((hooknum == NF_IP_POST_ROUTING && dir == IP_CT_DIR_ORIGINAL) ++ || (hooknum == NF_IP_PRE_ROUTING && dir == IP_CT_DIR_REPLY))) { ++ DEBUGP("nat_h323: Not touching dir %s at hook %s\n", ++ dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY", ++ hooknum == NF_IP_POST_ROUTING ? "POSTROUTING" ++ : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING" ++ : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???"); ++ return NF_ACCEPT; ++ } ++ ++ if (!exp) { ++ LOCK_BH(&ip_h323_lock); ++ if (!h323_signal_address_fixup(ct, pskb, ctinfo)) { ++ UNLOCK_BH(&ip_h323_lock); ++ return NF_DROP; ++ } ++ UNLOCK_BH(&ip_h323_lock); ++ return NF_ACCEPT; ++ } ++ ++ exp_info = &exp->help.exp_h225_info; ++ ++ LOCK_BH(&ip_h323_lock); ++ if (!h323_data_fixup(exp_info, ct, pskb, ctinfo, exp)) { ++ UNLOCK_BH(&ip_h323_lock); ++ return NF_DROP; ++ } ++ UNLOCK_BH(&ip_h323_lock); ++ ++ return NF_ACCEPT; ++} ++ ++static struct ip_nat_helper h225 = ++ { { NULL, NULL }, ++ "H.225", /* name */ ++ IP_NAT_HELPER_F_ALWAYS, /* flags */ ++ THIS_MODULE, /* module */ ++ { { 0, { __constant_htons(H225_PORT) } }, /* tuple */ ++ { 0, { 0 }, IPPROTO_TCP } }, ++ { { 0, { 0xFFFF } }, /* mask */ ++ { 0, { 0 }, 0xFFFF } }, ++ h225_nat_help, /* helper */ ++ h225_nat_expected /* expectfn */ ++ }; ++ ++static int __init init(void) ++{ ++ int ret; ++ ++ ret = ip_nat_helper_register(&h225); ++ ++ if (ret != 0) ++ printk("ip_nat_h323: cannot initialize the module!\n"); ++ ++ return ret; ++} ++ ++static void __exit fini(void) ++{ ++ ip_nat_helper_unregister(&h225); ++} ++ ++module_init(init); ++module_exit(fini); +diff -urN linux-2.4.32/include/linux/netfilter_ipv4/ip_conntrack.h linux-2.4.32.new/include/linux/netfilter_ipv4/ip_conntrack.h +--- linux-2.4.32/include/linux/netfilter_ipv4/ip_conntrack.h 2006-03-01 00:49:36.474532856 +0100 ++++ linux-2.4.32.new/include/linux/netfilter_ipv4/ip_conntrack.h 2006-03-01 00:50:18.699113744 +0100 +@@ -71,6 +71,7 @@ + #include + #include + #include ++#include + + /* per expectation: application helper private data */ + union ip_conntrack_expect_help { +@@ -79,6 +80,7 @@ + struct ip_ct_ftp_expect exp_ftp_info; + struct ip_ct_irc_expect exp_irc_info; + struct ip_ct_pptp_expect exp_pptp_info; ++ struct ip_ct_h225_expect exp_h225_info; + + #ifdef CONFIG_IP_NF_NAT_NEEDED + union { +@@ -93,6 +95,7 @@ + struct ip_ct_ftp_master ct_ftp_info; + struct ip_ct_irc_master ct_irc_info; + struct ip_ct_pptp_master ct_pptp_info; ++ struct ip_ct_h225_master ct_h225_info; + }; + + #ifdef CONFIG_IP_NF_NAT_NEEDED +diff -urN linux-2.4.32/include/linux/netfilter_ipv4/ip_conntrack_h323.h linux-2.4.32.new/include/linux/netfilter_ipv4/ip_conntrack_h323.h +--- linux-2.4.32/include/linux/netfilter_ipv4/ip_conntrack_h323.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.32.new/include/linux/netfilter_ipv4/ip_conntrack_h323.h 2006-03-01 00:50:18.700113592 +0100 +@@ -0,0 +1,30 @@ ++#ifndef _IP_CONNTRACK_H323_H ++#define _IP_CONNTRACK_H323_H ++/* H.323 connection tracking. */ ++ ++#ifdef __KERNEL__ ++/* Protects H.323 related data */ ++DECLARE_LOCK_EXTERN(ip_h323_lock); ++#endif ++ ++/* Default H.225 port */ ++#define H225_PORT 1720 ++ ++/* This structure is per expected connection */ ++struct ip_ct_h225_expect { ++ u_int16_t port; /* Port of the H.225 helper/RTCP/RTP channel */ ++ enum ip_conntrack_dir dir; /* Direction of the original connection */ ++ unsigned int offset; /* offset of the address in the payload */ ++}; ++ ++/* This structure exists only once per master */ ++struct ip_ct_h225_master { ++ int is_h225; /* H.225 or H.245 connection */ ++#ifdef CONFIG_IP_NF_NAT_NEEDED ++ enum ip_conntrack_dir dir; /* Direction of the original connection */ ++ u_int32_t seq[IP_CT_DIR_MAX]; /* Exceptional packet mangling for signal addressess... */ ++ unsigned int offset[IP_CT_DIR_MAX]; /* ...and the offset of the addresses in the payload */ ++#endif ++}; ++ ++#endif /* _IP_CONNTRACK_H323_H */ diff --git a/openwrt/target/linux/generic-2.4/patches/613-netfilter_nat_sip.patch b/openwrt/target/linux/generic-2.4/patches/613-netfilter_nat_sip.patch deleted file mode 100644 index 3ccbe94d0b..0000000000 --- a/openwrt/target/linux/generic-2.4/patches/613-netfilter_nat_sip.patch +++ /dev/null @@ -1,1254 +0,0 @@ -diff -urN linux-2.4.32/net/ipv4/netfilter/Config.in linux-2.4.32.new/net/ipv4/netfilter/Config.in ---- linux-2.4.32/net/ipv4/netfilter/Config.in 2006-02-04 19:16:25.000000000 +0100 -+++ linux-2.4.32.new/net/ipv4/netfilter/Config.in 2006-02-04 19:00:13.000000000 +0100 -@@ -15,6 +15,7 @@ - dep_tristate ' Connection byte counter support' CONFIG_IP_NF_MATCH_CONNBYTES $CONFIG_IP_NF_CT_ACCT $CONFIG_IP_NF_CONNTRACK $CONFIG_IP_NF_IPTABLES - dep_tristate ' GRE protocol support' CONFIG_IP_NF_CT_PROTO_GRE $CONFIG_IP_NF_CONNTRACK - dep_tristate ' PPTP protocol support' CONFIG_IP_NF_PPTP $CONFIG_IP_NF_CT_PROTO_GRE -+ dep_tristate ' SIP protocol support' CONFIG_IP_NF_SIP $CONFIG_IP_NF_CONNTRACK - fi - - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then -@@ -103,6 +104,13 @@ - define_tristate CONFIG_IP_NF_NAT_PROTO_GRE $CONFIG_IP_NF_NAT - fi - fi -+ if [ "$CONFIG_IP_NF_SIP" = "m" ]; then -+ define_tristate CONFIG_IP_NF_NAT_SIP m -+ else -+ if [ "$CONFIG_IP_NF_SIP" = "y" ]; then -+ define_tristate CONFIG_IP_NF_NAT_SIP $CONFIG_IP_NF_NAT -+ fi -+ fi - if [ "$CONFIG_IP_NF_AMANDA" = "m" ]; then - define_tristate CONFIG_IP_NF_NAT_AMANDA m - else -diff -urN linux-2.4.32/net/ipv4/netfilter/ip_conntrack_sip.c linux-2.4.32.new/net/ipv4/netfilter/ip_conntrack_sip.c ---- linux-2.4.32/net/ipv4/netfilter/ip_conntrack_sip.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.32.new/net/ipv4/netfilter/ip_conntrack_sip.c 2006-02-04 19:06:01.000000000 +0100 -@@ -0,0 +1,312 @@ -+/* -+ * SIP extension for IP connection tracking. -+ * -+ * Copyright (C) 2004, CyberTAN Corporation -+ * All Rights Reserved. -+ * -+ * THIS SOFTWARE IS OFFERED "AS IS", AND CYBERTAN GRANTS NO WARRANTIES OF ANY -+ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. CYBERTAN -+ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS -+ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+DECLARE_LOCK(ip_sip_lock); -+ -+struct module *ip_conntrack_sip = THIS_MODULE; -+ -+#define MAX_PORTS 8 -+static int ports[MAX_PORTS]; -+static int ports_c; -+#ifdef MODULE_PARM -+MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i"); -+#endif -+ -+#if 0 -+ #define DEBUGP printk -+#else -+ #define DEBUGP(format, args...) -+#endif -+ -+#define RTCP_SUPPORT -+ -+static int set_expected_rtp(struct ip_conntrack *ct, u_int32_t dstip, -+ u_int16_t dstport, unsigned int conntype) -+{ -+ struct ip_conntrack_expect expect, *exp = &expect; -+ struct ip_ct_sip_expect *exp_sip_info = &exp->help.exp_sip_info; -+ int ret = 0; -+ -+ memset(&expect, 0, sizeof(expect)); -+ LOCK_BH(&ip_sip_lock); -+ -+ DEBUGP("conntrack_sip: %s: [%s]: DST=%u.%u.%u.%u:%u\n", __FUNCTION__, -+ conntype == CONN_RTP ? "RTP" : "RTCP", NIPQUAD(dstip), dstport); -+ -+ /* exp_sip_info */ -+ exp_sip_info->port = dstport; -+ exp_sip_info->type = conntype; -+ exp_sip_info->nated = 0; -+ -+ /* new expectation */ -+ exp->tuple = ((struct ip_conntrack_tuple) -+ { { 0, { 0 } }, -+ { dstip, { htons(dstport) }, IPPROTO_UDP }}); -+ exp->mask = ((struct ip_conntrack_tuple) -+ { { 0, { 0 } }, -+ { 0xFFFFFFFF, { 0xFFFF }, 0xFFFF }}); -+ exp->expectfn = NULL; -+ -+ if ((ret=ip_conntrack_expect_related(ct, exp)) != 0) { -+ DEBUGP("Can't add new expectation. \n"); -+ } -+ -+ UNLOCK_BH(&ip_sip_lock); -+ -+ return ret; -+} -+ -+/* -+static int unset_expected_rtp(struct ip_conntrack *ct, u_int32_t dstip, u_int16_t dstport) -+{ -+ struct ip_conntrack_expect *exp; -+ const struct ip_conntrack_tuple tuple = { { 0, { 0 } }, -+ { dstip, { htons(dstport) }, IPPROTO_UDP }}; -+ -+ LOCK_BH(&ip_sip_lock); -+ -+ exp = ip_conntrack_expect_find_get(&tuple); -+ if (exp) { -+ DEBUGP("Find the expectation %p, then delete it.\n", exp); -+ ip_conntrack_unexpect_related(exp); -+ } -+ -+ UNLOCK_BH(&ip_sip_lock); -+ -+ return 0; -+}*/ -+ -+/* return: -+ * 0 : Not found -+ * 1 : Found domain name -+ * 2 : Found dotted quads -+ */ -+int find_sdp_rtp_addr(const char *data, size_t dlen, -+ unsigned int *numoff, unsigned int *numlen, u_int32_t *addr) -+{ -+ char *st, *p = (char *)data; -+ const char *limit = data + dlen; -+ unsigned char p1, p2, p3, p4; -+ -+ while (p < limit) { -+ /* find 'c=' line */ -+ if (strncmp(p, "\nc=",3) && strncmp(p, "\rc=",3)) { -+ p++; -+ continue; -+ } -+ p += 3; -+ -+ if (strncmp(p, "IN IP4 ",7)) -+ continue; -+ p += 7; -+ -+ /* IP address */ -+ st = p; -+ -+ /* FQDNs or dotted quads */ -+ while (isalpha(*p) || isdigit(*p) || (*p=='.') || (*p=='-')) { -+ p++; -+ if (p == limit) -+ return 0; -+ } -+ -+ *numoff = st - data; -+ *numlen = p - st; -+ -+ /* Convert the IP address */ -+ p1 = simple_strtoul(st, &st ,10); -+ if (*st != '.') -+ return 1; -+ p2 = simple_strtoul(st+1, &st, 10); -+ if (*st != '.') -+ return 1; -+ p3 = simple_strtoul(st+1, &st, 10); -+ if (*st != '.') -+ return 1; -+ p4 = simple_strtoul(st+1, &st, 10); -+ -+ *addr = (p1<<24) | (p2<<16) | (p3<<8) | p4; -+ -+ return 2; -+ } -+ -+ return 0; -+} -+ -+u_int16_t find_sdp_audio_port(const char *data, size_t dlen, -+ unsigned int *numoff, unsigned int *numlen) -+{ -+ char *st, *p = (char *)data; -+ const char *limit = data + dlen; -+ u_int16_t port = 0; -+ -+ while (p < limit) { -+ /* find 'm=' */ -+ if (strncmp(p, "\nm=", 3) && strncmp(p, "\rm=", 3)) { -+ p++; -+ continue; -+ } -+ p += 3; -+ -+ /* audio stream */ -+ if (strncmp(p ,"audio ",6)) -+ continue; -+ p += 6; -+ -+ st = p; -+ port = simple_strtoul(p, &p, 10); -+ -+ *numoff = st - data; -+ *numlen = p - st; -+ -+ return port; -+ } -+ -+ return 0; -+} -+ -+static int help(const struct iphdr *iph, size_t len, -+ struct ip_conntrack *ct, -+ enum ip_conntrack_info ctinfo) -+{ -+ int dir = CTINFO2DIR(ctinfo); -+ unsigned int matchlen, matchoff; -+ -+ u_int32_t ipaddr=0; -+ u_int16_t port = 0; -+ -+ int found = 0; -+ struct udphdr *udph = (void *)iph + iph->ihl * 4; -+ const char *data = (const char *)udph + 8; -+ unsigned int udplen = len - iph->ihl * 4; -+ unsigned int datalen = udplen - 8; -+ struct ip_ct_sip_master *ct_sip_info = &ct->help.ct_sip_info; -+ -+ DEBUGP("\nconntrack_sip: help(): DIR=%d, conntrackinfo=%u\n", dir, ctinfo); -+ DEBUGP("conntrack_sip: %u.%u.%u.%u:%u -> %u.%u.%u.%u:%u\n", -+ NIPQUAD(ct->tuplehash[dir].tuple.src.ip), -+ ntohs(ct->tuplehash[dir].tuple.src.u.udp.port), -+ NIPQUAD(ct->tuplehash[dir].tuple.dst.ip), -+ ntohs(ct->tuplehash[dir].tuple.dst.u.udp.port) ); -+ -+ /* Reset for a new incoming packet */ -+ ct_sip_info->mangled = 0; -+ -+ /* keep the connection alive */ -+ ip_ct_refresh_acct(ct, ctinfo, iph, (SIP_EXPIRES * HZ)); -+ -+ /* Don't need to set the expectation for upstream direction */ -+ if (dir == IP_CT_DIR_REPLY) -+ return NF_ACCEPT; -+ -+ /* Need to set the expected connection for further incoming RTP stream */ -+ if (strncmp(data, "INVITE", 6) != 0 && strncmp(data, "SIP/2.0 200", 11) != 0) { -+ DEBUGP("conntrack_sip: Not interesting packet.\n"); -+ return NF_ACCEPT; -+ } -+ -+ /* Find RTP address */ -+ found = find_sdp_rtp_addr(data, datalen, &matchoff, &matchlen, &ipaddr); -+ if (!found) -+ return NF_ACCEPT; -+ -+ DEBUGP("conntrack_sip: 'IN IP4' is %s.\n", (found == 1) ? "FQDNs" : "dotted quads"); -+ -+ /* If it's a null address, then the call is on hold */ -+ if (found == 2 && ipaddr == 0) { -+ DEBUGP("conntrack_sip: Null address is found.\n"); -+ return NF_ACCEPT; -+ } -+ -+ /* Find audio port, and we don't like the well-known ports, -+ * which is less than 1024 */ -+ port = find_sdp_audio_port(data, datalen, &matchoff, &matchlen); -+ if (port < 1024) -+ return NF_ACCEPT; -+ -+ DEBUGP("conntrack_sip: audio port=%d.\n", port); -+ -+ ipaddr = ct->tuplehash[dir].tuple.src.ip; -+ ct_sip_info->rtpport = port; -+ -+ /* RFC1889 - RTP uses an even port number and the corresponding RTCP -+ * stream uses the next higher (odd) port number. */ -+ if (set_expected_rtp(ct, ipaddr, port, CONN_RTP) == 0) { -+#ifdef RTCP_SUPPORT -+ set_expected_rtp(ct, ipaddr, port + 1, CONN_RTCP); -+#endif -+ } -+ -+ return NF_ACCEPT; -+} -+ -+static struct ip_conntrack_helper sip[MAX_PORTS]; -+ -+ -+/* Not __exit: called from init() */ -+static void fini(void) -+{ -+ int i; -+ for (i = 0; (i < MAX_PORTS) && ports[i]; i++) { -+ DEBUGP("ip_ct_sip: unregistering helper for port %d\n", -+ ports[i]); -+ ip_conntrack_helper_unregister(&sip[i]); -+ } -+} -+ -+static int __init init(void) -+{ -+ int i, ret; -+ -+ if (ports[0] == 0) -+ ports[0] = SIP_PORT; -+ -+ for (i = 0; (i < MAX_PORTS) && ports[i]; i++) { -+ memset(&sip[i], 0, sizeof(struct ip_conntrack_helper)); -+ sip[i].tuple.dst.u.udp.port = htons(ports[i]); -+ sip[i].tuple.dst.protonum = IPPROTO_UDP; -+ sip[i].mask.dst.u.udp.port = 0xF0FF; -+ sip[i].mask.dst.protonum = 0xFFFF; -+ sip[i].help = help; -+ sip[i].timeout = RTP_TIMEOUT; -+ DEBUGP("ip_ct_sip: registering helper for port %d\n", -+ ports[i]); -+ ret = ip_conntrack_helper_register(&sip[i]); -+ -+ if (ret) { -+ fini(); -+ return ret; -+ } -+ ports_c++; -+ } -+ return 0; -+} -+ -+ -+EXPORT_SYMBOL(ip_sip_lock); -+EXPORT_SYMBOL(ip_conntrack_sip); -+ -+module_init(init); -+module_exit(fini); -diff -urN linux-2.4.32/net/ipv4/netfilter/ip_nat_sip.c linux-2.4.32.new/net/ipv4/netfilter/ip_nat_sip.c ---- linux-2.4.32/net/ipv4/netfilter/ip_nat_sip.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.32.new/net/ipv4/netfilter/ip_nat_sip.c 2006-02-04 19:00:13.000000000 +0100 -@@ -0,0 +1,800 @@ -+/* -+ * SIP extension for TCP NAT alteration. -+ * -+ * Copyright (C) 2004, CyberTAN Corporation -+ * All Rights Reserved. -+ * -+ * THIS SOFTWARE IS OFFERED "AS IS", AND CYBERTAN GRANTS NO WARRANTIES OF ANY -+ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. CYBERTAN -+ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS -+ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#if 0 -+ #define DEBUGP printk -+#else -+ #define DEBUGP(format, args...) -+#endif -+ -+#define MAX_PORTS 8 -+static int ports[MAX_PORTS]; -+static int ports_c = 0; -+ -+#ifdef MODULE_PARM -+MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i"); -+#endif -+ -+DECLARE_LOCK_EXTERN(ip_sip_lock); -+ -+#define RTCP_SUPPORT -+ -+/* down(stream): caller -> callee -+ up(stream): caller <- callee */ -+ -+ -+/* Return 1 for match, 0 for accept, -1 for partial. */ -+static int find_pattern(const char *data, size_t dlen, -+ const char *pattern, size_t plen, -+ char skip, char term, -+ unsigned int *numoff, -+ unsigned int *numlen -+ ) -+{ -+ size_t i, j, k; -+ -+// DEBUGP("find_pattern `%s': dlen = %u\n", pattern, dlen); -+ if (dlen == 0) -+ return 0; -+ -+ if (dlen <= plen) { -+ /* Short packet: try for partial? */ -+ if (strnicmp(data, pattern, dlen) == 0) -+ return -1; -+ else return 0; -+ } -+ -+ for(i=0; i<= (dlen - plen); i++){ -+ if( memcmp(data + i, pattern, plen ) != 0 ) continue; -+ -+ /* patten match !! */ -+ *numoff=i + plen; -+ for (j=*numoff, k=0; data[j] != term; j++, k++) -+ if( j > dlen ) return -1 ; /* no terminal char */ -+ -+ *numlen = k; -+ return 1; -+ } -+ -+ return 0; -+} -+ -+static unsigned int -+sip_nat_expected(struct sk_buff **pskb, -+ unsigned int hooknum, -+ struct ip_conntrack *ct, -+ struct ip_nat_info *info) -+{ -+ struct ip_nat_multi_range mr; -+ u_int32_t newdstip, newsrcip, newip; -+ struct ip_ct_sip_expect *exp_sip_info; -+ struct ip_conntrack *master = master_ct(ct); -+ -+ IP_NF_ASSERT(info); -+ IP_NF_ASSERT(master); -+ IP_NF_ASSERT(!(info->initialized & (1<master->help.exp_sip_info; -+ -+ LOCK_BH(&ip_sip_lock); -+ -+ /* Outer machine IP */ -+ newsrcip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; -+ /* Client (virtual) IP under NAT */ -+ newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; -+ -+ UNLOCK_BH(&ip_sip_lock); -+ -+ if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC) -+ newip = newsrcip; -+ else -+ newip = newdstip; -+ -+ DEBUGP("sip_nat_expected: IP to %u.%u.%u.%u:%u\n", NIPQUAD(newip), -+ htons(exp_sip_info->port)); -+ -+ mr.rangesize = 1; -+ /* We don't want to manip the per-protocol, just the IPs... */ -+ mr.range[0].flags = IP_NAT_RANGE_MAP_IPS; -+ mr.range[0].min_ip = mr.range[0].max_ip = newip; -+ -+ /* ... unless we're doing a MANIP_DST, in which case, make -+ sure we map to the correct port */ -+ if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST) { -+ mr.range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED; -+ mr.range[0].min = mr.range[0].max -+ = ((union ip_conntrack_manip_proto) -+ { htons(exp_sip_info->port) }); -+ } -+ -+ return ip_nat_setup_info(ct, &mr, hooknum); -+} -+ -+static int _find_sip_via_addrport(const char *data, size_t dlen, -+ unsigned int *numoff, unsigned int *numlen) -+{ -+ const char *addr, *p = data; -+ const char *limit = data + dlen; -+ -+ while (p < limit) { -+ /* Find the topmost via tag */ -+ if (strnicmp(p, "\nvia:",5) && strnicmp(p, "\nv:",3) && -+ strnicmp(p, "\rvia:",5) && strnicmp(p, "\rv:",3)) { -+ p++; -+ continue; -+ } -+ -+ /* Look for UDP */ -+ while (*p!='U' && *p!='u') { -+ if (p == limit) -+ return 0; -+ p++; -+ } -+ p+= 3; -+ -+ if (p >= limit) -+ return 0; -+ -+ /* Skip a space */ -+ while (*p == ' '){ -+ if (p == limit) -+ return 0; -+ p++; -+ } -+ -+ /* IP address */ -+ addr = p; -+ -+ /* FQDNs or dotted quads */ -+ while (isalpha(*p) || isdigit(*p) || (*p=='.') || (*p=='-')) { -+ p++; -+ if (p == limit) -+ return 0; -+ } -+ -+ /* If there is a port number, skip it */ -+ if (*p == ':') { -+ p++; -+ if (p == limit) -+ return 0; -+ -+ while (isdigit(*p)) { -+ p++; -+ if (p == limit) -+ return 0; -+ } -+ } -+ -+ *numoff = addr - data; -+ *numlen = p - addr; -+ -+ return 1; -+ } -+ -+ return 0; /* Not found */ -+} -+ -+static int _mangle_sip_via(struct ip_conntrack *ct, enum ip_conntrack_info ctinfo, -+ struct sk_buff **pskb, u_int32_t newip, u_int16_t newport, -+ unsigned int numoff, unsigned int numlen) -+{ -+ int buflen; -+ char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")]; -+ -+ sprintf(buffer, "%u.%u.%u.%u:%u", NIPQUAD(newip), newport); -+ buflen = strlen(buffer); -+ -+ MUST_BE_LOCKED(&ip_sip_lock); -+ -+ if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo, numoff, -+ numlen, buffer, buflen) ) -+ return 0; -+ -+ DEBUGP("(SIP) Via is changed to %s.\n", buffer); -+ -+ return buflen - numlen; -+} -+ -+static int mangle_sip_via(struct ip_conntrack *ct, enum ip_conntrack_info ctinfo, -+ struct sk_buff **pskb, u_int32_t newip, u_int16_t newport) -+{ -+ struct iphdr *iph = (*pskb)->nh.iph; -+ struct udphdr *udph = (void *)iph + iph->ihl * 4; -+ const char *data = (const char *)udph + 8; -+ unsigned int udplen = ntohs(iph->tot_len) - (iph->ihl * 4); -+ unsigned int datalen = udplen - 8; -+ unsigned int matchoff, matchlen; -+ -+ /* Find the topmost via tag */ -+ _find_sip_via_addrport(data , datalen, &matchoff, &matchlen); -+ return _mangle_sip_via(ct, ctinfo, pskb, newip, newport, -+ matchoff, matchlen); -+} -+ -+static int mangle_sip_contact(struct ip_conntrack *ct, enum ip_conntrack_info ctinfo, -+ struct sk_buff **pskb, u_int32_t newip, u_int16_t newport) -+{ -+ struct iphdr *iph = (*pskb)->nh.iph; -+ struct udphdr *udph = (void *)iph + iph->ihl * 4; -+ const char *data = (const char *)udph + 8; -+ unsigned int udplen = ntohs(iph->tot_len) - (iph->ihl * 4); -+ unsigned int datalen = udplen - 8; -+ -+ int buflen, diff_len = 0; -+ char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")]; -+ const char *uri, *addr, *p = data; -+ const char *limit = data + datalen; -+ -+ -+ while (p < limit) { -+ if (strnicmp(p, "\ncontact:", 9) && strnicmp(p, "\nm:", 3) && -+ strnicmp(p, "\rcontact:", 9) && strnicmp(p, "\rm:", 3)) { -+ p++; -+ continue; -+ } -+ -+ while (strnicmp(p, "sip:", 4)) { -+ if (p == limit) -+ return 0; -+ p++; -+ } -+ p += 4; -+ -+ /* If there is user info in the contact */ -+ uri = p; -+ -+ while (*p!='@' && *p!='>' && *p!=';' && *p!='\n' && *p!='\r' && *p!='?' && *p!=',') { -+ if (p == limit) -+ return 0; -+ p++; -+ } -+ -+ if (*p=='@') -+ p++; -+ else -+ p = uri; /* back to previous URI pointer */ -+ -+ /* IP address */ -+ addr = p; -+ -+ /* FQDNs or dotted quads */ -+ while (isalpha(*p) || isdigit(*p) || (*p=='.') || (*p=='-')) { -+ p++; -+ if (p == limit) -+ return 0; -+ } -+ -+ /* If there is a port number, skip it */ -+ if (*p==':') { -+ p++; -+ while (isdigit(*p)) -+ p++; -+ } -+ -+ sprintf(buffer, "%u.%u.%u.%u:%u", NIPQUAD(newip), newport); -+ buflen = strlen(buffer); -+ -+ MUST_BE_LOCKED(&ip_sip_lock); -+ -+ if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo, addr - data, -+ p - addr, buffer, buflen) ) -+ return 0; -+ -+ diff_len = buflen - (p - addr); -+ DEBUGP("(SIP) Contact is changed to %s.\n", buffer); -+ break; -+ } -+ -+ return diff_len; -+} -+ -+static int _find_sip_content_length_size(const char *data, size_t dlen, -+ unsigned int *numoff, unsigned int *numlen) -+{ -+ char *st, *p = (char *)data; -+ const char *limit = data + dlen; -+ int size = 0; -+ -+ while (p < limit) { -+ if (strnicmp(p, "\nContent-Length:", 16) && strnicmp(p, "\nl:", 3) && -+ strnicmp(p, "\rContent-Length:", 16) && strnicmp(p, "\rm:", 3)) { -+ p++; -+ continue; -+ } -+ -+ /* Go through the string above */ -+ while (*p != ':') { -+ if (p == limit) -+ return 0; -+ p++; -+ } -+ p++; -+ -+ while (*p == ' ') { -+ if (p == limit) -+ return 0; -+ p++; -+ } -+ -+ st = p; -+ size = simple_strtoul(p, &p, 10); -+ -+ *numoff = st - data; -+ *numlen = p - st; -+ -+ return size; -+ } -+ -+ return 0; -+} -+ -+static int mangle_sip_content_length(struct ip_conntrack *ct, enum ip_conntrack_info ctinfo, -+ struct sk_buff **pskb, int diff_len) -+{ -+ struct iphdr *iph = (*pskb)->nh.iph; -+ struct udphdr *udph = (void *)iph + iph->ihl * 4; -+ const char *data = (const char *)udph + 8; -+ unsigned int udplen = ntohs(iph->tot_len) - (iph->ihl * 4); -+ unsigned int datalen = udplen - 8; -+ -+ unsigned int matchlen, matchoff; -+ int size, buflen; -+ char buffer[sizeof("nnnnn")]; -+ -+ /* original legth */ -+ size = _find_sip_content_length_size(data, datalen, &matchoff, &matchlen); -+ -+ /* new legth */ -+ sprintf(buffer, "%u", size + diff_len); -+ buflen = strlen(buffer); -+ -+ if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo, matchoff, -+ matchlen, buffer, buflen) ) -+ return 0; -+ -+ DEBUGP("(SDP) Content-Length is changed %d->%s.\n", size, buffer); -+ return buflen - matchlen; -+ -+} -+ -+static int mangle_sip_sdp_content(struct ip_conntrack *ct, enum ip_conntrack_info ctinfo, -+ struct sk_buff **pskb, u_int32_t newip, u_int16_t newport) -+{ -+ struct iphdr *iph = (*pskb)->nh.iph; -+ struct udphdr *udph = (void *)iph + iph->ihl * 4; -+ const char *data = (const char *)udph + 8; -+ unsigned int udplen = ntohs(iph->tot_len) - (iph->ihl * 4); -+ unsigned int datalen = udplen - 8; -+ -+ unsigned int matchlen, matchoff; -+ int found, buflen, diff_len = 0; -+ char buffer[sizeof("nnn.nnn.nnn.nnn")]; -+ char *addr, *p; -+ char *limit = (char *)data + datalen; -+ u_int32_t ipaddr = 0; -+ u_int16_t getport; -+ int dir; -+ -+ /* Find RTP address */ -+ found = find_sdp_rtp_addr(data, datalen, &matchoff, &matchlen, &ipaddr); -+ if (found) { -+ /* If it's a null address, then the call is on hold */ -+ if (found == 2 && ipaddr == 0) -+ return 0; -+ -+ sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(newip)); -+ buflen = strlen(buffer); -+ -+ MUST_BE_LOCKED(&ip_sip_lock); -+ -+ if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo, matchoff, -+ matchlen, buffer, buflen) ) -+ return 0; -+ -+ diff_len += (buflen - matchlen); -+ DEBUGP("(SDP) RTP address is changed to %s.\n", buffer); -+ } -+ -+ /* Find audio port */ -+ getport = find_sdp_audio_port(data, datalen, &matchoff, &matchlen); -+ if (getport != newport) { -+ sprintf(buffer, "%d", newport); -+ buflen = strlen(buffer); -+ -+ MUST_BE_LOCKED(&ip_sip_lock); -+ -+ if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo, matchoff, -+ matchlen, buffer, buflen) ) -+ return 0; -+ -+ diff_len += (buflen - matchlen); -+ DEBUGP("(SDP) audio port is changed to %d.\n", newport); -+ } -+ -+ dir = CTINFO2DIR(ctinfo); -+ if (dir == IP_CT_DIR_ORIGINAL) -+ return diff_len; -+ -+ /* Find Session ID address */ -+ found = find_pattern(data, datalen, " IN IP4 ", 8, ' ', '\r', -+ &matchoff, &matchlen); -+ if (found) { -+ p = addr = (char *)data + matchoff; -+ -+ /* FQDNs or dotted quads */ -+ while (isalpha(*p) || isdigit(*p) || (*p=='.') || (*p=='-')) { -+ p++; -+ if (p == limit) -+ return 0; -+ } -+ -+ sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(newip)); -+ buflen = strlen(buffer); -+ -+ MUST_BE_LOCKED(&ip_sip_lock); -+ -+ if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo, addr - data, -+ p - addr, buffer, buflen) ) -+ return 0; -+ -+ diff_len += (buflen - (p - addr)); -+ DEBUGP("(SDP) Session ID is changed to %s.\n", buffer); -+ } -+ -+ return diff_len; -+} -+ -+static int mangle_sip_packet(struct ip_conntrack *ct, enum ip_conntrack_info ctinfo, -+ struct sk_buff **pskb, u_int32_t newip) -+{ -+ struct iphdr *iph = (*pskb)->nh.iph; -+ struct udphdr *udph = (void *)iph + iph->ihl * 4; -+ const char *data = (const char *)udph + 8; -+ int diff_len = 0; -+ struct ip_ct_sip_master *ct_sip_info = &ct->help.ct_sip_info; -+ u_int16_t natport = ntohs(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.udp.port); -+ -+ DEBUGP("nat_sip: %s:(%d)\n", __FUNCTION__, __LINE__); -+ -+ ct_sip_info->mangled = 1; -+ -+ /* Changes the via, if this is a request */ -+ if (strnicmp(data,"SIP/2.0",7) != 0) { -+ mangle_sip_via(ct, ctinfo, pskb, newip, natport); -+ } -+ -+ mangle_sip_contact(ct, ctinfo, pskb, newip, natport); -+ -+ if ((diff_len = mangle_sip_sdp_content(ct, ctinfo, pskb, newip, ct_sip_info->rtpport)) != 0) -+ mangle_sip_content_length(ct, ctinfo, pskb, diff_len); -+ -+ return 1; -+} -+ -+static struct ip_conntrack_expect * -+expect_find(struct ip_conntrack *ct, u_int32_t dstip, u_int16_t dstport) -+{ -+ const struct ip_conntrack_tuple tuple = { { 0, { 0 } }, -+ { dstip, { htons(dstport) }, IPPROTO_UDP }}; -+ -+ return ip_conntrack_expect_find_get(&tuple); -+ -+} -+ -+static int sip_out_data_fixup(struct ip_conntrack *ct, -+ struct sk_buff **pskb, -+ enum ip_conntrack_info ctinfo, -+ struct ip_conntrack_expect *expect) -+{ -+ struct ip_conntrack_tuple newtuple; -+ struct ip_ct_sip_master *ct_sip_info = &ct->help.ct_sip_info; -+ struct ip_ct_sip_expect *exp_sip_info; -+ u_int32_t wanip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; // NAT wan ip -+ u_int16_t port = 0; -+#ifdef RTCP_SUPPORT -+ struct ip_conntrack_expect *rtcp_exp; -+#endif -+ -+ MUST_BE_LOCKED(&ip_sip_lock); -+ -+ if (expect) { -+ DEBUGP("nat_sip: %s: There is a exp %p.\n", __FUNCTION__, expect); -+ -+ exp_sip_info = &expect->help.exp_sip_info; -+ if (exp_sip_info->nated) { -+ DEBUGP("nat_sip: %s: The exp %p had been changed.\n", __FUNCTION__, expect); -+ goto mangle; -+ } -+ -+ /* RTP expect */ -+ if (exp_sip_info->type == CONN_RTP) { -+ port = ntohs(expect->tuple.dst.u.udp.port); -+#ifdef RTCP_SUPPORT -+ rtcp_exp = expect_find(ct, expect->tuple.dst.ip, port + 1); -+#endif -+ /* RFC1889 - If an application is supplied with an odd number -+ * for use as the RTP port, it should replace this number with -+ * the next lower (even) number. */ -+ if (port % 2) -+ port++; -+ -+ /* fullfill newtuple */ -+ newtuple.dst.ip = wanip; -+ newtuple.src.ip = expect->tuple.src.ip; -+ newtuple.dst.protonum = expect->tuple.dst.protonum; -+ -+ /* Try to get same port: if not, try to change it. */ -+ for (; port != 0; port += 2) { -+ newtuple.dst.u.udp.port = htons(port); -+ if (ip_conntrack_change_expect(expect, &newtuple) == 0) { -+#ifdef RTCP_SUPPORT -+ /* Change RTCP */ -+ if (rtcp_exp) { -+ DEBUGP("nat_sip: %s: RTCP exp %p found.\n", -+ __FUNCTION__, rtcp_exp); -+ newtuple.dst.u.udp.port = htons(port + 1); -+ if (ip_conntrack_change_expect(rtcp_exp, &newtuple) != 0) { -+ DEBUGP("nat_sip: %s: Can't change RTCP exp %p.\n", -+ __FUNCTION__, rtcp_exp); -+ continue; -+ } -+ rtcp_exp->help.exp_sip_info.nated = 1; -+ } -+#endif -+ break; -+ } -+ } -+ if (port == 0) -+ return 0; -+ -+ exp_sip_info->nated = 1; -+ ct_sip_info->rtpport = port; -+ DEBUGP("nat_sip: %s: RTP exp %p, masq port=%d\n", __FUNCTION__, expect, port); -+ } -+#ifdef RTCP_SUPPORT -+ else { -+ /* We ignore the RTCP expect, and will adjust it later -+ * during RTP expect */ -+ DEBUGP("nat_sip: %s: RTCP exp %p, by-pass.\n", __FUNCTION__, expect); -+ return 1; -+ } -+#endif -+ } -+ -+mangle: -+ /* Change address inside packet to match way we're mapping -+ this connection. */ -+ if (!ct_sip_info->mangled) -+ if (!mangle_sip_packet(ct, ctinfo, pskb, wanip)) -+ return 0; -+ -+ return 1; -+} -+ -+static int sip_in_data_fixup(struct ip_conntrack *ct, -+ struct sk_buff **pskb, -+ enum ip_conntrack_info ctinfo, -+ struct ip_conntrack_expect *expect) -+{ -+ struct iphdr *iph = (*pskb)->nh.iph; -+ struct udphdr *udph = (void *)iph + iph->ihl * 4; -+ const char *data = (const char *)udph + 8; -+ unsigned int udplen = ntohs(iph->tot_len) - (iph->ihl * 4); -+ unsigned int datalen = udplen - 8; -+ struct ip_ct_sip_master *ct_sip_info = &ct->help.ct_sip_info; -+ u_int32_t wanip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; // NAT wan ip -+ unsigned int matchlen, matchoff; -+ int found, diff_len = 0; -+ u_int32_t ipaddr = 0, vip = 0; -+ u_int16_t port = 0, vport = 0, aport = 0; -+ struct ip_conntrack_expect *exp; -+#ifdef RTCP_SUPPORT -+ struct ip_conntrack_expect *rtcpexp; -+#endif -+ -+ if (expect) -+ DEBUGP("nat_sip: %s: There is a exp %p.\n", __FUNCTION__, expect); -+ -+ /* Prevent from mangling the packet or expect twice */ -+ if (ct_sip_info->mangled) -+ return 1; -+ -+ ct_sip_info->mangled = 1; -+ -+ if (strnicmp(data, "SIP/2.0 200", 11) == 0) { -+ /* Find CSeq field */ -+ found = find_pattern(data, datalen, "CSeq: ", 6, ' ', '\r', -+ &matchoff, &matchlen); -+ if (found) { -+ char *p = (char *)data + matchoff; -+ -+ simple_strtoul(p, &p, 10); -+ if (strnicmp(p, " REGISTER", 9) == 0) { -+ DEBUGP("nat_sip: 200 OK - REGISTER\n"); -+ vip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; -+ vport = ntohs(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.udp.port); -+ mangle_sip_via(ct, ctinfo, pskb, vip, vport); -+ mangle_sip_contact(ct, ctinfo, pskb, vip, vport); -+ return 1; -+ } -+ } -+ } -+ -+ /* Only interesting the SDP content. */ -+ if (strnicmp(data, "INVITE", 6) != 0 && strnicmp(data, "SIP/2.0 200", 11) != 0) -+ return 1; -+ -+ /* Find RTP address */ -+ found = find_sdp_rtp_addr(data, datalen, &matchoff, &matchlen, &ipaddr); -+ -+ DEBUGP("nat_sip: sdp address found = %d, ipaddr = %u.\n", found, ipaddr); -+ if (found < 2) -+ return 1; -+ -+ /* Is it a null address or our WAN address? */ -+ if (ipaddr == 0 || (htonl(ipaddr) != wanip)) -+ return 1; -+ -+ DEBUGP("nat_sip: %s: This is a lookback RTP connection.\n", __FUNCTION__); -+ -+ /* Find audio port, and we don't like the well-known ports, -+ * which is less than 1024 */ -+ port = find_sdp_audio_port(data, datalen, &matchoff, &matchlen); -+ if (port < 1024) -+ return 0; -+ -+ exp = expect_find(ct, wanip, port); -+ if (exp) { -+ DEBUGP("nat_sip: %s: Found exp %p, tuple.dst=%u.%u.%u.%u:%u.\n", -+ __FUNCTION__, exp, NIPQUAD(ipaddr), port); -+ -+ /* Restore masq-ed SDP */ -+ vip = exp->expectant->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; -+ aport = exp->help.exp_sip_info.port; -+ if ((diff_len = mangle_sip_sdp_content(ct, ctinfo, pskb, vip, aport)) != 0) -+ mangle_sip_content_length(ct, ctinfo, pskb, diff_len); -+ -+ /* Unset RTP, RTCP expect, respectively */ -+ ip_conntrack_unexpect_related(exp); -+#ifdef RTCP_SUPPORT -+ rtcpexp = expect_find(ct, wanip, port + 1); -+ if (rtcpexp) -+ ip_conntrack_unexpect_related(rtcpexp); -+#endif -+ } -+ -+ return 1; -+} -+ -+static unsigned int nat_help(struct ip_conntrack *ct, -+ struct ip_conntrack_expect *exp, -+ struct ip_nat_info *info, -+ enum ip_conntrack_info ctinfo, -+ unsigned int hooknum, -+ struct sk_buff **pskb) -+{ -+ int dir; -+ struct iphdr *iph = (*pskb)->nh.iph; -+ struct udphdr *udph = (void *)iph + iph->ihl * 4; -+ const char *data = (const char *)udph + 8; -+ -+ /* Only mangle things once: original direction in POST_ROUTING -+ and reply direction on PRE_ROUTING. */ -+ dir = CTINFO2DIR(ctinfo); -+ if (!((hooknum == NF_IP_POST_ROUTING && dir == IP_CT_DIR_ORIGINAL) -+ || (hooknum == NF_IP_PRE_ROUTING && dir == IP_CT_DIR_REPLY))) { -+ DEBUGP("nat_sip: Not touching dir %s at hook %s\n", -+ dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY", -+ hooknum == NF_IP_POST_ROUTING ? "POSTROUTING" -+ : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING" -+ : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???"); -+ return NF_ACCEPT; -+ } -+ -+ if (strnicmp(data, "REGISTER" , 8) == 0) -+ DEBUGP("nat_sip: REGISTER\n"); -+ else if (strnicmp(data, "INVITE" , 6) == 0) -+ DEBUGP("nat_sip: INVITE\n"); -+ else if (strnicmp(data, "ACK" , 3) == 0) -+ DEBUGP("nat_sip: ACK\n"); -+ else if (strnicmp(data, "BYE", 3) == 0) -+ DEBUGP("nat_sip: BYE\n"); -+ else if (strnicmp(data, "SIP/2.0 200", 11) == 0) -+ DEBUGP("nat_sip: 200 OK\n"); -+ else if (strnicmp(data, "SIP/2.0 100", 11) == 0) -+ DEBUGP("nat_sip: 100 Trying\n"); -+ else if (strnicmp(data, "SIP/2.0 180", 11) == 0) -+ DEBUGP("nat_sip: 180 Ringing\n"); -+ -+ LOCK_BH(&ip_sip_lock); -+ -+ if (dir == IP_CT_DIR_ORIGINAL) -+ sip_out_data_fixup(ct, pskb, ctinfo, exp); -+ else -+ sip_in_data_fixup(ct, pskb, ctinfo, exp); -+ -+ UNLOCK_BH(&ip_sip_lock); -+ -+ return NF_ACCEPT; -+} -+ -+static struct ip_nat_helper sip[MAX_PORTS]; -+static char sip_names[MAX_PORTS][6]; -+ -+/* Not __exit: called from init() */ -+static void fini(void) -+{ -+ int i; -+ -+ for (i = 0; (i < MAX_PORTS) && ports[i]; i++) { -+ DEBUGP("ip_nat_sip: unregistering port %d\n", ports[i]); -+ ip_nat_helper_unregister(&sip[i]); -+ } -+} -+ -+static int __init init(void) -+{ -+ int i, ret=0; -+ char *tmpname; -+ -+ if (ports[0] == 0) -+ ports[0] = SIP_PORT; -+ -+ for (i = 0; (i < MAX_PORTS) && ports[i]; i++) { -+ -+ memset(&sip[i], 0, sizeof(struct ip_nat_helper)); -+ -+ sip[i].tuple.dst.u.udp.port = htons(ports[i]); -+ sip[i].tuple.dst.protonum = IPPROTO_UDP; -+ sip[i].mask.dst.u.udp.port = 0xF0FF; -+ sip[i].mask.dst.protonum = 0xFFFF; -+ sip[i].help = nat_help; -+ sip[i].expect = sip_nat_expected; -+ sip[i].flags = IP_NAT_HELPER_F_ALWAYS; -+ -+ tmpname = &sip_names[i][0]; -+ sprintf(tmpname, "sip%2.2d", i); -+ sip[i].name = tmpname; -+ -+ DEBUGP("ip_nat_sip: Trying to register for port %d\n", -+ ports[i]); -+ ret = ip_nat_helper_register(&sip[i]); -+ -+ if (ret) { -+ printk("ip_nat_sip: error registering " -+ "helper for port %d\n", ports[i]); -+ fini(); -+ return ret; -+ } -+ ports_c++; -+ } -+ -+ return ret; -+} -+ -+module_init(init); -+module_exit(fini); -diff -urN linux-2.4.32/net/ipv4/netfilter/Makefile linux-2.4.32.new/net/ipv4/netfilter/Makefile ---- linux-2.4.32/net/ipv4/netfilter/Makefile 2006-02-04 19:16:25.000000000 +0100 -+++ linux-2.4.32.new/net/ipv4/netfilter/Makefile 2006-02-04 19:00:13.000000000 +0100 -@@ -53,6 +53,10 @@ - ifdef CONFIG_IP_NF_NAT_PPTP - export-objs += ip_conntrack_pptp.o - endif -+obj-$(CONFIG_IP_NF_SIP) += ip_conntrack_sip.o -+ifdef CONFIG_IP_NF_NAT_SIP -+ export-objs += ip_conntrack_sip.o -+endif - - - # NAT helpers -@@ -62,6 +66,7 @@ - obj-$(CONFIG_IP_NF_NAT_IRC) += ip_nat_irc.o - obj-$(CONFIG_IP_NF_NAT_PROTO_GRE) += ip_nat_proto_gre.o - obj-$(CONFIG_IP_NF_NAT_PPTP) += ip_nat_pptp.o -+obj-$(CONFIG_IP_NF_NAT_SIP) += ip_nat_sip.o - - # generic IP tables - obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o -diff -urN linux-2.4.32/include/linux/netfilter_ipv4/ip_conntrack.h linux-2.4.32.new/include/linux/netfilter_ipv4/ip_conntrack.h ---- linux-2.4.32/include/linux/netfilter_ipv4/ip_conntrack.h 2006-02-04 19:16:25.000000000 +0100 -+++ linux-2.4.32.new/include/linux/netfilter_ipv4/ip_conntrack.h 2006-02-04 19:00:13.000000000 +0100 -@@ -71,6 +71,7 @@ - #include - #include - #include -+#include - - /* per expectation: application helper private data */ - union ip_conntrack_expect_help { -@@ -79,6 +80,7 @@ - struct ip_ct_ftp_expect exp_ftp_info; - struct ip_ct_irc_expect exp_irc_info; - struct ip_ct_pptp_expect exp_pptp_info; -+ struct ip_ct_sip_expect exp_sip_info; - - #ifdef CONFIG_IP_NF_NAT_NEEDED - union { -@@ -93,6 +95,7 @@ - struct ip_ct_ftp_master ct_ftp_info; - struct ip_ct_irc_master ct_irc_info; - struct ip_ct_pptp_master ct_pptp_info; -+ struct ip_ct_sip_master ct_sip_info; - }; - - #ifdef CONFIG_IP_NF_NAT_NEEDED -diff -urN linux-2.4.32/include/linux/netfilter_ipv4/ip_conntrack_sip.h linux-2.4.32.new/include/linux/netfilter_ipv4/ip_conntrack_sip.h ---- linux-2.4.32/include/linux/netfilter_ipv4/ip_conntrack_sip.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.32.new/include/linux/netfilter_ipv4/ip_conntrack_sip.h 2006-02-04 19:00:13.000000000 +0100 -@@ -0,0 +1,56 @@ -+#ifndef _IP_CONNTRACK_SIP_H -+#define _IP_CONNTRACK_SIP_H -+/* SIP tracking. */ -+ -+#ifdef __KERNEL__ -+ -+#include -+ -+/* Protects sip part of conntracks */ -+DECLARE_LOCK_EXTERN(ip_sip_lock); -+ -+#define SIP_PORT 5060 /* UDP */ -+#define SIP_EXPIRES 3600 /* seconds */ -+#define RTP_TIMEOUT 180 /* seconds */ -+ -+#endif /* __KERNEL__ */ -+ -+/* SIP Request */ -+#define SIP_INVITE 0x01 -+#define SIP_ACK 0x02 -+#define SIP_BYE 0x04 -+/* SIP Response */ -+#define SIP_100 0x10 -+#define SIP_200 0x20 -+#define SIP_200_BYE 0x40 -+/* SIP session direction */ -+#define SIP_OUTGOING 0 -+#define SIP_INCOMING 1 -+ -+enum ip_ct_conntype -+{ -+ CONN_SIP, -+ CONN_RTP, -+ CONN_RTCP, -+}; -+ -+/* This structure is per expected connection */ -+struct ip_ct_sip_expect -+{ -+ u_int16_t port; /* TCP port that was to be used */ -+ -+ enum ip_ct_conntype type; -+ int nated; -+}; -+ -+/* This structure exists only once per master */ -+struct ip_ct_sip_master { -+ int mangled; -+ u_int16_t rtpport; -+}; -+ -+extern u_int16_t find_sdp_audio_port(const char *data, size_t dlen, -+ unsigned int *numoff, unsigned int *numlen); -+extern int find_sdp_rtp_addr(const char *data, size_t dlen, -+ unsigned int *numoff, unsigned int *numlen, u_int32_t *addr); -+#endif /* _IP_CONNTRACK_SIP_H */ diff --git a/openwrt/target/linux/generic-2.4/patches/614-netfilter_nat_h323.patch b/openwrt/target/linux/generic-2.4/patches/614-netfilter_nat_h323.patch deleted file mode 100644 index e5f0dfb342..0000000000 --- a/openwrt/target/linux/generic-2.4/patches/614-netfilter_nat_h323.patch +++ /dev/null @@ -1,821 +0,0 @@ -diff -urN linux-2.4.32/net/ipv4/netfilter/Config.in linux-2.4.32/net/ipv4/netfilter/Config.in ---- linux-2.4.32/net/ipv4/netfilter/Config.in 2005-12-12 11:13:17.000000000 +0100 -+++ linux-2.4.32/net/ipv4/netfilter/Config.in 2005-12-12 11:18:47.000000000 +0100 -@@ -16,6 +16,7 @@ - dep_tristate ' GRE protocol support' CONFIG_IP_NF_CT_PROTO_GRE $CONFIG_IP_NF_CONNTRACK - dep_tristate ' PPTP protocol support' CONFIG_IP_NF_PPTP $CONFIG_IP_NF_CT_PROTO_GRE - dep_tristate ' SIP protocol support' CONFIG_IP_NF_SIP $CONFIG_IP_NF_CONNTRACK -+ dep_tristate ' H.323 (netmeeting) support' CONFIG_IP_NF_H323 $CONFIG_IP_NF_CONNTRACK - fi - - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then -@@ -112,6 +113,13 @@ - define_tristate CONFIG_IP_NF_NAT_SIP $CONFIG_IP_NF_NAT - fi - fi -+ if [ "$CONFIG_IP_NF_H323" = "m" ]; then -+ define_tristate CONFIG_IP_NF_NAT_H323 m -+ else -+ if [ "$CONFIG_IP_NF_H323" = "y" ]; then -+ define_tristate CONFIG_IP_NF_NAT_H323 $CONFIG_IP_NF_NAT -+ fi -+ fi - if [ "$CONFIG_IP_NF_AMANDA" = "m" ]; then - define_tristate CONFIG_IP_NF_NAT_AMANDA m - else -diff -urN linux-2.4.32/net/ipv4/netfilter/Makefile linux-2.4.32/net/ipv4/netfilter/Makefile ---- linux-2.4.32/net/ipv4/netfilter/Makefile 2005-12-12 11:13:17.000000000 +0100 -+++ linux-2.4.32/net/ipv4/netfilter/Makefile 2005-12-12 11:17:37.000000000 +0100 -@@ -57,6 +57,10 @@ - ifdef CONFIG_IP_NF_NAT_SIP - export-objs += ip_conntrack_sip.o - endif -+obj-$(CONFIG_IP_NF_H323) += ip_conntrack_h323.o -+ifdef CONFIG_IP_NF_NAT_H323 -+ export-objs += ip_conntrack_h323.o -+endif - - - # NAT helpers -@@ -67,6 +71,7 @@ - obj-$(CONFIG_IP_NF_NAT_PROTO_GRE) += ip_nat_proto_gre.o - obj-$(CONFIG_IP_NF_NAT_PPTP) += ip_nat_pptp.o - obj-$(CONFIG_IP_NF_NAT_SIP) += ip_nat_sip.o -+obj-$(CONFIG_IP_NF_NAT_H323) += ip_nat_h323.o - - # generic IP tables - obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o -diff -urN linux-2.4.32/net/ipv4/netfilter/ip_conntrack_h323.c linux-2.4.32/net/ipv4/netfilter/ip_conntrack_h323.c ---- linux-2.4.32/net/ipv4/netfilter/ip_conntrack_h323.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.32/net/ipv4/netfilter/ip_conntrack_h323.c 2005-12-12 11:14:54.000000000 +0100 -@@ -0,0 +1,302 @@ -+/* -+ * H.323 'brute force' extension for H.323 connection tracking. -+ * Jozsef Kadlecsik -+ * -+ * Based on ip_masq_h323.c for 2.2 kernels from CoRiTel, Sofia project. -+ * (http://www.coritel.it/projects/sofia/nat/) -+ * Uses Sampsa Ranta's excellent idea on using expectfn to 'bind' -+ * the unregistered helpers to the conntrack entries. -+ */ -+ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+MODULE_AUTHOR("Jozsef Kadlecsik "); -+MODULE_DESCRIPTION("H.323 'brute force' connection tracking module"); -+MODULE_LICENSE("GPL"); -+ -+DECLARE_LOCK(ip_h323_lock); -+struct module *ip_conntrack_h323 = THIS_MODULE; -+ -+#define DEBUGP(format, args...) -+ -+static int h245_help(const struct iphdr *iph, size_t len, -+ struct ip_conntrack *ct, -+ enum ip_conntrack_info ctinfo) -+{ -+ struct tcphdr *tcph = (void *)iph + iph->ihl * 4; -+ unsigned char *data = (unsigned char *) tcph + tcph->doff * 4; -+ unsigned char *data_limit; -+ u_int32_t tcplen = len - iph->ihl * 4; -+ u_int32_t datalen = tcplen - tcph->doff * 4; -+ int dir = CTINFO2DIR(ctinfo); -+ struct ip_ct_h225_master *info = &ct->help.ct_h225_info; -+ struct ip_conntrack_expect expect, *exp = &expect; -+ struct ip_ct_h225_expect *exp_info = &exp->help.exp_h225_info; -+ u_int16_t data_port; -+ u_int32_t data_ip; -+ unsigned int i; -+ -+ DEBUGP("ct_h245_help: help entered %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n", -+ NIPQUAD(iph->saddr), ntohs(tcph->source), -+ NIPQUAD(iph->daddr), ntohs(tcph->dest)); -+ -+ /* Can't track connections formed before we registered */ -+ if (!info) -+ return NF_ACCEPT; -+ -+ /* Until there's been traffic both ways, don't look in packets. */ -+ if (ctinfo != IP_CT_ESTABLISHED -+ && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) { -+ DEBUGP("ct_h245_help: Conntrackinfo = %u\n", ctinfo); -+ return NF_ACCEPT; -+ } -+ -+ /* Not whole TCP header or too short packet? */ -+ if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4 + 5) { -+ DEBUGP("ct_h245_help: tcplen = %u\n", (unsigned)tcplen); -+ return NF_ACCEPT; -+ } -+ -+ /* Checksum invalid? Ignore. */ -+ if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr, -+ csum_partial((char *)tcph, tcplen, 0))) { -+ DEBUGP("ct_h245_help: bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n", -+ tcph, tcplen, NIPQUAD(iph->saddr), -+ NIPQUAD(iph->daddr)); -+ return NF_ACCEPT; -+ } -+ -+ data_limit = (unsigned char *) data + datalen; -+ /* bytes: 0123 45 -+ ipadrr port */ -+ for (i = 0; data < (data_limit - 5); data++, i++) { -+ memcpy(&data_ip, data, sizeof(u_int32_t)); -+ if (data_ip == iph->saddr) { -+ memcpy(&data_port, data + 4, sizeof(u_int16_t)); -+ memset(&expect, 0, sizeof(expect)); -+ /* update the H.225 info */ -+ DEBUGP("ct_h245_help: new RTCP/RTP requested %u.%u.%u.%u:->%u.%u.%u.%u:%u\n", -+ NIPQUAD(ct->tuplehash[!dir].tuple.src.ip), -+ NIPQUAD(iph->saddr), ntohs(data_port)); -+ LOCK_BH(&ip_h323_lock); -+ info->is_h225 = H225_PORT + 1; -+ exp_info->port = data_port; -+ exp_info->dir = dir; -+ exp_info->offset = i; -+ -+ exp->seq = ntohl(tcph->seq) + i; -+ -+ exp->tuple = ((struct ip_conntrack_tuple) -+ { { ct->tuplehash[!dir].tuple.src.ip, -+ { 0 } }, -+ { data_ip, -+ { data_port }, -+ IPPROTO_UDP }}); -+ exp->mask = ((struct ip_conntrack_tuple) -+ { { 0xFFFFFFFF, { 0 } }, -+ { 0xFFFFFFFF, { 0xFFFF }, 0xFFFF }}); -+ -+ exp->expectfn = NULL; -+ -+ /* Ignore failure; should only happen with NAT */ -+ ip_conntrack_expect_related(ct, exp); -+ -+ UNLOCK_BH(&ip_h323_lock); -+ } -+ } -+ -+ return NF_ACCEPT; -+ -+} -+ -+/* H.245 helper is not registered! */ -+static struct ip_conntrack_helper h245 = -+ { { NULL, NULL }, -+ "H.245", /* name */ -+ IP_CT_HELPER_F_REUSE_EXPECT, /* flags */ -+ NULL, /* module */ -+ 8, /* max_ expected */ -+ 240, /* timeout */ -+ { { 0, { 0 } }, /* tuple */ -+ { 0, { 0 }, IPPROTO_TCP } }, -+ { { 0, { 0xFFFF } }, /* mask */ -+ { 0, { 0 }, 0xFFFF } }, -+ h245_help /* helper */ -+ }; -+ -+static int h225_expect(struct ip_conntrack *ct) -+{ -+ WRITE_LOCK(&ip_conntrack_lock); -+ ct->helper = &h245; -+ DEBUGP("h225_expect: helper for %p added\n", ct); -+ WRITE_UNLOCK(&ip_conntrack_lock); -+ -+ return NF_ACCEPT; /* unused */ -+} -+ -+static int h225_help(const struct iphdr *iph, size_t len, -+ struct ip_conntrack *ct, -+ enum ip_conntrack_info ctinfo) -+{ -+ struct tcphdr *tcph = (void *)iph + iph->ihl * 4; -+ unsigned char *data = (unsigned char *) tcph + tcph->doff * 4; -+ unsigned char *data_limit; -+ u_int32_t tcplen = len - iph->ihl * 4; -+ u_int32_t datalen = tcplen - tcph->doff * 4; -+ int dir = CTINFO2DIR(ctinfo); -+ struct ip_ct_h225_master *info = &ct->help.ct_h225_info; -+ struct ip_conntrack_expect expect, *exp = &expect; -+ struct ip_ct_h225_expect *exp_info = &exp->help.exp_h225_info; -+ u_int16_t data_port; -+ u_int32_t data_ip; -+ unsigned int i; -+ -+ DEBUGP("ct_h225_help: help entered %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n", -+ NIPQUAD(iph->saddr), ntohs(tcph->source), -+ NIPQUAD(iph->daddr), ntohs(tcph->dest)); -+ -+ /* Can't track connections formed before we registered */ -+ if (!info) -+ return NF_ACCEPT; -+ -+ /* Until there's been traffic both ways, don't look in packets. */ -+ if (ctinfo != IP_CT_ESTABLISHED -+ && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) { -+ DEBUGP("ct_h225_help: Conntrackinfo = %u\n", ctinfo); -+ return NF_ACCEPT; -+ } -+ -+ /* Not whole TCP header or too short packet? */ -+ if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4 + 5) { -+ DEBUGP("ct_h225_help: tcplen = %u\n", (unsigned)tcplen); -+ return NF_ACCEPT; -+ } -+ -+ /* Checksum invalid? Ignore. */ -+ if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr, -+ csum_partial((char *)tcph, tcplen, 0))) { -+ DEBUGP("ct_h225_help: bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n", -+ tcph, tcplen, NIPQUAD(iph->saddr), -+ NIPQUAD(iph->daddr)); -+ return NF_ACCEPT; -+ } -+ -+ data_limit = (unsigned char *) data + datalen; -+ /* bytes: 0123 45 -+ ipadrr port */ -+ for (i = 0; data < (data_limit - 5); data++, i++) { -+ memcpy(&data_ip, data, sizeof(u_int32_t)); -+ if (data_ip == iph->saddr) { -+ memcpy(&data_port, data + 4, sizeof(u_int16_t)); -+ if (data_port == tcph->source) { -+ /* Signal address */ -+ DEBUGP("ct_h225_help: sourceCallSignalAddress from %u.%u.%u.%u\n", -+ NIPQUAD(iph->saddr)); -+ /* Update the H.225 info so that NAT can mangle the address/port -+ even when we have no expected connection! */ -+#ifdef CONFIG_IP_NF_NAT_NEEDED -+ LOCK_BH(&ip_h323_lock); -+ info->dir = dir; -+ info->seq[IP_CT_DIR_ORIGINAL] = ntohl(tcph->seq) + i; -+ info->offset[IP_CT_DIR_ORIGINAL] = i; -+ UNLOCK_BH(&ip_h323_lock); -+#endif -+ } else { -+ memset(&expect, 0, sizeof(expect)); -+ -+ /* update the H.225 info */ -+ LOCK_BH(&ip_h323_lock); -+ info->is_h225 = H225_PORT; -+ exp_info->port = data_port; -+ exp_info->dir = dir; -+ exp_info->offset = i; -+ -+ exp->seq = ntohl(tcph->seq) + i; -+ -+ exp->tuple = ((struct ip_conntrack_tuple) -+ { { ct->tuplehash[!dir].tuple.src.ip, -+ { 0 } }, -+ { data_ip, -+ { data_port }, -+ IPPROTO_TCP }}); -+ exp->mask = ((struct ip_conntrack_tuple) -+ { { 0xFFFFFFFF, { 0 } }, -+ { 0xFFFFFFFF, { 0xFFFF }, 0xFFFF }}); -+ -+ exp->expectfn = h225_expect; -+ -+ /* Ignore failure */ -+ ip_conntrack_expect_related(ct, exp); -+ -+ DEBUGP("ct_h225_help: new H.245 requested %u.%u.%u.%u->%u.%u.%u.%u:%u\n", -+ NIPQUAD(ct->tuplehash[!dir].tuple.src.ip), -+ NIPQUAD(iph->saddr), ntohs(data_port)); -+ -+ UNLOCK_BH(&ip_h323_lock); -+ } -+#ifdef CONFIG_IP_NF_NAT_NEEDED -+ } else if (data_ip == iph->daddr) { -+ memcpy(&data_port, data + 4, sizeof(u_int16_t)); -+ if (data_port == tcph->dest) { -+ /* Signal address */ -+ DEBUGP("ct_h225_help: destCallSignalAddress %u.%u.%u.%u\n", -+ NIPQUAD(iph->daddr)); -+ /* Update the H.225 info so that NAT can mangle the address/port -+ even when we have no expected connection! */ -+ LOCK_BH(&ip_h323_lock); -+ info->dir = dir; -+ info->seq[IP_CT_DIR_REPLY] = ntohl(tcph->seq) + i; -+ info->offset[IP_CT_DIR_REPLY] = i; -+ UNLOCK_BH(&ip_h323_lock); -+ } -+#endif -+ } -+ } -+ -+ return NF_ACCEPT; -+ -+} -+ -+static struct ip_conntrack_helper h225 = -+ { { NULL, NULL }, -+ "H.225", /* name */ -+ IP_CT_HELPER_F_REUSE_EXPECT, /* flags */ -+ THIS_MODULE, /* module */ -+ 2, /* max_expected */ -+ 240, /* timeout */ -+ { { 0, { __constant_htons(H225_PORT) } }, /* tuple */ -+ { 0, { 0 }, IPPROTO_TCP } }, -+ { { 0, { 0xFFFF } }, /* mask */ -+ { 0, { 0 }, 0xFFFF } }, -+ h225_help /* helper */ -+ }; -+ -+static int __init init(void) -+{ -+ return ip_conntrack_helper_register(&h225); -+} -+ -+static void __exit fini(void) -+{ -+ /* Unregister H.225 helper */ -+ ip_conntrack_helper_unregister(&h225); -+} -+ -+#ifdef CONFIG_IP_NF_NAT_NEEDED -+EXPORT_SYMBOL(ip_h323_lock); -+#endif -+ -+module_init(init); -+module_exit(fini); -diff -urN linux-2.4.32/net/ipv4/netfilter/ip_nat_h323.c /linux-2.4.32/net/ipv4/netfilter/ip_nat_h323.c ---- linux-2.4.32/net/ipv4/netfilter/ip_nat_h323.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.32/net/ipv4/netfilter/ip_nat_h323.c 2005-12-12 11:14:54.000000000 +0100 -@@ -0,0 +1,403 @@ -+/* -+ * H.323 'brute force' extension for NAT alteration. -+ * Jozsef Kadlecsik -+ * -+ * Based on ip_masq_h323.c for 2.2 kernels from CoRiTel, Sofia project. -+ * (http://www.coritel.it/projects/sofia/nat.html) -+ * Uses Sampsa Ranta's excellent idea on using expectfn to 'bind' -+ * the unregistered helpers to the conntrack entries. -+ */ -+ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+MODULE_AUTHOR("Jozsef Kadlecsik "); -+MODULE_DESCRIPTION("H.323 'brute force' connection tracking module"); -+MODULE_LICENSE("GPL"); -+ -+DECLARE_LOCK_EXTERN(ip_h323_lock); -+struct module *ip_nat_h323 = THIS_MODULE; -+ -+#define DEBUGP(format, args...) -+ -+ -+static unsigned int -+h225_nat_expected(struct sk_buff **pskb, -+ unsigned int hooknum, -+ struct ip_conntrack *ct, -+ struct ip_nat_info *info); -+ -+static unsigned int h225_nat_help(struct ip_conntrack *ct, -+ struct ip_conntrack_expect *exp, -+ struct ip_nat_info *info, -+ enum ip_conntrack_info ctinfo, -+ unsigned int hooknum, -+ struct sk_buff **pskb); -+ -+static struct ip_nat_helper h245 = -+ { { NULL, NULL }, -+ "H.245", /* name */ -+ 0, /* flags */ -+ NULL, /* module */ -+ { { 0, { 0 } }, /* tuple */ -+ { 0, { 0 }, IPPROTO_TCP } }, -+ { { 0, { 0xFFFF } }, /* mask */ -+ { 0, { 0 }, 0xFFFF } }, -+ h225_nat_help, /* helper */ -+ h225_nat_expected /* expectfn */ -+ }; -+ -+static unsigned int -+h225_nat_expected(struct sk_buff **pskb, -+ unsigned int hooknum, -+ struct ip_conntrack *ct, -+ struct ip_nat_info *info) -+{ -+ struct ip_nat_multi_range mr; -+ u_int32_t newdstip, newsrcip, newip; -+ u_int16_t port; -+ struct ip_ct_h225_expect *exp_info; -+ struct ip_ct_h225_master *master_info; -+ struct ip_conntrack *master = master_ct(ct); -+ unsigned int is_h225, ret; -+ -+ IP_NF_ASSERT(info); -+ IP_NF_ASSERT(master); -+ -+ IP_NF_ASSERT(!(info->initialized & (1<master->expectant->help.ct_h225_info; -+ exp_info = &ct->master->help.exp_h225_info; -+ -+ LOCK_BH(&ip_h323_lock); -+ -+ DEBUGP("master: "); -+ DUMP_TUPLE(&master->tuplehash[IP_CT_DIR_ORIGINAL].tuple); -+ DUMP_TUPLE(&master->tuplehash[IP_CT_DIR_REPLY].tuple); -+ DEBUGP("conntrack: "); -+ DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); -+ if (exp_info->dir == IP_CT_DIR_ORIGINAL) { -+ /* Make connection go to the client. */ -+ newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; -+ newsrcip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip; -+ DEBUGP("h225_nat_expected: %u.%u.%u.%u->%u.%u.%u.%u (to client)\n", -+ NIPQUAD(newsrcip), NIPQUAD(newdstip)); -+ } else { -+ /* Make the connection go to the server */ -+ newdstip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip; -+ newsrcip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; -+ DEBUGP("h225_nat_expected: %u.%u.%u.%u->%u.%u.%u.%u (to server)\n", -+ NIPQUAD(newsrcip), NIPQUAD(newdstip)); -+ } -+ port = exp_info->port; -+ is_h225 = master_info->is_h225 == H225_PORT; -+ UNLOCK_BH(&ip_h323_lock); -+ -+ if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC) -+ newip = newsrcip; -+ else -+ newip = newdstip; -+ -+ DEBUGP("h225_nat_expected: IP to %u.%u.%u.%u\n", NIPQUAD(newip)); -+ -+ mr.rangesize = 1; -+ /* We don't want to manip the per-protocol, just the IPs... */ -+ mr.range[0].flags = IP_NAT_RANGE_MAP_IPS; -+ mr.range[0].min_ip = mr.range[0].max_ip = newip; -+ -+ /* ... unless we're doing a MANIP_DST, in which case, make -+ sure we map to the correct port */ -+ if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST) { -+ mr.range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED; -+ mr.range[0].min = mr.range[0].max -+ = ((union ip_conntrack_manip_proto) -+ { port }); -+ } -+ -+ ret = ip_nat_setup_info(ct, &mr, hooknum); -+ -+ if (is_h225) { -+ DEBUGP("h225_nat_expected: H.225, setting NAT helper for %p\n", ct); -+ /* NAT expectfn called with ip_nat_lock write-locked */ -+ info->helper = &h245; -+ } -+ return ret; -+} -+ -+static int h323_signal_address_fixup(struct ip_conntrack *ct, -+ struct sk_buff **pskb, -+ enum ip_conntrack_info ctinfo) -+{ -+ struct iphdr *iph = (*pskb)->nh.iph; -+ struct tcphdr *tcph = (void *)iph + iph->ihl*4; -+ unsigned char *data; -+ u_int32_t tcplen = (*pskb)->len - iph->ihl*4; -+ u_int32_t datalen = tcplen - tcph->doff*4; -+ struct ip_ct_h225_master *info = &ct->help.ct_h225_info; -+ u_int32_t newip; -+ u_int16_t port; -+ u_int8_t buffer[6]; -+ int i; -+ -+ MUST_BE_LOCKED(&ip_h323_lock); -+ -+ DEBUGP("h323_signal_address_fixup: %s %s\n", -+ between(info->seq[IP_CT_DIR_ORIGINAL], ntohl(tcph->seq), ntohl(tcph->seq) + datalen) -+ ? "yes" : "no", -+ between(info->seq[IP_CT_DIR_REPLY], ntohl(tcph->seq), ntohl(tcph->seq) + datalen) -+ ? "yes" : "no"); -+ if (!(between(info->seq[IP_CT_DIR_ORIGINAL], ntohl(tcph->seq), ntohl(tcph->seq) + datalen) -+ || between(info->seq[IP_CT_DIR_REPLY], ntohl(tcph->seq), ntohl(tcph->seq) + datalen))) -+ return 1; -+ -+ DEBUGP("h323_signal_address_fixup: offsets %u + 6 and %u + 6 in %u\n", -+ info->offset[IP_CT_DIR_ORIGINAL], -+ info->offset[IP_CT_DIR_REPLY], -+ tcplen); -+ DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); -+ DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple); -+ -+ for (i = 0; i < IP_CT_DIR_MAX; i++) { -+ DEBUGP("h323_signal_address_fixup: %s %s\n", -+ info->dir == IP_CT_DIR_ORIGINAL ? "original" : "reply", -+ i == IP_CT_DIR_ORIGINAL ? "caller" : "callee"); -+ if (!between(info->seq[i], ntohl(tcph->seq), -+ ntohl(tcph->seq) + datalen)) -+ continue; -+ if (!between(info->seq[i] + 6, ntohl(tcph->seq), -+ ntohl(tcph->seq) + datalen)) { -+ /* Partial retransmisison. It's a cracker being funky. */ -+ if (net_ratelimit()) { -+ printk("H.323_NAT: partial packet %u/6 in %u/%u\n", -+ info->seq[i], -+ ntohl(tcph->seq), -+ ntohl(tcph->seq) + datalen); -+ } -+ return 0; -+ } -+ -+ /* Change address inside packet to match way we're mapping -+ this connection. */ -+ if (i == IP_CT_DIR_ORIGINAL) { -+ newip = ct->tuplehash[!info->dir].tuple.dst.ip; -+ port = ct->tuplehash[!info->dir].tuple.dst.u.tcp.port; -+ } else { -+ newip = ct->tuplehash[!info->dir].tuple.src.ip; -+ port = ct->tuplehash[!info->dir].tuple.src.u.tcp.port; -+ } -+ -+ data = (char *) tcph + tcph->doff * 4 + info->offset[i]; -+ -+ DEBUGP("h323_signal_address_fixup: orig %s IP:port %u.%u.%u.%u:%u\n", -+ i == IP_CT_DIR_ORIGINAL ? "source" : "dest ", -+ data[0], data[1], data[2], data[3], -+ (data[4] << 8 | data[5])); -+ -+ /* Modify the packet */ -+ memcpy(buffer, &newip, 4); -+ memcpy(buffer + 4, &port, 2); -+ if (!ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, info->offset[i], -+ 6, buffer, 6)) -+ return 0; -+ -+ DEBUGP("h323_signal_address_fixup: new %s IP:port %u.%u.%u.%u:%u\n", -+ i == IP_CT_DIR_ORIGINAL ? "source" : "dest ", -+ data[0], data[1], data[2], data[3], -+ (data[4] << 8 | data[5])); -+ } -+ -+ return 1; -+} -+ -+static int h323_data_fixup(struct ip_ct_h225_expect *info, -+ struct ip_conntrack *ct, -+ struct sk_buff **pskb, -+ enum ip_conntrack_info ctinfo, -+ struct ip_conntrack_expect *expect) -+{ -+ u_int32_t newip; -+ u_int16_t port; -+ u_int8_t buffer[6]; -+ struct ip_conntrack_tuple newtuple; -+ struct iphdr *iph = (*pskb)->nh.iph; -+ struct tcphdr *tcph = (void *)iph + iph->ihl*4; -+ unsigned char *data; -+ u_int32_t tcplen = (*pskb)->len - iph->ihl*4; -+ struct ip_ct_h225_master *master_info = &ct->help.ct_h225_info; -+ int is_h225; -+ -+ MUST_BE_LOCKED(&ip_h323_lock); -+ DEBUGP("h323_data_fixup: offset %u + 6 in %u\n", info->offset, tcplen); -+ DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); -+ DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple); -+ -+ if (!between(expect->seq + 6, ntohl(tcph->seq), -+ ntohl(tcph->seq) + tcplen - tcph->doff * 4)) { -+ /* Partial retransmisison. It's a cracker being funky. */ -+ if (net_ratelimit()) { -+ printk("H.323_NAT: partial packet %u/6 in %u/%u\n", -+ expect->seq, -+ ntohl(tcph->seq), -+ ntohl(tcph->seq) + tcplen - tcph->doff * 4); -+ } -+ return 0; -+ } -+ -+ /* Change address inside packet to match way we're mapping -+ this connection. */ -+ if (info->dir == IP_CT_DIR_REPLY) { -+ /* Must be where client thinks server is */ -+ newip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip; -+ /* Expect something from client->server */ -+ newtuple.src.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; -+ newtuple.dst.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip; -+ } else { -+ /* Must be where server thinks client is */ -+ newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; -+ /* Expect something from server->client */ -+ newtuple.src.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip; -+ newtuple.dst.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; -+ } -+ -+ is_h225 = (master_info->is_h225 == H225_PORT); -+ -+ if (is_h225) { -+ newtuple.dst.protonum = IPPROTO_TCP; -+ newtuple.src.u.tcp.port = expect->tuple.src.u.tcp.port; -+ } else { -+ newtuple.dst.protonum = IPPROTO_UDP; -+ newtuple.src.u.udp.port = expect->tuple.src.u.udp.port; -+ } -+ -+ /* Try to get same port: if not, try to change it. */ -+ for (port = ntohs(info->port); port != 0; port++) { -+ if (is_h225) -+ newtuple.dst.u.tcp.port = htons(port); -+ else -+ newtuple.dst.u.udp.port = htons(port); -+ -+ if (ip_conntrack_change_expect(expect, &newtuple) == 0) -+ break; -+ } -+ if (port == 0) { -+ DEBUGP("h323_data_fixup: no free port found!\n"); -+ return 0; -+ } -+ -+ port = htons(port); -+ -+ data = (char *) tcph + tcph->doff * 4 + info->offset; -+ -+ DEBUGP("h323_data_fixup: orig IP:port %u.%u.%u.%u:%u\n", -+ data[0], data[1], data[2], data[3], -+ (data[4] << 8 | data[5])); -+ -+ /* Modify the packet */ -+ memcpy(buffer, &newip, 4); -+ memcpy(buffer + 4, &port, 2); -+ if (!ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, info->offset, -+ 6, buffer, 6)) -+ return 0; -+ -+ DEBUGP("h323_data_fixup: new IP:port %u.%u.%u.%u:%u\n", -+ data[0], data[1], data[2], data[3], -+ (data[4] << 8 | data[5])); -+ -+ return 1; -+} -+ -+static unsigned int h225_nat_help(struct ip_conntrack *ct, -+ struct ip_conntrack_expect *exp, -+ struct ip_nat_info *info, -+ enum ip_conntrack_info ctinfo, -+ unsigned int hooknum, -+ struct sk_buff **pskb) -+{ -+ int dir; -+ struct ip_ct_h225_expect *exp_info; -+ -+ /* Only mangle things once: original direction in POST_ROUTING -+ and reply direction on PRE_ROUTING. */ -+ dir = CTINFO2DIR(ctinfo); -+ DEBUGP("nat_h323: dir %s at hook %s\n", -+ dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY", -+ hooknum == NF_IP_POST_ROUTING ? "POSTROUTING" -+ : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING" -+ : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???"); -+ if (!((hooknum == NF_IP_POST_ROUTING && dir == IP_CT_DIR_ORIGINAL) -+ || (hooknum == NF_IP_PRE_ROUTING && dir == IP_CT_DIR_REPLY))) { -+ DEBUGP("nat_h323: Not touching dir %s at hook %s\n", -+ dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY", -+ hooknum == NF_IP_POST_ROUTING ? "POSTROUTING" -+ : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING" -+ : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???"); -+ return NF_ACCEPT; -+ } -+ -+ if (!exp) { -+ LOCK_BH(&ip_h323_lock); -+ if (!h323_signal_address_fixup(ct, pskb, ctinfo)) { -+ UNLOCK_BH(&ip_h323_lock); -+ return NF_DROP; -+ } -+ UNLOCK_BH(&ip_h323_lock); -+ return NF_ACCEPT; -+ } -+ -+ exp_info = &exp->help.exp_h225_info; -+ -+ LOCK_BH(&ip_h323_lock); -+ if (!h323_data_fixup(exp_info, ct, pskb, ctinfo, exp)) { -+ UNLOCK_BH(&ip_h323_lock); -+ return NF_DROP; -+ } -+ UNLOCK_BH(&ip_h323_lock); -+ -+ return NF_ACCEPT; -+} -+ -+static struct ip_nat_helper h225 = -+ { { NULL, NULL }, -+ "H.225", /* name */ -+ IP_NAT_HELPER_F_ALWAYS, /* flags */ -+ THIS_MODULE, /* module */ -+ { { 0, { __constant_htons(H225_PORT) } }, /* tuple */ -+ { 0, { 0 }, IPPROTO_TCP } }, -+ { { 0, { 0xFFFF } }, /* mask */ -+ { 0, { 0 }, 0xFFFF } }, -+ h225_nat_help, /* helper */ -+ h225_nat_expected /* expectfn */ -+ }; -+ -+static int __init init(void) -+{ -+ int ret; -+ -+ ret = ip_nat_helper_register(&h225); -+ -+ if (ret != 0) -+ printk("ip_nat_h323: cannot initialize the module!\n"); -+ -+ return ret; -+} -+ -+static void __exit fini(void) -+{ -+ ip_nat_helper_unregister(&h225); -+} -+ -+module_init(init); -+module_exit(fini); -diff -urN linux-2.4.32/include/linux/netfilter_ipv4/ip_conntrack.h linux-2.4.32/include/linux/netfilter_ipv4/ip_conntrack.h ---- linux-2.4.32/include/linux/netfilter_ipv4/ip_conntrack.h 2005-12-12 11:13:17.000000000 +0100 -+++ linux-2.4.32/include/linux/netfilter_ipv4/ip_conntrack.h 2005-12-12 11:16:13.000000000 +0100 -@@ -72,6 +72,7 @@ - #include - #include - #include -+#include - - /* per expectation: application helper private data */ - union ip_conntrack_expect_help { -@@ -81,6 +82,7 @@ - struct ip_ct_irc_expect exp_irc_info; - struct ip_ct_pptp_expect exp_pptp_info; - struct ip_ct_sip_expect exp_sip_info; -+ struct ip_ct_h225_expect exp_h225_info; - - #ifdef CONFIG_IP_NF_NAT_NEEDED - union { -@@ -96,6 +98,7 @@ - struct ip_ct_irc_master ct_irc_info; - struct ip_ct_pptp_master ct_pptp_info; - struct ip_ct_sip_master ct_sip_info; -+ struct ip_ct_h225_master ct_h225_info; - }; - - #ifdef CONFIG_IP_NF_NAT_NEEDED -diff -urN linux-2.4.32/include/linux/netfilter_ipv4/ip_conntrack_h323.h linux-2.4.32/include/linux/netfilter_ipv4/ip_conntrack_h323.h ---- linux-2.4.32/include/linux/netfilter_ipv4/ip_conntrack_h323.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.32/include/linux/netfilter_ipv4/ip_conntrack_h323.h 2005-12-12 11:14:54.000000000 +0100 -@@ -0,0 +1,30 @@ -+#ifndef _IP_CONNTRACK_H323_H -+#define _IP_CONNTRACK_H323_H -+/* H.323 connection tracking. */ -+ -+#ifdef __KERNEL__ -+/* Protects H.323 related data */ -+DECLARE_LOCK_EXTERN(ip_h323_lock); -+#endif -+ -+/* Default H.225 port */ -+#define H225_PORT 1720 -+ -+/* This structure is per expected connection */ -+struct ip_ct_h225_expect { -+ u_int16_t port; /* Port of the H.225 helper/RTCP/RTP channel */ -+ enum ip_conntrack_dir dir; /* Direction of the original connection */ -+ unsigned int offset; /* offset of the address in the payload */ -+}; -+ -+/* This structure exists only once per master */ -+struct ip_ct_h225_master { -+ int is_h225; /* H.225 or H.245 connection */ -+#ifdef CONFIG_IP_NF_NAT_NEEDED -+ enum ip_conntrack_dir dir; /* Direction of the original connection */ -+ u_int32_t seq[IP_CT_DIR_MAX]; /* Exceptional packet mangling for signal addressess... */ -+ unsigned int offset[IP_CT_DIR_MAX]; /* ...and the offset of the addresses in the payload */ -+#endif -+}; -+ -+#endif /* _IP_CONNTRACK_H323_H */ diff --git a/openwrt/target/linux/generic-2.4/patches/614-netfilter_nat_rtsp.patch b/openwrt/target/linux/generic-2.4/patches/614-netfilter_nat_rtsp.patch new file mode 100644 index 0000000000..6ae3e7b0aa --- /dev/null +++ b/openwrt/target/linux/generic-2.4/patches/614-netfilter_nat_rtsp.patch @@ -0,0 +1,1523 @@ +diff -urN linux-2.4.32/net/ipv4/netfilter/Config.in linux-2.4.32.new/net/ipv4/netfilter/Config.in +--- linux-2.4.32/net/ipv4/netfilter/Config.in 2006-03-01 00:53:57.884792456 +0100 ++++ linux-2.4.32.new/net/ipv4/netfilter/Config.in 2006-03-01 00:55:14.462150928 +0100 +@@ -16,6 +16,7 @@ + dep_tristate ' GRE protocol support' CONFIG_IP_NF_CT_PROTO_GRE $CONFIG_IP_NF_CONNTRACK + dep_tristate ' PPTP protocol support' CONFIG_IP_NF_PPTP $CONFIG_IP_NF_CT_PROTO_GRE + dep_tristate ' H.323 (netmeeting) support' CONFIG_IP_NF_H323 $CONFIG_IP_NF_CONNTRACK ++ dep_tristate ' RTSP protocol support' CONFIG_IP_NF_RTSP $CONFIG_IP_NF_CONNTRACK + fi + + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then +@@ -119,6 +120,13 @@ + define_tristate CONFIG_IP_NF_NAT_H323 $CONFIG_IP_NF_NAT + fi + fi ++ if [ "$CONFIG_IP_NF_RTSP" = "m" ]; then ++ define_tristate CONFIG_IP_NF_NAT_RTSP m ++ else ++ if [ "$CONFIG_IP_NF_RTSP" = "y" ]; then ++ define_tristate CONFIG_IP_NF_NAT_RTSP $CONFIG_IP_NF_NAT ++ fi ++ fi + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + dep_tristate ' Basic SNMP-ALG support (EXPERIMENTAL)' CONFIG_IP_NF_NAT_SNMP_BASIC $CONFIG_IP_NF_NAT + fi +diff -urN linux-2.4.32/net/ipv4/netfilter/Makefile linux-2.4.32.new/net/ipv4/netfilter/Makefile +--- linux-2.4.32/net/ipv4/netfilter/Makefile 2006-03-01 00:53:57.886792152 +0100 ++++ linux-2.4.32.new/net/ipv4/netfilter/Makefile 2006-03-01 00:55:14.463150776 +0100 +@@ -57,6 +57,11 @@ + ifdef CONFIG_IP_NF_NAT_H323 + export-objs += ip_conntrack_h323.o + endif ++obj-$(CONFIG_IP_NF_RTSP) += ip_conntrack_rtsp.o ++ifdef CONFIG_IP_NF_NAT_RTSP ++ export-objs += ip_conntrack_rtsp.o ++endif ++ + + + # NAT helpers +@@ -67,6 +72,7 @@ + obj-$(CONFIG_IP_NF_NAT_PROTO_GRE) += ip_nat_proto_gre.o + obj-$(CONFIG_IP_NF_NAT_PPTP) += ip_nat_pptp.o + obj-$(CONFIG_IP_NF_NAT_H323) += ip_nat_h323.o ++obj-$(CONFIG_IP_NF_NAT_RTSP) += ip_nat_rtsp.o + + # generic IP tables + obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o +diff -urN linux-2.4.32/net/ipv4/netfilter/ip_conntrack_rtsp.c linux-2.4.32.new/net/ipv4/netfilter/ip_conntrack_rtsp.c +--- linux-2.4.32/net/ipv4/netfilter/ip_conntrack_rtsp.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.32.new/net/ipv4/netfilter/ip_conntrack_rtsp.c 2006-03-01 00:55:14.465150472 +0100 +@@ -0,0 +1,507 @@ ++/* ++ * RTSP extension for IP connection tracking ++ * (C) 2003 by Tom Marshall ++ * based on ip_conntrack_irc.c ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version ++ * 2 of the License, or (at your option) any later version. ++ * ++ * Module load syntax: ++ * insmod ip_conntrack_rtsp.o ports=port1,port2,...port ++ * max_outstanding=n setup_timeout=secs ++ * ++ * If no ports are specified, the default will be port 554. ++ * ++ * With max_outstanding you can define the maximum number of not yet ++ * answered SETUP requests per RTSP session (default 8). ++ * With setup_timeout you can specify how long the system waits for ++ * an expected data channel (default 300 seconds). ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++#define NF_NEED_STRNCASECMP ++#define NF_NEED_STRTOU16 ++#define NF_NEED_STRTOU32 ++#define NF_NEED_NEXTLINE ++#include ++#define NF_NEED_MIME_NEXTLINE ++#include ++ ++#define MAX_SIMUL_SETUP 8 /* XXX: use max_outstanding */ ++ ++#define INFOP(fmt, args...) printk(KERN_INFO "%s: %s: " fmt, __FILE__, __FUNCTION__ , ## args) ++#ifdef IP_NF_RTSP_DEBUG ++#define DEBUGP(fmt, args...) printk(KERN_DEBUG "%s: %s: " fmt, __FILE__, __FUNCTION__ , ## args) ++#else ++#define DEBUGP(fmt, args...) ++#endif ++ ++#define MAX_PORTS 8 ++static int ports[MAX_PORTS]; ++static int num_ports = 0; ++static int max_outstanding = 8; ++static unsigned int setup_timeout = 300; ++ ++MODULE_AUTHOR("Tom Marshall "); ++MODULE_DESCRIPTION("RTSP connection tracking module"); ++MODULE_LICENSE("GPL"); ++#ifdef MODULE_PARM ++MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i"); ++MODULE_PARM_DESC(ports, "port numbers of RTSP servers"); ++MODULE_PARM(max_outstanding, "i"); ++MODULE_PARM_DESC(max_outstanding, "max number of outstanding SETUP requests per RTSP session"); ++MODULE_PARM(setup_timeout, "i"); ++MODULE_PARM_DESC(setup_timeout, "timeout on for unestablished data channels"); ++#endif ++ ++DECLARE_LOCK(ip_rtsp_lock); ++struct module* ip_conntrack_rtsp = THIS_MODULE; ++ ++/* ++ * Max mappings we will allow for one RTSP connection (for RTP, the number ++ * of allocated ports is twice this value). Note that SMIL burns a lot of ++ * ports so keep this reasonably high. If this is too low, you will see a ++ * lot of "no free client map entries" messages. ++ */ ++#define MAX_PORT_MAPS 16 ++ ++/*** default port list was here in the masq code: 554, 3030, 4040 ***/ ++ ++#define SKIP_WSPACE(ptr,len,off) while(off < len && isspace(*(ptr+off))) { off++; } ++ ++/* ++ * Parse an RTSP packet. ++ * ++ * Returns zero if parsing failed. ++ * ++ * Parameters: ++ * IN ptcp tcp data pointer ++ * IN tcplen tcp data len ++ * IN/OUT ptcpoff points to current tcp offset ++ * OUT phdrsoff set to offset of rtsp headers ++ * OUT phdrslen set to length of rtsp headers ++ * OUT pcseqoff set to offset of CSeq header ++ * OUT pcseqlen set to length of CSeq header ++ */ ++static int ++rtsp_parse_message(char* ptcp, uint tcplen, uint* ptcpoff, ++ uint* phdrsoff, uint* phdrslen, ++ uint* pcseqoff, uint* pcseqlen) ++{ ++ uint entitylen = 0; ++ uint lineoff; ++ uint linelen; ++ ++ if (!nf_nextline(ptcp, tcplen, ptcpoff, &lineoff, &linelen)) ++ { ++ return 0; ++ } ++ ++ *phdrsoff = *ptcpoff; ++ while (nf_mime_nextline(ptcp, tcplen, ptcpoff, &lineoff, &linelen)) ++ { ++ if (linelen == 0) ++ { ++ if (entitylen > 0) ++ { ++ *ptcpoff += min(entitylen, tcplen - *ptcpoff); ++ } ++ break; ++ } ++ if (lineoff+linelen > tcplen) ++ { ++ INFOP("!! overrun !!\n"); ++ break; ++ } ++ ++ if (nf_strncasecmp(ptcp+lineoff, "CSeq:", 5) == 0) ++ { ++ *pcseqoff = lineoff; ++ *pcseqlen = linelen; ++ } ++ if (nf_strncasecmp(ptcp+lineoff, "Content-Length:", 15) == 0) ++ { ++ uint off = lineoff+15; ++ SKIP_WSPACE(ptcp+lineoff, linelen, off); ++ nf_strtou32(ptcp+off, &entitylen); ++ } ++ } ++ *phdrslen = (*ptcpoff) - (*phdrsoff); ++ ++ return 1; ++} ++ ++/* ++ * Find lo/hi client ports (if any) in transport header ++ * In: ++ * ptcp, tcplen = packet ++ * tranoff, tranlen = buffer to search ++ * ++ * Out: ++ * pport_lo, pport_hi = lo/hi ports (host endian) ++ * ++ * Returns nonzero if any client ports found ++ * ++ * Note: it is valid (and expected) for the client to request multiple ++ * transports, so we need to parse the entire line. ++ */ ++static int ++rtsp_parse_transport(char* ptran, uint tranlen, ++ struct ip_ct_rtsp_expect* prtspexp) ++{ ++ int rc = 0; ++ uint off = 0; ++ ++ if (tranlen < 10 || !iseol(ptran[tranlen-1]) || ++ nf_strncasecmp(ptran, "Transport:", 10) != 0) ++ { ++ INFOP("sanity check failed\n"); ++ return 0; ++ } ++ DEBUGP("tran='%.*s'\n", (int)tranlen, ptran); ++ off += 10; ++ SKIP_WSPACE(ptran, tranlen, off); ++ ++ /* Transport: tran;field;field=val,tran;field;field=val,... */ ++ while (off < tranlen) ++ { ++ const char* pparamend; ++ uint nextparamoff; ++ ++ pparamend = memchr(ptran+off, ',', tranlen-off); ++ pparamend = (pparamend == NULL) ? ptran+tranlen : pparamend+1; ++ nextparamoff = pparamend-ptran; ++ ++ 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; ++ ++ off += 12; ++ numlen = nf_strtou16(ptran+off, &port); ++ off += numlen; ++ if (prtspexp->loport != 0 && prtspexp->loport != port) ++ { ++ DEBUGP("multiple ports found, port %hu ignored\n", port); ++ } ++ else ++ { ++ prtspexp->loport = prtspexp->hiport = port; ++ if (ptran[off] == '-') ++ { ++ off++; ++ numlen = nf_strtou16(ptran+off, &port); ++ off += numlen; ++ prtspexp->pbtype = pb_range; ++ prtspexp->hiport = port; ++ ++ // If we have a range, assume rtp: ++ // loport must be even, hiport must be loport+1 ++ if ((prtspexp->loport & 0x0001) != 0 || ++ prtspexp->hiport != prtspexp->loport+1) ++ { ++ DEBUGP("incorrect range: %hu-%hu, correcting\n", ++ prtspexp->loport, prtspexp->hiport); ++ prtspexp->loport &= 0xfffe; ++ prtspexp->hiport = prtspexp->loport+1; ++ } ++ } ++ else if (ptran[off] == '/') ++ { ++ off++; ++ numlen = nf_strtou16(ptran+off, &port); ++ off += numlen; ++ prtspexp->pbtype = pb_discon; ++ prtspexp->hiport = port; ++ } ++ rc = 1; ++ } ++ } ++ ++ /* ++ * Note we don't look for the destination parameter here. ++ * If we are using NAT, the NAT module will handle it. If not, ++ * and the client is sending packets elsewhere, the expectation ++ * will quietly time out. ++ */ ++ ++ off = nextfieldoff; ++ } ++ ++ off = nextparamoff; ++ } ++ ++ return rc; ++} ++ ++/*** conntrack functions ***/ ++ ++/* outbound packet: client->server */ ++static int ++help_out(const struct iphdr* iph, size_t pktlen, ++ struct ip_conntrack* ct, enum ip_conntrack_info ctinfo) ++{ ++ int dir = CTINFO2DIR(ctinfo); /* = IP_CT_DIR_ORIGINAL */ ++ struct tcphdr* tcph = (void*)iph + iph->ihl * 4; ++ uint tcplen = pktlen - iph->ihl * 4; ++ char* pdata = (char*)tcph + tcph->doff * 4; ++ uint datalen = tcplen - tcph->doff * 4; ++ uint dataoff = 0; ++ ++ struct ip_conntrack_expect exp; ++ ++ while (dataoff < datalen) ++ { ++ uint cmdoff = dataoff; ++ uint hdrsoff = 0; ++ uint hdrslen = 0; ++ uint cseqoff = 0; ++ uint cseqlen = 0; ++ uint lineoff = 0; ++ uint linelen = 0; ++ uint off; ++ int rc; ++ ++ if (!rtsp_parse_message(pdata, datalen, &dataoff, ++ &hdrsoff, &hdrslen, ++ &cseqoff, &cseqlen)) ++ { ++ break; /* not a valid message */ ++ } ++ ++ if (strncmp(pdata+cmdoff, "SETUP ", 6) != 0) ++ { ++ continue; /* not a SETUP message */ ++ } ++ DEBUGP("found a setup message\n"); ++ ++ memset(&exp, 0, sizeof(exp)); ++ ++ off = 0; ++ while (nf_mime_nextline(pdata+hdrsoff, hdrslen, &off, ++ &lineoff, &linelen)) ++ { ++ if (linelen == 0) ++ { ++ break; ++ } ++ if (off > hdrsoff+hdrslen) ++ { ++ INFOP("!! overrun !!"); ++ break; ++ } ++ ++ if (nf_strncasecmp(pdata+hdrsoff+lineoff, "Transport:", 10) == 0) ++ { ++ rtsp_parse_transport(pdata+hdrsoff+lineoff, linelen, ++ &exp.help.exp_rtsp_info); ++ } ++ } ++ ++ if (exp.help.exp_rtsp_info.loport == 0) ++ { ++ DEBUGP("no udp transports found\n"); ++ continue; /* no udp transports found */ ++ } ++ ++ DEBUGP("udp transport found, ports=(%d,%hu,%hu)\n", ++ (int)exp.help.exp_rtsp_info.pbtype, ++ exp.help.exp_rtsp_info.loport, ++ exp.help.exp_rtsp_info.hiport); ++ ++ LOCK_BH(&ip_rtsp_lock); ++ exp.seq = ntohl(tcph->seq) + hdrsoff; /* mark all the headers */ ++ exp.help.exp_rtsp_info.len = hdrslen; ++ ++ exp.tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip; ++ exp.mask.src.ip = 0xffffffff; ++ exp.tuple.dst.ip = ct->tuplehash[dir].tuple.src.ip; ++ exp.mask.dst.ip = 0xffffffff; ++ exp.tuple.dst.u.udp.port = exp.help.exp_rtsp_info.loport; ++ exp.mask.dst.u.udp.port = (exp.help.exp_rtsp_info.pbtype == pb_range) ? 0xfffe : 0xffff; ++ exp.tuple.dst.protonum = IPPROTO_UDP; ++ exp.mask.dst.protonum = 0xffff; ++ ++ DEBUGP("expect_related %u.%u.%u.%u:%u-%u.%u.%u.%u:%u\n", ++ NIPQUAD(exp.tuple.src.ip), ++ ntohs(exp.tuple.src.u.tcp.port), ++ NIPQUAD(exp.tuple.dst.ip), ++ ntohs(exp.tuple.dst.u.tcp.port)); ++ ++ /* pass the request off to the nat helper */ ++ rc = ip_conntrack_expect_related(ct, &exp); ++ UNLOCK_BH(&ip_rtsp_lock); ++ if (rc == 0) ++ { ++ DEBUGP("ip_conntrack_expect_related succeeded\n"); ++ } ++ else ++ { ++ INFOP("ip_conntrack_expect_related failed (%d)\n", rc); ++ } ++ } ++ ++ return NF_ACCEPT; ++} ++ ++/* inbound packet: server->client */ ++static int ++help_in(const struct iphdr* iph, size_t pktlen, ++ struct ip_conntrack* ct, enum ip_conntrack_info ctinfo) ++{ ++ return NF_ACCEPT; ++} ++ ++static int ++help(const struct iphdr* iph, size_t pktlen, ++ struct ip_conntrack* ct, enum ip_conntrack_info ctinfo) ++{ ++ /* tcplen not negative guarenteed by ip_conntrack_tcp.c */ ++ struct tcphdr* tcph = (void*)iph + iph->ihl * 4; ++ u_int32_t tcplen = pktlen - iph->ihl * 4; ++ ++ /* Until there's been traffic both ways, don't look in packets. */ ++ if (ctinfo != IP_CT_ESTABLISHED && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) ++ { ++ DEBUGP("conntrackinfo = %u\n", ctinfo); ++ return NF_ACCEPT; ++ } ++ ++ /* Not whole TCP header? */ ++ if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4) ++ { ++ DEBUGP("tcplen = %u\n", (unsigned)tcplen); ++ return NF_ACCEPT; ++ } ++ ++ /* Checksum invalid? Ignore. */ ++ /* FIXME: Source route IP option packets --RR */ ++ if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr, ++ csum_partial((char*)tcph, tcplen, 0))) ++ { ++ DEBUGP("bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n", ++ tcph, tcplen, NIPQUAD(iph->saddr), NIPQUAD(iph->daddr)); ++ return NF_ACCEPT; ++ } ++ ++ switch (CTINFO2DIR(ctinfo)) ++ { ++ case IP_CT_DIR_ORIGINAL: ++ help_out(iph, pktlen, ct, ctinfo); ++ break; ++ case IP_CT_DIR_REPLY: ++ help_in(iph, pktlen, ct, ctinfo); ++ break; ++ } ++ ++ return NF_ACCEPT; ++} ++ ++static struct ip_conntrack_helper rtsp_helpers[MAX_PORTS]; ++static char rtsp_names[MAX_PORTS][10]; ++ ++/* This function is intentionally _NOT_ defined as __exit */ ++static void ++fini(void) ++{ ++ int i; ++ for (i = 0; i < num_ports; i++) ++ { ++ DEBUGP("unregistering port %d\n", ports[i]); ++ ip_conntrack_helper_unregister(&rtsp_helpers[i]); ++ } ++} ++ ++static int __init ++init(void) ++{ ++ int i, ret; ++ struct ip_conntrack_helper *hlpr; ++ char *tmpname; ++ ++ printk("ip_conntrack_rtsp v" IP_NF_RTSP_VERSION " loading\n"); ++ ++ if (max_outstanding < 1) ++ { ++ printk("ip_conntrack_rtsp: max_outstanding must be a positive integer\n"); ++ return -EBUSY; ++ } ++ if (setup_timeout < 0) ++ { ++ printk("ip_conntrack_rtsp: setup_timeout must be a positive integer\n"); ++ return -EBUSY; ++ } ++ ++ /* If no port given, default to standard rtsp port */ ++ if (ports[0] == 0) ++ { ++ ports[0] = RTSP_PORT; ++ } ++ ++ for (i = 0; (i < MAX_PORTS) && ports[i]; i++) ++ { ++ hlpr = &rtsp_helpers[i]; ++ memset(hlpr, 0, sizeof(struct ip_conntrack_helper)); ++ 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 = 0xFFFF; ++ hlpr->max_expected = max_outstanding; ++ hlpr->timeout = setup_timeout; ++ hlpr->flags = IP_CT_HELPER_F_REUSE_EXPECT; ++ hlpr->me = ip_conntrack_rtsp; ++ hlpr->help = help; ++ ++ tmpname = &rtsp_names[i][0]; ++ if (ports[i] == RTSP_PORT) ++ { ++ sprintf(tmpname, "rtsp"); ++ } ++ else ++ { ++ sprintf(tmpname, "rtsp-%d", i); ++ } ++ hlpr->name = tmpname; ++ ++ DEBUGP("port #%d: %d\n", i, ports[i]); ++ ++ ret = ip_conntrack_helper_register(hlpr); ++ ++ if (ret) ++ { ++ printk("ip_conntrack_rtsp: ERROR registering port %d\n", ports[i]); ++ fini(); ++ return -EBUSY; ++ } ++ num_ports++; ++ } ++ return 0; ++} ++ ++#ifdef CONFIG_IP_NF_NAT_NEEDED ++EXPORT_SYMBOL(ip_rtsp_lock); ++#endif ++ ++module_init(init); ++module_exit(fini); +diff -urN linux-2.4.32/net/ipv4/netfilter/ip_nat_rtsp.c linux-2.4.32.new/net/ipv4/netfilter/ip_nat_rtsp.c +--- linux-2.4.32/net/ipv4/netfilter/ip_nat_rtsp.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.32.new/net/ipv4/netfilter/ip_nat_rtsp.c 2006-03-01 00:55:14.467150168 +0100 +@@ -0,0 +1,621 @@ ++/* ++ * RTSP extension for TCP NAT alteration ++ * (C) 2003 by Tom Marshall ++ * based on ip_nat_irc.c ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version ++ * 2 of the License, or (at your option) any later version. ++ * ++ * Module load syntax: ++ * insmod ip_nat_rtsp.o ports=port1,port2,...port ++ * stunaddr=
++ * destaction=[auto|strip|none] ++ * ++ * If no ports are specified, the default will be port 554 only. ++ * ++ * stunaddr specifies the address used to detect that a client is using STUN. ++ * If this address is seen in the destination parameter, it is assumed that ++ * the client has already punched a UDP hole in the firewall, so we don't ++ * mangle the client_port. If none is specified, it is autodetected. It ++ * only needs to be set if you have multiple levels of NAT. It should be ++ * set to the external address that the STUN clients detect. Note that in ++ * this case, it will not be possible for clients to use UDP with servers ++ * between the NATs. ++ * ++ * If no destaction is specified, auto is used. ++ * destaction=auto: strip destination parameter if it is not stunaddr. ++ * destaction=strip: always strip destination parameter (not recommended). ++ * destaction=none: do not touch destination parameter (not recommended). ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#define NF_NEED_STRNCASECMP ++#define NF_NEED_STRTOU16 ++#include ++#define NF_NEED_MIME_NEXTLINE ++#include ++ ++#define INFOP(fmt, args...) printk(KERN_INFO "%s: %s: " fmt, __FILE__, __FUNCTION__ , ## args) ++#ifdef IP_NF_RTSP_DEBUG ++#define DEBUGP(fmt, args...) printk(KERN_DEBUG "%s: %s: " fmt, __FILE__, __FUNCTION__ , ## args) ++#else ++#define DEBUGP(fmt, args...) ++#endif ++ ++#define MAX_PORTS 8 ++#define DSTACT_AUTO 0 ++#define DSTACT_STRIP 1 ++#define DSTACT_NONE 2 ++ ++static int ports[MAX_PORTS]; ++static char* stunaddr = NULL; ++static char* destaction = NULL; ++ ++static int num_ports = 0; ++static u_int32_t extip = 0; ++static int dstact = 0; ++ ++MODULE_AUTHOR("Tom Marshall "); ++MODULE_DESCRIPTION("RTSP network address translation module"); ++MODULE_LICENSE("GPL"); ++#ifdef MODULE_PARM ++MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i"); ++MODULE_PARM_DESC(ports, "port numbers of RTSP servers"); ++MODULE_PARM(stunaddr, "s"); ++MODULE_PARM_DESC(stunaddr, "Address for detecting STUN"); ++MODULE_PARM(destaction, "s"); ++MODULE_PARM_DESC(destaction, "Action for destination parameter (auto/strip/none)"); ++#endif ++ ++/* protects rtsp part of conntracks */ ++DECLARE_LOCK_EXTERN(ip_rtsp_lock); ++ ++#define SKIP_WSPACE(ptr,len,off) while(off < len && isspace(*(ptr+off))) { off++; } ++ ++/*** helper functions ***/ ++ ++static void ++get_skb_tcpdata(struct sk_buff* skb, char** pptcpdata, uint* ptcpdatalen) ++{ ++ struct iphdr* iph = (struct iphdr*)skb->nh.iph; ++ struct tcphdr* tcph = (struct tcphdr*)((char*)iph + iph->ihl*4); ++ ++ *pptcpdata = (char*)tcph + tcph->doff*4; ++ *ptcpdatalen = ((char*)skb->h.raw + skb->len) - *pptcpdata; ++} ++ ++/*** nat functions ***/ ++ ++/* ++ * Mangle the "Transport:" header: ++ * - Replace all occurences of "client_port=" ++ * - Handle destination parameter ++ * ++ * In: ++ * ct, ctinfo = conntrack context ++ * pskb = packet ++ * tranoff = Transport header offset from TCP data ++ * tranlen = Transport header length (incl. CRLF) ++ * rport_lo = replacement low port (host endian) ++ * rport_hi = replacement high port (host endian) ++ * ++ * Returns packet size difference. ++ * ++ * Assumes that a complete transport header is present, ending with CR or LF ++ */ ++static int ++rtsp_mangle_tran(struct ip_conntrack* ct, enum ip_conntrack_info ctinfo, ++ struct ip_conntrack_expect* exp, ++ struct sk_buff** pskb, 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 ip_ct_rtsp_expect* prtspexp = &exp->help.exp_rtsp_info; ++ struct ip_conntrack_tuple t; ++ ++ char szextaddr[15+1]; ++ uint extaddrlen; ++ int is_stun; ++ ++ get_skb_tcpdata(*pskb, &ptcp, &tcplen); ++ ptran = ptcp+tranoff; ++ ++ if (tranoff+tranlen > tcplen || tcplen-tranoff < tranlen || ++ tranlen < 10 || !iseol(ptran[tranlen-1]) || ++ nf_strncasecmp(ptran, "Transport:", 10) != 0) ++ { ++ INFOP("sanity check failed\n"); ++ return 0; ++ } ++ off += 10; ++ SKIP_WSPACE(ptcp+tranoff, tranlen, off); ++ ++ newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; ++ t = exp->tuple; ++ t.dst.ip = newip; ++ ++ extaddrlen = extip ? sprintf(szextaddr, "%u.%u.%u.%u", NIPQUAD(extip)) ++ : sprintf(szextaddr, "%u.%u.%u.%u", NIPQUAD(newip)); ++ DEBUGP("stunaddr=%s (%s)\n", szextaddr, (extip?"forced":"auto")); ++ ++ rbuf1len = rbufalen = 0; ++ switch (prtspexp->pbtype) ++ { ++ case pb_single: ++ for (loport = prtspexp->loport; loport != 0; loport++) /* XXX: improper wrap? */ ++ { ++ t.dst.u.udp.port = htons(loport); ++ if (ip_conntrack_change_expect(exp, &t) == 0) ++ { ++ DEBUGP("using port %hu\n", loport); ++ break; ++ } ++ } ++ if (loport != 0) ++ { ++ rbuf1len = sprintf(rbuf1, "%hu", loport); ++ rbufalen = sprintf(rbufa, "%hu", loport); ++ } ++ break; ++ case pb_range: ++ for (loport = prtspexp->loport; loport != 0; loport += 2) /* XXX: improper wrap? */ ++ { ++ t.dst.u.udp.port = htons(loport); ++ if (ip_conntrack_change_expect(exp, &t) == 0) ++ { ++ hiport = loport + ~exp->mask.dst.u.udp.port; ++ DEBUGP("using ports %hu-%hu\n", loport, hiport); ++ break; ++ } ++ } ++ if (loport != 0) ++ { ++ rbuf1len = sprintf(rbuf1, "%hu", loport); ++ rbufalen = sprintf(rbufa, "%hu-%hu", loport, loport+1); ++ } ++ break; ++ case pb_discon: ++ for (loport = prtspexp->loport; loport != 0; loport++) /* XXX: improper wrap? */ ++ { ++ t.dst.u.udp.port = htons(loport); ++ if (ip_conntrack_change_expect(exp, &t) == 0) ++ { ++ DEBUGP("using port %hu (1 of 2)\n", loport); ++ break; ++ } ++ } ++ for (hiport = prtspexp->hiport; hiport != 0; hiport++) /* XXX: improper wrap? */ ++ { ++ t.dst.u.udp.port = htons(hiport); ++ if (ip_conntrack_change_expect(exp, &t) == 0) ++ { ++ DEBUGP("using port %hu (2 of 2)\n", hiport); ++ break; ++ } ++ } ++ if (loport != 0 && hiport != 0) ++ { ++ rbuf1len = sprintf(rbuf1, "%hu", loport); ++ if (hiport == loport+1) ++ { ++ rbufalen = sprintf(rbufa, "%hu-%hu", loport, hiport); ++ } ++ else ++ { ++ rbufalen = sprintf(rbufa, "%hu/%hu", loport, hiport); ++ } ++ } ++ break; ++ } ++ ++ if (rbuf1len == 0) ++ { ++ return 0; /* cannot get replacement port(s) */ ++ } ++ ++ /* Transport: tran;field;field=val,tran;field;field=val,... */ ++ while (off < tranlen) ++ { ++ uint saveoff; ++ const char* pparamend; ++ uint nextparamoff; ++ ++ pparamend = memchr(ptran+off, ',', tranlen-off); ++ pparamend = (pparamend == NULL) ? ptran+tranlen : pparamend+1; ++ nextparamoff = pparamend-ptcp; ++ ++ /* ++ * We pass over each param twice. On the first pass, we look for a ++ * destination= field. It is handled by the security policy. If it ++ * is present, allowed, and equal to our external address, we assume ++ * that STUN is being used and we leave the client_port= field alone. ++ */ ++ is_stun = 0; ++ saveoff = off; ++ while (off < nextparamoff) ++ { ++ const char* pfieldend; ++ uint nextfieldoff; ++ ++ pfieldend = memchr(ptran+off, ';', nextparamoff-off); ++ nextfieldoff = (pfieldend == NULL) ? nextparamoff : pfieldend-ptran+1; ++ ++ if (dstact != DSTACT_NONE && strncmp(ptran+off, "destination=", 12) == 0) ++ { ++ if (strncmp(ptran+off+12, szextaddr, extaddrlen) == 0) ++ { ++ is_stun = 1; ++ } ++ if (dstact == DSTACT_STRIP || (dstact == DSTACT_AUTO && !is_stun)) ++ { ++ diff = nextfieldoff-off; ++ if (!ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, ++ off, diff, NULL, 0)) ++ { ++ /* mangle failed, all we can do is bail */ ++ return 0; ++ } ++ get_skb_tcpdata(*pskb, &ptcp, &tcplen); ++ ptran = ptcp+tranoff; ++ tranlen -= diff; ++ nextparamoff -= diff; ++ nextfieldoff -= diff; ++ } ++ } ++ ++ off = nextfieldoff; ++ } ++ if (is_stun) ++ { ++ continue; ++ } ++ off = saveoff; ++ while (off < nextparamoff) ++ { ++ const char* pfieldend; ++ uint nextfieldoff; ++ ++ pfieldend = memchr(ptran+off, ';', nextparamoff-off); ++ nextfieldoff = (pfieldend == NULL) ? nextparamoff : pfieldend-ptran+1; ++ ++ if (strncmp(ptran+off, "client_port=", 12) == 0) ++ { ++ u_int16_t port; ++ uint numlen; ++ uint origoff; ++ uint origlen; ++ char* rbuf = rbuf1; ++ uint rbuflen = rbuf1len; ++ ++ off += 12; ++ origoff = (ptran-ptcp)+off; ++ origlen = 0; ++ numlen = nf_strtou16(ptran+off, &port); ++ off += numlen; ++ origlen += numlen; ++ if (port != prtspexp->loport) ++ { ++ DEBUGP("multiple ports found, port %hu ignored\n", port); ++ } ++ else ++ { ++ if (ptran[off] == '-' || ptran[off] == '/') ++ { ++ off++; ++ origlen++; ++ numlen = nf_strtou16(ptran+off, &port); ++ off += numlen; ++ origlen += numlen; ++ rbuf = rbufa; ++ rbuflen = rbufalen; ++ } ++ ++ /* ++ * note we cannot just memcpy() if the sizes are the same. ++ * the mangle function does skb resizing, checks for a ++ * cloned skb, and updates the checksums. ++ * ++ * parameter 4 below is offset from start of tcp data. ++ */ ++ diff = origlen-rbuflen; ++ if (!ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, ++ origoff, origlen, rbuf, rbuflen)) ++ { ++ /* mangle failed, all we can do is bail */ ++ return 0; ++ } ++ get_skb_tcpdata(*pskb, &ptcp, &tcplen); ++ ptran = ptcp+tranoff; ++ tranlen -= diff; ++ nextparamoff -= diff; ++ nextfieldoff -= diff; ++ } ++ } ++ ++ off = nextfieldoff; ++ } ++ ++ off = nextparamoff; ++ } ++ ++ return 1; ++} ++ ++static unsigned int ++expected(struct sk_buff **pskb, uint hooknum, struct ip_conntrack* ct, struct ip_nat_info* info) ++{ ++ struct ip_nat_multi_range mr; ++ u_int32_t newdstip, newsrcip, newip; ++ ++ struct ip_conntrack *master = master_ct(ct); ++ ++ IP_NF_ASSERT(info); ++ IP_NF_ASSERT(master); ++ ++ IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum)))); ++ ++ newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; ++ newsrcip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; ++ newip = (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC) ? newsrcip : newdstip; ++ ++ DEBUGP("newsrcip=%u.%u.%u.%u, newdstip=%u.%u.%u.%u, newip=%u.%u.%u.%u\n", ++ NIPQUAD(newsrcip), NIPQUAD(newdstip), NIPQUAD(newip)); ++ ++ mr.rangesize = 1; ++ /* We don't want to manip the per-protocol, just the IPs. */ ++ mr.range[0].flags = IP_NAT_RANGE_MAP_IPS; ++ mr.range[0].min_ip = mr.range[0].max_ip = newip; ++ ++ return ip_nat_setup_info(ct, &mr, hooknum); ++} ++ ++static uint ++help_out(struct ip_conntrack* ct, enum ip_conntrack_info ctinfo, ++ struct ip_conntrack_expect* exp, struct sk_buff** pskb) ++{ ++ 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); ++ ++ struct ip_ct_rtsp_expect* prtspexp = &exp->help.exp_rtsp_info; ++ ++ get_skb_tcpdata(*pskb, &ptcp, &tcplen); ++ ++ hdrsoff = exp->seq - ntohl(tcph->seq); ++ hdrslen = prtspexp->len; ++ off = hdrsoff; ++ ++ while (nf_mime_nextline(ptcp, hdrsoff+hdrslen, &off, &lineoff, &linelen)) ++ { ++ if (linelen == 0) ++ { ++ break; ++ } ++ if (off > hdrsoff+hdrslen) ++ { ++ INFOP("!! overrun !!"); ++ break; ++ } ++ DEBUGP("hdr: len=%u, %.*s", linelen, (int)linelen, ptcp+lineoff); ++ ++ if (nf_strncasecmp(ptcp+lineoff, "Transport:", 10) == 0) ++ { ++ uint oldtcplen = tcplen; ++ if (!rtsp_mangle_tran(ct, ctinfo, exp, pskb, lineoff, linelen)) ++ { ++ break; ++ } ++ get_skb_tcpdata(*pskb, &ptcp, &tcplen); ++ hdrslen -= (oldtcplen-tcplen); ++ off -= (oldtcplen-tcplen); ++ lineoff -= (oldtcplen-tcplen); ++ linelen -= (oldtcplen-tcplen); ++ DEBUGP("rep: len=%u, %.*s", linelen, (int)linelen, ptcp+lineoff); ++ } ++ } ++ ++ return NF_ACCEPT; ++} ++ ++static uint ++help_in(struct ip_conntrack* ct, enum ip_conntrack_info ctinfo, ++ struct ip_conntrack_expect* exp, struct sk_buff** pskb) ++{ ++ /* XXX: unmangle */ ++ return NF_ACCEPT; ++} ++ ++static uint ++help(struct ip_conntrack* ct, ++ struct ip_conntrack_expect* exp, ++ struct ip_nat_info* info, ++ enum ip_conntrack_info ctinfo, ++ unsigned int hooknum, ++ struct sk_buff** pskb) ++{ ++ struct iphdr* iph = (struct iphdr*)(*pskb)->nh.iph; ++ struct tcphdr* tcph = (struct tcphdr*)((char*)iph + iph->ihl * 4); ++ uint datalen; ++ int dir; ++ struct ip_ct_rtsp_expect* ct_rtsp_info; ++ int rc = NF_ACCEPT; ++ ++ if (ct == NULL || exp == NULL || info == NULL || pskb == NULL) ++ { ++ DEBUGP("!! null ptr (%p,%p,%p,%p) !!\n", ct, exp, info, pskb); ++ return NF_ACCEPT; ++ } ++ ++ ct_rtsp_info = &exp->help.exp_rtsp_info; ++ ++ /* ++ * Only mangle things once: original direction in POST_ROUTING ++ * and reply direction on PRE_ROUTING. ++ */ ++ dir = CTINFO2DIR(ctinfo); ++ if (!((hooknum == NF_IP_POST_ROUTING && dir == IP_CT_DIR_ORIGINAL) ++ || (hooknum == NF_IP_PRE_ROUTING && dir == IP_CT_DIR_REPLY))) ++ { ++ DEBUGP("Not touching dir %s at hook %s\n", ++ dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY", ++ hooknum == NF_IP_POST_ROUTING ? "POSTROUTING" ++ : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING" ++ : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???"); ++ return NF_ACCEPT; ++ } ++ DEBUGP("got beyond not touching\n"); ++ ++ datalen = (*pskb)->len - iph->ihl * 4 - tcph->doff * 4; ++ ++ LOCK_BH(&ip_rtsp_lock); ++ /* Ensure the packet contains all of the marked data */ ++ if (!between(exp->seq + ct_rtsp_info->len, ++ ntohl(tcph->seq), ntohl(tcph->seq) + datalen)) ++ { ++ /* Partial retransmission? Probably a hacker. */ ++ if (net_ratelimit()) ++ { ++ INFOP("partial packet %u/%u in %u/%u\n", ++ exp->seq, ct_rtsp_info->len, ntohl(tcph->seq), ntohl(tcph->seq) + datalen); ++ } ++ UNLOCK_BH(&ip_rtsp_lock); ++ return NF_DROP; ++ } ++ ++ switch (dir) ++ { ++ case IP_CT_DIR_ORIGINAL: ++ rc = help_out(ct, ctinfo, exp, pskb); ++ break; ++ case IP_CT_DIR_REPLY: ++ rc = help_in(ct, ctinfo, exp, pskb); ++ break; ++ } ++ UNLOCK_BH(&ip_rtsp_lock); ++ ++ return rc; ++} ++ ++static struct ip_nat_helper ip_nat_rtsp_helpers[MAX_PORTS]; ++static char rtsp_names[MAX_PORTS][10]; ++ ++/* This function is intentionally _NOT_ defined as __exit */ ++static void ++fini(void) ++{ ++ int i; ++ ++ for (i = 0; i < num_ports; i++) ++ { ++ DEBUGP("unregistering helper for port %d\n", ports[i]); ++ ip_nat_helper_unregister(&ip_nat_rtsp_helpers[i]); ++ } ++} ++ ++static int __init ++init(void) ++{ ++ int ret = 0; ++ int i; ++ struct ip_nat_helper* hlpr; ++ char* tmpname; ++ ++ printk("ip_nat_rtsp v" IP_NF_RTSP_VERSION " loading\n"); ++ ++ if (ports[0] == 0) ++ { ++ ports[0] = RTSP_PORT; ++ } ++ ++ for (i = 0; (i < MAX_PORTS) && ports[i] != 0; i++) ++ { ++ hlpr = &ip_nat_rtsp_helpers[i]; ++ memset(hlpr, 0, sizeof(struct ip_nat_helper)); ++ ++ hlpr->tuple.dst.protonum = IPPROTO_TCP; ++ hlpr->tuple.src.u.tcp.port = htons(ports[i]); ++ hlpr->mask.src.u.tcp.port = 0xFFFF; ++ hlpr->mask.dst.protonum = 0xFFFF; ++ hlpr->help = help; ++ hlpr->flags = 0; ++ hlpr->me = THIS_MODULE; ++ hlpr->expect = expected; ++ ++ tmpname = &rtsp_names[i][0]; ++ if (ports[i] == RTSP_PORT) ++ { ++ sprintf(tmpname, "rtsp"); ++ } ++ else ++ { ++ sprintf(tmpname, "rtsp-%d", i); ++ } ++ hlpr->name = tmpname; ++ ++ DEBUGP("registering helper for port %d: name %s\n", ports[i], hlpr->name); ++ ret = ip_nat_helper_register(hlpr); ++ ++ if (ret) ++ { ++ printk("ip_nat_rtsp: error registering helper for port %d\n", ports[i]); ++ fini(); ++ return 1; ++ } ++ num_ports++; ++ } ++ if (stunaddr != NULL) ++ { ++ extip = in_aton(stunaddr); ++ } ++ if (destaction != NULL) ++ { ++ if (strcmp(destaction, "auto") == 0) ++ { ++ dstact = DSTACT_AUTO; ++ } ++ if (strcmp(destaction, "strip") == 0) ++ { ++ dstact = DSTACT_STRIP; ++ } ++ if (strcmp(destaction, "none") == 0) ++ { ++ dstact = DSTACT_NONE; ++ } ++ } ++ return ret; ++} ++ ++module_init(init); ++module_exit(fini); +--- linux-2.4.32/arch/mips/kernel/mips_ksyms.c 2006-03-01 00:49:34.142887320 +0100 ++++ linux-2.4.32.new/arch/mips/kernel/mips_ksyms.c 2006-03-01 00:55:14.469149864 +0100 +@@ -52,6 +52,7 @@ + /* + * String functions + */ ++EXPORT_SYMBOL_NOVERS(memchr); + EXPORT_SYMBOL_NOVERS(memcmp); + EXPORT_SYMBOL_NOVERS(memset); + EXPORT_SYMBOL_NOVERS(memcpy); +diff -urN linux-2.4.32/include/linux/netfilter_helpers.h linux-2.4.32.new/include/linux/netfilter_helpers.h +--- linux-2.4.32/include/linux/netfilter_helpers.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.32.new/include/linux/netfilter_helpers.h 2006-03-01 00:55:14.470149712 +0100 +@@ -0,0 +1,133 @@ ++/* ++ * Helpers for netfiler modules. This file provides implementations for basic ++ * functions such as strncasecmp(), etc. ++ * ++ * gcc will warn for defined but unused functions, so we only include the ++ * functions requested. The following macros are used: ++ * NF_NEED_STRNCASECMP nf_strncasecmp() ++ * NF_NEED_STRTOU16 nf_strtou16() ++ * NF_NEED_STRTOU32 nf_strtou32() ++ */ ++#ifndef _NETFILTER_HELPERS_H ++#define _NETFILTER_HELPERS_H ++ ++/* Only include these functions for kernel code. */ ++#ifdef __KERNEL__ ++ ++#include ++#define iseol(c) ( (c) == '\r' || (c) == '\n' ) ++ ++/* ++ * The standard strncasecmp() ++ */ ++#ifdef NF_NEED_STRNCASECMP ++static int ++nf_strncasecmp(const char* s1, const char* s2, u_int32_t len) ++{ ++ if (s1 == NULL || s2 == NULL) ++ { ++ if (s1 == NULL && s2 == NULL) ++ { ++ return 0; ++ } ++ return (s1 == NULL) ? -1 : 1; ++ } ++ while (len > 0 && tolower(*s1) == tolower(*s2)) ++ { ++ len--; ++ s1++; ++ s2++; ++ } ++ return ( (len == 0) ? 0 : (tolower(*s1) - tolower(*s2)) ); ++} ++#endif /* NF_NEED_STRNCASECMP */ ++ ++/* ++ * Parse a string containing a 16-bit unsigned integer. ++ * Returns the number of chars used, or zero if no number is found. ++ */ ++#ifdef NF_NEED_STRTOU16 ++static int ++nf_strtou16(const char* pbuf, u_int16_t* pval) ++{ ++ int n = 0; ++ ++ *pval = 0; ++ while (isdigit(pbuf[n])) ++ { ++ *pval = (*pval * 10) + (pbuf[n] - '0'); ++ n++; ++ } ++ ++ return n; ++} ++#endif /* NF_NEED_STRTOU16 */ ++ ++/* ++ * Parse a string containing a 32-bit unsigned integer. ++ * Returns the number of chars used, or zero if no number is found. ++ */ ++#ifdef NF_NEED_STRTOU32 ++static int ++nf_strtou32(const char* pbuf, u_int32_t* pval) ++{ ++ int n = 0; ++ ++ *pval = 0; ++ while (pbuf[n] >= '0' && pbuf[n] <= '9') ++ { ++ *pval = (*pval * 10) + (pbuf[n] - '0'); ++ n++; ++ } ++ ++ return n; ++} ++#endif /* NF_NEED_STRTOU32 */ ++ ++/* ++ * Given a buffer and length, advance to the next line and mark the current ++ * line. ++ */ ++#ifdef NF_NEED_NEXTLINE ++static int ++nf_nextline(char* p, uint len, uint* poff, uint* plineoff, uint* plinelen) ++{ ++ uint off = *poff; ++ uint physlen = 0; ++ ++ if (off >= len) ++ { ++ return 0; ++ } ++ ++ while (p[off] != '\n') ++ { ++ if (len-off <= 1) ++ { ++ return 0; ++ } ++ ++ physlen++; ++ off++; ++ } ++ ++ /* if we saw a crlf, physlen needs adjusted */ ++ if (physlen > 0 && p[off] == '\n' && p[off-1] == '\r') ++ { ++ physlen--; ++ } ++ ++ /* advance past the newline */ ++ off++; ++ ++ *plineoff = *poff; ++ *plinelen = physlen; ++ *poff = off; ++ ++ return 1; ++} ++#endif /* NF_NEED_NEXTLINE */ ++ ++#endif /* __KERNEL__ */ ++ ++#endif /* _NETFILTER_HELPERS_H */ +diff -urN linux-2.4.32/include/linux/netfilter_ipv4/ip_conntrack_rtsp.h linux-2.4.32.new/include/linux/netfilter_ipv4/ip_conntrack_rtsp.h +--- linux-2.4.32/include/linux/netfilter_ipv4/ip_conntrack_rtsp.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.32.new/include/linux/netfilter_ipv4/ip_conntrack_rtsp.h 2006-03-01 00:55:14.472149408 +0100 +@@ -0,0 +1,68 @@ ++/* ++ * RTSP extension for IP connection tracking. ++ * (C) 2003 by Tom Marshall ++ * based on ip_conntrack_irc.h ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version ++ * 2 of the License, or (at your option) any later version. ++ */ ++#ifndef _IP_CONNTRACK_RTSP_H ++#define _IP_CONNTRACK_RTSP_H ++ ++/* #define IP_NF_RTSP_DEBUG */ ++#define IP_NF_RTSP_VERSION "0.01" ++ ++/* port block types */ ++typedef enum { ++ pb_single, /* client_port=x */ ++ pb_range, /* client_port=x-y */ ++ pb_discon /* client_port=x/y (rtspbis) */ ++} portblock_t; ++ ++/* We record seq number and length of rtsp headers here, all in host order. */ ++ ++/* ++ * This structure is per expected connection. It is a member of struct ++ * ip_conntrack_expect. The TCP SEQ for the conntrack expect is stored ++ * there and we are expected to only store the length of the data which ++ * needs replaced. If a packet contains multiple RTSP messages, we create ++ * one expected connection per message. ++ * ++ * We use these variables to mark the entire header block. This may seem ++ * like overkill, but the nature of RTSP requires it. A header may appear ++ * multiple times in a message. We must treat two Transport headers the ++ * same as one Transport header with two entries. ++ */ ++struct ip_ct_rtsp_expect ++{ ++ u_int32_t len; /* length of header block */ ++ portblock_t pbtype; /* Type of port block that was requested */ ++ u_int16_t loport; /* Port that was requested, low or first */ ++ u_int16_t hiport; /* Port that was requested, high or second */ ++#if 0 ++ uint method; /* RTSP method */ ++ uint cseq; /* CSeq from request */ ++#endif ++}; ++ ++/* This structure exists only once per master */ ++struct ip_ct_rtsp_master ++{ ++ /* Empty (?) */ ++}; ++ ++ ++#ifdef __KERNEL__ ++ ++#include ++ ++#define RTSP_PORT 554 ++ ++/* Protects rtsp part of conntracks */ ++DECLARE_LOCK_EXTERN(ip_rtsp_lock); ++ ++#endif /* __KERNEL__ */ ++ ++#endif /* _IP_CONNTRACK_RTSP_H */ +diff -urN linux-2.4.32/include/linux/netfilter_mime.h linux-2.4.32.new/include/linux/netfilter_mime.h +--- linux-2.4.32/include/linux/netfilter_mime.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.32.new/include/linux/netfilter_mime.h 2006-03-01 00:55:14.473149256 +0100 +@@ -0,0 +1,90 @@ ++/* ++ * MIME functions for netfilter modules. This file provides implementations ++ * for basic MIME parsing. MIME headers are used in many protocols, such as ++ * HTTP, RTSP, SIP, etc. ++ * ++ * gcc will warn for defined but unused functions, so we only include the ++ * functions requested. The following macros are used: ++ * NF_NEED_MIME_NEXTLINE nf_mime_nextline() ++ */ ++#ifndef _NETFILTER_MIME_H ++#define _NETFILTER_MIME_H ++ ++/* Only include these functions for kernel code. */ ++#ifdef __KERNEL__ ++ ++#include ++#include ++ ++/* ++ * Given a buffer and length, advance to the next line and mark the current ++ * line. If the current line is empty, *plinelen will be set to zero. If ++ * not, it will be set to the actual line length (including CRLF). ++ * ++ * 'line' in this context means logical line (includes LWS continuations). ++ * Returns 1 on success, 0 on failure. ++ */ ++#ifdef NF_NEED_MIME_NEXTLINE ++static int ++nf_mime_nextline(char* p, uint len, uint* poff, uint* plineoff, uint* plinelen) ++{ ++ uint off = *poff; ++ uint physlen = 0; ++ int is_first_line = 1; ++ ++ if (off >= len) ++ { ++ return 0; ++ } ++ ++ do ++ { ++ while (p[off] != '\n') ++ { ++ if (len-off <= 1) ++ { ++ return 0; ++ } ++ ++ physlen++; ++ off++; ++ } ++ ++ /* if we saw a crlf, physlen needs adjusted */ ++ if (physlen > 0 && p[off] == '\n' && p[off-1] == '\r') ++ { ++ physlen--; ++ } ++ ++ /* advance past the newline */ ++ off++; ++ ++ /* check for an empty line */ ++ if (physlen == 0) ++ { ++ break; ++ } ++ ++ /* check for colon on the first physical line */ ++ if (is_first_line) ++ { ++ is_first_line = 0; ++ if (memchr(p+(*poff), ':', physlen) == NULL) ++ { ++ return 0; ++ } ++ } ++ } ++ while (p[off] == ' ' || p[off] == '\t'); ++ ++ *plineoff = *poff; ++ *plinelen = (physlen == 0) ? 0 : (off - *poff); ++ *poff = off; ++ ++ return 1; ++} ++#endif /* NF_NEED_MIME_NEXTLINE */ ++ ++#endif /* __KERNEL__ */ ++ ++#endif /* _NETFILTER_MIME_H */ +--- linux-2.4.32/include/linux/netfilter_ipv4/ip_conntrack.h 2006-03-01 00:53:57.889791696 +0100 ++++ linux-2.4.32.new/include/linux/netfilter_ipv4/ip_conntrack.h 2006-03-01 01:06:32.178122440 +0100 +@@ -72,6 +72,7 @@ + #include + #include + #include ++#include + + /* per expectation: application helper private data */ + union ip_conntrack_expect_help { +@@ -81,6 +82,7 @@ + struct ip_ct_irc_expect exp_irc_info; + struct ip_ct_pptp_expect exp_pptp_info; + struct ip_ct_h225_expect exp_h225_info; ++ struct ip_ct_rtsp_expect exp_rtsp_info; + + #ifdef CONFIG_IP_NF_NAT_NEEDED + union { +@@ -96,6 +98,7 @@ + struct ip_ct_irc_master ct_irc_info; + struct ip_ct_pptp_master ct_pptp_info; + struct ip_ct_h225_master ct_h225_info; ++ struct ip_ct_rtsp_master ct_rtsp_info; + }; + + #ifdef CONFIG_IP_NF_NAT_NEEDED diff --git a/openwrt/target/linux/generic-2.4/patches/615-netfilter_nat_mms.patch b/openwrt/target/linux/generic-2.4/patches/615-netfilter_nat_mms.patch index 14e070a64d..3871d59395 100644 --- a/openwrt/target/linux/generic-2.4/patches/615-netfilter_nat_mms.patch +++ b/openwrt/target/linux/generic-2.4/patches/615-netfilter_nat_mms.patch @@ -1,53 +1,53 @@ -diff -urN linux-2.4.32/net/ipv4/netfilter/Config.in linux-2.4.32/net/ipv4/netfilter/Config.in ---- linux-2.4.32/net/ipv4/netfilter/Config.in 2005-12-12 16:29:01.000000000 +0100 -+++ linux-2.4.32/net/ipv4/netfilter/Config.in 2005-12-12 16:35:37.000000000 +0100 +diff -urN linux-2.4.32/net/ipv4/netfilter/Config.in linux-2.4.32.new/net/ipv4/netfilter/Config.in +--- linux-2.4.32/net/ipv4/netfilter/Config.in 2006-03-01 01:12:48.268947944 +0100 ++++ linux-2.4.32.new/net/ipv4/netfilter/Config.in 2006-03-01 01:14:53.455916632 +0100 @@ -17,6 +17,7 @@ dep_tristate ' PPTP protocol support' CONFIG_IP_NF_PPTP $CONFIG_IP_NF_CT_PROTO_GRE - dep_tristate ' SIP protocol support' CONFIG_IP_NF_SIP $CONFIG_IP_NF_CONNTRACK dep_tristate ' H.323 (netmeeting) support' CONFIG_IP_NF_H323 $CONFIG_IP_NF_CONNTRACK + dep_tristate ' RTSP protocol support' CONFIG_IP_NF_RTSP $CONFIG_IP_NF_CONNTRACK + dep_tristate ' MMS protocol support' CONFIG_IP_NF_MMS $CONFIG_IP_NF_CONNTRACK fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then -@@ -120,6 +121,13 @@ - define_tristate CONFIG_IP_NF_NAT_H323 $CONFIG_IP_NF_NAT - fi +@@ -127,6 +128,13 @@ + define_tristate CONFIG_IP_NF_NAT_RTSP $CONFIG_IP_NF_NAT + fi fi + if [ "$CONFIG_IP_NF_MMS" = "m" ]; then -+ define_tristate CONFIG_IP_NF_NAT_MMS m ++ define_tristate CONFIG_IP_NF_NAT_MMS m + else -+ if [ "$CONFIG_IP_NF_MMS" = "y" ]; then -+ define_tristate CONFIG_IP_NF_NAT_MMS $CONFIG_IP_NF_NAT -+ fi ++ if [ "$CONFIG_IP_NF_MMS" = "y" ]; then ++ define_tristate CONFIG_IP_NF_NAT_MMS $CONFIG_IP_NF_NAT ++ fi + fi - if [ "$CONFIG_IP_NF_AMANDA" = "m" ]; then - define_tristate CONFIG_IP_NF_NAT_AMANDA m - else -diff -urN linux-2.4.32/net/ipv4/netfilter/Makefile linux-2.4.32/net/ipv4/netfilter/Makefile ---- linux-2.4.32/net/ipv4/netfilter/Makefile 2005-12-12 16:29:01.000000000 +0100 -+++ linux-2.4.32/net/ipv4/netfilter/Makefile 2005-12-12 16:36:26.000000000 +0100 + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + dep_tristate ' Basic SNMP-ALG support (EXPERIMENTAL)' CONFIG_IP_NF_NAT_SNMP_BASIC $CONFIG_IP_NF_NAT + fi +diff -urN linux-2.4.32/net/ipv4/netfilter/Makefile linux-2.4.32.new/net/ipv4/netfilter/Makefile +--- linux-2.4.32/net/ipv4/netfilter/Makefile 2006-03-01 01:12:48.270947640 +0100 ++++ linux-2.4.32.new/net/ipv4/netfilter/Makefile 2006-03-01 01:15:25.263081208 +0100 @@ -61,6 +61,10 @@ - ifdef CONFIG_IP_NF_NAT_H323 - export-objs += ip_conntrack_h323.o + ifdef CONFIG_IP_NF_NAT_RTSP + export-objs += ip_conntrack_rtsp.o endif +obj-$(CONFIG_IP_NF_MMS) += ip_conntrack_mms.o +ifdef CONFIG_IP_NF_NAT_MMS -+ export-objs += ip_conntrack_mms.o ++ export-objs += ip_conntrack_mms.o +endif - # NAT helpers -@@ -72,6 +76,7 @@ + +@@ -73,6 +77,7 @@ obj-$(CONFIG_IP_NF_NAT_PPTP) += ip_nat_pptp.o - obj-$(CONFIG_IP_NF_NAT_SIP) += ip_nat_sip.o obj-$(CONFIG_IP_NF_NAT_H323) += ip_nat_h323.o + obj-$(CONFIG_IP_NF_NAT_RTSP) += ip_nat_rtsp.o +obj-$(CONFIG_IP_NF_NAT_MMS) += ip_nat_mms.o # generic IP tables obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o -diff -urN linux-2.4.32/net/ipv4/netfilter/ip_conntrack_mms.c linux-2.4.32/net/ipv4/netfilter/ip_conntrack_mms.c +diff -urN linux-2.4.32/net/ipv4/netfilter/ip_conntrack_mms.c linux-2.4.32.new/net/ipv4/netfilter/ip_conntrack_mms.c --- linux-2.4.32/net/ipv4/netfilter/ip_conntrack_mms.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.32/net/ipv4/netfilter/ip_conntrack_mms.c 2005-12-12 16:32:54.000000000 +0100 ++++ linux-2.4.32.new/net/ipv4/netfilter/ip_conntrack_mms.c 2006-03-01 01:13:32.991149136 +0100 @@ -0,0 +1,292 @@ +/* MMS extension for IP connection tracking + * (C) 2002 by Filip Sneppe @@ -341,9 +341,9 @@ diff -urN linux-2.4.32/net/ipv4/netfilter/ip_conntrack_mms.c linux-2.4.32/net/ip + +module_init(init); +module_exit(fini); -diff -urN linux-2.4.32/net/ipv4/netfilter/ip_nat_mms.c linux-2.4.32/net/ipv4/netfilter/ip_nat_mms.c +diff -urN linux-2.4.32/net/ipv4/netfilter/ip_nat_mms.c linux-2.4.32.new/net/ipv4/netfilter/ip_nat_mms.c --- linux-2.4.32/net/ipv4/netfilter/ip_nat_mms.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.32/net/ipv4/netfilter/ip_nat_mms.c 2005-12-12 16:32:54.000000000 +0100 ++++ linux-2.4.32.new/net/ipv4/netfilter/ip_nat_mms.c 2006-03-01 01:13:32.992148984 +0100 @@ -0,0 +1,330 @@ +/* MMS extension for TCP NAT alteration. + * (C) 2002 by Filip Sneppe @@ -675,36 +675,36 @@ diff -urN linux-2.4.32/net/ipv4/netfilter/ip_nat_mms.c linux-2.4.32/net/ipv4/net + +module_init(init); +module_exit(fini); -diff -urN linux-2.4.32/include/linux/netfilter_ipv4/ip_conntrack.h linux-2.4.32/include/linux/netfilter_ipv4/ip_conntrack.h ---- linux-2.4.32/include/linux/netfilter_ipv4/ip_conntrack.h 2005-12-12 16:29:01.000000000 +0100 -+++ linux-2.4.32/include/linux/netfilter_ipv4/ip_conntrack.h 2005-12-12 16:34:09.000000000 +0100 +diff -urN linux-2.4.32/include/linux/netfilter_ipv4/ip_conntrack.h linux-2.4.32.new/include/linux/netfilter_ipv4/ip_conntrack.h +--- linux-2.4.32/include/linux/netfilter_ipv4/ip_conntrack.h 2006-03-01 01:12:47.910002512 +0100 ++++ linux-2.4.32.new/include/linux/netfilter_ipv4/ip_conntrack.h 2006-03-01 01:16:16.710260048 +0100 @@ -73,6 +73,7 @@ #include - #include #include + #include +#include /* per expectation: application helper private data */ union ip_conntrack_expect_help { @@ -83,6 +84,7 @@ struct ip_ct_pptp_expect exp_pptp_info; - struct ip_ct_sip_expect exp_sip_info; struct ip_ct_h225_expect exp_h225_info; + struct ip_ct_rtsp_expect exp_rtsp_info; + struct ip_ct_mms_expect exp_mms_info; #ifdef CONFIG_IP_NF_NAT_NEEDED union { @@ -99,6 +101,7 @@ struct ip_ct_pptp_master ct_pptp_info; - struct ip_ct_sip_master ct_sip_info; struct ip_ct_h225_master ct_h225_info; + struct ip_ct_rtsp_master ct_rtsp_info; + struct ip_ct_mms_master ct_mms_info; }; #ifdef CONFIG_IP_NF_NAT_NEEDED -diff -urN linux-2.4.32/include/linux/netfilter_ipv4/ip_conntrack_mms.h linux-2.4.32/include/linux/netfilter_ipv4/ip_conntrack_mms.h +diff -urN linux-2.4.32/include/linux/netfilter_ipv4/ip_conntrack_mms.h linux-2.4.32.new/include/linux/netfilter_ipv4/ip_conntrack_mms.h --- linux-2.4.32/include/linux/netfilter_ipv4/ip_conntrack_mms.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.32/include/linux/netfilter_ipv4/ip_conntrack_mms.h 2005-12-12 16:32:54.000000000 +0100 ++++ linux-2.4.32.new/include/linux/netfilter_ipv4/ip_conntrack_mms.h 2006-03-01 01:13:32.993148832 +0100 @@ -0,0 +1,31 @@ +#ifndef _IP_CONNTRACK_MMS_H +#define _IP_CONNTRACK_MMS_H diff --git a/openwrt/target/linux/generic-2.4/patches/617-netfilter_nat_rtsp.patch b/openwrt/target/linux/generic-2.4/patches/617-netfilter_nat_rtsp.patch deleted file mode 100644 index 28bf664423..0000000000 --- a/openwrt/target/linux/generic-2.4/patches/617-netfilter_nat_rtsp.patch +++ /dev/null @@ -1,1538 +0,0 @@ -diff -urN linux-2.4.32.orig/arch/mips/kernel/mips_ksyms.c linux-2.4.32/arch/mips/kernel/mips_ksyms.c ---- linux-2.4.32.orig/arch/mips/kernel/mips_ksyms.c 2005-12-29 12:17:49.000000000 +0100 -+++ linux-2.4.32/arch/mips/kernel/mips_ksyms.c 2005-12-29 12:18:26.000000000 +0100 -@@ -52,6 +52,7 @@ - /* - * String functions - */ -+EXPORT_SYMBOL_NOVERS(memchr); - EXPORT_SYMBOL_NOVERS(memcmp); - EXPORT_SYMBOL_NOVERS(memset); - EXPORT_SYMBOL_NOVERS(memcpy); -diff -urN linux-2.4.32.orig/Documentation/Configure.help linux-2.4.32/Documentation/Configure.help ---- linux-2.4.32.orig/Documentation/Configure.help 2005-12-29 12:17:55.000000000 +0100 -+++ linux-2.4.32/Documentation/Configure.help 2005-12-29 12:18:26.000000000 +0100 -@@ -2817,6 +2817,14 @@ - Documentation/modules.txt. If unsure, say `N'. - - -+RTSP protocol support -+CONFIG_IP_NF_RTSP -+ Support the RTSP protocol. This allows UDP transports to be setup -+ properly, including RTP and RDT. -+ -+ If you want to compile it as a module, say 'M' here and read -+ Documentation/modules.txt. If unsure, say 'Y'. -+ - IRC Send/Chat protocol support - CONFIG_IP_NF_IRC - There is a commonly-used extension to IRC called -diff -urN linux-2.4.32.orig/include/linux/netfilter_helpers.h linux-2.4.32/include/linux/netfilter_helpers.h ---- linux-2.4.32.orig/include/linux/netfilter_helpers.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.32/include/linux/netfilter_helpers.h 2005-12-29 12:18:26.000000000 +0100 -@@ -0,0 +1,133 @@ -+/* -+ * Helpers for netfiler modules. This file provides implementations for basic -+ * functions such as strncasecmp(), etc. -+ * -+ * gcc will warn for defined but unused functions, so we only include the -+ * functions requested. The following macros are used: -+ * NF_NEED_STRNCASECMP nf_strncasecmp() -+ * NF_NEED_STRTOU16 nf_strtou16() -+ * NF_NEED_STRTOU32 nf_strtou32() -+ */ -+#ifndef _NETFILTER_HELPERS_H -+#define _NETFILTER_HELPERS_H -+ -+/* Only include these functions for kernel code. */ -+#ifdef __KERNEL__ -+ -+#include -+#define iseol(c) ( (c) == '\r' || (c) == '\n' ) -+ -+/* -+ * The standard strncasecmp() -+ */ -+#ifdef NF_NEED_STRNCASECMP -+static int -+nf_strncasecmp(const char* s1, const char* s2, u_int32_t len) -+{ -+ if (s1 == NULL || s2 == NULL) -+ { -+ if (s1 == NULL && s2 == NULL) -+ { -+ return 0; -+ } -+ return (s1 == NULL) ? -1 : 1; -+ } -+ while (len > 0 && tolower(*s1) == tolower(*s2)) -+ { -+ len--; -+ s1++; -+ s2++; -+ } -+ return ( (len == 0) ? 0 : (tolower(*s1) - tolower(*s2)) ); -+} -+#endif /* NF_NEED_STRNCASECMP */ -+ -+/* -+ * Parse a string containing a 16-bit unsigned integer. -+ * Returns the number of chars used, or zero if no number is found. -+ */ -+#ifdef NF_NEED_STRTOU16 -+static int -+nf_strtou16(const char* pbuf, u_int16_t* pval) -+{ -+ int n = 0; -+ -+ *pval = 0; -+ while (isdigit(pbuf[n])) -+ { -+ *pval = (*pval * 10) + (pbuf[n] - '0'); -+ n++; -+ } -+ -+ return n; -+} -+#endif /* NF_NEED_STRTOU16 */ -+ -+/* -+ * Parse a string containing a 32-bit unsigned integer. -+ * Returns the number of chars used, or zero if no number is found. -+ */ -+#ifdef NF_NEED_STRTOU32 -+static int -+nf_strtou32(const char* pbuf, u_int32_t* pval) -+{ -+ int n = 0; -+ -+ *pval = 0; -+ while (pbuf[n] >= '0' && pbuf[n] <= '9') -+ { -+ *pval = (*pval * 10) + (pbuf[n] - '0'); -+ n++; -+ } -+ -+ return n; -+} -+#endif /* NF_NEED_STRTOU32 */ -+ -+/* -+ * Given a buffer and length, advance to the next line and mark the current -+ * line. -+ */ -+#ifdef NF_NEED_NEXTLINE -+static int -+nf_nextline(char* p, uint len, uint* poff, uint* plineoff, uint* plinelen) -+{ -+ uint off = *poff; -+ uint physlen = 0; -+ -+ if (off >= len) -+ { -+ return 0; -+ } -+ -+ while (p[off] != '\n') -+ { -+ if (len-off <= 1) -+ { -+ return 0; -+ } -+ -+ physlen++; -+ off++; -+ } -+ -+ /* if we saw a crlf, physlen needs adjusted */ -+ if (physlen > 0 && p[off] == '\n' && p[off-1] == '\r') -+ { -+ physlen--; -+ } -+ -+ /* advance past the newline */ -+ off++; -+ -+ *plineoff = *poff; -+ *plinelen = physlen; -+ *poff = off; -+ -+ return 1; -+} -+#endif /* NF_NEED_NEXTLINE */ -+ -+#endif /* __KERNEL__ */ -+ -+#endif /* _NETFILTER_HELPERS_H */ -diff -urN linux-2.4.32.orig/include/linux/netfilter_ipv4/ip_conntrack.h linux-2.4.32/include/linux/netfilter_ipv4/ip_conntrack.h ---- linux-2.4.32.orig/include/linux/netfilter_ipv4/ip_conntrack.h 2005-12-29 12:17:55.000000000 +0100 -+++ linux-2.4.32/include/linux/netfilter_ipv4/ip_conntrack.h 2005-12-29 12:18:26.000000000 +0100 -@@ -66,6 +66,7 @@ - }; - - /* Add protocol helper include file here */ -+#include - #include - - #include -@@ -78,6 +79,7 @@ - /* per expectation: application helper private data */ - union ip_conntrack_expect_help { - /* insert conntrack helper private data (expect) here */ -+ struct ip_ct_rtsp_expect exp_rtsp_info; - struct ip_ct_amanda_expect exp_amanda_info; - struct ip_ct_ftp_expect exp_ftp_info; - struct ip_ct_irc_expect exp_irc_info; -@@ -96,6 +98,7 @@ - /* per conntrack: application helper private data */ - union ip_conntrack_help { - /* insert conntrack helper private data (master) here */ -+ struct ip_ct_rtsp_master ct_rtsp_info; - struct ip_ct_ftp_master ct_ftp_info; - struct ip_ct_irc_master ct_irc_info; - struct ip_ct_pptp_master ct_pptp_info; -diff -urN linux-2.4.32.orig/include/linux/netfilter_ipv4/ip_conntrack_rtsp.h linux-2.4.32/include/linux/netfilter_ipv4/ip_conntrack_rtsp.h ---- linux-2.4.32.orig/include/linux/netfilter_ipv4/ip_conntrack_rtsp.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.32/include/linux/netfilter_ipv4/ip_conntrack_rtsp.h 2005-12-29 12:18:26.000000000 +0100 -@@ -0,0 +1,68 @@ -+/* -+ * RTSP extension for IP connection tracking. -+ * (C) 2003 by Tom Marshall -+ * based on ip_conntrack_irc.h -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version -+ * 2 of the License, or (at your option) any later version. -+ */ -+#ifndef _IP_CONNTRACK_RTSP_H -+#define _IP_CONNTRACK_RTSP_H -+ -+/* #define IP_NF_RTSP_DEBUG */ -+#define IP_NF_RTSP_VERSION "0.01" -+ -+/* port block types */ -+typedef enum { -+ pb_single, /* client_port=x */ -+ pb_range, /* client_port=x-y */ -+ pb_discon /* client_port=x/y (rtspbis) */ -+} portblock_t; -+ -+/* We record seq number and length of rtsp headers here, all in host order. */ -+ -+/* -+ * This structure is per expected connection. It is a member of struct -+ * ip_conntrack_expect. The TCP SEQ for the conntrack expect is stored -+ * there and we are expected to only store the length of the data which -+ * needs replaced. If a packet contains multiple RTSP messages, we create -+ * one expected connection per message. -+ * -+ * We use these variables to mark the entire header block. This may seem -+ * like overkill, but the nature of RTSP requires it. A header may appear -+ * multiple times in a message. We must treat two Transport headers the -+ * same as one Transport header with two entries. -+ */ -+struct ip_ct_rtsp_expect -+{ -+ u_int32_t len; /* length of header block */ -+ portblock_t pbtype; /* Type of port block that was requested */ -+ u_int16_t loport; /* Port that was requested, low or first */ -+ u_int16_t hiport; /* Port that was requested, high or second */ -+#if 0 -+ uint method; /* RTSP method */ -+ uint cseq; /* CSeq from request */ -+#endif -+}; -+ -+/* This structure exists only once per master */ -+struct ip_ct_rtsp_master -+{ -+ /* Empty (?) */ -+}; -+ -+ -+#ifdef __KERNEL__ -+ -+#include -+ -+#define RTSP_PORT 554 -+ -+/* Protects rtsp part of conntracks */ -+DECLARE_LOCK_EXTERN(ip_rtsp_lock); -+ -+#endif /* __KERNEL__ */ -+ -+#endif /* _IP_CONNTRACK_RTSP_H */ -diff -urN linux-2.4.32.orig/include/linux/netfilter_mime.h linux-2.4.32/include/linux/netfilter_mime.h ---- linux-2.4.32.orig/include/linux/netfilter_mime.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.32/include/linux/netfilter_mime.h 2005-12-29 12:18:26.000000000 +0100 -@@ -0,0 +1,90 @@ -+/* -+ * MIME functions for netfilter modules. This file provides implementations -+ * for basic MIME parsing. MIME headers are used in many protocols, such as -+ * HTTP, RTSP, SIP, etc. -+ * -+ * gcc will warn for defined but unused functions, so we only include the -+ * functions requested. The following macros are used: -+ * NF_NEED_MIME_NEXTLINE nf_mime_nextline() -+ */ -+#ifndef _NETFILTER_MIME_H -+#define _NETFILTER_MIME_H -+ -+/* Only include these functions for kernel code. */ -+#ifdef __KERNEL__ -+ -+#include -+#include -+ -+/* -+ * Given a buffer and length, advance to the next line and mark the current -+ * line. If the current line is empty, *plinelen will be set to zero. If -+ * not, it will be set to the actual line length (including CRLF). -+ * -+ * 'line' in this context means logical line (includes LWS continuations). -+ * Returns 1 on success, 0 on failure. -+ */ -+#ifdef NF_NEED_MIME_NEXTLINE -+static int -+nf_mime_nextline(char* p, uint len, uint* poff, uint* plineoff, uint* plinelen) -+{ -+ uint off = *poff; -+ uint physlen = 0; -+ int is_first_line = 1; -+ -+ if (off >= len) -+ { -+ return 0; -+ } -+ -+ do -+ { -+ while (p[off] != '\n') -+ { -+ if (len-off <= 1) -+ { -+ return 0; -+ } -+ -+ physlen++; -+ off++; -+ } -+ -+ /* if we saw a crlf, physlen needs adjusted */ -+ if (physlen > 0 && p[off] == '\n' && p[off-1] == '\r') -+ { -+ physlen--; -+ } -+ -+ /* advance past the newline */ -+ off++; -+ -+ /* check for an empty line */ -+ if (physlen == 0) -+ { -+ break; -+ } -+ -+ /* check for colon on the first physical line */ -+ if (is_first_line) -+ { -+ is_first_line = 0; -+ if (memchr(p+(*poff), ':', physlen) == NULL) -+ { -+ return 0; -+ } -+ } -+ } -+ while (p[off] == ' ' || p[off] == '\t'); -+ -+ *plineoff = *poff; -+ *plinelen = (physlen == 0) ? 0 : (off - *poff); -+ *poff = off; -+ -+ return 1; -+} -+#endif /* NF_NEED_MIME_NEXTLINE */ -+ -+#endif /* __KERNEL__ */ -+ -+#endif /* _NETFILTER_MIME_H */ -diff -urN linux-2.4.32.orig/net/ipv4/netfilter/Config.in linux-2.4.32/net/ipv4/netfilter/Config.in ---- linux-2.4.32.orig/net/ipv4/netfilter/Config.in 2005-12-29 12:17:55.000000000 +0100 -+++ linux-2.4.32/net/ipv4/netfilter/Config.in 2005-12-29 12:20:42.000000000 +0100 -@@ -18,6 +18,7 @@ - dep_tristate ' SIP protocol support' CONFIG_IP_NF_SIP $CONFIG_IP_NF_CONNTRACK - dep_tristate ' H.323 (netmeeting) support' CONFIG_IP_NF_H323 $CONFIG_IP_NF_CONNTRACK - dep_tristate ' MMS protocol support' CONFIG_IP_NF_MMS $CONFIG_IP_NF_CONNTRACK -+ dep_tristate ' RTSP protocol support' CONFIG_IP_NF_RTSP $CONFIG_IP_NF_CONNTRACK - fi - - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then -@@ -128,6 +129,13 @@ - define_tristate CONFIG_IP_NF_NAT_MMS $CONFIG_IP_NF_NAT - fi - fi -+ if [ "$CONFIG_IP_NF_RTSP" = "m" ]; then -+ define_tristate CONFIG_IP_NF_NAT_RTSP m -+ else -+ if [ "$CONFIG_IP_NF_RTSP" = "y" ]; then -+ define_tristate CONFIG_IP_NF_NAT_RTSP $CONFIG_IP_NF_NAT -+ fi -+ fi - if [ "$CONFIG_IP_NF_AMANDA" = "m" ]; then - define_tristate CONFIG_IP_NF_NAT_AMANDA m - else -diff -urN linux-2.4.32.orig/net/ipv4/netfilter/ip_conntrack_rtsp.c linux-2.4.32/net/ipv4/netfilter/ip_conntrack_rtsp.c ---- linux-2.4.32.orig/net/ipv4/netfilter/ip_conntrack_rtsp.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.32/net/ipv4/netfilter/ip_conntrack_rtsp.c 2005-12-29 12:18:26.000000000 +0100 -@@ -0,0 +1,507 @@ -+/* -+ * RTSP extension for IP connection tracking -+ * (C) 2003 by Tom Marshall -+ * based on ip_conntrack_irc.c -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version -+ * 2 of the License, or (at your option) any later version. -+ * -+ * Module load syntax: -+ * insmod ip_conntrack_rtsp.o ports=port1,port2,...port -+ * max_outstanding=n setup_timeout=secs -+ * -+ * If no ports are specified, the default will be port 554. -+ * -+ * With max_outstanding you can define the maximum number of not yet -+ * answered SETUP requests per RTSP session (default 8). -+ * With setup_timeout you can specify how long the system waits for -+ * an expected data channel (default 300 seconds). -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+#include -+#define NF_NEED_STRNCASECMP -+#define NF_NEED_STRTOU16 -+#define NF_NEED_STRTOU32 -+#define NF_NEED_NEXTLINE -+#include -+#define NF_NEED_MIME_NEXTLINE -+#include -+ -+#define MAX_SIMUL_SETUP 8 /* XXX: use max_outstanding */ -+ -+#define INFOP(fmt, args...) printk(KERN_INFO "%s: %s: " fmt, __FILE__, __FUNCTION__ , ## args) -+#ifdef IP_NF_RTSP_DEBUG -+#define DEBUGP(fmt, args...) printk(KERN_DEBUG "%s: %s: " fmt, __FILE__, __FUNCTION__ , ## args) -+#else -+#define DEBUGP(fmt, args...) -+#endif -+ -+#define MAX_PORTS 8 -+static int ports[MAX_PORTS]; -+static int num_ports = 0; -+static int max_outstanding = 8; -+static unsigned int setup_timeout = 300; -+ -+MODULE_AUTHOR("Tom Marshall "); -+MODULE_DESCRIPTION("RTSP connection tracking module"); -+MODULE_LICENSE("GPL"); -+#ifdef MODULE_PARM -+MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i"); -+MODULE_PARM_DESC(ports, "port numbers of RTSP servers"); -+MODULE_PARM(max_outstanding, "i"); -+MODULE_PARM_DESC(max_outstanding, "max number of outstanding SETUP requests per RTSP session"); -+MODULE_PARM(setup_timeout, "i"); -+MODULE_PARM_DESC(setup_timeout, "timeout on for unestablished data channels"); -+#endif -+ -+DECLARE_LOCK(ip_rtsp_lock); -+struct module* ip_conntrack_rtsp = THIS_MODULE; -+ -+/* -+ * Max mappings we will allow for one RTSP connection (for RTP, the number -+ * of allocated ports is twice this value). Note that SMIL burns a lot of -+ * ports so keep this reasonably high. If this is too low, you will see a -+ * lot of "no free client map entries" messages. -+ */ -+#define MAX_PORT_MAPS 16 -+ -+/*** default port list was here in the masq code: 554, 3030, 4040 ***/ -+ -+#define SKIP_WSPACE(ptr,len,off) while(off < len && isspace(*(ptr+off))) { off++; } -+ -+/* -+ * Parse an RTSP packet. -+ * -+ * Returns zero if parsing failed. -+ * -+ * Parameters: -+ * IN ptcp tcp data pointer -+ * IN tcplen tcp data len -+ * IN/OUT ptcpoff points to current tcp offset -+ * OUT phdrsoff set to offset of rtsp headers -+ * OUT phdrslen set to length of rtsp headers -+ * OUT pcseqoff set to offset of CSeq header -+ * OUT pcseqlen set to length of CSeq header -+ */ -+static int -+rtsp_parse_message(char* ptcp, uint tcplen, uint* ptcpoff, -+ uint* phdrsoff, uint* phdrslen, -+ uint* pcseqoff, uint* pcseqlen) -+{ -+ uint entitylen = 0; -+ uint lineoff; -+ uint linelen; -+ -+ if (!nf_nextline(ptcp, tcplen, ptcpoff, &lineoff, &linelen)) -+ { -+ return 0; -+ } -+ -+ *phdrsoff = *ptcpoff; -+ while (nf_mime_nextline(ptcp, tcplen, ptcpoff, &lineoff, &linelen)) -+ { -+ if (linelen == 0) -+ { -+ if (entitylen > 0) -+ { -+ *ptcpoff += min(entitylen, tcplen - *ptcpoff); -+ } -+ break; -+ } -+ if (lineoff+linelen > tcplen) -+ { -+ INFOP("!! overrun !!\n"); -+ break; -+ } -+ -+ if (nf_strncasecmp(ptcp+lineoff, "CSeq:", 5) == 0) -+ { -+ *pcseqoff = lineoff; -+ *pcseqlen = linelen; -+ } -+ if (nf_strncasecmp(ptcp+lineoff, "Content-Length:", 15) == 0) -+ { -+ uint off = lineoff+15; -+ SKIP_WSPACE(ptcp+lineoff, linelen, off); -+ nf_strtou32(ptcp+off, &entitylen); -+ } -+ } -+ *phdrslen = (*ptcpoff) - (*phdrsoff); -+ -+ return 1; -+} -+ -+/* -+ * Find lo/hi client ports (if any) in transport header -+ * In: -+ * ptcp, tcplen = packet -+ * tranoff, tranlen = buffer to search -+ * -+ * Out: -+ * pport_lo, pport_hi = lo/hi ports (host endian) -+ * -+ * Returns nonzero if any client ports found -+ * -+ * Note: it is valid (and expected) for the client to request multiple -+ * transports, so we need to parse the entire line. -+ */ -+static int -+rtsp_parse_transport(char* ptran, uint tranlen, -+ struct ip_ct_rtsp_expect* prtspexp) -+{ -+ int rc = 0; -+ uint off = 0; -+ -+ if (tranlen < 10 || !iseol(ptran[tranlen-1]) || -+ nf_strncasecmp(ptran, "Transport:", 10) != 0) -+ { -+ INFOP("sanity check failed\n"); -+ return 0; -+ } -+ DEBUGP("tran='%.*s'\n", (int)tranlen, ptran); -+ off += 10; -+ SKIP_WSPACE(ptran, tranlen, off); -+ -+ /* Transport: tran;field;field=val,tran;field;field=val,... */ -+ while (off < tranlen) -+ { -+ const char* pparamend; -+ uint nextparamoff; -+ -+ pparamend = memchr(ptran+off, ',', tranlen-off); -+ pparamend = (pparamend == NULL) ? ptran+tranlen : pparamend+1; -+ nextparamoff = pparamend-ptran; -+ -+ 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; -+ -+ off += 12; -+ numlen = nf_strtou16(ptran+off, &port); -+ off += numlen; -+ if (prtspexp->loport != 0 && prtspexp->loport != port) -+ { -+ DEBUGP("multiple ports found, port %hu ignored\n", port); -+ } -+ else -+ { -+ prtspexp->loport = prtspexp->hiport = port; -+ if (ptran[off] == '-') -+ { -+ off++; -+ numlen = nf_strtou16(ptran+off, &port); -+ off += numlen; -+ prtspexp->pbtype = pb_range; -+ prtspexp->hiport = port; -+ -+ // If we have a range, assume rtp: -+ // loport must be even, hiport must be loport+1 -+ if ((prtspexp->loport & 0x0001) != 0 || -+ prtspexp->hiport != prtspexp->loport+1) -+ { -+ DEBUGP("incorrect range: %hu-%hu, correcting\n", -+ prtspexp->loport, prtspexp->hiport); -+ prtspexp->loport &= 0xfffe; -+ prtspexp->hiport = prtspexp->loport+1; -+ } -+ } -+ else if (ptran[off] == '/') -+ { -+ off++; -+ numlen = nf_strtou16(ptran+off, &port); -+ off += numlen; -+ prtspexp->pbtype = pb_discon; -+ prtspexp->hiport = port; -+ } -+ rc = 1; -+ } -+ } -+ -+ /* -+ * Note we don't look for the destination parameter here. -+ * If we are using NAT, the NAT module will handle it. If not, -+ * and the client is sending packets elsewhere, the expectation -+ * will quietly time out. -+ */ -+ -+ off = nextfieldoff; -+ } -+ -+ off = nextparamoff; -+ } -+ -+ return rc; -+} -+ -+/*** conntrack functions ***/ -+ -+/* outbound packet: client->server */ -+static int -+help_out(const struct iphdr* iph, size_t pktlen, -+ struct ip_conntrack* ct, enum ip_conntrack_info ctinfo) -+{ -+ int dir = CTINFO2DIR(ctinfo); /* = IP_CT_DIR_ORIGINAL */ -+ struct tcphdr* tcph = (void*)iph + iph->ihl * 4; -+ uint tcplen = pktlen - iph->ihl * 4; -+ char* pdata = (char*)tcph + tcph->doff * 4; -+ uint datalen = tcplen - tcph->doff * 4; -+ uint dataoff = 0; -+ -+ struct ip_conntrack_expect exp; -+ -+ while (dataoff < datalen) -+ { -+ uint cmdoff = dataoff; -+ uint hdrsoff = 0; -+ uint hdrslen = 0; -+ uint cseqoff = 0; -+ uint cseqlen = 0; -+ uint lineoff = 0; -+ uint linelen = 0; -+ uint off; -+ int rc; -+ -+ if (!rtsp_parse_message(pdata, datalen, &dataoff, -+ &hdrsoff, &hdrslen, -+ &cseqoff, &cseqlen)) -+ { -+ break; /* not a valid message */ -+ } -+ -+ if (strncmp(pdata+cmdoff, "SETUP ", 6) != 0) -+ { -+ continue; /* not a SETUP message */ -+ } -+ DEBUGP("found a setup message\n"); -+ -+ memset(&exp, 0, sizeof(exp)); -+ -+ off = 0; -+ while (nf_mime_nextline(pdata+hdrsoff, hdrslen, &off, -+ &lineoff, &linelen)) -+ { -+ if (linelen == 0) -+ { -+ break; -+ } -+ if (off > hdrsoff+hdrslen) -+ { -+ INFOP("!! overrun !!"); -+ break; -+ } -+ -+ if (nf_strncasecmp(pdata+hdrsoff+lineoff, "Transport:", 10) == 0) -+ { -+ rtsp_parse_transport(pdata+hdrsoff+lineoff, linelen, -+ &exp.help.exp_rtsp_info); -+ } -+ } -+ -+ if (exp.help.exp_rtsp_info.loport == 0) -+ { -+ DEBUGP("no udp transports found\n"); -+ continue; /* no udp transports found */ -+ } -+ -+ DEBUGP("udp transport found, ports=(%d,%hu,%hu)\n", -+ (int)exp.help.exp_rtsp_info.pbtype, -+ exp.help.exp_rtsp_info.loport, -+ exp.help.exp_rtsp_info.hiport); -+ -+ LOCK_BH(&ip_rtsp_lock); -+ exp.seq = ntohl(tcph->seq) + hdrsoff; /* mark all the headers */ -+ exp.help.exp_rtsp_info.len = hdrslen; -+ -+ exp.tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip; -+ exp.mask.src.ip = 0xffffffff; -+ exp.tuple.dst.ip = ct->tuplehash[dir].tuple.src.ip; -+ exp.mask.dst.ip = 0xffffffff; -+ exp.tuple.dst.u.udp.port = exp.help.exp_rtsp_info.loport; -+ exp.mask.dst.u.udp.port = (exp.help.exp_rtsp_info.pbtype == pb_range) ? 0xfffe : 0xffff; -+ exp.tuple.dst.protonum = IPPROTO_UDP; -+ exp.mask.dst.protonum = 0xffff; -+ -+ DEBUGP("expect_related %u.%u.%u.%u:%u-%u.%u.%u.%u:%u\n", -+ NIPQUAD(exp.tuple.src.ip), -+ ntohs(exp.tuple.src.u.tcp.port), -+ NIPQUAD(exp.tuple.dst.ip), -+ ntohs(exp.tuple.dst.u.tcp.port)); -+ -+ /* pass the request off to the nat helper */ -+ rc = ip_conntrack_expect_related(ct, &exp); -+ UNLOCK_BH(&ip_rtsp_lock); -+ if (rc == 0) -+ { -+ DEBUGP("ip_conntrack_expect_related succeeded\n"); -+ } -+ else -+ { -+ INFOP("ip_conntrack_expect_related failed (%d)\n", rc); -+ } -+ } -+ -+ return NF_ACCEPT; -+} -+ -+/* inbound packet: server->client */ -+static int -+help_in(const struct iphdr* iph, size_t pktlen, -+ struct ip_conntrack* ct, enum ip_conntrack_info ctinfo) -+{ -+ return NF_ACCEPT; -+} -+ -+static int -+help(const struct iphdr* iph, size_t pktlen, -+ struct ip_conntrack* ct, enum ip_conntrack_info ctinfo) -+{ -+ /* tcplen not negative guarenteed by ip_conntrack_tcp.c */ -+ struct tcphdr* tcph = (void*)iph + iph->ihl * 4; -+ u_int32_t tcplen = pktlen - iph->ihl * 4; -+ -+ /* Until there's been traffic both ways, don't look in packets. */ -+ if (ctinfo != IP_CT_ESTABLISHED && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) -+ { -+ DEBUGP("conntrackinfo = %u\n", ctinfo); -+ return NF_ACCEPT; -+ } -+ -+ /* Not whole TCP header? */ -+ if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4) -+ { -+ DEBUGP("tcplen = %u\n", (unsigned)tcplen); -+ return NF_ACCEPT; -+ } -+ -+ /* Checksum invalid? Ignore. */ -+ /* FIXME: Source route IP option packets --RR */ -+ if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr, -+ csum_partial((char*)tcph, tcplen, 0))) -+ { -+ DEBUGP("bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n", -+ tcph, tcplen, NIPQUAD(iph->saddr), NIPQUAD(iph->daddr)); -+ return NF_ACCEPT; -+ } -+ -+ switch (CTINFO2DIR(ctinfo)) -+ { -+ case IP_CT_DIR_ORIGINAL: -+ help_out(iph, pktlen, ct, ctinfo); -+ break; -+ case IP_CT_DIR_REPLY: -+ help_in(iph, pktlen, ct, ctinfo); -+ break; -+ } -+ -+ return NF_ACCEPT; -+} -+ -+static struct ip_conntrack_helper rtsp_helpers[MAX_PORTS]; -+static char rtsp_names[MAX_PORTS][10]; -+ -+/* This function is intentionally _NOT_ defined as __exit */ -+static void -+fini(void) -+{ -+ int i; -+ for (i = 0; i < num_ports; i++) -+ { -+ DEBUGP("unregistering port %d\n", ports[i]); -+ ip_conntrack_helper_unregister(&rtsp_helpers[i]); -+ } -+} -+ -+static int __init -+init(void) -+{ -+ int i, ret; -+ struct ip_conntrack_helper *hlpr; -+ char *tmpname; -+ -+ printk("ip_conntrack_rtsp v" IP_NF_RTSP_VERSION " loading\n"); -+ -+ if (max_outstanding < 1) -+ { -+ printk("ip_conntrack_rtsp: max_outstanding must be a positive integer\n"); -+ return -EBUSY; -+ } -+ if (setup_timeout < 0) -+ { -+ printk("ip_conntrack_rtsp: setup_timeout must be a positive integer\n"); -+ return -EBUSY; -+ } -+ -+ /* If no port given, default to standard rtsp port */ -+ if (ports[0] == 0) -+ { -+ ports[0] = RTSP_PORT; -+ } -+ -+ for (i = 0; (i < MAX_PORTS) && ports[i]; i++) -+ { -+ hlpr = &rtsp_helpers[i]; -+ memset(hlpr, 0, sizeof(struct ip_conntrack_helper)); -+ 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 = 0xFFFF; -+ hlpr->max_expected = max_outstanding; -+ hlpr->timeout = setup_timeout; -+ hlpr->flags = IP_CT_HELPER_F_REUSE_EXPECT; -+ hlpr->me = ip_conntrack_rtsp; -+ hlpr->help = help; -+ -+ tmpname = &rtsp_names[i][0]; -+ if (ports[i] == RTSP_PORT) -+ { -+ sprintf(tmpname, "rtsp"); -+ } -+ else -+ { -+ sprintf(tmpname, "rtsp-%d", i); -+ } -+ hlpr->name = tmpname; -+ -+ DEBUGP("port #%d: %d\n", i, ports[i]); -+ -+ ret = ip_conntrack_helper_register(hlpr); -+ -+ if (ret) -+ { -+ printk("ip_conntrack_rtsp: ERROR registering port %d\n", ports[i]); -+ fini(); -+ return -EBUSY; -+ } -+ num_ports++; -+ } -+ return 0; -+} -+ -+#ifdef CONFIG_IP_NF_NAT_NEEDED -+EXPORT_SYMBOL(ip_rtsp_lock); -+#endif -+ -+module_init(init); -+module_exit(fini); -diff -urN linux-2.4.32.orig/net/ipv4/netfilter/ip_nat_rtsp.c linux-2.4.32/net/ipv4/netfilter/ip_nat_rtsp.c ---- linux-2.4.32.orig/net/ipv4/netfilter/ip_nat_rtsp.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.32/net/ipv4/netfilter/ip_nat_rtsp.c 2005-12-29 12:18:26.000000000 +0100 -@@ -0,0 +1,621 @@ -+/* -+ * RTSP extension for TCP NAT alteration -+ * (C) 2003 by Tom Marshall -+ * based on ip_nat_irc.c -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version -+ * 2 of the License, or (at your option) any later version. -+ * -+ * Module load syntax: -+ * insmod ip_nat_rtsp.o ports=port1,port2,...port -+ * stunaddr=
-+ * destaction=[auto|strip|none] -+ * -+ * If no ports are specified, the default will be port 554 only. -+ * -+ * stunaddr specifies the address used to detect that a client is using STUN. -+ * If this address is seen in the destination parameter, it is assumed that -+ * the client has already punched a UDP hole in the firewall, so we don't -+ * mangle the client_port. If none is specified, it is autodetected. It -+ * only needs to be set if you have multiple levels of NAT. It should be -+ * set to the external address that the STUN clients detect. Note that in -+ * this case, it will not be possible for clients to use UDP with servers -+ * between the NATs. -+ * -+ * If no destaction is specified, auto is used. -+ * destaction=auto: strip destination parameter if it is not stunaddr. -+ * destaction=strip: always strip destination parameter (not recommended). -+ * destaction=none: do not touch destination parameter (not recommended). -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#define NF_NEED_STRNCASECMP -+#define NF_NEED_STRTOU16 -+#include -+#define NF_NEED_MIME_NEXTLINE -+#include -+ -+#define INFOP(fmt, args...) printk(KERN_INFO "%s: %s: " fmt, __FILE__, __FUNCTION__ , ## args) -+#ifdef IP_NF_RTSP_DEBUG -+#define DEBUGP(fmt, args...) printk(KERN_DEBUG "%s: %s: " fmt, __FILE__, __FUNCTION__ , ## args) -+#else -+#define DEBUGP(fmt, args...) -+#endif -+ -+#define MAX_PORTS 8 -+#define DSTACT_AUTO 0 -+#define DSTACT_STRIP 1 -+#define DSTACT_NONE 2 -+ -+static int ports[MAX_PORTS]; -+static char* stunaddr = NULL; -+static char* destaction = NULL; -+ -+static int num_ports = 0; -+static u_int32_t extip = 0; -+static int dstact = 0; -+ -+MODULE_AUTHOR("Tom Marshall "); -+MODULE_DESCRIPTION("RTSP network address translation module"); -+MODULE_LICENSE("GPL"); -+#ifdef MODULE_PARM -+MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i"); -+MODULE_PARM_DESC(ports, "port numbers of RTSP servers"); -+MODULE_PARM(stunaddr, "s"); -+MODULE_PARM_DESC(stunaddr, "Address for detecting STUN"); -+MODULE_PARM(destaction, "s"); -+MODULE_PARM_DESC(destaction, "Action for destination parameter (auto/strip/none)"); -+#endif -+ -+/* protects rtsp part of conntracks */ -+DECLARE_LOCK_EXTERN(ip_rtsp_lock); -+ -+#define SKIP_WSPACE(ptr,len,off) while(off < len && isspace(*(ptr+off))) { off++; } -+ -+/*** helper functions ***/ -+ -+static void -+get_skb_tcpdata(struct sk_buff* skb, char** pptcpdata, uint* ptcpdatalen) -+{ -+ struct iphdr* iph = (struct iphdr*)skb->nh.iph; -+ struct tcphdr* tcph = (struct tcphdr*)((char*)iph + iph->ihl*4); -+ -+ *pptcpdata = (char*)tcph + tcph->doff*4; -+ *ptcpdatalen = ((char*)skb->h.raw + skb->len) - *pptcpdata; -+} -+ -+/*** nat functions ***/ -+ -+/* -+ * Mangle the "Transport:" header: -+ * - Replace all occurences of "client_port=" -+ * - Handle destination parameter -+ * -+ * In: -+ * ct, ctinfo = conntrack context -+ * pskb = packet -+ * tranoff = Transport header offset from TCP data -+ * tranlen = Transport header length (incl. CRLF) -+ * rport_lo = replacement low port (host endian) -+ * rport_hi = replacement high port (host endian) -+ * -+ * Returns packet size difference. -+ * -+ * Assumes that a complete transport header is present, ending with CR or LF -+ */ -+static int -+rtsp_mangle_tran(struct ip_conntrack* ct, enum ip_conntrack_info ctinfo, -+ struct ip_conntrack_expect* exp, -+ struct sk_buff** pskb, 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 ip_ct_rtsp_expect* prtspexp = &exp->help.exp_rtsp_info; -+ struct ip_conntrack_tuple t; -+ -+ char szextaddr[15+1]; -+ uint extaddrlen; -+ int is_stun; -+ -+ get_skb_tcpdata(*pskb, &ptcp, &tcplen); -+ ptran = ptcp+tranoff; -+ -+ if (tranoff+tranlen > tcplen || tcplen-tranoff < tranlen || -+ tranlen < 10 || !iseol(ptran[tranlen-1]) || -+ nf_strncasecmp(ptran, "Transport:", 10) != 0) -+ { -+ INFOP("sanity check failed\n"); -+ return 0; -+ } -+ off += 10; -+ SKIP_WSPACE(ptcp+tranoff, tranlen, off); -+ -+ newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; -+ t = exp->tuple; -+ t.dst.ip = newip; -+ -+ extaddrlen = extip ? sprintf(szextaddr, "%u.%u.%u.%u", NIPQUAD(extip)) -+ : sprintf(szextaddr, "%u.%u.%u.%u", NIPQUAD(newip)); -+ DEBUGP("stunaddr=%s (%s)\n", szextaddr, (extip?"forced":"auto")); -+ -+ rbuf1len = rbufalen = 0; -+ switch (prtspexp->pbtype) -+ { -+ case pb_single: -+ for (loport = prtspexp->loport; loport != 0; loport++) /* XXX: improper wrap? */ -+ { -+ t.dst.u.udp.port = htons(loport); -+ if (ip_conntrack_change_expect(exp, &t) == 0) -+ { -+ DEBUGP("using port %hu\n", loport); -+ break; -+ } -+ } -+ if (loport != 0) -+ { -+ rbuf1len = sprintf(rbuf1, "%hu", loport); -+ rbufalen = sprintf(rbufa, "%hu", loport); -+ } -+ break; -+ case pb_range: -+ for (loport = prtspexp->loport; loport != 0; loport += 2) /* XXX: improper wrap? */ -+ { -+ t.dst.u.udp.port = htons(loport); -+ if (ip_conntrack_change_expect(exp, &t) == 0) -+ { -+ hiport = loport + ~exp->mask.dst.u.udp.port; -+ DEBUGP("using ports %hu-%hu\n", loport, hiport); -+ break; -+ } -+ } -+ if (loport != 0) -+ { -+ rbuf1len = sprintf(rbuf1, "%hu", loport); -+ rbufalen = sprintf(rbufa, "%hu-%hu", loport, loport+1); -+ } -+ break; -+ case pb_discon: -+ for (loport = prtspexp->loport; loport != 0; loport++) /* XXX: improper wrap? */ -+ { -+ t.dst.u.udp.port = htons(loport); -+ if (ip_conntrack_change_expect(exp, &t) == 0) -+ { -+ DEBUGP("using port %hu (1 of 2)\n", loport); -+ break; -+ } -+ } -+ for (hiport = prtspexp->hiport; hiport != 0; hiport++) /* XXX: improper wrap? */ -+ { -+ t.dst.u.udp.port = htons(hiport); -+ if (ip_conntrack_change_expect(exp, &t) == 0) -+ { -+ DEBUGP("using port %hu (2 of 2)\n", hiport); -+ break; -+ } -+ } -+ if (loport != 0 && hiport != 0) -+ { -+ rbuf1len = sprintf(rbuf1, "%hu", loport); -+ if (hiport == loport+1) -+ { -+ rbufalen = sprintf(rbufa, "%hu-%hu", loport, hiport); -+ } -+ else -+ { -+ rbufalen = sprintf(rbufa, "%hu/%hu", loport, hiport); -+ } -+ } -+ break; -+ } -+ -+ if (rbuf1len == 0) -+ { -+ return 0; /* cannot get replacement port(s) */ -+ } -+ -+ /* Transport: tran;field;field=val,tran;field;field=val,... */ -+ while (off < tranlen) -+ { -+ uint saveoff; -+ const char* pparamend; -+ uint nextparamoff; -+ -+ pparamend = memchr(ptran+off, ',', tranlen-off); -+ pparamend = (pparamend == NULL) ? ptran+tranlen : pparamend+1; -+ nextparamoff = pparamend-ptcp; -+ -+ /* -+ * We pass over each param twice. On the first pass, we look for a -+ * destination= field. It is handled by the security policy. If it -+ * is present, allowed, and equal to our external address, we assume -+ * that STUN is being used and we leave the client_port= field alone. -+ */ -+ is_stun = 0; -+ saveoff = off; -+ while (off < nextparamoff) -+ { -+ const char* pfieldend; -+ uint nextfieldoff; -+ -+ pfieldend = memchr(ptran+off, ';', nextparamoff-off); -+ nextfieldoff = (pfieldend == NULL) ? nextparamoff : pfieldend-ptran+1; -+ -+ if (dstact != DSTACT_NONE && strncmp(ptran+off, "destination=", 12) == 0) -+ { -+ if (strncmp(ptran+off+12, szextaddr, extaddrlen) == 0) -+ { -+ is_stun = 1; -+ } -+ if (dstact == DSTACT_STRIP || (dstact == DSTACT_AUTO && !is_stun)) -+ { -+ diff = nextfieldoff-off; -+ if (!ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, -+ off, diff, NULL, 0)) -+ { -+ /* mangle failed, all we can do is bail */ -+ return 0; -+ } -+ get_skb_tcpdata(*pskb, &ptcp, &tcplen); -+ ptran = ptcp+tranoff; -+ tranlen -= diff; -+ nextparamoff -= diff; -+ nextfieldoff -= diff; -+ } -+ } -+ -+ off = nextfieldoff; -+ } -+ if (is_stun) -+ { -+ continue; -+ } -+ off = saveoff; -+ while (off < nextparamoff) -+ { -+ const char* pfieldend; -+ uint nextfieldoff; -+ -+ pfieldend = memchr(ptran+off, ';', nextparamoff-off); -+ nextfieldoff = (pfieldend == NULL) ? nextparamoff : pfieldend-ptran+1; -+ -+ if (strncmp(ptran+off, "client_port=", 12) == 0) -+ { -+ u_int16_t port; -+ uint numlen; -+ uint origoff; -+ uint origlen; -+ char* rbuf = rbuf1; -+ uint rbuflen = rbuf1len; -+ -+ off += 12; -+ origoff = (ptran-ptcp)+off; -+ origlen = 0; -+ numlen = nf_strtou16(ptran+off, &port); -+ off += numlen; -+ origlen += numlen; -+ if (port != prtspexp->loport) -+ { -+ DEBUGP("multiple ports found, port %hu ignored\n", port); -+ } -+ else -+ { -+ if (ptran[off] == '-' || ptran[off] == '/') -+ { -+ off++; -+ origlen++; -+ numlen = nf_strtou16(ptran+off, &port); -+ off += numlen; -+ origlen += numlen; -+ rbuf = rbufa; -+ rbuflen = rbufalen; -+ } -+ -+ /* -+ * note we cannot just memcpy() if the sizes are the same. -+ * the mangle function does skb resizing, checks for a -+ * cloned skb, and updates the checksums. -+ * -+ * parameter 4 below is offset from start of tcp data. -+ */ -+ diff = origlen-rbuflen; -+ if (!ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, -+ origoff, origlen, rbuf, rbuflen)) -+ { -+ /* mangle failed, all we can do is bail */ -+ return 0; -+ } -+ get_skb_tcpdata(*pskb, &ptcp, &tcplen); -+ ptran = ptcp+tranoff; -+ tranlen -= diff; -+ nextparamoff -= diff; -+ nextfieldoff -= diff; -+ } -+ } -+ -+ off = nextfieldoff; -+ } -+ -+ off = nextparamoff; -+ } -+ -+ return 1; -+} -+ -+static unsigned int -+expected(struct sk_buff **pskb, uint hooknum, struct ip_conntrack* ct, struct ip_nat_info* info) -+{ -+ struct ip_nat_multi_range mr; -+ u_int32_t newdstip, newsrcip, newip; -+ -+ struct ip_conntrack *master = master_ct(ct); -+ -+ IP_NF_ASSERT(info); -+ IP_NF_ASSERT(master); -+ -+ IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum)))); -+ -+ newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; -+ newsrcip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; -+ newip = (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC) ? newsrcip : newdstip; -+ -+ DEBUGP("newsrcip=%u.%u.%u.%u, newdstip=%u.%u.%u.%u, newip=%u.%u.%u.%u\n", -+ NIPQUAD(newsrcip), NIPQUAD(newdstip), NIPQUAD(newip)); -+ -+ mr.rangesize = 1; -+ /* We don't want to manip the per-protocol, just the IPs. */ -+ mr.range[0].flags = IP_NAT_RANGE_MAP_IPS; -+ mr.range[0].min_ip = mr.range[0].max_ip = newip; -+ -+ return ip_nat_setup_info(ct, &mr, hooknum); -+} -+ -+static uint -+help_out(struct ip_conntrack* ct, enum ip_conntrack_info ctinfo, -+ struct ip_conntrack_expect* exp, struct sk_buff** pskb) -+{ -+ 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); -+ -+ struct ip_ct_rtsp_expect* prtspexp = &exp->help.exp_rtsp_info; -+ -+ get_skb_tcpdata(*pskb, &ptcp, &tcplen); -+ -+ hdrsoff = exp->seq - ntohl(tcph->seq); -+ hdrslen = prtspexp->len; -+ off = hdrsoff; -+ -+ while (nf_mime_nextline(ptcp, hdrsoff+hdrslen, &off, &lineoff, &linelen)) -+ { -+ if (linelen == 0) -+ { -+ break; -+ } -+ if (off > hdrsoff+hdrslen) -+ { -+ INFOP("!! overrun !!"); -+ break; -+ } -+ DEBUGP("hdr: len=%u, %.*s", linelen, (int)linelen, ptcp+lineoff); -+ -+ if (nf_strncasecmp(ptcp+lineoff, "Transport:", 10) == 0) -+ { -+ uint oldtcplen = tcplen; -+ if (!rtsp_mangle_tran(ct, ctinfo, exp, pskb, lineoff, linelen)) -+ { -+ break; -+ } -+ get_skb_tcpdata(*pskb, &ptcp, &tcplen); -+ hdrslen -= (oldtcplen-tcplen); -+ off -= (oldtcplen-tcplen); -+ lineoff -= (oldtcplen-tcplen); -+ linelen -= (oldtcplen-tcplen); -+ DEBUGP("rep: len=%u, %.*s", linelen, (int)linelen, ptcp+lineoff); -+ } -+ } -+ -+ return NF_ACCEPT; -+} -+ -+static uint -+help_in(struct ip_conntrack* ct, enum ip_conntrack_info ctinfo, -+ struct ip_conntrack_expect* exp, struct sk_buff** pskb) -+{ -+ /* XXX: unmangle */ -+ return NF_ACCEPT; -+} -+ -+static uint -+help(struct ip_conntrack* ct, -+ struct ip_conntrack_expect* exp, -+ struct ip_nat_info* info, -+ enum ip_conntrack_info ctinfo, -+ unsigned int hooknum, -+ struct sk_buff** pskb) -+{ -+ struct iphdr* iph = (struct iphdr*)(*pskb)->nh.iph; -+ struct tcphdr* tcph = (struct tcphdr*)((char*)iph + iph->ihl * 4); -+ uint datalen; -+ int dir; -+ struct ip_ct_rtsp_expect* ct_rtsp_info; -+ int rc = NF_ACCEPT; -+ -+ if (ct == NULL || exp == NULL || info == NULL || pskb == NULL) -+ { -+ DEBUGP("!! null ptr (%p,%p,%p,%p) !!\n", ct, exp, info, pskb); -+ return NF_ACCEPT; -+ } -+ -+ ct_rtsp_info = &exp->help.exp_rtsp_info; -+ -+ /* -+ * Only mangle things once: original direction in POST_ROUTING -+ * and reply direction on PRE_ROUTING. -+ */ -+ dir = CTINFO2DIR(ctinfo); -+ if (!((hooknum == NF_IP_POST_ROUTING && dir == IP_CT_DIR_ORIGINAL) -+ || (hooknum == NF_IP_PRE_ROUTING && dir == IP_CT_DIR_REPLY))) -+ { -+ DEBUGP("Not touching dir %s at hook %s\n", -+ dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY", -+ hooknum == NF_IP_POST_ROUTING ? "POSTROUTING" -+ : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING" -+ : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???"); -+ return NF_ACCEPT; -+ } -+ DEBUGP("got beyond not touching\n"); -+ -+ datalen = (*pskb)->len - iph->ihl * 4 - tcph->doff * 4; -+ -+ LOCK_BH(&ip_rtsp_lock); -+ /* Ensure the packet contains all of the marked data */ -+ if (!between(exp->seq + ct_rtsp_info->len, -+ ntohl(tcph->seq), ntohl(tcph->seq) + datalen)) -+ { -+ /* Partial retransmission? Probably a hacker. */ -+ if (net_ratelimit()) -+ { -+ INFOP("partial packet %u/%u in %u/%u\n", -+ exp->seq, ct_rtsp_info->len, ntohl(tcph->seq), ntohl(tcph->seq) + datalen); -+ } -+ UNLOCK_BH(&ip_rtsp_lock); -+ return NF_DROP; -+ } -+ -+ switch (dir) -+ { -+ case IP_CT_DIR_ORIGINAL: -+ rc = help_out(ct, ctinfo, exp, pskb); -+ break; -+ case IP_CT_DIR_REPLY: -+ rc = help_in(ct, ctinfo, exp, pskb); -+ break; -+ } -+ UNLOCK_BH(&ip_rtsp_lock); -+ -+ return rc; -+} -+ -+static struct ip_nat_helper ip_nat_rtsp_helpers[MAX_PORTS]; -+static char rtsp_names[MAX_PORTS][10]; -+ -+/* This function is intentionally _NOT_ defined as __exit */ -+static void -+fini(void) -+{ -+ int i; -+ -+ for (i = 0; i < num_ports; i++) -+ { -+ DEBUGP("unregistering helper for port %d\n", ports[i]); -+ ip_nat_helper_unregister(&ip_nat_rtsp_helpers[i]); -+ } -+} -+ -+static int __init -+init(void) -+{ -+ int ret = 0; -+ int i; -+ struct ip_nat_helper* hlpr; -+ char* tmpname; -+ -+ printk("ip_nat_rtsp v" IP_NF_RTSP_VERSION " loading\n"); -+ -+ if (ports[0] == 0) -+ { -+ ports[0] = RTSP_PORT; -+ } -+ -+ for (i = 0; (i < MAX_PORTS) && ports[i] != 0; i++) -+ { -+ hlpr = &ip_nat_rtsp_helpers[i]; -+ memset(hlpr, 0, sizeof(struct ip_nat_helper)); -+ -+ hlpr->tuple.dst.protonum = IPPROTO_TCP; -+ hlpr->tuple.src.u.tcp.port = htons(ports[i]); -+ hlpr->mask.src.u.tcp.port = 0xFFFF; -+ hlpr->mask.dst.protonum = 0xFFFF; -+ hlpr->help = help; -+ hlpr->flags = 0; -+ hlpr->me = THIS_MODULE; -+ hlpr->expect = expected; -+ -+ tmpname = &rtsp_names[i][0]; -+ if (ports[i] == RTSP_PORT) -+ { -+ sprintf(tmpname, "rtsp"); -+ } -+ else -+ { -+ sprintf(tmpname, "rtsp-%d", i); -+ } -+ hlpr->name = tmpname; -+ -+ DEBUGP("registering helper for port %d: name %s\n", ports[i], hlpr->name); -+ ret = ip_nat_helper_register(hlpr); -+ -+ if (ret) -+ { -+ printk("ip_nat_rtsp: error registering helper for port %d\n", ports[i]); -+ fini(); -+ return 1; -+ } -+ num_ports++; -+ } -+ if (stunaddr != NULL) -+ { -+ extip = in_aton(stunaddr); -+ } -+ if (destaction != NULL) -+ { -+ if (strcmp(destaction, "auto") == 0) -+ { -+ dstact = DSTACT_AUTO; -+ } -+ if (strcmp(destaction, "strip") == 0) -+ { -+ dstact = DSTACT_STRIP; -+ } -+ if (strcmp(destaction, "none") == 0) -+ { -+ dstact = DSTACT_NONE; -+ } -+ } -+ return ret; -+} -+ -+module_init(init); -+module_exit(fini); -diff -urN linux-2.4.32.orig/net/ipv4/netfilter/Makefile linux-2.4.32/net/ipv4/netfilter/Makefile ---- linux-2.4.32.orig/net/ipv4/netfilter/Makefile 2005-12-29 12:17:55.000000000 +0100 -+++ linux-2.4.32/net/ipv4/netfilter/Makefile 2005-12-29 12:18:26.000000000 +0100 -@@ -32,6 +32,14 @@ - obj-$(CONFIG_IP_NF_CONNTRACK) += ip_conntrack.o - - # connection tracking helpers -+ -+# rtsp protocol support -+obj-$(CONFIG_IP_NF_RTSP) += ip_conntrack_rtsp.o -+ifdef CONFIG_IP_NF_NAT_RTSP -+ export-objs += ip_conntrack_rtsp.o -+endif -+obj-$(CONFIG_IP_NF_NAT_RTSP) += ip_nat_rtsp.o -+ - obj-$(CONFIG_IP_NF_AMANDA) += ip_conntrack_amanda.o - ifdef CONFIG_IP_NF_AMANDA - export-objs += ip_conntrack_amanda.o diff --git a/openwrt/target/linux/generic-2.4/patches/617-netfilter_time.patch b/openwrt/target/linux/generic-2.4/patches/617-netfilter_time.patch new file mode 100644 index 0000000000..3593571b46 --- /dev/null +++ b/openwrt/target/linux/generic-2.4/patches/617-netfilter_time.patch @@ -0,0 +1,238 @@ +diff -urN linux-2.4.32.orig/net/ipv4/netfilter/Config.in linux-2.4.32/net/ipv4/netfilter/Config.in +--- linux-2.4.32.orig/net/ipv4/netfilter/Config.in 2006-01-07 12:11:37.000000000 +0100 ++++ linux-2.4.32/net/ipv4/netfilter/Config.in 2006-01-07 12:15:45.000000000 +0100 +@@ -48,6 +48,7 @@ + dep_tristate ' netfilter MARK match support' CONFIG_IP_NF_MATCH_MARK $CONFIG_IP_NF_IPTABLES + dep_tristate ' Multiple port match support' CONFIG_IP_NF_MATCH_MULTIPORT $CONFIG_IP_NF_IPTABLES + dep_tristate ' TOS match support' CONFIG_IP_NF_MATCH_TOS $CONFIG_IP_NF_IPTABLES ++ dep_tristate ' TIME match support (EXPERIMENTAL)' CONFIG_IP_NF_MATCH_TIME $CONFIG_IP_NF_IPTABLES + dep_tristate ' condition match support' CONFIG_IP_NF_MATCH_CONDITION $CONFIG_IP_NF_IPTABLES + dep_tristate ' recent match support' CONFIG_IP_NF_MATCH_RECENT $CONFIG_IP_NF_IPTABLES + dep_tristate ' ECN match support' CONFIG_IP_NF_MATCH_ECN $CONFIG_IP_NF_IPTABLES +diff -urN linux-2.4.32.orig/net/ipv4/netfilter/ipt_time.c linux-2.4.32/net/ipv4/netfilter/ipt_time.c +--- linux-2.4.32.orig/net/ipv4/netfilter/ipt_time.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.32/net/ipv4/netfilter/ipt_time.c 2006-01-07 12:14:32.000000000 +0100 +@@ -0,0 +1,193 @@ ++/* ++ This is a module which is used for time matching ++ It is using some modified code from dietlibc (localtime() function) ++ that you can find at http://www.fefe.de/dietlibc/ ++ This file is distributed under the terms of the GNU General Public ++ License (GPL). Copies of the GPL can be obtained from: ftp://prep.ai.mit.edu/pub/gnu/GPL ++ 2001-05-04 Fabrice MARIE : initial development. ++ 2001-21-05 Fabrice MARIE : bug fix in the match code, ++ thanks to "Zeng Yu" for bug report. ++ 2001-26-09 Fabrice MARIE : force the match to be in LOCAL_IN or PRE_ROUTING only. ++ 2001-30-11 Fabrice : added the possibility to use the match in FORWARD/OUTPUT with a little hack, ++ added Nguyen Dang Phuoc Dong patch to support timezones. ++ 2004-05-02 Fabrice : added support for date matching, from an idea of Fabien COELHO. ++*/ ++ ++#include ++#include ++#include ++#include ++#include ++ ++MODULE_AUTHOR("Fabrice MARIE "); ++MODULE_DESCRIPTION("Match arrival timestamp/date"); ++MODULE_LICENSE("GPL"); ++ ++struct tm ++{ ++ int tm_sec; /* Seconds. [0-60] (1 leap second) */ ++ int tm_min; /* Minutes. [0-59] */ ++ int tm_hour; /* Hours. [0-23] */ ++ int tm_mday; /* Day. [1-31] */ ++ int tm_mon; /* Month. [0-11] */ ++ int tm_year; /* Year - 1900. */ ++ int tm_wday; /* Day of week. [0-6] */ ++ int tm_yday; /* Days in year.[0-365] */ ++ int tm_isdst; /* DST. [-1/0/1]*/ ++ ++ long int tm_gmtoff; /* we don't care, we count from GMT */ ++ const char *tm_zone; /* we don't care, we count from GMT */ ++}; ++ ++void ++localtime(const time_t *timepr, struct tm *r); ++ ++static int ++match(const struct sk_buff *skb, ++ const struct net_device *in, ++ const struct net_device *out, ++ const void *matchinfo, ++ int offset, ++ const void *hdr, ++ u_int16_t datalen, ++ int *hotdrop) ++{ ++ const struct ipt_time_info *info = matchinfo; /* match info for rule */ ++ struct tm currenttime; /* time human readable */ ++ u_int8_t days_of_week[7] = {64, 32, 16, 8, 4, 2, 1}; ++ u_int16_t packet_time; ++ struct timeval kerneltimeval; ++ time_t packet_local_time; ++ ++ /* if kerneltime=1, we don't read the skb->timestamp but kernel time instead */ ++ if (info->kerneltime) ++ { ++ do_gettimeofday(&kerneltimeval); ++ packet_local_time = kerneltimeval.tv_sec; ++ } ++ else ++ packet_local_time = skb->stamp.tv_sec; ++ ++ /* First we make sure we are in the date start-stop boundaries */ ++ if ((packet_local_time < info->date_start) || (packet_local_time > info->date_stop)) ++ return 0; /* We are outside the date boundaries */ ++ ++ /* Transform the timestamp of the packet, in a human readable form */ ++ localtime(&packet_local_time, ¤ttime); ++ ++ /* check if we match this timestamp, we start by the days... */ ++ if ((days_of_week[currenttime.tm_wday] & info->days_match) != days_of_week[currenttime.tm_wday]) ++ return 0; /* the day doesn't match */ ++ ++ /* ... check the time now */ ++ packet_time = (currenttime.tm_hour * 60) + currenttime.tm_min; ++ if ((packet_time < info->time_start) || (packet_time > info->time_stop)) ++ return 0; ++ ++ /* here we match ! */ ++ return 1; ++} ++ ++static int ++checkentry(const char *tablename, ++ const struct ipt_ip *ip, ++ void *matchinfo, ++ unsigned int matchsize, ++ unsigned int hook_mask) ++{ ++ struct ipt_time_info *info = matchinfo; /* match info for rule */ ++ ++ /* First, check that we are in the correct hooks */ ++ if (hook_mask ++ & ~((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_IN) | (1 << NF_IP_FORWARD) | (1 << NF_IP_LOCAL_OUT))) ++ { ++ printk("ipt_time: error, only valid for PRE_ROUTING, LOCAL_IN, FORWARD and OUTPUT)\n"); ++ return 0; ++ } ++ /* we use the kerneltime if we are in forward or output */ ++ info->kerneltime = 1; ++ if (hook_mask & ~((1 << NF_IP_FORWARD) | (1 << NF_IP_LOCAL_OUT))) ++ /* we use the skb time */ ++ info->kerneltime = 0; ++ ++ /* Check the size */ ++ if (matchsize != IPT_ALIGN(sizeof(struct ipt_time_info))) ++ return 0; ++ /* Now check the coherence of the data ... */ ++ if ((info->time_start > 1439) || /* 23*60+59 = 1439*/ ++ (info->time_stop > 1439)) ++ { ++ printk(KERN_WARNING "ipt_time: invalid argument\n"); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++static struct ipt_match time_match = { ++ .name = "time", ++ .match = match, ++ .checkentry = checkentry, ++ .me = THIS_MODULE, ++}; ++ ++static int __init init(void) ++{ ++ printk("ipt_time loading\n"); ++ return ipt_register_match(&time_match); ++} ++ ++static void __exit fini(void) ++{ ++ ipt_unregister_match(&time_match); ++ printk("ipt_time unloaded\n"); ++} ++ ++module_init(init); ++module_exit(fini); ++ ++ ++/* The part below is borowed and modified from dietlibc */ ++ ++/* seconds per day */ ++#define SPD 24*60*60 ++ ++void ++localtime(const time_t *timepr, struct tm *r) { ++ time_t i; ++ time_t timep; ++ extern struct timezone sys_tz; ++ const unsigned int __spm[12] = ++ { 0, ++ (31), ++ (31+28), ++ (31+28+31), ++ (31+28+31+30), ++ (31+28+31+30+31), ++ (31+28+31+30+31+30), ++ (31+28+31+30+31+30+31), ++ (31+28+31+30+31+30+31+31), ++ (31+28+31+30+31+30+31+31+30), ++ (31+28+31+30+31+30+31+31+30+31), ++ (31+28+31+30+31+30+31+31+30+31+30), ++ }; ++ register time_t work; ++ ++ timep = (*timepr) - (sys_tz.tz_minuteswest * 60); ++ work=timep%(SPD); ++ r->tm_sec=work%60; work/=60; ++ r->tm_min=work%60; r->tm_hour=work/60; ++ work=timep/(SPD); ++ r->tm_wday=(4+work)%7; ++ for (i=1970; ; ++i) { ++ register time_t k= (!(i%4) && ((i%100) || !(i%400)))?366:365; ++ if (work>k) ++ work-=k; ++ else ++ break; ++ } ++ r->tm_year=i-1900; ++ for (i=11; i && __spm[i]>work; --i) ; ++ r->tm_mon=i; ++ r->tm_mday=work-__spm[i]+1; ++} +diff -urN linux-2.4.32.orig/net/ipv4/netfilter/Makefile linux-2.4.32/net/ipv4/netfilter/Makefile +--- linux-2.4.32.orig/net/ipv4/netfilter/Makefile 2006-01-07 12:11:37.000000000 +0100 ++++ linux-2.4.32/net/ipv4/netfilter/Makefile 2006-01-07 12:16:07.000000000 +0100 +@@ -118,6 +118,7 @@ + obj-$(CONFIG_IP_NF_MATCH_MULTIPORT) += ipt_multiport.o + obj-$(CONFIG_IP_NF_MATCH_OWNER) += ipt_owner.o + obj-$(CONFIG_IP_NF_MATCH_TOS) += ipt_tos.o ++obj-$(CONFIG_IP_NF_MATCH_TIME) += ipt_time.o + obj-$(CONFIG_IP_NF_MATCH_CONDITION) += ipt_condition.o + + obj-$(CONFIG_IP_NF_MATCH_RECENT) += ipt_recent.o +diff -urN linux-2.4.32.orig/include/linux/netfilter_ipv4/ipt_time.h linux-2.4.32/include/linux/netfilter_ipv4/ipt_time.h +--- linux-2.4.32.orig/include/linux/netfilter_ipv4/ipt_time.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.32/include/linux/netfilter_ipv4/ipt_time.h 2006-01-07 12:16:42.000000000 +0100 +@@ -0,0 +1,15 @@ ++#ifndef __ipt_time_h_included__ ++#define __ipt_time_h_included__ ++ ++ ++struct ipt_time_info { ++ u_int8_t days_match; /* 1 bit per day. -SMTWTFS */ ++ u_int16_t time_start; /* 0 < time_start < 23*60+59 = 1439 */ ++ u_int16_t time_stop; /* 0:0 < time_stat < 23:59 */ ++ u_int8_t kerneltime; /* ignore skb time (and use kerneltime) or not. */ ++ time_t date_start; ++ time_t date_stop; ++}; ++ ++ ++#endif /* __ipt_time_h_included__ */ diff --git a/openwrt/target/linux/generic-2.4/patches/618-netfilter_multiport_backport.patch b/openwrt/target/linux/generic-2.4/patches/618-netfilter_multiport_backport.patch new file mode 100644 index 0000000000..c34f9ecbb7 --- /dev/null +++ b/openwrt/target/linux/generic-2.4/patches/618-netfilter_multiport_backport.patch @@ -0,0 +1,231 @@ +diff -urN linux.old/include/linux/netfilter_ipv4/ipt_multiport.h linux.dev/include/linux/netfilter_ipv4/ipt_multiport.h +--- linux.old/include/linux/netfilter_ipv4/ipt_multiport.h 2000-12-11 22:31:30.000000000 +0100 ++++ linux.dev/include/linux/netfilter_ipv4/ipt_multiport.h 2006-02-04 05:23:54.318518250 +0100 +@@ -11,11 +11,12 @@ + + #define IPT_MULTI_PORTS 15 + +-/* Must fit inside union ipt_matchinfo: 16 bytes */ +-struct ipt_multiport ++struct ipt_multiport_v1 + { + u_int8_t flags; /* Type of comparison */ + u_int8_t count; /* Number of ports */ + u_int16_t ports[IPT_MULTI_PORTS]; /* Ports */ ++ u_int8_t pflags[IPT_MULTI_PORTS]; /* Port flags */ ++ u_int8_t invert; /* Invert flag */ + }; + #endif /*_IPT_MULTIPORT_H*/ +diff -urN linux.old/net/ipv4/netfilter/ipt_multiport.c linux.dev/net/ipv4/netfilter/ipt_multiport.c +--- linux.old/net/ipv4/netfilter/ipt_multiport.c 2003-06-13 16:51:39.000000000 +0200 ++++ linux.dev/net/ipv4/netfilter/ipt_multiport.c 2006-02-04 05:34:27.362081000 +0100 +@@ -1,5 +1,14 @@ + /* Kernel module to match one of a list of TCP/UDP ports: ports are in + the same place so we can treat them as equal. */ ++ ++/* (C) 1999-2001 Paul `Rusty' Russell ++ * (C) 2002-2004 Netfilter Core Team ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++ + #include + #include + #include +@@ -8,97 +17,136 @@ + #include + #include + ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Netfilter Core Team "); ++MODULE_DESCRIPTION("iptables multiple port match module"); ++ + #if 0 + #define duprintf(format, args...) printk(format , ## args) + #else + #define duprintf(format, args...) + #endif + ++/* from linux 2.6 skbuff.h */ ++static inline void *skb_header_pointer(const struct sk_buff *skb, int offset, ++ int len, void *buffer) ++{ ++ int hlen = skb_headlen(skb); ++ ++ if (hlen - offset >= len) ++ return skb->data + offset; ++ ++ if (skb_copy_bits(skb, offset, buffer, len) < 0) ++ return NULL; ++ ++ return buffer; ++} ++ ++ + /* Returns 1 if the port is matched by the test, 0 otherwise. */ + static inline int +-ports_match(const u_int16_t *portlist, enum ipt_multiport_flags flags, +- u_int8_t count, u_int16_t src, u_int16_t dst) ++ports_match_v1(const struct ipt_multiport_v1 *minfo, ++ u_int16_t src, u_int16_t dst) + { + unsigned int i; +- for (i=0; icount; i++) { ++ s = minfo->ports[i]; ++ ++ if (minfo->pflags[i]) { ++ /* range port matching */ ++ e = minfo->ports[++i]; ++ duprintf("src or dst matches with %d-%d?\n", s, e); ++ ++ if (minfo->flags == IPT_MULTIPORT_SOURCE ++ && src >= s && src <= e) ++ return 1 ^ minfo->invert; ++ if (minfo->flags == IPT_MULTIPORT_DESTINATION ++ && dst >= s && dst <= e) ++ return 1 ^ minfo->invert; ++ if (minfo->flags == IPT_MULTIPORT_EITHER ++ && ((dst >= s && dst <= e) ++ || (src >= s && src <= e))) ++ return 1 ^ minfo->invert; ++ } else { ++ /* exact port matching */ ++ duprintf("src or dst matches with %d?\n", s); ++ ++ if (minfo->flags == IPT_MULTIPORT_SOURCE ++ && src == s) ++ return 1 ^ minfo->invert; ++ if (minfo->flags == IPT_MULTIPORT_DESTINATION ++ && dst == s) ++ return 1 ^ minfo->invert; ++ if (minfo->flags == IPT_MULTIPORT_EITHER ++ && (src == s || dst == s)) ++ return 1 ^ minfo->invert; ++ } ++ } ++ ++ return minfo->invert; + } + + static int +-match(const struct sk_buff *skb, +- const struct net_device *in, +- const struct net_device *out, +- const void *matchinfo, +- int offset, +- const void *hdr, +- u_int16_t datalen, +- int *hotdrop) ++match_v1(const struct sk_buff *skb, ++ const struct net_device *in, ++ const struct net_device *out, ++ const void *matchinfo, ++ int offset, ++ int *hotdrop) + { +- const struct udphdr *udp = hdr; +- const struct ipt_multiport *multiinfo = matchinfo; ++ u16 _ports[2], *pptr; ++ const struct ipt_multiport_v1 *multiinfo = matchinfo; ++ ++ if (offset) ++ return 0; + +- /* Must be big enough to read ports. */ +- if (offset == 0 && datalen < sizeof(struct udphdr)) { ++ pptr = skb_header_pointer(skb, skb->nh.iph->ihl * 4, ++ sizeof(_ports), _ports); ++ if (pptr == NULL) { + /* We've been asked to examine this packet, and we +- can't. Hence, no choice but to drop. */ +- duprintf("ipt_multiport:" +- " Dropping evil offset=0 tinygram.\n"); +- *hotdrop = 1; +- return 0; ++ * can't. Hence, no choice but to drop. ++ */ ++ duprintf("ipt_multiport:" ++ " Dropping evil offset=0 tinygram.\n"); ++ *hotdrop = 1; ++ return 0; + } + +- /* Must not be a fragment. */ +- return !offset +- && ports_match(multiinfo->ports, +- multiinfo->flags, multiinfo->count, +- ntohs(udp->source), ntohs(udp->dest)); ++ return ports_match_v1(multiinfo, ntohs(pptr[0]), ntohs(pptr[1])); + } + +-/* Called when user tries to insert an entry of this type. */ + static int +-checkentry(const char *tablename, +- const struct ipt_ip *ip, +- void *matchinfo, +- unsigned int matchsize, +- unsigned int hook_mask) ++checkentry_v1(const char *tablename, ++ const struct ipt_ip *ip, ++ void *matchinfo, ++ unsigned int matchsize, ++ unsigned int hook_mask) + { +- const struct ipt_multiport *multiinfo = matchinfo; +- +- if (matchsize != IPT_ALIGN(sizeof(struct ipt_multiport))) +- return 0; +- +- /* Must specify proto == TCP/UDP, no unknown flags or bad count */ +- return (ip->proto == IPPROTO_TCP || ip->proto == IPPROTO_UDP) +- && !(ip->invflags & IPT_INV_PROTO) +- && matchsize == IPT_ALIGN(sizeof(struct ipt_multiport)) +- && (multiinfo->flags == IPT_MULTIPORT_SOURCE +- || multiinfo->flags == IPT_MULTIPORT_DESTINATION +- || multiinfo->flags == IPT_MULTIPORT_EITHER) +- && multiinfo->count <= IPT_MULTI_PORTS; ++ return (matchsize == IPT_ALIGN(sizeof(struct ipt_multiport_v1))); + } + +-static struct ipt_match multiport_match +-= { { NULL, NULL }, "multiport", &match, &checkentry, NULL, THIS_MODULE }; ++static struct ipt_match multiport_match_v1 = { ++ .name = "multiport", ++ .match = &match_v1, ++ .checkentry = &checkentry_v1, ++ .me = THIS_MODULE, ++}; + + static int __init init(void) + { +- return ipt_register_match(&multiport_match); ++ int err; ++ ++ err = ipt_register_match(&multiport_match_v1); ++ ++ return err; + } + + static void __exit fini(void) + { +- ipt_unregister_match(&multiport_match); ++ ipt_unregister_match(&multiport_match_v1); + } + + module_init(init); + module_exit(fini); +-MODULE_LICENSE("GPL"); diff --git a/openwrt/target/linux/generic-2.4/patches/618-netfilter_time.patch b/openwrt/target/linux/generic-2.4/patches/618-netfilter_time.patch deleted file mode 100644 index 3593571b46..0000000000 --- a/openwrt/target/linux/generic-2.4/patches/618-netfilter_time.patch +++ /dev/null @@ -1,238 +0,0 @@ -diff -urN linux-2.4.32.orig/net/ipv4/netfilter/Config.in linux-2.4.32/net/ipv4/netfilter/Config.in ---- linux-2.4.32.orig/net/ipv4/netfilter/Config.in 2006-01-07 12:11:37.000000000 +0100 -+++ linux-2.4.32/net/ipv4/netfilter/Config.in 2006-01-07 12:15:45.000000000 +0100 -@@ -48,6 +48,7 @@ - dep_tristate ' netfilter MARK match support' CONFIG_IP_NF_MATCH_MARK $CONFIG_IP_NF_IPTABLES - dep_tristate ' Multiple port match support' CONFIG_IP_NF_MATCH_MULTIPORT $CONFIG_IP_NF_IPTABLES - dep_tristate ' TOS match support' CONFIG_IP_NF_MATCH_TOS $CONFIG_IP_NF_IPTABLES -+ dep_tristate ' TIME match support (EXPERIMENTAL)' CONFIG_IP_NF_MATCH_TIME $CONFIG_IP_NF_IPTABLES - dep_tristate ' condition match support' CONFIG_IP_NF_MATCH_CONDITION $CONFIG_IP_NF_IPTABLES - dep_tristate ' recent match support' CONFIG_IP_NF_MATCH_RECENT $CONFIG_IP_NF_IPTABLES - dep_tristate ' ECN match support' CONFIG_IP_NF_MATCH_ECN $CONFIG_IP_NF_IPTABLES -diff -urN linux-2.4.32.orig/net/ipv4/netfilter/ipt_time.c linux-2.4.32/net/ipv4/netfilter/ipt_time.c ---- linux-2.4.32.orig/net/ipv4/netfilter/ipt_time.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.32/net/ipv4/netfilter/ipt_time.c 2006-01-07 12:14:32.000000000 +0100 -@@ -0,0 +1,193 @@ -+/* -+ This is a module which is used for time matching -+ It is using some modified code from dietlibc (localtime() function) -+ that you can find at http://www.fefe.de/dietlibc/ -+ This file is distributed under the terms of the GNU General Public -+ License (GPL). Copies of the GPL can be obtained from: ftp://prep.ai.mit.edu/pub/gnu/GPL -+ 2001-05-04 Fabrice MARIE : initial development. -+ 2001-21-05 Fabrice MARIE : bug fix in the match code, -+ thanks to "Zeng Yu" for bug report. -+ 2001-26-09 Fabrice MARIE : force the match to be in LOCAL_IN or PRE_ROUTING only. -+ 2001-30-11 Fabrice : added the possibility to use the match in FORWARD/OUTPUT with a little hack, -+ added Nguyen Dang Phuoc Dong patch to support timezones. -+ 2004-05-02 Fabrice : added support for date matching, from an idea of Fabien COELHO. -+*/ -+ -+#include -+#include -+#include -+#include -+#include -+ -+MODULE_AUTHOR("Fabrice MARIE "); -+MODULE_DESCRIPTION("Match arrival timestamp/date"); -+MODULE_LICENSE("GPL"); -+ -+struct tm -+{ -+ int tm_sec; /* Seconds. [0-60] (1 leap second) */ -+ int tm_min; /* Minutes. [0-59] */ -+ int tm_hour; /* Hours. [0-23] */ -+ int tm_mday; /* Day. [1-31] */ -+ int tm_mon; /* Month. [0-11] */ -+ int tm_year; /* Year - 1900. */ -+ int tm_wday; /* Day of week. [0-6] */ -+ int tm_yday; /* Days in year.[0-365] */ -+ int tm_isdst; /* DST. [-1/0/1]*/ -+ -+ long int tm_gmtoff; /* we don't care, we count from GMT */ -+ const char *tm_zone; /* we don't care, we count from GMT */ -+}; -+ -+void -+localtime(const time_t *timepr, struct tm *r); -+ -+static int -+match(const struct sk_buff *skb, -+ const struct net_device *in, -+ const struct net_device *out, -+ const void *matchinfo, -+ int offset, -+ const void *hdr, -+ u_int16_t datalen, -+ int *hotdrop) -+{ -+ const struct ipt_time_info *info = matchinfo; /* match info for rule */ -+ struct tm currenttime; /* time human readable */ -+ u_int8_t days_of_week[7] = {64, 32, 16, 8, 4, 2, 1}; -+ u_int16_t packet_time; -+ struct timeval kerneltimeval; -+ time_t packet_local_time; -+ -+ /* if kerneltime=1, we don't read the skb->timestamp but kernel time instead */ -+ if (info->kerneltime) -+ { -+ do_gettimeofday(&kerneltimeval); -+ packet_local_time = kerneltimeval.tv_sec; -+ } -+ else -+ packet_local_time = skb->stamp.tv_sec; -+ -+ /* First we make sure we are in the date start-stop boundaries */ -+ if ((packet_local_time < info->date_start) || (packet_local_time > info->date_stop)) -+ return 0; /* We are outside the date boundaries */ -+ -+ /* Transform the timestamp of the packet, in a human readable form */ -+ localtime(&packet_local_time, ¤ttime); -+ -+ /* check if we match this timestamp, we start by the days... */ -+ if ((days_of_week[currenttime.tm_wday] & info->days_match) != days_of_week[currenttime.tm_wday]) -+ return 0; /* the day doesn't match */ -+ -+ /* ... check the time now */ -+ packet_time = (currenttime.tm_hour * 60) + currenttime.tm_min; -+ if ((packet_time < info->time_start) || (packet_time > info->time_stop)) -+ return 0; -+ -+ /* here we match ! */ -+ return 1; -+} -+ -+static int -+checkentry(const char *tablename, -+ const struct ipt_ip *ip, -+ void *matchinfo, -+ unsigned int matchsize, -+ unsigned int hook_mask) -+{ -+ struct ipt_time_info *info = matchinfo; /* match info for rule */ -+ -+ /* First, check that we are in the correct hooks */ -+ if (hook_mask -+ & ~((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_IN) | (1 << NF_IP_FORWARD) | (1 << NF_IP_LOCAL_OUT))) -+ { -+ printk("ipt_time: error, only valid for PRE_ROUTING, LOCAL_IN, FORWARD and OUTPUT)\n"); -+ return 0; -+ } -+ /* we use the kerneltime if we are in forward or output */ -+ info->kerneltime = 1; -+ if (hook_mask & ~((1 << NF_IP_FORWARD) | (1 << NF_IP_LOCAL_OUT))) -+ /* we use the skb time */ -+ info->kerneltime = 0; -+ -+ /* Check the size */ -+ if (matchsize != IPT_ALIGN(sizeof(struct ipt_time_info))) -+ return 0; -+ /* Now check the coherence of the data ... */ -+ if ((info->time_start > 1439) || /* 23*60+59 = 1439*/ -+ (info->time_stop > 1439)) -+ { -+ printk(KERN_WARNING "ipt_time: invalid argument\n"); -+ return 0; -+ } -+ -+ return 1; -+} -+ -+static struct ipt_match time_match = { -+ .name = "time", -+ .match = match, -+ .checkentry = checkentry, -+ .me = THIS_MODULE, -+}; -+ -+static int __init init(void) -+{ -+ printk("ipt_time loading\n"); -+ return ipt_register_match(&time_match); -+} -+ -+static void __exit fini(void) -+{ -+ ipt_unregister_match(&time_match); -+ printk("ipt_time unloaded\n"); -+} -+ -+module_init(init); -+module_exit(fini); -+ -+ -+/* The part below is borowed and modified from dietlibc */ -+ -+/* seconds per day */ -+#define SPD 24*60*60 -+ -+void -+localtime(const time_t *timepr, struct tm *r) { -+ time_t i; -+ time_t timep; -+ extern struct timezone sys_tz; -+ const unsigned int __spm[12] = -+ { 0, -+ (31), -+ (31+28), -+ (31+28+31), -+ (31+28+31+30), -+ (31+28+31+30+31), -+ (31+28+31+30+31+30), -+ (31+28+31+30+31+30+31), -+ (31+28+31+30+31+30+31+31), -+ (31+28+31+30+31+30+31+31+30), -+ (31+28+31+30+31+30+31+31+30+31), -+ (31+28+31+30+31+30+31+31+30+31+30), -+ }; -+ register time_t work; -+ -+ timep = (*timepr) - (sys_tz.tz_minuteswest * 60); -+ work=timep%(SPD); -+ r->tm_sec=work%60; work/=60; -+ r->tm_min=work%60; r->tm_hour=work/60; -+ work=timep/(SPD); -+ r->tm_wday=(4+work)%7; -+ for (i=1970; ; ++i) { -+ register time_t k= (!(i%4) && ((i%100) || !(i%400)))?366:365; -+ if (work>k) -+ work-=k; -+ else -+ break; -+ } -+ r->tm_year=i-1900; -+ for (i=11; i && __spm[i]>work; --i) ; -+ r->tm_mon=i; -+ r->tm_mday=work-__spm[i]+1; -+} -diff -urN linux-2.4.32.orig/net/ipv4/netfilter/Makefile linux-2.4.32/net/ipv4/netfilter/Makefile ---- linux-2.4.32.orig/net/ipv4/netfilter/Makefile 2006-01-07 12:11:37.000000000 +0100 -+++ linux-2.4.32/net/ipv4/netfilter/Makefile 2006-01-07 12:16:07.000000000 +0100 -@@ -118,6 +118,7 @@ - obj-$(CONFIG_IP_NF_MATCH_MULTIPORT) += ipt_multiport.o - obj-$(CONFIG_IP_NF_MATCH_OWNER) += ipt_owner.o - obj-$(CONFIG_IP_NF_MATCH_TOS) += ipt_tos.o -+obj-$(CONFIG_IP_NF_MATCH_TIME) += ipt_time.o - obj-$(CONFIG_IP_NF_MATCH_CONDITION) += ipt_condition.o - - obj-$(CONFIG_IP_NF_MATCH_RECENT) += ipt_recent.o -diff -urN linux-2.4.32.orig/include/linux/netfilter_ipv4/ipt_time.h linux-2.4.32/include/linux/netfilter_ipv4/ipt_time.h ---- linux-2.4.32.orig/include/linux/netfilter_ipv4/ipt_time.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.32/include/linux/netfilter_ipv4/ipt_time.h 2006-01-07 12:16:42.000000000 +0100 -@@ -0,0 +1,15 @@ -+#ifndef __ipt_time_h_included__ -+#define __ipt_time_h_included__ -+ -+ -+struct ipt_time_info { -+ u_int8_t days_match; /* 1 bit per day. -SMTWTFS */ -+ u_int16_t time_start; /* 0 < time_start < 23*60+59 = 1439 */ -+ u_int16_t time_stop; /* 0:0 < time_stat < 23:59 */ -+ u_int8_t kerneltime; /* ignore skb time (and use kerneltime) or not. */ -+ time_t date_start; -+ time_t date_stop; -+}; -+ -+ -+#endif /* __ipt_time_h_included__ */ diff --git a/openwrt/target/linux/generic-2.4/patches/619-netfilter_multiport_backport.patch b/openwrt/target/linux/generic-2.4/patches/619-netfilter_multiport_backport.patch deleted file mode 100644 index c34f9ecbb7..0000000000 --- a/openwrt/target/linux/generic-2.4/patches/619-netfilter_multiport_backport.patch +++ /dev/null @@ -1,231 +0,0 @@ -diff -urN linux.old/include/linux/netfilter_ipv4/ipt_multiport.h linux.dev/include/linux/netfilter_ipv4/ipt_multiport.h ---- linux.old/include/linux/netfilter_ipv4/ipt_multiport.h 2000-12-11 22:31:30.000000000 +0100 -+++ linux.dev/include/linux/netfilter_ipv4/ipt_multiport.h 2006-02-04 05:23:54.318518250 +0100 -@@ -11,11 +11,12 @@ - - #define IPT_MULTI_PORTS 15 - --/* Must fit inside union ipt_matchinfo: 16 bytes */ --struct ipt_multiport -+struct ipt_multiport_v1 - { - u_int8_t flags; /* Type of comparison */ - u_int8_t count; /* Number of ports */ - u_int16_t ports[IPT_MULTI_PORTS]; /* Ports */ -+ u_int8_t pflags[IPT_MULTI_PORTS]; /* Port flags */ -+ u_int8_t invert; /* Invert flag */ - }; - #endif /*_IPT_MULTIPORT_H*/ -diff -urN linux.old/net/ipv4/netfilter/ipt_multiport.c linux.dev/net/ipv4/netfilter/ipt_multiport.c ---- linux.old/net/ipv4/netfilter/ipt_multiport.c 2003-06-13 16:51:39.000000000 +0200 -+++ linux.dev/net/ipv4/netfilter/ipt_multiport.c 2006-02-04 05:34:27.362081000 +0100 -@@ -1,5 +1,14 @@ - /* Kernel module to match one of a list of TCP/UDP ports: ports are in - the same place so we can treat them as equal. */ -+ -+/* (C) 1999-2001 Paul `Rusty' Russell -+ * (C) 2002-2004 Netfilter Core Team -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ - #include - #include - #include -@@ -8,97 +17,136 @@ - #include - #include - -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Netfilter Core Team "); -+MODULE_DESCRIPTION("iptables multiple port match module"); -+ - #if 0 - #define duprintf(format, args...) printk(format , ## args) - #else - #define duprintf(format, args...) - #endif - -+/* from linux 2.6 skbuff.h */ -+static inline void *skb_header_pointer(const struct sk_buff *skb, int offset, -+ int len, void *buffer) -+{ -+ int hlen = skb_headlen(skb); -+ -+ if (hlen - offset >= len) -+ return skb->data + offset; -+ -+ if (skb_copy_bits(skb, offset, buffer, len) < 0) -+ return NULL; -+ -+ return buffer; -+} -+ -+ - /* Returns 1 if the port is matched by the test, 0 otherwise. */ - static inline int --ports_match(const u_int16_t *portlist, enum ipt_multiport_flags flags, -- u_int8_t count, u_int16_t src, u_int16_t dst) -+ports_match_v1(const struct ipt_multiport_v1 *minfo, -+ u_int16_t src, u_int16_t dst) - { - unsigned int i; -- for (i=0; icount; i++) { -+ s = minfo->ports[i]; -+ -+ if (minfo->pflags[i]) { -+ /* range port matching */ -+ e = minfo->ports[++i]; -+ duprintf("src or dst matches with %d-%d?\n", s, e); -+ -+ if (minfo->flags == IPT_MULTIPORT_SOURCE -+ && src >= s && src <= e) -+ return 1 ^ minfo->invert; -+ if (minfo->flags == IPT_MULTIPORT_DESTINATION -+ && dst >= s && dst <= e) -+ return 1 ^ minfo->invert; -+ if (minfo->flags == IPT_MULTIPORT_EITHER -+ && ((dst >= s && dst <= e) -+ || (src >= s && src <= e))) -+ return 1 ^ minfo->invert; -+ } else { -+ /* exact port matching */ -+ duprintf("src or dst matches with %d?\n", s); -+ -+ if (minfo->flags == IPT_MULTIPORT_SOURCE -+ && src == s) -+ return 1 ^ minfo->invert; -+ if (minfo->flags == IPT_MULTIPORT_DESTINATION -+ && dst == s) -+ return 1 ^ minfo->invert; -+ if (minfo->flags == IPT_MULTIPORT_EITHER -+ && (src == s || dst == s)) -+ return 1 ^ minfo->invert; -+ } -+ } -+ -+ return minfo->invert; - } - - static int --match(const struct sk_buff *skb, -- const struct net_device *in, -- const struct net_device *out, -- const void *matchinfo, -- int offset, -- const void *hdr, -- u_int16_t datalen, -- int *hotdrop) -+match_v1(const struct sk_buff *skb, -+ const struct net_device *in, -+ const struct net_device *out, -+ const void *matchinfo, -+ int offset, -+ int *hotdrop) - { -- const struct udphdr *udp = hdr; -- const struct ipt_multiport *multiinfo = matchinfo; -+ u16 _ports[2], *pptr; -+ const struct ipt_multiport_v1 *multiinfo = matchinfo; -+ -+ if (offset) -+ return 0; - -- /* Must be big enough to read ports. */ -- if (offset == 0 && datalen < sizeof(struct udphdr)) { -+ pptr = skb_header_pointer(skb, skb->nh.iph->ihl * 4, -+ sizeof(_ports), _ports); -+ if (pptr == NULL) { - /* We've been asked to examine this packet, and we -- can't. Hence, no choice but to drop. */ -- duprintf("ipt_multiport:" -- " Dropping evil offset=0 tinygram.\n"); -- *hotdrop = 1; -- return 0; -+ * can't. Hence, no choice but to drop. -+ */ -+ duprintf("ipt_multiport:" -+ " Dropping evil offset=0 tinygram.\n"); -+ *hotdrop = 1; -+ return 0; - } - -- /* Must not be a fragment. */ -- return !offset -- && ports_match(multiinfo->ports, -- multiinfo->flags, multiinfo->count, -- ntohs(udp->source), ntohs(udp->dest)); -+ return ports_match_v1(multiinfo, ntohs(pptr[0]), ntohs(pptr[1])); - } - --/* Called when user tries to insert an entry of this type. */ - static int --checkentry(const char *tablename, -- const struct ipt_ip *ip, -- void *matchinfo, -- unsigned int matchsize, -- unsigned int hook_mask) -+checkentry_v1(const char *tablename, -+ const struct ipt_ip *ip, -+ void *matchinfo, -+ unsigned int matchsize, -+ unsigned int hook_mask) - { -- const struct ipt_multiport *multiinfo = matchinfo; -- -- if (matchsize != IPT_ALIGN(sizeof(struct ipt_multiport))) -- return 0; -- -- /* Must specify proto == TCP/UDP, no unknown flags or bad count */ -- return (ip->proto == IPPROTO_TCP || ip->proto == IPPROTO_UDP) -- && !(ip->invflags & IPT_INV_PROTO) -- && matchsize == IPT_ALIGN(sizeof(struct ipt_multiport)) -- && (multiinfo->flags == IPT_MULTIPORT_SOURCE -- || multiinfo->flags == IPT_MULTIPORT_DESTINATION -- || multiinfo->flags == IPT_MULTIPORT_EITHER) -- && multiinfo->count <= IPT_MULTI_PORTS; -+ return (matchsize == IPT_ALIGN(sizeof(struct ipt_multiport_v1))); - } - --static struct ipt_match multiport_match --= { { NULL, NULL }, "multiport", &match, &checkentry, NULL, THIS_MODULE }; -+static struct ipt_match multiport_match_v1 = { -+ .name = "multiport", -+ .match = &match_v1, -+ .checkentry = &checkentry_v1, -+ .me = THIS_MODULE, -+}; - - static int __init init(void) - { -- return ipt_register_match(&multiport_match); -+ int err; -+ -+ err = ipt_register_match(&multiport_match_v1); -+ -+ return err; - } - - static void __exit fini(void) - { -- ipt_unregister_match(&multiport_match); -+ ipt_unregister_match(&multiport_match_v1); - } - - module_init(init); - module_exit(fini); --MODULE_LICENSE("GPL"); diff --git a/openwrt/target/linux/package/Makefile b/openwrt/target/linux/package/Makefile index 77a0583fdf..4a81f8e919 100644 --- a/openwrt/target/linux/package/Makefile +++ b/openwrt/target/linux/package/Makefile @@ -17,6 +17,7 @@ package-$(BR2_PACKAGE_KMOD_SWITCH) += switch package-$(BR2_PACKAGE_KMOD_UEAGLE_ATM) += ueagle-atm package-$(BR2_PACKAGE_KMOD_DIAG) += diag package-$(BR2_PACKAGE_KMOD_WLCOMPAT) += wlcompat +package-$(BR2_PACKAGE_KMOD_ZD1211) += zd1211 bcm43xx-dscape-compile: ieee80211-dscape-compile wlcompat-compile: base-files-compile diff --git a/openwrt/target/linux/x86-2.4/config b/openwrt/target/linux/x86-2.4/config index 7b4afaa9c0..1adc29508e 100644 --- a/openwrt/target/linux/x86-2.4/config +++ b/openwrt/target/linux/x86-2.4/config @@ -286,7 +286,6 @@ CONFIG_IP_NF_CT_ACCT=m CONFIG_IP_NF_MATCH_CONNBYTES=m CONFIG_IP_NF_CT_PROTO_GRE=m CONFIG_IP_NF_PPTP=m -CONFIG_IP_NF_SIP=m CONFIG_IP_NF_H323=m CONFIG_IP_NF_MMS=m CONFIG_IP_NF_RTSP=m @@ -339,7 +338,6 @@ CONFIG_IP_NF_TARGET_MASQUERADE=y CONFIG_IP_NF_TARGET_REDIRECT=m CONFIG_IP_NF_TARGET_NETMAP=m CONFIG_IP_NF_NAT_PPTP=m -CONFIG_IP_NF_NAT_SIP=m CONFIG_IP_NF_NAT_H323=m CONFIG_IP_NF_NAT_PROTO_GRE=m CONFIG_IP_NF_NAT_MMS=m