📄 nath323alg.c
字号:
/* natH323Alg.c */
/* Copyright 2000-2003 Wind River Systems, Inc. */
/* @format.tab-size 4, @format.use-tabs true, @format.new-line lf */
/* WindNet NAT "installable" H.323 Application Level Gateway (ALG) */
/*
modification history
--------------------
01b,23apr03,zhu updated copyright
01a,21apr03,myz replaced swap(_long) with the ntohs(l) and htons(l) macros.
111202 zhu Fixed Endianess problems for MACROs.
091902 jsv Changed memory accesses to use macros and avoid alignment
exceptions on MIPS.
101901 tk Fix data type to avoid warning in T3 compiler.
092101 tk Modify due to changes in the natGetTransportBind() format.
080801 tk Add event callback routine for H.245 ALG
073001 tk Redo entire H323 ALG. The old code was incorrectly designed.
042001 tk Fix a bug in natH245Packet and add more comments
030901 tk Fix synchronization problem with NAT initialization.
*/
/*
#define H323_DEBUG
*/
/* NAT-specific headers */
#include <nat/natAlgApi.h>
#include "nat.h" /* IP_ADDRESS */
#include <nat_api.h> /* natGetGlobalAddress */
/* ANSI headers */
#include <stdio.h> /* printf */
#include <string.h> /* memset */
/* VxWorks headers */
#include <in.h> /* IPPROTO_TCP */
/* Global function declarations */
STATUS natH323Init(u_short h323_port);
static const char* h225_alg_desc
= "WindNet NAT - H.323/H.225 ALG v1.0 - Copyright 2000-2003 Wind River Systems, Inc.";
static const char* h225_alg_name = "H.225 ALG";
static const char* h245_alg_desc
= "WindNet NAT - H.323/H.245 ALG v1.0 - Copyright 2000-2003 Wind River Systems, Inc.";
static const char* h245_alg_name = "H.245 ALG";
static NAT_ID_INFO nat_instance[1]; /* currently support only one instance of NAT */
NAT_AGENT_INFO h323Alg[2]; /* support 2 ALGs: H.225 and H.245 */
/* constants */
#define IP_PORT_LENGTH 6 /* size of IP and port */
#define MAX_LOGICAL_CHANNELS 20 /* max number of logical channels (UDP) that can be opened */
#define T1_120_PORT 1503 /* T1.120 standard port */
/* macros */
#if _BYTE_ORDER==_LITTLE_ENDIAN
#define READ_ALIGN_SAFE32(ptr) ((ULONG)( ((((BYTE*)(ptr))[3]) << 24) | \
((((BYTE*)(ptr))[2]) << 16) | \
((((BYTE*)(ptr))[1]) << 8) | \
((((BYTE*)(ptr))[0]) << 0) \
))
#define READ_ALIGN_SAFE16(ptr) ((USHORT)( ((((BYTE*)(ptr))[1]) << 8) | \
((((BYTE*)(ptr))[0]) << 0) \
))
#define WRITE_ALIGN_SAFE32(ptr, val) \
do { \
((BYTE*)(ptr))[3] = (((ULONG)(val)) >> 24); \
((BYTE*)(ptr))[2] = (((ULONG)(val)) >> 16); \
((BYTE*)(ptr))[1] = (((ULONG)(val)) >> 8); \
((BYTE*)(ptr))[0] = (((ULONG)(val)) >> 0); \
} while(0)
#define WRITE_ALIGN_SAFE16(ptr, val) \
do { \
((BYTE*)(ptr))[1] = (((ULONG)(val)) >> 8); \
((BYTE*)(ptr))[0] = (((ULONG)(val)) >> 0); \
} while(0)
#endif /* _BYTE_ORDER==_LITTLE_ENDIAN */
#if _BYTE_ORDER==_BIG_ENDIAN
#define READ_ALIGN_SAFE32(ptr) ((ULONG)( ((((BYTE*)(ptr))[0]) << 24) | \
((((BYTE*)(ptr))[1]) << 16) | \
((((BYTE*)(ptr))[2]) << 8) | \
((((BYTE*)(ptr))[3]) << 0) \
))
#define READ_ALIGN_SAFE16(ptr) ((USHORT)( ((((BYTE*)(ptr))[0]) << 8) | \
((((BYTE*)(ptr))[1]) << 0) \
))
#define WRITE_ALIGN_SAFE32(ptr, val) \
do { \
((BYTE*)(ptr))[0] = (((ULONG)(val)) >> 24); \
((BYTE*)(ptr))[1] = (((ULONG)(val)) >> 16); \
((BYTE*)(ptr))[2] = (((ULONG)(val)) >> 8); \
((BYTE*)(ptr))[3] = (((ULONG)(val)) >> 0); \
} while(0)
#define WRITE_ALIGN_SAFE16(ptr, val) \
do { \
((BYTE*)(ptr))[0] = (((ULONG)(val)) >> 8); \
((BYTE*)(ptr))[1] = (((ULONG)(val)) >> 0); \
} while(0)
#endif /* _BYTE_ORDER==_BIG_ENDIAN */
/* data types */
typedef enum {
H225Alg = 0,
H245Alg
} H323AlgType;
typedef struct {
IP_ADDRESS ip_addr;
USHORT port;
} TRANSPORT_ADDR;
/* Function declaration */
static STATUS natRegisterAlg ( /* to register an H.323 ALG to NAT */
NAT_ID_INFO *nat_id,
u_short port,
H323AlgType alg,
NAT_AGENT_INFO *agent_info_p);
static void natAdjustChecksum( /* adjust checksum for changes in H.323 payload data */
BYTE *data,
TRANSPORT_ADDR *new_transport,
NAT_BIND_TYPE nat_type,
USHORT *checksum);
/* static variables */
static u_long logical_channel_bind[MAX_LOGICAL_CHANNELS];
/*****************************************************************************
Function: natH245Packet
Description:
This function handles the H.245 call control packets. NAT calls this function
after translating the address and port number in the IP and TCP headers, and
when the source or destination port is the H.245 port. The H.245 port was
negotiated during the H.225 call signaling session and registered to NAT.
The H.245 call control protocol is used in H.323 to negotiate call parameters
between two end-points. For example, it negotiates the UDP connections for
the open logical channels for RTP and RTCP streams between the two endpoints.
In addition, it also negotiates the TCP connection for the T1.120 session.
NOTE 1:
The H.245 message is ASN.1 encoded. However, due to resource and schedule
constraint, rather than employing an ASN.1 decoder, this function uses a simple
work-around alternative which appears to work just as well. This work-around
strategy looks for the ip+port address in the H.245 payload by taking advantage
of the fact that the port number always follows immediately after the ip address.
Since the ALG can get the expected ip address from NAT, it can search byte by
byte for this ip address to locate where it is in the H.245 payload.
Local host (L) <---------------> NAT <----------------> Global host (G)
The tuple of IP address and TCP/UDP port number is sometimes called transport
address in some publications, and the same terminology will be used here.
For an outbound packet, L may be sending its transport addresses to G to let
G make TCP/UDP connections to it. Similarly, for an inbound packet, G may be
sending its transport addresses to L to let L make TCP/UDP connections to it.
Since only the L's transport addresses in the payload need to be translated,
it is sufficient to examine only the outbound packets.
NOTE 2:
TCP sequence adjustment is not required since it is a binary substitution of
IP address and port number in the payload. However, the checksum in the TCP
header must be adjusted when the TCP payload is modified.
*****************************************************************************/
BOOL natH245Packet(u_long nat_id, u_long agent_id, u_long session_id,
NAT_DIRECTION direction, void* packet)
{
BYTE *data, *data_start;
TCP_PACKET *tcp_packet;
USHORT port, *port_data;
USHORT checksum;
IP_ADDRESS local_address, ip_addr, *ip_data;
NAT_ID_INFO *nat_p;
NAT_BIND_INFO bind_info;
NAT_BIND_SESSION session;
NAT_STATUS status;
int i, data_length;
TRANSPORT_ADDR transport;
if (direction == NAT_INBOUND)
{
return (TRUE);
}
if (nat_instance[0].id != nat_id)
{
nat_printf(NAT_PRINTF_ERROR, "natH225Packet: Invalid nat id\n");
return(FALSE);
}
nat_p = &nat_instance[0];
tcp_packet = (TCP_PACKET*)packet;
/* length of TCP payload */
data_length = (u_long) (tcp_packet->ip_header.total_length -
(tcp_packet->ip_header.version_header_length.header_length << 2) -
(tcp_packet->tcp_header.header_length_byte.header_length << 2));
if (data_length <= 0) /* no payload to look at */
{
return (TRUE);
}
/* go to start of TCP payload */
data = (BYTE *)(&tcp_packet->tcp_header);
data += (tcp_packet->tcp_header.header_length_byte.header_length << 2);
data_start = data;
/* From L's global transport address in TCP/IP header, locate the TCP bind entry
to obtain L's local transport address.
*/
session.protocol = IPPROTO_TCP;
session.local_addr = 0;
session.local_transport = 0;
session.global_addr = ntohl(tcp_packet->ip_header.source_address);
session.global_transport = ntohs(tcp_packet->tcp_header.source_port);
session.remote_addr = ntohl(tcp_packet->ip_header.destination_address);
session.remote_transport = ntohs(tcp_packet->tcp_header.destination_port);
if ((status = natGetTransportBind(nat_id, &session, &bind_info, NAT_BIND_FULL)) != NAT_OK)
{
nat_printf (NAT_PRINTF_ERROR,
"H245ALG: natGetTransportBind returns = %d, Transport Bind of address %x port %d not found\n",
status, ntohl(tcp_packet->ip_header.source_address),
ntohs(tcp_packet->tcp_header.source_port));
return(FALSE);
}
nat_printf(NAT_PRINTF_TRACE, "H245ALG: Bind entry match found\n");
local_address = bind_info.local_addr; /* L's local ip */
/* search for L's ip address in the H.245 payload for all possible
** TCP/UDP connections that may be negotiated. For each one found, create
** create a static TCP/UDP control block to get the translated transport address.
** We must do this for all L's ip address found in the H.245 payload
** since we are not decoding the ASN.1 message thus don't really know
** which ones will actually be used. A check is made to prevent creation
** of duplicate bind entries. The ID of each created static entry is recorded
** so the ALG can delete them when the Netmeeting session is terminated.
*/
while ((data + IP_PORT_LENGTH) <= (data_start + data_length))
{
ip_addr = READ_ALIGN_SAFE32(data);
ip_addr = ntohl (ip_addr);
/* look for L's global address match */
if (ip_addr == local_address)
{
port = READ_ALIGN_SAFE16(data + sizeof(IP_ADDRESS));
port = ntohs (port);
if (port > LOWER_EPHEMERAL_PORT_VALUE)
{
nat_printf(NAT_PRINTF_TRACE, "Local host address found in H245 payload\n");
nat_printf(NAT_PRINTF_DATA,
"H245 ALG: Local host's ip match found, ip = %x, port = %x\n", ip_addr, port);
/* if NAPT, create a UDP bind entry for this transport address if it hasn't
been created yet
*/
if (nat_p->type == NAT_TYPE_NAPT)
{
memset(&bind_info,0,sizeof(NAT_BIND_INFO)); /* reset bind_info */
if (port == T1_120_PORT)
{
session.protocol = IPPROTO_TCP;
}
else
{
session.protocol = IPPROTO_UDP;
}
session.local_addr = local_address;
session.local_transport = port;
session.global_addr = 0;
session.global_transport = 0;
session.remote_addr = ntohl(tcp_packet->ip_header.destination_address);
session.remote_transport = 0;
if ((status = natGetTransportBind(nat_id, &session,
&bind_info, NAT_BIND_PARTIAL)) == NAT_BIND_NO_MATCH)
{
memset(&bind_info,0,sizeof(NAT_BIND_INFO));
bind_info.id = 0; /* request to create a new bind */
bind_info.agent_id = h323Alg[H245Alg].id;
bind_info.type = NAT_BIND_NAPT;
bind_info.direction = NAT_OUTBOUND;
if (port == T1_120_PORT)
{
bind_info.protocol = IPPROTO_TCP;
}
else
{
bind_info.protocol = IPPROTO_UDP;
}
bind_info.static_entry = TRUE;
bind_info.use_local_port = TRUE;
bind_info.local_addr = local_address;
bind_info.local_transport = port;
bind_info.global_addr = ntohl(tcp_packet->ip_header.source_address);
bind_info.global_transport = 0;
bind_info.remote_addr = ntohl(tcp_packet->ip_header.destination_address);
bind_info.remote_transport = 0; /* destination port is still unknown now */
status = natSetBind(nat_id, agent_id, &bind_info);
if(status != NAT_OK)
{
nat_printf (NAT_PRINTF_ERROR,
"H245 ALG: Failed to create UDP bind, natSetBind returned %d\n",status);
return (FALSE);
}
nat_printf(NAT_PRINTF_TRACE, "H245 ALG: New bind created\n");
nat_printf(NAT_PRINTF_DATA,
"H245 ALG: A new bind created for la = %x, lp = %d, gp =%d\n",
bind_info.local_addr, bind_info.local_transport, bind_info.global_transport);
/* record the ID of the created bind */
for (i=0; i<MAX_LOGICAL_CHANNELS; i++)
{
if (logical_channel_bind[i] == 0)
{
logical_channel_bind[i] = bind_info.id;
break;
}
}
if (i == MAX_LOGICAL_CHANNELS)
{
printf("Number of binds created by H.245 exceeds the limit\n");
}
}
else
{
if (status != NAT_OK)
{
nat_printf(NAT_PRINTF_ERROR,
"natH245Packet: natGetTransportBind returns error\n");
return (FALSE);
}
}
} /* NAPT */
/********************************************************************
Replace L's local address with its global address in the payload.
Adjust the TCP checksum accordingly.
*********************************************************************/
ip_data = (IP_ADDRESS *) data;
transport.ip_addr = htonl (bind_info.global_addr);
port_data = (USHORT *) (data + sizeof(IP_ADDRESS));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -