-/*
- * H.323 'brute force' extension for H.323 connection tracking.
+/*
+ * H.323 'brute force' extension for H.323 connection tracking.
* Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
+ * (c) 2005 Max Kellermann <max@duempel.org>
*
* Based on ip_masq_h323.c for 2.2 kernels from CoRiTel, Sofia project.
* (http://www.coritel.it/projects/sofia/nat/)
MODULE_DESCRIPTION("H.323 'brute force' connection tracking module");
MODULE_LICENSE("GPL");
+/* This is slow, but it's simple. --RR */
+static char h323_buffer[65536];
+static DECLARE_LOCK(h323_buffer_lock);
+
DECLARE_LOCK(ip_h323_lock);
struct module *ip_conntrack_h323 = THIS_MODULE;
struct ip_conntrack *ct,
enum ip_conntrack_info ctinfo)
{
- struct tcphdr *tcph = (void *)skb->nh.iph + skb->nh.iph->ihl * 4;
- unsigned char *data = (unsigned char *) tcph + tcph->doff * 4;
+ struct iphdr *iph = skb->nh.iph;
+ struct tcphdr _tcph, *tcph;
+ unsigned char *data;
unsigned char *data_limit;
- u_int32_t tcplen = skb->len - skb->nh.iph->ihl * 4;
- u_int32_t datalen = tcplen - tcph->doff * 4;
+ unsigned dataoff, datalen;
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;
+ struct ip_conntrack_expect *exp;
+ struct ip_ct_h225_expect *exp_info;
u_int16_t data_port;
u_int32_t data_ip;
unsigned int i;
+ int ret;
- 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) {
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);
+ tcph = skb_header_pointer(skb, skb->nh.iph->ihl*4,
+ sizeof(_tcph), &_tcph);
+ if (tcph == NULL)
return NF_ACCEPT;
- }
- /* Checksum invalid? Ignore. */
- /* FIXME: Source route IP option packets --RR */
- if (tcp_v4_check(tcph, tcplen, skb->nh.iph->saddr, skb->nh.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(skb->nh.iph->saddr),
- NIPQUAD(skb->nh.iph->daddr));
+ 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));
+
+ dataoff = skb->nh.iph->ihl*4 + tcph->doff*4;
+ /* No data? */
+ if (dataoff >= skb->len) {
+ DEBUGP("ct_h245_help: skblen = %u\n", skb->len);
return NF_ACCEPT;
}
+ datalen = skb->len - dataoff;
+
+ LOCK_BH(&h323_buffer_lock);
+ data = skb_header_pointer(skb, dataoff,
+ datalen, h323_buffer);
+ BUG_ON(data == NULL);
- data_limit = (unsigned char *) data + datalen;
+ data_limit = data + datalen - 6;
/* bytes: 0123 45
ipadrr port */
- for (i = 0; data < (data_limit - 5); data++, i++) {
+ for (i = 0; data <= data_limit; data++, i++) {
data_ip = *((u_int32_t *)data);
- if (data_ip == skb->nh.iph->saddr) {
+ 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(skb->nh.iph->saddr), ntohs(data_port));
+ NIPQUAD(iph->saddr), ntohs(data_port));
+
+ exp = ip_conntrack_expect_alloc();
+ if (exp == NULL) {
+ ret = NF_ACCEPT;
+ goto out;
+ }
+
+ exp_info = &exp->help.exp_h225_info;
+
LOCK_BH(&ip_h323_lock);
info->is_h225 = H225_PORT + 1;
exp_info->port = data_port;
exp_info->offset = i;
exp->seq = ntohl(tcph->seq) + i;
-
+
exp->tuple = ((struct ip_conntrack_tuple)
{ { ct->tuplehash[!dir].tuple.src.ip,
{ 0 } },
exp->mask = ((struct ip_conntrack_tuple)
{ { 0xFFFFFFFF, { 0 } },
{ 0xFFFFFFFF, { .tcp = { 0xFFFF } }, 0xFFFF }});
-
+
exp->expectfn = NULL;
-
+
/* Ignore failure; should only happen with NAT */
ip_conntrack_expect_related(exp, ct);
}
}
- return NF_ACCEPT;
-
+ ret = NF_ACCEPT;
+ out:
+ UNLOCK_BH(&h323_buffer_lock);
+ return ret;
}
/* H.245 helper is not registered! */
-static struct ip_conntrack_helper h245 =
- { { NULL, NULL },
- name : "H.245", /* name */
- flags: IP_CT_HELPER_F_REUSE_EXPECT, /* flags */
- me: THIS_MODULE, /* module */
- max_expected: 8, /* max_ expected */
- timeout: 240, /* timeout */
- tuple: { { 0, { 0 } }, /* tuple */
- { 0, { 0 }, IPPROTO_TCP } },
- mask: { { 0, { 0xFFFF } }, /* mask */
- { 0, { 0 }, 0xFFFF } },
- h245_help /* helper */
- };
+static struct ip_conntrack_helper h245 = {
+ .name = "H.245",
+ .flags = IP_CT_HELPER_F_REUSE_EXPECT,
+ .max_expected = 8,
+ .timeout = 240,
+ .tuple = { .dst = { .protonum = IPPROTO_TCP } },
+ .mask = { .src = { .u = { 0xFFFF } },
+ .dst = { .protonum = 0xFFFF } },
+ .help = h245_help
+};
static int h225_expect(struct ip_conntrack *ct)
{
ct->helper = &h245;
DEBUGP("h225_expect: helper for %p added\n", ct);
WRITE_UNLOCK(&ip_conntrack_lock);
-
+
return NF_ACCEPT; /* unused */
}
struct ip_conntrack *ct,
enum ip_conntrack_info ctinfo)
{
- struct tcphdr *tcph = (void *)skb->nh.iph + skb->nh.iph->ihl * 4;
- unsigned char *data = (unsigned char *) tcph + tcph->doff * 4;
+ struct iphdr *iph = skb->nh.iph;
+ struct tcphdr _tcph, *tcph;
+ unsigned char *data;
unsigned char *data_limit;
- u_int32_t tcplen = skb->len - skb->nh.iph->ihl * 4;
- u_int32_t datalen = tcplen - tcph->doff * 4;
+ unsigned dataoff, datalen;
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;
+ struct ip_conntrack_expect *exp;
+ struct ip_ct_h225_expect *exp_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(skb->nh.iph->saddr), ntohs(tcph->source),
- NIPQUAD(skb->nh.iph->daddr), ntohs(tcph->dest));
-
- /* Can't track connections formed before we registered */
- if (!info)
- return NF_ACCEPT;
+ int ret;
/* Until there's been traffic both ways, don't look in packets. */
if (ctinfo != IP_CT_ESTABLISHED
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);
+ tcph = skb_header_pointer(skb, skb->nh.iph->ihl*4,
+ sizeof(_tcph), &_tcph);
+ if (tcph == NULL)
return NF_ACCEPT;
- }
- /* Checksum invalid? Ignore. */
- /* FIXME: Source route IP option packets --RR */
- if (tcp_v4_check(tcph, tcplen, skb->nh.iph->saddr, skb->nh.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(skb->nh.iph->saddr),
- NIPQUAD(skb->nh.iph->daddr));
+ 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));
+
+ dataoff = skb->nh.iph->ihl*4 + tcph->doff*4;
+ /* No data? */
+ if (dataoff >= skb->len) {
+ DEBUGP("ct_h225_help: skblen = %u\n", skb->len);
return NF_ACCEPT;
}
-
- data_limit = (unsigned char *) data + datalen;
+ datalen = skb->len - dataoff;
+
+ LOCK_BH(&h323_buffer_lock);
+ data = skb_header_pointer(skb, dataoff,
+ datalen, h323_buffer);
+ BUG_ON(data == NULL);
+
+ data_limit = data + datalen - 6;
/* bytes: 0123 45
ipadrr port */
- for (i = 0; data < (data_limit - 5); data++, i++) {
+ for (i = 0; data <= data_limit; data++, i++) {
data_ip = *((u_int32_t *)data);
- if (data_ip == skb->nh.iph->saddr) {
+ 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(skb->nh.iph->saddr));
+ 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
UNLOCK_BH(&ip_h323_lock);
#endif
} else {
- memset(&expect, 0, sizeof(expect));
-
/* update the H.225 info */
+ exp = ip_conntrack_expect_alloc();
+ if (exp == NULL) {
+ ret = NF_ACCEPT;
+ goto out;
+ }
+
+ exp_info = &exp->help.exp_h225_info;
+
LOCK_BH(&ip_h323_lock);
info->is_h225 = H225_PORT;
exp_info->port = data_port;
exp->mask = ((struct ip_conntrack_tuple)
{ { 0xFFFFFFFF, { 0 } },
{ 0xFFFFFFFF, { .tcp = { 0xFFFF } }, 0xFFFF }});
-
+
exp->expectfn = h225_expect;
-
+
/* Ignore failure */
ip_conntrack_expect_related(exp, ct);
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(skb->nh.iph->saddr), ntohs(data_port));
+ NIPQUAD(iph->saddr), ntohs(data_port));
UNLOCK_BH(&ip_h323_lock);
- }
+ }
#ifdef CONFIG_IP_NF_NAT_NEEDED
- } else if (data_ip == skb->nh.iph->daddr) {
+ } 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(skb->nh.iph->daddr));
+ 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);
}
}
- return NF_ACCEPT;
-
+ ret = NF_ACCEPT;
+ out:
+ UNLOCK_BH(&h323_buffer_lock);
+ return ret;
}
-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 struct ip_conntrack_helper h225 = {
+ .name = "H.225",
+ .flags = IP_CT_HELPER_F_REUSE_EXPECT,
+ .me = THIS_MODULE,
+ .max_expected = 2,
+ .timeout = 240,
+ .tuple = { .src = { .ip = 0,
+ .u = { .tcp = { .port =
+ __constant_htons(H225_PORT) } }
+ },
+ .dst = { .ip = 0,
+ .u = { .all = 0 },
+ .protonum = IPPROTO_TCP
+ }
+ },
+ .mask = { .src = { .ip = 0,
+ .u = { .tcp = { .port = 0xffff } }
+ },
+ .dst = { .ip = 0,
+ .u = { .all = 0 },
+ .protonum = 0xffff
+ }
+ },
+ .help = h225_help
+};
static int __init init(void)
{
+ printk("ip_conntrack_h323: init \n");
return ip_conntrack_helper_register(&h225);
}
static void __exit fini(void)
{
- /* Unregister H.225 helper */
+ /* Unregister H.225 helper */
ip_conntrack_helper_unregister(&h225);
}
EXPORT_SYMBOL(ip_h323_lock);
+PROVIDES_CONNTRACK(h225);
+PROVIDES_CONNTRACK(h245);
module_init(init);
module_exit(fini);