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

1843 lines
65 KiB
C

/*
******************************************************************************
* SOURCE FILE
*
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipike_pfkeyv2_linux.c,v $ $Revision: 1.18 $
* $Source: /home/interpeak/CVSRoot/ipike/src/ipike_pfkeyv2_linux.c,v $
* $Author: edahlber $ $Date: 2010-04-23 15:31:41 $
* $State: Exp $ $Locker: $
*
* INTERPEAK_COPYRIGHT_STRING
* Design and implementation by Kenneth Jonsson <kenneth@interpeak.se>
******************************************************************************
*/
/* Native implementation used only if not Interpeak IPSec used */
#if (defined(IP_PORT_LINUX) || defined(IP_PORT_LAS)) && !defined(IPIPSEC2) && !defined(IPIPSEC)
/*
****************************************************************************
* 1 DESCRIPTION
****************************************************************************
*/
/*
****************************************************************************
* 2 CONFIGURATION
****************************************************************************
*/
#include "ipike_config.h"
/*
****************************************************************************
* 3 INCLUDE FILES
****************************************************************************
*/
#include "ipike_h.h"
#include "ipike_ipsec_attributes.h"
#include "ipike_ipsec_sadb.h"
#include "ipike_pfkeyv2.h"
#include <ipcom_os.h>
#include <ipcom_psock.h>
#include <errno.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/socket.h>
#define HAVE_PFKEY_POLICY_PRIORITY
#include <linux/pfkeyv2.h>
#include <linux/ipsec.h>
/*
****************************************************************************
* 4 EXTERN PROTOTYPES
****************************************************************************
*/
/*
****************************************************************************
* 5 DEFINES
****************************************************************************
*/
#define IPCOM_P_OLD_SOCK_ADDR_FIX
/* The fraction of bytes, compared to the hard expiration limit, that should
* be transfered before the soft expiration */
#define IPIKE_SOFT_TO_HARD_FRAC (0.9)
/* Buffer space allocated for send/receive of PF_KEY messages */
#define IPIKE_PFKEY_SOCKET_BUFFER_SIZE 1000
#ifndef UDP_ENCAP_ESPINUDP
#define UDP_ENCAP_ESPINUDP 2
#endif
#ifndef PRIORITY_DEFAULT
#define PRIORITY_DEFAULT 0x80000000
#endif
/*
****************************************************************************
* 6 TYPES
****************************************************************************
*/
struct sadb_address_full
{
struct sadb_address addr;
union Ip_sockaddr_union sock;
};
#ifdef IPCOM_P_OLD_SOCK_ADDR_FIX
struct Ip_sockaddr_in_old
{
Ip_u16 sin_family;
Ip_in_port_t sin_port; /* 16 bit TCP/UDP port in network endian */
struct Ip_in_addr sin_addr;
char sin_zero[8]; /* unused */
};
#endif
struct in6_addr
{
union
{
__u8 u6_addr8[16];
__u16 u6_addr16[8];
__u32 u6_addr32[4];
} in6_u;
#define s6_addr in6_u.u6_addr8
#define s6_addr16 in6_u.u6_addr16
#define s6_addr32 in6_u.u6_addr32
};
struct sockaddr_in6 {
unsigned short int sin6_family; /* AF_INET6 */
__u16 sin6_port; /* Transport layer port # */
__u32 sin6_flowinfo; /* IPv6 flow information */
struct in6_addr sin6_addr; /* IPv6 address */
__u32 sin6_scope_id; /* scope id (new in RFC2553) */
};
/*
****************************************************************************
* 7 LOCAL PROTOTYPES
****************************************************************************
*/
/*
*===========================================================================
* ipike_pfkey2_enc_from_transform
*===========================================================================
* Description: Gets the encoding algorithm from a transform.
* Parameters: proposal_proto_id - The proposal protocol ID.
* transform - The selected IPSec transform.
* enc - Will hold the encryption algorithm id if the call was
* successful.
* Returns: IPIKE_SUCCESS
* IPIKE_INVALID_VALUE
*/
IP_STATIC Ipike_error
ipike_pfkey2_enc_from_transform(
Ip_u8 proposal_proto_id,
Ipike_transform_ipsec* transform,
Ip_u8* enc);
/*
*===========================================================================
* ipike_pfkey2_auth_from_transform
*===========================================================================
* Description: Gets the authentication algorithm from a transform.
* Parameters: proposal_proto_id - The proposal protocol ID.
* transfor - The selected IPSec transform.
* auth - Will hold the authentication algorithm id if the call
* was successful.
* Returns: IPIKE_SUCCESS
* IPIKE_INVALID_VALUE
*/
IP_STATIC Ipike_error
ipike_pfkey2_auth_from_transform(
Ip_u8 proposal_proto_id,
Ipike_transform_ipsec* transform,
Ip_u8* auth);
/*
*===========================================================================
* ipike_pfkey2_satype_from_proto_id
*===========================================================================
* Description: Converts the proposal protcol ID to the corresponding PF_KEY
* SA type value.
* Parameters: proto_id - The proposal protocol ID.
* sa_type - will contain the SA type if the call was successful.
* Returns: IPIKE_SUCCESS
* IPIKE_INVALID_VALUE
*/
IP_STATIC Ipike_error
ipike_pfkey2_satype_from_proto_id(Ip_u8 proto_id, Ip_u8* sa_type);
/*
*===========================================================================
* ipike_pfkey2_write_socket
*===========================================================================
* Description: Writes the content of 'iov' to the pfkey socket.
* Parameters: sock - the pfkey socket
* iov - A array of pfkey data structures to send.
* count - The number of elements in the 'iov' array.
* len - The total length of the message.
* Returns: IPIKE_SUCCESS
* IPIKE_PFKEYV2_ERROR
* IPIKE_SA_NOT_FOUND
*/
IP_STATIC Ipike_error
ipike_pfkey2_write_socket(int sock, struct iovec* iov, int count, int len);
/*
*===========================================================================
* ipike_pfkey2_write
*===========================================================================
* Description: Writes the content of 'iov' to the IP stack.
* Parameters: iov - A array of pfkey data structures to send.
* count - The number of elements in the 'iov' array.
* len - The total length of the message.
* Returns: IPIKE_SUCCESS
* IPIKE_PFKEYV2_ERROR
* IPIKE_SA_NOT_FOUND
*/
IP_STATIC Ipike_error
ipike_pfkey2_write(struct iovec* iov, int count, int len);
/*
*===========================================================================
* ipike_pfkeyv2_process_sa_expire
*===========================================================================
* Description: Extracts enough infomation to identify which IPSec SA that
* did timeout and ínvoke the 'sa expire' callback.
* Parameters: sm - The pointer to the header of the message.
* Returns: A standard error code.
*/
IP_STATIC Ipike_error
ipike_pfkeyv2_process_sa_expire(struct sadb_msg* sm);
/*
*===========================================================================
* ipike_pfkeyv2_process_sa_acquire
*===========================================================================
* Description: IPSec require a generation of a new flow.
* Parameters: sm - The pointer to the header of the message.
* Returns: A standard error code.
*/
IP_STATIC Ipike_error
ipike_pfkeyv2_process_sa_acquire(struct sadb_msg* sm);
/*
*===========================================================================
* ipike_pfkeyv2_process_sa_remove
*===========================================================================
* Description: IPSec SA is deleted.
* Parameters: sm - The pointer to the header of the message.
* Returns: A standard error code.
*/
IP_STATIC Ipike_error
ipike_pfkeyv2_process_sa_remove(struct sadb_msg* sm);
/*
*===========================================================================
* ipike_pfkeyv2_register
*===========================================================================
* Description: Register for IPSec acquire SA messages.
* Parameters: sock - pfkey socket
* Returns:
*
*/
IP_STATIC Ipike_error
ipike_pfkeyv2_register(int sock);
/*
****************************************************************************
* 8 DATA
****************************************************************************
*/
IP_STATIC int ipike_pfkeyv2_soft_to_hard_time = 300;
/*
****************************************************************************
* 9 LOCAL FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipike_sockaddr2native
*===========================================================================
*/
IP_STATIC void
ipike_sockaddr2native(struct Ip_sockaddr* addr)
{
#ifdef IPCOM_P_OLD_SOCK_ADDR_FIX
if (addr != IP_NULL && addr->sa_family == IP_AF_INET)
((struct Ip_sockaddr_in_old *)addr)->sin_family = IP_AF_INET;
#ifdef IPCOM_USE_INET6
if (addr != IP_NULL && addr->sa_family == IP_AF_INET6)
((struct sockaddr_in6 *)addr)->sin6_family = IP_AF_INET6;
#endif
#endif
}
/*
*===========================================================================
* ipike_sockaddr2ipcom
*===========================================================================
*/
IP_STATIC void
ipike_sockaddr2ipcom(struct Ip_sockaddr* addr)
{
#ifdef IPCOM_P_OLD_SOCK_ADDR_FIX
if (addr != IP_NULL && ((struct Ip_sockaddr_in_old *)addr)->sin_family == IP_AF_INET)
{
((struct Ip_sockaddr_in *)addr)->sin_family = IP_AF_INET;
((struct Ip_sockaddr_in *)addr)->sin_len = sizeof(struct Ip_sockaddr_in);
}
#ifdef IPCOM_USE_INET6
if (addr != IP_NULL && ((struct sockaddr_in6 *)addr)->sin6_family == IP_AF_INET6)
{
((struct Ip_sockaddr_in6 *)addr)->sin6_family = IP_AF_INET6;
((struct Ip_sockaddr_in6 *)addr)->sin6_len = sizeof(struct Ip_sockaddr_in6);
}
#endif
#endif
}
/*
*===========================================================================
* ipike_pfkey2_enc_from_transform
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_pfkey2_enc_from_transform(
Ip_u8 proposal_proto_id,
Ipike_transform_ipsec* transform,
Ip_u8* enc)
{
if (proposal_proto_id != IPIKE_PROTO_IPSEC_ESP)
{
*enc = SADB_EALG_NONE;
return IPIKE_SUCCESS;
}
switch (transform->id)
{
case IPIKE_IPSEC_ESP_DES:
*enc = SADB_EALG_DESCBC;
break;
case IPIKE_IPSEC_ESP_3DES:
*enc = SADB_EALG_3DESCBC;
break;
case IPIKE_IPSEC_ESP_BLOWFISH:
*enc = SADB_X_EALG_BLOWFISHCBC;
break;
case IPIKE_IPSEC_ESP_CAST:
*enc = SADB_X_EALG_CASTCBC;
break;
case IPIKE_IPSEC_ESP_AESCBC:
*enc = SADB_X_EALG_AESCBC;
break;
case IPIKE_IPSEC_ESP_AESCTR:
*enc = SADB_X_EALG_AESCTR;
break;
case IPIKE_IPSEC_ESP_NULL:
*enc = SADB_EALG_NULL;
break;
default:
IPCOM_LOG1(ERR,
"ipike_pfkey2_enc_from_transform: can not translate transform id (%d) "
"to a corresponding PF_KEY encrypt algorithm",
transform->id);
return IPIKE_INVALID_VALUE;
}
return IPIKE_SUCCESS;
}
/*
*===========================================================================
* ipike_pfkey2_auth_from_transform
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_pfkey2_auth_from_transform(
Ip_u8 proposal_proto_id,
Ipike_transform_ipsec* transform,
Ip_u8* auth)
{
if (proposal_proto_id == IPIKE_PROTO_IPSEC_AH)
{
switch (transform->id)
{
case IPIKE_IPSEC_AH_MD5:
*auth = SADB_AALG_MD5HMAC;
break;
case IPIKE_IPSEC_AH_SHA:
*auth = SADB_AALG_SHA1HMAC;
break;
default:
IPCOM_LOG1(ERR,
"ipike_pfkey2_enc_from_transform: can not translate transform id (%d) "
"to a corresponding PF_KEY authentication algorithm",
transform->id);
return IPIKE_INVALID_VALUE;
}
}
if (proposal_proto_id == IPIKE_PROTO_IPSEC_ESP)
{
switch (transform->authentication_algorithm)
{
case 0:
*auth = SADB_AALG_NONE;
break;
case IPIKE_IPSEC_AUTHENTICATION_ALG_HMAC_MD5:
*auth = SADB_AALG_MD5HMAC;
break;
case IPIKE_IPSEC_AUTHENTICATION_ALG_HMAC_SHA1:
*auth = SADB_AALG_SHA1HMAC;
break;
default:
IPCOM_LOG1(ERR,
"ipike_pfkey2_enc_from_transform: invalid authentication algorithm (%d) ",
transform->authentication_algorithm);
return IPIKE_INVALID_VALUE;
}
}
return IPIKE_SUCCESS;
}
/*
*===========================================================================
* ipike_pfkey2_satype_from_proto_id
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_pfkey2_satype_from_proto_id(Ip_u8 proto_id, Ip_u8* sa_type)
{
switch (proto_id)
{
case 0:
*sa_type = 0;
break;
case IPIKE_PROTO_IPSEC_AH:
*sa_type = SADB_SATYPE_AH;
break;
case IPIKE_PROTO_IPSEC_ESP:
*sa_type = SADB_SATYPE_ESP;
break;
default:
IPCOM_LOG1(ERR,
"ipike_pfkey2_satype_from_proposal: unknown proposal protocol ID (%d)",
proto_id);
*sa_type = SADB_SATYPE_UNSPEC;
return IPIKE_INVALID_VALUE;
}
return IPIKE_SUCCESS;
}
/*
*===========================================================================
* ipike_pfkey2_proto_id_from_satype
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_pfkey2_proto_id_from_satype(Ip_u8 sa_type, Ip_u8* proto_id)
{
switch (sa_type)
{
case SADB_SATYPE_UNSPEC:
*proto_id = 0;
break;
case SADB_SATYPE_AH:
*proto_id = IPIKE_PROTO_IPSEC_AH;
break;
case SADB_SATYPE_ESP:
*proto_id = IPIKE_PROTO_IPSEC_ESP;
break;
default:
IPCOM_LOG1(ERR,
"ipike_pfkey2_proto_id_from_satype: unknown SA type (%d)",
sa_type);
return IPIKE_INVALID_VALUE;
}
return IPIKE_SUCCESS;
}
/*
*===========================================================================
* ipike_pfkey2_proto_from_proto_id
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_pfkey2_proto_from_proto_id(Ip_u8 proto_id, Ip_u8* sa_type)
{
switch (proto_id)
{
case 0:
*sa_type = 0;
break;
case IPIKE_PROTO_IPSEC_AH:
*sa_type = IP_IPPROTO_AH;
break;
case IPIKE_PROTO_IPSEC_ESP:
*sa_type = IP_IPPROTO_ESP;
break;
default:
IPCOM_LOG1(ERR, "ipike_pfkey2_proto_from_proto_id: unknown protocol ID (%d)", proto_id);
*sa_type = 0;
return IPIKE_INVALID_VALUE;
}
return IPIKE_SUCCESS;
}
/*
*===========================================================================
* ipike_pfkey2_get_extaddr_ptr
*===========================================================================
*/
IP_STATIC Ip_u8*
ipike_pfkey2_get_extaddr_ptr(struct sadb_address_full* extaddr)
{
return (Ip_u8*)(&extaddr->sock);
}
/*
*===========================================================================
* ipike_pfkey2_network_to_extaddr
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_pfkey2_network_to_extaddr(
struct sadb_address_full* extaddr,
Ip_u8 proto,
union Ip_sockaddr_union* ipaddr,
union Ip_sockaddr_union* ipmask,
Ip_u16 port)
{
Ip_u8 n;
Ip_u8* p;
(void)ipike_copy_address(&extaddr->sock, ipaddr);
if (ipmask != IP_NULL)
(void)ipike_apply_network_mask(&extaddr->sock, ipmask);
(void)ipike_set_port(&extaddr->sock, port);
ipike_sockaddr2native((struct Ip_sockaddr*)&extaddr->sock);
if (ipmask != IP_NULL)
{
n = ipike_get_addr_len(ipmask);
p = ipike_get_addr_ptr(ipmask);
while ((n > 0) && (p[n-1] == 0))
n--;
}
else
{
n = ipike_get_addr_len(ipaddr);
}
extaddr->addr.sadb_address_len = (Ip_u16)(sizeof(extaddr->addr) + ipaddr->sa.sa_len);
extaddr->addr.sadb_address_len = (Ip_u16)((extaddr->addr.sadb_address_len + 7) / 8);
if (proto == 0)
extaddr->addr.sadb_address_proto = 0xff;
else
extaddr->addr.sadb_address_proto = proto;
extaddr->addr.sadb_address_prefixlen = (Ip_u8)(8 * n);
extaddr->addr.sadb_address_reserved = 0;
return IPIKE_SUCCESS;
}
/*
*===========================================================================
* ipike_pfkey2_ipaddr_to_extaddr
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_pfkey2_ipaddr_to_extaddr(
struct sadb_address_full* extaddr,
Ip_u8 proto,
union Ip_sockaddr_union* ipaddr,
Ip_u16 port)
{
return ipike_pfkey2_network_to_extaddr(extaddr, proto, ipaddr, IP_NULL, port);
}
/*
*===========================================================================
* ipike_pfkey2_extaddr_to_ipaddr
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_pfkey2_extaddr_to_ipaddr(
union Ip_sockaddr_union* ipaddr,
Ip_u8* proto,
struct sadb_address_full* extaddr)
{
ipike_sockaddr2ipcom((struct Ip_sockaddr*)&extaddr->sock);
(void)ipike_copy_address(ipaddr, &extaddr->sock);
if (proto != IP_NULL)
*proto = extaddr->addr.sadb_address_proto;
return IPIKE_SUCCESS;
}
/*
*===========================================================================
* ipike_pfkey2_write_socket
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_pfkey2_write_socket(int sock, struct iovec* iov, int count, int len)
{
char buf[IPIKE_PFKEY_SOCKET_BUFFER_SIZE];
struct sadb_msg* sm = (struct sadb_msg*) iov[0].iov_base;
Ip_u8 msg_type = sm->sadb_msg_type;
Ip_u32 pid = sm->sadb_msg_pid;
Ipike_error err;
err = IPIKE_SUCCESS;
if (sock < 0)
{
IPCOM_LOG1(ERR, "ipike_pfkey2_write_socket: failed to create PF_KEY socket - %s",
ipcom_strerror(ipcom_errno));
return IPIKE_PFKEY_ERROR;
}
if (writev(sock, iov, count) != len)
{
IPCOM_LOG1(ERR, "ipike_pfkey2_write_socket: socket write failed - %s",
ipcom_strerror(ipcom_errno));
err = IPIKE_PFKEY_ERROR;
goto cleanup;
}
sm = (struct sadb_msg*) buf;
do {
if (ipcom_socketread(sock, buf, IPIKE_PFKEY_SOCKET_BUFFER_SIZE) <= 0)
{
IPCOM_LOG1(ERR, "ipike_pfkey2_write_socket: read %s", ipcom_strerror(ipcom_errno));
err = IPIKE_PFKEY_ERROR;
goto cleanup;
}
} while (((sm->sadb_msg_type != msg_type) && (sm->sadb_msg_type != 0)) ||
(sm->sadb_msg_pid != pid));
if (sm->sadb_msg_errno == IP_ERRNO_ESRCH)
{
IPCOM_LOG0(ERR, "ipike_pfkey2_write_socket: no sa");
(void)ipcom_errno_set(sm->sadb_msg_errno);
err = IPIKE_SA_NOT_FOUND;
goto cleanup;
}
if (sm->sadb_msg_errno != 0)
{
(void)ipcom_errno_set(sm->sadb_msg_errno);
IPCOM_LOG1(ERR, "ipike_pfkey2_write_socket: pfkey %s", ipcom_strerror(ipcom_errno));
err = IPIKE_PFKEY_ERROR;
goto cleanup;
}
cleanup:
return err;
}
/*
*===========================================================================
* ipike_pfkey2_write
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_pfkey2_write(struct iovec* iov, int count, int len)
{
Ipike_error err;
int pf_key_sock;
pf_key_sock = ipcom_socket(PF_KEY, (int)IP_SOCK_RAW, PF_KEY_V2);
if (pf_key_sock < 0)
{
IPCOM_LOG2(ERR, "ipike_pfkey2_write: failed to create PF_KEY (%d) socket - %s",
PF_KEY, ipcom_strerror(ipcom_errno));
return IPIKE_PFKEY_ERROR;
}
if (IPIKE_SUCCESS != (err = ipike_pfkey2_write_socket(pf_key_sock, iov, count, len)))
{
IPCOM_LOG2(ERR, "ipike_pfkey2_write: failed to write PF_KEY (%d) socket - %s",
PF_KEY, ipcom_strerror(ipcom_errno));
goto cleanup;
}
cleanup:
(void)ipcom_socketclose(pf_key_sock);
return err;
}
/*
*===========================================================================
* ipike_pfkeyv2_process_sa_expire
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_pfkeyv2_process_sa_expire(struct sadb_msg* sm)
{
struct sadb_sa* sa = IP_NULL;
struct sadb_address_full* dst_addr = IP_NULL;
struct sadb_address_full* src_addr = IP_NULL;
struct sadb_ext* ext = IP_NULL;
void* buffer_end = IP_NULL;
Ipike_pfkey2_ipsec_sa_param param;
Ip_bool is_hard = IP_FALSE;
ipcom_memset(&param, 0, sizeof(param));
ext = (struct sadb_ext*) (((Ip_u8 *) sm) + sizeof(struct sadb_msg));
buffer_end = (void*) (((Ip_u8 *) sm) + sm->sadb_msg_len * 8);
if (sm->sadb_msg_errno != 0)
{
(void)ipcom_errno_set(sm->sadb_msg_errno);
IPCOM_LOG1(ERR,
"ipike_pfkeyv2_process_sa_expire: pfkey %s", ipcom_strerror(ipcom_errno));
return IPIKE_PFKEY_ERROR;
}
while ((void *) ext < buffer_end && (sa == IP_NULL || dst_addr == IP_NULL))
{
switch (ext->sadb_ext_type)
{
case SADB_EXT_SA:
sa = (struct sadb_sa*) ext;
break;
case SADB_EXT_ADDRESS_SRC:
case SADB_EXT_ADDRESS_DST:
if (ext->sadb_ext_type == SADB_EXT_ADDRESS_SRC)
src_addr = (struct sadb_address_full*) ext;
else
dst_addr = (struct sadb_address_full*) ext;
break;
case SADB_EXT_LIFETIME_HARD:
is_hard = IP_TRUE;
break;
case SADB_EXT_LIFETIME_SOFT:
is_hard = IP_FALSE;
break;
}
ext = (struct sadb_ext*) (((Ip_u8*) ext) + ext->sadb_ext_len * 8);
}
if (sa == IP_NULL || src_addr == IP_NULL || dst_addr == IP_NULL)
{
IPCOM_LOG0(ERR, "ipike_pfkeyv2_process_sa_expire: malformed expire message");
return IPIKE_PFKEY_ERROR;
}
if (IPIKE_SUCCESS != ipike_pfkey2_proto_id_from_satype(sm->sadb_msg_satype, &param.proto))
{
IPCOM_LOG1(ERR,
"ipike_pfkeyv2_process_sa_expire: unknown SA type (%d)", sm->sadb_msg_satype);
return IPIKE_PFKEY_ERROR;
}
(void)ipike_pfkey2_extaddr_to_ipaddr(&param.src_addr, IP_NULL, src_addr);
(void)ipike_pfkey2_extaddr_to_ipaddr(&param.dst_addr, IP_NULL, dst_addr);
ipcom_memcpy(param.spi, &sa->sadb_sa_spi, sizeof(param.spi));
return ipike.pfkeyv2.sa_expire_cb(&param, is_hard, IP_TRUE);
}
/*
*===========================================================================
* ipike_pfkeyv2_process_sa_acquire
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_pfkeyv2_process_sa_acquire(struct sadb_msg *sm)
{
struct sadb_sa* sa = IP_NULL;
struct sadb_address_full* dst_addr = IP_NULL;
struct sadb_address_full* src_addr = IP_NULL;
struct sadb_ext* ext = IP_NULL;
void* buffer_end = IP_NULL;
Ipike_pfkey2_ipsec_sa_param param;
ipcom_memset(&param, 0, sizeof(param));
ext = (struct sadb_ext*) (((Ip_u8 *) sm) + sizeof(struct sadb_msg));
buffer_end = (void*) (((Ip_u8 *) sm) + sm->sadb_msg_len * 8);
if (sm->sadb_msg_errno != 0)
{
(void)ipcom_errno_set(sm->sadb_msg_errno);
IPCOM_LOG1(ERR,
"ipike_pfkeyv2_process_sa_acquire: pfkey %s", ipcom_strerror(ipcom_errno));
return IPIKE_PFKEY_ERROR;
}
while ((void *) ext < buffer_end && (sa == IP_NULL || dst_addr == IP_NULL))
{
switch (ext->sadb_ext_type)
{
case SADB_EXT_ADDRESS_SRC:
case SADB_EXT_ADDRESS_DST:
if (ext->sadb_ext_type == SADB_EXT_ADDRESS_SRC)
src_addr = (struct sadb_address_full*) ext;
else
dst_addr = (struct sadb_address_full*) ext;
break;
case SADB_EXT_SUPPORTED_AUTH:
case SADB_EXT_SUPPORTED_ENCRYPT:
break;
}
ext = (struct sadb_ext*) (((Ip_u8*) ext) + ext->sadb_ext_len * 8);
}
if (src_addr == IP_NULL || dst_addr == IP_NULL)
{
IPCOM_LOG0(ERR, "ipike_pfkeyv2_process_sa_acquire: malformed acquire message");
return IPIKE_PFKEY_ERROR;
}
(void)ipike_pfkey2_extaddr_to_ipaddr(&param.src_addr, IP_NULL, src_addr);
(void)ipike_pfkey2_extaddr_to_ipaddr(&param.dst_addr, IP_NULL, dst_addr);
return ipike.pfkeyv2.sa_acquire_cb(&param);
}
/*
*===========================================================================
* ipike_pfkeyv2_process_sa_remove
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_pfkeyv2_process_sa_remove(struct sadb_msg* sm)
{
struct sadb_sa* sa = IP_NULL;
struct sadb_address_full* dst_addr = IP_NULL;
struct sadb_address_full* src_addr = IP_NULL;
struct sadb_ext* ext = IP_NULL;
void* buffer_end = IP_NULL;
Ipike_pfkey2_ipsec_sa_param param;
ipcom_memset(&param, 0, sizeof(param));
ext = (struct sadb_ext*) (((Ip_u8 *) sm) + sizeof(struct sadb_msg));
buffer_end = (void*) (((Ip_u8 *) sm) + sm->sadb_msg_len * 8);
if (sm->sadb_msg_errno != 0)
{
(void)ipcom_errno_set(sm->sadb_msg_errno);
IPCOM_LOG1(ERR,
"ipike_pfkeyv2_process_sa_remove: pfkey %s", ipcom_strerror(ipcom_errno));
return IPIKE_PFKEY_ERROR;
}
while ((void *) ext < buffer_end && (sa == IP_NULL || dst_addr == IP_NULL))
{
switch (ext->sadb_ext_type)
{
case SADB_EXT_SA:
sa = (struct sadb_sa*) ext;
break;
case SADB_EXT_ADDRESS_SRC:
case SADB_EXT_ADDRESS_DST:
if (ext->sadb_ext_type == SADB_EXT_ADDRESS_SRC)
src_addr = (struct sadb_address_full*) ext;
else
dst_addr = (struct sadb_address_full*) ext;
break;
}
ext = (struct sadb_ext*) (((Ip_u8*) ext) + ext->sadb_ext_len * 8);
}
if (sa == IP_NULL || src_addr == IP_NULL || dst_addr == IP_NULL)
{
IPCOM_LOG0(ERR, "ipike_pfkeyv2_process_sa_remove: malformed expire message");
return IPIKE_PFKEY_ERROR;
}
if (IPIKE_SUCCESS != ipike_pfkey2_proto_id_from_satype(sm->sadb_msg_satype, &param.proto))
{
IPCOM_LOG1(ERR,
"ipike_pfkeyv2_process_sa_expire: unknown SA type (%d)", sm->sadb_msg_satype);
return IPIKE_PFKEY_ERROR;
}
(void)ipike_pfkey2_extaddr_to_ipaddr(&param.src_addr, IP_NULL, src_addr);
(void)ipike_pfkey2_extaddr_to_ipaddr(&param.dst_addr, IP_NULL, dst_addr);
ipcom_memcpy(param.spi, &sa->sadb_sa_spi, sizeof(param.spi));
return ipike.pfkeyv2.sa_remove_cb(&param);
}
/*
*===========================================================================
* ipike_pfkeyv2_process_sa_flush
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_pfkeyv2_process_sa_flush(struct sadb_msg* sm)
{
(void)sm;
return ipike.pfkeyv2.sa_flush_cb();
}
/*
*===========================================================================
* ipike_pfkeyv2_register
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_pfkeyv2_register(int sock)
{
Ipike_error err;
struct iovec iov[1];
struct sadb_msg smsg;
ipcom_memset(iov, 0, sizeof(iov));
ipcom_memset(&smsg, 0, sizeof(smsg));
/* Key socket header */
smsg.sadb_msg_version = PF_KEY_V2;
smsg.sadb_msg_type = SADB_REGISTER;
smsg.sadb_msg_seq = 0;
smsg.sadb_msg_pid = ipcom_getpid();
smsg.sadb_msg_len = sizeof(smsg) / 8;
iov[0].iov_base = &smsg;
iov[0].iov_len = sizeof(smsg);
smsg.sadb_msg_satype = SADB_SATYPE_AH;
if (IPIKE_SUCCESS != (err = ipike_pfkey2_write_socket(
sock, iov, 1, smsg.sadb_msg_len * 8)))
return err;
smsg.sadb_msg_satype = SADB_SATYPE_ESP;
if (IPIKE_SUCCESS != (err = ipike_pfkey2_write_socket(
sock, iov, 1, smsg.sadb_msg_len * 8)))
return err;
return IPIKE_SUCCESS;
}
/*
*===========================================================================
* ipike_pfkeyv2_flush
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_pfkeyv2_flush(int sock)
{
Ipike_error err;
struct iovec iov[1];
struct sadb_msg smsg;
IPCOM_LOG0(DEBUG2, "ipike_pfkeyv2_flush - start");
ipcom_memset(iov, 0, sizeof(iov));
ipcom_memset(&smsg, 0, sizeof(smsg));
/* Key socket header */
smsg.sadb_msg_version = PF_KEY_V2;
smsg.sadb_msg_type = SADB_FLUSH;
smsg.sadb_msg_seq = 0;
smsg.sadb_msg_pid = ipcom_getpid();
smsg.sadb_msg_len = sizeof(smsg) / 8;
iov[0].iov_base = &smsg;
iov[0].iov_len = sizeof(smsg);
if (IPIKE_SUCCESS != (err = ipike_pfkey2_write_socket(sock, iov, 1, smsg.sadb_msg_len * 8)))
{
IPCOM_LOG0(DEBUG2, "ipike_pfkeyv2_flush - failed to write to socket");
return err;
}
IPCOM_LOG0(DEBUG2, "ipike_pfkeyv2_flush - completed");
return IPIKE_SUCCESS;
}
/*
*===========================================================================
* ipike_pfkeyv2_spd_flush
*===========================================================================
*/
IP_STATIC Ipike_error
ipike_pfkeyv2_spd_flush(int sock)
{
Ipike_error err;
struct iovec iov[1];
struct sadb_msg smsg;
IPCOM_LOG0(DEBUG2, "ipike_pfkeyv2_spd_flush - start");
ipcom_memset(iov, 0, sizeof(iov));
ipcom_memset(&smsg, 0, sizeof(smsg));
/* Key socket header */
smsg.sadb_msg_version = PF_KEY_V2;
smsg.sadb_msg_type = SADB_X_SPDFLUSH;
smsg.sadb_msg_seq = 0;
smsg.sadb_msg_pid = ipcom_getpid();
smsg.sadb_msg_len = sizeof(smsg) / 8;
iov[0].iov_base = &smsg;
iov[0].iov_len = sizeof(smsg);
if (IPIKE_SUCCESS != (err = ipike_pfkey2_write_socket(sock, iov, 1, smsg.sadb_msg_len * 8)))
{
IPCOM_LOG0(DEBUG2, "ipike_pfkeyv2_spd_flush - failed to write to socket");
return err;
}
IPCOM_LOG0(DEBUG2, "ipike_pfkeyv2_spd_flush - completed");
return IPIKE_SUCCESS;
}
/*
*===========================================================================
* ipike_pfkeyv2_set_lifetime_kbytes
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC void
ipike_pfkeyv2_set_lifetime_kbytes(uint64_t *lifetime_bytes, Ip_u64 life_kbytes, Ip_bool soft)
{
if (soft)
{
/* Take 7/8 of hard value */
*lifetime_bytes -= (*lifetime_bytes) >> 3;
}
*lifetime_bytes = (life_kbytes << 10);
return;
}
/*
****************************************************************************
* 10 PUBLIC FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipike_pfkeyv2_add_sa
*===========================================================================
*/
IP_GLOBAL Ipike_error
ipike_pfkeyv2_add_sa(Ipike_ipsec_sadb_entry* ipsec_sa)
{
struct iovec iov[13];
struct sadb_msg smsg;
struct sadb_sa sadb_sa;
struct sadb_x_sa2 sadb_sa2;
struct sadb_lifetime sadb_hard_expiration;
struct sadb_lifetime sadb_soft_expiration;
struct sadb_address_full sadb_dst_addr;
struct sadb_address_full sadb_src_addr;
struct sadb_key sadb_auth_key;
struct sadb_key sadb_encryption_key;
struct sadb_x_nat_t_type sadb_nat_type;
struct sadb_x_nat_t_port sadb_nat_sport;
struct sadb_x_nat_t_port sadb_nat_dport;
Ip_u16 port;
Ip_u8 e_key[256];
Ip_u8 a_key[256];
int count = 0;
Ipike_error err;
ipcom_memset(iov, 0, sizeof(iov));
ipcom_memset(&smsg, 0, sizeof(smsg));
ipcom_memset(&sadb_sa, 0, sizeof(sadb_sa));
ipcom_memset(&sadb_sa2, 0, sizeof(sadb_sa2));
ipcom_memset(&sadb_hard_expiration, 0, sizeof(sadb_hard_expiration));
ipcom_memset(&sadb_soft_expiration, 0, sizeof(sadb_soft_expiration));
ipcom_memset(&sadb_src_addr, 0, sizeof(sadb_src_addr));
ipcom_memset(&sadb_dst_addr, 0, sizeof(sadb_dst_addr));
ipcom_memset(&sadb_auth_key, 0, sizeof(sadb_auth_key));
ipcom_memset(&sadb_encryption_key, 0, sizeof(sadb_encryption_key));
ipcom_memset(&sadb_nat_type, 0, sizeof(sadb_nat_type));
ipcom_memset(&sadb_nat_sport, 0, sizeof(sadb_nat_sport));
ipcom_memset(&sadb_nat_dport, 0, sizeof(sadb_nat_dport));
ipcom_memset(e_key, 0, sizeof(e_key));
ipcom_memset(a_key, 0, sizeof(a_key));
/* Key socket header */
smsg.sadb_msg_version = PF_KEY_V2;
smsg.sadb_msg_type = SADB_ADD; /*i(ipsec_sa->is_inbound) ? SADB_UPDATE : SADB_ADD;*/
err = ipike_pfkey2_satype_from_proto_id(ipsec_sa->proto, &smsg.sadb_msg_satype);
if (IPIKE_SUCCESS != err)
return err;
if (ipsec_sa->is_inbound)
ipcom_memcpy(&smsg.sadb_msg_seq, ipsec_sa->spi, 4);
else
ipcom_memcpy(&smsg.sadb_msg_seq, ipsec_sa->other->spi, 4);
smsg.sadb_msg_pid = ipcom_getpid();
smsg.sadb_msg_len = sizeof(smsg) / 8;
iov[count].iov_base = &smsg;
iov[count++].iov_len = sizeof(smsg);
/* Association Extension */
sadb_sa.sadb_sa_exttype = SADB_EXT_SA;
sadb_sa.sadb_sa_len = sizeof(sadb_sa) / 8;
sadb_sa.sadb_sa_state = SADB_SASTATE_MATURE;
sadb_sa.sadb_sa_flags = 0;
sadb_sa.sadb_sa_replay = 4;
err = ipike_pfkey2_enc_from_transform(ipsec_sa->proto, &ipsec_sa->transform_param,
&sadb_sa.sadb_sa_encrypt);
if (IPIKE_SUCCESS != err)
return err;
err = ipike_pfkey2_auth_from_transform(ipsec_sa->proto, &ipsec_sa->transform_param,
&sadb_sa.sadb_sa_auth);
if (IPIKE_SUCCESS != err)
return err;
ipcom_memcpy(&sadb_sa.sadb_sa_spi, ipsec_sa->spi, sizeof(ipsec_sa->spi));
iov[count].iov_base = &sadb_sa;
iov[count++].iov_len = sizeof(sadb_sa);
smsg.sadb_msg_len += sadb_sa.sadb_sa_len;
/* sadb_x_sa2 */
sadb_sa2.sadb_x_sa2_exttype = SADB_X_EXT_SA2;
sadb_sa2.sadb_x_sa2_len = sizeof(sadb_sa2) / 8;
if ((ipsec_sa->transform_param.encapsulation_mode == IPIKE_IPSEC_ENCAPSULATION_MODE_TUNNEL) ||
(ipsec_sa->transform_param.encapsulation_mode == IPIKE_IPSEC_ENCAPSULATION_MODE_UDP_TUNNEL))
sadb_sa2.sadb_x_sa2_mode = IPSEC_MODE_TUNNEL;
else if ((ipsec_sa->transform_param.encapsulation_mode == IPIKE_IPSEC_ENCAPSULATION_MODE_TRANSPORT) ||
(ipsec_sa->transform_param.encapsulation_mode == IPIKE_IPSEC_ENCAPSULATION_MODE_UDP_TRANSPORT))
sadb_sa2.sadb_x_sa2_mode = IPSEC_MODE_TRANSPORT;
else
sadb_sa2.sadb_x_sa2_mode = IPSEC_MODE_ANY;
sadb_sa2.sadb_x_sa2_reqid = 0;
iov[count].iov_base = &sadb_sa2;
iov[count++].iov_len = sizeof(sadb_sa2);
smsg.sadb_msg_len += sadb_sa2.sadb_x_sa2_len;
/* Address Extension (source address) */
if (ipsec_sa->is_behind_nat)
port = ipike_get_port(&ipsec_sa->sa_src_addr);
else
port = 0;
sadb_src_addr.addr.sadb_address_exttype = SADB_EXT_ADDRESS_SRC;
err = ipike_pfkey2_ipaddr_to_extaddr(&sadb_src_addr, 0, &ipsec_sa->sa_src_addr, port);
if (IPIKE_SUCCESS != err)
return err;
iov[count].iov_base = &sadb_src_addr;
iov[count++].iov_len = sadb_src_addr.addr.sadb_address_len * 8;
smsg.sadb_msg_len += sadb_src_addr.addr.sadb_address_len;
/* Address Extension (destination address) */
if (ipsec_sa->is_behind_nat)
port = ipike_get_port(&ipsec_sa->sa_dst_addr);
else
port = 0;
sadb_dst_addr.addr.sadb_address_exttype = SADB_EXT_ADDRESS_DST;
err = ipike_pfkey2_ipaddr_to_extaddr(&sadb_dst_addr, 0, &ipsec_sa->sa_dst_addr, port);
if (IPIKE_SUCCESS != err)
return err;
iov[count].iov_base = &sadb_dst_addr;
iov[count++].iov_len = sadb_src_addr.addr.sadb_address_len * 8;
smsg.sadb_msg_len += sadb_dst_addr.addr.sadb_address_len;
if (ipsec_sa->auth_key.len > 0)
{
/* Key Extension (encryption) */
sadb_auth_key.sadb_key_exttype = SADB_EXT_KEY_AUTH;
sadb_auth_key.sadb_key_len = (uint16_t)
((sizeof(sadb_auth_key) + ((ipsec_sa->auth_key.len + 7) / 8) * 8) / 8);
sadb_auth_key.sadb_key_bits = (Ip_u16) (8 * ipsec_sa->auth_key.len);
ipcom_memcpy(a_key, ipsec_sa->auth_key.value, ipsec_sa->auth_key.len);
/* Key header */
iov[count].iov_base = &sadb_auth_key;
iov[count++].iov_len = sizeof(sadb_auth_key);
/* Key */
iov[count].iov_base = a_key;
iov[count++].iov_len = ((ipsec_sa->auth_key.len + 7) / 8) * 8;
smsg.sadb_msg_len += sadb_auth_key.sadb_key_len;
}
if (ipsec_sa->proto == IPIKE_PROTO_IPSEC_ESP)
{
/* Key Extension (encryption) */
sadb_encryption_key.sadb_key_exttype = SADB_EXT_KEY_ENCRYPT;
sadb_encryption_key.sadb_key_len = (uint16_t)
((sizeof(sadb_encryption_key) + ((ipsec_sa->encryption_key.len + 7) / 8) * 8) / 8);
sadb_encryption_key.sadb_key_bits = (Ip_u16) (8 * ipsec_sa->encryption_key.len);
ipcom_memcpy(e_key, ipsec_sa->encryption_key.value, ipsec_sa->encryption_key.len);
/* Key header */
iov[count].iov_base = &sadb_encryption_key;
iov[count++].iov_len = sizeof(sadb_encryption_key);
/* Key */
iov[count].iov_base = e_key;
iov[count++].iov_len = ((ipsec_sa->encryption_key.len + 7) / 8) * 8;
smsg.sadb_msg_len += sadb_encryption_key.sadb_key_len;
}
/* Hard expiration */
sadb_hard_expiration.sadb_lifetime_exttype = SADB_EXT_LIFETIME_HARD;
sadb_hard_expiration.sadb_lifetime_len = sizeof(sadb_hard_expiration) / 8;
ipike_pfkeyv2_set_lifetime_kbytes(&sadb_hard_expiration.sadb_lifetime_bytes,
ipsec_sa->transform_param.life_duration_kbytes,
IP_FALSE);
IP_U64_SETLO(sadb_hard_expiration.sadb_lifetime_addtime, ipsec_sa->transform_param.life_duration_sec);
iov[count].iov_base = &sadb_hard_expiration;
iov[count++].iov_len = sizeof(sadb_hard_expiration);
smsg.sadb_msg_len += sadb_hard_expiration.sadb_lifetime_len;
/* Soft expiration */
sadb_soft_expiration.sadb_lifetime_exttype = SADB_EXT_LIFETIME_SOFT;
sadb_soft_expiration.sadb_lifetime_len = sizeof(sadb_soft_expiration) / 8;
if (ipsec_sa->transform_param.life_duration_sec > 0)
{
if (ipsec_sa->transform_param.life_duration_sec < 30)
ipsec_sa->transform_param.life_duration_sec = ipike_pfkeyv2_soft_to_hard_time;
if (ipsec_sa->transform_param.life_duration_sec < 2*ipike_pfkeyv2_soft_to_hard_time)
/* We have internal polling for expire at 10 seconds interval, so make
* sure at least two of those is executed. */
IP_U64_SETLO(sadb_soft_expiration.sadb_lifetime_addtime,
(Ip_u32) (ipsec_sa->transform_param.life_duration_sec - 20));
else
IP_U64_SETLO(sadb_soft_expiration.sadb_lifetime_addtime,
ipsec_sa->transform_param.life_duration_sec - ipike_pfkeyv2_soft_to_hard_time);
}
ipike_pfkeyv2_set_lifetime_kbytes(&sadb_hard_expiration.sadb_lifetime_bytes,
ipsec_sa->transform_param.life_duration_kbytes,
IP_TRUE);
iov[count].iov_base = &sadb_soft_expiration;
iov[count++].iov_len = sizeof(sadb_soft_expiration);
smsg.sadb_msg_len += sadb_soft_expiration.sadb_lifetime_len;
if (ipsec_sa->is_behind_nat)
{
/* NAT Traversal type */
sadb_nat_type.sadb_x_nat_t_type_exttype = SADB_X_EXT_NAT_T_TYPE;
sadb_nat_type.sadb_x_nat_t_type_type = UDP_ENCAP_ESPINUDP;
sadb_nat_type.sadb_x_nat_t_type_len = sizeof(struct sadb_x_nat_t_type) / 8;
iov[count].iov_base = &sadb_nat_type;
iov[count++].iov_len = sizeof(sadb_nat_type);
smsg.sadb_msg_len += sadb_nat_type.sadb_x_nat_t_type_len;
/* NAT Traversal source port */
sadb_nat_sport.sadb_x_nat_t_port_exttype = SADB_X_EXT_NAT_T_SPORT;
sadb_nat_sport.sadb_x_nat_t_port_port = ipike_get_port(&ipsec_sa->sa_src_addr);
sadb_nat_sport.sadb_x_nat_t_port_port = ip_htons(sadb_nat_sport.sadb_x_nat_t_port_port);
sadb_nat_sport.sadb_x_nat_t_port_len = sizeof(struct sadb_x_nat_t_port) / 8;
iov[count].iov_base = &sadb_nat_sport;
iov[count++].iov_len = sizeof(sadb_nat_sport);
smsg.sadb_msg_len += sadb_nat_sport.sadb_x_nat_t_port_len;
/* NAT Traversal destination port */
sadb_nat_dport.sadb_x_nat_t_port_exttype = SADB_X_EXT_NAT_T_DPORT;
sadb_nat_dport.sadb_x_nat_t_port_port = ipike_get_port(&ipsec_sa->sa_dst_addr);
sadb_nat_dport.sadb_x_nat_t_port_port = ip_htons(sadb_nat_dport.sadb_x_nat_t_port_port);
sadb_nat_dport.sadb_x_nat_t_port_len = sizeof(struct sadb_x_nat_t_port) / 8;
iov[count].iov_base = &sadb_nat_dport;
iov[count++].iov_len = sizeof(sadb_nat_dport);
smsg.sadb_msg_len += sadb_nat_dport.sadb_x_nat_t_port_len;
}
return ipike_pfkey2_write(iov, count, smsg.sadb_msg_len * 8);
}
/*
*===========================================================================
* ipike_pfkeyv2_remove_sa
*===========================================================================
*/
IP_GLOBAL Ipike_error
ipike_pfkeyv2_remove_sa(Ipike_ipsec_sadb_entry *ipsec_sa)
{
struct iovec iov[5];
struct sadb_msg smsg;
struct sadb_sa sadb_sa;
struct sadb_address_full sadb_src_addr;
struct sadb_address_full sadb_dst_addr;
int count = 0;
Ipike_error err;
ipcom_memset(iov, 0, sizeof(iov));
ipcom_memset(&smsg, 0, sizeof(smsg));
ipcom_memset(&sadb_sa, 0, sizeof(sadb_sa));
ipcom_memset(&sadb_src_addr, 0, sizeof(sadb_src_addr));
ipcom_memset(&sadb_dst_addr, 0, sizeof(sadb_dst_addr));
/* Key socket header */
smsg.sadb_msg_version = PF_KEY_V2;
smsg.sadb_msg_type = SADB_DELETE;
err = ipike_pfkey2_satype_from_proto_id(ipsec_sa->proto, &smsg.sadb_msg_satype);
if (IPIKE_SUCCESS != err)
return err;
smsg.sadb_msg_seq = 1;
smsg.sadb_msg_pid = ipcom_getpid();
smsg.sadb_msg_len = sizeof(smsg) / 8;
iov[count].iov_base = &smsg;
iov[count++].iov_len = sizeof(smsg);
/* Association Extension */
sadb_sa.sadb_sa_exttype = SADB_EXT_SA;
sadb_sa.sadb_sa_len = sizeof(sadb_sa) / 8;
sadb_sa.sadb_sa_state = SADB_SASTATE_MATURE;
sadb_sa.sadb_sa_flags = 0;
ipcom_memcpy(&sadb_sa.sadb_sa_spi, ipsec_sa->spi, sizeof(ipsec_sa->spi));
iov[count].iov_base = &sadb_sa;
iov[count++].iov_len = sizeof(sadb_sa);
smsg.sadb_msg_len += sadb_sa.sadb_sa_len;
/* Address Extension (source address) */
sadb_src_addr.addr.sadb_address_exttype = SADB_EXT_ADDRESS_SRC;
err = ipike_pfkey2_ipaddr_to_extaddr(&sadb_src_addr, 0, &ipsec_sa->sa_src_addr, 0);
if (IPIKE_SUCCESS != err)
return err;
iov[count].iov_base = &sadb_src_addr;
iov[count++].iov_len = sadb_src_addr.addr.sadb_address_len * 8;
smsg.sadb_msg_len += sadb_src_addr.addr.sadb_address_len;
/* Address Extension (destination address) */
sadb_dst_addr.addr.sadb_address_exttype = SADB_EXT_ADDRESS_DST;
err = ipike_pfkey2_ipaddr_to_extaddr(&sadb_dst_addr, 0, &ipsec_sa->sa_dst_addr, 0);
if (IPIKE_SUCCESS != err)
return err;
iov[count].iov_base = &sadb_dst_addr;
iov[count++].iov_len = sadb_dst_addr.addr.sadb_address_len * 8;
smsg.sadb_msg_len += sadb_dst_addr.addr.sadb_address_len;
return ipike_pfkey2_write(iov, count, smsg.sadb_msg_len * 8);
}
/*
*===========================================================================
* ipike_pfkeyv2_exist_sa
*===========================================================================
*/
IP_GLOBAL Ipike_error
ipike_pfkeyv2_exist_sa(Ipike_ipsec_sadb_entry *ipsec_sa, Ip_bool *exist)
{
struct iovec iov[5];
struct sadb_msg smsg;
struct sadb_sa sadb_sa;
struct sadb_address_full sadb_src_addr;
struct sadb_address_full sadb_dst_addr;
int count = 0;
Ipike_error err;
ipcom_memset(iov, 0, sizeof(iov));
ipcom_memset(&smsg, 0, sizeof(smsg));
ipcom_memset(&sadb_sa, 0, sizeof(sadb_sa));
ipcom_memset(&sadb_src_addr, 0, sizeof(sadb_src_addr));
ipcom_memset(&sadb_dst_addr, 0, sizeof(sadb_dst_addr));
/* Key socket header */
smsg.sadb_msg_version = PF_KEY_V2;
smsg.sadb_msg_type = SADB_GET;
err = ipike_pfkey2_satype_from_proto_id(ipsec_sa->proto, &smsg.sadb_msg_satype);
if (IPIKE_SUCCESS != err)
return err;
smsg.sadb_msg_seq = 1;
smsg.sadb_msg_pid = ipcom_getpid();
smsg.sadb_msg_len = sizeof(smsg) / 8;
iov[count].iov_base = &smsg;
iov[count++].iov_len = sizeof(smsg);
/* Association Extension */
sadb_sa.sadb_sa_exttype = SADB_EXT_SA;
sadb_sa.sadb_sa_len = sizeof(sadb_sa) / 8;
sadb_sa.sadb_sa_state = SADB_SASTATE_MATURE;
sadb_sa.sadb_sa_flags = 0;
ipcom_memcpy(&sadb_sa.sadb_sa_spi, ipsec_sa->spi, sizeof(ipsec_sa->spi));
iov[count].iov_base = &sadb_sa;
iov[count++].iov_len = sizeof(sadb_sa);
smsg.sadb_msg_len += sadb_sa.sadb_sa_len;
/* Address Extension (source address) */
sadb_src_addr.addr.sadb_address_exttype = SADB_EXT_ADDRESS_SRC;
err = ipike_pfkey2_ipaddr_to_extaddr(&sadb_src_addr, 0, &ipsec_sa->sa_src_addr, 0);
if (IPIKE_SUCCESS != err)
return err;
iov[count].iov_base = &sadb_src_addr;
iov[count++].iov_len = sizeof(sadb_src_addr);
smsg.sadb_msg_len += sadb_src_addr.addr.sadb_address_len;
/* Address Extension (destination address) */
sadb_dst_addr.addr.sadb_address_exttype = SADB_EXT_ADDRESS_DST;
err = ipike_pfkey2_ipaddr_to_extaddr(&sadb_dst_addr, 0, &ipsec_sa->sa_dst_addr, 0);
if (IPIKE_SUCCESS != err)
return err;
iov[count].iov_base = &sadb_dst_addr;
iov[count++].iov_len = sizeof(sadb_dst_addr);
smsg.sadb_msg_len += sadb_dst_addr.addr.sadb_address_len;
err = ipike_pfkey2_write(iov, count, smsg.sadb_msg_len * 8);
if (err != IPIKE_SUCCESS && err != IPIKE_SA_NOT_FOUND)
return err;
*exist = (err == IPIKE_SA_NOT_FOUND ? IP_FALSE : IP_TRUE);
return IPIKE_SUCCESS;
}
/*
*===========================================================================
* ipike_pfkeyv2_group_sa
*===========================================================================
*/
IP_GLOBAL Ipike_error
ipike_pfkeyv2_group_sa(
Ipike_ipsec_sadb_entry* ipsec_sa1,
Ipike_ipsec_sadb_entry* ipsec_sa2)
{
/* Not supported (not needed) */
(void)ipsec_sa1;
(void)ipsec_sa2;
return IPIKE_SUCCESS;
}
/*
*===========================================================================
* ipike_pfkeyv2_get_ipsec_policy
*===========================================================================
*/
IP_STATIC void
ipike_pfkeyv2_get_ipsec_policy(
Ip_u8 dir,
Ip_u16 encap_mode,
Ip_u8 proto,
union Ip_sockaddr_union* src_ipaddr,
union Ip_sockaddr_union* dst_ipaddr,
Ip_u8* buf,
Ip_u32* buf_len)
{
struct sadb_x_policy* policy;
struct sadb_x_ipsecrequest* ipsec_req;
struct sadb_address_full addr;
/* Policy buffer is big enough so skip sanity check. The buffer will get
* policy and ipsecrequest structures followed by source and destination
* address structures. */
policy = (struct sadb_x_policy*)buf;
ipsec_req = (struct sadb_x_ipsecrequest*)(policy + 1);
ip_assert(*buf_len >= (sizeof(*policy) + sizeof(*ipsec_req) + 2*sizeof(struct sadb_address_full)));
*buf_len = sizeof(*policy) + sizeof(*ipsec_req);
policy->sadb_x_policy_exttype = SADB_X_EXT_POLICY;
policy->sadb_x_policy_type = IPSEC_POLICY_IPSEC;
policy->sadb_x_policy_dir = dir;
#ifdef HAVE_PFKEY_POLICY_PRIORITY
policy->sadb_x_policy_priority = PRIORITY_DEFAULT;
#endif
ipsec_req->sadb_x_ipsecrequest_level = IPSEC_LEVEL_REQUIRE;
if ((encap_mode == IPIKE_IPSEC_ENCAPSULATION_MODE_TUNNEL) ||
(encap_mode == IPIKE_IPSEC_ENCAPSULATION_MODE_UDP_TUNNEL))
ipsec_req->sadb_x_ipsecrequest_mode = IPSEC_MODE_TUNNEL;
else if ((encap_mode == IPIKE_IPSEC_ENCAPSULATION_MODE_TRANSPORT) ||
(encap_mode == IPIKE_IPSEC_ENCAPSULATION_MODE_UDP_TRANSPORT))
ipsec_req->sadb_x_ipsecrequest_mode = IPSEC_MODE_TRANSPORT;
else
ipsec_req->sadb_x_ipsecrequest_mode = IPSEC_MODE_ANY;
(void)ipike_pfkey2_proto_from_proto_id(proto, &proto);
ipsec_req->sadb_x_ipsecrequest_proto = proto;
ipsec_req->sadb_x_ipsecrequest_len = sizeof(*ipsec_req);
if (ipsec_req->sadb_x_ipsecrequest_mode == IPSEC_MODE_TUNNEL)
{
(void)ipike_pfkey2_ipaddr_to_extaddr(&addr, 0, src_ipaddr, 0);
ipcom_memcpy(buf + (*buf_len),
ipike_pfkey2_get_extaddr_ptr(&addr),
src_ipaddr->sa.sa_len);
*buf_len += src_ipaddr->sa.sa_len;
ipsec_req->sadb_x_ipsecrequest_len += src_ipaddr->sa.sa_len;
(void)ipike_pfkey2_ipaddr_to_extaddr(&addr, 0, dst_ipaddr, 0);
ipcom_memcpy(buf + (*buf_len),
ipike_pfkey2_get_extaddr_ptr(&addr),
dst_ipaddr->sa.sa_len);
*buf_len += dst_ipaddr->sa.sa_len;
ipsec_req->sadb_x_ipsecrequest_len += dst_ipaddr->sa.sa_len;
}
policy->sadb_x_policy_len = (ipsec_req->sadb_x_ipsecrequest_len + sizeof(*ipsec_req)) / 8;
return;
}
/*
*===========================================================================
* ipike_pfkeyv2_get_forward_policy
*===========================================================================
*/
IP_STATIC void
ipike_pfkeyv2_get_forward_policy(
Ip_u8 dir,
Ip_u8* buf,
Ip_u32* buf_len)
{
struct sadb_x_policy* policy;
/* Policy buffer is big enough so skip sanity check. The buffer will get
* policy and ipsecrequest structures followed by source and destination
* address structures. */
policy = (struct sadb_x_policy*)buf;
ip_assert(*buf_len >= sizeof(*policy));
*buf_len = sizeof(*policy);
policy->sadb_x_policy_exttype = SADB_X_EXT_POLICY;
policy->sadb_x_policy_type = IPSEC_POLICY_NONE;
policy->sadb_x_policy_dir = dir;
#ifdef HAVE_PFKEY_POLICY_PRIORITY
policy->sadb_x_policy_priority = PRIORITY_DEFAULT;
#endif
policy->sadb_x_policy_len = (sizeof(*policy) / 8);
return;
}
/*
*===========================================================================
* ipike_pfkeyv2_add_flow
*===========================================================================
*/
IP_GLOBAL Ipike_error
ipike_pfkeyv2_add_flow(Ipike_ipsec_sadb_entry* ipsec_sa)
{
Ipike_error err;
struct iovec iov[5];
struct sadb_msg smsg;
struct sadb_sa sadb_sa;
struct sadb_lifetime sadb_hard_expiration;
struct sadb_address_full src_addr;
struct sadb_address_full dst_addr;
Ip_u8 tmp[sizeof(struct sadb_x_policy) + sizeof(struct sadb_x_ipsecrequest) + 2*sizeof(struct sadb_address_full)];
Ip_u32 tmp_len;
Ip_u16 port;
int count;
ipcom_memset(iov, 0, sizeof(iov));
ipcom_memset(&smsg, 0, sizeof(smsg));
ipcom_memset(&sadb_sa, 0, sizeof(sadb_sa));
ipcom_memset(&src_addr, 0, sizeof(src_addr));
ipcom_memset(&dst_addr, 0, sizeof(dst_addr));
ipcom_memset(&sadb_hard_expiration, 0, sizeof(sadb_hard_expiration));
ipcom_memset(tmp, 0, sizeof(tmp));
count = 0;
/* Key socket header */
smsg.sadb_msg_version = PF_KEY_V2;
smsg.sadb_msg_type = SADB_X_SPDUPDATE;
smsg.sadb_msg_satype = 0;
smsg.sadb_msg_seq = 0;
smsg.sadb_msg_pid = ipcom_getpid();
smsg.sadb_msg_len = sizeof(smsg) / 8;
iov[count].iov_base = &smsg;
iov[count++].iov_len = sizeof(smsg);
/* Address Extension (source flow) */
port = ipike_get_port(&ipsec_sa->flow_src_addr);
src_addr.addr.sadb_address_exttype = SADB_EXT_ADDRESS_SRC;
err = ipike_pfkey2_network_to_extaddr(&src_addr,
ipsec_sa->flow_proto,
&ipsec_sa->flow_src_addr,
&ipsec_sa->flow_src_mask,
port);
if (IPIKE_SUCCESS != err)
return err;
iov[count].iov_base = &src_addr;
iov[count++].iov_len = src_addr.addr.sadb_address_len * 8;
smsg.sadb_msg_len += src_addr.addr.sadb_address_len;
/* Address Extension (destination flow) */
port = ipike_get_port(&ipsec_sa->flow_dst_addr);
dst_addr.addr.sadb_address_exttype = SADB_EXT_ADDRESS_DST;
err = ipike_pfkey2_network_to_extaddr(&dst_addr,
ipsec_sa->flow_proto,
&ipsec_sa->flow_dst_addr,
&ipsec_sa->flow_dst_mask,
port);
if (IPIKE_SUCCESS != err)
return err;
iov[count].iov_base = &dst_addr;
iov[count++].iov_len = src_addr.addr.sadb_address_len * 8;
smsg.sadb_msg_len += dst_addr.addr.sadb_address_len;
/* Hard expiration */
sadb_hard_expiration.sadb_lifetime_exttype = SADB_EXT_LIFETIME_HARD;
sadb_hard_expiration.sadb_lifetime_len = sizeof(sadb_hard_expiration) / 8;
ipike_pfkeyv2_set_lifetime_kbytes(&sadb_hard_expiration.sadb_lifetime_bytes,
ipsec_sa->transform_param.life_duration_kbytes,
IP_FALSE);
IP_U64_SETLO(sadb_hard_expiration.sadb_lifetime_addtime, ipsec_sa->transform_param.life_duration_sec);
iov[count].iov_base = &sadb_hard_expiration;
iov[count++].iov_len = sizeof(sadb_hard_expiration);
smsg.sadb_msg_len += sadb_hard_expiration.sadb_lifetime_len;
/* Policy */
tmp_len = sizeof(tmp);
if (ipsec_sa->proto != 0)
{
ipike_pfkeyv2_get_ipsec_policy(ipsec_sa->is_inbound ? IPSEC_DIR_INBOUND : IPSEC_DIR_OUTBOUND,
ipsec_sa->transform_param.encapsulation_mode,
ipsec_sa->proto,
&ipsec_sa->sa_src_addr,
&ipsec_sa->sa_dst_addr,
tmp,
&tmp_len);
}
else
{
ipike_pfkeyv2_get_forward_policy(ipsec_sa->is_inbound ? IPSEC_DIR_INBOUND : IPSEC_DIR_OUTBOUND,
tmp,
&tmp_len);
}
iov[count].iov_base = tmp;
iov[count++].iov_len = tmp_len;
smsg.sadb_msg_len += (Ip_u16)(tmp_len / 8);
return ipike_pfkey2_write(iov, count, smsg.sadb_msg_len * 8);
}
/*
*===========================================================================
* ipike_pfkeyv2_remove_flow
*===========================================================================
*/
IP_GLOBAL Ipike_error
ipike_pfkeyv2_remove_flow(Ipike_ipsec_sadb_entry* ipsec_sa)
{
struct iovec iov[5];
struct sadb_msg smsg;
struct sadb_sa sadb_sa;
struct sadb_address_full src_addr;
struct sadb_address_full dst_addr;
Ip_u8 tmp[sizeof(struct sadb_x_policy) + sizeof(struct sadb_x_ipsecrequest) + 2*sizeof(struct sadb_address_full)];
Ip_u32 tmp_len;
Ip_u16 port;
int count;
Ipike_error err;
ipcom_memset(iov, 0, sizeof(iov));
ipcom_memset(&smsg, 0, sizeof(smsg));
ipcom_memset(&sadb_sa, 0, sizeof(sadb_sa));
ipcom_memset(&src_addr, 0, sizeof(src_addr));
ipcom_memset(&dst_addr, 0, sizeof(dst_addr));
ipcom_memset(tmp, 0, sizeof(tmp));
count = 0;
/* Key socket header */
smsg.sadb_msg_version = PF_KEY_V2;
smsg.sadb_msg_type = SADB_X_SPDDELETE;
smsg.sadb_msg_satype = 0;
smsg.sadb_msg_seq = 0;
smsg.sadb_msg_pid = ipcom_getpid();
smsg.sadb_msg_len = sizeof(smsg) / 8;
iov[count].iov_base = &smsg;
iov[count++].iov_len = sizeof(smsg);
/* Address Extension (source flow) */
port = ipike_get_port(&ipsec_sa->flow_src_addr);
src_addr.addr.sadb_address_exttype = SADB_EXT_ADDRESS_SRC;
err = ipike_pfkey2_network_to_extaddr(&src_addr,
ipsec_sa->flow_proto,
&ipsec_sa->flow_src_addr,
&ipsec_sa->flow_src_mask,
port);
if (IPIKE_SUCCESS != err)
return err;
iov[count].iov_base = &src_addr;
iov[count++].iov_len = src_addr.addr.sadb_address_len * 8;
smsg.sadb_msg_len += src_addr.addr.sadb_address_len;
/* Address Extension (destination flow) */
port = ipike_get_port(&ipsec_sa->flow_dst_addr);
dst_addr.addr.sadb_address_exttype = SADB_EXT_ADDRESS_DST;
err = ipike_pfkey2_network_to_extaddr(&dst_addr,
ipsec_sa->flow_proto,
&ipsec_sa->flow_dst_addr,
&ipsec_sa->flow_dst_mask,
port);
if (IPIKE_SUCCESS != err)
return err;
iov[count].iov_base = &dst_addr;
iov[count++].iov_len = src_addr.addr.sadb_address_len * 8;
smsg.sadb_msg_len += dst_addr.addr.sadb_address_len;
/* Policy */
tmp_len = sizeof(tmp);
if (ipsec_sa->proto != 0)
{
ipike_pfkeyv2_get_ipsec_policy(ipsec_sa->is_inbound ? IPSEC_DIR_INBOUND : IPSEC_DIR_OUTBOUND,
ipsec_sa->transform_param.encapsulation_mode,
ipsec_sa->proto,
&ipsec_sa->sa_src_addr,
&ipsec_sa->sa_dst_addr,
tmp,
&tmp_len);
}
else
{
ipike_pfkeyv2_get_forward_policy(ipsec_sa->is_inbound ? IPSEC_DIR_INBOUND : IPSEC_DIR_OUTBOUND,
tmp,
&tmp_len);
}
iov[count].iov_base = tmp;
iov[count++].iov_len = tmp_len;
smsg.sadb_msg_len += (Ip_u16)(tmp_len / 8);
return ipike_pfkey2_write(iov, count, smsg.sadb_msg_len * 8);
}
/*
*===========================================================================
* ipike_pfkeyv2_process_socket_event
*===========================================================================
*/
IP_GLOBAL Ipike_error
ipike_pfkeyv2_process_socket_event(void)
{
char buf[IPIKE_PFKEY_SOCKET_BUFFER_SIZE];
struct sadb_msg* sm = (struct sadb_msg*)buf;
if (ipcom_socketread(ipike.pfkeyv2.sock, buf, IPIKE_PFKEY_SOCKET_BUFFER_SIZE) < 0)
{
IPCOM_LOG1(WARNING, "ipike_pfkeyv2_process_socket_event() :: ipcom_socketread() error: %s", ipcom_strerror(ipcom_errno));
return IPIKE_PFKEY_ERROR;
}
IPCOM_LOG1(DEBUG2, "ipike_pfkeyv2_process_socket_event() :: %s",
sm->sadb_msg_type == SADB_EXPIRE ? "expire" :
sm->sadb_msg_type == SADB_ACQUIRE ? "acquire" :
sm->sadb_msg_type == SADB_DELETE ? "delete" :
sm->sadb_msg_type == SADB_FLUSH ? "flush" :
"ignored");
switch (sm->sadb_msg_type)
{
case SADB_EXPIRE:
return ipike_pfkeyv2_process_sa_expire(sm);
case SADB_ACQUIRE:
return ipike_pfkeyv2_process_sa_acquire(sm);
case SADB_DELETE:
return ipike_pfkeyv2_process_sa_remove(sm);
case SADB_FLUSH:
return ipike_pfkeyv2_process_sa_flush(sm);
default:
/* ignore other events */
break;
}
return IPIKE_SUCCESS;
}
/*
*===========================================================================
* ipike_pfkeyv2_startup
*===========================================================================
*/
IP_GLOBAL Ipike_error
ipike_pfkeyv2_startup(void)
{
if (ipike.pfkeyv2.initialized)
ipike_dispatcher_shutdown();
IPCOM_LOG0(DEBUG2, "ipike_pfkeyv2_startup - initializing");
ipike.pfkeyv2.sock = socket(PF_KEY, SOCK_RAW, PF_KEY_V2);
if (ipike.pfkeyv2.sock < 0)
{
IPCOM_LOG1(ERR, "ipike_pfkeyv2_startup: failed to open PF_KEY socket - %s", ipcom_strerror(errno));
if (errno == IP_ERRNO_EPROTONOSUPPORT)
IPCOM_LOG0(ERR, "ipike_pfkeyv2_startup: make sure your kernel is compiled with option KEY");
return IPIKE_PFKEY_ERROR;
}
IPCOM_LOG0(DEBUG2, "ipike_pfkeyv2_startup - got pfkey socket");
if (ipcom_sysvar_get_as_int("ipike.pfkeyv2.flush_startup", 0) != 0)
{
(void)ipike_pfkeyv2_flush(ipike.pfkeyv2.sock);
(void)ipike_pfkeyv2_spd_flush(ipike.pfkeyv2.sock);
}
(void)ipike_pfkeyv2_register(ipike.pfkeyv2.sock);
ipike.pfkeyv2.initialized = IP_TRUE;
IPCOM_LOG0(DEBUG2, "ipike_pfkeyv2_startup - completed");
return IPIKE_SUCCESS;
}
/*
*===========================================================================
* ipike_pfkeyv2_shutdown
*===========================================================================
*/
IP_GLOBAL void
ipike_pfkeyv2_shutdown(void)
{
if (!ipike.pfkeyv2.initialized)
return;
if (ipcom_sysvar_get_as_int("ipike.pfkeyv2.flush_shutdown", 0) != 0)
(void)ipike_pfkeyv2_flush(ipike.pfkeyv2.sock);
(void)ipcom_socketclose(ipike.pfkeyv2.sock);
ipike.pfkeyv2.sock = IP_INVALID_SOCKET;
ipike.pfkeyv2.initialized = IP_FALSE;
return;
}
/*
*===========================================================================
* ipike_pfkeyv2_reconfigure
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_GLOBAL Ipike_error
ipike_pfkeyv2_reconfigure(void)
{
Ipike_error err = IPIKE_SUCCESS;
if (ipike.pfkeyv2.initialized)
{
if (ipcom_sysvar_get_as_int("ipike.pfkeyv2.flush_reconfigure", 0) != 0)
err = ipike_pfkeyv2_flush(ipike.pfkeyv2.sock);
ipike_pfkeyv2_soft_to_hard_time = ipcom_sysvar_get_as_int("ipike.pfkeyv2.soft_to_hard_time", 300);
}
return err;
}
#else
int ipike_ppfkeyv2_empty_file;
#endif /* !defined(IPIPSEC2) && !defined(IPIPSEC) */
/*
****************************************************************************
* END OF FILE
****************************************************************************
*/