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

1924 lines
63 KiB
C

/*
******************************************************************************
* SOURCE FILE
*
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipike2_payload_notify.c,v $ $Revision: 1.53.10.12 $
* $Source: /home/interpeak/CVSRoot/ipike/src/ipike2_payload_notify.c,v $
* $Author: yli12 $ $Date: 2017-08-14 02:19:00 $
* $State: Exp $ $Locker: $
*
* INTERPEAK_COPYRIGHT_STRING
* Design and implementation by Kenneth Jonsson <kenneth@interpeak.se>
******************************************************************************
*/
/*
****************************************************************************
* 1 DESCRIPTION
****************************************************************************
*/
/* Notify payload (IKE version 2) */
/*
****************************************************************************
* 2 CONFIGURATION
****************************************************************************
*/
#include "ipike_config.h"
/*
****************************************************************************
* 3 INCLUDE FILES
****************************************************************************
*/
#ifdef IPIKE_USE_VERSION2
#include "ipike_h.h"
#include "ipike2_payload_notify.h"
#include "ipike2_exchange_sa_init.h"
#include "ipike2_exchange_info.h"
#include "ipike_util.h"
#include "ipike_crypto.h"
#include "ipike_sadb.h"
#include "ipike_ipsec_attributes.h"
#include "ipike_ipsec_sadb.h"
#include <ipcom_clib.h>
#include <ipcom_syslog.h>
#include <openssl/rand.h>
/*
****************************************************************************
* 4 EXTERN PROTOTYPES
****************************************************************************
*/
/*
****************************************************************************
* 5 DEFINES
****************************************************************************
*/
/*
****************************************************************************
* 6 TYPES
****************************************************************************
*/
/*
****************************************************************************
* 7 LOCAL PROTOTYPES
****************************************************************************
*/
/*
*===========================================================================
* Ipike_payload_notify_spi
*===========================================================================
* Description: Returns a pointer to the SPI data in the payload.
* Parameters: notify - a notification payload.
* Returns: A pointer to the SPI data.
*
*/
IP_STATIC Ip_u8 *
Ipike_payload_notify_spi(Ipike2_notify_payload* notify);
/*
*===========================================================================
* Ipike_payload_notify_data
*===========================================================================
* Description: Returns a pointer to the notification data in the payload.
* Parameters: notify - a notification payload.
* Returns: A pointer to the notification data.
*
*/
IP_STATIC Ip_u8 *
Ipike_payload_notify_data(Ipike2_notify_payload* notify);
/*
*===========================================================================
* Ipike_payload_notify_data_length
*===========================================================================
* Description: Returns the length of the hash data.
* Parameters: notify - a notification payload.
* Returns: The length of the notification data (in bytes).
*
*
*/
IP_STATIC Ip_u16
Ipike_payload_notify_data_length(Ipike2_notify_payload* notify);
/*
****************************************************************************
* 8 DATA
****************************************************************************
*/
/*
****************************************************************************
* 9 LOCAL FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* Ipike_payload_notify_spi
*===========================================================================
*/
IP_STATIC Ip_u8 *
Ipike_payload_notify_spi(Ipike2_notify_payload* notify)
{
return (Ip_u8*) notify + IPIKE_NOTIFY_HEADER_LENGTH;
}
/*
*===========================================================================
* Ipike_payload_notify_data
*===========================================================================
*/
IP_STATIC Ip_u8 *
Ipike_payload_notify_data(Ipike2_notify_payload* notify)
{
return (Ip_u8*) notify + IPIKE_NOTIFY_HEADER_LENGTH + notify->spi_size;
}
/*
*===========================================================================
* Ipike_payload_notify_data_length
*===========================================================================
*/
IP_STATIC Ip_u16
Ipike_payload_notify_data_length(Ipike2_notify_payload* notify)
{
return IPIKE_PAYLOAD_DATA_LENGTH(notify->header.length, (IPIKE_NOTIFY_HEADER_LENGTH + notify->spi_size));
}
/*
*===========================================================================
* ipike_payload_notify_generate_nat_detection_data
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_payload_notify_generate_nat_detection_data(
Ip_u8 cookie_i[IPIKE_ISAKMP_COOKIE_SIZE],
Ip_u8 cookie_r[IPIKE_ISAKMP_COOKIE_SIZE],
union Ip_sockaddr_union* address,
Ipike_value *hash)
{
Ipike_value data;
Ipike_error err = IPIKE_SUCCESS;
Ip_u8 port[2];
data.len = 0;
data.value = IP_NULL;
hash->value = IP_NULL;
/* Hash spi values and ip address */
port[0] = (Ip_u8)(ipike_addr_get_port(address) >> 8);
port[1] = (Ip_u8)(ipike_addr_get_port(address));
err = ipike_set_data(&data, cookie_i, IPIKE_ISAKMP_COOKIE_SIZE);
if ( IPIKE_SUCCESS != err )
goto out;
err = ipike_append_data(&data, cookie_r, IPIKE_ISAKMP_COOKIE_SIZE);
if ( IPIKE_SUCCESS != err )
goto out;
err = ipike_append_data(&data, ipike_addr_get_ptr(address), ipike_addr_get_len(address));
if ( IPIKE_SUCCESS != err )
goto out;
err = ipike_append_data(&data, port, 2);
if ( IPIKE_SUCCESS != err )
goto out;
err = ipike_crypto_hash(IPIKE_ATTR_HASH_SHA1, &data, hash);
if ( IPIKE_SUCCESS != err )
goto out;
IPCOM_LOG2(DEBUG2, "NAT Traversal for %s[%d]", ipike_addr_to_str(address), ipike_addr_get_port(address));
IPCOM_LOG1(DEBUG2, " Initiator cookie %s", ipike_cookie_to_string(cookie_i));
IPCOM_LOG1(DEBUG2, " Responder cookie %s", ipike_cookie_to_string(cookie_r));
(void)ipike_print_memory(IPCOM_LOG_DEBUG2, "Hash: ", hash->value, hash->len);
(void)ipike_print_memory(IPCOM_LOG_DEBUG2, "Data: ", data.value, data.len);
out:
if (IP_NULL != data.value)
ipcom_free(data.value);
return err;
}
/*
*===========================================================================
* ipike_payload_notify_process_invalid_ke
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_payload_notify_process_invalid_ke(
Ipike_isakmp_exchange* ie,
Ipike2_notify_payload* payload)
{
Ip_u8* data;
Ip_u16 len;
Ip_u16 group;
data = Ipike_payload_notify_data(payload);
len = Ipike_payload_notify_data_length(payload);
/* Responder didn't accept our d-h group, try with the specified group */
if (len == 2)
{
group = ip_htons(*((Ip_u16*)data));
DH_free(ie->dh);
ie->dh = IP_NULL;
if (IPIKE_SUCCESS == ipike_exchange_generate_dh_key(ie, IP_NULL, group))
{
/* Restart message pair */
ie->message_number -= 2;
/* Reset message ID if this is an IKE INIT message */
if ( ie->exchange_type == IPIKE2_ISAKMP_EXCH_IKE_SA_INIT )
{
ie->ike_sa->v2.message_id = 0;
/* RFC4718 Section 2.1
* Make sure that the responder SPI is set to zero */
ipcom_memset(ie->ike_sa->responder_cookie, 0, IPIKE_ISAKMP_COOKIE_SIZE);
}
return IPIKE_SUCCESS;
}
}
return IPIKE_EXCH_FINNISHED;
}
/*
*===========================================================================
* Ipike_payload_message_type_to_string
*===========================================================================
*/
IP_STATIC const char *
ipike_payload_message_type_to_string(Ip_u16 message_type)
{
const char* s;
if ((message_type >= IPIKE_NOTI_ERR_PRIVATE_USE_LOW) &&
(message_type <= IPIKE_NOTI_ERR_PRIVATE_USE_HIGH))
return "Error Private Use";
if (message_type >= IPIKE_NOTI_INF_PRIVATE_USE_LOW)
return "Information Private Use";
if (ipike_map_string(ipike.notify_map, message_type, &s) != IPIKE_SUCCESS)
return "Invalid message type";
return s;
}
/*
*===========================================================================
* ipike_payload_notify_process_error
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_payload_notify_process_error(
Ipike_isakmp_exchange* ie,
Ipike2_notify_payload* payload,
Ip_u16 type)
{
Ipike_error err = IPIKE_SUCCESS;
IPCOM_LOG1(INFO, "ipike_payload_notify_process_error() :: notify message '%s'",
ipike_payload_message_type_to_string(ip_htons(payload->message_type)));
/* Handle some error messages */
switch (type)
{
case IPIKE_NOTI_ERR_KE_PAYLOAD:
err = ipike_payload_notify_process_invalid_ke(ie, payload);
break;
case IPIKE_NOTI_ERR_INVALID_IKE_SPI:
/* The IKE SA doesn't exist for the other side, so delete it
* Removing the IKE SA in IKEv2 will implicitly remove all
* child IPsec SAs */
(void)ipike_sadb_set_state(ie, ie->ike_sa, IPIKE_SA_DYING);
/* Always abort exchange */
err = IPIKE_EXCH_FINNISHED;
break;
case IPIKE_NOTI_ERR_NO_PROPOSAL_CHOSEN:
/* Handle denied IKE rekey request */
if ( ie->exchange_type == IPIKE2_ISAKMP_EXCH_CREATE_CHILD_SA &&
ie->ike_sa_new)
{
IPCOM_LOG0(WARNING, "ipike_payload_notify_process_error() :: "\
"IKE rekey exchange rejected with NO_PROPOSAL_CHOSEN");
ie->ike_sa_new->error = IPIKE_ISAKMP_NO_PROPOSAL_CHOSEN;
}
else
{
IPCOM_LOG0(WARNING, "ipike_payload_notify_process_error() :: "\
"exchange rejected with NO_PROPOSAL_CHOSEN");
if ( ie->exchange_type == IPIKE2_ISAKMP_EXCH_IKE_AUTH ||
ie->exchange_type == IPIKE2_ISAKMP_EXCH_CREATE_CHILD_SA)
{
/* RFC4718 Section 4.2:
* This is also in line with how the CREATE_CHILD_SA exchange
* works: a failure to create a CHILD_SA does not close the IKE_SA. */
ie->ipsec_sa->error = IPIKE_ISAKMP_NO_PROPOSAL_CHOSEN;
}
else
{
/* Abort exchange */
err = IPIKE_EXCH_FINNISHED;
}
}
break;
case IPIKE_NOTI_ERR_NO_ADDITIONAL_SAS:
/* Handle denied IPsec rekey request */
if ( ie->exchange_type == IPIKE2_ISAKMP_EXCH_CREATE_CHILD_SA &&
ie->ipsec_sa )
{
IPCOM_LOG0(WARNING, "ipike_payload_notify_process_error() ::"\
" IPsec rekey exchange rejected with NO_ADDITIONAL_SAS");
ie->ipsec_sa->error = IPIKE_ISAKMP_NO_ADDITIONAL_SAS;
}
else
{
IPCOM_LOG0(WARNING, "ipike_payload_notify_process_error() :: "\
"exchange rejected with NO_ADDITIONAL_SAS");
/* Abort exchange */
err = IPIKE_EXCH_FINNISHED;
}
break;
default:
/* Ignore error notifications in two cases:
* 1. Send empty response if information exchange.
* 2. This is a request that contains a notification error.
* Otherwise, abort this exchange immediately */
if ( ie->exchange_type == IPIKE2_ISAKMP_EXCH_INFORMATIONAL ||
(ie->isakmp_flags & IPIKE_ISAKMP_RESPONSE) )
{
IPCOM_LOG1(NOTICE, "ipike_payload_notify_process_error() :: "\
"ignoring error notification (%d)", type);
}
else
{
IPCOM_LOG1(NOTICE, "ipike_payload_notify_process_error() :: "\
"aborting exchange", type);
err = IPIKE_EXCH_FINNISHED;
}
break;
}
return err;
}
/*
*===========================================================================
* ipike_payload_notify_process_nat_detection
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_payload_notify_process_nat_detection(
Ipike_isakmp_exchange* ie,
Ipike2_notify_payload* payload,
Ip_bool source)
{
Ipike_error err;
Ipike_value data;
union Ip_sockaddr_union* address;
/* We have at least got some NAT data and will be able to tell whether
* a NAT is between */
ie->ike_sa->has_got_nat_data = IP_TRUE;
if ( source )
{
if (ie->msg.peer_addr.sa.sa_family != 0)
address = &ie->msg.peer_addr;
else
address = &ie->ike_sa->peer_addr;
}
else
{
if (ie->msg.local_addr.sa.sa_family != 0)
address = &ie->msg.local_addr;
else
address = &ie->ike_sa->local_addr;
}
/* As responder of the IKE INIT message we must calculate the hash
with a zero responder cookie (spi) */
if ( !ie->ike_sa->is_initiator &&
ie->exchange_type == IPIKE2_ISAKMP_EXCH_IKE_SA_INIT)
{
Ip_u8 zero_cookie[IPIKE_ISAKMP_COOKIE_SIZE] = {0};
/* Generate the notify data */
err = ipike_payload_notify_generate_nat_detection_data(
ie->ike_sa->initiator_cookie,
zero_cookie,
address,
&data);
}
else
{
/* Generate the notify data */
err = ipike_payload_notify_generate_nat_detection_data(
ie->ike_sa->initiator_cookie,
ie->ike_sa->responder_cookie,
address,
&data);
}
if ( IPIKE_SUCCESS != err )
{
IPCOM_LOG0(ERR, "ipike_payload_notify_process_nat_detection() :: failed to generate NAT data");
return err;
}
/* Verify data are equal */
if ( data.len == Ipike_payload_notify_data_length(payload) &&
ipcom_memcmp(data.value, Ipike_payload_notify_data(payload), data.len) == 0 )
{
/* There is no NAT between source and destination */
if (source)
ie->ike_sa->peer_behind_nat = IP_FALSE;
else
ie->ike_sa->local_behind_nat = IP_FALSE;
}
else
{
if (source)
IPCOM_LOG0(DEBUG2, "ipike_payload_notify_process_nat_detection() :: source behind NAT");
else
IPCOM_LOG0(DEBUG2, "ipike_payload_notify_process_nat_detection() :: destination behind NAT");
}
ipcom_free(data.value);
return IPIKE_SUCCESS;
}
/*
*===========================================================================
* ipike_payload_notify_process_cookie
*===========================================================================
*/
IP_GLOBAL Ipike_error
ipike_payload_notify_process_cookie(
Ipike_isakmp_exchange* ie,
Ipike2_notify_payload* payload)
{
Ip_u8* data;
Ip_size_t length;
Ipike_error err;
if (IPIKE_NOTI_INF_COOKIE != ip_htons(payload->message_type))
{
IPCOM_LOG0(DEBUG2, "ipike_payload_notify_process_cookie - Not a cookie notify from initiator");
err = IPIKE_ISAKMP_INVALID_SYNTAX;
}
else
{
/* The initiator should resend the initial request with the same cookie
* value. The responder must verify that correct notify value is sent. */
length = ip_ntohs(payload->header.length) - sizeof(*payload);
data = ((Ip_u8*)payload) + sizeof(Ipike2_notify_payload);
if ((length < 1) || (length > 64))
{
err = IPIKE_ISAKMP_INVALID_SYNTAX;
}
else if (ie->ike_sa->is_initiator)
{
err = ipike_cpy_data(&(ie->cookie), data, length);
/* Restart message pair */
ie->message_number -= 2;
ie->message_id = 0;
ie->ike_sa->v2.message_id--;
}
else
{
if (length != sizeof(ie->ike_sa->responder_cookie)
|| ipcom_memcmp(ie->cookie.value, data, length))
{
IPCOM_LOG0(ERR, "Exchange aborted, bad cookie from initiator");
err = IPIKE_ISAKMP_INVALID_SYNTAX;
}
else
{
ipcom_memcpy(ie->ike_sa->responder_cookie, data, length);
ie->has_cookie = IP_TRUE;
err = IPIKE_SUCCESS;
}
}
}
return err;
}
/*
*===========================================================================
* ipike_payload_notify_process_rekey
*===========================================================================
*/
IP_GLOBAL Ipike_error
ipike_payload_notify_process_rekey(
Ipike_isakmp_exchange* ie,
Ipike2_notify_payload* payload)
{
Ipike_error err = IPIKE_SUCCESS;
if (IPIKE_NOTI_INF_REKEY_SA != ip_htons(payload->message_type))
{
IPCOM_LOG0(DEBUG2, "ipike_payload_notify_process_rekey() ::"\
" not a rekey notify from initiator");
return IPIKE_ISAKMP_INVALID_SYNTAX;
}
if (payload->spi_size == 4)
{
Ipike_value spi_data;
Ipike_ipsec_sadb_entry *ipsec_sa = IP_NULL;
/* Need to switch the ie ipsec conf pointer based on rekey */
err = ipike_set_data(&spi_data,(const void*)Ipike_payload_notify_spi(payload), 4);
if (err == IPIKE_SUCCESS)
{
err = ipike_ipsec_sadb_hash_get(spi_data.value, 0,
&ie->msg.local_addr, &ie->msg.peer_addr, &ipsec_sa);
if (err != IPIKE_SUCCESS)
err = ipike_ipsec_sadb_hash_get(spi_data.value, 0,
&ie->msg.peer_addr, &ie->msg.local_addr, &ipsec_sa);
}
if (err == IPIKE_SUCCESS)
{
Ipike_config_ipsec_sa *ipsec_conf;
ip_assert(ipsec_sa != IP_NULL);
ipsec_conf = ipike_config_get_ipsec_sa_from_id(ipike.config.ipsec_sa, ipsec_sa->ipsec_id);
if (ipsec_conf == IP_NULL)
{
IPCOM_LOG0(ERR, "ipike_payload_notify_process_rekey() ::"\
" unable to identify ipsec conf using rekey spi");
err = IPIKE_ISAKMP_INVALID_SPI;
}
else
{
IPCOM_LOG0(DEBUG2, "ipike_payload_notify_process_rekey() :: "\
"identified ipsec_conf using rekey spi");
ie->ipsec_conf = ipsec_conf;
}
/* The other side has initiated an rekey, steal reference to keep track
of simultaneous IPsec rekey, will remove it when the exchange is done */
ie->ike_sa->v2.child_ike_sa_pair[IPIKE_SA_IPSEC_REKEY_RESP] = ie->ipsec_sa;
/* Set IKE SA rekey flag */
IP_BIT_SET(ie->ike_sa->v2.flags, IPIKE_SA_FLAG_IPSEC_RESP_REKEY);
/* Make sure that this IPsec SA rekey does not collide with an IKE SA rekey */
if ( IP_BIT_ISSET(ie->ike_sa->v2.flags, IPIKE_SA_FLAG_IKE_INIT_REKEY) ||
IP_BIT_ISSET(ie->ike_sa->v2.flags, IPIKE_SA_FLAG_IKE_RESP_REKEY))
{
IPCOM_LOG0(WARNING, "ipike_payload_notify_process_rekey() ::"\
" recevied IPsec SA rekey request during IKE rekey");
/* From RFC4718: "If a host receives a request to create or rekey a
* CHILD_SA after it has started rekeying the IKE_SA, it should reply
* with NO_ADDITIONAL_SAS." */
ie->ipsec_sa->error = IPIKE_ISAKMP_NO_ADDITIONAL_SAS;
/* Continue the exchange so we can form a proper reply */
}
}
IPIKE_FREEP(spi_data.value);
}
return err;
}
/*
*===========================================================================
* ipike_payload_notify_process_initial_contact
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_payload_notify_process_initial_contact(Ipike_isakmp_exchange* ie)
{
/* Remove all IKE SA:s with same local/peer and not this responder
* and/or initiator cookie */
ipike_sadb_remove_all_except_this(ie->ike_sa);
return IPIKE_SUCCESS;
}
/*
*===========================================================================
* ipike_payload_notify_process_mobike_supported
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_payload_notify_process_mobike_supported(Ipike_isakmp_exchange* ie)
{
/* Peer sends message that mobike is supported, so enable if we support */
if (ipcom_sysvar_get_as_int("ipike.mobike", 0) != 0)
ie->ike_sa->mobike.enabled = IP_TRUE;
return IPIKE_SUCCESS;
}
/*
*===========================================================================
* ipike_payload_notify_process_additional_address
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_payload_notify_process_additional_address(
Ip_bool ip4,
Ipike_isakmp_exchange* ie,
Ipike2_notify_payload* payload)
{
union Ip_sockaddr_union* addr = IP_NULL;
Ip_u8* data = IP_NULL;
Ip_size_t len = 0;
Ipike_error err = IPIKE_SUCCESS;
/* Always clear list when new list of addresses arrives (from new exchange) */
if ((ie->ike_sa->mobike.peer_addresses != IP_NULL) &&
(ie->message_id != ie->ike_sa->mobike.message_id_addresses))
{
ipike_array_free((void**)ie->ike_sa->mobike.peer_addresses, ipcom_free);
ie->ike_sa->mobike.peer_addresses = IP_NULL;
}
ie->ike_sa->mobike.message_id_addresses = ie->message_id;
/* Store address for future use */
if (IP_NULL == (addr = ipcom_calloc(1, sizeof(*addr))))
{
IP_PANIC();
err = IPIKE_OUT_OF_MEMORY;
}
else
{
/* Initiate address structure */
len = ip_ntohs(payload->header.length) - sizeof(*payload);
data = ((Ip_u8*)payload) + (ip_ntohs(payload->header.length) - len);
err = ipike_addr_set_from_data(data, len, addr);
/* Check correct type of address */
#ifdef IPCOM_USE_INET
if ((IPIKE_SUCCESS == err) && ip4 && (addr->sa.sa_family != IP_AF_INET))
err = IPIKE_ISAKMP_INVALID_PAYLOAD;
#endif
#ifdef IPCOM_USE_INET6
if ((IPIKE_SUCCESS == err) && !ip4 && (addr->sa.sa_family != IP_AF_INET6))
err = IPIKE_ISAKMP_INVALID_PAYLOAD;
#endif
/* Add to list */
if (IPIKE_SUCCESS == err)
err = ipike_array_add((void***)&ie->ike_sa->mobike.peer_addresses, addr);
if (IPIKE_SUCCESS != err)
ipcom_free(addr);
}
return err;
}
/*
*===========================================================================
* ipike_payload_notify_process_no_additional_addresses
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_payload_notify_process_no_additional_addresses(Ipike_isakmp_exchange* ie)
{
(void)ie;
return IPIKE_SUCCESS;
}
/*
*===========================================================================
* ipike_payload_notify_process_update_sa_addresses
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_payload_notify_process_update_sa_addresses(Ipike_isakmp_exchange* ie)
{
if (ie->ike_conf == IP_NULL)
{
IPCOM_LOG0(ERR, "ipike_payload_notify_process_update_sa_addresses() ::"\
"new address not allowed for configuration");
return IPIKE_UNACCEPTABLE_ADDRESSES;
}
/* Store address of the remote peer */
return ipike_addr_copy(&ie->ike_sa->mobike.update.peer_addr,
&ie->msg.peer_addr);
}
/*
*===========================================================================
* ipike_payload_notify_process_cookie2
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_payload_notify_process_cookie2(
Ipike_isakmp_exchange* ie,
Ipike2_notify_payload* payload)
{
Ip_u8* data = IP_NULL;
Ip_size_t len = 0;
Ipike_error err = IPIKE_SUCCESS;
/* The responder should return the same cookie value. The initiator must
* verify that correct notify value is returned. */
len = ip_ntohs(payload->header.length) - sizeof(*payload);
data = ((Ip_u8*)payload) + (ip_ntohs(payload->header.length) - len);
if (ie->ike_sa->mobike.cookie2.value != IP_NULL)
{
/* Initiator side, verify received cookie2 with stored value */
if ( ie->ike_sa->mobike.cookie2.len != len ||
ipcom_memcmp(ie->ike_sa->mobike.cookie2.value, data, len) != 0 )
{
IPCOM_LOG0(ERR, "ipike_payload_notify_process_cookie2() ::"\
" bad cookie2 received, routability check failed");
}
else
{
/* Commit address update */
err = ipike_dispatch_commit_address_update(ie->ike_sa);
if (IPIKE_SUCCESS != err)
{
IPCOM_LOG0(ERR, "ipike_payload_notify_process_cookie2() ::"\
" update address failed");
}
/* Address updated, clear it */
ipcom_memset(&ie->ike_sa->mobike.update.peer_addr,
0,
sizeof(ie->ike_sa->mobike.update.peer_addr));
}
}
else
{
/* Responder side, return cookie2 to initiator */
err = ipike_set_data(&ie->ike_sa->mobike.cookie2, data, len);
/* Return cookie2 to initiator */
if (IPIKE_SUCCESS == err)
err = ipike_payload_notify_cookie2(&ie->ike_sa->mobike.cookie2,
(Ipike2_notify_payload**)&ie->phase2.notify_or_delete);
}
IPIKE_FREEP(ie->ike_sa->mobike.cookie2.value);
return err;
}
/*
*===========================================================================
* ipike_payload_notify_process_no_nats_allowed
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_payload_notify_process_no_nats_allowed(
Ipike_isakmp_exchange* ie,
Ipike2_notify_payload* payload)
{
Ipike_error err = IPIKE_SUCCESS;
Ip_u8* data = IP_NULL;
Ip_size_t len = 0;
Ip_u16 port = 0;
union Ip_sockaddr_union src_addr;
union Ip_sockaddr_union dst_addr;
/* There are either src/dst ip4 or ip6 address followed by src/dst port */
len = ip_ntohs(payload->header.length) - sizeof(*payload);
data = ((Ip_u8*)payload) + (ip_ntohs(payload->header.length) - len);
if ((len == (4 + 4 + 2 + 2)) || /* ip4 */
(len == (16 + 16 + 2 + 2))) /* ip6 */
{
err = ipike_addr_set_from_data(data, (len-4)/2, &src_addr);
if (IPIKE_SUCCESS == err)
err = ipike_addr_set_from_data(data + (len-4)/2, (len - 4)/2, &dst_addr);
ipcom_memcpy(&port, data + (len-4), sizeof(port));
(void)ipike_addr_set_port(&src_addr, ip_ntohs(port));
ipcom_memcpy(&port, data + (len-2), sizeof(port));
(void)ipike_addr_set_port(&dst_addr, ip_ntohs(port));
/* Compare addresses */
if (!ipike_addr_are_equal_port(&src_addr, &ie->msg.peer_addr) ||
!ipike_addr_are_equal_port(&dst_addr, &ie->msg.local_addr))
{
IPCOM_LOG0(ERR, "ipike_payload_notify_process_no_nats_allowed: NAT between local and peer");
err = IPIKE_UNEXPECTED_NAT_DETECTED;
}
}
else
{
err = IPIKE_ISAKMP_INVALID_PAYLOAD;
}
return err;
}
/*
*===========================================================================
* ipike_payload_notify_process_no_nats_allowed
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_payload_notify_process_http_cert_lookup_supported(
Ipike_isakmp_exchange* ie)
{
if ( ipike.use_hash_and_url )
{
ie->ike_sa->v2.use_hash_and_url = IP_TRUE;
IPCOM_LOG0(DEBUG2, "ipike_payload_notify_process_http_cert_lookup_supported: Hash and URL enabled");
}
return IPIKE_SUCCESS;;
}
#ifdef IPIKE_USE_ROHC
/*
*===========================================================================
* ipike_payload_notify_process_rohc
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_payload_notify_process_rohc(
Ipike2_notify_payload* payload,
Ipike_isakmp_exchange* ie)
{
Ip_ssize_t data_len = 0;
Ipike_attribute * attr;
Ipike_rohc * rohc;
/* Only applicable when negotiation IPsec SAs */
if ( ie->ipsec_sa == NULL )
return IPIKE_SUCCESS;
if ( ie->ipsec_sa->v2.rohc == NULL )
{
ie->ipsec_sa->v2.rohc = ipcom_malloc(sizeof(Ipike_rohc));
if ( ie->ipsec_sa->v2.rohc == NULL )
return IPIKE_OUT_OF_MEMORY;
ipcom_memset(ie->ipsec_sa->v2.rohc, 0, sizeof(Ipike_rohc));
}
rohc = ie->ipsec_sa->v2.rohc;
attr = (Ipike_attribute * ) Ipike_payload_notify_data(payload);
data_len = Ipike_payload_notify_data_length(payload);
while ( attr != IP_NULL)
{
switch ( IPIKE_ATTR_TYPE(ip_ntohs(attr->type)) )
{
case IPIKE_ATTR_ROHC_MAX_CID:
rohc->remote.max_cid = ip_ntohs(attr->value);
break;
case IPIKE_ATTR_ROHC_PROFILE:
if ( rohc->remote.num_profiles < IPIKE_CONFIG_ROHC_PROFILE_NUM_MAX - 1 )
rohc->remote.profiles[rohc->remote.num_profiles++] = ip_ntohs(attr->value);
break;
case IPIKE_ATTR_ROHC_INTEG:
if ( rohc->remote.num_integ_algs < IPIKE_CONFIG_ROHC_INTEG_NUM_MAX - 1 )
rohc->remote.integ_algs[rohc->remote.num_integ_algs++] = ip_ntohs(attr->value);
break;
case IPIKE_ATTR_ROHC_ICV_LEN:
rohc->remote.icv_len = ip_ntohs(attr->value);
break;
case IPIKE_ATTR_ROHC_MRRU:
rohc->remote.mrru = ip_ntohs(attr->value);
break;
default:
IPCOM_LOG1(WARNING, "ipike_payload_notify_process_rohc() ::"\
" received unknown ROHC attributes %d",
ip_ntohs(attr->type));
break;
}
attr = ipike_next_attribute(attr, &data_len);
}
/* We have received a proposed ROHC suite */
IPCOM_LOG0(DEBUG, "ipike_payload_notify_process_rohc() ::"\
" received ROHC parameters");
#ifdef IP_DEBUG
{
Ip_u32 i = 0;
IPCOM_LOG1(DEBUG2, " MAX_CID %u", rohc->remote.max_cid);
IPCOM_LOG1(DEBUG2, " MRRU %u", rohc->remote.mrru);
IPCOM_LOG1(DEBUG2, " ICV_LEN %u", rohc->remote.icv_len);
for ( i = 0; i < rohc->remote.num_profiles; i++ )
IPCOM_LOG1(DEBUG2, " PROFILE %u", rohc->remote.profiles[i]);
for ( i = 0; i < rohc->remote.num_integ_algs; i++ )
IPCOM_LOG1(DEBUG2, " INTEG %u", rohc->remote.integ_algs[i]);
}
#endif
return IPIKE_SUCCESS;
}
#endif /* IPIKE_USE_ROHC */
/*
*===========================================================================
* ipike_payload_notify_process_info
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_payload_notify_process_info(
Ipike_isakmp_exchange* ie,
Ipike2_notify_payload* payload,
Ip_u16 type)
{
Ipike_error err = IPIKE_SUCCESS;
/* Handle some notify messages */
switch (type)
{
case IPIKE_NOTI_INF_USE_TRANSPORT_MODE:
ie->ike_sa->v2.transport_notify = IP_TRUE;
break;
case IPIKE_NOTI_INF_REKEY_SA:
/*!!LOBREKEY
* Only rekey of IPSEC SA supported, so fail if IKE SA.
* IKE spi is 8 bytes and IPSEC spi is 4 bytes
*/
if (payload->spi_size != 4)
err = IPIKE_NOTI_ERR_NO_ADDITIONAL_SAS;
else
err = ipike_payload_notify_process_rekey(ie, payload);
break;
case IPIKE_NOTI_INF_NAT_DETECTION_DESTINATION_IP:
err = ipike_payload_notify_process_nat_detection(ie, payload, IP_FALSE);
break;
case IPIKE_NOTI_INF_NAT_DETECTION_SOURCE_IP:
err = ipike_payload_notify_process_nat_detection(ie, payload, IP_TRUE);
break;
case IPIKE_NOTI_INF_COOKIE:
err = ipike_payload_notify_process_cookie(ie, payload);
break;
case IPIKE_NOTI_INF_INITIAL_CONTACT:
err = ipike_payload_notify_process_initial_contact(ie);
break;
case IPIKE_NOTI_INF_MOBIKE_SUPPORTED:
err = ipike_payload_notify_process_mobike_supported(ie);
break;
case IPIKE_NOTI_INF_ADDITIONAL_IP4_ADDRESS:
err = ipike_payload_notify_process_additional_address(IP_TRUE, ie, payload);
break;
case IPIKE_NOTI_INF_ADDITIONAL_IP6_ADDRESS:
err = ipike_payload_notify_process_additional_address(IP_FALSE, ie, payload);
break;
case IPIKE_NOTI_INF_NO_ADDITIONAL_ADDRESSES:
err = ipike_payload_notify_process_no_additional_addresses(ie);
break;
case IPIKE_NOTI_INF_UPDATE_SA_ADDRESSES:
err = ipike_payload_notify_process_update_sa_addresses(ie);
break;
case IPIKE_NOTI_INF_COOKIE2:
err = ipike_payload_notify_process_cookie2(ie, payload);
break;
case IPIKE_NOTI_INF_NO_NATS_ALLOWED:
err = ipike_payload_notify_process_no_nats_allowed(ie, payload);
break;
case IPIKE_NOTI_INF_ESP_TFC_PADDING_NOT_SUPPORTED:
if (ie->ipsec_sa)
ie->ipsec_sa->v2.use_tfc = IP_FALSE;
break;
case IPIKE_NOTI_INF_HTTP_CERT_LOOKUP_SUPPORTED:
err = ipike_payload_notify_process_http_cert_lookup_supported(ie);
break;
#ifdef IPIKE_USE_ROHC
case IPIKE_NOTI_INF_ROHC_SUPPORTED:
err = ipike_payload_notify_process_rohc(payload, ie);
break;
#endif
default:
break;
}
return err;
}
/*
*===========================================================================
* ipike_payload_notify_error_to_message_type
*===========================================================================
*/
IP_STATIC Ip_bool
ipike_payload_notify_error_require_spi(
Ipike_error err)
{
/* Add error codes that requires the SPI to be added in the
* notify payload */
switch (err)
{
case IPIKE_ISAKMP_INVALID_IKE_SPI:
return IP_TRUE;
default:
return IP_FALSE;
}
return IP_FALSE;
}
/*
****************************************************************************
* 10 PUBLIC FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipike_payload_notify_error_to_message_type
*===========================================================================
*/
IP_PUBLIC Ipike_error
ipike_payload_notify_error_to_message_type(
Ipike_error err,
Ip_u16* message_type)
{
switch (err)
{
case IPIKE_ISAKMP_UNSUPPORTED_CRITICAL_PAYLOAD:
*message_type = IPIKE_NOTI_ERR_UNSUPPORTED_CRITICAL_PAYLOAD;
break;
case IPIKE_ISAKMP_INVALID_IKE_SPI:
*message_type = IPIKE_NOTI_ERR_INVALID_IKE_SPI;
break;
case IPIKE_ISAKMP_INVALID_MAJOR_VERSION:
*message_type = IPIKE_NOTI_ERR_INVALID_MAJOR_VERSION;
break;
case IPIKE_ISAKMP_INVALID_SYNTAX:
*message_type = IPIKE_NOTI_ERR_INVALID_SYNTAX;
break;
case IPIKE_ISAKMP_INVALID_MESSAGE_ID:
*message_type = IPIKE_NOTI_ERR_INVALID_MESSAGE_ID;
break;
case IPIKE_ISAKMP_INVALID_SPI:
*message_type = IPIKE_NOTI_ERR_INVALID_SPI;
break;
case IPIKE_ISAKMP_NO_PROPOSAL_CHOSEN:
*message_type = IPIKE_NOTI_ERR_NO_PROPOSAL_CHOSEN;
break;
case IPIKE_ISAKMP_KE_PAYLOAD:
*message_type = IPIKE_NOTI_ERR_KE_PAYLOAD;
break;
case IPIKE_ISAKMP_INVALID_ID_TYPE:
*message_type = IPIKE_NOTI_ERR_INVALID_ID_INFORMATION;
break;
case IPIKE_ISAKMP_AUTHENTICATION_FAILED:
/* Returned from ipike_policy_accept_id */
case IPIKE_AUTHENTICATION_FAILED:
*message_type = IPIKE_NOTI_ERR_AUTHENTICATION_FAILED;
break;
case IPIKE_ISAKMP_SINGLE_PAIR_REQUIRED:
*message_type = IPIKE_NOTI_ERR_SINGLE_PAIR_REQUIRED;
break;
case IPIKE_ISAKMP_NO_ADDITIONAL_SAS:
*message_type = IPIKE_NOTI_ERR_NO_ADDITIONAL_SAS;
break;
case IPIKE_ISAKMP_INTERNAL_ADDRESS_FAILURE:
*message_type = IPIKE_NOTI_ERR_INTERNAL_ADDRESS_FAILURE;
break;
case IPIKE_ISAKMP_FAILED_CP_REQUIRED:
*message_type = IPIKE_NOTI_ERR_FAILED_CP_REQUIRED;
break;
case IPIKE_ISAKMP_TS_UNACCEPTABLE:
*message_type = IPIKE_NOTI_ERR_TS_UNACCEPTABLE;
break;
case IPIKE_ISAKMP_INVALID_SELECTORS:
*message_type = IPIKE_NOTI_ERR_INVALID_SELECTORS;
break;
case IPIKE_NONCE_INVALID_SIZE:
*message_type = IPIKE_NOTI_ERR_INVALID_SYNTAX;
break;
case IPIKE_UNACCEPTABLE_ADDRESSES:
*message_type = IPIKE_NOTI_ERR_UNACCEPTABLE_ADDRESSES;
break;
case IPIKE_UNEXPECTED_NAT_DETECTED:
*message_type = IPIKE_NOTI_ERR_UNEXPECTED_NAT_DETECTED;
break;
case IPIKE_SA_NOT_FOUND:
*message_type = IPIKE_NOTI_ERR_NO_PROPOSAL_CHOSEN;
break;
default:
/* Can not inform the other party about the error condition */
return IPIKE_INTERNAL_ERROR;
}
return IPIKE_SUCCESS;
}
/*
*===========================================================================
* ipike_payload_notify_add_error_reply
*===========================================================================
*/
IP_PUBLIC Ipike_error
ipike_payload_notify_add_error_reply(
Ipike_isakmp_exchange *ie,
Ipike_payload_header*** reply_payloads)
{
Ipike_sadb_entry* sa;
Ipike2_notify_payload* notify;
Ip_size_t size;
Ipike_error err;
Ip_u8 spi_size = 0;
Ip_u8* spi_data = IP_NULL;
/* Only responses may send errors. The exchange should be ended in case requests fail */
if ( !(ie->isakmp_flags & IPIKE_ISAKMP_RESPONSE) )
return IPIKE_EXCH_FINNISHED;
/* Create notify payload */
if ( ie->exchange_type == IPIKE2_ISAKMP_EXCH_INFORMATIONAL ||
ie->exchange_type == IPIKE2_ISAKMP_EXCH_IKE_SA_INIT ||
ie->exchange_type == IPIKE2_ISAKMP_EXCH_IKE_AUTH)
{
sa = ie->ike_sa;
/* Only handle IPsec SA errors if we don't have IKE SA errors */
if ( sa->error == IPIKE_SUCCESS && ie->ipsec_sa != IP_NULL &&
ie->ipsec_sa-> error != IPIKE_SUCCESS)
sa = ie->ipsec_sa;
}
else
{
if (ie->ike_sa_new != IP_NULL)
sa = ie->ike_sa_new;
else
sa = ie->ipsec_sa;
ip_assert(sa != IP_NULL);
if ( ipike_payload_notify_error_require_spi(sa->error) )
{
if (sa->is_initiator)
{
spi_size = (Ip_u8)sa->v2.spi_i.len;
spi_data = sa->v2.spi_i.value;
}
else
{
spi_size = (Ip_u8)sa->v2.spi_r.len;
spi_data = sa->v2.spi_r.value;
}
}
}
size = sizeof(*notify) + spi_size + sa->notify_data.len;
notify = (Ipike2_notify_payload*)ipcom_calloc(1, size);
if (IP_NULL == notify)
{
IP_PANIC();
return IPIKE_OUT_OF_MEMORY;
}
notify->header.next_payload = IPIKE2_PAYLOAD_NOTIFY;
notify->header.length = ip_htons((Ip_u16)size);
if (ie->exchange_type == IPIKE2_ISAKMP_EXCH_IKE_SA_INIT ||
ie->exchange_type == IPIKE2_ISAKMP_EXCH_IKE_AUTH)
/*Fix vxw6-80697. RFC 4306, protocol id must be sent as zero,
*for notifications that do not relate to an existing SA*/
notify->protocol_id = 0; /*IPIKE_PROTO_ISAKMP;*/
else
notify->protocol_id = sa->v2.sa.proto_id;
err = ipike_payload_notify_error_to_message_type(sa->error, &notify->message_type);
if (err != IPIKE_SUCCESS)
{
ipcom_free(notify);
IPCOM_LOG0(DEBUG, "ipike_payload_notify_add_error_reply() :: unknown error message");
}
else
{
notify->message_type = ip_htons(notify->message_type);
notify->spi_size = spi_size;
ipcom_memcpy(Ipike_payload_notify_spi(notify), spi_data, spi_size);
ipcom_memcpy(Ipike_payload_notify_data(notify), sa->notify_data.value, sa->notify_data.len);
/* Add notify to payload list */
err = ipike_array_add((void***) reply_payloads, notify);
if (err != IPIKE_SUCCESS)
ipcom_free(notify);
}
return err;
}
/*
*===========================================================================
* Ipike_payload_notify_create
*===========================================================================
*/
IP_GLOBAL Ipike_error
ipike_payload_notify_create(
Ip_u8 protocol_id,
Ip_u16 message_type,
Ipike_value* spi,
Ipike_value* data,
Ipike2_notify_payload** payload)
{
Ip_u16 length;
Ipike2_notify_payload* notify;
length = IPIKE_NOTIFY_HEADER_LENGTH;
if (IP_NULL != spi)
length = (Ip_u16)(length + spi->len);
if (IP_NULL != data)
length = (Ip_u16)(length + data->len);
if (IP_NULL == (notify = ipcom_calloc(1, length)))
{
IP_PANIC();
return IPIKE_OUT_OF_MEMORY;
}
notify->header.length = ip_htons(length);
notify->header.next_payload = IPIKE2_PAYLOAD_NOTIFY;
notify->protocol_id = protocol_id;
notify->message_type = ip_ntohs(message_type);
if (IP_NULL != spi)
{
notify->spi_size = (Ip_u8)spi->len;
ipcom_memcpy(Ipike_payload_notify_spi(notify), spi->value, spi->len);
}
if (IP_NULL != data)
{
ipcom_memcpy(Ipike_payload_notify_data(notify), data->value, data->len);
}
*payload = notify;
return IPIKE_SUCCESS;
}
/*
*===========================================================================
* Ipike_payload_notify_check
*===========================================================================
*/
IP_GLOBAL Ipike_error
ipike_payload_notify_check(Ipike2_notify_payload* notify)
{
if (ip_ntohs(notify->header.length) < IPIKE_NOTIFY_HEADER_LENGTH + notify->spi_size)
{
IPCOM_LOG3(ERR,
"Ipike_payload_notify_check: The indicated length of the notify payload (%d) is less than the header (%d) + spi size (%d)",
ip_ntohs(notify->header.length),
IPIKE_NOTIFY_HEADER_LENGTH,
notify->spi_size);
return IPIKE_ISAKMP_INVALID_SYNTAX;
}
return IPIKE_SUCCESS;
}
/*
*===========================================================================
* ipike_payload_notify_process
*===========================================================================
*/
IP_GLOBAL Ipike_error
ipike_payload_notify_process(Ipike_isakmp_exchange *ie, Ipike2_notify_payload *payload)
{
Ip_u16 type;
type = ip_htons(payload->message_type);
if (type >= 1 && type <= IPIKE_NOTI_ERR_PRIVATE_USE_HIGH)
return ipike_payload_notify_process_error(ie, payload, type);
else
return ipike_payload_notify_process_info(ie, payload, type);
}
/*
*===========================================================================
* Ipike_payload_notify_print
*===========================================================================
*/
IP_GLOBAL void
Ipike_payload_notify_print(Ipike2_notify_payload* notify)
{
const char* type = IP_NULL;
/* lint */
(void)type;
type = ipike_payload_message_type_to_string(ip_ntohs(notify->message_type));
IPCOM_LOG2(DEBUG2, " message type: %s (%d)",
type,
ip_ntohs(notify->message_type));
if (notify->protocol_id != 0)
{
IPCOM_LOG1(DEBUG2, " protocol id: %s",
ipike_proposal_proto_id_to_string(notify->protocol_id));
}
if (notify->spi_size != 0)
{
(void)ipike_print_memory(IPCOM_LOG_DEBUG2, " spi: ",
Ipike_payload_notify_spi(notify),
notify->spi_size);
}
if (Ipike_payload_notify_data_length(notify) > 0)
{
if (Ipike_payload_notify_data_length(notify) > 16)
{
(void)ipike_print_memory(IPCOM_LOG_DEBUG2, " data:\n",
Ipike_payload_notify_data(notify),
Ipike_payload_notify_data_length(notify));
}
else
{
(void)ipike_print_memory(IPCOM_LOG_DEBUG2, " data: ",
Ipike_payload_notify_data(notify),
Ipike_payload_notify_data_length(notify));
}
}
return;
}
/*
*===========================================================================
* ipike_payload_notify_transport_mode
*===========================================================================
*/
IP_GLOBAL Ipike_error
ipike_payload_notify_transport_mode(Ipike2_notify_payload** payload)
{
Ipike_error err;
if (IPIKE_SUCCESS != (err = ipike_payload_notify_create(
IPIKE_PROTO_ISAKMP,
IPIKE_NOTI_INF_USE_TRANSPORT_MODE,
IP_NULL,
IP_NULL,
payload)))
{
IPCOM_LOG0(DEBUG, "ipike_payload_notify_transport_mode: failed to create");
}
return err;
}
/*
*===========================================================================
* ipike_payload_notify_dont_use_tfc
*===========================================================================
*/
IP_GLOBAL Ipike_error
ipike_payload_notify_dont_use_tfc(Ipike2_notify_payload** payload)
{
Ipike_error err;
if (IPIKE_SUCCESS != (err = ipike_payload_notify_create(
IPIKE_PROTO_ISAKMP,
IPIKE_NOTI_INF_ESP_TFC_PADDING_NOT_SUPPORTED ,
IP_NULL,
IP_NULL,
payload)))
{
IPCOM_LOG0(DEBUG, "ipike_payload_notify_dont_use_tfc: failed to create");
}
return err;
}
/*
*===========================================================================
* ipike_payload_notify_rekey_sa
*===========================================================================
*/
IP_GLOBAL Ipike_error
ipike_payload_notify_rekey_sa(
Ip_u16 proto_id,
Ipike_value *spi,
Ipike2_notify_payload **payload)
{
Ipike_error err;
err = ipike_payload_notify_create((Ip_u8)proto_id, IPIKE_NOTI_INF_REKEY_SA,spi, IP_NULL, payload);
if (err != IPIKE_SUCCESS)
{
IPCOM_LOG0(DEBUG, "ipike_payload_notify_rekey_sa: failed to create");
}
return err;
}
/*
*===========================================================================
* ipike_payload_notify_nat_detection
*===========================================================================
*/
IP_GLOBAL Ipike_error
ipike_payload_notify_nat_detection(
Ipike_isakmp_exchange* ie,
Ip_bool source,
Ipike2_notify_payload** payload)
{
Ipike_error err;
Ipike_value data;
Ip_u16 type;
union Ip_sockaddr_union* address;
data.value = IP_NULL;
if ( source )
{
if (ie->msg.local_addr.sa.sa_family != 0)
address = &ie->msg.local_addr;
else
address = &ie->ike_sa->local_addr;
}
else
{
if (ie->msg.peer_addr.sa.sa_family != 0)
address = &ie->msg.peer_addr;
else
address = &ie->ike_sa->peer_addr;
}
err = ipike_payload_notify_generate_nat_detection_data(ie->ike_sa->initiator_cookie,
ie->ike_sa->responder_cookie,
address,
&data);
if ( IPIKE_SUCCESS == err )
{
if ( source )
type = IPIKE_NOTI_INF_NAT_DETECTION_SOURCE_IP;
else
type = IPIKE_NOTI_INF_NAT_DETECTION_DESTINATION_IP;
err = ipike_payload_notify_create(IPIKE_PROTO_ISAKMP, type, IP_NULL, &data, payload);
if ( IPIKE_SUCCESS != err )
IPCOM_LOG0(DEBUG, "ipike_payload_notify_nat_detection() :: failed to create");
}
if (IP_NULL != data.value)
ipcom_free(data.value);
return err;
}
/*
*===========================================================================
* ipike_payload_notify_cookie
*===========================================================================
*/
IP_GLOBAL Ipike_error
ipike_payload_notify_cookie(
Ipike_isakmp_exchange* ie,
Ipike_value* cookie,
Ipike2_notify_payload** payload)
{
Ipike_error err = IPIKE_SUCCESS;
if (IP_NULL == cookie->value)
{
/* This will be called by responder to get the cookie value to send to
* initiator. We will use the exchange responder cookie as the cookie
* value, since we need to set the responder cookie value to zero and
* still remember that value since we should restore it later (the value
* is used to get unique ike sa). */
cookie->len = sizeof(ie->ike_sa->responder_cookie);
cookie->value = ipcom_malloc(cookie->len);
if (IP_NULL == cookie->value)
{
IP_PANIC();
err = IPIKE_OUT_OF_MEMORY;
}
else
{
ipcom_memcpy(cookie->value, ie->ike_sa->responder_cookie, cookie->len);
}
}
if ((IPIKE_SUCCESS == err) &&
(IPIKE_SUCCESS != (err = ipike_payload_notify_create(
IPIKE_PROTO_ISAKMP,
IPIKE_NOTI_INF_COOKIE,
IP_NULL,
cookie,
payload))))
{
IPCOM_LOG0(DEBUG, "ipike_payload_notify_cookie: failed to create");
}
return err;
}
/*
*===========================================================================
* ipike_payload_notify_initial_contact
*===========================================================================
*/
IP_GLOBAL Ipike_error
ipike_payload_notify_initial_contact(
Ipike2_notify_payload** payload)
{
Ipike_error err;
if (IPIKE_SUCCESS != (err = ipike_payload_notify_create(
IPIKE_PROTO_ISAKMP,
IPIKE_NOTI_INF_INITIAL_CONTACT,
IP_NULL,
IP_NULL,
payload)))
{
IPCOM_LOG0(DEBUG, "ipike_payload_notify_initial_contact: failed to create");
}
return err;
}
/*
*===========================================================================
* ipike_payload_notify_mobike_supported
*===========================================================================
*/
IP_GLOBAL Ipike_error
ipike_payload_notify_mobike_supported(
Ipike2_notify_payload** payload)
{
Ipike_error err;
if (IPIKE_SUCCESS != (err = ipike_payload_notify_create(
IPIKE_PROTO_ISAKMP,
IPIKE_NOTI_INF_MOBIKE_SUPPORTED,
IP_NULL,
IP_NULL,
payload)))
{
IPCOM_LOG0(DEBUG, "ipike_payload_notify_mobike_supported: failed to create");
}
return err;
}
/*
*===========================================================================
* ipike_payload_notify_additional_ip_address
*===========================================================================
*/
IP_GLOBAL Ipike_error
ipike_payload_notify_additional_ip_address(
union Ip_sockaddr_union* addr,
Ipike2_notify_payload** payload)
{
Ipike_error err = IPIKE_SUCCESS;
Ipike_value data = {0};
Ip_u16 type = 0;
#ifdef IPCOM_USE_INET
if (addr->sin.sin_family == IP_AF_INET)
type = IPIKE_NOTI_INF_ADDITIONAL_IP4_ADDRESS;
#endif
#ifdef IPCOM_USE_INET6
if (addr->sin.sin_family == IP_AF_INET6)
type = IPIKE_NOTI_INF_ADDITIONAL_IP6_ADDRESS;
#endif
if (type == 0)
err = IPIKE_INTERNAL_ERROR;
if (IPIKE_SUCCESS == err)
{
data.len = ipike_addr_get_len(addr);
data.value = ipike_addr_get_ptr(addr);
if (IPIKE_SUCCESS != (err = ipike_payload_notify_create(
IPIKE_PROTO_ISAKMP,
type,
IP_NULL,
&data,
payload)))
{
IPCOM_LOG0(DEBUG, "ipike_payload_notify_additional_ip_address: failed to create");
}
}
return err;
}
/*
*===========================================================================
* ipike_payload_notify_no_additional_addresses
*===========================================================================
*/
IP_GLOBAL Ipike_error
ipike_payload_notify_no_additional_addresses(
Ipike2_notify_payload** payload)
{
Ipike_error err;
if (IPIKE_SUCCESS != (err = ipike_payload_notify_create(
IPIKE_PROTO_ISAKMP,
IPIKE_NOTI_INF_NO_ADDITIONAL_ADDRESSES,
IP_NULL,
IP_NULL,
payload)))
{
IPCOM_LOG0(DEBUG, "ipike_payload_notify_no_additional_addresses: failed to create");
}
return err;
}
/*
*===========================================================================
* ipike_payload_notify_update_sa_addresses
*===========================================================================
*/
IP_GLOBAL Ipike_error
ipike_payload_notify_update_sa_addresses(
Ipike2_notify_payload** payload)
{
Ipike_error err;
if (IPIKE_SUCCESS != (err = ipike_payload_notify_create(
IPIKE_PROTO_ISAKMP,
IPIKE_NOTI_INF_UPDATE_SA_ADDRESSES,
IP_NULL,
IP_NULL,
payload)))
{
IPCOM_LOG0(DEBUG, "ipike_payload_notify_update_sa_addresses: failed to create");
}
return err;
}
/*
*===========================================================================
* ipike_payload_notify_cookie2
*===========================================================================
*/
IP_GLOBAL Ipike_error
ipike_payload_notify_cookie2(
Ipike_value* cookie2,
Ipike2_notify_payload** payload)
{
Ipike_error err = IPIKE_SUCCESS;
/* Generate cookie2 if not set */
if (cookie2->value == IP_NULL)
{
cookie2->len = (Ip_size_t)ipcom_sysvar_get_as_int("ipike.nonce_size", 64);
if (cookie2->len > 64)
cookie2->len = 64;
if (cookie2->len < 8)
cookie2->len = 8;
if ((cookie2->value = ipcom_malloc(cookie2->len)) == IP_NULL)
{
IP_PANIC();
err = IPIKE_OUT_OF_MEMORY;
}
else if (RAND_bytes(cookie2->value, (int)cookie2->len) == 0)
{
err = IPIKE_INVALID_VALUE;
}
}
/* Create payload */
if (IPIKE_SUCCESS == err)
{
if (IPIKE_SUCCESS != (err = ipike_payload_notify_create(
IPIKE_PROTO_ISAKMP,
IPIKE_NOTI_INF_COOKIE2,
IP_NULL,
cookie2,
payload)))
{
IPCOM_LOG0(DEBUG, "ipike_payload_notify_cookie2: failed to create");
}
}
return err;
}
/*
*===========================================================================
* ipike_payload_notify_no_nats_allowed
*===========================================================================
*/
IP_GLOBAL Ipike_error
ipike_payload_notify_no_nats_allowed(
union Ip_sockaddr_union* src_addr,
union Ip_sockaddr_union* dst_addr,
Ipike2_notify_payload** payload)
{
Ipike_error err = IPIKE_SUCCESS;
Ipike_value data = {0};
Ip_u16 port = 0;
data.value = ipcom_malloc(sizeof(*src_addr) + sizeof(*dst_addr));
if (data.value == IP_NULL)
{
IP_PANIC();
err = IPIKE_OUT_OF_MEMORY;
}
else
{
data.len = 0;
ipcom_memcpy(data.value + data.len, ipike_addr_get_ptr(src_addr), ipike_addr_get_len(src_addr));
data.len += ipike_addr_get_len(src_addr);
ipcom_memcpy(data.value + data.len, ipike_addr_get_ptr(dst_addr), ipike_addr_get_len(dst_addr));
data.len += ipike_addr_get_len(dst_addr);
port = ipike_addr_get_port(src_addr);
port = ip_htons(port);
ipcom_memcpy(data.value + data.len, &port, sizeof(port));
data.len += sizeof(port);
port = ipike_addr_get_port(dst_addr);
port = ip_htons(port);
ipcom_memcpy(data.value + data.len, &port, sizeof(port));
data.len += sizeof(port);
if (IPIKE_SUCCESS != (err = ipike_payload_notify_create(
IPIKE_PROTO_ISAKMP,
IPIKE_NOTI_INF_NO_NATS_ALLOWED,
IP_NULL,
&data,
payload)))
{
IPCOM_LOG0(DEBUG, "ipike_payload_notify_no_nats_allowed: failed to create");
}
ipcom_free(data.value);
}
return err;
}
/*
*===========================================================================
* ipike_payload_notify_http_cert_lookup_support
*===========================================================================
*/
IP_GLOBAL Ipike_error
ipike_payload_notify_http_cert_lookup_support(
Ipike2_notify_payload** payload)
{
Ipike_error err;
err = ipike_payload_notify_create(IPIKE_PROTO_ISAKMP,
IPIKE_NOTI_INF_HTTP_CERT_LOOKUP_SUPPORTED,
IP_NULL,
IP_NULL,
payload);
if (err != IPIKE_SUCCESS)
{
IPCOM_LOG0(DEBUG, "ipike_payload_notify_http_cert_lookup_support() ::"\
" failed to create");
}
return err;
}
#ifdef IPIKE_USE_ROHC
/*
*===========================================================================
* ipike_payload_notify_http_cert_lookup_support
*===========================================================================
*/
IP_GLOBAL Ipike_error
ipike_payload_notify_rohc(
Ipike2_notify_payload** payload,
Ipike_isakmp_exchange* ie)
{
Ipike_attribute attr_list[IPIKE_ATTR_ROHC_NUM_MAX];
Ipike_attribute * attr;
Ipike_attribute * attr_end;
Ipike_value data;
Ipike_error err;
Ipike_rohc * rohc;
Ip_u32 i;
/* Only applicable when negotiation IPsec SAs */
if ( ie->ipsec_sa == NULL || ie->ipsec_sa->v2.rohc == IP_NULL )
return IPIKE_SUCCESS;
rohc = ie->ipsec_sa->v2.rohc;
attr = &attr_list[0];
attr_end = &attr_list[IPIKE_ATTR_ROHC_NUM_MAX];
ip_assert(IPIKE_ATTR_ROHC_NUM_MAX > 5);
/* Exactly one MAX_CID attribute MUST be sent */
attr->type = ip_htons(IPIKE_ATTR_ROHC_MAX_CID | IPIKE_ATTR_BASIC);
attr->value = ip_htons(rohc->local.max_cid);
attr++;
/* There MUST be at least one ROHC_INTEG attribute contained within the
* ROHC_SUPPORTED Notify message */
for ( i = 0; i < rohc->local.num_integ_algs; i++ )
{
attr->type = ip_htons(IPIKE_ATTR_ROHC_INTEG | IPIKE_ATTR_BASIC);
attr->value = ip_htons(rohc->local.integ_algs[i]);
attr++;
}
/* There MAY be zero or one ROHC_ICV_LEN attribute contained within the
* ROHC_SUPPORTED Notify message */
attr->type = ip_htons(IPIKE_ATTR_ROHC_ICV_LEN | IPIKE_ATTR_BASIC);
attr->value = ip_htons(rohc->local.icv_len);
attr++;
/* There MAY be zero or one MRRU attribute contained within the
* ROHC_SUPPORTED Notify message */
attr->type = ip_htons(IPIKE_ATTR_ROHC_MRRU | IPIKE_ATTR_BASIC);
attr->value = ip_htons(rohc->local.mrru);
attr++;
/* There MUST be at least one ROHC_PROFILE attribute included in the
* ROHC_SUPPORTED Notify message */
for ( i = 0; i < rohc->local.num_profiles; i++ )
{
attr->type = ip_htons(IPIKE_ATTR_ROHC_PROFILE | IPIKE_ATTR_BASIC);
attr->value = ip_htons(rohc->local.profiles[i]);
attr++;
if ( attr >= attr_end )
break;
}
if ( attr == &attr_list[IPIKE_ATTR_ROHC_NUM_MAX] )
{
/* Increase IPIKE_ATTR_ROHC_NUM_MAX if this happens */
IPCOM_LOG0(WARNING, "ipike_payload_notify_rohc() :: All profiles may"\
" not have been added");
}
data.value = (Ip_u8 *) attr_list;
data.len = (Ip_size_t)(attr - attr_list) * sizeof(Ipike_attribute);
err = ipike_payload_notify_create(IPIKE_PROTO_ISAKMP,
IPIKE_NOTI_INF_ROHC_SUPPORTED,
IP_NULL,
&data,
payload);
if (err != IPIKE_SUCCESS)
{
IPCOM_LOG0(ERR, "ipike_payload_notify_rohc() :: failed to create");
return err;
}
return err;
}
#endif /* IPIKE_USE_ROHC */
#else
int ipike_payload_notify_empty_file = 0;
#endif /* IPIKE_USE_VERSION2 */
/*
****************************************************************************
* END OF FILE
****************************************************************************
*/