From: Florian Fainelli Date: Tue, 28 Feb 2006 23:27:45 +0000 (+0000) Subject: Remove SIP connection tracking helpers, licence unclear, too many unresolved symbols X-Git-Tag: whiterussian_rc5~103 X-Git-Url: http://git.openwrt.org/?a=commitdiff_plain;h=4da91cfd7750a3438903eddf1e5aa0deade63d97;p=openwrt%2Fsvn-archive%2Fopenwrt.git Remove SIP connection tracking helpers, licence unclear, too many unresolved symbols SVN-Revision: 3290 --- diff --git a/openwrt/target/linux/linux-2.4/config/brcm b/openwrt/target/linux/linux-2.4/config/brcm index 5e60fd0f8f..5eaadf77bc 100644 --- a/openwrt/target/linux/linux-2.4/config/brcm +++ b/openwrt/target/linux/linux-2.4/config/brcm @@ -347,7 +347,6 @@ CONFIG_IP_NF_TFTP=m CONFIG_IP_NF_IRC=y 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_RTSP=m CONFIG_IP_NF_QUEUE=m @@ -384,7 +383,6 @@ CONFIG_IP_NF_NAT_NEEDED=y CONFIG_IP_NF_TARGET_MASQUERADE=y CONFIG_IP_NF_TARGET_REDIRECT=m CONFIG_IP_NF_NAT_PPTP=m -CONFIG_IP_NF_NAT_SIP=m CONFIG_IP_NF_NAT_H323=m CONFIG_IP_NF_NAT_RTSP=m CONFIG_IP_NF_NAT_PROTO_GRE=m diff --git a/openwrt/target/linux/linux-2.4/patches/generic/116-netfilter_nat_h323.patch b/openwrt/target/linux/linux-2.4/patches/generic/116-netfilter_nat_h323.patch new file mode 100644 index 0000000000..99b3a7b107 --- /dev/null +++ b/openwrt/target/linux/linux-2.4/patches/generic/116-netfilter_nat_h323.patch @@ -0,0 +1,821 @@ +diff -urN linux-2.4.30/net/ipv4/netfilter/Config.in linux-2.4.30.new/net/ipv4/netfilter/Config.in +--- linux-2.4.30/net/ipv4/netfilter/Config.in 2006-02-28 23:39:57.844781136 +0100 ++++ linux-2.4.30.new/net/ipv4/netfilter/Config.in 2006-02-28 23:45:18.819985488 +0100 +@@ -13,6 +13,7 @@ + dep_tristate ' IRC protocol support' CONFIG_IP_NF_IRC $CONFIG_IP_NF_CONNTRACK + 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 +@@ -94,6 +95,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.30/net/ipv4/netfilter/Makefile linux-2.4.30.new/net/ipv4/netfilter/Makefile +--- linux-2.4.30/net/ipv4/netfilter/Makefile 2006-02-28 23:39:57.847780680 +0100 ++++ linux-2.4.30.new/net/ipv4/netfilter/Makefile 2006-02-28 23:45:58.759913696 +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.30/net/ipv4/netfilter/ip_conntrack_h323.c linux-2.4.30.new/net/ipv4/netfilter/ip_conntrack_h323.c +--- linux-2.4.30/net/ipv4/netfilter/ip_conntrack_h323.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.30.new/net/ipv4/netfilter/ip_conntrack_h323.c 2006-02-28 23:43:35.239732080 +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.30/net/ipv4/netfilter/ip_nat_h323.c linux-2.4.30.new/net/ipv4/netfilter/ip_nat_h323.c +--- linux-2.4.30/net/ipv4/netfilter/ip_nat_h323.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.30.new/net/ipv4/netfilter/ip_nat_h323.c 2006-02-28 23:43:35.240731928 +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.30/include/linux/netfilter_ipv4/ip_conntrack.h linux-2.4.30.new/include/linux/netfilter_ipv4/ip_conntrack.h +--- linux-2.4.30/include/linux/netfilter_ipv4/ip_conntrack.h 2006-02-28 23:39:57.588820048 +0100 ++++ linux-2.4.30.new/include/linux/netfilter_ipv4/ip_conntrack.h 2006-02-28 23:48:57.946673168 +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.30/include/linux/netfilter_ipv4/ip_conntrack_h323.h linux-2.4.30.new/include/linux/netfilter_ipv4/ip_conntrack_h323.h +--- linux-2.4.30/include/linux/netfilter_ipv4/ip_conntrack_h323.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.30.new/include/linux/netfilter_ipv4/ip_conntrack_h323.h 2006-02-28 23:43:35.261728736 +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/linux-2.4/patches/generic/116-netfilter_nat_sip.patch b/openwrt/target/linux/linux-2.4/patches/generic/116-netfilter_nat_sip.patch deleted file mode 100644 index 6bb1af3691..0000000000 --- a/openwrt/target/linux/linux-2.4/patches/generic/116-netfilter_nat_sip.patch +++ /dev/null @@ -1,1254 +0,0 @@ -diff -urN linux-2.4.30/net/ipv4/netfilter/Config.in linux-2.4.30.new/net/ipv4/netfilter/Config.in ---- linux-2.4.30/net/ipv4/netfilter/Config.in 2006-02-14 01:14:42.758184584 +0100 -+++ linux-2.4.30.new/net/ipv4/netfilter/Config.in 2006-02-14 01:16:16.325960120 +0100 -@@ -13,6 +13,7 @@ - dep_tristate ' IRC protocol support' CONFIG_IP_NF_IRC $CONFIG_IP_NF_CONNTRACK - 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 -@@ -87,6 +88,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.30/net/ipv4/netfilter/ip_conntrack_sip.c linux-2.4.30.new/net/ipv4/netfilter/ip_conntrack_sip.c ---- linux-2.4.30/net/ipv4/netfilter/ip_conntrack_sip.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.30.new/net/ipv4/netfilter/ip_conntrack_sip.c 2006-02-14 01:16:16.327959816 +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(ct, (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.30/net/ipv4/netfilter/ip_nat_sip.c linux-2.4.30.new/net/ipv4/netfilter/ip_nat_sip.c ---- linux-2.4.30/net/ipv4/netfilter/ip_nat_sip.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.30.new/net/ipv4/netfilter/ip_nat_sip.c 2006-02-14 01:16:16.328959664 +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.30/net/ipv4/netfilter/Makefile linux-2.4.30.new/net/ipv4/netfilter/Makefile ---- linux-2.4.30/net/ipv4/netfilter/Makefile 2006-02-14 01:14:42.760184280 +0100 -+++ linux-2.4.30.new/net/ipv4/netfilter/Makefile 2006-02-14 01:16:16.329959512 +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.30/include/linux/netfilter_ipv4/ip_conntrack.h linux-2.4.30.new/include/linux/netfilter_ipv4/ip_conntrack.h ---- linux-2.4.30/include/linux/netfilter_ipv4/ip_conntrack.h 2006-02-14 01:14:42.014297672 +0100 -+++ linux-2.4.30.new/include/linux/netfilter_ipv4/ip_conntrack.h 2006-02-14 01:16:16.330959360 +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.30/include/linux/netfilter_ipv4/ip_conntrack_sip.h linux-2.4.30.new/include/linux/netfilter_ipv4/ip_conntrack_sip.h ---- linux-2.4.30/include/linux/netfilter_ipv4/ip_conntrack_sip.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.30.new/include/linux/netfilter_ipv4/ip_conntrack_sip.h 2006-02-14 01:16:16.331959208 +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/linux-2.4/patches/generic/117-netfilter_nat_h323.patch b/openwrt/target/linux/linux-2.4/patches/generic/117-netfilter_nat_h323.patch deleted file mode 100644 index e18627a73d..0000000000 --- a/openwrt/target/linux/linux-2.4/patches/generic/117-netfilter_nat_h323.patch +++ /dev/null @@ -1,821 +0,0 @@ -diff -urN linux-2.4.30/net/ipv4/netfilter/Config.in linux-2.4.30.new/net/ipv4/netfilter/Config.in ---- linux-2.4.30/net/ipv4/netfilter/Config.in 2006-02-07 15:42:18.000000000 +0100 -+++ linux-2.4.30.new/net/ipv4/netfilter/Config.in 2006-02-07 15:42:53.000000000 +0100 -@@ -14,6 +14,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 -@@ -95,6 +96,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.30/net/ipv4/netfilter/ip_conntrack_h323.c linux-2.4.30.new/net/ipv4/netfilter/ip_conntrack_h323.c ---- linux-2.4.30/net/ipv4/netfilter/ip_conntrack_h323.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.30.new/net/ipv4/netfilter/ip_conntrack_h323.c 2006-02-07 15:42:53.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.30/net/ipv4/netfilter/ip_nat_h323.c linux-2.4.30.new/net/ipv4/netfilter/ip_nat_h323.c ---- linux-2.4.30/net/ipv4/netfilter/ip_nat_h323.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.30.new/net/ipv4/netfilter/ip_nat_h323.c 2006-02-07 15:42:53.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.30/net/ipv4/netfilter/Makefile linux-2.4.30.new/net/ipv4/netfilter/Makefile ---- linux-2.4.30/net/ipv4/netfilter/Makefile 2006-02-07 15:42:18.000000000 +0100 -+++ linux-2.4.30.new/net/ipv4/netfilter/Makefile 2006-02-07 15:42:53.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.30/include/linux/netfilter_ipv4/ip_conntrack.h linux-2.4.30.new/include/linux/netfilter_ipv4/ip_conntrack.h ---- linux-2.4.30/include/linux/netfilter_ipv4/ip_conntrack.h 2006-02-07 15:42:18.000000000 +0100 -+++ linux-2.4.30.new/include/linux/netfilter_ipv4/ip_conntrack.h 2006-02-07 15:42:53.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.30/include/linux/netfilter_ipv4/ip_conntrack_h323.h linux-2.4.30.new/include/linux/netfilter_ipv4/ip_conntrack_h323.h ---- linux-2.4.30/include/linux/netfilter_ipv4/ip_conntrack_h323.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.30.new/include/linux/netfilter_ipv4/ip_conntrack_h323.h 2006-02-07 15:42:53.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/linux-2.4/patches/generic/117-netfilter_nat_rtsp.patch b/openwrt/target/linux/linux-2.4/patches/generic/117-netfilter_nat_rtsp.patch new file mode 100644 index 0000000000..8697a1cac1 --- /dev/null +++ b/openwrt/target/linux/linux-2.4/patches/generic/117-netfilter_nat_rtsp.patch @@ -0,0 +1,1498 @@ +diff -urN linux-2.4.30/net/ipv4/netfilter/Config.in linux-2.4.30.new/net/ipv4/netfilter/Config.in +--- linux-2.4.30/net/ipv4/netfilter/Config.in 2006-02-28 23:55:30.907933976 +0100 ++++ linux-2.4.30.new/net/ipv4/netfilter/Config.in 2006-02-28 23:59:58.032324896 +0100 +@@ -14,6 +14,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 +@@ -102,6 +103,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.30/net/ipv4/netfilter/Makefile linux-2.4.30.new/net/ipv4/netfilter/Makefile +--- linux-2.4.30/net/ipv4/netfilter/Makefile 2006-02-28 23:55:30.932930176 +0100 ++++ linux-2.4.30.new/net/ipv4/netfilter/Makefile 2006-03-01 00:00:38.575161448 +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.30/net/ipv4/netfilter/ip_conntrack_rtsp.c linux-2.4.30.new/net/ipv4/netfilter/ip_conntrack_rtsp.c +--- linux-2.4.30/net/ipv4/netfilter/ip_conntrack_rtsp.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.30.new/net/ipv4/netfilter/ip_conntrack_rtsp.c 2006-02-28 23:58:15.173961744 +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.30/net/ipv4/netfilter/ip_nat_rtsp.c linux-2.4.30.new/net/ipv4/netfilter/ip_nat_rtsp.c +--- linux-2.4.30/net/ipv4/netfilter/ip_nat_rtsp.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.30.new/net/ipv4/netfilter/ip_nat_rtsp.c 2006-02-28 23:58:15.175961440 +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.30/arch/mips/kernel/mips_ksyms.c linux-2.4.30.new/arch/mips/kernel/mips_ksyms.c +--- linux-2.4.30/arch/mips/kernel/mips_ksyms.c 2004-02-18 14:36:30.000000000 +0100 ++++ linux-2.4.30.new/arch/mips/kernel/mips_ksyms.c 2006-02-28 23:58:15.724877992 +0100 +@@ -48,6 +48,7 @@ + /* + * String functions + */ ++EXPORT_SYMBOL_NOVERS(memchr); + EXPORT_SYMBOL_NOVERS(memcmp); + EXPORT_SYMBOL_NOVERS(memset); + EXPORT_SYMBOL_NOVERS(memcpy); +diff -urN linux-2.4.30/include/linux/netfilter_helpers.h linux-2.4.30.new/include/linux/netfilter_helpers.h +--- linux-2.4.30/include/linux/netfilter_helpers.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.30.new/include/linux/netfilter_helpers.h 2006-02-28 23:58:15.199957792 +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.30/include/linux/netfilter_ipv4/ip_conntrack_rtsp.h linux-2.4.30.new/include/linux/netfilter_ipv4/ip_conntrack_rtsp.h +--- linux-2.4.30/include/linux/netfilter_ipv4/ip_conntrack_rtsp.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.30.new/include/linux/netfilter_ipv4/ip_conntrack_rtsp.h 2006-02-28 23:58:15.227953536 +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.30/include/linux/netfilter_mime.h linux-2.4.30.new/include/linux/netfilter_mime.h +--- linux-2.4.30/include/linux/netfilter_mime.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.30.new/include/linux/netfilter_mime.h 2006-02-28 23:58:15.228953384 +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 --git a/openwrt/target/linux/linux-2.4/patches/generic/118-netfilter_nat_rtsp.patch b/openwrt/target/linux/linux-2.4/patches/generic/118-netfilter_nat_rtsp.patch deleted file mode 100644 index 4b7a5c7d81..0000000000 --- a/openwrt/target/linux/linux-2.4/patches/generic/118-netfilter_nat_rtsp.patch +++ /dev/null @@ -1,1520 +0,0 @@ -diff -urN linux-2.4.30/net/ipv4/netfilter/Config.in linux-2.4.30.new/net/ipv4/netfilter/Config.in ---- linux-2.4.30/net/ipv4/netfilter/Config.in 2006-02-14 14:02:20.000000000 +0100 -+++ linux-2.4.30.new/net/ipv4/netfilter/Config.in 2006-02-14 13:49:55.000000000 +0100 -@@ -15,6 +15,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 - fi - - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then -@@ -103,6 +104,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_IP_NF_AMANDA" = "m" ]; then - define_tristate CONFIG_IP_NF_NAT_AMANDA m - else -diff -urN linux-2.4.30/net/ipv4/netfilter/ip_conntrack_rtsp.c linux-2.4.30.new/net/ipv4/netfilter/ip_conntrack_rtsp.c ---- linux-2.4.30/net/ipv4/netfilter/ip_conntrack_rtsp.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.30.new/net/ipv4/netfilter/ip_conntrack_rtsp.c 2006-02-14 13:49:55.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.30/net/ipv4/netfilter/ip_nat_rtsp.c linux-2.4.30.new/net/ipv4/netfilter/ip_nat_rtsp.c ---- linux-2.4.30/net/ipv4/netfilter/ip_nat_rtsp.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.30.new/net/ipv4/netfilter/ip_nat_rtsp.c 2006-02-14 13:49:55.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.30/net/ipv4/netfilter/Makefile linux-2.4.30.new/net/ipv4/netfilter/Makefile ---- linux-2.4.30/net/ipv4/netfilter/Makefile 2006-02-14 14:02:20.000000000 +0100 -+++ linux-2.4.30.new/net/ipv4/netfilter/Makefile 2006-02-14 13:49:55.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 -urN linux-2.4.30/include/linux/netfilter_helpers.h linux-2.4.30.new/include/linux/netfilter_helpers.h ---- linux-2.4.30/include/linux/netfilter_helpers.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.30.new/include/linux/netfilter_helpers.h 2006-02-14 13:49:55.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.30/include/linux/netfilter_ipv4/ip_conntrack.h linux-2.4.30.new/include/linux/netfilter_ipv4/ip_conntrack.h ---- linux-2.4.30/include/linux/netfilter_ipv4/ip_conntrack.h 2006-02-14 14:02:20.000000000 +0100 -+++ linux-2.4.30.new/include/linux/netfilter_ipv4/ip_conntrack.h 2006-02-14 13:49:55.000000000 +0100 -@@ -66,6 +66,7 @@ - }; - - /* Add protocol helper include file here */ -+#include - #include - - #include -@@ -77,6 +78,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; -@@ -94,6 +96,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.30/include/linux/netfilter_ipv4/ip_conntrack_rtsp.h linux-2.4.30.new/include/linux/netfilter_ipv4/ip_conntrack_rtsp.h ---- linux-2.4.30/include/linux/netfilter_ipv4/ip_conntrack_rtsp.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.30.new/include/linux/netfilter_ipv4/ip_conntrack_rtsp.h 2006-02-14 13:49:55.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.30/include/linux/netfilter_mime.h linux-2.4.30.new/include/linux/netfilter_mime.h ---- linux-2.4.30/include/linux/netfilter_mime.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.4.30.new/include/linux/netfilter_mime.h 2006-02-14 13:49:55.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.30/arch/mips/kernel/mips_ksyms.c linux-2.4.30.new/arch/mips/kernel/mips_ksyms.c ---- linux-2.4.30/arch/mips/kernel/mips_ksyms.c 2004-02-18 14:36:30.000000000 +0100 -+++ linux-2.4.30.new/arch/mips/kernel/mips_ksyms.c 2006-02-14 13:50:27.000000000 +0100 -@@ -48,6 +48,7 @@ - /* - * String functions - */ -+EXPORT_SYMBOL_NOVERS(memchr); - EXPORT_SYMBOL_NOVERS(memcmp); - EXPORT_SYMBOL_NOVERS(memset); - EXPORT_SYMBOL_NOVERS(memcpy);