From: Max Kellermann <max@duempel.org>
To: netfilter-devel@lists.netfilter.org
Subject: [PATCH pom-ng] H.225 parser for h323-conntrack-nat
Date: Thu, 17 Mar 2005 04:24:05 +0100 [thread overview]
Message-ID: <20050317032405.GA7200@roonstrasse.net> (raw)
[-- Attachment #1: Type: text/plain, Size: 833 bytes --]
Hi,
this patch implements a "real" H.225 parser, replacing the old "brute
force" algorithm. This parser is not complete yet; it currently only
handles CONNECT packets, although that seems to be enough for most
H.323 clients. I tested with ohphone, MS Netmeeting and gnomemeeting
(plus a nfsim test which I will publish soon). NAT works well.
I havn't written a H.245 parser yet, that's the next item on my todo
list.
The attached patch applies to the pom-ng trunk after you merged my
last patches from the linux-2.6.11 branch:
cd h323-conntrack-nat/linux-2.6.11
svn merge -r 3689:3690 \
https://svn.netfilter.org/netfilter/branches/patch-o-matic-ng/linux-2.6.11/h323-conntrack-nat/linux-2.6
(I guess the linux-2.6.11 branch is obsolete since the
h323-conntrack-nat/linux-2.6.11 directory was introduced by Harald)
Max
[-- Attachment #2: h323_parse_h225_no_bruteforce.patch --]
[-- Type: text/plain, Size: 8494 bytes --]
Thu Mar 17 04:05:23 CET 2005 max@duempel.org
* replaced brute force by a H.225 parser, still incomplete
diff -rN -u old-h323-7/h323-conntrack-nat/linux-2.6.11/net/ipv4/netfilter/ip_conntrack_h323.c new-h323-7/h323-conntrack-nat/linux-2.6.11/net/ipv4/netfilter/ip_conntrack_h323.c
--- old-h323-7/h323-conntrack-nat/linux-2.6.11/net/ipv4/netfilter/ip_conntrack_h323.c 2005-03-17 04:07:06.847233824 +0100
+++ new-h323-7/h323-conntrack-nat/linux-2.6.11/net/ipv4/netfilter/ip_conntrack_h323.c 2005-03-17 04:04:05.000000000 +0100
@@ -178,21 +178,204 @@
WRITE_UNLOCK(&ip_conntrack_lock);
}
-/* FIXME: This should be in userspace. Later. */
+/**
+ * Parse a Q.931 CONNECT packet and handle NAT/expectations for the
+ * H.245 transport address.
+ */
+static int h225_parse_q931_connect(struct sk_buff **pskb,
+ struct ip_conntrack *ct,
+ enum ip_conntrack_info ctinfo,
+ const unsigned char *data,
+ unsigned i, unsigned length)
+{
+ int dir = CTINFO2DIR(ctinfo);
+ u_int32_t data_ip;
+ u_int16_t data_port;
+ struct ip_conntrack_expect *exp;
+
+ /* protocol(1) + header(3) + protocolIdentifier(6) +
+ h245ipAddress(1) + h245ipv4(4) + h245ipv4port(2) */
+ if (length < 17)
+ return NF_ACCEPT;
+
+ if (data[i++] != 0x05) /* X.208 / X.209 */
+ return NF_ACCEPT;
+
+ /* XXX: h225 header connect? */
+ if (data[i++] != 0x22 || data[i++] != 0xc0 || data[i++] != 0x06)
+ return NF_ACCEPT;
+
+ /* protocolIdentifier, ignore the last 2 bytes (minor
+ version) */
+ if (memcmp(data + i, "\x00\x08\x91\x4a", 4) != 0)
+ return NF_ACCEPT;
+
+ i += 6;
+
+ if (data[i++] != 0x00) /* h245ipAddress? */
+ return NF_ACCEPT;
+
+ /* compare the IP address - this is only a valid H.245
+ transport address, if it equals the source address of the
+ packet */
+ data_ip = *(u_int32_t *)(data + i);
+ if (data_ip != ct->tuplehash[dir].tuple.src.ip)
+ return NF_ACCEPT;
+
+
+ data_port = *((u_int16_t *)(data + i + 4));
+
+ /* match found: create an expectation */
+ exp = ip_conntrack_expect_alloc();
+ if (exp == NULL)
+ return NF_ACCEPT;
+
+ exp->tuple = ((struct ip_conntrack_tuple)
+ { { ct->tuplehash[!dir].tuple.src.ip,
+ { 0 } },
+ { ct->tuplehash[!dir].tuple.dst.ip,
+ { .tcp = { data_port } },
+ IPPROTO_TCP }});
+ exp->mask = ((struct ip_conntrack_tuple)
+ { { 0xFFFFFFFF, { 0 } },
+ { 0xFFFFFFFF, { .tcp = { 0xFFFF } }, 0xFF }});
+
+ exp->expectfn = h225_expect;
+ exp->master = ct;
+
+ /* call NAT hook and register expectation */
+ if (ip_nat_h225_hook != NULL) {
+ return ip_nat_h225_hook(pskb, ctinfo, i,
+ exp);
+ } else {
+ /* Can't expect this? Best to drop packet now. */
+ if (ip_conntrack_expect_related(exp) != 0) {
+ ip_conntrack_expect_free(exp);
+ return NF_DROP;
+ } else {
+ return NF_ACCEPT;
+ }
+ }
+}
+
+/**
+ * Scan a Q.931 packet for a user-to-user information element
+ * (IE). Return the index, or 0 if none found.
+ */
+static unsigned q931_find_u2u(const unsigned char *data,
+ unsigned datalen,
+ unsigned int i,
+ unsigned *lengthp) {
+ unsigned char type;
+ unsigned length;
+
+ /* traverse all Q.931 information elements (IE) */
+ while (i + 2 <= datalen) {
+ type = data[i++];
+
+ /* highest bit set means one-byte IE */
+ if (type & 0x80)
+ continue;
+
+ length = data[i++];
+
+ if (type == 0x7e) { /* user-to-user */
+ /* user-to-user IEs have a 16 bit length
+ field */
+ length = (length << 8) | data[i++];
+ if (i + length > datalen)
+ return 0;
+
+ *lengthp = length;
+ return i;
+ }
+
+ i += length;
+ }
+
+ return 0;
+}
+
+/**
+ * Parse a Q.931/H.225 packet and handle NAT/expectations for the
+ * H.245 transport address (if applicable).
+ */
+static int h225_parse_q931(struct sk_buff **pskb,
+ struct ip_conntrack *ct,
+ enum ip_conntrack_info ctinfo,
+ const unsigned char *data,
+ unsigned datalen, unsigned i) {
+ u_int8_t q931_message_type;
+ unsigned length;
+
+ /* parse Q.931 packet */
+ if (data[i++] != 0x08) /* protocol discriminator */
+ return NF_ACCEPT;
+
+ /* call reference */
+ i += 1 + data[i];
+ if (i >= datalen)
+ return NF_ACCEPT;
+
+ /* only some Q.931 message types can contain a H.245 transport
+ address - we can ignore the rest in this module */
+ q931_message_type = data[i++];
+ if (q931_message_type == 0x07) {
+ /* CONNECT */
+
+ /* find a user-to-user information element (IE) */
+ i = q931_find_u2u(data, datalen, i, &length);
+ if (i == 0)
+ return NF_ACCEPT;
+
+ return h225_parse_q931_connect(pskb, ct, ctinfo,
+ data, i, length);
+ } else {
+ /* XXX handle q931_message_type 0x01, 0x02, 0x03 */
+ return NF_ACCEPT;
+ }
+}
+
+/**
+ * Parse a TPKT/Q.931/H.225 packet and handle NAT/expectations for the
+ * H.245 transport address (if applicable).
+ */
+static int h225_parse_tpkt(struct sk_buff **pskb,
+ struct ip_conntrack *ct,
+ enum ip_conntrack_info ctinfo,
+ const unsigned char *data,
+ unsigned datalen) {
+ unsigned int i = 0;
+ u_int16_t tpkt_len;
+
+ /* expect TPKT header, see RFC 1006 */
+ if (data[0] != 0x03 || data[1] != 0x00)
+ return NF_ACCEPT;
+
+ i += 2;
+
+ tpkt_len = ntohs(*(u_int16_t*)(data + i));
+ if (tpkt_len < 16)
+ return NF_ACCEPT;
+
+ if (tpkt_len < datalen)
+ datalen = tpkt_len;
+
+ i += 2;
+
+ /* parse Q.931 packet */
+ return h225_parse_q931(pskb, ct, ctinfo,
+ data, datalen, i);
+}
+
static int h225_help(struct sk_buff **pskb,
struct ip_conntrack *ct,
enum ip_conntrack_info ctinfo)
{
struct tcphdr _tcph, *tcph;
unsigned char *data;
- unsigned char *data_limit;
unsigned dataoff, datalen;
- int dir = CTINFO2DIR(ctinfo);
- struct ip_conntrack_expect *exp;
- u_int16_t data_port;
- u_int32_t data_ip;
- unsigned int i;
- int ret;
+ int ret = NF_ACCEPT;
/* Until there's been traffic both ways, don't look in packets. */
if (ctinfo != IP_CT_ESTABLISHED
@@ -218,79 +401,18 @@
}
datalen = (*pskb)->len - dataoff;
+ if (datalen < 32)
+ return NF_ACCEPT;
+
+ /* get data portion, and evaluate it */
LOCK_BH(&ip_h323_lock);
data = skb_header_pointer((*pskb), dataoff,
datalen, h323_buffer);
BUG_ON(data == NULL);
- data_limit = data + datalen - 6;
- /* bytes: 0123 45
- ipadrr port */
- for (i = 0; data <= data_limit; data++, i++) {
- data_ip = *((u_int32_t *)data);
- if (data_ip == ct->tuplehash[dir].tuple.src.ip) {
- data_port = *((u_int16_t *)(data + 4));
- if (data_port == ct->tuplehash[dir].tuple.src.u.tcp.port) {
- /* Signal address */
- DEBUGP("ct_h225_help: sourceCallSignalAddress from %u.%u.%u.%u\n",
- NIPQUAD((*pskb)->nh.iph->saddr));
- /* Update the H.225 info so that NAT can mangle the address/port
- even when we have no expected connection! */
- if (ip_nat_h225_signal_hook != NULL)
- ip_nat_h225_signal_hook(pskb, ct, ctinfo,
- i, IP_CT_DIR_ORIGINAL, dir);
- } else {
- /* update the H.225 info */
- exp = ip_conntrack_expect_alloc();
- if (exp == NULL) {
- ret = NF_ACCEPT;
- goto out;
- }
-
- exp->tuple = ((struct ip_conntrack_tuple)
- { { ct->tuplehash[!dir].tuple.src.ip,
- { 0 } },
- { data_ip,
- { .tcp = { data_port } },
- IPPROTO_TCP }});
- exp->mask = ((struct ip_conntrack_tuple)
- { { 0xFFFFFFFF, { 0 } },
- { 0xFFFFFFFF, { .tcp = { 0xFFFF } }, 0xFF }});
-
- exp->expectfn = h225_expect;
- exp->master = ct;
-
- if (ip_nat_h225_hook != NULL) {
- ret = ip_nat_h225_hook(pskb, ctinfo, i,
- exp);
- } else {
- /* Can't expect this? Best to drop packet now. */
- if (ip_conntrack_expect_related(exp) != 0) {
- ip_conntrack_expect_free(exp);
- ret = NF_DROP;
- } else
- ret = NF_ACCEPT;
- }
- }
-
- break;
- } else if (data_ip == ct->tuplehash[dir].tuple.dst.ip) {
- data_port = *((u_int16_t *)(data + 4));
- if (data_port == ct->tuplehash[dir].tuple.dst.u.tcp.port) {
- /* Signal address */
- DEBUGP("ct_h225_help: destCallSignalAddress %u.%u.%u.%u\n",
- NIPQUAD((*pskb)->nh.iph->daddr));
- /* Update the H.225 info so that NAT can mangle the address/port
- even when we have no expected connection! */
- if (ip_nat_h225_signal_hook != NULL)
- ip_nat_h225_signal_hook(pskb, ct, ctinfo,
- i, IP_CT_DIR_REPLY, dir);
- }
- }
- }
+ ret = h225_parse_tpkt(pskb, ct, ctinfo,
+ data, datalen);
- ret = NF_ACCEPT;
- out:
UNLOCK_BH(&ip_h323_lock);
return ret;
}
next reply other threads:[~2005-03-17 3:24 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2005-03-17 3:24 Max Kellermann [this message]
2005-04-01 5:58 ` [PATCH pom-ng] H.225 parser for h323-conntrack-nat Harald Welte
2005-04-04 8:07 ` Jozsef Kadlecsik
2005-04-04 9:10 ` Max Kellermann
2005-04-04 9:28 ` Jozsef Kadlecsik
2005-04-04 14:01 ` Wang Jian
2005-04-04 14:06 ` Max Kellermann
2005-04-04 15:04 ` Wang Jian
2005-04-04 15:06 ` Max Kellermann
2005-04-04 15:32 ` Wang Jian
2005-04-04 15:51 ` Max Kellermann
2005-04-04 15:58 ` Wang Jian
2005-04-10 20:41 ` Harald Welte
2005-04-10 21:01 ` Max Kellermann
2005-04-10 21:21 ` Harald Welte
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20050317032405.GA7200@roonstrasse.net \
--to=max@duempel.org \
--cc=netfilter-devel@lists.netfilter.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.