diff options
author | Andreas Baumann <mail@andreasbaumann.cc> | 2015-01-03 12:04:58 +0100 |
---|---|---|
committer | Andreas Baumann <mail@andreasbaumann.cc> | 2015-01-03 12:04:58 +0100 |
commit | 008d0be72b2f160382c6e880765e96b64a050c65 (patch) | |
tree | 36f48a98a3815a408e2ce1693dd182af90f80305 /release/src/linux/linux/net/ipv4/netfilter/ip_conntrack_h323.c | |
parent | 611becfb8726c60cb060368541ad98191d4532f5 (diff) | |
download | tomato-008d0be72b2f160382c6e880765e96b64a050c65.tar.gz tomato-008d0be72b2f160382c6e880765e96b64a050c65.tar.bz2 |
imported original firmware WRT54GL_v4.30.11_11_US
Diffstat (limited to 'release/src/linux/linux/net/ipv4/netfilter/ip_conntrack_h323.c')
-rw-r--r-- | release/src/linux/linux/net/ipv4/netfilter/ip_conntrack_h323.c | 325 |
1 files changed, 325 insertions, 0 deletions
diff --git a/release/src/linux/linux/net/ipv4/netfilter/ip_conntrack_h323.c b/release/src/linux/linux/net/ipv4/netfilter/ip_conntrack_h323.c new file mode 100644 index 00000000..cb0b1da5 --- /dev/null +++ b/release/src/linux/linux/net/ipv4/netfilter/ip_conntrack_h323.c @@ -0,0 +1,325 @@ +/* + * H.323 'brute force' extension for H.323 connection tracking. + * Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> + * + * 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 <linux/module.h> +#include <linux/netfilter.h> +#include <linux/ip.h> +#include <net/checksum.h> +#include <net/tcp.h> + +#include <linux/netfilter_ipv4/lockhelp.h> +#include <linux/netfilter_ipv4/ip_conntrack.h> +#include <linux/netfilter_ipv4/ip_conntrack_core.h> +#include <linux/netfilter_ipv4/ip_conntrack_helper.h> +#include <linux/netfilter_ipv4/ip_conntrack_tuple.h> +#include <linux/netfilter_ipv4/ip_conntrack_h323.h> + +MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); +MODULE_DESCRIPTION("H.323 'brute force' connection tracking module"); +MODULE_LICENSE("GPL"); + +DECLARE_LOCK(ip_h323_lock); +struct module *ip_conntrack_h323 = THIS_MODULE; + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(format, args...) +#endif + +/* FIXME: This should be in userspace. Later. */ +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. */ + /* FIXME: Source route IP option packets --RR */ + 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++) { + data_ip = *((u_int32_t *)data); + if (data_ip == iph->saddr) { + data_port = *((u_int16_t *)(data + 4)); + 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; + + *((u_int32_t *)data) = ct->tuplehash[!dir].tuple.dst.ip; //!!! Netmeeting fix + + { + unsigned int chksum; + + chksum = csum_partial((char *)tcph + tcph->doff*4, + datalen, 0); + + tcph->check = 0; + tcph->check = tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr, + csum_partial((char *)tcph, tcph->doff*4, chksum)); + + } + + + 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 */ +} + +/* FIXME: This should be in userspace. Later. */ +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. */ + /* FIXME: Source route IP option packets --RR */ + 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++) { + data_ip = *((u_int32_t *)data); + if (data_ip == iph->saddr) { + data_port = *((u_int16_t *)(data + 4)); + 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) { + data_port = *((u_int16_t *)(data + 4)); + 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); |