📄 nat_icmp_datagram.c
字号:
/* nat_icmp_datagram.c */
/* Copyright 2000-2003 Wind River Systems, Inc. */
/* @format.tab-size 4, @format.use-tabs true, @format.new-line lf */
/*
modification history
--------------------
01g,16may03,myz Reworked SPR#87054 fix
01f,13may03,myz fixed wrong port number problem in functions: handle_icmp
_embedded_tcp(udp)_translation_global_rx_datagram_nats.
01e,23apr03,zhu updated copyright
01d,21apr03,myz replaced swap(_long) with the ntohs(l) and htons(l) macros.
01c,10apr03,zhu allow icmp protocol type in icmp host unreachable message
datagram
01b,10apr03,zhu cleaned up SPR#87054 fix
01a,28mar03,zhu SPR#87054 fix: send ICMP host unreachable message back to
local host
100901 tk Changes due to parameter addition in match_spoofed_port_with_udp_entry.
072601 tk Fix call to match_ports_with_udp_entry to use match_ports_with_udp_entry_inbound
and match_ports_with_udp_entry_outbound instead. Also fix call to
match_ports_with_tcp_entry to use match_ports_with_tcp_entry_inbound
and match_ports_with_tcp_entry_outbound instead.
050701 tk Update handle_icmp_translation_global_rx_datagram_nats to check for embedded ICMP
frame (for time-exceeded message). Add a new function
handle_icmp_embedded_icmp_translation_global_rx_datagram_nats to process embedded
ICMP translation (e.g. ICMP time-exceeded message).
042101 tk Fix bugs in basic NAT ICMP translations for both global port and local port in
functions handle_icmp_translation_global_rx_datagram_natg() and
handle_icmp_translation_local_rx_datagram_natg () respectively.
The bugs can cause page fault, wrong address translation in embedded IP, and
checksum errors.
*/
#include "nat.h"
/************************************************************************/
static enum TEST handle_icmp_translation_global_rx_datagram_nats (ICMP_PACKET *sptr_icmp_packet);
static enum TEST handle_icmp_translation_global_rx_datagram_natg (ICMP_PACKET *sptr_icmp_packet);
static enum TEST handle_icmp_translation_local_rx_datagram_nats (ICMP_PACKET *sptr_icmp_packet);
static enum TEST handle_icmp_translation_local_rx_datagram_natg (ICMP_PACKET *sptr_icmp_packet);
static enum TEST handle_icmp_embedded_tcp_translation_global_rx_datagram_nats (ICMP_PACKET *sptr_icmp_packet);
static enum TEST handle_icmp_embedded_udp_translation_global_rx_datagram_nats (ICMP_PACKET *sptr_icmp_packet);
static enum TEST handle_icmp_embedded_tcp_translation_local_rx_datagram_nats (ICMP_PACKET *sptr_icmp_packet);
static enum TEST handle_icmp_embedded_udp_translation_local_rx_datagram_nats (ICMP_PACKET *sptr_icmp_packet);
static enum TEST handle_icmp_embedded_icmp_translation_global_rx_datagram_nats (ICMP_PACKET *sptr_icmp_packet);
/************************************************************************/
enum TEST handle_icmp_translation_global_rx_datagram (ICMP_PACKET *sptr_icmp_packet)
{
enum TEST pass_or_fail;
if (nat.single_global_address_enabled == TRUE)
{
pass_or_fail = handle_icmp_translation_global_rx_datagram_nats (
sptr_icmp_packet);
if (pass_or_fail == FAIL)
{
/* Try IP translation, in case it use Basic NAT static entries */
pass_or_fail = handle_icmp_translation_global_rx_datagram_natg(
sptr_icmp_packet);
}
}
else
{
pass_or_fail = handle_icmp_translation_global_rx_datagram_natg (
sptr_icmp_packet);
}
return (pass_or_fail);
}
/***************************************************************************/
enum TEST handle_icmp_translation_local_rx_datagram (ICMP_PACKET *sptr_icmp_packet)
{
enum TEST pass_or_fail;
if (nat.single_global_address_enabled == TRUE)
{
pass_or_fail = handle_icmp_translation_local_rx_datagram_nats (
sptr_icmp_packet);
if (pass_or_fail == FAIL)
{
/* Try IP translation, in case it use Basic NAT static entries */
pass_or_fail = handle_icmp_translation_local_rx_datagram_natg(
sptr_icmp_packet);
}
}
else
{
pass_or_fail = handle_icmp_translation_local_rx_datagram_natg (
sptr_icmp_packet);
}
return (pass_or_fail);
}
/**********************************************************************************************
Description:
Handle packet received from global port in Basic NAT
**********************************************************************************************/
static enum TEST handle_icmp_translation_global_rx_datagram_natg (ICMP_PACKET *sptr_icmp_packet)
{
ICMP_DATA changed_data;
ICMP_DATA unchanged_data;
IP_PACKET nested_ip_packet;
IP_TRANSLATION_ENTRY *sptr_ip_translation_entry;
USHORT checksum;
nested_ip_packet.header = sptr_icmp_packet->header.option.unreachable_message.ip_data;
nat_printf (NAT_PRINTF_TRACE, "ICMP: translate embedded IP header\n");
unchanged_data.ip_data.addresses.source_address = nested_ip_packet.header.source_address;
unchanged_data.ip_data.addresses.destination_address = nested_ip_packet.header.destination_address;
unchanged_data.ip_data.ip_checksum = nested_ip_packet.header.header_checksum;
sptr_ip_translation_entry = match_sa_with_global_address (
ntohl (unchanged_data.ip_data.addresses.source_address),
&nat.natg.ip_translation_list);
if (sptr_ip_translation_entry == NULL)
{
nat_printf (NAT_PRINTF_TRACE, "ICMP received global: Can't match embedded source IP in ICMP datagram.\n");
return (FAIL);
}
changed_data.ip_data.addresses.source_address = htonl (sptr_ip_translation_entry->sa_local_address);
changed_data.ip_data.addresses.destination_address = nested_ip_packet.header.destination_address;
changed_data.ip_data.ip_checksum = nested_ip_packet.header.header_checksum;
/* adjust checksum in embedded IP header */
checksum_fixup ((BYTE *) &changed_data.ip_data.ip_checksum,
(BYTE *) &unchanged_data.ip_data.addresses.source_address, (USHORT) sizeof (IP_ADDRESS),
(BYTE *) &changed_data.ip_data.addresses.source_address, (USHORT )sizeof (IP_ADDRESS));
nested_ip_packet.header.source_address = changed_data.ip_data.addresses.source_address;
nested_ip_packet.header.header_checksum = changed_data.ip_data.ip_checksum;
changed_data.icmp_checksum = sptr_icmp_packet->header.checksum;
/* adjust ICMP header checksum, first with change in embedded IP address */
checksum_fixup ((BYTE *) &changed_data.icmp_checksum,
(BYTE *) &sptr_icmp_packet->header.option.unreachable_message.ip_data.source_address,
sizeof (ULONG),
(BYTE *) &nested_ip_packet.header.source_address,
sizeof (ULONG));
checksum = changed_data.icmp_checksum; /* save for printing debug msg */
/* adjust ICMP header checksum, then with change in embedded IP header checksum */
checksum_fixup ((BYTE *) &changed_data.icmp_checksum,
(BYTE *) &sptr_icmp_packet->header.option.unreachable_message.ip_data.header_checksum,
sizeof (USHORT),
(BYTE *) &nested_ip_packet.header.header_checksum,
sizeof (USHORT));
sptr_icmp_packet->header.option.unreachable_message.ip_data.source_address =
changed_data.ip_data.addresses.source_address;
sptr_icmp_packet->header.option.unreachable_message.ip_data.destination_address =
changed_data.ip_data.addresses.destination_address;
sptr_icmp_packet->header.option.unreachable_message.ip_data.header_checksum =
changed_data.ip_data.ip_checksum;
sptr_icmp_packet->header.checksum = changed_data.icmp_checksum;
nat_printf (NAT_PRINTF_TRACE, "ICMP received global: translate IP header of ICMP packet\n");
/* this function also adjusts IP header's checksum */
if (handle_ip_translation_global_rx_natg ((IP_PACKET *) sptr_icmp_packet) == NULL)
{
return (FAIL);
}
return (PASS);
}
/**********************************************************************************************
Description:
Handle ICMP packet received from global port in NAPT. The ICMP datagram may be of
destination unreachable message or time-exceeded message.
**********************************************************************************************/
static enum TEST handle_icmp_translation_global_rx_datagram_nats (ICMP_PACKET *sptr_icmp_packet)
{
if (sptr_icmp_packet->header.type == ICMP_DESTINATION_UNREACHABLE_TYPE)
{
switch (sptr_icmp_packet->header.option.unreachable_message.ip_data.protocol)
{
case TCP_PROTOCOL:
if (handle_icmp_embedded_tcp_translation_global_rx_datagram_nats (sptr_icmp_packet) == FAIL)
{
return (FAIL);
}
break;
case UDP_PROTOCOL:
if (handle_icmp_embedded_udp_translation_global_rx_datagram_nats (sptr_icmp_packet) == FAIL)
{
return (FAIL);
}
break;
case ICMP_PROTOCOL:
if (handle_icmp_embedded_icmp_translation_global_rx_datagram_nats (sptr_icmp_packet) == FAIL)
{
return (FAIL);
}
break;
default:
nat_printf(NAT_PRINTF_ERROR,
"Global port: Unrecognized protocol in ICMP unreachable message datagram.\n");
return (FAIL);
}
}
else if (sptr_icmp_packet->header.type == ICMP_TIME_EXCEEDED_TYPE)
{
switch (sptr_icmp_packet->header.option.time_exceeded_message.ip_data.protocol)
{
case ICMP_PROTOCOL:
if (handle_icmp_embedded_icmp_translation_global_rx_datagram_nats (sptr_icmp_packet) == FAIL)
{
return (FAIL);
}
break;
default:
nat_printf (NAT_PRINTF_ERROR,
"Global port: Unrecognized protocol in ICMP time-exceeded datagram.\n");
return (FAIL);
}
}
return (PASS);
}
/**********************************************************************************************
Description:
Handle ICMP packet received from local port in NAPT. Only needs to handle destination
unreachable message. There is no reason that NAT should receive time-exceeded message
from local port.
**********************************************************************************************/
static enum TEST handle_icmp_translation_local_rx_datagram_nats (ICMP_PACKET *sptr_icmp_packet)
{
switch (sptr_icmp_packet->header.option.unreachable_message.ip_data.protocol)
{
case TCP_PROTOCOL:
if (handle_icmp_embedded_tcp_translation_local_rx_datagram_nats (sptr_icmp_packet) == FAIL)
{
return (FAIL);
}
break;
case UDP_PROTOCOL:
if (handle_icmp_embedded_udp_translation_local_rx_datagram_nats (sptr_icmp_packet) == FAIL)
{
return (FAIL);
}
break;
default:
nat_printf (NAT_PRINTF_ERROR,
"Local port: Unrecognized protocol in ICMP unreachable message datagram.\n");
return (FAIL);
}
return (PASS);
}
/***************************************************************************/
static enum TEST handle_icmp_embedded_tcp_translation_global_rx_datagram_nats (ICMP_PACKET *sptr_icmp_packet)
{
NAT_ICMP_EMBEDDED_HEADER *sptr_icmp_embedded_header=NULL;
NAT_CURRENCY_TRANSLATION_ENTRY *sptr_tcp_translation_entry=NULL;
IP_ADDRESS address;
USHORT local_port_number;
USHORT checksum;
TCP_PACKET sptr_tcp_packet;
sptr_tcp_packet = *(TCP_PACKET *)&sptr_icmp_packet->header.option.unreachable_message.ip_data;
sptr_icmp_embedded_header = (NAT_ICMP_EMBEDDED_HEADER *) &sptr_icmp_packet->header.option.unreachable_message.ip_data;
semTake(natentrylock, WAIT_FOREVER);
if(!sptr_tcp_translation_entry)
sptr_tcp_translation_entry = match_ports_with_tcp_entry_inbound (&sptr_tcp_packet);
semGive(natentrylock);
/* Did we find a TCP translation entry? */
if (sptr_tcp_translation_entry == NULL)
{
/* no way to determine who to send the ICMP message to*/
return FAIL;
}
/* TCP translation entry found */
address = htonl (sptr_tcp_translation_entry->local_address);
local_port_number = htons (sptr_tcp_translation_entry->local_port);
tcp_sequence_number_fixup_global_rx (&sptr_tcp_packet.tcp_header, sptr_tcp_translation_entry);
if (local_port_number != 0x0000)
{
checksum = sptr_tcp_packet.tcp_header.checksum;
checksum_fixup ((BYTE *) &checksum,
(BYTE *) &sptr_tcp_packet.tcp_header.source_port, sizeof (USHORT),
(BYTE *) &local_port_number, sizeof (USHORT));
sptr_tcp_packet.tcp_header.source_port = local_port_number;
sptr_tcp_packet.tcp_header.checksum = checksum;
}
checksum = sptr_tcp_packet.ip_header.header_checksum;
checksum_fixup ((BYTE *) &checksum,
(BYTE *) &sptr_tcp_packet.ip_header.source_address, sizeof (IP_ADDRESS),
(BYTE *) &address, sizeof (IP_ADDRESS));
sptr_tcp_packet.ip_header.source_address = address;
sptr_tcp_packet.ip_header.header_checksum = checksum;
checksum = sptr_icmp_packet->header.checksum;
checksum_fixup ((BYTE *) &checksum,
(BYTE *) &sptr_icmp_packet->header.option.unreachable_message.ip_data, sizeof (NAT_ICMP_EMBEDDED_HEADER),
(BYTE *) &sptr_tcp_packet, sizeof (NAT_ICMP_EMBEDDED_HEADER));
*sptr_icmp_embedded_header = *(NAT_ICMP_EMBEDDED_HEADER *) &sptr_tcp_packet;
sptr_icmp_packet->header.checksum = checksum;
checksum = sptr_icmp_packet->ip_header.header_checksum;
checksum_fixup ((BYTE *) &checksum,
(BYTE *) &sptr_icmp_packet->ip_header.destination_address, sizeof (IP_ADDRESS),
(BYTE *) &address, sizeof (IP_ADDRESS));
sptr_icmp_packet->ip_header.destination_address = address;
sptr_icmp_packet->ip_header.header_checksum = checksum;
return (PASS);
}
/***************************************************************************/
static enum TEST handle_icmp_embedded_udp_translation_global_rx_datagram_nats (ICMP_PACKET *sptr_icmp_packet)
{
NAT_ICMP_EMBEDDED_HEADER *sptr_icmp_embedded_header=NULL;
NAT_CURRENCY_TRANSLATION_ENTRY *sptr_udp_translation_entry=NULL;
IP_ADDRESS address;
USHORT checksum;
USHORT local_port_number;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -