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

646 lines
22 KiB
C

/*
******************************************************************************
* SOURCE FILE
*
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipike_payload_nat.c,v $ $Revision: 1.14.10.4 $
* $Source: /home/interpeak/CVSRoot/ipike/src/ipike_payload_nat.c,v $
* $Author: hxie $ $Date: 2012-09-07 00:16:46 $
* $State: Exp $ $Locker: $
*
* INTERPEAK_COPYRIGHT_STRING
* Design and implementation by Magnus Alstrom <info@interpeak.se>
******************************************************************************
*/
/*
****************************************************************************
* 1 DESCRIPTION
****************************************************************************
*/
/* NAT Discovery payload
* NAT Original Address payload
*
* Payloads for discovering and handling of NAT traversal (RFC 3947)
*/
/*
****************************************************************************
* 2 CONFIGURATION
****************************************************************************
*/
/*
****************************************************************************
* 3 INCLUDE FILES
****************************************************************************
*/
#include "ipike_h.h"
#include "ipike_config.h"
#include "ipike_payload_nat.h"
#include <ipcom_clib.h>
#include <ipcom_syslog.h>
#include <openssl/md5.h>
#include <openssl/sha.h>
/*
****************************************************************************
* 4 EXTERN PROTOTYPES
****************************************************************************
*/
/*
****************************************************************************
* 5 DEFINES
****************************************************************************
*/
/*
****************************************************************************
* 6 TYPES
****************************************************************************
*/
/*
****************************************************************************
* 7 LOCAL PROTOTYPES
****************************************************************************
*/
/*
*===========================================================================
* ipike_nat_discovery_data
*===========================================================================
* Description: Returns a pointer to the nat discovery data in the payload.
* Parameters: nat_discovery - a nat discovery payload.
* Returns: A pointer to the nat discovery data.
*
*/
IP_STATIC Ip_u8*
ipike_nat_discovery_data(Ipike_nat_discovery_payload* nat_discovery);
/*
*===========================================================================
* ipike_nat_discovery_data_length
*===========================================================================
* Description: Returns the length of the nat discovery data.
* Parameters: nat_discovery - nat discovery payload.
* Returns: The length of the nat discovery data (in bytes).
*
*
*/
IP_STATIC Ip_u16
ipike_nat_discovery_data_length(Ipike_nat_discovery_payload* nat_discovery);
/*
*===========================================================================
* ipike_nat_original_address_data
*===========================================================================
* Description: Returns a pointer to the nat original data in the payload.
* Parameters: nat_org_addr - a nat original address payload.
* Returns: A pointer to the nat original data.
*
*/
IP_STATIC Ip_u8*
ipike_nat_original_address_data(Ipike_nat_org_addr_payload* nat_org_addr);
/*
*===========================================================================
* ipike_nat_original_address_data_length
*===========================================================================
* Description: Returns the length of the nat original data in the payload.
* Parameters: nat_org_addr - a nat original address payload.
* Returns: The length of the nat original address data (in bytes).
*
*
*/
IP_STATIC Ip_u16
ipike_nat_original_address_data_length(Ipike_nat_org_addr_payload* nat_org_addr);
/*
****************************************************************************
* 8 DATA
****************************************************************************
*/
/*
****************************************************************************
* 9 LOCAL FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipike_nat_discovery_data
*===========================================================================
*/
IP_STATIC Ip_u8*
ipike_nat_discovery_data(Ipike_nat_discovery_payload* nat_discovery)
{
return (Ip_u8*) nat_discovery + IPIKE_NAT_DISCOVERY_HEADER_LENGTH;
}
/*
*===========================================================================
* ipike_nat_discovery_data_length
*===========================================================================
*/
IP_STATIC Ip_u16
ipike_nat_discovery_data_length(Ipike_nat_discovery_payload* nat_discovery)
{
return IPIKE_PAYLOAD_DATA_LENGTH(nat_discovery->header.length, IPIKE_NAT_DISCOVERY_HEADER_LENGTH);
}
/*
*===========================================================================
* ipike_nat_original_address_data
*===========================================================================
*/
IP_STATIC Ip_u8*
ipike_nat_original_address_data(Ipike_nat_org_addr_payload* nat_org_addr)
{
return (Ip_u8*) nat_org_addr + IPIKE_NAT_ORG_ADDR_HEADER_LENGTH;
}
/*
*===========================================================================
* ipike_nat_original_address_data_length
*===========================================================================
*/
IP_STATIC Ip_u16
ipike_nat_original_address_data_length(Ipike_nat_org_addr_payload* nat_org_addr)
{
return IPIKE_PAYLOAD_DATA_LENGTH(nat_org_addr->header.length, IPIKE_NAT_ORG_ADDR_HEADER_LENGTH);
}
/*
*===========================================================================
* ipike_nat_original_address_new
*===========================================================================
*/
IP_STATIC Ipike_nat_org_addr_payload*
ipike_nat_original_address_new(
union Ip_sockaddr_union* address)
{
Ip_size_t len = 0;
Ipike_nat_org_addr_payload* ret = IP_NULL;
len = IPIKE_NAT_ORG_ADDR_HEADER_LENGTH + ipike_addr_get_len(address);
if (IP_NULL == (ret = ipcom_calloc(1, len)))
{
IPCOM_LOG0(CRIT, "ipike_nat_original_address_new() :: out of memory");
return IP_NULL;
}
ret->header.length = ip_htons(len);
ret->header.next_payload = IPIKE_PAYLOAD_NAT_ORIGINAL_ADDRESS;
if (ipike_addr_get_len(address) == 4)
ret->type = IPIKE_ID_IPV4_ADDR;
else
ret->type = IPIKE_ID_IPV6_ADDR;
ipcom_memcpy(ipike_nat_original_address_data(ret),
ipike_addr_get_ptr(address),
ipike_addr_get_len(address));
return ret;
}
/*
****************************************************************************
* 10 PUBLIC FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipike_nat_discovery_new
*===========================================================================
*/
IP_GLOBAL Ipike_nat_discovery_payload*
ipike_nat_discovery_new(
const Ip_u8* nat_discovery_data,
Ip_u16 nat_discovery_len)
{
Ipike_nat_discovery_payload* ret = IP_NULL;
if (IP_NULL == (ret = ipcom_calloc(1, IPIKE_NAT_DISCOVERY_HEADER_LENGTH + nat_discovery_len)))
{
IPCOM_LOG0(CRIT, "ipike_nat_discovery_new: out of memory");
return IP_NULL;
}
ret->header.length = ip_htons(IPIKE_NAT_DISCOVERY_HEADER_LENGTH + nat_discovery_len);
ret->header.next_payload = IPIKE_PAYLOAD_NAT_DISCOVERY;
ipcom_memcpy(ipike_nat_discovery_data(ret), nat_discovery_data, nat_discovery_len);
return ret;
}
/*
*===========================================================================
* ipike_nat_discovery_create
*===========================================================================
*/
IP_GLOBAL Ipike_error
ipike_nat_discovery_create(
union Ip_sockaddr_union* address,
Ip_u8* i_cookie,
Ip_u8* r_cookie,
Ip_u16 hash_alg,
Ipike_nat_discovery_payload** nat_discovery)
{
Ipike_error err;
Ipike_value n;
ipcom_memset(&n, 0, sizeof(n));
err = ipike_nat_discovery_generate(address, i_cookie, r_cookie, hash_alg, &n);
if (err != IPIKE_SUCCESS)
return err;
*nat_discovery = ipike_nat_discovery_new(n.value, (Ip_u16)n.len);
ipcom_free(n.value);
if (IP_NULL == *nat_discovery)
{
IP_PANIC();
return IPIKE_OUT_OF_MEMORY;
}
return IPIKE_SUCCESS;
}
/*
*===========================================================================
* ipike_nat_discovery_check_payload
*===========================================================================
*/
IP_GLOBAL Ipike_error
ipike_nat_discovery_check_payload(Ipike_nat_discovery_payload* nat_discovery)
{
size_t len = ipike_nat_discovery_data_length(nat_discovery);
if (len < IPIKE_NAT_DISCOVERY_MIN_LEN ||
len > IPIKE_NAT_DISCOVERY_MAX_LEN)
{
IPCOM_LOG3(ERR, "ipike_nat_discovery_check_payload() :: the NAT "\
"discovery size must be between %u and %u, "\
"this nat_discovery was %u",
IPIKE_NAT_DISCOVERY_MIN_LEN,
IPIKE_NAT_DISCOVERY_MAX_LEN,
len);
return IPIKE_ATTRIBUTE_INVALID_VALUE;
}
return IPIKE_SUCCESS;
}
/*
*===========================================================================
* ipike_nat_discovery_generate_pair
*===========================================================================
*/
IP_GLOBAL Ipike_error
ipike_nat_discovery_generate_pair(Ipike_sadb_entry* ike_sa, Ip_u16 hash_alg)
{
Ipike_error err = IPIKE_SUCCESS;
/* Is NAT discovery disabled? */
if (ipike.port_nat != 0)
{
IPIKE_FREEP(ike_sa->local_nat_data.value);
IPIKE_FREEP(ike_sa->peer_nat_data.value);
ike_sa->local_nat_data.value = IP_NULL;
ike_sa->peer_nat_data.value = IP_NULL;
err = ipike_nat_discovery_generate(&ike_sa->local_addr,
ike_sa->initiator_cookie,
ike_sa->responder_cookie,
hash_alg,
&ike_sa->local_nat_data);
if (err != IPIKE_SUCCESS)
{
IPCOM_LOG0(ERR, "Failed to generate local NAT data");
}
else
{
err = ipike_nat_discovery_generate(&ike_sa->peer_addr,
ike_sa->initiator_cookie,
ike_sa->responder_cookie,
hash_alg,
&ike_sa->peer_nat_data);
if (err != IPIKE_SUCCESS)
{
IPCOM_LOG0(ERR, "Failed to generate peer NAT data");
}
}
}
return err;
}
/*
*===========================================================================
* ipike_nat_discovery_start
*===========================================================================
*/
IP_GLOBAL Ipike_error
ipike_nat_discovery_start(Ipike_sadb_entry* ike_sa, Ip_u16 hash_alg)
{
Ipike_error err = IPIKE_SUCCESS;
/* Is NAT discovery disabled? */
if (ipike.port_nat == 0)
{
ike_sa->local_behind_nat = IP_FALSE;
ike_sa->peer_behind_nat = IP_FALSE;
}
/* Always consider behind NAT and let the discover payloads tell differently */
else
{
ike_sa->local_behind_nat = IP_TRUE;
ike_sa->peer_behind_nat = IP_TRUE;
ike_sa->has_got_nat_data = IP_FALSE;
err = ipike_nat_discovery_generate_pair(ike_sa, hash_alg);
}
return err;
}
/*
*===========================================================================
* ipike_nat_discovery_end
*===========================================================================
*/
IP_GLOBAL Ipike_error
ipike_nat_discovery_end(Ipike_isakmp_exchange* ie)
{
Ipike_error err = IPIKE_SUCCESS;
Ipike_sadb_entry* ike_sa = ie->ike_sa;
if (!ike_sa->has_got_nat_data)
{
ike_sa->local_behind_nat = IP_FALSE;
ike_sa->peer_behind_nat = IP_FALSE;
}
if (ike_sa->local_behind_nat ||
ike_sa->peer_behind_nat ||
(ipcom_sysvar_get_as_int("ipike.always_nat", 0) != 0) ||
(ike_sa->has_got_nat_data &&
(ipcom_sysvar_get_as_int("ipike.mobike", 0) != 0)))
{
if (ike_sa->local_behind_nat)
IPCOM_LOG0(DEBUG, "Local is behind a NAT");
if (ike_sa->peer_behind_nat)
IPCOM_LOG0(DEBUG, "Peer is behind a NAT");
/* In case of reauthentication we might already have updated
* the IKE SA with correct port */
if (ipike_addr_get_port(&ike_sa->local_addr) == ipike.port ||
ipike_addr_get_port(&ike_sa->peer_addr) == ipike.port)
{
/* Switch to NAT port (default 4500) */
ipike_sadb_update_port(ike_sa, ipike.port_nat,
ike_sa->is_initiator ? ipike.port_nat
: ipike_addr_get_port(&ie->msg.peer_addr));
}
(void)ipike_addr_set_port(&ie->msg.local_addr,
ipike_addr_get_port(&ike_sa->local_addr));
(void)ipike_addr_set_port(&ie->msg.peer_addr,
ipike_addr_get_port(&ike_sa->peer_addr));
}
return err;
}
/*
*===========================================================================
* ipike_nat_discovery_process
*===========================================================================
*/
IP_GLOBAL Ipike_error
ipike_nat_discovery_process(
Ipike_sadb_entry* ike_sa,
Ipike_nat_discovery_payload* payload)
{
ike_sa->has_got_nat_data = IP_TRUE;
/* Is the payload for the local address? */
if ((ipike_nat_discovery_data_length(payload) ==
ike_sa->local_nat_data.len) &&
!ipcom_memcmp(ipike_nat_discovery_data(payload),
ike_sa->local_nat_data.value,
ike_sa->local_nat_data.len))
{
ike_sa->local_behind_nat = IP_FALSE;
}
/* Is the payload for the peer address? */
else if ((ipike_nat_discovery_data_length(payload) ==
ike_sa->peer_nat_data.len) &&
!ipcom_memcmp(ipike_nat_discovery_data(payload),
ike_sa->peer_nat_data.value,
ike_sa->peer_nat_data.len))
{
ike_sa->peer_behind_nat = IP_FALSE;
}
return IPIKE_SUCCESS;
}
/*
*===========================================================================
* ipike_nat_discovery_generate
*===========================================================================
*/
IP_GLOBAL Ipike_error
ipike_nat_discovery_generate(
union Ip_sockaddr_union* addr,
Ip_u8* i_cookie,
Ip_u8* r_cookie,
Ip_u16 hash_alg,
Ipike_value* nat_discovery)
{
const EVP_MD* evp_md;
EVP_MD_CTX ctx;
Ip_u16 port;
IPCOM_LOG2(DEBUG2, "NAT-Traversal for %s[%d]", ipike_addr_to_str(addr), ipike_addr_get_port(addr));
IPCOM_LOG1(DEBUG2, " Initiator cookie %s", ipike_cookie_to_string(i_cookie));
IPCOM_LOG1(DEBUG2, " Responder cookie %s", ipike_cookie_to_string(r_cookie));
IPCOM_LOG1(DEBUG2, " Hash Algorithm %s", ipike_attribute_hash_alg_to_string(hash_alg));
if (IP_NULL == (evp_md = ipike_attribute_get_evp_hash(hash_alg)))
return IPIKE_SA_HASH_ALGORITHM_NOT_SUPPORTED;
nat_discovery->len = (Ip_size_t) EVP_MD_size(evp_md);
nat_discovery->value = ipcom_malloc(nat_discovery->len);
if (IP_NULL == nat_discovery->value)
{
IP_PANIC();
return IPIKE_OUT_OF_MEMORY;
}
(void)EVP_DigestInit(&ctx, evp_md);
/* digest cookies */
(void)EVP_DigestUpdate(&ctx, i_cookie, IPIKE_ISAKMP_COOKIE_SIZE);
(void)EVP_DigestUpdate(&ctx, r_cookie, IPIKE_ISAKMP_COOKIE_SIZE);
/* digest address */
(void)EVP_DigestUpdate(&ctx, ipike_addr_get_ptr(addr), ipike_addr_get_len(addr));
/* digest port */
port = ipike_addr_get_port(addr);
port = ip_ntohs(port);
(void)EVP_DigestUpdate(&ctx, &port, 2);
(void)EVP_DigestFinal(&ctx, nat_discovery->value, (unsigned int*)&nat_discovery->len);
(void)ipike_print_memory(IPCOM_LOG_DEBUG2, "Hash: ", nat_discovery->value, nat_discovery->len);
return IPIKE_SUCCESS;
}
/*
*===========================================================================
* ipike_nat_discovery_print_payload
*===========================================================================
*/
IP_GLOBAL void
ipike_nat_discovery_print_payload(Ipike_nat_discovery_payload* nat_discovery)
{
char* hex = IP_NULL;
hex = ipike_memory_to_string(ipike_nat_discovery_data(nat_discovery),
ipike_nat_discovery_data_length(nat_discovery),
4);
if (IP_NULL == hex)
{
IPCOM_LOG0(CRIT, "ipike_print_nat_discovery_payload: out of memory");
return;
}
IPCOM_LOG1(DEBUG2, " nat discovery: %s", hex);
ipcom_free(hex);
return;
}
/*
*===========================================================================
* ipike_nat_original_address_create
*===========================================================================
*/
IP_GLOBAL Ipike_error
ipike_nat_original_address_create(
union Ip_sockaddr_union* address,
Ipike_nat_org_addr_payload** nat_org_addr)
{
*nat_org_addr = ipike_nat_original_address_new(address);
if (IP_NULL == *nat_org_addr)
{
IP_PANIC();
return IPIKE_OUT_OF_MEMORY;
}
return IPIKE_SUCCESS;
}
/*
*===========================================================================
* ipike_nat_original_address_check_payload
*===========================================================================
*/
IP_GLOBAL Ipike_error
ipike_nat_original_address_check_payload(
Ipike_nat_org_addr_payload* nat_org_addr)
{
if ( nat_org_addr->type == IPIKE_ID_IPV4_ADDR )
{
if ( ipike_nat_original_address_data_length(nat_org_addr)
!= IPIKE_NAT_ORG_ADDR_MIN_LEN)
{
IPCOM_LOG2(ERR,
"ipike_nat_original_address_check_payload() :: "
" expected length %u, got %u",
IPIKE_NAT_DISCOVERY_MIN_LEN,
ipike_nat_original_address_data_length(nat_org_addr));
return IPIKE_ATTRIBUTE_INVALID_VALUE;
}
}
else if ( nat_org_addr->type == IPIKE_ID_IPV6_ADDR )
{
if ( ipike_nat_original_address_data_length(nat_org_addr)
!= IPIKE_NAT_ORG_ADDR_MAX_LEN)
{
IPCOM_LOG2(ERR,
"ipike_nat_original_address_check_payload() :: "
" expected length %u, got %u",
IPIKE_NAT_ORG_ADDR_MAX_LEN,
ipike_nat_original_address_data_length(nat_org_addr));
return IPIKE_ATTRIBUTE_INVALID_VALUE;
}
}
else
{
IPCOM_LOG1(ERR, "ipike_nat_original_address_check_payload() :: "
"invalid ID type %u",
nat_org_addr->type);
return IPIKE_ATTRIBUTE_INVALID_TYPE;
}
return IPIKE_SUCCESS;
}
/*
*===========================================================================
* ipike_nat_original_address_extract
*===========================================================================
*/
IP_GLOBAL Ipike_error
ipike_nat_original_address_extract(
Ipike_nat_org_addr_payload* payload,
union Ip_sockaddr_union* nat_org_addr)
{
return ipike_addr_set_from_data(ipike_nat_original_address_data(payload),
ipike_nat_original_address_data_length(payload),
nat_org_addr);
}
/*
*===========================================================================
* ipike_nat_original_address_print_payload
*===========================================================================
*/
IP_GLOBAL void
ipike_nat_original_address_print_payload(
Ipike_nat_org_addr_payload* nat_org_addr)
{
char* hex = IP_NULL;
hex = ipike_memory_to_string(ipike_nat_original_address_data(nat_org_addr),
ipike_nat_original_address_data_length(nat_org_addr),
4);
if (IP_NULL == hex)
{
IPCOM_LOG0(CRIT, "ipike_nat_original_address_print_payload()"\
" :: out of memory");
return;
}
IPCOM_LOG1(DEBUG2, " ID type: %s",
ipike_attribute_id_type_to_string(nat_org_addr->type));
IPCOM_LOG1(DEBUG2, " NAT-OA: %s", hex);
ipcom_free(hex);
return;
}
/*
****************************************************************************
* END OF FILE
****************************************************************************
*/