Files
m241Neelima/components/ip_net2-6.9/wrnad/wrnad_pfkey.c
T
2026-07-30 11:19:44 +05:30

1073 lines
28 KiB
C

/* wrnad_pfkey.c - Wind River network acceleration daemon (NAD) */
/*
* Copyright (c) 2010 Wind River Systems, Inc.
*
* The right to copy, distribute or otherwise make use of this software
* may be licensed only pursuant to the terms of an applicable Wind River
* license agreement.
*/
/* includes */
#if !defined(IPWRNAD) || defined(IPIPSEC2)
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <syslog.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include "wrnad.h"
/* defines */
/* typedefs */
/* imports */
/* globals */
/* locals */
static char recvbuf[WRNAD_RECVBUF_SIZE];
/*******************************************************************************
*
* wrnad_pfkey_typestr - find pfkey type in string format
*
* This routine returns the pfkey message type as a string
*
* RETURNS: string representation of pfkey message type.
*
* ERRNO: N/A
*/
const char *
wrnad_pfkey_typestr(int type)
{
switch (type)
{
case SADB_RESERVED:
return "SADB_RESERVED";
case SADB_GETSPI:
return "SADB_GETSPI";
case SADB_UPDATE:
return "SADB_UPDATE";
case SADB_ADD:
return "SADB_ADD";
case SADB_DELETE:
return "SADB_DELETE";
case SADB_GET:
return "SADB_GET";
case SADB_ACQUIRE:
return "SADB_ACQUIRE";
case SADB_REGISTER:
return "SADB_REGISTER";
case SADB_EXPIRE:
return "SADB_EXPIRE";
case SADB_FLUSH:
return "SADB_FLUSH";
case SADB_DUMP:
return "SADB_DUMP";
case SADB_X_PROMISC:
return "SADB_X_PROMISC";
case SADB_X_SPDADD:
return "SADB_X_SPDADD";
case SADB_X_SPDDELETE:
return "SADB_X_SPDDELETE";
case SADB_X_SPDFLUSH:
return "SADB_X_SPDFLUSH";
/* Linux native */
#ifndef IPWRNAD
case SADB_X_PCHANGE:
return "SADB_X_PCHANGE";
case SADB_X_SPDUPDATE:
return "SADB_X_SPDUPDATE";
case SADB_X_SPDGET:
return "SADB_X_SPDGET";
case SADB_X_SPDACQUIRE:
return "SADB_X_SPDACQUIRE";
case SADB_X_SPDDUMP:
return "SADB_X_SPDDUMP";
case SADB_X_SPDSETIDX:
return "SADB_X_SPDSETIDX";
case SADB_X_SPDEXPIRE:
return "SADB_X_SPDEXPIRE";
case SADB_X_SPDDELETE2:
return "SADB_X_SPDDELETE2";
case SADB_X_NAT_T_NEW_MAPPING:
return "SADB_X_NAT_T_NEW_MAPPING";
#endif /* ifndef IPWRNAD */
/* Interpeak BSD-versions */
#ifdef SADB_X_ADDFLOW
case SADB_X_ADDFLOW:
return "SADB_X_ADDFLOW";
#endif
#ifdef SADB_X_DELFLOW
case SADB_X_DELFLOW:
return "SADB_X_DELFLOW";
#endif
#ifdef SADB_X_GRPSPIS
case SADB_X_GRPSPIS:
return "SADB_X_GRPSPIS";
#endif
#ifdef SADB_X_BINDSA
case SADB_X_BINDSA:
return "SADB_X_BINDSA";
#endif
#ifdef SADB_X_FINDFLOW
case SADB_X_FINDFLOW:
return "SADB_X_FINDFLOW";
#endif
#ifdef SADB_X_DUMPFLOW
case SADB_X_DUMPFLOW:
return "SADB_X_DUMPFLOW";
#endif
#ifdef SADB_X_MIGRATE
case SADB_X_MIGRATE:
return "SADB_X_MIGRATE";
#endif
/* Unknown */
default:
return "UNKNOWN";
}
}
/*******************************************************************************
*
* wrnad_pfkey_satypestr - find pfkey sa type in string format
*
* This routine returns the pfkey message sa type as a string
*
* RETURNS: string representation of pfkey message sa type.
*
* ERRNO: N/A
*/
static const char *
wrnad_pfkey_satypestr(int type)
{
switch (type)
{
case SADB_SATYPE_UNSPEC:
return "UNSPEC";
case SADB_SATYPE_AH:
return "AH";
case SADB_SATYPE_ESP:
return "ESP";
case SADB_SATYPE_RSVP:
return "RSVP";
case SADB_SATYPE_OSPFV2:
return "OSPFV2";
case SADB_SATYPE_RIPV2:
return "RIPV2";
case SADB_SATYPE_MIP:
return "MIP";
#ifdef SADB_X_SATYPE_IPCOMP
case SADB_X_SATYPE_IPCOMP:
return "IPCOMP";
#endif
default:
return "UNKNOWN";
}
}
/*******************************************************************************
*
* wrnad_pfkey_sastatestr - find pfkey sa state in string format
*
* This routine returns the pfkey message sa state as a string
*
* RETURNS: string representation of pfkey message sa state.
*
* ERRNO: N/A
*/
static const char *
wrnad_pfkey_sastatestr(int state)
{
switch (state)
{
case SADB_SASTATE_LARVAL:
return "LARVAL";
case SADB_SASTATE_MATURE:
return "MATURE";
case SADB_SASTATE_DYING:
return "DYING";
case SADB_SASTATE_DEAD:
return "DEAD";
default:
return "UNKNOWN";
}
}
/*******************************************************************************
*
* wrnad_pfkey_saaalgstr - find pfkey sa aalg in string format
*
* This routine returns the pfkey message sa aalg as a string
*
* RETURNS: string representation of pfkey message sa aalg.
*
* ERRNO: N/A
*/
static const char *
wrnad_pfkey_saaalgstr(int aalg)
{
switch (aalg)
{
case SADB_AALG_NONE:
return "NONE";
case SADB_AALG_MD5HMAC:
return "MD5HMAC";
case SADB_AALG_SHA1HMAC:
return "SHA1HMAC";
#ifdef SADB_X_AALG_SHA2_256HMAC
case SADB_X_AALG_SHA2_256HMAC:
return "SHA2_256HMAC";
#endif
#ifdef SADB_X_AALG_SHA2_384HMAC
case SADB_X_AALG_SHA2_384HMAC:
return "SHA2_384HMAC";
#endif
#ifdef SADB_X_AALG_SHA2_512HMAC
case SADB_X_AALG_SHA2_512HMAC:
return "SHA2_512HMAC";
#endif
#ifdef SADB_X_AALG_RIPEMD160HMAC
case SADB_X_AALG_RIPEMD160HMAC:
return "RIPEMD160HMAC";
#endif
#ifdef SADB_X_AALG_AES_XCBC_MAC
case SADB_X_AALG_AES_XCBC_MAC:
return "AES_XCBC_MAC";
#endif
#ifdef SADB_X_AALG_NULL
case SADB_X_AALG_NULL:
return "NULL";
#endif
default:
return "UNKNOWN";
}
}
/*******************************************************************************
*
* wrnad_pfkey_saealgstr - find pfkey sa ealg in string format
*
* This routine returns the pfkey message sa ealg as a string
*
* RETURNS: string representation of pfkey message sa ealg.
*
* ERRNO: N/A
*/
static const char *
wrnad_pfkey_saealgstr(int ealg)
{
switch (ealg)
{
case SADB_EALG_NONE:
return "NONE";
case SADB_EALG_DESCBC:
return "DESCBC";
case SADB_EALG_3DESCBC:
return "3DESCBC";
#ifndef IPWRNAD
case SADB_X_EALG_CASTCBC:
return "CASTCBC";
case SADB_X_EALG_BLOWFISHCBC:
return "BLOWFISHCBC";
case SADB_EALG_NULL:
return "NULL";
#endif
case SADB_X_EALG_AESCBC:
return "AESCBC";
#ifdef SADB_X_EALG_AESCTR
case SADB_X_EALG_AESCTR:
return "AESCTR";
#ifndef IPWRNAD
case SADB_X_EALG_AES_CCM_ICV8:
return "AES_CCM_ICV8";
case SADB_X_EALG_AES_CCM_ICV12:
return "AES_CCM_ICV12";
case SADB_X_EALG_AES_CCM_ICV16:
return "AES_CCM_ICV16";
case SADB_X_EALG_AES_GCM_ICV8:
return "AES_GCM_ICV8";
case SADB_X_EALG_AES_GCM_ICV12:
return "AES_GCM_ICV12";
case SADB_X_EALG_AES_GCM_ICV16:
return "AES_GCM_ICV16";
case SADB_X_EALG_CAMELLIACBC:
return "CAMELLIACBC";
#endif
#endif /* SADB_X_EALG_AESCTR */
default:
return "UNKNOWN";
}
}
/*******************************************************************************
*
* wrnad_pfkey_exttypestr - find pfkey extension header type in string format
*
* This routine returns the pfkey extension header type as a string
*
* RETURNS: string representation of pfkey extension header type.
*
* ERRNO: N/A
*/
static const char *
wrnad_pfkey_exttypestr(int type)
{
switch (type)
{
case SADB_EXT_RESERVED:
return "SADB_EXT_RESERVED";
case SADB_EXT_SA:
return "SADB_EXT_SA";
case SADB_EXT_LIFETIME_CURRENT:
return "SADB_EXT_LIFETIME_CURRENT";
case SADB_EXT_LIFETIME_HARD:
return "SADB_EXT_LIFETIME_HARD";
case SADB_EXT_LIFETIME_SOFT:
return "SADB_EXT_LIFETIME_SOFT";
case SADB_EXT_ADDRESS_SRC:
return "SADB_EXT_ADDRESS_SRC";
case SADB_EXT_ADDRESS_DST:
return "SADB_EXT_ADDRESS_DST";
case SADB_EXT_ADDRESS_PROXY:
return "SADB_EXT_ADDRESS_PROXY";
case SADB_EXT_KEY_AUTH:
return "SADB_EXT_KEY_AUTH";
case SADB_EXT_KEY_ENCRYPT:
return "SADB_EXT_KEY_ENCRYPT";
case SADB_EXT_IDENTITY_SRC:
return "SADB_EXT_IDENTITY_SRC";
case SADB_EXT_IDENTITY_DST:
return "SADB_EXT_IDENTITY_DST";
case SADB_EXT_SENSITIVITY:
return "SADB_EXT_SENSITIVITY";
case SADB_EXT_PROPOSAL:
return "SADB_EXT_PROPOSAL";
case SADB_EXT_SPIRANGE:
return "SADB_EXT_SPIRANGE";
case SADB_X_EXT_POLICY:
return "SADB_X_EXT_POLICY";
/* Linux */
#ifndef IPWRNAD
case SADB_EXT_SUPPORTED_AUTH:
return "SADB_EXT_SUPPORTED_AUTH";
case SADB_EXT_SUPPORTED_ENCRYPT:
return "SADB_EXT_SUPPORTED_ENCRYPT";
case SADB_X_EXT_KMPRIVATE:
return "SADB_X_EXT_KMPRIVATE";
case SADB_X_EXT_NAT_T_TYPE:
return "SADB_X_EXT_NAT_T_TYPE";
case SADB_X_EXT_NAT_T_SPORT:
return "SADB_X_EXT_NAT_T_SPORT";
case SADB_X_EXT_NAT_T_DPORT:
return "SADB_X_EXT_NAT_T_DPORT";
case SADB_X_EXT_NAT_T_OA:
return "SADB_X_EXT_NAT_T_OA";
#endif /* ifndef IPWRNAD */
/* Optional */
#ifdef SADB_X_EXT_SEC_CTX
case SADB_X_EXT_SEC_CTX:
return "SADB_X_EXT_SEC_CTX";
#endif
#ifdef SADB_X_EXT_KMADDRESS
case SADB_X_EXT_KMADDRESS:
return "SADB_X_EXT_KMADDRES";
#endif
/* Interpeak/BSD */
#ifdef SADB_X_EXT_SRC_MASK
case SADB_X_EXT_SRC_MASK:
return "SADB_X_EXT_SRC_MASK";
#endif
#ifdef SADB_X_EXT_DST_MASK
case SADB_X_EXT_DST_MASK:
return "SADB_X_EXT_DST_MASK";
#endif
#ifdef SADB_X_EXT_PROTOCOL
case SADB_X_EXT_PROTOCOL:
return "SADB_X_EXT_PROTOCOL";
#endif
#ifdef SADB_X_EXT_SA2
case SADB_X_EXT_SA2:
return "SADB_X_EXT_SA2";
#endif
#ifdef SADB_X_EXT_SRC_FLOW
case SADB_X_EXT_SRC_FLOW:
return "SADB_X_EXT_SRC_FLOW";
#endif
#ifdef SADB_X_EXT_DST_FLOW
case SADB_X_EXT_DST_FLOW:
return "SADB_X_EXT_DST_FLOW";
#endif
#ifdef SADB_X_EXT_DST2
case SADB_X_EXT_DST2:
return "SADB_X_EXT_DST2";
#endif
#ifdef SADB_X_EXT_FLOW_OPTIONS
case SADB_X_EXT_FLOW_OPTIONS:
return "SADB_X_EXT_FLOW_OPTIONS";
#endif
#ifdef SADB_X_EXT_UDPENCAP
case SADB_X_EXT_UDPENCAP:
return "SADB_X_EXT_UDPENCAP";
#endif
#ifdef SADB_X_EXT_SRCMAX_FLOW
case SADB_X_EXT_SRCMAX_FLOW:
return "SADB_X_EXT_SRCMAX_FLOW";
#endif
#ifdef SADB_X_EXT_DSTMAX_FLOW
case SADB_X_EXT_DSTMAX_FLOW:
return "SADB_X_EXT_DSTMAX_FLOW";
#endif
#ifdef SADB_X_EXT_SA_OPTIONS
case SADB_X_EXT_SA_OPTIONS:
return "SADB_X_EXT_SA_OPTIONS";
#endif
default:
return "UNKNOWN";
}
}
/*******************************************************************************
*
* wrnad_pfkey_policy_typestr - find pfkey policy type in string format
*
* This routine returns the pfkey policy type as a string
*
* RETURNS: string representation of pfkey policy type message.
*
* ERRNO: N/A
*/
static const char *
wrnad_pfkey_policy_typestr(int type)
{
switch (type)
{
case IPSEC_POLICY_DISCARD:
return "DISCARD";
case IPSEC_POLICY_NONE:
return "NONE";
case IPSEC_POLICY_IPSEC:
return "IPSEC";
case IPSEC_POLICY_ENTRUST:
return "ENTRUST";
case IPSEC_POLICY_BYPASS:
return "BYPASS";
default:
return "UNKNOWN";
}
}
/*******************************************************************************
*
* wrnad_pfkey_policy_dirstr - find pfkey policy dir in string format
*
* This routine returns the pfkey policy dir as a string
*
* RETURNS: string representation of pfkey policy dir message.
*
* ERRNO: N/A
*/
static const char *
wrnad_pfkey_policy_dirstr(int dir)
{
switch (dir)
{
case IPSEC_DIR_ANY:
return "ANY";
case IPSEC_DIR_INBOUND:
return "INBOUND";
case IPSEC_DIR_OUTBOUND:
return "OUTBOUND";
case IPSEC_DIR_FWD:
return "FWD";
case IPSEC_DIR_MAX:
return "MAX";
case IPSEC_DIR_INVALID:
return "INVALID";
default:
return "UNKNOWN";
}
}
/*******************************************************************************
*
* wrnad_pfkey_ipsecrequest_modestr - find pfkey ipsecrequest mode in string format
*
* This routine returns the pfkey ipsecrequest mode as a string
*
* RETURNS: string representation of pfkey ipsecrequest mode message.
*
* ERRNO: N/A
*/
static const char *
wrnad_pfkey_ipsecrequest_modestr(int mode)
{
switch (mode)
{
case IPSEC_MODE_ANY:
return "ANY";
case IPSEC_MODE_TRANSPORT:
return "TRANSPORT";
case IPSEC_MODE_TUNNEL:
return "TUNNEL";
case IPSEC_MODE_BEET:
return "BEET";
default:
return "UNKNOWN";
}
}
/*******************************************************************************
*
* wrnad_pfkey_ipsecrequest_levelstr - find pfkey ipsecrequest level in string format
*
* This routine returns the pfkey ipsecrequest level as a string
*
* RETURNS: string representation of pfkey ipsecrequest level message.
*
* ERRNO: N/A
*/
static const char *
wrnad_pfkey_ipsecrequest_levelstr(int level)
{
switch (level)
{
case IPSEC_LEVEL_DEFAULT:
return "DEFAULT";
case IPSEC_LEVEL_USE:
return "USE";
case IPSEC_LEVEL_REQUIRE:
return "TUNNEL";
case IPSEC_LEVEL_UNIQUE:
return "UNIQUE";
default:
return "UNKNOWN";
}
}
/*******************************************************************************
*
* wrnad_pfkey_parse_extensions - parse PF_KEY extension headers
*
* This routine parses PF_KEY extension headers
*
* RETURNS: 0 if exited normally, else -1.
*
* ERRNO: N/A
*/
static int
wrnad_pfkey_parse_extensions(struct sadb_msg *msg)
{
struct sadb_ext *ext;
struct sadb_sa *sa;
struct sadb_lifetime *lifetime;
struct sadb_address *address;
struct sockaddr *sockaddr;
struct sadb_key *key;
struct sadb_x_policy *policy;
struct sadb_x_ipsecrequest *request;
int extlen, i;
char buf[64];
unsigned char *p;
extlen = (msg->sadb_msg_len << 3) - sizeof(struct sadb_msg);
ext = (struct sadb_ext *)((char *)msg + sizeof(struct sadb_msg));
while (extlen > 0)
{
if (!ext->sadb_ext_len || extlen < (ext->sadb_ext_len << 3))
{
wrnad_log(LOG_WARNING, "pfkey extension header length is invalid. sadb_ext_len=%d total=%d", ext->sadb_ext_len, extlen);
return -1;
}
switch (ext->sadb_ext_type)
{
case SADB_EXT_SA:
case SADB_X_EXT_SA2:
sa = (struct sadb_sa *)ext;
if ((sa->sadb_sa_len << 3) != sizeof(struct sadb_sa))
{
wrnad_log(LOG_WARNING, "pfkey association extension length %d is invalid", sa->sadb_sa_len);
return -1;
}
wrnad_log(LOG_DEBUG, "Pfkey association extension: len=%u, type=%s, spi=0x%x, replay=%u, state=%s, auth=%s, encrypt=%s, flags=0x%x",
sa->sadb_sa_len,
wrnad_pfkey_exttypestr(sa->sadb_sa_exttype),
ntohl(sa->sadb_sa_spi),
sa->sadb_sa_replay,
wrnad_pfkey_sastatestr(sa->sadb_sa_state),
wrnad_pfkey_saaalgstr(sa->sadb_sa_auth),
wrnad_pfkey_saealgstr(sa->sadb_sa_encrypt),
sa->sadb_sa_flags);
break;
case SADB_EXT_LIFETIME_HARD:
case SADB_EXT_LIFETIME_SOFT:
case SADB_EXT_LIFETIME_CURRENT:
lifetime = (struct sadb_lifetime *)ext;
if ((lifetime->sadb_lifetime_len << 3) != sizeof(struct sadb_lifetime))
{
wrnad_log(LOG_WARNING, "pfkey lifetime extension length %d is invalid", lifetime->sadb_lifetime_len);
return -1;
}
wrnad_log(LOG_DEBUG, "Pfkey lifetime extension: len=%u, type=%s allocations=%u bytes=%u addtime=%u usetime=%u",
lifetime->sadb_lifetime_len,
wrnad_pfkey_exttypestr(lifetime->sadb_lifetime_exttype),
lifetime->sadb_lifetime_allocations,
lifetime->sadb_lifetime_bytes,
lifetime->sadb_lifetime_addtime,
lifetime->sadb_lifetime_usetime);
break;
case SADB_EXT_ADDRESS_SRC:
case SADB_EXT_ADDRESS_DST:
case SADB_EXT_ADDRESS_PROXY:
#ifdef SADB_X_EXT_SRC_MASK
case SADB_X_EXT_SRC_MASK:
#endif
#ifdef SADB_X_EXT_DST_MASK
case SADB_X_EXT_DST_MASK:
#endif
#ifdef SADB_X_EXT_SRC_FLOW
case SADB_X_EXT_SRC_FLOW:
#endif
#ifdef SADB_X_EXT_DST_FLOW
case SADB_X_EXT_DST_FLOW:
#endif
#ifdef SADB_X_EXT_DST2
case SADB_X_EXT_DST2:
#endif
#ifdef SADB_X_EXT_SRCMAX_FLOW
case SADB_X_EXT_SRCMAX_FLOW:
#endif
#ifdef SADB_X_EXT_DSTMAX_FLOW
case SADB_X_EXT_DSTMAX_FLOW:
#endif
address = (struct sadb_address *)ext;
if ((address->sadb_address_len << 3) < (unsigned short)sizeof(struct sadb_address) + (unsigned short)sizeof(struct sockaddr_in))
{
wrnad_log(LOG_WARNING, "Pfkey address extension length %d is invalid", address->sadb_address_len);
return -1;
}
wrnad_log(LOG_DEBUG, "Pfkey address extension: len=%u, type=%s proto=%u prefixlen=%u reserved=%u",
address->sadb_address_len,
wrnad_pfkey_exttypestr(address->sadb_address_exttype),
address->sadb_address_proto,
address->sadb_address_prefixlen,
address->sadb_address_reserved);
sockaddr = (struct sockaddr *)(address + 1);
if (sockaddr->sa_family == AF_INET)
{
struct sockaddr_in *sockaddr_in;
sockaddr_in = (struct sockaddr_in *)sockaddr;
if (inet_ntop(sockaddr_in->sin_family, &sockaddr_in->sin_addr, buf, sizeof(buf)) != NULL)
{
wrnad_log(LOG_DEBUG, "Socket address: family=%u, port=%u address=%s",
sockaddr_in->sin_family,
ntohs(sockaddr_in->sin_port),
buf);
}
}
break;
case SADB_EXT_KEY_AUTH:
case SADB_EXT_KEY_ENCRYPT:
key = (struct sadb_key *)ext;
if ((key->sadb_key_len << 3) < (unsigned short)sizeof(struct sadb_key))
{
wrnad_log(LOG_WARNING, "Pfkey key extension length %d is invalid", key->sadb_key_len);
return -1;
}
wrnad_log(LOG_DEBUG, "Pfkey key extension: len=%u, type=%s bits=%u reserved=%u",
key->sadb_key_len,
wrnad_pfkey_exttypestr(key->sadb_key_exttype),
key->sadb_key_bits,
key->sadb_key_reserved);
if ((key->sadb_key_len << 3) < (unsigned short)sizeof(struct sadb_key) + (key->sadb_key_bits >> 3))
{
wrnad_log(LOG_WARNING, "Pfkey key extension length %d is invalid", key->sadb_key_len);
return -1;
}
p = (unsigned char *)(key + 1);
for (i=0; i<(key->sadb_key_bits >> 3); i++)
{
if (i < (int)sizeof(buf))
sprintf(&buf[i<<1], "%02x", p[i]);
}
wrnad_log(LOG_DEBUG, "Key: %s", buf);
break;
case SADB_X_EXT_POLICY:
policy = (struct sadb_x_policy *)ext;
if ((policy->sadb_x_policy_len << 3) < (unsigned short)sizeof(struct sadb_x_policy) + (unsigned short)sizeof(struct sadb_x_ipsecrequest))
{
wrnad_log(LOG_WARNING, "Pfkey policy extension length %d is invalid", policy->sadb_x_policy_len);
return -1;
}
wrnad_log(LOG_DEBUG, "Pfkey policy extension: len=%u type=%s policytype=%s dir=%s reserved=%u id=%u prio=%u",
policy->sadb_x_policy_len,
wrnad_pfkey_exttypestr(policy->sadb_x_policy_exttype),
wrnad_pfkey_policy_typestr(policy->sadb_x_policy_type),
wrnad_pfkey_policy_dirstr(policy->sadb_x_policy_dir),
policy->sadb_x_policy_reserved,
policy->sadb_x_policy_id,
policy->sadb_x_policy_priority);
request = (struct sadb_x_ipsecrequest *)(policy + 1);
wrnad_log(LOG_DEBUG, "Pfkey ipsec request extension: len=%u proto=%s mode=%s level=%s",
request->sadb_x_ipsecrequest_len,
request->sadb_x_ipsecrequest_proto == IPPROTO_AH ? "AH" : "ESP",
wrnad_pfkey_ipsecrequest_modestr(request->sadb_x_ipsecrequest_mode),
wrnad_pfkey_ipsecrequest_levelstr(request->sadb_x_ipsecrequest_level));
break;
default:
wrnad_log(LOG_DEBUG, "Pfkey extension header: len=%u, type=%s(%d)",
ext->sadb_ext_len,
wrnad_pfkey_exttypestr(ext->sadb_ext_type),
ext->sadb_ext_type);
break;
}
extlen -= ext->sadb_ext_len << 3;
ext = (struct sadb_ext *)((char *)ext + (ext->sadb_ext_len << 3));
}
return 0;
}
/*******************************************************************************
*
* wrnad_pfkey_sa_handler - pfkey handler for SA messages
*
* This routine handles pfkey SA messages.
*
* RETURNS: -1 = failed
* 0 = skip
* 1 = action
*
* ERRNO: N/A
*/
static int
wrnad_pfkey_sa_handler(struct sadb_msg *msg)
{
int ret;
ret = wrnad_pfkey_parse_extensions(msg);
if (ret == 0)
ret = 1;
return ret;
}
/*******************************************************************************
*
* wrnad_pfkey_spd_handler - pfkey handler for SPD messages
*
* This routine handles pfkey SA messages.
*
* RETURNS: -1 = failed
* 0 = skip
* 1 = action
*
* ERRNO: N/A
*/
static int
wrnad_pfkey_spd_handler(struct sadb_msg *msg)
{
int ret;
ret = wrnad_pfkey_parse_extensions(msg);
if (ret == 0)
ret = 1;
return ret;
}
/*******************************************************************************
*
* wrnad_pfkey_find_handler - find pfkey handler
*
* This routine returns a handler form the pfkey message type.
*
* RETURNS: handler or NULL if not found
*
* ERRNO: N/A
*/
static wrnad_pfkey_handler
wrnad_pfkey_find_handler(struct sadb_msg *msg)
{
switch (msg->sadb_msg_type)
{
/* SA's */
case SADB_ADD:
case SADB_DELETE:
case SADB_FLUSH:
#ifdef SADB_X_GRPSPIS
case SADB_X_GRPSPIS:
#endif
return wrnad_pfkey_sa_handler;
/* Flows */
case SADB_X_SPDADD:
case SADB_X_SPDDELETE:
case SADB_X_SPDFLUSH:
#ifdef SADB_X_ADDFLOW
case SADB_X_ADDFLOW:
#endif
#ifdef SADB_X_DELFLOW
case SADB_X_DELFLOW:
#endif
return wrnad_pfkey_spd_handler;
default:
return NULL;
}
}
/*******************************************************************************
*
* wrnad_pfkey_parse - parse message received on pfkey socket
*
* This routine parses indivudual messages received on a pfkey socket
*
* RETURNS: 0 if exited normally, else -1.
*
* ERRNO: N/A
*/
static int
wrnad_pfkey_parse(int fd, struct sadb_msg *msg)
{
wrnad_pfkey_handler f;
int ret;
/* Find handler */
if ((f = wrnad_pfkey_find_handler(msg)))
{
ret = f(msg);
if (ret == 1)
{
/* Send pfkey message over MIPC */
msg->sadb_msg_seq = 0x80000000;
/* Linux does not always seem to clear the reserved field */
msg->sadb_msg_reserved = 0;
ret = wrnad_mipc_send_pfkey(fd, msg);
}
return ret;
}
else
{
wrnad_log(LOG_DEBUG, "No handler found for pfkey message type %d (%s)",
msg->sadb_msg_type, wrnad_pfkey_typestr(msg->sadb_msg_type));
return -1;
}
}
/*******************************************************************************
*
* wrnad_pfkey_scan - scan message received on pfkey socket
*
* This routine scans messages received on a pfkey socket
*
* RETURNS: 0 if exited normally, else -1.
*
* ERRNO: N/A
*/
static int
wrnad_pfkey_scan(char *buf, int buflen, int fd)
{
struct sadb_msg *msg;
msg = (struct sadb_msg *)buf;
if (buflen >= (int)sizeof(*msg) && buflen == (msg->sadb_msg_len << 3))
{
wrnad_log(LOG_DEBUG, "Pfkey base header: version=%u, type=%s, errno=%u, satype=%s, len=%u, reserved=%u, seq=%u, pid=%u",
msg->sadb_msg_version,
wrnad_pfkey_typestr(msg->sadb_msg_type),
msg->sadb_msg_errno,
wrnad_pfkey_satypestr(msg->sadb_msg_satype),
msg->sadb_msg_len,
msg->sadb_msg_reserved,
msg->sadb_msg_seq,
msg->sadb_msg_pid);
if (msg->sadb_msg_version == PF_KEY_V2)
{
if (wrnad_pfkey_parse(fd, msg) >= 0)
{
wrnad_log(LOG_DEBUG, "Pfkey message type %s handled ok.",
wrnad_pfkey_typestr(msg->sadb_msg_type));
}
}
}
else
{
wrnad_log(LOG_WARNING, "Pfkey message broken! Length was %d.", buflen);
return -1;
}
return 0;
}
/*******************************************************************************
*
* wrnad_pfkey_close - close pfkey socket
*
* This routine closes a pfkey socket
*
* RETURNS: N/A
*
* ERRNO: N/A
*/
void
wrnad_pfkey_close(int fd)
{
if (fd >= 0)
close(fd);
}
/*******************************************************************************
*
* wrnad_pfkey_open - open and register pfkey socket
*
* This routine opens a rtnetlink socket and binds it.
*
* RETURNS: socket descriptor if exited normally, else -1.
*
* ERRNO: N/A
*/
int
wrnad_pfkey_open(void)
{
int fd, ret;
struct sadb_msg msg;
fd = socket(PF_KEY, SOCK_RAW, PF_KEY_V2);
if (fd < 0)
{
wrnad_log(LOG_ERR, "Failed to open pfkey socket!");
return -1;
}
wrnad_log(LOG_DEBUG, "Pfkey socket %d created.", fd);
msg.sadb_msg_version = PF_KEY_V2;
msg.sadb_msg_type = SADB_REGISTER;
msg.sadb_msg_errno = 0;
msg.sadb_msg_satype = SADB_SATYPE_ESP;
msg.sadb_msg_len = sizeof(msg) >> 3;
msg.sadb_msg_reserved = 0;
msg.sadb_msg_seq = 0;
msg.sadb_msg_pid = getpid();
ret = send(fd, &msg, sizeof(msg), 0);
if (ret < 0)
{
wrnad_log(LOG_ERR, "Failed to register for SATYPE ESP!");
return -1;
}
msg.sadb_msg_version = PF_KEY_V2;
msg.sadb_msg_type = SADB_REGISTER;
msg.sadb_msg_errno = 0;
msg.sadb_msg_satype = SADB_SATYPE_AH;
msg.sadb_msg_len = sizeof(msg) >> 3;
msg.sadb_msg_reserved = 0;
msg.sadb_msg_seq = 0;
msg.sadb_msg_pid = getpid();
ret = send(fd, &msg, sizeof(msg), 0);
if (ret < 0)
{
wrnad_log(LOG_ERR, "Failed to register for SATYPE AH!");
return -1;
}
return fd;
}
/*******************************************************************************
*
* wrnad_pfkey_recv - recv on a pfkey socket
*
* This routine receives messages on a pfkey socket
*
* RETURNS: 0 if exited normally, else -1.
*
* ERRNO: N/A
*/
int
wrnad_pfkey_recv(int pfkeyfd, int mipcfd)
{
int len;
len = recv(pfkeyfd, recvbuf, sizeof(recvbuf), 0);
if (len < 0)
{
wrnad_log(LOG_ERR, "Recv on pfkey socket %d interrupted by error %s -> exit.", pfkeyfd, strerror(errno));
return -1;
}
else if (len == 0)
{
wrnad_log(LOG_ERR, "Recv on pfkey socket %d interrupted by EOF.", pfkeyfd);
return -1;
}
wrnad_log(LOG_DEBUG, "Recv on pfkey socket %d returned %d bytes of data.", pfkeyfd, len);
/* Scan receive message */
if (wrnad_pfkey_scan(recvbuf, len, mipcfd) < 0)
wrnad_log(LOG_WARNING, "Pfkey message failed scan!\n");
else
wrnad_log(LOG_DEBUG, "Pfkey message scanned ok.\n");
return 0;
}
#endif /* !IPWRNAD || IPIPSEC2 */