/* ****************************************************************************** * 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 ****************************************************************************** */ /* 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 #include #include #include #include #include #define HAVE_PFKEY_POLICY_PRIORITY #include #include /* **************************************************************************** * 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 **************************************************************************** */