1843 lines
65 KiB
C
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(¶m, 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, ¶m.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(¶m.src_addr, IP_NULL, src_addr);
|
|
(void)ipike_pfkey2_extaddr_to_ipaddr(¶m.dst_addr, IP_NULL, dst_addr);
|
|
ipcom_memcpy(param.spi, &sa->sadb_sa_spi, sizeof(param.spi));
|
|
|
|
return ipike.pfkeyv2.sa_expire_cb(¶m, 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(¶m, 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(¶m.src_addr, IP_NULL, src_addr);
|
|
(void)ipike_pfkey2_extaddr_to_ipaddr(¶m.dst_addr, IP_NULL, dst_addr);
|
|
|
|
return ipike.pfkeyv2.sa_acquire_cb(¶m);
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* 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(¶m, 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, ¶m.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(¶m.src_addr, IP_NULL, src_addr);
|
|
(void)ipike_pfkey2_extaddr_to_ipaddr(¶m.dst_addr, IP_NULL, dst_addr);
|
|
ipcom_memcpy(param.spi, &sa->sadb_sa_spi, sizeof(param.spi));
|
|
|
|
return ipike.pfkeyv2.sa_remove_cb(¶m);
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* 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
|
|
****************************************************************************
|
|
*/
|