mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-28 18:51:56 -04:00
[NETFILTER]: nf_conntrack/nf_nat: add H.323 helper port
Add IPv4 and IPv6 capable nf_conntrack port of the H.323 conntrack/NAT helper. Signed-off-by: Patrick McHardy <[email protected]> Signed-off-by: David S. Miller <[email protected]>
This commit is contained in:
parent
1695890057
commit
f587de0e2f
15 changed files with 2600 additions and 14 deletions
|
|
@ -529,6 +529,11 @@ config IP_NF_NAT_H323
|
|||
default IP_NF_NAT if IP_NF_H323=y
|
||||
default m if IP_NF_H323=m
|
||||
|
||||
config NF_NAT_H323
|
||||
tristate
|
||||
depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT
|
||||
default NF_NAT && NF_CONNTRACK_H323
|
||||
|
||||
config IP_NF_NAT_SIP
|
||||
tristate
|
||||
depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ endif
|
|||
ip_conntrack_pptp-objs := ip_conntrack_helper_pptp.o ip_conntrack_proto_gre.o
|
||||
ip_nat_pptp-objs := ip_nat_helper_pptp.o ip_nat_proto_gre.o
|
||||
|
||||
ip_conntrack_h323-objs := ip_conntrack_helper_h323.o ip_conntrack_helper_h323_asn1.o
|
||||
ip_conntrack_h323-objs := ip_conntrack_helper_h323.o ../../netfilter/nf_conntrack_h323_asn1.o
|
||||
ip_nat_h323-objs := ip_nat_helper_h323.o
|
||||
|
||||
# connection tracking
|
||||
|
|
@ -52,6 +52,7 @@ obj-$(CONFIG_IP_NF_NAT_SIP) += ip_nat_sip.o
|
|||
# NAT helpers (nf_conntrack)
|
||||
obj-$(CONFIG_NF_NAT_AMANDA) += nf_nat_amanda.o
|
||||
obj-$(CONFIG_NF_NAT_FTP) += nf_nat_ftp.o
|
||||
obj-$(CONFIG_NF_NAT_H323) += nf_nat_h323.o
|
||||
|
||||
# generic IP tables
|
||||
obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o
|
||||
|
|
|
|||
|
|
@ -1,874 +0,0 @@
|
|||
/****************************************************************************
|
||||
* ip_conntrack_helper_h323_asn1.c - BER and PER decoding library for H.323
|
||||
* conntrack/NAT module.
|
||||
*
|
||||
* Copyright (c) 2006 by Jing Min Zhao <zhaojingmin@users.sourceforge.net>
|
||||
*
|
||||
* This source code is licensed under General Public License version 2.
|
||||
*
|
||||
* See ip_conntrack_helper_h323_asn1.h for details.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef __KERNEL__
|
||||
#include <linux/kernel.h>
|
||||
#else
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
#include <linux/netfilter_ipv4/ip_conntrack_helper_h323_asn1.h>
|
||||
|
||||
/* Trace Flag */
|
||||
#ifndef H323_TRACE
|
||||
#define H323_TRACE 0
|
||||
#endif
|
||||
|
||||
#if H323_TRACE
|
||||
#define TAB_SIZE 4
|
||||
#define IFTHEN(cond, act) if(cond){act;}
|
||||
#ifdef __KERNEL__
|
||||
#define PRINT printk
|
||||
#else
|
||||
#define PRINT printf
|
||||
#endif
|
||||
#define FNAME(name) name,
|
||||
#else
|
||||
#define IFTHEN(cond, act)
|
||||
#define PRINT(fmt, args...)
|
||||
#define FNAME(name)
|
||||
#endif
|
||||
|
||||
/* ASN.1 Types */
|
||||
#define NUL 0
|
||||
#define BOOL 1
|
||||
#define OID 2
|
||||
#define INT 3
|
||||
#define ENUM 4
|
||||
#define BITSTR 5
|
||||
#define NUMSTR 6
|
||||
#define NUMDGT 6
|
||||
#define TBCDSTR 6
|
||||
#define OCTSTR 7
|
||||
#define PRTSTR 7
|
||||
#define IA5STR 7
|
||||
#define GENSTR 7
|
||||
#define BMPSTR 8
|
||||
#define SEQ 9
|
||||
#define SET 9
|
||||
#define SEQOF 10
|
||||
#define SETOF 10
|
||||
#define CHOICE 11
|
||||
|
||||
/* Constraint Types */
|
||||
#define FIXD 0
|
||||
/* #define BITS 1-8 */
|
||||
#define BYTE 9
|
||||
#define WORD 10
|
||||
#define CONS 11
|
||||
#define SEMI 12
|
||||
#define UNCO 13
|
||||
|
||||
/* ASN.1 Type Attributes */
|
||||
#define SKIP 0
|
||||
#define STOP 1
|
||||
#define DECODE 2
|
||||
#define EXT 4
|
||||
#define OPEN 8
|
||||
#define OPT 16
|
||||
|
||||
|
||||
/* ASN.1 Field Structure */
|
||||
typedef struct field_t {
|
||||
#if H323_TRACE
|
||||
char *name;
|
||||
#endif
|
||||
unsigned char type;
|
||||
unsigned char sz;
|
||||
unsigned char lb;
|
||||
unsigned char ub;
|
||||
unsigned short attr;
|
||||
unsigned short offset;
|
||||
struct field_t *fields;
|
||||
} field_t;
|
||||
|
||||
/* Bit Stream */
|
||||
typedef struct {
|
||||
unsigned char *buf;
|
||||
unsigned char *beg;
|
||||
unsigned char *end;
|
||||
unsigned char *cur;
|
||||
unsigned bit;
|
||||
} bitstr_t;
|
||||
|
||||
/* Tool Functions */
|
||||
#define INC_BIT(bs) if((++bs->bit)>7){bs->cur++;bs->bit=0;}
|
||||
#define INC_BITS(bs,b) if((bs->bit+=b)>7){bs->cur+=bs->bit>>3;bs->bit&=7;}
|
||||
#define BYTE_ALIGN(bs) if(bs->bit){bs->cur++;bs->bit=0;}
|
||||
#define CHECK_BOUND(bs,n) if(bs->cur+(n)>bs->end)return(H323_ERROR_BOUND)
|
||||
static unsigned get_len(bitstr_t * bs);
|
||||
static unsigned get_bit(bitstr_t * bs);
|
||||
static unsigned get_bits(bitstr_t * bs, unsigned b);
|
||||
static unsigned get_bitmap(bitstr_t * bs, unsigned b);
|
||||
static unsigned get_uint(bitstr_t * bs, int b);
|
||||
|
||||
/* Decoder Functions */
|
||||
static int decode_nul(bitstr_t * bs, field_t * f, char *base, int level);
|
||||
static int decode_bool(bitstr_t * bs, field_t * f, char *base, int level);
|
||||
static int decode_oid(bitstr_t * bs, field_t * f, char *base, int level);
|
||||
static int decode_int(bitstr_t * bs, field_t * f, char *base, int level);
|
||||
static int decode_enum(bitstr_t * bs, field_t * f, char *base, int level);
|
||||
static int decode_bitstr(bitstr_t * bs, field_t * f, char *base, int level);
|
||||
static int decode_numstr(bitstr_t * bs, field_t * f, char *base, int level);
|
||||
static int decode_octstr(bitstr_t * bs, field_t * f, char *base, int level);
|
||||
static int decode_bmpstr(bitstr_t * bs, field_t * f, char *base, int level);
|
||||
static int decode_seq(bitstr_t * bs, field_t * f, char *base, int level);
|
||||
static int decode_seqof(bitstr_t * bs, field_t * f, char *base, int level);
|
||||
static int decode_choice(bitstr_t * bs, field_t * f, char *base, int level);
|
||||
|
||||
/* Decoder Functions Vector */
|
||||
typedef int (*decoder_t) (bitstr_t *, field_t *, char *, int);
|
||||
static decoder_t Decoders[] = {
|
||||
decode_nul,
|
||||
decode_bool,
|
||||
decode_oid,
|
||||
decode_int,
|
||||
decode_enum,
|
||||
decode_bitstr,
|
||||
decode_numstr,
|
||||
decode_octstr,
|
||||
decode_bmpstr,
|
||||
decode_seq,
|
||||
decode_seqof,
|
||||
decode_choice,
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* H.323 Types
|
||||
****************************************************************************/
|
||||
#include "ip_conntrack_helper_h323_types.c"
|
||||
|
||||
/****************************************************************************
|
||||
* Functions
|
||||
****************************************************************************/
|
||||
/* Assume bs is aligned && v < 16384 */
|
||||
unsigned get_len(bitstr_t * bs)
|
||||
{
|
||||
unsigned v;
|
||||
|
||||
v = *bs->cur++;
|
||||
|
||||
if (v & 0x80) {
|
||||
v &= 0x3f;
|
||||
v <<= 8;
|
||||
v += *bs->cur++;
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
unsigned get_bit(bitstr_t * bs)
|
||||
{
|
||||
unsigned b = (*bs->cur) & (0x80 >> bs->bit);
|
||||
|
||||
INC_BIT(bs);
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
/* Assume b <= 8 */
|
||||
unsigned get_bits(bitstr_t * bs, unsigned b)
|
||||
{
|
||||
unsigned v, l;
|
||||
|
||||
v = (*bs->cur) & (0xffU >> bs->bit);
|
||||
l = b + bs->bit;
|
||||
|
||||
if (l < 8) {
|
||||
v >>= 8 - l;
|
||||
bs->bit = l;
|
||||
} else if (l == 8) {
|
||||
bs->cur++;
|
||||
bs->bit = 0;
|
||||
} else { /* l > 8 */
|
||||
|
||||
v <<= 8;
|
||||
v += *(++bs->cur);
|
||||
v >>= 16 - l;
|
||||
bs->bit = l - 8;
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
/* Assume b <= 32 */
|
||||
unsigned get_bitmap(bitstr_t * bs, unsigned b)
|
||||
{
|
||||
unsigned v, l, shift, bytes;
|
||||
|
||||
if (!b)
|
||||
return 0;
|
||||
|
||||
l = bs->bit + b;
|
||||
|
||||
if (l < 8) {
|
||||
v = (unsigned) (*bs->cur) << (bs->bit + 24);
|
||||
bs->bit = l;
|
||||
} else if (l == 8) {
|
||||
v = (unsigned) (*bs->cur++) << (bs->bit + 24);
|
||||
bs->bit = 0;
|
||||
} else {
|
||||
for (bytes = l >> 3, shift = 24, v = 0; bytes;
|
||||
bytes--, shift -= 8)
|
||||
v |= (unsigned) (*bs->cur++) << shift;
|
||||
|
||||
if (l < 32) {
|
||||
v |= (unsigned) (*bs->cur) << shift;
|
||||
v <<= bs->bit;
|
||||
} else if (l > 32) {
|
||||
v <<= bs->bit;
|
||||
v |= (*bs->cur) >> (8 - bs->bit);
|
||||
}
|
||||
|
||||
bs->bit = l & 0x7;
|
||||
}
|
||||
|
||||
v &= 0xffffffff << (32 - b);
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Assume bs is aligned and sizeof(unsigned int) == 4
|
||||
****************************************************************************/
|
||||
unsigned get_uint(bitstr_t * bs, int b)
|
||||
{
|
||||
unsigned v = 0;
|
||||
|
||||
switch (b) {
|
||||
case 4:
|
||||
v |= *bs->cur++;
|
||||
v <<= 8;
|
||||
case 3:
|
||||
v |= *bs->cur++;
|
||||
v <<= 8;
|
||||
case 2:
|
||||
v |= *bs->cur++;
|
||||
v <<= 8;
|
||||
case 1:
|
||||
v |= *bs->cur++;
|
||||
break;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
int decode_nul(bitstr_t * bs, field_t * f, char *base, int level)
|
||||
{
|
||||
PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name);
|
||||
|
||||
return H323_ERROR_NONE;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
int decode_bool(bitstr_t * bs, field_t * f, char *base, int level)
|
||||
{
|
||||
PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name);
|
||||
|
||||
INC_BIT(bs);
|
||||
|
||||
CHECK_BOUND(bs, 0);
|
||||
return H323_ERROR_NONE;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
int decode_oid(bitstr_t * bs, field_t * f, char *base, int level)
|
||||
{
|
||||
int len;
|
||||
|
||||
PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name);
|
||||
|
||||
BYTE_ALIGN(bs);
|
||||
CHECK_BOUND(bs, 1);
|
||||
len = *bs->cur++;
|
||||
bs->cur += len;
|
||||
|
||||
CHECK_BOUND(bs, 0);
|
||||
return H323_ERROR_NONE;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
int decode_int(bitstr_t * bs, field_t * f, char *base, int level)
|
||||
{
|
||||
unsigned len;
|
||||
|
||||
PRINT("%*.s%s", level * TAB_SIZE, " ", f->name);
|
||||
|
||||
switch (f->sz) {
|
||||
case BYTE: /* Range == 256 */
|
||||
BYTE_ALIGN(bs);
|
||||
bs->cur++;
|
||||
break;
|
||||
case WORD: /* 257 <= Range <= 64K */
|
||||
BYTE_ALIGN(bs);
|
||||
bs->cur += 2;
|
||||
break;
|
||||
case CONS: /* 64K < Range < 4G */
|
||||
len = get_bits(bs, 2) + 1;
|
||||
BYTE_ALIGN(bs);
|
||||
if (base && (f->attr & DECODE)) { /* timeToLive */
|
||||
unsigned v = get_uint(bs, len) + f->lb;
|
||||
PRINT(" = %u", v);
|
||||
*((unsigned *) (base + f->offset)) = v;
|
||||
}
|
||||
bs->cur += len;
|
||||
break;
|
||||
case UNCO:
|
||||
BYTE_ALIGN(bs);
|
||||
CHECK_BOUND(bs, 2);
|
||||
len = get_len(bs);
|
||||
bs->cur += len;
|
||||
break;
|
||||
default: /* 2 <= Range <= 255 */
|
||||
INC_BITS(bs, f->sz);
|
||||
break;
|
||||
}
|
||||
|
||||
PRINT("\n");
|
||||
|
||||
CHECK_BOUND(bs, 0);
|
||||
return H323_ERROR_NONE;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
int decode_enum(bitstr_t * bs, field_t * f, char *base, int level)
|
||||
{
|
||||
PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name);
|
||||
|
||||
if ((f->attr & EXT) && get_bit(bs)) {
|
||||
INC_BITS(bs, 7);
|
||||
} else {
|
||||
INC_BITS(bs, f->sz);
|
||||
}
|
||||
|
||||
CHECK_BOUND(bs, 0);
|
||||
return H323_ERROR_NONE;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
int decode_bitstr(bitstr_t * bs, field_t * f, char *base, int level)
|
||||
{
|
||||
unsigned len;
|
||||
|
||||
PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name);
|
||||
|
||||
BYTE_ALIGN(bs);
|
||||
switch (f->sz) {
|
||||
case FIXD: /* fixed length > 16 */
|
||||
len = f->lb;
|
||||
break;
|
||||
case WORD: /* 2-byte length */
|
||||
CHECK_BOUND(bs, 2);
|
||||
len = (*bs->cur++) << 8;
|
||||
len += (*bs->cur++) + f->lb;
|
||||
break;
|
||||
case SEMI:
|
||||
CHECK_BOUND(bs, 2);
|
||||
len = get_len(bs);
|
||||
break;
|
||||
default:
|
||||
len = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
bs->cur += len >> 3;
|
||||
bs->bit = len & 7;
|
||||
|
||||
CHECK_BOUND(bs, 0);
|
||||
return H323_ERROR_NONE;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
int decode_numstr(bitstr_t * bs, field_t * f, char *base, int level)
|
||||
{
|
||||
unsigned len;
|
||||
|
||||
PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name);
|
||||
|
||||
/* 2 <= Range <= 255 */
|
||||
len = get_bits(bs, f->sz) + f->lb;
|
||||
|
||||
BYTE_ALIGN(bs);
|
||||
INC_BITS(bs, (len << 2));
|
||||
|
||||
CHECK_BOUND(bs, 0);
|
||||
return H323_ERROR_NONE;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
int decode_octstr(bitstr_t * bs, field_t * f, char *base, int level)
|
||||
{
|
||||
unsigned len;
|
||||
|
||||
PRINT("%*.s%s", level * TAB_SIZE, " ", f->name);
|
||||
|
||||
switch (f->sz) {
|
||||
case FIXD: /* Range == 1 */
|
||||
if (f->lb > 2) {
|
||||
BYTE_ALIGN(bs);
|
||||
if (base && (f->attr & DECODE)) {
|
||||
/* The IP Address */
|
||||
IFTHEN(f->lb == 4,
|
||||
PRINT(" = %d.%d.%d.%d:%d",
|
||||
bs->cur[0], bs->cur[1],
|
||||
bs->cur[2], bs->cur[3],
|
||||
bs->cur[4] * 256 + bs->cur[5]));
|
||||
*((unsigned *) (base + f->offset)) =
|
||||
bs->cur - bs->buf;
|
||||
}
|
||||
}
|
||||
len = f->lb;
|
||||
break;
|
||||
case BYTE: /* Range == 256 */
|
||||
BYTE_ALIGN(bs);
|
||||
CHECK_BOUND(bs, 1);
|
||||
len = (*bs->cur++) + f->lb;
|
||||
break;
|
||||
case SEMI:
|
||||
BYTE_ALIGN(bs);
|
||||
CHECK_BOUND(bs, 2);
|
||||
len = get_len(bs) + f->lb;
|
||||
break;
|
||||
default: /* 2 <= Range <= 255 */
|
||||
len = get_bits(bs, f->sz) + f->lb;
|
||||
BYTE_ALIGN(bs);
|
||||
break;
|
||||
}
|
||||
|
||||
bs->cur += len;
|
||||
|
||||
PRINT("\n");
|
||||
|
||||
CHECK_BOUND(bs, 0);
|
||||
return H323_ERROR_NONE;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
int decode_bmpstr(bitstr_t * bs, field_t * f, char *base, int level)
|
||||
{
|
||||
unsigned len;
|
||||
|
||||
PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name);
|
||||
|
||||
switch (f->sz) {
|
||||
case BYTE: /* Range == 256 */
|
||||
BYTE_ALIGN(bs);
|
||||
CHECK_BOUND(bs, 1);
|
||||
len = (*bs->cur++) + f->lb;
|
||||
break;
|
||||
default: /* 2 <= Range <= 255 */
|
||||
len = get_bits(bs, f->sz) + f->lb;
|
||||
BYTE_ALIGN(bs);
|
||||
break;
|
||||
}
|
||||
|
||||
bs->cur += len << 1;
|
||||
|
||||
CHECK_BOUND(bs, 0);
|
||||
return H323_ERROR_NONE;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
int decode_seq(bitstr_t * bs, field_t * f, char *base, int level)
|
||||
{
|
||||
unsigned ext, bmp, i, opt, len = 0, bmp2, bmp2_len;
|
||||
int err;
|
||||
field_t *son;
|
||||
unsigned char *beg = NULL;
|
||||
|
||||
PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name);
|
||||
|
||||
/* Decode? */
|
||||
base = (base && (f->attr & DECODE)) ? base + f->offset : NULL;
|
||||
|
||||
/* Extensible? */
|
||||
ext = (f->attr & EXT) ? get_bit(bs) : 0;
|
||||
|
||||
/* Get fields bitmap */
|
||||
bmp = get_bitmap(bs, f->sz);
|
||||
if (base)
|
||||
*(unsigned *) base = bmp;
|
||||
|
||||
/* Decode the root components */
|
||||
for (i = opt = 0, son = f->fields; i < f->lb; i++, son++) {
|
||||
if (son->attr & STOP) {
|
||||
PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, " ",
|
||||
son->name);
|
||||
return H323_ERROR_STOP;
|
||||
}
|
||||
|
||||
if (son->attr & OPT) { /* Optional component */
|
||||
if (!((0x80000000U >> (opt++)) & bmp)) /* Not exist */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Decode */
|
||||
if (son->attr & OPEN) { /* Open field */
|
||||
CHECK_BOUND(bs, 2);
|
||||
len = get_len(bs);
|
||||
CHECK_BOUND(bs, len);
|
||||
if (!base) {
|
||||
PRINT("%*.s%s\n", (level + 1) * TAB_SIZE,
|
||||
" ", son->name);
|
||||
bs->cur += len;
|
||||
continue;
|
||||
}
|
||||
beg = bs->cur;
|
||||
|
||||
/* Decode */
|
||||
if ((err = (Decoders[son->type]) (bs, son, base,
|
||||
level + 1)) <
|
||||
H323_ERROR_NONE)
|
||||
return err;
|
||||
|
||||
bs->cur = beg + len;
|
||||
bs->bit = 0;
|
||||
} else if ((err = (Decoders[son->type]) (bs, son, base,
|
||||
level + 1)) <
|
||||
H323_ERROR_NONE)
|
||||
return err;
|
||||
}
|
||||
|
||||
/* No extension? */
|
||||
if (!ext)
|
||||
return H323_ERROR_NONE;
|
||||
|
||||
/* Get the extension bitmap */
|
||||
bmp2_len = get_bits(bs, 7) + 1;
|
||||
CHECK_BOUND(bs, (bmp2_len + 7) >> 3);
|
||||
bmp2 = get_bitmap(bs, bmp2_len);
|
||||
bmp |= bmp2 >> f->sz;
|
||||
if (base)
|
||||
*(unsigned *) base = bmp;
|
||||
BYTE_ALIGN(bs);
|
||||
|
||||
/* Decode the extension components */
|
||||
for (opt = 0; opt < bmp2_len; opt++, i++, son++) {
|
||||
if (i < f->ub && son->attr & STOP) {
|
||||
PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, " ",
|
||||
son->name);
|
||||
return H323_ERROR_STOP;
|
||||
}
|
||||
|
||||
if (!((0x80000000 >> opt) & bmp2)) /* Not present */
|
||||
continue;
|
||||
|
||||
/* Check Range */
|
||||
if (i >= f->ub) { /* Newer Version? */
|
||||
CHECK_BOUND(bs, 2);
|
||||
len = get_len(bs);
|
||||
CHECK_BOUND(bs, len);
|
||||
bs->cur += len;
|
||||
continue;
|
||||
}
|
||||
|
||||
CHECK_BOUND(bs, 2);
|
||||
len = get_len(bs);
|
||||
CHECK_BOUND(bs, len);
|
||||
if (!base || !(son->attr & DECODE)) {
|
||||
PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, " ",
|
||||
son->name);
|
||||
bs->cur += len;
|
||||
continue;
|
||||
}
|
||||
beg = bs->cur;
|
||||
|
||||
if ((err = (Decoders[son->type]) (bs, son, base,
|
||||
level + 1)) <
|
||||
H323_ERROR_NONE)
|
||||
return err;
|
||||
|
||||
bs->cur = beg + len;
|
||||
bs->bit = 0;
|
||||
}
|
||||
return H323_ERROR_NONE;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
int decode_seqof(bitstr_t * bs, field_t * f, char *base, int level)
|
||||
{
|
||||
unsigned count, effective_count = 0, i, len = 0;
|
||||
int err;
|
||||
field_t *son;
|
||||
unsigned char *beg = NULL;
|
||||
|
||||
PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name);
|
||||
|
||||
/* Decode? */
|
||||
base = (base && (f->attr & DECODE)) ? base + f->offset : NULL;
|
||||
|
||||
/* Decode item count */
|
||||
switch (f->sz) {
|
||||
case BYTE:
|
||||
BYTE_ALIGN(bs);
|
||||
CHECK_BOUND(bs, 1);
|
||||
count = *bs->cur++;
|
||||
break;
|
||||
case WORD:
|
||||
BYTE_ALIGN(bs);
|
||||
CHECK_BOUND(bs, 2);
|
||||
count = *bs->cur++;
|
||||
count <<= 8;
|
||||
count = *bs->cur++;
|
||||
break;
|
||||
case SEMI:
|
||||
BYTE_ALIGN(bs);
|
||||
CHECK_BOUND(bs, 2);
|
||||
count = get_len(bs);
|
||||
break;
|
||||
default:
|
||||
count = get_bits(bs, f->sz);
|
||||
break;
|
||||
}
|
||||
count += f->lb;
|
||||
|
||||
/* Write Count */
|
||||
if (base) {
|
||||
effective_count = count > f->ub ? f->ub : count;
|
||||
*(unsigned *) base = effective_count;
|
||||
base += sizeof(unsigned);
|
||||
}
|
||||
|
||||
/* Decode nested field */
|
||||
son = f->fields;
|
||||
if (base)
|
||||
base -= son->offset;
|
||||
for (i = 0; i < count; i++) {
|
||||
if (son->attr & OPEN) {
|
||||
BYTE_ALIGN(bs);
|
||||
len = get_len(bs);
|
||||
CHECK_BOUND(bs, len);
|
||||
if (!base || !(son->attr & DECODE)) {
|
||||
PRINT("%*.s%s\n", (level + 1) * TAB_SIZE,
|
||||
" ", son->name);
|
||||
bs->cur += len;
|
||||
continue;
|
||||
}
|
||||
beg = bs->cur;
|
||||
|
||||
if ((err = (Decoders[son->type]) (bs, son,
|
||||
i <
|
||||
effective_count ?
|
||||
base : NULL,
|
||||
level + 1)) <
|
||||
H323_ERROR_NONE)
|
||||
return err;
|
||||
|
||||
bs->cur = beg + len;
|
||||
bs->bit = 0;
|
||||
} else
|
||||
if ((err = (Decoders[son->type]) (bs, son,
|
||||
i <
|
||||
effective_count ?
|
||||
base : NULL,
|
||||
level + 1)) <
|
||||
H323_ERROR_NONE)
|
||||
return err;
|
||||
|
||||
if (base)
|
||||
base += son->offset;
|
||||
}
|
||||
|
||||
return H323_ERROR_NONE;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************/
|
||||
int decode_choice(bitstr_t * bs, field_t * f, char *base, int level)
|
||||
{
|
||||
unsigned type, ext, len = 0;
|
||||
int err;
|
||||
field_t *son;
|
||||
unsigned char *beg = NULL;
|
||||
|
||||
PRINT("%*.s%s\n", level * TAB_SIZE, " ", f->name);
|
||||
|
||||
/* Decode? */
|
||||
base = (base && (f->attr & DECODE)) ? base + f->offset : NULL;
|
||||
|
||||
/* Decode the choice index number */
|
||||
if ((f->attr & EXT) && get_bit(bs)) {
|
||||
ext = 1;
|
||||
type = get_bits(bs, 7) + f->lb;
|
||||
} else {
|
||||
ext = 0;
|
||||
type = get_bits(bs, f->sz);
|
||||
}
|
||||
|
||||
/* Write Type */
|
||||
if (base)
|
||||
*(unsigned *) base = type;
|
||||
|
||||
/* Check Range */
|
||||
if (type >= f->ub) { /* Newer version? */
|
||||
BYTE_ALIGN(bs);
|
||||
len = get_len(bs);
|
||||
CHECK_BOUND(bs, len);
|
||||
bs->cur += len;
|
||||
return H323_ERROR_NONE;
|
||||
}
|
||||
|
||||
/* Transfer to son level */
|
||||
son = &f->fields[type];
|
||||
if (son->attr & STOP) {
|
||||
PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, " ", son->name);
|
||||
return H323_ERROR_STOP;
|
||||
}
|
||||
|
||||
if (ext || (son->attr & OPEN)) {
|
||||
BYTE_ALIGN(bs);
|
||||
len = get_len(bs);
|
||||
CHECK_BOUND(bs, len);
|
||||
if (!base || !(son->attr & DECODE)) {
|
||||
PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, " ",
|
||||
son->name);
|
||||
bs->cur += len;
|
||||
return H323_ERROR_NONE;
|
||||
}
|
||||
beg = bs->cur;
|
||||
|
||||
if ((err = (Decoders[son->type]) (bs, son, base, level + 1)) <
|
||||
H323_ERROR_NONE)
|
||||
return err;
|
||||
|
||||
bs->cur = beg + len;
|
||||
bs->bit = 0;
|
||||
} else if ((err = (Decoders[son->type]) (bs, son, base, level + 1)) <
|
||||
H323_ERROR_NONE)
|
||||
return err;
|
||||
|
||||
return H323_ERROR_NONE;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
int DecodeRasMessage(unsigned char *buf, size_t sz, RasMessage * ras)
|
||||
{
|
||||
static field_t ras_message = {
|
||||
FNAME("RasMessage") CHOICE, 5, 24, 32, DECODE | EXT,
|
||||
0, _RasMessage
|
||||
};
|
||||
bitstr_t bs;
|
||||
|
||||
bs.buf = bs.beg = bs.cur = buf;
|
||||
bs.end = buf + sz;
|
||||
bs.bit = 0;
|
||||
|
||||
return decode_choice(&bs, &ras_message, (char *) ras, 0);
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
static int DecodeH323_UserInformation(unsigned char *buf, unsigned char *beg,
|
||||
size_t sz, H323_UserInformation * uuie)
|
||||
{
|
||||
static field_t h323_userinformation = {
|
||||
FNAME("H323-UserInformation") SEQ, 1, 2, 2, DECODE | EXT,
|
||||
0, _H323_UserInformation
|
||||
};
|
||||
bitstr_t bs;
|
||||
|
||||
bs.buf = buf;
|
||||
bs.beg = bs.cur = beg;
|
||||
bs.end = beg + sz;
|
||||
bs.bit = 0;
|
||||
|
||||
return decode_seq(&bs, &h323_userinformation, (char *) uuie, 0);
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
int DecodeMultimediaSystemControlMessage(unsigned char *buf, size_t sz,
|
||||
MultimediaSystemControlMessage *
|
||||
mscm)
|
||||
{
|
||||
static field_t multimediasystemcontrolmessage = {
|
||||
FNAME("MultimediaSystemControlMessage") CHOICE, 2, 4, 4,
|
||||
DECODE | EXT, 0, _MultimediaSystemControlMessage
|
||||
};
|
||||
bitstr_t bs;
|
||||
|
||||
bs.buf = bs.beg = bs.cur = buf;
|
||||
bs.end = buf + sz;
|
||||
bs.bit = 0;
|
||||
|
||||
return decode_choice(&bs, &multimediasystemcontrolmessage,
|
||||
(char *) mscm, 0);
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
int DecodeQ931(unsigned char *buf, size_t sz, Q931 * q931)
|
||||
{
|
||||
unsigned char *p = buf;
|
||||
int len;
|
||||
|
||||
if (!p || sz < 1)
|
||||
return H323_ERROR_BOUND;
|
||||
|
||||
/* Protocol Discriminator */
|
||||
if (*p != 0x08) {
|
||||
PRINT("Unknown Protocol Discriminator\n");
|
||||
return H323_ERROR_RANGE;
|
||||
}
|
||||
p++;
|
||||
sz--;
|
||||
|
||||
/* CallReferenceValue */
|
||||
if (sz < 1)
|
||||
return H323_ERROR_BOUND;
|
||||
len = *p++;
|
||||
sz--;
|
||||
if (sz < len)
|
||||
return H323_ERROR_BOUND;
|
||||
p += len;
|
||||
sz -= len;
|
||||
|
||||
/* Message Type */
|
||||
if (sz < 1)
|
||||
return H323_ERROR_BOUND;
|
||||
q931->MessageType = *p++;
|
||||
PRINT("MessageType = %02X\n", q931->MessageType);
|
||||
if (*p & 0x80) {
|
||||
p++;
|
||||
sz--;
|
||||
}
|
||||
|
||||
/* Decode Information Elements */
|
||||
while (sz > 0) {
|
||||
if (*p == 0x7e) { /* UserUserIE */
|
||||
if (sz < 3)
|
||||
break;
|
||||
p++;
|
||||
len = *p++ << 8;
|
||||
len |= *p++;
|
||||
sz -= 3;
|
||||
if (sz < len)
|
||||
break;
|
||||
p++;
|
||||
len--;
|
||||
return DecodeH323_UserInformation(buf, p, len,
|
||||
&q931->UUIE);
|
||||
}
|
||||
p++;
|
||||
sz--;
|
||||
if (sz < 1)
|
||||
break;
|
||||
len = *p++;
|
||||
if (sz < len)
|
||||
break;
|
||||
p += len;
|
||||
sz -= len;
|
||||
}
|
||||
|
||||
PRINT("Q.931 UUIE not found\n");
|
||||
|
||||
return H323_ERROR_BOUND;
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
596
net/ipv4/netfilter/nf_nat_h323.c
Normal file
596
net/ipv4/netfilter/nf_nat_h323.c
Normal file
|
|
@ -0,0 +1,596 @@
|
|||
/*
|
||||
* H.323 extension for NAT alteration.
|
||||
*
|
||||
* Copyright (c) 2006 Jing Min Zhao <zhaojingmin@users.sourceforge.net>
|
||||
*
|
||||
* This source code is licensed under General Public License version 2.
|
||||
*
|
||||
* Based on the 'brute force' H.323 NAT module by
|
||||
* Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/tcp.h>
|
||||
#include <net/tcp.h>
|
||||
|
||||
#include <net/netfilter/nf_nat.h>
|
||||
#include <net/netfilter/nf_nat_helper.h>
|
||||
#include <net/netfilter/nf_nat_rule.h>
|
||||
#include <net/netfilter/nf_conntrack_helper.h>
|
||||
#include <net/netfilter/nf_conntrack_expect.h>
|
||||
#include <linux/netfilter/nf_conntrack_h323.h>
|
||||
|
||||
#if 0
|
||||
#define DEBUGP printk
|
||||
#else
|
||||
#define DEBUGP(format, args...)
|
||||
#endif
|
||||
|
||||
/****************************************************************************/
|
||||
static int set_addr(struct sk_buff **pskb,
|
||||
unsigned char **data, int dataoff,
|
||||
unsigned int addroff, __be32 ip, __be16 port)
|
||||
{
|
||||
enum ip_conntrack_info ctinfo;
|
||||
struct nf_conn *ct = ip_conntrack_get(*pskb, &ctinfo);
|
||||
struct {
|
||||
__be32 ip;
|
||||
__be16 port;
|
||||
} __attribute__ ((__packed__)) buf;
|
||||
struct tcphdr _tcph, *th;
|
||||
|
||||
buf.ip = ip;
|
||||
buf.port = port;
|
||||
addroff += dataoff;
|
||||
|
||||
if ((*pskb)->nh.iph->protocol == IPPROTO_TCP) {
|
||||
if (!nf_nat_mangle_tcp_packet(pskb, ct, ctinfo,
|
||||
addroff, sizeof(buf),
|
||||
(char *) &buf, sizeof(buf))) {
|
||||
if (net_ratelimit())
|
||||
printk("nf_nat_h323: nf_nat_mangle_tcp_packet"
|
||||
" error\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Relocate data pointer */
|
||||
th = skb_header_pointer(*pskb, (*pskb)->nh.iph->ihl * 4,
|
||||
sizeof(_tcph), &_tcph);
|
||||
if (th == NULL)
|
||||
return -1;
|
||||
*data = (*pskb)->data + (*pskb)->nh.iph->ihl * 4 +
|
||||
th->doff * 4 + dataoff;
|
||||
} else {
|
||||
if (!nf_nat_mangle_udp_packet(pskb, ct, ctinfo,
|
||||
addroff, sizeof(buf),
|
||||
(char *) &buf, sizeof(buf))) {
|
||||
if (net_ratelimit())
|
||||
printk("nf_nat_h323: nf_nat_mangle_udp_packet"
|
||||
" error\n");
|
||||
return -1;
|
||||
}
|
||||
/* nf_nat_mangle_udp_packet uses skb_make_writable() to copy
|
||||
* or pull everything in a linear buffer, so we can safely
|
||||
* use the skb pointers now */
|
||||
*data = (*pskb)->data + (*pskb)->nh.iph->ihl * 4 +
|
||||
sizeof(struct udphdr);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
static int set_h225_addr(struct sk_buff **pskb,
|
||||
unsigned char **data, int dataoff,
|
||||
TransportAddress *taddr,
|
||||
union nf_conntrack_address *addr, __be16 port)
|
||||
{
|
||||
return set_addr(pskb, data, dataoff, taddr->ipAddress.ip,
|
||||
addr->ip, port);
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
static int set_h245_addr(struct sk_buff **pskb,
|
||||
unsigned char **data, int dataoff,
|
||||
H245_TransportAddress *taddr,
|
||||
union nf_conntrack_address *addr, __be16 port)
|
||||
{
|
||||
return set_addr(pskb, data, dataoff,
|
||||
taddr->unicastAddress.iPAddress.network,
|
||||
addr->ip, port);
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
static int set_sig_addr(struct sk_buff **pskb, struct nf_conn *ct,
|
||||
enum ip_conntrack_info ctinfo,
|
||||
unsigned char **data,
|
||||
TransportAddress *taddr, int count)
|
||||
{
|
||||
struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info;
|
||||
int dir = CTINFO2DIR(ctinfo);
|
||||
int i;
|
||||
__be16 port;
|
||||
union nf_conntrack_address addr;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
if (get_h225_addr(ct, *data, &taddr[i], &addr, &port)) {
|
||||
if (addr.ip == ct->tuplehash[dir].tuple.src.u3.ip &&
|
||||
port == info->sig_port[dir]) {
|
||||
/* GW->GK */
|
||||
|
||||
/* Fix for Gnomemeeting */
|
||||
if (i > 0 &&
|
||||
get_h225_addr(ct, *data, &taddr[0],
|
||||
&addr, &port) &&
|
||||
(ntohl(addr.ip) & 0xff000000) == 0x7f000000)
|
||||
i = 0;
|
||||
|
||||
DEBUGP
|
||||
("nf_nat_ras: set signal address "
|
||||
"%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
|
||||
NIPQUAD(ip), port,
|
||||
NIPQUAD(ct->tuplehash[!dir].tuple.dst.
|
||||
ip), info->sig_port[!dir]);
|
||||
return set_h225_addr(pskb, data, 0, &taddr[i],
|
||||
&ct->tuplehash[!dir].
|
||||
tuple.dst.u3,
|
||||
info->sig_port[!dir]);
|
||||
} else if (addr.ip == ct->tuplehash[dir].tuple.dst.u3.ip &&
|
||||
port == info->sig_port[dir]) {
|
||||
/* GK->GW */
|
||||
DEBUGP
|
||||
("nf_nat_ras: set signal address "
|
||||
"%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
|
||||
NIPQUAD(ip), port,
|
||||
NIPQUAD(ct->tuplehash[!dir].tuple.src.
|
||||
ip), info->sig_port[!dir]);
|
||||
return set_h225_addr(pskb, data, 0, &taddr[i],
|
||||
&ct->tuplehash[!dir].
|
||||
tuple.src.u3,
|
||||
info->sig_port[!dir]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
static int set_ras_addr(struct sk_buff **pskb, struct nf_conn *ct,
|
||||
enum ip_conntrack_info ctinfo,
|
||||
unsigned char **data,
|
||||
TransportAddress *taddr, int count)
|
||||
{
|
||||
int dir = CTINFO2DIR(ctinfo);
|
||||
int i;
|
||||
__be16 port;
|
||||
union nf_conntrack_address addr;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
if (get_h225_addr(ct, *data, &taddr[i], &addr, &port) &&
|
||||
addr.ip == ct->tuplehash[dir].tuple.src.u3.ip &&
|
||||
port == ct->tuplehash[dir].tuple.src.u.udp.port) {
|
||||
DEBUGP("nf_nat_ras: set rasAddress "
|
||||
"%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
|
||||
NIPQUAD(ip), ntohs(port),
|
||||
NIPQUAD(ct->tuplehash[!dir].tuple.dst.u3.ip),
|
||||
ntohs(ct->tuplehash[!dir].tuple.dst.u.udp.
|
||||
port));
|
||||
return set_h225_addr(pskb, data, 0, &taddr[i],
|
||||
&ct->tuplehash[!dir].tuple.dst.u3,
|
||||
ct->tuplehash[!dir].tuple.
|
||||
dst.u.udp.port);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
static int nat_rtp_rtcp(struct sk_buff **pskb, struct nf_conn *ct,
|
||||
enum ip_conntrack_info ctinfo,
|
||||
unsigned char **data, int dataoff,
|
||||
H245_TransportAddress *taddr,
|
||||
__be16 port, __be16 rtp_port,
|
||||
struct nf_conntrack_expect *rtp_exp,
|
||||
struct nf_conntrack_expect *rtcp_exp)
|
||||
{
|
||||
struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info;
|
||||
int dir = CTINFO2DIR(ctinfo);
|
||||
int i;
|
||||
u_int16_t nated_port;
|
||||
|
||||
/* Set expectations for NAT */
|
||||
rtp_exp->saved_proto.udp.port = rtp_exp->tuple.dst.u.udp.port;
|
||||
rtp_exp->expectfn = nf_nat_follow_master;
|
||||
rtp_exp->dir = !dir;
|
||||
rtcp_exp->saved_proto.udp.port = rtcp_exp->tuple.dst.u.udp.port;
|
||||
rtcp_exp->expectfn = nf_nat_follow_master;
|
||||
rtcp_exp->dir = !dir;
|
||||
|
||||
/* Lookup existing expects */
|
||||
for (i = 0; i < H323_RTP_CHANNEL_MAX; i++) {
|
||||
if (info->rtp_port[i][dir] == rtp_port) {
|
||||
/* Expected */
|
||||
|
||||
/* Use allocated ports first. This will refresh
|
||||
* the expects */
|
||||
rtp_exp->tuple.dst.u.udp.port = info->rtp_port[i][dir];
|
||||
rtcp_exp->tuple.dst.u.udp.port =
|
||||
htons(ntohs(info->rtp_port[i][dir]) + 1);
|
||||
break;
|
||||
} else if (info->rtp_port[i][dir] == 0) {
|
||||
/* Not expected */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Run out of expectations */
|
||||
if (i >= H323_RTP_CHANNEL_MAX) {
|
||||
if (net_ratelimit())
|
||||
printk("nf_nat_h323: out of expectations\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Try to get a pair of ports. */
|
||||
for (nated_port = ntohs(rtp_exp->tuple.dst.u.udp.port);
|
||||
nated_port != 0; nated_port += 2) {
|
||||
rtp_exp->tuple.dst.u.udp.port = htons(nated_port);
|
||||
if (nf_conntrack_expect_related(rtp_exp) == 0) {
|
||||
rtcp_exp->tuple.dst.u.udp.port =
|
||||
htons(nated_port + 1);
|
||||
if (nf_conntrack_expect_related(rtcp_exp) == 0)
|
||||
break;
|
||||
nf_conntrack_unexpect_related(rtp_exp);
|
||||
}
|
||||
}
|
||||
|
||||
if (nated_port == 0) { /* No port available */
|
||||
if (net_ratelimit())
|
||||
printk("nf_nat_h323: out of RTP ports\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Modify signal */
|
||||
if (set_h245_addr(pskb, data, dataoff, taddr,
|
||||
&ct->tuplehash[!dir].tuple.dst.u3,
|
||||
htons((port & htons(1)) ? nated_port + 1 :
|
||||
nated_port)) == 0) {
|
||||
/* Save ports */
|
||||
info->rtp_port[i][dir] = rtp_port;
|
||||
info->rtp_port[i][!dir] = htons(nated_port);
|
||||
} else {
|
||||
nf_conntrack_unexpect_related(rtp_exp);
|
||||
nf_conntrack_unexpect_related(rtcp_exp);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Success */
|
||||
DEBUGP("nf_nat_h323: expect RTP %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
|
||||
NIPQUAD(rtp_exp->tuple.src.ip),
|
||||
ntohs(rtp_exp->tuple.src.u.udp.port),
|
||||
NIPQUAD(rtp_exp->tuple.dst.ip),
|
||||
ntohs(rtp_exp->tuple.dst.u.udp.port));
|
||||
DEBUGP("nf_nat_h323: expect RTCP %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
|
||||
NIPQUAD(rtcp_exp->tuple.src.ip),
|
||||
ntohs(rtcp_exp->tuple.src.u.udp.port),
|
||||
NIPQUAD(rtcp_exp->tuple.dst.ip),
|
||||
ntohs(rtcp_exp->tuple.dst.u.udp.port));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
static int nat_t120(struct sk_buff **pskb, struct nf_conn *ct,
|
||||
enum ip_conntrack_info ctinfo,
|
||||
unsigned char **data, int dataoff,
|
||||
H245_TransportAddress *taddr, __be16 port,
|
||||
struct nf_conntrack_expect *exp)
|
||||
{
|
||||
int dir = CTINFO2DIR(ctinfo);
|
||||
u_int16_t nated_port = ntohs(port);
|
||||
|
||||
/* Set expectations for NAT */
|
||||
exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
|
||||
exp->expectfn = nf_nat_follow_master;
|
||||
exp->dir = !dir;
|
||||
|
||||
/* Try to get same port: if not, try to change it. */
|
||||
for (; nated_port != 0; nated_port++) {
|
||||
exp->tuple.dst.u.tcp.port = htons(nated_port);
|
||||
if (nf_conntrack_expect_related(exp) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (nated_port == 0) { /* No port available */
|
||||
if (net_ratelimit())
|
||||
printk("nf_nat_h323: out of TCP ports\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Modify signal */
|
||||
if (set_h245_addr(pskb, data, dataoff, taddr,
|
||||
&ct->tuplehash[!dir].tuple.dst.u3,
|
||||
htons(nated_port)) < 0) {
|
||||
nf_conntrack_unexpect_related(exp);
|
||||
return -1;
|
||||
}
|
||||
|
||||
DEBUGP("nf_nat_h323: expect T.120 %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
|
||||
NIPQUAD(exp->tuple.src.ip), ntohs(exp->tuple.src.u.tcp.port),
|
||||
NIPQUAD(exp->tuple.dst.ip), ntohs(exp->tuple.dst.u.tcp.port));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
static int nat_h245(struct sk_buff **pskb, struct nf_conn *ct,
|
||||
enum ip_conntrack_info ctinfo,
|
||||
unsigned char **data, int dataoff,
|
||||
TransportAddress *taddr, __be16 port,
|
||||
struct nf_conntrack_expect *exp)
|
||||
{
|
||||
struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info;
|
||||
int dir = CTINFO2DIR(ctinfo);
|
||||
u_int16_t nated_port = ntohs(port);
|
||||
|
||||
/* Set expectations for NAT */
|
||||
exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
|
||||
exp->expectfn = nf_nat_follow_master;
|
||||
exp->dir = !dir;
|
||||
|
||||
/* Check existing expects */
|
||||
if (info->sig_port[dir] == port)
|
||||
nated_port = ntohs(info->sig_port[!dir]);
|
||||
|
||||
/* Try to get same port: if not, try to change it. */
|
||||
for (; nated_port != 0; nated_port++) {
|
||||
exp->tuple.dst.u.tcp.port = htons(nated_port);
|
||||
if (nf_conntrack_expect_related(exp) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (nated_port == 0) { /* No port available */
|
||||
if (net_ratelimit())
|
||||
printk("nf_nat_q931: out of TCP ports\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Modify signal */
|
||||
if (set_h225_addr(pskb, data, dataoff, taddr,
|
||||
&ct->tuplehash[!dir].tuple.dst.u3,
|
||||
htons(nated_port)) == 0) {
|
||||
/* Save ports */
|
||||
info->sig_port[dir] = port;
|
||||
info->sig_port[!dir] = htons(nated_port);
|
||||
} else {
|
||||
nf_conntrack_unexpect_related(exp);
|
||||
return -1;
|
||||
}
|
||||
|
||||
DEBUGP("nf_nat_q931: expect H.245 %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
|
||||
NIPQUAD(exp->tuple.src.ip), ntohs(exp->tuple.src.u.tcp.port),
|
||||
NIPQUAD(exp->tuple.dst.ip), ntohs(exp->tuple.dst.u.tcp.port));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* This conntrack expect function replaces nf_conntrack_q931_expect()
|
||||
* which was set by nf_conntrack_h323.c.
|
||||
****************************************************************************/
|
||||
static void ip_nat_q931_expect(struct nf_conn *new,
|
||||
struct nf_conntrack_expect *this)
|
||||
{
|
||||
struct ip_nat_range range;
|
||||
|
||||
if (this->tuple.src.u3.ip != 0) { /* Only accept calls from GK */
|
||||
nf_nat_follow_master(new, this);
|
||||
return;
|
||||
}
|
||||
|
||||
/* This must be a fresh one. */
|
||||
BUG_ON(new->status & IPS_NAT_DONE_MASK);
|
||||
|
||||
/* Change src to where master sends to */
|
||||
range.flags = IP_NAT_RANGE_MAP_IPS;
|
||||
range.min_ip = range.max_ip = new->tuplehash[!this->dir].tuple.src.u3.ip;
|
||||
|
||||
/* hook doesn't matter, but it has to do source manip */
|
||||
nf_nat_setup_info(new, &range, NF_IP_POST_ROUTING);
|
||||
|
||||
/* For DST manip, map port here to where it's expected. */
|
||||
range.flags = (IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED);
|
||||
range.min = range.max = this->saved_proto;
|
||||
range.min_ip = range.max_ip =
|
||||
new->master->tuplehash[!this->dir].tuple.src.u3.ip;
|
||||
|
||||
/* hook doesn't matter, but it has to do destination manip */
|
||||
nf_nat_setup_info(new, &range, NF_IP_PRE_ROUTING);
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
static int nat_q931(struct sk_buff **pskb, struct nf_conn *ct,
|
||||
enum ip_conntrack_info ctinfo,
|
||||
unsigned char **data, TransportAddress *taddr, int idx,
|
||||
__be16 port, struct nf_conntrack_expect *exp)
|
||||
{
|
||||
struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info;
|
||||
int dir = CTINFO2DIR(ctinfo);
|
||||
u_int16_t nated_port = ntohs(port);
|
||||
union nf_conntrack_address addr;
|
||||
|
||||
/* Set expectations for NAT */
|
||||
exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
|
||||
exp->expectfn = ip_nat_q931_expect;
|
||||
exp->dir = !dir;
|
||||
|
||||
/* Check existing expects */
|
||||
if (info->sig_port[dir] == port)
|
||||
nated_port = ntohs(info->sig_port[!dir]);
|
||||
|
||||
/* Try to get same port: if not, try to change it. */
|
||||
for (; nated_port != 0; nated_port++) {
|
||||
exp->tuple.dst.u.tcp.port = htons(nated_port);
|
||||
if (nf_conntrack_expect_related(exp) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (nated_port == 0) { /* No port available */
|
||||
if (net_ratelimit())
|
||||
printk("nf_nat_ras: out of TCP ports\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Modify signal */
|
||||
if (set_h225_addr(pskb, data, 0, &taddr[idx],
|
||||
&ct->tuplehash[!dir].tuple.dst.u3,
|
||||
htons(nated_port)) == 0) {
|
||||
/* Save ports */
|
||||
info->sig_port[dir] = port;
|
||||
info->sig_port[!dir] = htons(nated_port);
|
||||
|
||||
/* Fix for Gnomemeeting */
|
||||
if (idx > 0 &&
|
||||
get_h225_addr(ct, *data, &taddr[0], &addr, &port) &&
|
||||
(ntohl(addr.ip) & 0xff000000) == 0x7f000000) {
|
||||
set_h225_addr_hook(pskb, data, 0, &taddr[0],
|
||||
&ct->tuplehash[!dir].tuple.dst.u3,
|
||||
info->sig_port[!dir]);
|
||||
}
|
||||
} else {
|
||||
nf_conntrack_unexpect_related(exp);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Success */
|
||||
DEBUGP("nf_nat_ras: expect Q.931 %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
|
||||
NIPQUAD(exp->tuple.src.ip), ntohs(exp->tuple.src.u.tcp.port),
|
||||
NIPQUAD(exp->tuple.dst.ip), ntohs(exp->tuple.dst.u.tcp.port));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
static void ip_nat_callforwarding_expect(struct nf_conn *new,
|
||||
struct nf_conntrack_expect *this)
|
||||
{
|
||||
struct nf_nat_range range;
|
||||
|
||||
/* This must be a fresh one. */
|
||||
BUG_ON(new->status & IPS_NAT_DONE_MASK);
|
||||
|
||||
/* Change src to where master sends to */
|
||||
range.flags = IP_NAT_RANGE_MAP_IPS;
|
||||
range.min_ip = range.max_ip = new->tuplehash[!this->dir].tuple.src.u3.ip;
|
||||
|
||||
/* hook doesn't matter, but it has to do source manip */
|
||||
nf_nat_setup_info(new, &range, NF_IP_POST_ROUTING);
|
||||
|
||||
/* For DST manip, map port here to where it's expected. */
|
||||
range.flags = (IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED);
|
||||
range.min = range.max = this->saved_proto;
|
||||
range.min_ip = range.max_ip = this->saved_ip;
|
||||
|
||||
/* hook doesn't matter, but it has to do destination manip */
|
||||
nf_nat_setup_info(new, &range, NF_IP_PRE_ROUTING);
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
static int nat_callforwarding(struct sk_buff **pskb, struct nf_conn *ct,
|
||||
enum ip_conntrack_info ctinfo,
|
||||
unsigned char **data, int dataoff,
|
||||
TransportAddress *taddr, __be16 port,
|
||||
struct nf_conntrack_expect *exp)
|
||||
{
|
||||
int dir = CTINFO2DIR(ctinfo);
|
||||
u_int16_t nated_port;
|
||||
|
||||
/* Set expectations for NAT */
|
||||
exp->saved_ip = exp->tuple.dst.u3.ip;
|
||||
exp->tuple.dst.u3.ip = ct->tuplehash[!dir].tuple.dst.u3.ip;
|
||||
exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
|
||||
exp->expectfn = ip_nat_callforwarding_expect;
|
||||
exp->dir = !dir;
|
||||
|
||||
/* Try to get same port: if not, try to change it. */
|
||||
for (nated_port = ntohs(port); nated_port != 0; nated_port++) {
|
||||
exp->tuple.dst.u.tcp.port = htons(nated_port);
|
||||
if (nf_conntrack_expect_related(exp) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (nated_port == 0) { /* No port available */
|
||||
if (net_ratelimit())
|
||||
printk("nf_nat_q931: out of TCP ports\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Modify signal */
|
||||
if (!set_h225_addr(pskb, data, dataoff, taddr,
|
||||
&ct->tuplehash[!dir].tuple.dst.u3,
|
||||
htons(nated_port)) == 0) {
|
||||
nf_conntrack_unexpect_related(exp);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Success */
|
||||
DEBUGP("nf_nat_q931: expect Call Forwarding "
|
||||
"%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
|
||||
NIPQUAD(exp->tuple.src.ip), ntohs(exp->tuple.src.u.tcp.port),
|
||||
NIPQUAD(exp->tuple.dst.ip), ntohs(exp->tuple.dst.u.tcp.port));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
static int __init init(void)
|
||||
{
|
||||
BUG_ON(rcu_dereference(set_h245_addr_hook) != NULL);
|
||||
BUG_ON(rcu_dereference(set_h225_addr_hook) != NULL);
|
||||
BUG_ON(rcu_dereference(set_sig_addr_hook) != NULL);
|
||||
BUG_ON(rcu_dereference(set_ras_addr_hook) != NULL);
|
||||
BUG_ON(rcu_dereference(nat_rtp_rtcp_hook) != NULL);
|
||||
BUG_ON(rcu_dereference(nat_t120_hook) != NULL);
|
||||
BUG_ON(rcu_dereference(nat_h245_hook) != NULL);
|
||||
BUG_ON(rcu_dereference(nat_callforwarding_hook) != NULL);
|
||||
BUG_ON(rcu_dereference(nat_q931_hook) != NULL);
|
||||
|
||||
rcu_assign_pointer(set_h245_addr_hook, set_h245_addr);
|
||||
rcu_assign_pointer(set_h225_addr_hook, set_h225_addr);
|
||||
rcu_assign_pointer(set_sig_addr_hook, set_sig_addr);
|
||||
rcu_assign_pointer(set_ras_addr_hook, set_ras_addr);
|
||||
rcu_assign_pointer(nat_rtp_rtcp_hook, nat_rtp_rtcp);
|
||||
rcu_assign_pointer(nat_t120_hook, nat_t120);
|
||||
rcu_assign_pointer(nat_h245_hook, nat_h245);
|
||||
rcu_assign_pointer(nat_callforwarding_hook, nat_callforwarding);
|
||||
rcu_assign_pointer(nat_q931_hook, nat_q931);
|
||||
|
||||
DEBUGP("nf_nat_h323: init success\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
static void __exit fini(void)
|
||||
{
|
||||
rcu_assign_pointer(set_h245_addr_hook, NULL);
|
||||
rcu_assign_pointer(set_h225_addr_hook, NULL);
|
||||
rcu_assign_pointer(set_sig_addr_hook, NULL);
|
||||
rcu_assign_pointer(set_ras_addr_hook, NULL);
|
||||
rcu_assign_pointer(nat_rtp_rtcp_hook, NULL);
|
||||
rcu_assign_pointer(nat_t120_hook, NULL);
|
||||
rcu_assign_pointer(nat_h245_hook, NULL);
|
||||
rcu_assign_pointer(nat_callforwarding_hook, NULL);
|
||||
rcu_assign_pointer(nat_q931_hook, NULL);
|
||||
synchronize_rcu();
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
module_init(init);
|
||||
module_exit(fini);
|
||||
|
||||
MODULE_AUTHOR("Jing Min Zhao <[email protected]>");
|
||||
MODULE_DESCRIPTION("H.323 NAT helper");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("ip_nat_h323");
|
||||
Loading…
Reference in a new issue