From 027c1750c25b8b7f5dccc09db51e77aee49cf43e Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Mon, 12 Dec 2005 12:01:43 +0000 Subject: [PATCH] Added support for the H323 connection tracking module SVN-Revision: 2639 --- openwrt/target/linux/linux-2.4/config/brcm | 2 + openwrt/target/linux/linux-2.4/config/x86 | 2 + .../generic/614-netfilter_nat_h323.patch | 821 ++++++++++++++++++ 3 files changed, 825 insertions(+) create mode 100644 openwrt/target/linux/linux-2.4/patches/generic/614-netfilter_nat_h323.patch diff --git a/openwrt/target/linux/linux-2.4/config/brcm b/openwrt/target/linux/linux-2.4/config/brcm index 94a9018ec8..8bd18cf14d 100644 --- a/openwrt/target/linux/linux-2.4/config/brcm +++ b/openwrt/target/linux/linux-2.4/config/brcm @@ -363,6 +363,7 @@ CONFIG_IP_NF_MATCH_CONNBYTES=m CONFIG_IP_NF_CT_PROTO_GRE=m CONFIG_IP_NF_PPTP=m CONFIG_IP_NF_SIP=m +CONFIG_IP_NF_H323=m CONFIG_IP_NF_QUEUE=m CONFIG_IP_NF_IPTABLES=y CONFIG_IP_NF_MATCH_LIMIT=m @@ -412,6 +413,7 @@ CONFIG_IP_NF_TARGET_REDIRECT=m CONFIG_IP_NF_TARGET_NETMAP=m CONFIG_IP_NF_NAT_PPTP=m CONFIG_IP_NF_NAT_SIP=m +CONFIG_IP_NF_NAT_H323=m CONFIG_IP_NF_NAT_PROTO_GRE=m CONFIG_IP_NF_NAT_AMANDA=m CONFIG_IP_NF_NAT_SNMP_BASIC=m diff --git a/openwrt/target/linux/linux-2.4/config/x86 b/openwrt/target/linux/linux-2.4/config/x86 index bc139cc3a8..335823199b 100644 --- a/openwrt/target/linux/linux-2.4/config/x86 +++ b/openwrt/target/linux/linux-2.4/config/x86 @@ -287,6 +287,7 @@ CONFIG_IP_NF_MATCH_CONNBYTES=m CONFIG_IP_NF_CT_PROTO_GRE=m CONFIG_IP_NF_PPTP=m CONFIG_IP_NF_SIP=m +CONFIG_IP_NF_H323=m CONFIG_IP_NF_QUEUE=m CONFIG_IP_NF_IPTABLES=y CONFIG_IP_NF_MATCH_LIMIT=m @@ -336,6 +337,7 @@ CONFIG_IP_NF_TARGET_REDIRECT=m CONFIG_IP_NF_TARGET_NETMAP=m CONFIG_IP_NF_NAT_PPTP=m CONFIG_IP_NF_NAT_SIP=m +CONFIG_IP_NF_NAT_H323=m CONFIG_IP_NF_NAT_PROTO_GRE=m CONFIG_IP_NF_NAT_AMANDA=m CONFIG_IP_NF_NAT_SNMP_BASIC=m diff --git a/openwrt/target/linux/linux-2.4/patches/generic/614-netfilter_nat_h323.patch b/openwrt/target/linux/linux-2.4/patches/generic/614-netfilter_nat_h323.patch new file mode 100644 index 0000000000..e5f0dfb342 --- /dev/null +++ b/openwrt/target/linux/linux-2.4/patches/generic/614-netfilter_nat_h323.patch @@ -0,0 +1,821 @@ +diff -urN linux-2.4.32/net/ipv4/netfilter/Config.in linux-2.4.32/net/ipv4/netfilter/Config.in +--- linux-2.4.32/net/ipv4/netfilter/Config.in 2005-12-12 11:13:17.000000000 +0100 ++++ linux-2.4.32/net/ipv4/netfilter/Config.in 2005-12-12 11:18:47.000000000 +0100 +@@ -16,6 +16,7 @@ + dep_tristate ' GRE protocol support' CONFIG_IP_NF_CT_PROTO_GRE $CONFIG_IP_NF_CONNTRACK + dep_tristate ' PPTP protocol support' CONFIG_IP_NF_PPTP $CONFIG_IP_NF_CT_PROTO_GRE + dep_tristate ' SIP protocol support' CONFIG_IP_NF_SIP $CONFIG_IP_NF_CONNTRACK ++ dep_tristate ' H.323 (netmeeting) support' CONFIG_IP_NF_H323 $CONFIG_IP_NF_CONNTRACK + fi + + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then +@@ -112,6 +113,13 @@ + define_tristate CONFIG_IP_NF_NAT_SIP $CONFIG_IP_NF_NAT + fi + fi ++ if [ "$CONFIG_IP_NF_H323" = "m" ]; then ++ define_tristate CONFIG_IP_NF_NAT_H323 m ++ else ++ if [ "$CONFIG_IP_NF_H323" = "y" ]; then ++ define_tristate CONFIG_IP_NF_NAT_H323 $CONFIG_IP_NF_NAT ++ fi ++ fi + if [ "$CONFIG_IP_NF_AMANDA" = "m" ]; then + define_tristate CONFIG_IP_NF_NAT_AMANDA m + else +diff -urN linux-2.4.32/net/ipv4/netfilter/Makefile linux-2.4.32/net/ipv4/netfilter/Makefile +--- linux-2.4.32/net/ipv4/netfilter/Makefile 2005-12-12 11:13:17.000000000 +0100 ++++ linux-2.4.32/net/ipv4/netfilter/Makefile 2005-12-12 11:17:37.000000000 +0100 +@@ -57,6 +57,10 @@ + ifdef CONFIG_IP_NF_NAT_SIP + export-objs += ip_conntrack_sip.o + endif ++obj-$(CONFIG_IP_NF_H323) += ip_conntrack_h323.o ++ifdef CONFIG_IP_NF_NAT_H323 ++ export-objs += ip_conntrack_h323.o ++endif + + + # NAT helpers +@@ -67,6 +71,7 @@ + obj-$(CONFIG_IP_NF_NAT_PROTO_GRE) += ip_nat_proto_gre.o + obj-$(CONFIG_IP_NF_NAT_PPTP) += ip_nat_pptp.o + obj-$(CONFIG_IP_NF_NAT_SIP) += ip_nat_sip.o ++obj-$(CONFIG_IP_NF_NAT_H323) += ip_nat_h323.o + + # generic IP tables + obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o +diff -urN linux-2.4.32/net/ipv4/netfilter/ip_conntrack_h323.c linux-2.4.32/net/ipv4/netfilter/ip_conntrack_h323.c +--- linux-2.4.32/net/ipv4/netfilter/ip_conntrack_h323.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.32/net/ipv4/netfilter/ip_conntrack_h323.c 2005-12-12 11:14:54.000000000 +0100 +@@ -0,0 +1,302 @@ ++/* ++ * H.323 'brute force' extension for H.323 connection tracking. ++ * Jozsef Kadlecsik ++ * ++ * Based on ip_masq_h323.c for 2.2 kernels from CoRiTel, Sofia project. ++ * (http://www.coritel.it/projects/sofia/nat/) ++ * Uses Sampsa Ranta's excellent idea on using expectfn to 'bind' ++ * the unregistered helpers to the conntrack entries. ++ */ ++ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++MODULE_AUTHOR("Jozsef Kadlecsik "); ++MODULE_DESCRIPTION("H.323 'brute force' connection tracking module"); ++MODULE_LICENSE("GPL"); ++ ++DECLARE_LOCK(ip_h323_lock); ++struct module *ip_conntrack_h323 = THIS_MODULE; ++ ++#define DEBUGP(format, args...) ++ ++static int h245_help(const struct iphdr *iph, size_t len, ++ struct ip_conntrack *ct, ++ enum ip_conntrack_info ctinfo) ++{ ++ struct tcphdr *tcph = (void *)iph + iph->ihl * 4; ++ unsigned char *data = (unsigned char *) tcph + tcph->doff * 4; ++ unsigned char *data_limit; ++ u_int32_t tcplen = len - iph->ihl * 4; ++ u_int32_t datalen = tcplen - tcph->doff * 4; ++ int dir = CTINFO2DIR(ctinfo); ++ struct ip_ct_h225_master *info = &ct->help.ct_h225_info; ++ struct ip_conntrack_expect expect, *exp = &expect; ++ struct ip_ct_h225_expect *exp_info = &exp->help.exp_h225_info; ++ u_int16_t data_port; ++ u_int32_t data_ip; ++ unsigned int i; ++ ++ DEBUGP("ct_h245_help: help entered %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n", ++ NIPQUAD(iph->saddr), ntohs(tcph->source), ++ NIPQUAD(iph->daddr), ntohs(tcph->dest)); ++ ++ /* Can't track connections formed before we registered */ ++ if (!info) ++ return NF_ACCEPT; ++ ++ /* Until there's been traffic both ways, don't look in packets. */ ++ if (ctinfo != IP_CT_ESTABLISHED ++ && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) { ++ DEBUGP("ct_h245_help: Conntrackinfo = %u\n", ctinfo); ++ return NF_ACCEPT; ++ } ++ ++ /* Not whole TCP header or too short packet? */ ++ if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4 + 5) { ++ DEBUGP("ct_h245_help: tcplen = %u\n", (unsigned)tcplen); ++ return NF_ACCEPT; ++ } ++ ++ /* Checksum invalid? Ignore. */ ++ if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr, ++ csum_partial((char *)tcph, tcplen, 0))) { ++ DEBUGP("ct_h245_help: bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n", ++ tcph, tcplen, NIPQUAD(iph->saddr), ++ NIPQUAD(iph->daddr)); ++ return NF_ACCEPT; ++ } ++ ++ data_limit = (unsigned char *) data + datalen; ++ /* bytes: 0123 45 ++ ipadrr port */ ++ for (i = 0; data < (data_limit - 5); data++, i++) { ++ memcpy(&data_ip, data, sizeof(u_int32_t)); ++ if (data_ip == iph->saddr) { ++ memcpy(&data_port, data + 4, sizeof(u_int16_t)); ++ memset(&expect, 0, sizeof(expect)); ++ /* update the H.225 info */ ++ DEBUGP("ct_h245_help: new RTCP/RTP requested %u.%u.%u.%u:->%u.%u.%u.%u:%u\n", ++ NIPQUAD(ct->tuplehash[!dir].tuple.src.ip), ++ NIPQUAD(iph->saddr), ntohs(data_port)); ++ LOCK_BH(&ip_h323_lock); ++ info->is_h225 = H225_PORT + 1; ++ exp_info->port = data_port; ++ exp_info->dir = dir; ++ exp_info->offset = i; ++ ++ exp->seq = ntohl(tcph->seq) + i; ++ ++ exp->tuple = ((struct ip_conntrack_tuple) ++ { { ct->tuplehash[!dir].tuple.src.ip, ++ { 0 } }, ++ { data_ip, ++ { data_port }, ++ IPPROTO_UDP }}); ++ exp->mask = ((struct ip_conntrack_tuple) ++ { { 0xFFFFFFFF, { 0 } }, ++ { 0xFFFFFFFF, { 0xFFFF }, 0xFFFF }}); ++ ++ exp->expectfn = NULL; ++ ++ /* Ignore failure; should only happen with NAT */ ++ ip_conntrack_expect_related(ct, exp); ++ ++ UNLOCK_BH(&ip_h323_lock); ++ } ++ } ++ ++ return NF_ACCEPT; ++ ++} ++ ++/* H.245 helper is not registered! */ ++static struct ip_conntrack_helper h245 = ++ { { NULL, NULL }, ++ "H.245", /* name */ ++ IP_CT_HELPER_F_REUSE_EXPECT, /* flags */ ++ NULL, /* module */ ++ 8, /* max_ expected */ ++ 240, /* timeout */ ++ { { 0, { 0 } }, /* tuple */ ++ { 0, { 0 }, IPPROTO_TCP } }, ++ { { 0, { 0xFFFF } }, /* mask */ ++ { 0, { 0 }, 0xFFFF } }, ++ h245_help /* helper */ ++ }; ++ ++static int h225_expect(struct ip_conntrack *ct) ++{ ++ WRITE_LOCK(&ip_conntrack_lock); ++ ct->helper = &h245; ++ DEBUGP("h225_expect: helper for %p added\n", ct); ++ WRITE_UNLOCK(&ip_conntrack_lock); ++ ++ return NF_ACCEPT; /* unused */ ++} ++ ++static int h225_help(const struct iphdr *iph, size_t len, ++ struct ip_conntrack *ct, ++ enum ip_conntrack_info ctinfo) ++{ ++ struct tcphdr *tcph = (void *)iph + iph->ihl * 4; ++ unsigned char *data = (unsigned char *) tcph + tcph->doff * 4; ++ unsigned char *data_limit; ++ u_int32_t tcplen = len - iph->ihl * 4; ++ u_int32_t datalen = tcplen - tcph->doff * 4; ++ int dir = CTINFO2DIR(ctinfo); ++ struct ip_ct_h225_master *info = &ct->help.ct_h225_info; ++ struct ip_conntrack_expect expect, *exp = &expect; ++ struct ip_ct_h225_expect *exp_info = &exp->help.exp_h225_info; ++ u_int16_t data_port; ++ u_int32_t data_ip; ++ unsigned int i; ++ ++ DEBUGP("ct_h225_help: help entered %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n", ++ NIPQUAD(iph->saddr), ntohs(tcph->source), ++ NIPQUAD(iph->daddr), ntohs(tcph->dest)); ++ ++ /* Can't track connections formed before we registered */ ++ if (!info) ++ return NF_ACCEPT; ++ ++ /* Until there's been traffic both ways, don't look in packets. */ ++ if (ctinfo != IP_CT_ESTABLISHED ++ && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) { ++ DEBUGP("ct_h225_help: Conntrackinfo = %u\n", ctinfo); ++ return NF_ACCEPT; ++ } ++ ++ /* Not whole TCP header or too short packet? */ ++ if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4 + 5) { ++ DEBUGP("ct_h225_help: tcplen = %u\n", (unsigned)tcplen); ++ return NF_ACCEPT; ++ } ++ ++ /* Checksum invalid? Ignore. */ ++ if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr, ++ csum_partial((char *)tcph, tcplen, 0))) { ++ DEBUGP("ct_h225_help: bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n", ++ tcph, tcplen, NIPQUAD(iph->saddr), ++ NIPQUAD(iph->daddr)); ++ return NF_ACCEPT; ++ } ++ ++ data_limit = (unsigned char *) data + datalen; ++ /* bytes: 0123 45 ++ ipadrr port */ ++ for (i = 0; data < (data_limit - 5); data++, i++) { ++ memcpy(&data_ip, data, sizeof(u_int32_t)); ++ if (data_ip == iph->saddr) { ++ memcpy(&data_port, data + 4, sizeof(u_int16_t)); ++ if (data_port == tcph->source) { ++ /* Signal address */ ++ DEBUGP("ct_h225_help: sourceCallSignalAddress from %u.%u.%u.%u\n", ++ NIPQUAD(iph->saddr)); ++ /* Update the H.225 info so that NAT can mangle the address/port ++ even when we have no expected connection! */ ++#ifdef CONFIG_IP_NF_NAT_NEEDED ++ LOCK_BH(&ip_h323_lock); ++ info->dir = dir; ++ info->seq[IP_CT_DIR_ORIGINAL] = ntohl(tcph->seq) + i; ++ info->offset[IP_CT_DIR_ORIGINAL] = i; ++ UNLOCK_BH(&ip_h323_lock); ++#endif ++ } else { ++ memset(&expect, 0, sizeof(expect)); ++ ++ /* update the H.225 info */ ++ LOCK_BH(&ip_h323_lock); ++ info->is_h225 = H225_PORT; ++ exp_info->port = data_port; ++ exp_info->dir = dir; ++ exp_info->offset = i; ++ ++ exp->seq = ntohl(tcph->seq) + i; ++ ++ exp->tuple = ((struct ip_conntrack_tuple) ++ { { ct->tuplehash[!dir].tuple.src.ip, ++ { 0 } }, ++ { data_ip, ++ { data_port }, ++ IPPROTO_TCP }}); ++ exp->mask = ((struct ip_conntrack_tuple) ++ { { 0xFFFFFFFF, { 0 } }, ++ { 0xFFFFFFFF, { 0xFFFF }, 0xFFFF }}); ++ ++ exp->expectfn = h225_expect; ++ ++ /* Ignore failure */ ++ ip_conntrack_expect_related(ct, exp); ++ ++ DEBUGP("ct_h225_help: new H.245 requested %u.%u.%u.%u->%u.%u.%u.%u:%u\n", ++ NIPQUAD(ct->tuplehash[!dir].tuple.src.ip), ++ NIPQUAD(iph->saddr), ntohs(data_port)); ++ ++ UNLOCK_BH(&ip_h323_lock); ++ } ++#ifdef CONFIG_IP_NF_NAT_NEEDED ++ } else if (data_ip == iph->daddr) { ++ memcpy(&data_port, data + 4, sizeof(u_int16_t)); ++ if (data_port == tcph->dest) { ++ /* Signal address */ ++ DEBUGP("ct_h225_help: destCallSignalAddress %u.%u.%u.%u\n", ++ NIPQUAD(iph->daddr)); ++ /* Update the H.225 info so that NAT can mangle the address/port ++ even when we have no expected connection! */ ++ LOCK_BH(&ip_h323_lock); ++ info->dir = dir; ++ info->seq[IP_CT_DIR_REPLY] = ntohl(tcph->seq) + i; ++ info->offset[IP_CT_DIR_REPLY] = i; ++ UNLOCK_BH(&ip_h323_lock); ++ } ++#endif ++ } ++ } ++ ++ return NF_ACCEPT; ++ ++} ++ ++static struct ip_conntrack_helper h225 = ++ { { NULL, NULL }, ++ "H.225", /* name */ ++ IP_CT_HELPER_F_REUSE_EXPECT, /* flags */ ++ THIS_MODULE, /* module */ ++ 2, /* max_expected */ ++ 240, /* timeout */ ++ { { 0, { __constant_htons(H225_PORT) } }, /* tuple */ ++ { 0, { 0 }, IPPROTO_TCP } }, ++ { { 0, { 0xFFFF } }, /* mask */ ++ { 0, { 0 }, 0xFFFF } }, ++ h225_help /* helper */ ++ }; ++ ++static int __init init(void) ++{ ++ return ip_conntrack_helper_register(&h225); ++} ++ ++static void __exit fini(void) ++{ ++ /* Unregister H.225 helper */ ++ ip_conntrack_helper_unregister(&h225); ++} ++ ++#ifdef CONFIG_IP_NF_NAT_NEEDED ++EXPORT_SYMBOL(ip_h323_lock); ++#endif ++ ++module_init(init); ++module_exit(fini); +diff -urN linux-2.4.32/net/ipv4/netfilter/ip_nat_h323.c /linux-2.4.32/net/ipv4/netfilter/ip_nat_h323.c +--- linux-2.4.32/net/ipv4/netfilter/ip_nat_h323.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.32/net/ipv4/netfilter/ip_nat_h323.c 2005-12-12 11:14:54.000000000 +0100 +@@ -0,0 +1,403 @@ ++/* ++ * H.323 'brute force' extension for NAT alteration. ++ * Jozsef Kadlecsik ++ * ++ * Based on ip_masq_h323.c for 2.2 kernels from CoRiTel, Sofia project. ++ * (http://www.coritel.it/projects/sofia/nat.html) ++ * Uses Sampsa Ranta's excellent idea on using expectfn to 'bind' ++ * the unregistered helpers to the conntrack entries. ++ */ ++ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++MODULE_AUTHOR("Jozsef Kadlecsik "); ++MODULE_DESCRIPTION("H.323 'brute force' connection tracking module"); ++MODULE_LICENSE("GPL"); ++ ++DECLARE_LOCK_EXTERN(ip_h323_lock); ++struct module *ip_nat_h323 = THIS_MODULE; ++ ++#define DEBUGP(format, args...) ++ ++ ++static unsigned int ++h225_nat_expected(struct sk_buff **pskb, ++ unsigned int hooknum, ++ struct ip_conntrack *ct, ++ struct ip_nat_info *info); ++ ++static unsigned int h225_nat_help(struct ip_conntrack *ct, ++ struct ip_conntrack_expect *exp, ++ struct ip_nat_info *info, ++ enum ip_conntrack_info ctinfo, ++ unsigned int hooknum, ++ struct sk_buff **pskb); ++ ++static struct ip_nat_helper h245 = ++ { { NULL, NULL }, ++ "H.245", /* name */ ++ 0, /* flags */ ++ NULL, /* module */ ++ { { 0, { 0 } }, /* tuple */ ++ { 0, { 0 }, IPPROTO_TCP } }, ++ { { 0, { 0xFFFF } }, /* mask */ ++ { 0, { 0 }, 0xFFFF } }, ++ h225_nat_help, /* helper */ ++ h225_nat_expected /* expectfn */ ++ }; ++ ++static unsigned int ++h225_nat_expected(struct sk_buff **pskb, ++ unsigned int hooknum, ++ struct ip_conntrack *ct, ++ struct ip_nat_info *info) ++{ ++ struct ip_nat_multi_range mr; ++ u_int32_t newdstip, newsrcip, newip; ++ u_int16_t port; ++ struct ip_ct_h225_expect *exp_info; ++ struct ip_ct_h225_master *master_info; ++ struct ip_conntrack *master = master_ct(ct); ++ unsigned int is_h225, ret; ++ ++ IP_NF_ASSERT(info); ++ IP_NF_ASSERT(master); ++ ++ IP_NF_ASSERT(!(info->initialized & (1<master->expectant->help.ct_h225_info; ++ exp_info = &ct->master->help.exp_h225_info; ++ ++ LOCK_BH(&ip_h323_lock); ++ ++ DEBUGP("master: "); ++ DUMP_TUPLE(&master->tuplehash[IP_CT_DIR_ORIGINAL].tuple); ++ DUMP_TUPLE(&master->tuplehash[IP_CT_DIR_REPLY].tuple); ++ DEBUGP("conntrack: "); ++ DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); ++ if (exp_info->dir == IP_CT_DIR_ORIGINAL) { ++ /* Make connection go to the client. */ ++ newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; ++ newsrcip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip; ++ DEBUGP("h225_nat_expected: %u.%u.%u.%u->%u.%u.%u.%u (to client)\n", ++ NIPQUAD(newsrcip), NIPQUAD(newdstip)); ++ } else { ++ /* Make the connection go to the server */ ++ newdstip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip; ++ newsrcip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; ++ DEBUGP("h225_nat_expected: %u.%u.%u.%u->%u.%u.%u.%u (to server)\n", ++ NIPQUAD(newsrcip), NIPQUAD(newdstip)); ++ } ++ port = exp_info->port; ++ is_h225 = master_info->is_h225 == H225_PORT; ++ UNLOCK_BH(&ip_h323_lock); ++ ++ if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC) ++ newip = newsrcip; ++ else ++ newip = newdstip; ++ ++ DEBUGP("h225_nat_expected: IP to %u.%u.%u.%u\n", NIPQUAD(newip)); ++ ++ mr.rangesize = 1; ++ /* We don't want to manip the per-protocol, just the IPs... */ ++ mr.range[0].flags = IP_NAT_RANGE_MAP_IPS; ++ mr.range[0].min_ip = mr.range[0].max_ip = newip; ++ ++ /* ... unless we're doing a MANIP_DST, in which case, make ++ sure we map to the correct port */ ++ if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST) { ++ mr.range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED; ++ mr.range[0].min = mr.range[0].max ++ = ((union ip_conntrack_manip_proto) ++ { port }); ++ } ++ ++ ret = ip_nat_setup_info(ct, &mr, hooknum); ++ ++ if (is_h225) { ++ DEBUGP("h225_nat_expected: H.225, setting NAT helper for %p\n", ct); ++ /* NAT expectfn called with ip_nat_lock write-locked */ ++ info->helper = &h245; ++ } ++ return ret; ++} ++ ++static int h323_signal_address_fixup(struct ip_conntrack *ct, ++ struct sk_buff **pskb, ++ enum ip_conntrack_info ctinfo) ++{ ++ struct iphdr *iph = (*pskb)->nh.iph; ++ struct tcphdr *tcph = (void *)iph + iph->ihl*4; ++ unsigned char *data; ++ u_int32_t tcplen = (*pskb)->len - iph->ihl*4; ++ u_int32_t datalen = tcplen - tcph->doff*4; ++ struct ip_ct_h225_master *info = &ct->help.ct_h225_info; ++ u_int32_t newip; ++ u_int16_t port; ++ u_int8_t buffer[6]; ++ int i; ++ ++ MUST_BE_LOCKED(&ip_h323_lock); ++ ++ DEBUGP("h323_signal_address_fixup: %s %s\n", ++ between(info->seq[IP_CT_DIR_ORIGINAL], ntohl(tcph->seq), ntohl(tcph->seq) + datalen) ++ ? "yes" : "no", ++ between(info->seq[IP_CT_DIR_REPLY], ntohl(tcph->seq), ntohl(tcph->seq) + datalen) ++ ? "yes" : "no"); ++ if (!(between(info->seq[IP_CT_DIR_ORIGINAL], ntohl(tcph->seq), ntohl(tcph->seq) + datalen) ++ || between(info->seq[IP_CT_DIR_REPLY], ntohl(tcph->seq), ntohl(tcph->seq) + datalen))) ++ return 1; ++ ++ DEBUGP("h323_signal_address_fixup: offsets %u + 6 and %u + 6 in %u\n", ++ info->offset[IP_CT_DIR_ORIGINAL], ++ info->offset[IP_CT_DIR_REPLY], ++ tcplen); ++ DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); ++ DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple); ++ ++ for (i = 0; i < IP_CT_DIR_MAX; i++) { ++ DEBUGP("h323_signal_address_fixup: %s %s\n", ++ info->dir == IP_CT_DIR_ORIGINAL ? "original" : "reply", ++ i == IP_CT_DIR_ORIGINAL ? "caller" : "callee"); ++ if (!between(info->seq[i], ntohl(tcph->seq), ++ ntohl(tcph->seq) + datalen)) ++ continue; ++ if (!between(info->seq[i] + 6, ntohl(tcph->seq), ++ ntohl(tcph->seq) + datalen)) { ++ /* Partial retransmisison. It's a cracker being funky. */ ++ if (net_ratelimit()) { ++ printk("H.323_NAT: partial packet %u/6 in %u/%u\n", ++ info->seq[i], ++ ntohl(tcph->seq), ++ ntohl(tcph->seq) + datalen); ++ } ++ return 0; ++ } ++ ++ /* Change address inside packet to match way we're mapping ++ this connection. */ ++ if (i == IP_CT_DIR_ORIGINAL) { ++ newip = ct->tuplehash[!info->dir].tuple.dst.ip; ++ port = ct->tuplehash[!info->dir].tuple.dst.u.tcp.port; ++ } else { ++ newip = ct->tuplehash[!info->dir].tuple.src.ip; ++ port = ct->tuplehash[!info->dir].tuple.src.u.tcp.port; ++ } ++ ++ data = (char *) tcph + tcph->doff * 4 + info->offset[i]; ++ ++ DEBUGP("h323_signal_address_fixup: orig %s IP:port %u.%u.%u.%u:%u\n", ++ i == IP_CT_DIR_ORIGINAL ? "source" : "dest ", ++ data[0], data[1], data[2], data[3], ++ (data[4] << 8 | data[5])); ++ ++ /* Modify the packet */ ++ memcpy(buffer, &newip, 4); ++ memcpy(buffer + 4, &port, 2); ++ if (!ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, info->offset[i], ++ 6, buffer, 6)) ++ return 0; ++ ++ DEBUGP("h323_signal_address_fixup: new %s IP:port %u.%u.%u.%u:%u\n", ++ i == IP_CT_DIR_ORIGINAL ? "source" : "dest ", ++ data[0], data[1], data[2], data[3], ++ (data[4] << 8 | data[5])); ++ } ++ ++ return 1; ++} ++ ++static int h323_data_fixup(struct ip_ct_h225_expect *info, ++ struct ip_conntrack *ct, ++ struct sk_buff **pskb, ++ enum ip_conntrack_info ctinfo, ++ struct ip_conntrack_expect *expect) ++{ ++ u_int32_t newip; ++ u_int16_t port; ++ u_int8_t buffer[6]; ++ struct ip_conntrack_tuple newtuple; ++ struct iphdr *iph = (*pskb)->nh.iph; ++ struct tcphdr *tcph = (void *)iph + iph->ihl*4; ++ unsigned char *data; ++ u_int32_t tcplen = (*pskb)->len - iph->ihl*4; ++ struct ip_ct_h225_master *master_info = &ct->help.ct_h225_info; ++ int is_h225; ++ ++ MUST_BE_LOCKED(&ip_h323_lock); ++ DEBUGP("h323_data_fixup: offset %u + 6 in %u\n", info->offset, tcplen); ++ DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); ++ DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple); ++ ++ if (!between(expect->seq + 6, ntohl(tcph->seq), ++ ntohl(tcph->seq) + tcplen - tcph->doff * 4)) { ++ /* Partial retransmisison. It's a cracker being funky. */ ++ if (net_ratelimit()) { ++ printk("H.323_NAT: partial packet %u/6 in %u/%u\n", ++ expect->seq, ++ ntohl(tcph->seq), ++ ntohl(tcph->seq) + tcplen - tcph->doff * 4); ++ } ++ return 0; ++ } ++ ++ /* Change address inside packet to match way we're mapping ++ this connection. */ ++ if (info->dir == IP_CT_DIR_REPLY) { ++ /* Must be where client thinks server is */ ++ newip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip; ++ /* Expect something from client->server */ ++ newtuple.src.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; ++ newtuple.dst.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip; ++ } else { ++ /* Must be where server thinks client is */ ++ newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; ++ /* Expect something from server->client */ ++ newtuple.src.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip; ++ newtuple.dst.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; ++ } ++ ++ is_h225 = (master_info->is_h225 == H225_PORT); ++ ++ if (is_h225) { ++ newtuple.dst.protonum = IPPROTO_TCP; ++ newtuple.src.u.tcp.port = expect->tuple.src.u.tcp.port; ++ } else { ++ newtuple.dst.protonum = IPPROTO_UDP; ++ newtuple.src.u.udp.port = expect->tuple.src.u.udp.port; ++ } ++ ++ /* Try to get same port: if not, try to change it. */ ++ for (port = ntohs(info->port); port != 0; port++) { ++ if (is_h225) ++ newtuple.dst.u.tcp.port = htons(port); ++ else ++ newtuple.dst.u.udp.port = htons(port); ++ ++ if (ip_conntrack_change_expect(expect, &newtuple) == 0) ++ break; ++ } ++ if (port == 0) { ++ DEBUGP("h323_data_fixup: no free port found!\n"); ++ return 0; ++ } ++ ++ port = htons(port); ++ ++ data = (char *) tcph + tcph->doff * 4 + info->offset; ++ ++ DEBUGP("h323_data_fixup: orig IP:port %u.%u.%u.%u:%u\n", ++ data[0], data[1], data[2], data[3], ++ (data[4] << 8 | data[5])); ++ ++ /* Modify the packet */ ++ memcpy(buffer, &newip, 4); ++ memcpy(buffer + 4, &port, 2); ++ if (!ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, info->offset, ++ 6, buffer, 6)) ++ return 0; ++ ++ DEBUGP("h323_data_fixup: new IP:port %u.%u.%u.%u:%u\n", ++ data[0], data[1], data[2], data[3], ++ (data[4] << 8 | data[5])); ++ ++ return 1; ++} ++ ++static unsigned int h225_nat_help(struct ip_conntrack *ct, ++ struct ip_conntrack_expect *exp, ++ struct ip_nat_info *info, ++ enum ip_conntrack_info ctinfo, ++ unsigned int hooknum, ++ struct sk_buff **pskb) ++{ ++ int dir; ++ struct ip_ct_h225_expect *exp_info; ++ ++ /* Only mangle things once: original direction in POST_ROUTING ++ and reply direction on PRE_ROUTING. */ ++ dir = CTINFO2DIR(ctinfo); ++ DEBUGP("nat_h323: dir %s at hook %s\n", ++ dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY", ++ hooknum == NF_IP_POST_ROUTING ? "POSTROUTING" ++ : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING" ++ : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???"); ++ if (!((hooknum == NF_IP_POST_ROUTING && dir == IP_CT_DIR_ORIGINAL) ++ || (hooknum == NF_IP_PRE_ROUTING && dir == IP_CT_DIR_REPLY))) { ++ DEBUGP("nat_h323: Not touching dir %s at hook %s\n", ++ dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY", ++ hooknum == NF_IP_POST_ROUTING ? "POSTROUTING" ++ : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING" ++ : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???"); ++ return NF_ACCEPT; ++ } ++ ++ if (!exp) { ++ LOCK_BH(&ip_h323_lock); ++ if (!h323_signal_address_fixup(ct, pskb, ctinfo)) { ++ UNLOCK_BH(&ip_h323_lock); ++ return NF_DROP; ++ } ++ UNLOCK_BH(&ip_h323_lock); ++ return NF_ACCEPT; ++ } ++ ++ exp_info = &exp->help.exp_h225_info; ++ ++ LOCK_BH(&ip_h323_lock); ++ if (!h323_data_fixup(exp_info, ct, pskb, ctinfo, exp)) { ++ UNLOCK_BH(&ip_h323_lock); ++ return NF_DROP; ++ } ++ UNLOCK_BH(&ip_h323_lock); ++ ++ return NF_ACCEPT; ++} ++ ++static struct ip_nat_helper h225 = ++ { { NULL, NULL }, ++ "H.225", /* name */ ++ IP_NAT_HELPER_F_ALWAYS, /* flags */ ++ THIS_MODULE, /* module */ ++ { { 0, { __constant_htons(H225_PORT) } }, /* tuple */ ++ { 0, { 0 }, IPPROTO_TCP } }, ++ { { 0, { 0xFFFF } }, /* mask */ ++ { 0, { 0 }, 0xFFFF } }, ++ h225_nat_help, /* helper */ ++ h225_nat_expected /* expectfn */ ++ }; ++ ++static int __init init(void) ++{ ++ int ret; ++ ++ ret = ip_nat_helper_register(&h225); ++ ++ if (ret != 0) ++ printk("ip_nat_h323: cannot initialize the module!\n"); ++ ++ return ret; ++} ++ ++static void __exit fini(void) ++{ ++ ip_nat_helper_unregister(&h225); ++} ++ ++module_init(init); ++module_exit(fini); +diff -urN linux-2.4.32/include/linux/netfilter_ipv4/ip_conntrack.h linux-2.4.32/include/linux/netfilter_ipv4/ip_conntrack.h +--- linux-2.4.32/include/linux/netfilter_ipv4/ip_conntrack.h 2005-12-12 11:13:17.000000000 +0100 ++++ linux-2.4.32/include/linux/netfilter_ipv4/ip_conntrack.h 2005-12-12 11:16:13.000000000 +0100 +@@ -72,6 +72,7 @@ + #include + #include + #include ++#include + + /* per expectation: application helper private data */ + union ip_conntrack_expect_help { +@@ -81,6 +82,7 @@ + struct ip_ct_irc_expect exp_irc_info; + struct ip_ct_pptp_expect exp_pptp_info; + struct ip_ct_sip_expect exp_sip_info; ++ struct ip_ct_h225_expect exp_h225_info; + + #ifdef CONFIG_IP_NF_NAT_NEEDED + union { +@@ -96,6 +98,7 @@ + struct ip_ct_irc_master ct_irc_info; + struct ip_ct_pptp_master ct_pptp_info; + struct ip_ct_sip_master ct_sip_info; ++ struct ip_ct_h225_master ct_h225_info; + }; + + #ifdef CONFIG_IP_NF_NAT_NEEDED +diff -urN linux-2.4.32/include/linux/netfilter_ipv4/ip_conntrack_h323.h linux-2.4.32/include/linux/netfilter_ipv4/ip_conntrack_h323.h +--- linux-2.4.32/include/linux/netfilter_ipv4/ip_conntrack_h323.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.32/include/linux/netfilter_ipv4/ip_conntrack_h323.h 2005-12-12 11:14:54.000000000 +0100 +@@ -0,0 +1,30 @@ ++#ifndef _IP_CONNTRACK_H323_H ++#define _IP_CONNTRACK_H323_H ++/* H.323 connection tracking. */ ++ ++#ifdef __KERNEL__ ++/* Protects H.323 related data */ ++DECLARE_LOCK_EXTERN(ip_h323_lock); ++#endif ++ ++/* Default H.225 port */ ++#define H225_PORT 1720 ++ ++/* This structure is per expected connection */ ++struct ip_ct_h225_expect { ++ u_int16_t port; /* Port of the H.225 helper/RTCP/RTP channel */ ++ enum ip_conntrack_dir dir; /* Direction of the original connection */ ++ unsigned int offset; /* offset of the address in the payload */ ++}; ++ ++/* This structure exists only once per master */ ++struct ip_ct_h225_master { ++ int is_h225; /* H.225 or H.245 connection */ ++#ifdef CONFIG_IP_NF_NAT_NEEDED ++ enum ip_conntrack_dir dir; /* Direction of the original connection */ ++ u_int32_t seq[IP_CT_DIR_MAX]; /* Exceptional packet mangling for signal addressess... */ ++ unsigned int offset[IP_CT_DIR_MAX]; /* ...and the offset of the addresses in the payload */ ++#endif ++}; ++ ++#endif /* _IP_CONNTRACK_H323_H */ -- 2.30.2