1924 lines
63 KiB
C
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, ¬ify->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
|
|
****************************************************************************
|
|
*/
|