Author: pluto
Date: Fri May 20 12:18:33 2005
New Revision: 6006

Added:
   netfilter-2.6/patch-o-matic-ng/trunk/net/ipv4/netfilter/asn1_per.c
   netfilter-2.6/patch-o-matic-ng/trunk/net/ipv4/netfilter/asn1_per.h
   
netfilter-2.6/patch-o-matic-ng/trunk/net/ipv4/netfilter/ip_conntrack_h323_core.c
   
netfilter-2.6/patch-o-matic-ng/trunk/net/ipv4/netfilter/ip_conntrack_h323_h225.c
   
netfilter-2.6/patch-o-matic-ng/trunk/net/ipv4/netfilter/ip_conntrack_h323_h245.c
Modified:
   
netfilter-2.6/patch-o-matic-ng/trunk/include/linux/netfilter_ipv4/ip_conntrack_h323.h
   netfilter-2.6/patch-o-matic-ng/trunk/net/ipv4/netfilter/Makefile
   netfilter-2.6/patch-o-matic-ng/trunk/net/ipv4/netfilter/ip_conntrack_h323.c
   netfilter-2.6/patch-o-matic-ng/trunk/net/ipv4/netfilter/ip_nat_h323.c
Log:
- h.323 updated (h.225/h.245 support added).


Modified: 
netfilter-2.6/patch-o-matic-ng/trunk/include/linux/netfilter_ipv4/ip_conntrack_h323.h
==============================================================================
--- 
netfilter-2.6/patch-o-matic-ng/trunk/include/linux/netfilter_ipv4/ip_conntrack_h323.h
       (original)
+++ 
netfilter-2.6/patch-o-matic-ng/trunk/include/linux/netfilter_ipv4/ip_conntrack_h323.h
       Fri May 20 12:18:33 2005
@@ -7,13 +7,9 @@
 /* Default H.225 port */
 #define H225_PORT      1720
 
-/* This structure exists only once per master */
-struct ip_ct_h225_master {
-       int dummy;
-};
-
 struct ip_conntrack_expect;
 struct ip_conntrack;
+struct ip_conntrack_helper;
 
 extern int (*ip_nat_h245_hook)(struct sk_buff **pskb,
                               enum ip_conntrack_info ctinfo,
@@ -32,6 +28,8 @@
                                       int dir,
                                       int orig_dir);
 
+extern struct ip_conntrack_helper ip_conntrack_helper_h225;
+
 void ip_conntrack_h245_expect(struct ip_conntrack *new,
                              struct ip_conntrack_expect *this);
 

Modified: netfilter-2.6/patch-o-matic-ng/trunk/net/ipv4/netfilter/Makefile
==============================================================================
--- netfilter-2.6/patch-o-matic-ng/trunk/net/ipv4/netfilter/Makefile    
(original)
+++ netfilter-2.6/patch-o-matic-ng/trunk/net/ipv4/netfilter/Makefile    Fri May 
20 12:18:33 2005
@@ -11,6 +11,7 @@
  
 # H.323 support
 obj-$(CONFIG_IP_NF_H323) += ip_conntrack_h323.o
+ip_conntrack_h323-objs := ip_conntrack_h323_core.o ip_conntrack_h323_h225.o 
ip_conntrack_h323_h245.o asn1_per.o
 obj-$(CONFIG_IP_NF_NAT_H323) += ip_nat_h323.o
 
 # conntrack netlink interface

Added: netfilter-2.6/patch-o-matic-ng/trunk/net/ipv4/netfilter/asn1_per.c
==============================================================================
--- (empty file)
+++ netfilter-2.6/patch-o-matic-ng/trunk/net/ipv4/netfilter/asn1_per.c  Fri May 
20 12:18:33 2005
@@ -0,0 +1,353 @@
+/*
+ * Tiny ASN.1 packet encoding rules (PER) library.
+ *
+ * This is a tiny library which helps parsing ASN.1/PER packets
+ * (i.e. read only). It is meant to be secure and small.
+ *
+ * Warning, this library may still be incomplete and buggy.
+ *
+ * (c) 2005 Max Kellermann <[EMAIL PROTECTED]>
+ */
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+
+#include "asn1_per.h"
+
+void asn1_per_initialize(struct asn1_per_buffer *bb,
+                        const unsigned char *data,
+                        unsigned length, unsigned position) {
+       *bb = (struct asn1_per_buffer){
+               .data = data,
+               .length = length,
+               .i = position,
+               .bit = 8,
+               .error = 0,
+       };
+}
+
+int asn1_per_read_bit(struct asn1_per_buffer *bb) {
+       int value;
+
+       if (bb->error)
+               return 0;
+
+       if (bb->i >= bb->length) {
+               bb->error = 1;
+               return 0;
+       }
+
+       bb->bit--;
+
+       value = (bb->data[bb->i] & (1 << bb->bit)) != 0;
+
+       if (bb->bit == 0) {
+               bb->bit = 8;
+               bb->i++;
+       }
+
+       return value;
+}
+
+unsigned asn1_per_read_bits(struct asn1_per_buffer *bb, unsigned count) {
+       unsigned value;
+
+       if (bb->error)
+               return 0;
+       if (bb->i >= bb->length) {
+               bb->error = 1;
+               return 0;
+       }
+
+       if (count > 32) {
+               /* XXX support more than 32 bits in the future here? */
+               bb->error = 1;
+               return 0;
+       }
+
+       if (count <= bb->bit) {
+               value = (bb->data[bb->i] >> (bb->bit - count)) & (0xff >> (8 - 
count));
+
+               bb->bit -= count;
+               if (bb->bit == 0) {
+                       bb->bit = 8;
+                       bb->i++;
+               }
+
+               return value;
+       }
+
+       count -= bb->bit;
+
+       value = bb->data[bb->i] & (0xff >> (8 - bb->bit));
+       bb->i++;
+
+       while (count >= 8) {
+               if (bb->i >= bb->length) {
+                       bb->error = 1;
+                       return 0;
+               }
+
+               value = (value << 8) | bb->data[bb->i];
+
+               bb->i++;
+               count -= 8;
+       }
+
+       if (count > 0) {
+               if (bb->i >= bb->length) {
+                       bb->error = 1;
+                       return 0;
+               }
+
+               value = (value << count) | (bb->data[bb->i] >> (8 - count));
+       }
+
+       bb->bit = 8 - count;
+
+       return value;
+}
+
+void asn1_per_read_bitmap(struct asn1_per_buffer *bb, unsigned count,
+                         struct asn1_per_bitmap *bitmap) {
+       unsigned char *p;
+
+       memset(bitmap, 0, sizeof(*bitmap));
+
+       if (bb->error)
+               return;
+
+       if (count > sizeof(bitmap->data) * 8) {
+               /* XXX limited bit map support */
+               bb->error = 1;
+               return;
+       }
+
+       for (p = bitmap->data; count > 8; count -= 8)
+               *p++ = (unsigned char)asn1_per_read_bits(bb, 8);
+
+       if (count > 0)
+               *p = asn1_per_read_bits(bb, count) << (8 - count);
+
+       return;
+}
+
+void asn1_per_read_bytes(struct asn1_per_buffer *bb,
+                        void *buffer, unsigned count) {
+       if (bb->error)
+               return;
+
+       if (bb->bit != 8) {
+               bb->error = 1;
+               return;
+       }
+
+       if (bb->i + count > bb->length) {
+               bb->error = 1;
+               return;
+       }
+
+       memcpy(buffer, bb->data + bb->i, count);
+
+       bb->i += count;
+}
+
+void asn1_per_byte_align(struct asn1_per_buffer *bb) {
+       if (bb->bit < 8) {
+               bb->bit = 8;
+               bb->i++;
+       }
+}
+
+static unsigned count_bits(unsigned range) {
+       unsigned bits = 0;
+
+       if (range == 0)
+               return 32;
+
+       if (range == 1)
+               return 1;
+
+       while (bits < 32 && range > (unsigned)(1 << bits))
+               bits++;
+
+       return bits;
+}
+
+unsigned asn1_per_read_unsigned(struct asn1_per_buffer *bb,
+                               unsigned lower, unsigned upper) {
+       unsigned range = (upper - lower) + 1;
+       unsigned bits = count_bits(range);
+
+       if (lower == upper)
+               return lower;
+
+       if (range == 0 || range > 255) {
+               if (bits > 16)
+                       bits = asn1_per_read_length(bb, 1, (bits+7)/8) * 8;
+               else if (bits > 8)
+                       bits = 16;
+               asn1_per_byte_align(bb);
+       }
+
+       return lower + asn1_per_read_bits(bb, bits);
+}
+
+unsigned asn1_per_read_length(struct asn1_per_buffer *bb,
+                             unsigned lower, unsigned upper) {
+       if (upper < 65536)
+               return asn1_per_read_unsigned(bb, lower, upper);
+
+       asn1_per_byte_align(bb);
+
+       if (!asn1_per_read_bit(bb))
+               return asn1_per_read_bits(bb, 7);
+
+       if (!asn1_per_read_bit(bb))
+               return asn1_per_read_bits(bb, 14);
+
+       bb->error = 1;
+       return 0;
+}
+
+unsigned asn1_per_read_small(struct asn1_per_buffer *bb) {
+       unsigned length;
+
+       if (!asn1_per_read_bit(bb))
+               return asn1_per_read_bits(bb, 6);
+
+       length = asn1_per_read_length(bb, 0, INT_MAX);
+
+       asn1_per_byte_align(bb);
+
+       return asn1_per_read_bits(bb, length * 8);
+}
+
+unsigned asn1_per_read_choice_header(struct asn1_per_buffer *bb,
+                                    int extendable,
+                                    unsigned options, unsigned *after) {
+       int extended;
+       unsigned choice;
+
+       extended = extendable && asn1_per_read_bit(bb);
+       if (extended) {
+               unsigned length;
+
+               choice = asn1_per_read_small(bb) + options;
+               length = asn1_per_read_length(bb, 0, INT_MAX);
+               *after = bb->i + length;
+       } else if (options < 2) {
+               choice = 0;
+               *after = 0;
+       } else {
+               choice = asn1_per_read_bits(bb, count_bits(options));
+               *after = 0;
+       }
+
+       return choice;
+}
+
+void asn1_per_read_sequence_header(struct asn1_per_buffer *bb, int extendable,
+                                  unsigned optional_count,
+                                  struct asn1_per_sequence_header *hdr) {
+       hdr->extended = extendable && asn1_per_read_bit(bb);
+       asn1_per_read_bitmap(bb, optional_count, &hdr->present);
+}
+
+void asn1_per_read_sequence_extension_header(struct asn1_per_buffer *bb,
+                                            const struct 
asn1_per_sequence_header *hdr,
+                                            struct 
asn1_per_sequence_extension_header *ext) {
+       if (!hdr->extended) {
+               memset(ext, 0, sizeof(*ext));
+               return;
+       }
+
+       ext->count = asn1_per_read_small(bb) + 1;
+       if (bb->error)
+               return;
+
+       asn1_per_read_bitmap(bb, ext->count, &ext->present);
+}
+
+void asn1_per_skip_sequence_extension(struct asn1_per_buffer *bb,
+                                     const struct asn1_per_sequence_header 
*hdr) {
+       struct asn1_per_sequence_extension_header ext;
+       unsigned i;
+
+       asn1_per_read_sequence_extension_header(bb, hdr, &ext);
+       if (bb->error)
+               return;
+
+       for (i = 0; i < ext.count && !bb->error; i++) {
+               if (asn1_per_bitmap_get(&ext.present, i))
+                       asn1_per_skip_octet_string(bb);
+       }
+}
+
+void asn1_per_skip_object_id(struct asn1_per_buffer *bb) {
+       unsigned length;
+
+       length = asn1_per_read_length(bb, 0, 255);
+       switch (length) {
+       case 0:
+               break;
+
+       case 1:
+               asn1_per_read_bits(bb, 8);
+               break;
+
+       case 2:
+               asn1_per_read_bits(bb, 16);
+               break;
+
+       default:
+               asn1_per_byte_align(bb);
+
+               bb->i += length;
+               if (bb->i > bb->length)
+                       bb->error = 1;
+       }
+}
+
+unsigned asn1_per_read_octet_string_header(struct asn1_per_buffer *bb) {
+       unsigned length;
+
+       length = asn1_per_read_length(bb, 0, INT_MAX);
+       if (length > 2)
+               asn1_per_byte_align(bb);
+
+       return length;
+}
+
+void asn1_per_skip_octet_string(struct asn1_per_buffer *bb) {
+       unsigned length;
+
+       length = asn1_per_read_length(bb, 0, INT_MAX);
+       switch (length) {
+       case 0:
+               break;
+
+       case 1:
+               asn1_per_read_bits(bb, 8);
+               break;
+
+       case 2:
+               asn1_per_read_bits(bb, 16);
+               break;
+
+       default:
+               asn1_per_byte_align(bb);
+
+               bb->i += length;
+               if (bb->i > bb->length)
+                       bb->error = 1;
+       }
+}
+
+
+int asn1_per_bitmap_get(const struct asn1_per_bitmap *bitmap, unsigned i) {
+       if (i >= sizeof(bitmap->data) * 8)
+               return 0;
+
+       return (bitmap->data[i / 8] & (1 << (7 - (i % 8)))) != 0;
+}

Added: netfilter-2.6/patch-o-matic-ng/trunk/net/ipv4/netfilter/asn1_per.h
==============================================================================
--- (empty file)
+++ netfilter-2.6/patch-o-matic-ng/trunk/net/ipv4/netfilter/asn1_per.h  Fri May 
20 12:18:33 2005
@@ -0,0 +1,83 @@
+/*
+ * Tiny ASN.1 packet encoding rules (PER) library.
+ *
+ * This is a tiny library which helps parsing ASN.1/PER packets
+ * (i.e. read only). It is meant to be secure and small.
+ *
+ * Warning, this library may still be incomplete and buggy.
+ *
+ * (c) 2005 Max Kellermann <[EMAIL PROTECTED]>
+ */
+
+#ifndef __ASN1_PER_H
+#define __ASN1_PER_H
+
+struct asn1_per_buffer {
+       const unsigned char *data;
+       unsigned length, i, bit;
+       int error;
+};
+
+struct asn1_per_bitmap {
+       unsigned char data[16];
+};
+
+struct asn1_per_sequence_header {
+       int extended;
+       struct asn1_per_bitmap present;
+};
+
+struct asn1_per_sequence_extension_header {
+       unsigned count;
+       struct asn1_per_bitmap present;
+};
+
+void asn1_per_initialize(struct asn1_per_buffer *bb,
+                        const unsigned char *data,
+                        unsigned length, unsigned position);
+
+int asn1_per_read_bit(struct asn1_per_buffer *bb);
+
+unsigned asn1_per_read_bits(struct asn1_per_buffer *bb, unsigned count);
+
+void asn1_per_read_bitmap(struct asn1_per_buffer *bb, unsigned count,
+                         struct asn1_per_bitmap *bitmap);
+
+void asn1_per_read_bytes(struct asn1_per_buffer *bb,
+                        void *buffer, unsigned count);
+
+void asn1_per_byte_align(struct asn1_per_buffer *bb);
+
+unsigned asn1_per_read_unsigned(struct asn1_per_buffer *bb,
+                               unsigned lower, unsigned upper);
+
+unsigned asn1_per_read_length(struct asn1_per_buffer *bb,
+                             unsigned lower, unsigned upper);
+
+unsigned asn1_per_read_small(struct asn1_per_buffer *bb);
+
+unsigned asn1_per_read_choice_header(struct asn1_per_buffer *bb,
+                                    int extendable,
+                                    unsigned options, unsigned *after);
+
+void asn1_per_read_sequence_header(struct asn1_per_buffer *bb, int extendable,
+                                  unsigned optional_count,
+                                  struct asn1_per_sequence_header *hdr);
+
+void asn1_per_read_sequence_extension_header(struct asn1_per_buffer *bb,
+                                            const struct 
asn1_per_sequence_header *hdr,
+                                            struct 
asn1_per_sequence_extension_header *ext);
+
+void asn1_per_skip_sequence_extension(struct asn1_per_buffer *bb,
+                                     const struct asn1_per_sequence_header 
*hdr);
+
+void asn1_per_skip_object_id(struct asn1_per_buffer *bb);
+
+unsigned asn1_per_read_octet_string_header(struct asn1_per_buffer *bb);
+
+void asn1_per_skip_octet_string(struct asn1_per_buffer *bb);
+
+
+int asn1_per_bitmap_get(const struct asn1_per_bitmap *bitmap, unsigned i);
+
+#endif

Modified: 
netfilter-2.6/patch-o-matic-ng/trunk/net/ipv4/netfilter/ip_conntrack_h323.c
==============================================================================
--- netfilter-2.6/patch-o-matic-ng/trunk/net/ipv4/netfilter/ip_conntrack_h323.c 
(original)
+++ netfilter-2.6/patch-o-matic-ng/trunk/net/ipv4/netfilter/ip_conntrack_h323.c 
Fri May 20 12:18:33 2005
@@ -160,7 +160,8 @@
 }
 
 /* H.245 helper is not registered! */
-static struct ip_conntrack_helper h245 = {
+static struct ip_conntrack_helper h245 =
+{
        .name = "H.245",
        .max_expected = 8,
        .timeout = 240,
@@ -419,7 +420,8 @@
        return ret;
 }
 
-static struct ip_conntrack_helper h225 = {
+static struct ip_conntrack_helper h225 =
+{
        .name = "H.225",
        .me = THIS_MODULE,
        .max_expected = 2,

Added: 
netfilter-2.6/patch-o-matic-ng/trunk/net/ipv4/netfilter/ip_conntrack_h323_core.c
==============================================================================
--- (empty file)
+++ 
netfilter-2.6/patch-o-matic-ng/trunk/net/ipv4/netfilter/ip_conntrack_h323_core.c
    Fri May 20 12:18:33 2005
@@ -0,0 +1,38 @@
+/*
+ * H.323 connection tracking helper
+ * (c) 2005 Max Kellermann <[EMAIL PROTECTED]>
+ *
+ * Based on the 'brute force' H.323 connection tracking module by
+ * Jozsef Kadlecsik <[EMAIL PROTECTED]>
+ */
+
+
+#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("Max Kellermann <[EMAIL PROTECTED]>");
+MODULE_DESCRIPTION("H.323 connection tracking helper");
+MODULE_LICENSE("GPL");
+
+static int __init init(void)
+{
+       return ip_conntrack_helper_register(&ip_conntrack_helper_h225);
+}
+
+static void __exit fini(void)
+{
+       ip_conntrack_helper_unregister(&ip_conntrack_helper_h225);
+}
+
+module_init(init);
+module_exit(fini);

Added: 
netfilter-2.6/patch-o-matic-ng/trunk/net/ipv4/netfilter/ip_conntrack_h323_h225.c
==============================================================================
--- (empty file)
+++ 
netfilter-2.6/patch-o-matic-ng/trunk/net/ipv4/netfilter/ip_conntrack_h323_h225.c
    Fri May 20 12:18:33 2005
@@ -0,0 +1,406 @@
+/*
+ * H.323/H.225 connection tracking helper
+ * (c) 2005 Max Kellermann <[EMAIL PROTECTED]>
+ *
+ * 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>
+
+#include "asn1_per.h"
+
+/* This is slow, but it's simple. --RR */
+static char h225_buffer[65536];
+
+static DECLARE_LOCK(ip_h225_lock);
+
+int (*ip_nat_h225_hook)(struct sk_buff **pskb,
+                       enum ip_conntrack_info ctinfo,
+                       unsigned int offset,
+                       struct ip_conntrack_expect *exp);
+EXPORT_SYMBOL_GPL(ip_nat_h225_hook);
+
+void (*ip_nat_h225_signal_hook)(struct sk_buff **pskb,
+                               struct ip_conntrack *ct,
+                               enum ip_conntrack_info ctinfo,
+                               unsigned int offset,
+                               int dir,
+                               int orig_dir);
+EXPORT_SYMBOL_GPL(ip_nat_h225_signal_hook);
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+/**
+ * Parse an H.225 TransportAddress and return the position of the IP
+ * address (if present). Returns 1 on success.
+ */
+static int h225_parse_transport_address(struct asn1_per_buffer *bb, unsigned 
*i,
+                                       u_int32_t *ip, u_int16_t *port) {
+       unsigned choice, after;
+
+       choice = asn1_per_read_choice_header(bb, 1, 7, &after);
+       if (bb->error)
+               return 0;
+
+       switch (choice) {
+       case 0: /* ipAddress */
+               asn1_per_byte_align(bb);
+               *i = bb->i;
+               asn1_per_read_bytes(bb, ip, sizeof(*ip));
+               asn1_per_read_bytes(bb, port, sizeof(*port));
+               return !bb->error;
+
+       default:
+               if (after == 0) {
+                       DEBUGP("TransportAddress %u not yet supported\n", 
choice);
+                       bb->error = 1;
+               } else {
+                       bb->i = after;
+               }
+               return 0;
+       }
+}
+
+/**
+ * Parse a H.225 Connect-UUIE packet and handle NAT/expectations for
+ * the H.245 transport address.
+ */
+static int h225_parse_connect_uuie(struct sk_buff **pskb,
+                                  struct ip_conntrack *ct,
+                                  enum ip_conntrack_info ctinfo,
+                                  struct asn1_per_buffer *bb) {
+       struct asn1_per_sequence_header hdr;
+
+       asn1_per_read_sequence_header(bb, 1, 1, &hdr);
+
+       /* protocolIdentifier */
+       asn1_per_skip_object_id(bb);
+
+       /* h245Address */
+       if (asn1_per_bitmap_get(&hdr.present, 0)) {
+               int dir = CTINFO2DIR(ctinfo);
+               struct ip_conntrack_expect *exp;
+               int ret;
+               unsigned i;
+               u_int32_t ip;
+               u_int16_t port;
+
+               ret = h225_parse_transport_address(bb, &i, &ip, &port);
+               if (ret) {
+                       DEBUGP("H.245 transportAddress: %u.%u.%u.%u:%u\n",
+                              NIPQUAD(ip), ntohs(port));
+               }
+               if (ret && ip == ct->tuplehash[dir].tuple.src.ip) {
+                       /* 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 = { port } },
+                                           IPPROTO_TCP }});
+                       exp->mask = ((struct ip_conntrack_tuple)
+                                       { { 0xFFFFFFFF, { 0 } },
+                                         { 0xFFFFFFFF, { .tcp = { 0xFFFF } }, 
0xFF }});
+
+                       exp->expectfn = ip_conntrack_h245_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;
+                               }
+                       }
+               }
+       }
+
+       /* XXX */
+       bb->error = 1;
+
+       asn1_per_skip_sequence_extension(bb, &hdr);
+
+       return NF_ACCEPT;
+}
+
+/**
+ * Parse a H.225 H323-UU-PDU packet and handle NAT/expectations for
+ * the H.245 transport address.
+ */
+static int h225_parse_uu_pdu(struct sk_buff **pskb,
+                            struct ip_conntrack *ct,
+                            enum ip_conntrack_info ctinfo,
+                            struct asn1_per_buffer *bb) {
+       struct asn1_per_sequence_header hdr;
+       unsigned choice, after;
+       int ret;
+
+       asn1_per_read_sequence_header(bb, 1, 1, &hdr);
+
+       /* h323-message-body */
+       choice = asn1_per_read_choice_header(bb, 1, 7, &after);
+       switch (choice) {
+       case 2: /* connect */
+               ret = h225_parse_connect_uuie(pskb, ct, ctinfo, bb);
+               if (ret != NF_ACCEPT)
+                       return ret;
+               break;
+
+       default:
+               if (after == 0) {
+                       bb->error = 1;
+                       return NF_ACCEPT;
+               }
+
+               bb->i = after;
+       }
+
+       asn1_per_skip_sequence_extension(bb, &hdr);
+
+       return NF_ACCEPT;
+}
+
+/**
+ * Parse a H.225 packet and handle NAT/expectations for the H.245
+ * transport address.
+ */
+static int h225_parse(struct sk_buff **pskb,
+                     struct ip_conntrack *ct,
+                     enum ip_conntrack_info ctinfo,
+                     struct asn1_per_buffer *bb) {
+       struct asn1_per_sequence_header hdr;
+
+       asn1_per_read_sequence_header(bb, 1, 1, &hdr);
+
+       return h225_parse_uu_pdu(pskb, ct, ctinfo, bb);
+}
+
+/**
+ * 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)
+{
+       struct asn1_per_buffer bb;
+
+       if (i + 2 > length)
+               return NF_ACCEPT;
+
+       if (data[i++] != 0x05) /* X.208 / X.209 */
+               return NF_ACCEPT;
+
+       asn1_per_initialize(&bb, data, length, i);
+
+       return h225_parse(pskb, ct, ctinfo, &bb);
+}
+
+/**
+ * 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;
+
+       if (i + 3 > datalen)
+               return NF_ACCEPT;
+
+       /* 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;
+
+               /* the length returned by q931_find_u2u() is relative
+                  to i */
+               length += i;
+
+               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;
+
+       if (i + 4 > datalen)
+               return NF_ACCEPT;
+
+       /* 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 < 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 dataoff, datalen;
+       int ret = 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;
+       }
+
+       tcph = skb_header_pointer((*pskb), (*pskb)->nh.iph->ihl*4,
+                                 sizeof(_tcph), &_tcph);
+       if (tcph == NULL)
+               return NF_ACCEPT;
+
+       DEBUGP("ct_h225_help: help entered %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n",
+               NIPQUAD((*pskb)->nh.iph->saddr), ntohs(tcph->source),
+               NIPQUAD((*pskb)->nh.iph->daddr), ntohs(tcph->dest));
+
+       dataoff = (*pskb)->nh.iph->ihl*4 + tcph->doff*4;
+       /* No data? */
+       if (dataoff >= (*pskb)->len) {
+               DEBUGP("ct_h225_help: skblen = %u\n", (*pskb)->len);
+               return NF_ACCEPT;
+       }
+       datalen = (*pskb)->len - dataoff;
+
+       if (datalen < 16)
+               return NF_ACCEPT;
+
+       /* get data portion, and evaluate it */
+       LOCK_BH(&ip_h225_lock);
+       data = skb_header_pointer((*pskb), dataoff,
+                                 datalen, h225_buffer);
+       BUG_ON(data == NULL);
+
+       ret = h225_parse_tpkt(pskb, ct, ctinfo,
+                             data, datalen);
+
+       UNLOCK_BH(&ip_h225_lock);
+       return ret;
+}
+
+struct ip_conntrack_helper ip_conntrack_helper_h225 =
+{
+       .name = "H.225",
+       .me = THIS_MODULE,
+       .max_expected = 2,
+       .timeout = 240,
+       .tuple = { .src = { .u = { __constant_htons(H225_PORT) } },
+                  .dst = { .protonum = IPPROTO_TCP } },
+       .mask = { .src = { .u = { 0xFFFF } },
+                 .dst = { .protonum = 0xFF } },
+       .help = h225_help
+};
+EXPORT_SYMBOL_GPL(ip_conntrack_helper_h225);

Added: 
netfilter-2.6/patch-o-matic-ng/trunk/net/ipv4/netfilter/ip_conntrack_h323_h245.c
==============================================================================
--- (empty file)
+++ 
netfilter-2.6/patch-o-matic-ng/trunk/net/ipv4/netfilter/ip_conntrack_h323_h245.c
    Fri May 20 12:18:33 2005
@@ -0,0 +1,960 @@
+/*
+ * H.323/H.245 connection tracking helper
+ * (c) 2005 Max Kellermann <[EMAIL PROTECTED]>
+ *
+ * Based on the 'brute force' H.323 connection tracking module by
+ * Jozsef Kadlecsik <[EMAIL PROTECTED]>
+ */
+
+
+#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>
+
+#include "asn1_per.h"
+
+/* This is slow, but it's simple. --RR */
+static char h245_buffer[65536];
+
+static DECLARE_LOCK(ip_h245_lock);
+
+struct module *ip_conntrack_h245 = THIS_MODULE;
+
+int (*ip_nat_h245_hook)(struct sk_buff **pskb,
+                       enum ip_conntrack_info ctinfo,
+                       unsigned int offset,
+                       struct ip_conntrack_expect *exp);
+EXPORT_SYMBOL_GPL(ip_nat_h245_hook);
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+/**
+ * Skip an H.245 NonStandardIdentifier, discarding its value.
+ */
+static void h245_skip_nonstandard_id(struct asn1_per_buffer *bb) {
+       unsigned choice;
+
+       choice = asn1_per_read_bits(bb, 1);
+       switch (choice) {
+       case 0:
+               asn1_per_skip_object_id(bb);
+               break;
+
+       case 1:
+               asn1_per_read_unsigned(bb, 0, 255);
+               asn1_per_read_unsigned(bb, 0, 255);
+               asn1_per_read_unsigned(bb, 0, 65535);
+               break;
+       }
+}
+
+/**
+ * Skip an H.245 NonStandardParameter, discarding its value.
+ */
+static void h245_skip_nonstandard_param(struct asn1_per_buffer *bb) {
+       h245_skip_nonstandard_id(bb);
+       asn1_per_skip_octet_string(bb);
+}
+
+/**
+ * Skip an H.245 VideoCapability, discarding its value.
+ */
+static void h245_skip_video_capability(struct asn1_per_buffer *bb) {
+       unsigned choice, after;
+
+       choice = asn1_per_read_choice_header(bb, 1, 5, &after);
+       DEBUGP("video_capability: choice=%u after=%u error=%d\n",
+              choice, after, bb->error);
+
+       if (bb->error)
+               return;
+
+       /* XXX support the rest */
+       switch (choice) {
+       case 0: /* nonStandard */
+               h245_skip_nonstandard_param(bb);
+               break;
+
+       default:
+               if (after == 0) {
+                       DEBUGP("unsupported audio_capability %u\n", choice);
+                       bb->error = 1;
+               }
+       }
+
+       if (after > 0)
+               bb->i = after;
+}
+
+/**
+ * Skip an H.245 AudioCapability, discarding its value.
+ */
+static void h245_skip_audio_capability(struct asn1_per_buffer *bb) {
+       unsigned choice, after;
+
+       choice = asn1_per_read_choice_header(bb, 1, 14, &after);
+       DEBUGP("audio_capability: audio_capability=%u after=%u error=%d\n", 
choice, after, bb->error);
+
+       if (bb->error)
+               return;
+
+       /* XXX support the rest */
+       switch (choice) {
+               unsigned value;
+
+       case 0: /* nonStandard */
+               h245_skip_nonstandard_param(bb);
+               break;
+
+       case 1:
+       case 2:
+       case 3:
+       case 4:
+       case 5:
+       case 6:
+       case 7:
+       case 9:
+       case 10:
+       case 11:
+       case 14:
+       case 17:
+               value = asn1_per_read_unsigned(bb, 1, 256);
+               DEBUGP("value %u = %u\n", choice, value);
+               break;
+       default:
+               if (after == 0) {
+                       DEBUGP("unsupported audio_capability %u\n", choice);
+                       bb->error = 1;
+               }
+       }
+
+       if (after > 0)
+               bb->i = after;
+}
+
+/**
+ * Skip an H.245 DataType, discarding its value.
+ */
+static void h245_skip_data_type(struct asn1_per_buffer *bb) {
+       unsigned choice, after;
+
+       choice = asn1_per_read_choice_header(bb, 1, 6, &after);
+
+       if (bb->error)
+               return;
+
+       /* XXX support the rest */
+       switch (choice) {
+       case 0: /* nonStandard */
+               h245_skip_nonstandard_param(bb);
+               break;
+
+       case 1: /* nullData */
+               break;
+
+       case 2: /* videoData */
+               h245_skip_video_capability(bb);
+               break;
+
+       case 3: /* audioData */
+               h245_skip_audio_capability(bb);
+               break;
+
+       default:
+               if (after == 0) {
+                       DEBUGP("unsupported data_type %u\n", choice);
+                       bb->error = 1;
+               }
+       }
+
+       if (after > 0)
+               bb->i = after;
+}
+
+/**
+ * Parse an H.245 UnicastAddress and return the position of the IP
+ * address (if present). Returns 1 on success.
+ */
+static int h245_parse_unicast_address(struct asn1_per_buffer *bb, unsigned *i,
+                                     u_int32_t *ip, u_int16_t *port) {
+       unsigned choice, after;
+
+       choice = asn1_per_read_choice_header(bb, 1, 5, &after);
+       DEBUGP("Parsing UnicastAddress choice=%u after=%u\n", choice, after);
+       switch (choice) {
+       case 0: /* iPAddress */
+               asn1_per_read_bit(bb); /* XXX use this bit */
+               asn1_per_byte_align(bb);
+               *i = bb->i;
+               asn1_per_read_bytes(bb, ip, sizeof(*ip));
+               asn1_per_read_bytes(bb, port, sizeof(*port));
+               return !bb->error;
+       default:
+               if (after == 0) {
+                       DEBUGP("UnicastAddress %u not yet supported\n", choice);
+                       bb->error = 1;
+               } else {
+                       bb->i = after;
+               }
+               return 0;
+       }
+}
+
+/**
+ * Parse an H.245 TransportAddress and return the position of the
+ * Unicast IP address (if present). Returns 1 on success.
+ */
+static int h245_parse_transport_address(struct asn1_per_buffer *bb, unsigned 
*i,
+                                       u_int32_t *ip, u_int16_t *port) {
+       unsigned choice, after;
+
+       choice = asn1_per_read_choice_header(bb, 1, 2, &after);
+       switch (choice) {
+       case 0: /* UnicastAddress */
+               return h245_parse_unicast_address(bb, i, ip, port);
+       case 1: /* MulticastAddress */
+               /* XXX */
+               DEBUGP("MulticastAddress not yet supported\n");
+               bb->error = 1;
+               return 0;
+       default:
+               if (after == 0) {
+                       DEBUGP("ERROR7\n");
+                       bb->error = 1;
+               } else {
+                       bb->i = after;
+               }
+               return 0;
+       }
+}
+
+/**
+ * Skip an H.245 TerminalLabel, discarding its value.
+ */
+static void h245_skip_terminal_label(struct asn1_per_buffer *bb) {
+       struct asn1_per_sequence_header hdr;
+
+       asn1_per_read_sequence_header(bb, 1, 0, &hdr);
+
+       /* mcuNumber */
+       asn1_per_read_unsigned(bb, 0, 192);
+       /* terminalNumber */
+       asn1_per_read_unsigned(bb, 0, 192);
+
+       asn1_per_skip_sequence_extension(bb, &hdr);
+}
+
+/**
+ * Parse an H.245 H2250LogicalChannelParameters request packet and
+ * handle NAT/expectations for the logical channel address.
+ */
+static int h245_parse_h2250_lchannel_params(struct sk_buff **pskb,
+                                           struct ip_conntrack *ct,
+                                           enum ip_conntrack_info ctinfo,
+                                           struct asn1_per_buffer *bb) {
+       struct asn1_per_sequence_header hdr;
+       unsigned session_id;
+
+       asn1_per_read_sequence_header(bb, 1, 10, &hdr);
+
+       /* nonStandard */
+       if (asn1_per_bitmap_get(&hdr.present, 0))
+               h245_skip_nonstandard_param(bb);
+
+       /* sessionID */
+       session_id = asn1_per_read_unsigned(bb, 0, 255);
+
+       /* associatedSessionID */
+       if (asn1_per_bitmap_get(&hdr.present, 1))
+               asn1_per_read_unsigned(bb, 1, 255);
+
+       /* mediaChannel */
+       DEBUGP("lchannel_params mediaChannel: i=%u bit=%u\n", bb->i, bb->bit);
+       if (asn1_per_bitmap_get(&hdr.present, 2)) {
+               int dir = CTINFO2DIR(ctinfo);
+               struct ip_conntrack_expect *exp;
+               int ret;
+               unsigned i;
+               u_int32_t ip;
+               u_int16_t port;
+
+               ret = h245_parse_transport_address(bb, &i, &ip, &port);
+               if (ret)
+                       DEBUGP("mediaChannel IPv4 address: %u.%u.%u.%u:%u\n",
+                              NIPQUAD(ip), ntohs(port));
+               if (ret && ip == ct->tuplehash[dir].tuple.src.ip) {
+                       /* 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,
+                                           { .udp = { port } },
+                                           IPPROTO_UDP }});
+                       exp->mask = ((struct ip_conntrack_tuple)
+                                       { { 0xFFFFFFFF, { 0 } },
+                                         { 0xFFFFFFFF, { .udp = { 0xFFFF } }, 
0xFF }});
+
+                       exp->master = ct;
+
+                       /* call NAT hook and register expectation */
+                       if (ip_nat_h245_hook != NULL) {
+                               return ip_nat_h245_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;
+                               }
+                       }
+               }
+       }
+
+       /* mediaGuaranteedDelivery */
+       if (asn1_per_bitmap_get(&hdr.present, 3))
+               asn1_per_read_bit(bb);
+
+       /* mediaControlChannel */
+       DEBUGP("lchannel_params controlChannel: i=%u bit=%u\n", bb->i, bb->bit);
+       if (asn1_per_bitmap_get(&hdr.present, 4)) {
+               int dir = CTINFO2DIR(ctinfo);
+               struct ip_conntrack_expect *exp;
+               int ret;
+               unsigned i;
+               u_int32_t ip;
+               u_int16_t port;
+
+               ret = h245_parse_transport_address(bb, &i, &ip, &port);
+               if (ret)
+                       DEBUGP("mediaControlChannel IPv4 address: 
%u.%u.%u.%u:%u\n",
+                              NIPQUAD(ip), ntohs(port));
+               if (ret && ip == ct->tuplehash[dir].tuple.src.ip) {
+                       /* 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,
+                                           { .udp = { port } },
+                                           IPPROTO_UDP }});
+                       exp->mask = ((struct ip_conntrack_tuple)
+                                       { { 0xFFFFFFFF, { 0 } },
+                                         { 0xFFFFFFFF, { .udp = { 0xFFFF } }, 
0xFF }});
+
+                       exp->master = ct;
+
+                       /* call NAT hook and register expectation */
+                       if (ip_nat_h245_hook != NULL) {
+                               return ip_nat_h245_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;
+                               }
+                       }
+               }
+       }
+
+       /* mediaControlGuaranteedDelivery */
+       if (asn1_per_bitmap_get(&hdr.present, 5))
+               asn1_per_read_bit(bb);
+
+       /* silenceSuppression */
+       if (asn1_per_bitmap_get(&hdr.present, 6))
+               asn1_per_read_bit(bb);
+
+       /* destination */
+       if (asn1_per_bitmap_get(&hdr.present, 7))
+               h245_skip_terminal_label(bb);
+
+       /* dynamicRTPPayloadType */
+       if (asn1_per_bitmap_get(&hdr.present, 8))
+               asn1_per_read_unsigned(bb, 96, 127);
+
+       /* mediaPacketization */
+       if (asn1_per_bitmap_get(&hdr.present, 9)) {
+               unsigned choice, after;
+
+               choice = asn1_per_read_choice_header(bb, 1, 1, &after);
+               switch (choice) {
+               case 0: /* h261aVideoPacketization */
+                       break;
+
+               default:
+                       if (after == 0) {
+                               DEBUGP("ERROR7\n");
+                               bb->error = 1;
+                               return NF_ACCEPT;
+                       }
+
+                       bb->i = after;
+               }
+       }
+
+       /* XXX */
+
+       asn1_per_skip_sequence_extension(bb, &hdr);
+
+       return NF_ACCEPT;
+}
+
+/**
+ * Parse an H.245 OpenLogicalChannel request packet and handle
+ * NAT/expectations for the logical channel address.
+ */
+static int h245_parse_open_lchannel(struct sk_buff **pskb,
+                                   struct ip_conntrack *ct,
+                                   enum ip_conntrack_info ctinfo,
+                                   struct asn1_per_buffer *bb) {
+       struct asn1_per_sequence_header hdr, hdr2;
+       unsigned forwardLogicalChannelNumber;
+       unsigned choice, after;
+
+       asn1_per_read_sequence_header(bb, 1, 1, &hdr);
+
+       forwardLogicalChannelNumber = asn1_per_read_unsigned(bb, 1, 65535);
+
+       /* entering forwardLogicalChannelParameters */
+       asn1_per_read_sequence_header(bb, 1, 1, &hdr2);
+       if (asn1_per_bitmap_get(&hdr2.present, 0))
+               asn1_per_read_unsigned(bb, 0, 65535);
+
+       h245_skip_data_type(bb);
+
+       /* multiplexParameters */
+       choice = asn1_per_read_choice_header(bb, 1, 3, &after);
+       if (bb->error)
+               return NF_ACCEPT;
+
+       switch (choice) {
+       case 3: /* h2250LogicalChannelParameters */
+               h245_parse_h2250_lchannel_params(pskb, ct, ctinfo, bb);
+               break;
+       default:
+               if (after == 0) {
+                       DEBUGP("unsupported multiplex_parameter %u\n", choice);
+                       bb->error = 1;
+                       return NF_ACCEPT;
+               }
+       }
+
+       if (bb->error)
+               return NF_ACCEPT;
+
+       if (after > 0)
+               bb->i = after;
+
+       asn1_per_skip_sequence_extension(bb, &hdr2);
+
+       /* leaving multiplexParameters, forwardLogicalChannelParameters */
+
+       /* reverseLogicalChannelParameters */
+       if (asn1_per_bitmap_get(&hdr.present, 0)) {
+               asn1_per_read_sequence_header(bb, 1, 1, &hdr2);
+
+               h245_skip_data_type(bb);
+
+               /* multiplexParameters */
+               if (asn1_per_bitmap_get(&hdr2.present, 0)) {
+                       choice = asn1_per_read_choice_header(bb, 1, 2, &after);
+                       if (bb->error)
+                               return NF_ACCEPT;
+
+                       DEBUGP("reverse_parameter multiplex=%u after=%u\n", 
choice, after);
+
+                       switch (choice) {
+                       case 2: /* h2250LogicalChannelParameters */
+                               h245_parse_h2250_lchannel_params(pskb, ct, 
ctinfo, bb);
+                               break;
+                       default:
+                               if (after == 0) {
+                                       DEBUGP("unsupported multiplex_parameter 
%u\n", choice);
+                                       bb->error = 1;
+                                       return NF_ACCEPT;
+                               }
+                       }
+
+                       if (bb->error)
+                               return NF_ACCEPT;
+
+                       if (after > 0)
+                               bb->i = after;
+               }
+
+               asn1_per_skip_sequence_extension(bb, &hdr2);
+       }
+
+       asn1_per_skip_sequence_extension(bb, &hdr);
+
+       /* XXX */
+       return NF_ACCEPT;
+}
+
+/**
+ * Parse an H.245 request packet and handle NAT/expectations for the
+ * logical channel address.
+ */
+static int h245_parse_request(struct sk_buff **pskb,
+                             struct ip_conntrack *ct,
+                             enum ip_conntrack_info ctinfo,
+                             struct asn1_per_buffer *bb) {
+       unsigned choice, after;
+
+       choice = asn1_per_read_choice_header(bb, 1, 11, &after);
+       DEBUGP("H.245: message_type=%u\n", choice);
+       switch (choice) {
+       case 3:
+               return h245_parse_open_lchannel(pskb, ct, ctinfo, bb);
+       default:
+               return NF_ACCEPT;
+       }
+}
+
+/**
+ * Parse an H.245 H222LogicalChannelParameters response packet and
+ * handle NAT/expectations for the logical channel address.
+ */
+static int h245_parse_h222_lchannel_params(struct sk_buff **pskb,
+                                          struct ip_conntrack *ct,
+                                          enum ip_conntrack_info ctinfo,
+                                          struct asn1_per_buffer *bb) {
+       struct asn1_per_sequence_header hdr;
+
+       asn1_per_read_sequence_header(bb, 1, 3, &hdr);
+
+       if (bb->error)
+               return NF_ACCEPT;
+
+       /* resourceID */
+       asn1_per_read_unsigned(bb, 0, 65535);
+
+       /* subChannelID */
+       asn1_per_read_unsigned(bb, 0, 8191);
+
+       /* pcr-pid */
+       if (asn1_per_bitmap_get(&hdr.present, 0))
+               asn1_per_read_unsigned(bb, 0, 8191);
+
+       /* programDescriptors */
+       if (asn1_per_bitmap_get(&hdr.present, 1))
+               asn1_per_skip_octet_string(bb);
+
+       /* streamDescriptors */
+       if (asn1_per_bitmap_get(&hdr.present, 2))
+               asn1_per_skip_octet_string(bb);
+
+       asn1_per_skip_sequence_extension(bb, &hdr);
+
+       return NF_ACCEPT;
+}
+
+/**
+ * Parse an H.245 H2250LogicalChannelAckParameters response packet and
+ * handle NAT/expectations for the logical channel address.
+ */
+static int h245_parse_h2250_lchannel_ack_params(struct sk_buff **pskb,
+                                               struct ip_conntrack *ct,
+                                               enum ip_conntrack_info ctinfo,
+                                               struct asn1_per_buffer *bb) {
+       struct asn1_per_sequence_header hdr;
+       unsigned count;
+
+       DEBUGP("entering h245_parse_h2250_lchannel_ack_params\n");
+
+       asn1_per_read_sequence_header(bb, 1, 5, &hdr);
+
+       /* nonStandard */
+       if (asn1_per_bitmap_get(&hdr.present, 0)) {
+               count = asn1_per_read_length(bb, 0, UINT_MAX);
+               while (count > 0) {
+                       h245_skip_nonstandard_param(bb);
+                       if (bb->error)
+                               return NF_ACCEPT;
+               }
+       }
+
+       /* sessionID */
+       if (asn1_per_bitmap_get(&hdr.present, 1))
+               asn1_per_read_unsigned(bb, 1, 255);
+
+       /* mediaChannel */
+       if (asn1_per_bitmap_get(&hdr.present, 2)) {
+               int ret;
+               unsigned i;
+               u_int32_t ip;
+               u_int16_t port;
+               int dir = CTINFO2DIR(ctinfo);
+               struct ip_conntrack_expect *exp;
+
+               ret = h245_parse_transport_address(bb, &i, &ip, &port);
+               DEBUGP("entering mediaChannel ret=%d i=%u ip=%x port=%u\n",
+                      ret, i, ip, port);
+               if (ret && ip == ct->tuplehash[dir].tuple.src.ip) {
+                       /* 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,
+                                           { .udp = { port } },
+                                           IPPROTO_UDP }});
+                       exp->mask = ((struct ip_conntrack_tuple)
+                                       { { 0xFFFFFFFF, { 0 } },
+                                         { 0xFFFFFFFF, { .udp = { 0xFFFF } }, 
0xFF }});
+
+                       exp->master = ct;
+
+                       /* call NAT hook and register expectation */
+                       if (ip_nat_h245_hook != NULL) {
+                               ret = ip_nat_h245_hook(pskb, ctinfo, i, exp);
+                               if (ret != NF_ACCEPT)
+                                       return ret;
+                       } 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;
+                               }
+                       }
+               }
+       }
+
+       /* mediaControlChannel */
+       if (asn1_per_bitmap_get(&hdr.present, 3)) {
+               int ret;
+               unsigned i;
+               u_int32_t ip;
+               u_int16_t port;
+               int dir = CTINFO2DIR(ctinfo);
+               struct ip_conntrack_expect *exp;
+
+               ret = h245_parse_transport_address(bb, &i, &ip, &port);
+               DEBUGP("entering mediaControlChannel ret=%d i=%u ip=%x 
port=%u\n",
+                      ret, i, ip, port);
+               if (ret && ip == ct->tuplehash[dir].tuple.src.ip) {
+                       /* 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,
+                                           { .udp = { port } },
+                                           IPPROTO_UDP }});
+                       exp->mask = ((struct ip_conntrack_tuple)
+                                       { { 0xFFFFFFFF, { 0 } },
+                                         { 0xFFFFFFFF, { .udp = { 0xFFFF } }, 
0xFF }});
+
+                       exp->master = ct;
+
+                       /* call NAT hook and register expectation */
+                       if (ip_nat_h245_hook != NULL) {
+                               ret = ip_nat_h245_hook(pskb, ctinfo, i, exp);
+                               if (ret != NF_ACCEPT)
+                                       return ret;
+                       } 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;
+                               }
+                       }
+               }
+       }
+
+       /* dynamicRTPPayloadType */
+       if (asn1_per_bitmap_get(&hdr.present, 1))
+               asn1_per_read_unsigned(bb, 96, 127);
+
+       asn1_per_skip_sequence_extension(bb, &hdr);
+
+       return NF_ACCEPT;
+}
+
+/**
+ * Parse an H.245 OpenLogicalChannelAck response packet and handle
+ * NAT/expectations for the logical channel address.
+ */
+static int h245_parse_open_lchannel_ack(struct sk_buff **pskb,
+                                       struct ip_conntrack *ct,
+                                       enum ip_conntrack_info ctinfo,
+                                       struct asn1_per_buffer *bb) {
+       struct asn1_per_sequence_header hdr, hdr2;
+       struct asn1_per_sequence_extension_header ext;
+       unsigned forwardLogicalChannelNumber;
+       unsigned choice, after, after2, i;
+
+       asn1_per_read_sequence_header(bb, 1, 1, &hdr);
+
+       forwardLogicalChannelNumber = asn1_per_read_unsigned(bb, 1, 65535);
+       DEBUGP("forwardLogicalChannelNumber=%u\n", forwardLogicalChannelNumber);
+
+       /* reverseLogicalChannelParameters */
+       if (asn1_per_bitmap_get(&hdr.present, 0)) {
+               DEBUGP("reverseLogicalChannelParameters present\n");
+               asn1_per_read_sequence_header(bb, 1, 2, &hdr2);
+
+               /* reverseLogicalChannelNumber */
+               asn1_per_read_unsigned(bb, 1, 65535);
+
+               /* portNumber */
+               if (asn1_per_bitmap_get(&hdr.present, 0))
+                       asn1_per_read_unsigned(bb, 0, 65535);
+
+               /* multiplexParameters */
+               if (asn1_per_bitmap_get(&hdr2.present, 1)) {
+                       choice = asn1_per_read_choice_header(bb, 1, 1, &after);
+                       if (bb->error)
+                               return NF_ACCEPT;
+
+                       switch (choice) {
+                       case 0: /* h222LogicalChannelParameters */
+                               h245_parse_h222_lchannel_params(pskb, ct,
+                                                               ctinfo, bb);
+                               break;
+                       case 1: /* h2250LogicalChannelParameters */
+                               h245_parse_h2250_lchannel_params(pskb, ct,
+                                                                ctinfo, bb);
+                               break;
+                       default:
+                               if (after == 0) {
+                                       DEBUGP("unsupported multiplex_parameter 
%u\n", choice);
+                                       bb->error = 1;
+                                       return NF_ACCEPT;
+                               }
+                       }
+
+                       if (bb->error)
+                               return NF_ACCEPT;
+
+                       if (after > 0)
+                               bb->i = after;
+               }
+
+               asn1_per_skip_sequence_extension(bb, &hdr2);
+       }
+
+       asn1_per_read_sequence_extension_header(bb, &hdr, &ext);
+       if (bb->error)
+               return NF_ACCEPT;
+
+       /* separateStack */
+       if (asn1_per_bitmap_get(&ext.present, 0))
+               asn1_per_skip_octet_string(bb);
+
+       /* forwardMultiplexAckParameters */
+       if (asn1_per_bitmap_get(&ext.present, 1)) {
+               DEBUGP("forwardMultiplexAckParameters present\n");
+
+               after = asn1_per_read_octet_string_header(bb);
+               DEBUGP("forwardMultiplexAckParameters present length=%u i=%u 
after=%u end=%u\n",
+                      after, bb->i, bb->i + after, bb->length);
+               after += bb->i;
+
+               choice = asn1_per_read_choice_header(bb, 1, 1, &after2);
+               if (bb->error)
+                       return NF_ACCEPT;
+
+               DEBUGP("entering forwardMultiplexAckParameters choice=%u 
after=%u\n", choice, after2);
+
+               switch (choice) {
+               case 0: /* h2250LogicalChannelAckParameters */
+                       h245_parse_h2250_lchannel_ack_params(pskb, ct,
+                                                            ctinfo, bb);
+                       break;
+               }
+
+               if (bb->error)
+                       return NF_ACCEPT;
+
+               bb->i = after;
+       }
+
+       for (i = 2; i < ext.count; i++)
+               if (asn1_per_bitmap_get(&ext.present, i))
+                       asn1_per_skip_octet_string(bb);
+
+       return NF_ACCEPT;
+}
+
+/**
+ * Parse an H.245 response packet and handle NAT/expectations for the
+ * logical channel address.
+ */
+static int h245_parse_response(struct sk_buff **pskb,
+                              struct ip_conntrack *ct,
+                              enum ip_conntrack_info ctinfo,
+                              struct asn1_per_buffer *bb) {
+       unsigned choice, after;
+
+       choice = asn1_per_read_choice_header(bb, 1, 19, &after);
+       DEBUGP("H.245: response type=%u\n", choice);
+       switch (choice) {
+       case 5: /* openLogicalChannelAck */
+               return h245_parse_open_lchannel_ack(pskb, ct, ctinfo, bb);
+
+       default:
+               return NF_ACCEPT;
+       }
+}
+
+/**
+ * Parse an H.245 packet and handle NAT/expectations for the logical
+ * channel address.
+ */
+static int h245_parse(struct sk_buff **pskb,
+                     struct ip_conntrack *ct,
+                     enum ip_conntrack_info ctinfo,
+                     struct asn1_per_buffer *bb) {
+       unsigned choice, after;
+
+       choice = asn1_per_read_choice_header(bb, 1, 4, &after);
+       DEBUGP("H.245: message_class=%u\n", choice);
+       switch (choice) {
+       case 0:
+               return h245_parse_request(pskb, ct, ctinfo, bb);
+       case 1:
+               return h245_parse_response(pskb, ct, ctinfo, bb);
+       default:
+               return NF_ACCEPT;
+       }
+}
+
+/**
+ * Parse a TPKT/H.245 packet and handle NAT/expectations for the
+ * logical channel transport address (if applicable).
+ */
+static int h245_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;
+       struct asn1_per_buffer bb;
+
+       if (i + 4 > datalen)
+               return NF_ACCEPT;
+
+       /* 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 < datalen)
+               datalen = tpkt_len;
+
+       i += 2;
+
+       /* parse H.245 packet (ASN.1 PER) */
+       asn1_per_initialize(&bb, data, datalen, i);
+
+       return h245_parse(pskb, ct, ctinfo, &bb);
+}
+
+static int h245_help(struct sk_buff **pskb,
+                    struct ip_conntrack *ct,
+                    enum ip_conntrack_info ctinfo)
+{
+       struct tcphdr _tcph, *tcph;
+       unsigned char *data;
+       unsigned dataoff, datalen;
+       int ret;
+
+       /* 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;
+       }
+
+       tcph = skb_header_pointer(*pskb, (*pskb)->nh.iph->ihl*4,
+                                 sizeof(_tcph), &_tcph);
+       if (tcph == NULL)
+               return NF_ACCEPT;
+
+       DEBUGP("ct_h245_help: help entered %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n",
+               NIPQUAD((*pskb)->nh.iph->saddr), ntohs(tcph->source),
+               NIPQUAD((*pskb)->nh.iph->daddr), ntohs(tcph->dest));
+
+       dataoff = (*pskb)->nh.iph->ihl*4 + tcph->doff*4;
+       /* No data? */
+       if (dataoff >= (*pskb)->len) {
+               DEBUGP("ct_h245_help: skblen = %u\n", (*pskb)->len);
+               return NF_ACCEPT;
+       }
+       datalen = (*pskb)->len - dataoff;
+
+       if (datalen < 16)
+               return NF_ACCEPT;
+
+       LOCK_BH(&ip_h245_lock);
+       data = skb_header_pointer((*pskb), dataoff,
+                                 datalen, h245_buffer);
+       BUG_ON(data == NULL);
+
+       ret = h245_parse_tpkt(pskb, ct, ctinfo,
+                             data, datalen);
+
+       UNLOCK_BH(&ip_h245_lock);
+       return ret;
+}
+
+/* H.245 helper is not registered! */
+static struct ip_conntrack_helper h245 =
+{
+       .name = "H.245",
+       .max_expected = 8,
+       .timeout = 240,
+       .tuple = { .dst = { .protonum = IPPROTO_TCP } },
+       .mask = { .src = { .u = { 0xFFFF } },
+                 .dst = { .protonum = 0xFF } },
+       .help = h245_help
+};
+
+void ip_conntrack_h245_expect(struct ip_conntrack *new,
+                             struct ip_conntrack_expect *this)
+{
+       WRITE_LOCK(&ip_conntrack_lock);
+       new->helper = &h245;
+       DEBUGP("h225_expect: helper for %p added\n", new);
+       WRITE_UNLOCK(&ip_conntrack_lock);
+}
+EXPORT_SYMBOL_GPL(ip_conntrack_h245_expect);

Modified: netfilter-2.6/patch-o-matic-ng/trunk/net/ipv4/netfilter/ip_nat_h323.c
==============================================================================
--- netfilter-2.6/patch-o-matic-ng/trunk/net/ipv4/netfilter/ip_nat_h323.c       
(original)
+++ netfilter-2.6/patch-o-matic-ng/trunk/net/ipv4/netfilter/ip_nat_h323.c       
Fri May 20 12:18:33 2005
@@ -126,6 +126,54 @@
        return NF_ACCEPT;
 }
 
+static int ip_nat_h245(struct sk_buff **pskb,
+                      enum ip_conntrack_info ctinfo,
+                      unsigned int offset,
+                      struct ip_conntrack_expect *exp)
+{
+       u_int16_t port;
+       struct {
+               u_int32_t ip;
+               u_int16_t port;
+       } __attribute__ ((__packed__)) newdata;
+       int dir = CTINFO2DIR(ctinfo);
+       struct ip_conntrack *ct = exp->master;
+       int ret;
+
+       /* Connection will come from wherever this packet goes, hence !dir */
+       newdata.ip = ct->tuplehash[!dir].tuple.dst.ip;
+       exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
+       exp->dir = !dir;
+
+       /* When you see the packet, we need to NAT it the same as the
+        * this one. */
+       exp->expectfn = ip_nat_follow_master;
+
+       /* Try to get same port: if not, try to change it. */
+       for (port = ntohs(exp->saved_proto.tcp.port); port != 0; port++) {
+               exp->tuple.dst.u.tcp.port = htons(port);
+               if (ip_conntrack_expect_related(exp) == 0)
+                       break;
+       }
+
+       if (port == 0) {
+               ip_conntrack_expect_free(exp);
+               return NF_DROP;
+       }
+
+       newdata.port = htons(port);
+
+       /* now mangle packet */
+       ret = ip_nat_mangle_tcp_packet(pskb, ct, ctinfo,
+                                      offset,
+                                      sizeof(newdata),
+                                      (const char*)&newdata, sizeof(newdata));
+       if (!ret)
+               return NF_DROP;
+
+       return NF_ACCEPT;
+}
+
 static int __init init(void)
 {
        BUG_ON(ip_nat_h225_hook != NULL);
@@ -133,7 +181,7 @@
 
        ip_nat_h225_hook = ip_nat_h225;
        ip_nat_h225_signal_hook = ip_nat_h225_signal;
-       ip_nat_h245_hook = ip_nat_h225;
+       ip_nat_h245_hook = ip_nat_h245;
 
        return 0;
 }
_______________________________________________
pld-cvs-commit mailing list
[email protected]
http://lists.pld-linux.org/mailman/listinfo/pld-cvs-commit

Reply via email to