📄 nat_tcp.c
字号:
/* nat_tcp.c */
/* Copyright 2000-2003 Wind River Systems, Inc. */
/* @format.tab-size 4, @format.use-tabs true, @format.new-line lf */
/*
modification history
--------------------
01c,24apr03,zhu updated copyright
01b,21apr03,myz replaced swap(_long) with the ntohs(l) and htons(l) macros,
replaced RWOS list functions with ones in dllLib.c.
01a,15apr03,zhu check tcp reset flag
040903 vks updated Copyright info
040303 vks replaced table_malloc call with calloc
101501 tk Fix bug. When no matches found for inbound TCP packet in NAPT, return(PASS)
to pass the untranslated packet to the network stack.
100301 tk Fix bug. Address (IP) static entry didn't work in NAPT.
092401 tk Fix bug in handle_tcp_translation_global_rx_nats() to create one or more dynamic
binds from a static entry so that the static bind can support multiple global
clients to the same local server.
082301 tk Assign remote address to the translation entry and bind entry upon receiving
TCP packet from global port in NAPT mode.
080701 tk Add code in handle_tcp_translation_local_rx_nats for handling H.323 protocol.
072601 tk Fix call to match_ports_with_tcp_entry to use match_ports_with_tcp_entry_inbound
and match_ports_with_tcp_entry_outbound instead.
070201 tk Modified implementations to call natSetBind to create TCP control blocks so it
will work with the upgraded version of ALG API.
051401 tk Fix natShow for basic NAT. Local address is displayed as global address.
051101 tk Fix NAPT so it can also work with static address-based translations.
051001 tk Fix TCP state transition problem. TCP local or/and global state may be in the
wrong state. One known effect of this is TCP control block might not get freed
12 hours after the TCP connection was closed. Problem was due to failure to do
swap_long on the sequence numbers when comparing current and previous sequence
numbers to determine whether it needs to do state transition.
050401 tk Fix problem of multiple global servers being unable to connect to a local server
simultaneously. Also, fix the indication of static or dynamic binds in the
TCP control blocks (in the TCP translation list).
042101 tk Add some comments
*/
/*
#define TCP_DEBUG
*/
#include "nat.h"
#include "nat_api.h"
IMPORT FUNCPTR _func_packetsend;
/**************************************************************************************************/
static enum TEST handle_tcp_translation_global_rx_natg (TCP_PACKET *sptr_tcp_packet);
static enum TEST handle_tcp_translation_global_rx_nats (TCP_PACKET *sptr_tcp_packet);
static void do_tcp_sequence_number_fixup (enum NAT_TCP_DELTA_SIGN delta_sign, ULONG *ulptr_packet_sequence_number,
USHORT *usptr_checksum, SEQUENCE_HEADER *sptr_sequence_list);
/**************************************************************************************************/
enum TEST handle_tcp_translation_global_rx (TCP_PACKET *sptr_tcp_packet)
{
enum TEST pass_or_fail;
if (nat.single_global_address_enabled == TRUE)
{
pass_or_fail = handle_tcp_translation_global_rx_nats (sptr_tcp_packet);
}
else
{
pass_or_fail = handle_tcp_translation_global_rx_natg (sptr_tcp_packet);
}
return (pass_or_fail);
}
/*************************************************************************************************/
enum TEST handle_tcp_translation_local_rx (TCP_PACKET *sptr_tcp_packet)
{
enum TEST pass_or_fail;
if (nat.single_global_address_enabled == TRUE)
{
pass_or_fail = handle_tcp_translation_local_rx_nats (sptr_tcp_packet);
}
else
{
pass_or_fail = handle_tcp_translation_local_rx_natg (sptr_tcp_packet);
}
return (pass_or_fail);
}
/********************************************************************************************
Description:
handle_ip_translation_local_rx_natg() replaces the source IP with IP from global address
pool. It also creates a new entry in the IP translation list.
new_tcp_translation_entry() creates a new entry in the TCP translation list.
********************************************************************************************/
enum TEST handle_tcp_translation_local_rx_natg (TCP_PACKET *sptr_tcp_packet)
{
NAT_CURRENCY_TRANSLATION_ENTRY *sptr_tcp_translation_entry=NULL;
IP_TRANSLATION_ENTRY *sptr_working_ip_translation_entry=NULL;
BYTE_ENUM (BOOLEAN) do_state_transition;
IP_ADDRESS source_address;
NAT_BIND_INFO bind_info;
NAT_STATUS status;
source_address = sptr_tcp_packet->ip_header.source_address;
sptr_working_ip_translation_entry = handle_ip_translation_local_rx_natg ((IP_PACKET *) sptr_tcp_packet);
if (sptr_working_ip_translation_entry == NULL)
{
return (FAIL);
}
checksum_fixup ((BYTE *) &sptr_tcp_packet->tcp_header.checksum,
(BYTE *) &source_address, sizeof (source_address),
(BYTE *) &sptr_tcp_packet->ip_header.source_address, sizeof (source_address));
semTake(natentrylock, WAIT_FOREVER);
sptr_tcp_translation_entry = find_entry (sptr_tcp_packet->ip_header.source_address,
sptr_tcp_packet->ip_header.destination_address,sptr_tcp_packet->tcp_header.source_port,sptr_tcp_packet->tcp_header.destination_port);
if (sptr_tcp_translation_entry == NULL)
{
semGive(natentrylock);
if (sptr_tcp_packet->tcp_header.flags.synchronize_flag == TRUE)
{
memset(&bind_info,0,sizeof(bind_info));
bind_info.agent_id = 0; /* agent is NAT */
bind_info.type = NAT_BIND_BASIC;
bind_info.direction = NAT_OUTBOUND;
bind_info.protocol = IPPROTO_TCP;
bind_info.static_entry = FALSE;
/* convert source and destination transport addresses to host format */
bind_info.local_addr = ntohl(source_address);
bind_info.local_transport = ntohs(sptr_tcp_packet->tcp_header.source_port);
bind_info.remote_addr = ntohl(sptr_tcp_packet->ip_header.destination_address);
bind_info.remote_transport = ntohs(sptr_tcp_packet->tcp_header.destination_port);
/* save the current IP translation entry */
bind_info.nat_address_entry = (u_long) sptr_working_ip_translation_entry;
status = natSetBind((u_long)&nat, 0, &bind_info);
if(status != NAT_OK)
{
nat_printf (NAT_PRINTF_ERROR,
"handle_tcp_translation_local_rx_natg: natSetBind returned %d\n",status);
return(FAIL);
}
semTake(natentrylock, WAIT_FOREVER);
sptr_tcp_translation_entry = (NAT_CURRENCY_TRANSLATION_ENTRY *) bind_info.nat_transport_entry;
}
else
{
return (FAIL);
}
}
tcp_sequence_number_fixup_local_rx (&sptr_tcp_packet->tcp_header, sptr_tcp_translation_entry);
/*
if (ntohl(sptr_tcp_packet->tcp_header.sequence_number) >=
ntohl(sptr_tcp_translation_entry->local_sequence_number))
{
do_state_transition = TRUE;
}
else
*/
if(sptr_tcp_packet->tcp_header.flags.reset_flag == TRUE)
{
do_state_transition = TRUE;
}
else
{
do_state_transition = FALSE;
}
/*
sptr_tcp_translation_entry->local_sequence_number = sptr_tcp_packet->tcp_header.sequence_number;
*/
if (do_state_transition == TRUE)
{
if (sptr_tcp_packet->tcp_header.flags.acknowledgment_flag == TRUE)
{
tcp_state_transistion_local_rx (NAT_ACK, sptr_tcp_translation_entry);
}
if (sptr_tcp_packet->tcp_header.flags.synchronize_flag == TRUE)
{
tcp_state_transistion_local_rx (NAT_SYNCH, sptr_tcp_translation_entry);
}
if (sptr_tcp_packet->tcp_header.flags.finished_flag == TRUE)
{
tcp_state_transistion_local_rx (NAT_FIN, sptr_tcp_translation_entry);
}
if (sptr_tcp_packet->tcp_header.flags.reset_flag == TRUE)
{
tcp_state_transistion_local_rx (NAT_RESET, sptr_tcp_translation_entry);
}
if ((sptr_tcp_packet->tcp_header.flags.acknowledgment_flag == FALSE) &&
(sptr_tcp_packet->tcp_header.flags.synchronize_flag == FALSE) &&
(sptr_tcp_packet->tcp_header.flags.reset_flag == FALSE) &&
(sptr_tcp_packet->tcp_header.flags.finished_flag == FALSE))
{
tcp_state_transistion_local_rx (NAT_ESTABLISHED, sptr_tcp_translation_entry);
}
}
semGive(natentrylock);
return (PASS);
}
/**************************************************************************************************
Description:
Check if there is a match for destination address in IP translation list.
If not, return.
Else, replace destination IP with local IP and adjust checksum.
Check for match in the TCP translation list.
If not, create an entry in the TCP translation list.
**************************************************************************************************/
static enum TEST handle_tcp_translation_global_rx_natg (TCP_PACKET *sptr_tcp_packet)
{
IP_TRANSLATION_ENTRY *sptr_ip_translation_entry=NULL;
bool do_state_transition;
NAT_CURRENCY_TRANSLATION_ENTRY *sptr_tcp_translation_entry=NULL;
IP_ADDRESS destination_address;
NAT_BIND_INFO bind_info;
NAT_STATUS status;
destination_address = sptr_tcp_packet->ip_header.destination_address;
sptr_ip_translation_entry = handle_ip_translation_global_rx_natg ((IP_PACKET *) sptr_tcp_packet);
if (sptr_ip_translation_entry == NULL)
{
return (PASS); /* changed so that packets meant for upper layers can be passed to IP */
}
checksum_fixup ((BYTE *) &sptr_tcp_packet->tcp_header.checksum,
(BYTE *) &destination_address, sizeof (destination_address),
(BYTE *) &sptr_tcp_packet->ip_header.destination_address, sizeof (destination_address));
semTake(natentrylock, WAIT_FOREVER);
sptr_tcp_translation_entry = match_ports_with_tcp_entry_inbound (sptr_tcp_packet);
if (sptr_tcp_translation_entry == NULL)
{
semGive(natentrylock);
if (sptr_tcp_packet->tcp_header.flags.synchronize_flag == TRUE)
{
memset(&bind_info,0,sizeof(bind_info));
bind_info.agent_id = 0; /* agent is NAT */
bind_info.type = NAT_BIND_BASIC;
bind_info.direction = NAT_INBOUND;
bind_info.protocol = IPPROTO_TCP;
bind_info.static_entry = FALSE;
/* convert source and destination transport addresses to host format */
bind_info.local_addr = ntohl(sptr_tcp_packet->ip_header.destination_address);
bind_info.local_transport = ntohs(sptr_tcp_packet->tcp_header.destination_port);
bind_info.remote_addr = ntohl(sptr_tcp_packet->ip_header.source_address);
bind_info.remote_transport = ntohs(sptr_tcp_packet->tcp_header.source_port);
/* save the current IP translation entry */
bind_info.nat_address_entry = (u_long) sptr_ip_translation_entry;
status = natSetBind((u_long)&nat, 0, &bind_info);
if(status != NAT_OK)
{
nat_printf (NAT_PRINTF_ERROR,
"handle_tcp_translation_global_rx_natg: natSetBind returned %d\n",status);
return(FAIL);
}
semTake(natentrylock, WAIT_FOREVER);
sptr_tcp_translation_entry = (NAT_CURRENCY_TRANSLATION_ENTRY *) bind_info.nat_transport_entry;
}
else
{
return (FAIL);
}
}
tcp_sequence_number_fixup_global_rx (&sptr_tcp_packet->tcp_header, sptr_tcp_translation_entry);
/*
if (ntohl(sptr_tcp_packet->tcp_header.sequence_number) >=
ntohl(sptr_tcp_translation_entry->global_sequence_number))
{
do_state_transition = TRUE;
}
else
*/
if (sptr_tcp_packet->tcp_header.flags.reset_flag == TRUE)
{
do_state_transition = TRUE;
}
else
{
do_state_transition = FALSE;
}
/*
sptr_tcp_translation_entry->global_sequence_number = sptr_tcp_packet->tcp_header.sequence_number;
*/
if (do_state_transition == TRUE)
{
if (sptr_tcp_packet->tcp_header.flags.acknowledgment_flag == TRUE)
{
tcp_state_transistion_global_rx (NAT_ACK, sptr_tcp_translation_entry);
}
if (sptr_tcp_packet->tcp_header.flags.synchronize_flag == TRUE)
{
tcp_state_transistion_global_rx (NAT_SYNCH, sptr_tcp_translation_entry);
}
if (sptr_tcp_packet->tcp_header.flags.finished_flag == TRUE)
{
tcp_state_transistion_global_rx (NAT_FIN, sptr_tcp_translation_entry);
}
if (sptr_tcp_packet->tcp_header.flags.reset_flag == TRUE)
{
tcp_state_transistion_global_rx (NAT_RESET, sptr_tcp_translation_entry);
}
if ((sptr_tcp_packet->tcp_header.flags.acknowledgment_flag == FALSE) &&
(sptr_tcp_packet->tcp_header.flags.synchronize_flag == FALSE) &&
(sptr_tcp_packet->tcp_header.flags.reset_flag == FALSE) &&
(sptr_tcp_packet->tcp_header.flags.finished_flag == FALSE))
{
tcp_state_transistion_global_rx (NAT_ESTABLISHED, sptr_tcp_translation_entry);
}
}
semGive(natentrylock);
return (PASS);
}
/**************************************************************************************************
Description:
This function handles translation of TCP packets received from global port in NAPT mode.
- First, see if there is a match of the spoofed port.
- If yes and this is not a static entry (see NOTE below), go ahead and translate.
- If no or static entry, check for a match of the tuple of local address & port and
global port in the TCP translation list.
- If no match is found, check if the destination port can be found in the static port table.
- If no, look for a match in the IP translation list (i.e. process it as Basic NAT).
- Fix up the TCP sequence number if necessary.
- Do the address and port translation on the packet before giving it to the higher layer.
NOTE:
If static entry is true, it implies the session was started inbound. It is not enough that
the spoofed port match is found since the spoofed port is the global port assigned from the
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -