1073 lines
28 KiB
C
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 */
|