Files
m241Neelima/components/ip_net2-6.9/ipnet2/src/ipnet_nat_ipsecproxy.c
T
2026-07-30 11:19:44 +05:30

1033 lines
41 KiB
C

/*
******************************************************************************
* SOURCE FILE
*
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipnet_nat_ipsecproxy.c,v $ $Revision: 1.13 $
* $Source: /home/interpeak/CVSRoot/ipnet2/src/ipnet_nat_ipsecproxy.c,v $
* $Author: markus $
* $State: Exp $ $Locker: $
*
* INTERPEAK_COPYRIGHT_STRING
* Design and implementation by Markus Carlstedt <markus@interpeak.se>
******************************************************************************
*/
/*
****************************************************************************
* 1 DESCRIPTION
****************************************************************************
* Proxy (ALG) for the IKE/ESP protocol.
*/
/*
****************************************************************************
* 2 CONFIGURATION
****************************************************************************
*/
#ifndef IPCOM_KERNEL
#define IPCOM_KERNEL
#endif
#include "ipnet_config.h"
/*
****************************************************************************
* 3 INCLUDE FILES
****************************************************************************
*/
#ifdef IPNET_USE_NAT
#define IPCOM_USE_CLIB_PROTO
#include <ipcom_clib.h>
#include <ipcom_sock.h>
#include <ipcom_inet.h>
#include <ipcom_syslog.h>
#include <ipcom_list.h>
#include "ipnet_nat.h"
/*
****************************************************************************
* 4 DEFINES
****************************************************************************
*/
#ifndef IPCOM_SYSLOG_PRIORITY
#define IPCOM_SYSLOG_PRIORITY IPNET_SYSLOG_PRIORITY
#endif
#ifndef IPCOM_SYSLOG_FACILITY
#define IPCOM_SYSLOG_FACILITY IPCOM_LOG_IPNET
#endif
/* ISAKMP timeouts in seconds */
#define IPNET_NAT_ISAKMP_INIT_TIMEOUT 2*60
#define IPNET_NAT_ISAKMP_ESTABLISHED_TIMEOUT 15*60
#define IPNET_NAT_ISAKMP_OLD_TIMEOUT 5*60
/* ESP timeouts in seconds */
#define IPNET_NAT_ESP_INIT_TIMEOUT 2*60
#define IPNET_NAT_ESP_ESTABLISHED_TIMEOUT 15*60
#define IPNET_NAT_ESP_SQUELCHED_TIMEOUT 30
/* Maximum number of retries to establish a translation entry */
#define IPNET_NAT_ESP_INIT_MAX_RETRIES 5
/* Maximum number of ESP translations */
#define IPNET_NAT_ESP_TRANS_MAX_ENTRIES 128
/* Maximum number of ISAKMP translations */
#define IPNET_NAT_ISAKMP_TRANS_MAX_ENTRIES 128
/*
****************************************************************************
* 5 TYPES
****************************************************************************
*/
/*
*===========================================================================
* Ipnet_nat_esp_hdr
*===========================================================================
*/
#include <ipcom_align16.h>
typedef IP_PACKED1 struct Ipnet_nat_esp_hdr_struct
{
Ip_u32 spi;
Ip_u32 seqno;
}
IP_PACKED2 Ipnet_nat_esp_hdr;
#include <ipcom_align16.h>
/*
*===========================================================================
* Ipnet_nat_esp_trans
*===========================================================================
*/
typedef struct Ipnet_nat_esp_trans_struct
{
Ipcom_list list; /* list pointer */
Ip_u32 local_address;
Ip_u32 remote_address;
Ip_u32 outbound_spi;
Ip_u32 inbound_spi;
Ip_u32 blocking;
Ip_u32 squelched;
Ip_u32 outbound_retry_count;
void *tmo; /* pointer to timeout */
}
Ipnet_nat_esp_trans;
/*
*===========================================================================
* Ipnet_nat_isakmp_hdr
*===========================================================================
*/
#include <ipcom_align16.h>
typedef IP_PACKED1 struct Ipnet_nat_isakmp_hdr_struct
{
Ip_u64 init_cookie;
Ip_u64 resp_cookie;
}
IP_PACKED2 Ipnet_nat_isakmp_hdr;
#include <ipcom_align16.h>
/*
*===========================================================================
* Ipnet_nat_isakmp_trans
*===========================================================================
*/
typedef struct Ipnet_nat_isakmp_trans_struct
{
Ipcom_list list; /* list pointer */
Ip_u32 local_address;
Ip_u32 remote_address;
Ip_u64 init_cookie;
Ip_u64 resp_cookie;
Ip_u32 old;
Ip_u32 create_time;
void *tmo; /* pointer to timeout */
}
Ipnet_nat_isakmp_trans;
/*
****************************************************************************
* 6 EXTERN PROTOTYPES
****************************************************************************
*/
/*
****************************************************************************
* 7 LOCAL PROTOTYPES
****************************************************************************
*/
/*
****************************************************************************
* 8 DATA
****************************************************************************
*/
IP_STATIC Ipcom_list ipnet_nat_proxy_ipsec_esp_list;
IP_STATIC Ipcom_list ipnet_nat_proxy_ipsec_isakmp_list;
/*
****************************************************************************
* 9 LOCAL FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipnet_nat_proxy_esp_translation_timeout
*===========================================================================
* Description: Timeout handler for ESP translation timeouts.
* Parameters: cookie - a cookie that is set when the timeout is added.
* Returns: nothing.
*/
IP_STATIC void
ipnet_nat_proxy_esp_translation_timeout(void *cookie)
{
Ipnet_nat_esp_trans *trans = cookie;
IPCOM_LOG4(DEBUG, "ipnet_nat_proxy_esp_translation_timeout() :: expired translation:\n"
"local address=0x%08x remote address=0x%08x\n"
"outbound spi=0x%08x inbound spi=0x%08x",
trans->local_address, trans->remote_address,
trans->outbound_spi, trans->inbound_spi);
ipcom_list_remove(&trans->list);
ipcom_free(trans);
}
/*
*===========================================================================
* ipnet_nat_proxy_ipsec_esp_find_pending
*===========================================================================
* Description: Match ESP packets with the list of pending ESP translation
* entries.
* Parameters: remote_address - public side address.
* Returns: Pointer to the translation or IP_NULL if not found.
*/
IP_STATIC Ipnet_nat_esp_trans *
ipnet_nat_proxy_ipsec_esp_find_pending(Ip_u32 remote_address)
{
Ipnet_nat_esp_trans *trans;
for (trans = IPCOM_LIST_FIRST(&ipnet_nat_proxy_ipsec_esp_list);
trans != IP_NULL;
trans = IPCOM_LIST_NEXT(&trans->list))
{
if (trans->remote_address == remote_address
&& trans->inbound_spi == 0)
{
IPCOM_LOG1(DEBUG, "ipnet_nat_proxy_ipsec_esp_find_pending() :: found pending entry for:\n"
"remote address=0x%08x inbound spi=0",
remote_address);
return trans;
}
}
IPCOM_LOG1(DEBUG, "ipnet_nat_proxy_ipsec_esp_find_pending() :: no pending entry for:\n"
"remote address=0x%08x inbound spi=0",
remote_address);
return IP_NULL;
}
/*
*===========================================================================
* ipnet_nat_proxy_ipsec_esp_match_outbound
*===========================================================================
* Description: Match outgoing ESP packets with the list of ESP translation
* entries.
* Parameters: spi - security parameter index.
* local_address - private side address.
* remote_address - public side address.
* Returns: Pointer to the translation or IP_NULL if not found.
*/
IP_STATIC Ipnet_nat_esp_trans *
ipnet_nat_proxy_ipsec_esp_match_outbound(Ip_u32 spi,
Ip_u32 local_address,
Ip_u32 remote_address)
{
Ipnet_nat_esp_trans *trans;
for (trans = IPCOM_LIST_FIRST(&ipnet_nat_proxy_ipsec_esp_list);
trans != IP_NULL;
trans = IPCOM_LIST_NEXT(&trans->list))
{
if (trans->outbound_spi == spi
&& trans->local_address == local_address
&& trans->remote_address == remote_address)
{
IPCOM_LOG3(DEBUG, "ipnet_nat_proxy_ipsec_esp_match_outbound() :: found match for:\n"
"local address=0x%08x remote address=0x%08x outbound spi=0x%08x",
local_address, remote_address, spi);
return trans;
}
}
IPCOM_LOG3(DEBUG, "ipnet_nat_proxy_ipsec_esp_match_outbound() :: no match for:\n"
"local address=0x%08x remote address=0x%08x outbound spi=0x%08x",
local_address, remote_address, spi);
return IP_NULL;
}
/*
*===========================================================================
* ipnet_nat_proxy_ipsec_esp_match_inbound
*===========================================================================
* Description: Match incoming ESP packets with the list of ESP translation
* entries.
* Parameters: spi - security parameter index.
* local_address - private side address.
* remote_address - public side address.
* Returns: Pointer to the translation or IP_NULL if not found.
*/
IP_STATIC Ipnet_nat_esp_trans *
ipnet_nat_proxy_ipsec_esp_match_inbound(Ip_u32 spi, Ip_u32 remote_address)
{
Ipnet_nat_esp_trans *trans;
for (trans = IPCOM_LIST_FIRST(&ipnet_nat_proxy_ipsec_esp_list);
trans != IP_NULL;
trans = IPCOM_LIST_NEXT(&trans->list))
{
if (trans->inbound_spi == spi
&& trans->remote_address == remote_address)
{
IPCOM_LOG2(DEBUG, "ipnet_nat_proxy_ipsec_esp_match_inbound() :: found match for:\n"
"remote address=0x%08x inbound spi=0x%08x",
remote_address, spi);
return trans;
}
}
IPCOM_LOG2(DEBUG, "ipnet_nat_proxy_ipsec_esp_match_inbound() :: no match for:\n"
"remote address=0x%08x inbound spi=0x%08x",
remote_address, spi);
return IP_NULL;
}
/*
*===========================================================================
* ipnet_nat_proxy_ipsec_esp_new
*===========================================================================
* Description: Create a new ESP translation entry and add it to the list.
* Parameters: spi - security parameter index.
* local_address - private side address.
* remote_address - public side address.
* Returns: pointer to the translation entry or IP_NULL if failed.
*/
IP_STATIC Ipnet_nat_esp_trans *
ipnet_nat_proxy_ipsec_esp_new(Ip_u32 spi,
Ip_u32 local_address,
Ip_u32 remote_address,
void *mapping)
{
Ipnet_nat_esp_trans *trans;
/* Check that there is room for another translation entry */
if(ipnet_nat_proxy_ipsec_esp_list.size >= IPNET_NAT_ESP_TRANS_MAX_ENTRIES)
{
IPCOM_LOG0(ERR, "ipnet_nat_proxy_ipsec_esp_new() ::"
"failed - too many translations");
return IP_NULL;
}
trans = ipcom_malloc(sizeof(*trans));
if (trans == IP_NULL)
{
IPCOM_LOG0(ERR, "ipnet_nat_proxy_ipsec_esp_new() ::"
"failed to allocate memory for translation entry");
return IP_NULL;
}
ipcom_memset(trans, 0, sizeof(*trans));
trans->inbound_spi = 0;
trans->blocking = 0;
trans->squelched = 0;
trans->outbound_retry_count = 0;
trans->outbound_spi = spi;
trans->local_address = local_address;
trans->remote_address = remote_address;
ipcom_list_insert_last(&ipnet_nat_proxy_ipsec_esp_list, &trans->list);
/* Add the timeout */
if (ipnet_nat_proxy_timeout_schedule(IPNET_NAT_ESP_INIT_TIMEOUT,
ipnet_nat_proxy_esp_translation_timeout,
trans,
&trans->tmo) < 0)
{
ipcom_list_remove(&trans->list);
ipcom_free(trans);
return IP_NULL;
}
/* Update the mapping timeout */
ipnet_nat_proxy_set_mapping_timeout(IPNET_NAT_ESP_INIT_TIMEOUT, mapping);
return trans;
}
/*
*===========================================================================
* ipnet_nat_proxy_isakmp_translation_timeout
*===========================================================================
* Description: Timeout handler for ISAKMP translation timeouts.
* Parameters: cookie - a cookie that is set when the timeout is added.
* Returns: nothing.
*/
IP_STATIC void
ipnet_nat_proxy_isakmp_translation_timeout(void *cookie)
{
Ipnet_nat_isakmp_trans *trans = cookie;
IPCOM_LOG6(DEBUG, "ipnet_nat_proxy_isakmp_translation_timeout() :: expired translation:\n"
"local address=0x%08x remote address=0x%08x\n"
"initiator cookie=0x%08x%08x responder cookie=0x%08x%08x",
trans->local_address, trans->remote_address,
IP_U64_GETHI(trans->init_cookie), IP_U64_GETLO(trans->init_cookie),
IP_U64_GETHI(trans->resp_cookie), IP_U64_GETLO(trans->resp_cookie));
ipcom_list_remove(&trans->list);
ipcom_free(trans);
}
/*
*===========================================================================
* ipnet_nat_proxy_ipsec_isakmp_match_outbound
*===========================================================================
* Description: Match outgoing ISAKMP packets with the list of ISAKMP
* translation entries.
* Parameters: init_cookie - pointer to initiator cookie.
* resp_cookie - pointer to responder cookie.
* local_address - private side address.
* remote_address - public side address.
* Returns: Pointer to the translation or IP_NULL if not found.
*/
IP_STATIC Ipnet_nat_isakmp_trans *
ipnet_nat_proxy_ipsec_isakmp_match_outbound(Ip_u64 *init_cookie,
Ip_u64 *resp_cookie,
Ip_u32 local_address,
Ip_u32 remote_address)
{
Ipnet_nat_isakmp_trans *trans;
for (trans = IPCOM_LIST_FIRST(&ipnet_nat_proxy_ipsec_isakmp_list);
trans != IP_NULL;
trans = IPCOM_LIST_NEXT(&trans->list))
{
if (IP_U64_EQUAL(trans->init_cookie, *init_cookie)
&& IP_U64_EQUAL(trans->resp_cookie, *resp_cookie)
&& trans->local_address == local_address
&& trans->remote_address == remote_address)
{
IPCOM_LOG6(DEBUG, "ipnet_nat_proxy_ipsec_isakmp_match_outbound() :: found match for:\n"
"local address=0x%08x remote address=0x%08x\n"
"initiator cookie=0x%08x%08x responder cookie=0x%08x%08x",
local_address, remote_address,
IP_U64_GETHI(*init_cookie), IP_U64_GETLO(*init_cookie),
IP_U64_GETHI(*resp_cookie), IP_U64_GETLO(*resp_cookie));
return trans;
}
}
IPCOM_LOG6(DEBUG, "ipnet_nat_proxy_ipsec_isakmp_match_outbound() :: no match for:\n"
"local address=0x%08x remote address=0x%08x\n"
"initiator cookie=0x%08x%08x responder cookie=0x%08x%08x",
local_address, remote_address,
IP_U64_GETHI(*init_cookie), IP_U64_GETLO(*init_cookie),
IP_U64_GETHI(*resp_cookie), IP_U64_GETLO(*resp_cookie));
return IP_NULL;
}
/*
*===========================================================================
* ipnet_nat_proxy_ipsec_isakmp_match_inbound
*===========================================================================
* Description: Match incoming ISAKMP packets with the list of ISAKMP
* translation entries.
* Parameters: init_cookie - pointer to initiator cookie.
* resp_cookie - pointer to responder cookie.
* remote_address - public side address.
* Returns: Pointer to the translation or IP_NULL if not found.
*/
IP_STATIC Ipnet_nat_isakmp_trans *
ipnet_nat_proxy_ipsec_isakmp_match_inbound(Ip_u64 *init_cookie,
Ip_u64 *resp_cookie,
Ip_u32 remote_address)
{
Ipnet_nat_isakmp_trans *trans;
for (trans = IPCOM_LIST_FIRST(&ipnet_nat_proxy_ipsec_isakmp_list);
trans != IP_NULL;
trans = IPCOM_LIST_NEXT(&trans->list))
{
if (IP_U64_EQUAL(trans->init_cookie, *init_cookie)
&& IP_U64_EQUAL(trans->resp_cookie, *resp_cookie)
&& trans->remote_address == remote_address)
{
IPCOM_LOG5(DEBUG, "ipnet_nat_proxy_ipsec_isakmp_match_inbound() :: found match for:\n"
"remote address=0x%08x\n"
"initiator cookie=0x%08x%08x responder cookie=0x%08x%08x",
remote_address,
IP_U64_GETHI(*init_cookie), IP_U64_GETLO(*init_cookie),
IP_U64_GETHI(*resp_cookie), IP_U64_GETLO(*resp_cookie));
return trans;
}
}
IPCOM_LOG5(DEBUG, "ipnet_nat_proxy_ipsec_isakmp_match_inbound() :: no match for:\n"
"remote address=0x%08x\n"
"initiator cookie=0x%08x%08x responder cookie=0x%08x%08x",
remote_address,
IP_U64_GETHI(*init_cookie), IP_U64_GETLO(*init_cookie),
IP_U64_GETHI(*resp_cookie), IP_U64_GETLO(*resp_cookie));
return IP_NULL;
}
/*
*===========================================================================
* ipnet_nat_proxy_ipsec_isakmp_new
*===========================================================================
* Description: Create a new ISAKMP translation entry and add it to the list.
* Parameters: init_cookie - pointer to initiator cookie.
* resp_cookie - pointer to responder cookie.
* local_address - private side address.
* remote_address - public side address.
* Returns: pointer to the translation entry or IP_NULL if failed.
*/
IP_STATIC Ipnet_nat_isakmp_trans *
ipnet_nat_proxy_ipsec_isakmp_new(Ip_u64 *init_cookie,
Ip_u64 *resp_cookie,
Ip_u32 local_address,
Ip_u32 remote_address,
void *mapping)
{
Ipnet_nat_isakmp_trans *trans;
Ipnet_nat_proxy_tuple proxy_tuple;
/* Check that there is room for another translation */
if(ipnet_nat_proxy_ipsec_isakmp_list.size >= IPNET_NAT_ISAKMP_TRANS_MAX_ENTRIES)
{
IPCOM_LOG0(ERR, "ipnet_nat_proxy_ipsec_isakmp_new() ::"
"failed - too many translations");
return IP_NULL;
}
trans = ipcom_malloc(sizeof(*trans));
if (trans == IP_NULL)
{
IPCOM_LOG0(ERR, "ipnet_nat_proxy_ipsec_isakmp_new() ::"
"failed to allocate memory for translation entry");
return IP_NULL;
}
ipcom_memset(trans, 0, sizeof(*trans));
IP_U64_COPY(trans->init_cookie, *init_cookie);
IP_U64_COPY(trans->resp_cookie, *resp_cookie);
trans->local_address = local_address;
trans->remote_address = remote_address;
trans->create_time = ipnet_nat_proxy_get_time();
ipcom_list_insert_last(&ipnet_nat_proxy_ipsec_isakmp_list, &trans->list);
/* Add the timeout */
if (ipnet_nat_proxy_timeout_schedule(IPNET_NAT_ISAKMP_INIT_TIMEOUT,
ipnet_nat_proxy_isakmp_translation_timeout,
trans,
&trans->tmo) < 0)
{
ipcom_list_remove(&trans->list);
ipcom_free(trans);
return IP_NULL;
}
/* Update the mapping timeout */
ipnet_nat_proxy_set_mapping_timeout(IPNET_NAT_ISAKMP_INIT_TIMEOUT, mapping);
/* Add a mapping for ESP in case that the first ESP packet is inbound */
ipcom_memset(&proxy_tuple, 0, sizeof(proxy_tuple));
proxy_tuple.protocol = IP_IPPROTO_ESP;
proxy_tuple.private_addr = local_address;
proxy_tuple.public_addr = remote_address;
(void)ipnet_nat_proxy_add_mapping(&proxy_tuple,
0,
mapping,
IP_FALSE, /* NAT port = local source port */
IP_FALSE,
ipnet_nat_proxy_ipsec,
IP_NULL);
return trans;
}
/*
*===========================================================================
* ipnet_nat_proxy_ipsec_isakmp_cleanup_list
*===========================================================================
* Description: Remove old entries in the ISAKMP translation list.
* Parameters: init_cookie - pointer to initiator cookie.
* resp_cookie - pointer to responder cookie.
* local_address - private side address.
* remote_address - public side address.
* Returns: Pointer to the translation or IP_NULL if not found.
*/
IP_STATIC void
ipnet_nat_proxy_ipsec_isakmp_cleanup_list(Ip_u64 *init_cookie,
Ip_u64 *resp_cookie,
Ip_u32 local_address,
Ip_u32 remote_address)
{
Ipnet_nat_isakmp_trans *trans;
for (trans = IPCOM_LIST_FIRST(&ipnet_nat_proxy_ipsec_isakmp_list);
trans != IP_NULL;
trans = IPCOM_LIST_NEXT(&trans->list))
{
if (!trans->old &&
trans->local_address == local_address &&
trans->remote_address == remote_address)
{
if (IP_U64_NEQUAL(trans->init_cookie, *init_cookie) ||
IP_U64_NEQUAL(trans->resp_cookie, *resp_cookie))
{
IPCOM_LOG6(DEBUG, "ipnet_nat_proxy_ipsec_isakmp_cleanup_list() :: found old entry:\n"
"local address=0x%08x remote address=0x%08x\n"
"initiator cookie=0x%08x%08x responder cookie=0x%08x%08x",
trans->local_address, trans->remote_address,
IP_U64_GETHI(trans->init_cookie), IP_U64_GETLO(trans->init_cookie),
IP_U64_GETHI(trans->resp_cookie), IP_U64_GETLO(trans->resp_cookie));
trans->old = 1;
ipnet_nat_proxy_timeout_reschedule(IPNET_NAT_ISAKMP_OLD_TIMEOUT,
ipnet_nat_proxy_isakmp_translation_timeout,
trans,
&trans->tmo);
}
}
}
}
/*
*===========================================================================
* ipnet_nat_proxy_ipsec_isakmp_find_active
*===========================================================================
* Description: Find active entries in the ISAKMP translation list.
* Parameters: remote_address - public side address.
* active_address - pointer to active address.
* Returns: Pointer to the translation or IP_NULL if not found.
*/
IP_STATIC Ip_u32
ipnet_nat_proxy_ipsec_isakmp_find_active(Ip_u32 remote_address,
Ip_u32 *active_address)
{
Ipnet_nat_isakmp_trans *trans;
Ip_u32 num = 0, tmp = 0;
for (trans = IPCOM_LIST_FIRST(&ipnet_nat_proxy_ipsec_isakmp_list);
trans != IP_NULL;
trans = IPCOM_LIST_NEXT(&trans->list))
{
/* Get the newest entry */
if (trans->remote_address == remote_address
&& (Ip_s32)(trans->create_time - tmp) >= 0)
{
tmp = trans->create_time;
*active_address = trans->local_address;
num = 1;
}
}
if (num > 0)
{
IPCOM_LOG2(DEBUG, "ipnet_nat_proxy_ipsec_isakmp_find_active() :: found active isakmp entry:\n"
"local address=0x%08x remote address=0x%08x\n",
*active_address, remote_address);
}
return num;
}
/*
*===========================================================================
* ipnet_nat_proxy_ipsec_esp
*===========================================================================
* Description: Track ESP packets and forward responses to inner host.
* Parameters: newhdr - pointer to optionally write new IP header.
* appdata - pointer to application data.
* applen - pointer to length of application data.
* param - pointer to proxy parameters.
* Returns: 1 = Packet modified.
* 0 = Packet untouched.
* -1 = Drop packet.
*/
IP_STATIC int
ipnet_nat_proxy_ipsec_esp(Ip_u8 *newhdr,
Ip_u8 *appdata,
int applen,
Ipnet_nat_proxy_param *param)
{
Ipcom_ip_header *iph;
Ipnet_nat_esp_hdr *esp;
Ipnet_nat_esp_trans *trans;
Ip_u32 spi, active_address = 0, num;
/* Check that at least a header is included */
if (applen < (int)sizeof(*esp))
{
IPCOM_LOG0(WARNING, "ipnet_nat_proxy_ipsec_esp() :: message too short for ESP header");
return 0;
}
esp = (Ipnet_nat_esp_hdr *)appdata;
spi = IP_GET_NTOHL(&esp->spi);
if (param->incoming == IP_FALSE)
{
/* Try to find translation entry, with both initiator and responder cookie */
trans = ipnet_nat_proxy_ipsec_esp_match_outbound(spi, param->tuple.private_addr, param->tuple.public_addr);
/* No entry found, maybe create a new one */
if (trans == IP_NULL)
{
trans = ipnet_nat_proxy_ipsec_esp_find_pending(param->tuple.public_addr);
if (trans != IP_NULL && !trans->squelched)
{
/* Found one in progress to same host....need to wait awhile */
trans->blocking = 1;
ipnet_nat_proxy_timeout_reschedule(IPNET_NAT_ESP_INIT_TIMEOUT,
ipnet_nat_proxy_esp_translation_timeout,
trans,
&trans->tmo);
/* Update the mapping timeout */
ipnet_nat_proxy_set_mapping_timeout(IPNET_NAT_ESP_INIT_TIMEOUT, param->mapping);
IPCOM_LOG1(DEBUG, "ipnet_nat_proxy_ipsec_esp() ::"
"Blocked ESP packet dropped from local host 0x%08x", param->tuple.private_addr);
return -1;
}
else
{
/* Create a new entry, no others in progress to same host... */
trans = ipnet_nat_proxy_ipsec_esp_new(spi,
param->tuple.private_addr,
param->tuple.public_addr,
param->mapping);
if (trans == IP_NULL)
return -1;
}
}
else
{
if (trans->squelched)
{
IPCOM_LOG1(DEBUG, "ipnet_nat_proxy_ipsec_esp() ::"
"Squelched ESP Packet Dropped from local host 0x%08x", param->tuple.private_addr);
return -1;
}
/* The remote end hasn't responded yet.... */
if (trans->inbound_spi == 0)
{
ipnet_nat_proxy_timeout_reschedule(IPNET_NAT_ESP_INIT_TIMEOUT,
ipnet_nat_proxy_esp_translation_timeout,
trans,
&trans->tmo);
/* Update the mapping timeout */
ipnet_nat_proxy_set_mapping_timeout(IPNET_NAT_ESP_INIT_TIMEOUT, param->mapping);
if (trans->blocking)
{
trans->outbound_retry_count++;
IPCOM_LOG2(DEBUG, "ipnet_nat_proxy_ipsec_esp() ::"
"ESP Outbound Retry Count = %d on local host 0x%08x",
trans->outbound_retry_count, param->tuple.private_addr);
if (trans->outbound_retry_count > IPNET_NAT_ESP_INIT_MAX_RETRIES)
{
trans->squelched = 1;
ipnet_nat_proxy_timeout_reschedule(IPNET_NAT_ESP_SQUELCHED_TIMEOUT,
ipnet_nat_proxy_esp_translation_timeout,
trans,
&trans->tmo);
/* Update the mapping timeout */
IPCOM_LOG1(DEBUG, "ipnet_nat_proxy_ipsec_esp() ::"
"Squelched ESP Packet Dropped from local host 0x%08x", param->tuple.private_addr);
return -1;
}
}
}
else
{
/* Update the mapping timeout */
ipnet_nat_proxy_set_mapping_timeout(IPNET_NAT_ESP_ESTABLISHED_TIMEOUT, param->mapping);
}
}
return 0;
}
else
{
/* Try to find translation entry, with both initiator and responder cookie */
trans = ipnet_nat_proxy_ipsec_esp_match_inbound(spi, param->tuple.public_addr);
/* If not found, try pending entry */
if (trans == IP_NULL)
trans = ipnet_nat_proxy_ipsec_esp_find_pending(param->tuple.public_addr);
/* No entry found, try to guess who should get the packet based on ISAKMP traffic */
if (trans == IP_NULL)
{
num = ipnet_nat_proxy_ipsec_isakmp_find_active(param->tuple.public_addr, &active_address);
if (num == 0)
{
IPCOM_LOG1(DEBUG, "ipnet_nat_proxy_ipsec_esp() ::"
"ESP packet droppped from remote host 0x%08x", param->tuple.public_addr);
return -1;
}
}
if (trans != IP_NULL)
{
/* Save the inbound spi if needed */
if (trans->inbound_spi == 0)
trans->inbound_spi = spi;
/* Reset the translation entry timer */
ipnet_nat_proxy_timeout_reschedule(IPNET_NAT_ESP_ESTABLISHED_TIMEOUT,
ipnet_nat_proxy_esp_translation_timeout,
trans,
&trans->tmo);
/* Update the mapping timeout */
ipnet_nat_proxy_set_mapping_timeout(IPNET_NAT_ESP_ESTABLISHED_TIMEOUT, param->mapping);
active_address = trans->local_address;
}
/* Translate the destination address.... */
iph = (Ipcom_ip_header *)newhdr;
IP_SET_HTONL(&iph->dst, active_address);
return 1;
}
}
/*
*===========================================================================
* ipnet_nat_proxy_ipsec_isakmp
*===========================================================================
* Description: Track ISAKMP packets and forward responses to inner host.
* Parameters: newhdr - pointer to optionally write new IP header.
* appdata - pointer to application data.
* applen - pointer to length of application data.
* param - pointer to proxy parameters.
* Returns: 1 = Packet modified.
* 0 = Packet untouched.
* -1 = Drop packet.
*/
IP_STATIC int
ipnet_nat_proxy_ipsec_isakmp(Ip_u8 *newhdr,
Ip_u8 *appdata,
int applen,
Ipnet_nat_proxy_param *param)
{
Ipcom_ip_header *iph;
Ipnet_nat_isakmp_hdr *isakmp;
Ipnet_nat_isakmp_trans *trans;
Ip_u64 init_cookie, resp_cookie, null_cookie;
/* Check that at least a header is included */
if (applen < (int)sizeof(*isakmp))
{
IPCOM_LOG0(WARNING, "ipnet_nat_proxy_ipsec_isakmp() :: message too short for ISAKMP header");
return 0;
}
isakmp = (Ipnet_nat_isakmp_hdr *)appdata;
#ifdef IPCOM_USE_LONGLONG_TYPE
init_cookie = IP_GET_NTOH64(&isakmp->init_cookie);
resp_cookie = IP_GET_NTOH64(&isakmp->resp_cookie);
#else
ipcom_memcpy(&init_cookie.hi, &isakmp->init_cookie, 4);
init_cookie.hi = ip_ntohl(init_cookie.hi);
ipcom_memcpy(&init_cookie.lo, (Ip_u8 *)&isakmp->init_cookie + 4, 4);
init_cookie.lo = ip_ntohl(init_cookie.lo);
ipcom_memcpy(&resp_cookie.hi, &isakmp->resp_cookie, 4);
resp_cookie.hi = ip_ntohl(resp_cookie.hi);
ipcom_memcpy(&resp_cookie.lo, (Ip_u8 *)&isakmp->resp_cookie + 4, 4);
resp_cookie.lo = ip_ntohl(resp_cookie.lo);
#endif /* #ifdef IPCOM_USE_LONGLONG_TYPE */
IP_U64_SET(null_cookie, 0, 0);
/* If the initiator cookie is zero, give up... */
if (IP_U64_GETHI(init_cookie) == 0 && IP_U64_GETLO(init_cookie) == 0)
return 0;
if (param->incoming == IP_FALSE)
{
/* Try to find translation entry, with both initiator and responder cookie */
trans = ipnet_nat_proxy_ipsec_isakmp_match_outbound(&init_cookie,
&resp_cookie,
param->tuple.private_addr,
param->tuple.public_addr);
/* If not found, try without responder cookie */
if (trans == IP_NULL)
trans = ipnet_nat_proxy_ipsec_isakmp_match_outbound(&init_cookie,
&null_cookie,
param->tuple.private_addr,
param->tuple.public_addr);
/* No entry found, create a new one */
if (trans == IP_NULL)
trans = ipnet_nat_proxy_ipsec_isakmp_new(&init_cookie,
&resp_cookie,
param->tuple.private_addr,
param->tuple.public_addr,
param->mapping);
if (trans == IP_NULL)
return -1;
/* Reset the translation entry timer */
if (IP_U64_GETHI(trans->resp_cookie) == 0 && IP_U64_GETLO(trans->resp_cookie) == 0)
{
ipnet_nat_proxy_timeout_reschedule(IPNET_NAT_ISAKMP_INIT_TIMEOUT,
ipnet_nat_proxy_isakmp_translation_timeout,
trans,
&trans->tmo);
/* Update the mapping timeout */
ipnet_nat_proxy_set_mapping_timeout(IPNET_NAT_ISAKMP_INIT_TIMEOUT, param->mapping);
}
else
{
ipnet_nat_proxy_timeout_reschedule(IPNET_NAT_ISAKMP_ESTABLISHED_TIMEOUT,
ipnet_nat_proxy_isakmp_translation_timeout,
trans,
&trans->tmo);
/* Update the mapping timeout */
ipnet_nat_proxy_set_mapping_timeout(IPNET_NAT_ISAKMP_ESTABLISHED_TIMEOUT, param->mapping);
}
return 0;
}
else
{
/* Try to find translation entry, with both initiator and responder cookie */
trans = ipnet_nat_proxy_ipsec_isakmp_match_inbound(&init_cookie,
&resp_cookie,
param->tuple.public_addr);
/* If not found, try without responder cookie */
if (trans == IP_NULL)
trans = ipnet_nat_proxy_ipsec_isakmp_match_inbound(&init_cookie,
&null_cookie,
param->tuple.public_addr);
/* No entry found, drop packet */
if (trans == IP_NULL)
{
IPCOM_LOG1(DEBUG, "ipnet_nat_proxy_ipsec_isakmp() ::"
"ISAKMP packet droppped from remote host 0x%08x", param->tuple.public_addr);
return -1;
}
/* Save the responder cookie if needed */
if (IP_U64_GETHI(trans->resp_cookie) == 0 && IP_U64_GETLO(trans->resp_cookie) == 0)
IP_U64_COPY(trans->resp_cookie, resp_cookie);
ipnet_nat_proxy_ipsec_isakmp_cleanup_list(&init_cookie,
&resp_cookie,
trans->local_address,
param->tuple.public_addr);
/* Reset the translation entry timer */
ipnet_nat_proxy_timeout_reschedule(IPNET_NAT_ISAKMP_ESTABLISHED_TIMEOUT,
ipnet_nat_proxy_isakmp_translation_timeout,
trans,
&trans->tmo);
/* Update the mapping timeout */
ipnet_nat_proxy_set_mapping_timeout(IPNET_NAT_ISAKMP_ESTABLISHED_TIMEOUT, param->mapping);
/* Translate the destination address.... */
iph = (Ipcom_ip_header *)newhdr;
IP_SET_HTONL(&iph->dst, trans->local_address);
return 1;
}
}
/*
****************************************************************************
* 10 GLOBAL FUNCTIONS
****************************************************************************
*/
/*
****************************************************************************
* 11 PUBLIC FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipnet_nat_proxy_ipsec
*===========================================================================
* Description: NAT proxy for the IPSEC protocol.
* Parameters: newhdr - pointer to optionally write new IP header.
* appdata - pointer to application data.
* applen - pointer to length of application data.
* growspace - space available to extend application data.
* param - pointer to proxy parameters.
* newdata - pointer to pointer to new application data.
* Returns: 1 = Packet modified.
* 0 = Packet untouched.
* -1 = Drop packet.
*/
IP_PUBLIC int
ipnet_nat_proxy_ipsec(Ip_u8 *newhdr,
Ip_u8 *appdata,
int *applen,
int growspace,
Ipnet_nat_proxy_param *param,
Ip_u8 **newdata)
{
IP_STATIC int init = 0;
(void)growspace;
(void)newdata;
/* Cannot handle fragments other than the first */
if (param->fragoff != 0)
return 0;
/* IKE/ESP proxy does not apply to NAT-PT or redirect rules */
if(param->natpt == IP_TRUE || param->inbound == IP_TRUE)
return 0;
if (!init)
{
ipcom_list_init(&ipnet_nat_proxy_ipsec_esp_list);
ipcom_list_init(&ipnet_nat_proxy_ipsec_isakmp_list);
init = 1;
}
if (param->tuple.protocol == IP_IPPROTO_ESP)
return ipnet_nat_proxy_ipsec_esp(newhdr, appdata, *applen, param);
else
return ipnet_nat_proxy_ipsec_isakmp(newhdr, appdata, *applen, param);
}
#else
int ipnet_nat_ipsecproxy_empty_file;
#endif /* IPNET_USE_NAT */
/*
****************************************************************************
* END OF FILE
****************************************************************************
*/