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

3826 lines
133 KiB
C

/*
******************************************************************************
* INTERPEAK SOURCE FILE
*
* Document no: @(#) $Name: VXWORKS_ITER40_RCPL8_2024030303 $ $RCSfile: ipipsec_cmd_keyadm.c,v $ $Revision: 1.64.2.13 $
* $Source: /home/interpeak/CVSRoot/ipipsec2/src/ipipsec_cmd_keyadm.c,v $
* $Author: jren $
* $State: Exp $ $Locker: $
*
* INTERPEAK_COPYRIGHT_STRING
* Design and implementation by Lennart Bang <lob@interpeak.se>
******************************************************************************
*/
/*
****************************************************************************
* 1 DESCRIPTION.
****************************************************************************
*/
/*
****************************************************************************
* 2 CONFIGURATION
****************************************************************************
*/
#ifdef IPCOM_KERNEL
#undef IPCOM_KERNEL
#endif
#include "ipipsec_config.h"
#define IPCOM_USE_CLIB_PROTO
#include "ipipsec_h.h"
/*
****************************************************************************
* 3 INCLUDE FILES.
****************************************************************************
*/
/* IPCOM */
#include <ipcom_clib.h>
#if IPCOM_USE_SHELL != IPCOM_SHELL_NONE || defined(IP_PORT_LAS)
#include <ipcom_clib2.h>
#endif
#include <ipcom_sock.h>
#include <ipcom_inet.h>
#include <ipcom_os.h>
#include <ipcom_tags.h>
#include <ipcom_getopt.h>
#include <ipcom_sysvar.h>
#include <ipcom_syslog.h>
#include <ipcom_cmd.h>
/* Interpeak IPSEC */
#include "ipipsec.h"
#include "ipipsec_pfkeyv2.h"
/*
****************************************************************************
* 4 MACROS/TYPES
****************************************************************************
*/
/* Should not be evenly dividable by 8 in order to detect truncated SADB messages */
#define MAX_RCVBUF_SIZE (2048 - 1)
#define IPCOM_SYSLOG_PRIORITY IPIPSEC_SYSTEM_PRIORITY
#define IPCOM_SYSLOG_FACILITY IPCOM_LOG_IPIPSEC
/*
****************************************************************************
* 5 TYPES
****************************************************************************
*/
/*
*===========================================================================
* sadb_address_full
*===========================================================================
*/
struct sadb_address_full
{
struct sadb_address addr;
union Ip_sockaddr_union sock;
Ip_u8 pad[8];
};
/*
*===========================================================================
* Ipipsec_sadb_extbits
*===========================================================================
*/
typedef struct Extbits_struct
{
Ip_u64 in_req;
}
Extbits;
/*
*===========================================================================
* Variables - Vars
*===========================================================================
*/
typedef struct Vars_struct
{
int argc;
char **argv;
Ip_fd fd;
void *exthdr[SADB_EXT_MAX+1];
Ipipsec_pfkeyv2_sadb *sadb;
struct sadb_msg sadbmsg;
Ip_u8 *orgbuf;
char *stdoutbuf;
Ip_u8 *msgbuf;
/* options */
Ip_u32 minspi, maxspi;
Ip_u32 spi_n, spi2_n;
union Ip_sockaddr_union srcaddr;
union Ip_sockaddr_union dstaddr;
union Ip_sockaddr_union proxyaddr;
union Ip_sockaddr_union srctunnel;
union Ip_sockaddr_union dsttunnel;
union Ip_sockaddr_union dstaddr2;
Ip_s8 satype, satype2;
Ip_u8 have_satype;
Ip_u8 flow_type;
Ip_u8 dscp;
Ip_u32 flow_id;
union Ip_sockaddr_union srcmask;
union Ip_sockaddr_union dstmask;
union Ip_sockaddr_union srcflow;
union Ip_sockaddr_union dstflow;
union Ip_sockaddr_union srcmaxflow;
union Ip_sockaddr_union dstmaxflow;
union Ip_sockaddr_union zeroaddr;
Ip_u16 dstport_n, srcport_n;
Ip_u16 dstmaxport_n, srcmaxport_n;
Ip_u16 udpencap_port; /*NOTE: port in host endian! */
Ip_u8 transport_proto;
Ip_u8 have_transport_proto;
Ip_u8 ports0, ports1;
int replay;
int flow_priority, sa_priority;
Ip_u32 ls_sec, lh_sec;
Ip_u64 ls_bytes, lh_bytes;
Ip_u8 encrypt_type;
Ip_u8 encrypt_bytes;
struct sadb_key encrypt_sadb;
Ip_u8 encrypt_key[128];
Ip_u8 auth_type;
Ip_u8 auth_bytes;
struct sadb_key auth_sadb;
Ip_u8 auth_key[IPIPSEC_AUTH_MAXKEYLEN];
Ip_u32 test;
Ip_u64 extmap;
int syslog, silent, count;
Ip_u32 sa_flags;
Ip_u32 timeout_seconds;
#ifdef IPIPSEC_USE_LINUX_PFKEYV2_API
Ip_bool is_linux;
Ip_u32 reqid; /* For unique mode (-u setkey option) */
#endif
}
Vars;
/*
*===========================================================================
* Command
*===========================================================================
*/
typedef struct Command_struct
{
char *name;
int (*func)(Vars *vars);
void (*usage)(Vars *vars);
int type;
}
Command;
/*
*===========================================================================
* Ctrl
*===========================================================================
*/
#define CTRL_GET 1
#define CTRL_SET 2
typedef struct Ctrl_struct
{
char *name;
Ip_tag id;
Ip_u32 mode; /* 1=get, 2=set, 3=get&set */
}
Ctrl;
/*
****************************************************************************
* 6 PROTOTYPES.
****************************************************************************
*/
IP_EXTERN IP_CONST char *ipipsec_pfkeyv2_command[SADB_MAX + 2];
IP_EXTERN int ipipsec_pfkeyv2_ext_size[SADB_EXT_MAX+1];
IP_PUBLIC int ipipsec_cmd_keyadm(int argc, char **argv);
static int keyadm_dump(Vars *vars);
static int keyadm_getspi(Vars *vars);
static int keyadm_flush(Vars *vars);
static int keyadm_get(Vars *vars);
static int keyadm_update(Vars *vars);
static int keyadm_add(Vars *vars);
static int keyadm_delete(Vars *vars);
static int keyadm_addflow(Vars *vars);
static int keyadm_delflow(Vars *vars);
static int keyadm_grpspis(Vars *vars);
static int keyadm_findflow(Vars *vars);
static int keyadm_dumpflow(Vars *vars);
static int keyadm_monitor(Vars *vars);
static int keyadm_register(Vars *vars);
static void keyadm_add_usage(Vars *vars);
static void keyadm_delete_usage(Vars *vars);
static void keyadm_get_usage(Vars *vars);
static void keyadm_grpspis_usage(Vars *vars);
static void keyadm_getspi_usage(Vars *vars);
static void keyadm_update_usage(Vars *vars);
static void keyadm_addflow_usage(Vars *vars);
static void keyadm_delflow_usage(Vars *vars);
static void keyadm_findflow_usage(Vars *vars);
static IP_CONST char *
keyadm_cmd_bits_to_str(char **map, Ip_u32 bits, char *str, Ip_size_t str_len);
#ifdef IPIPSEC_USE_LINUX_PFKEYV2_API
static int keyadm_spdadd(Vars *vars);
static void keyadm_spdadd_usage(Vars *vars);
static int keyadm_spdupdate(Vars *vars);
static void keyadm_spdupdate_usage(Vars *vars);
static int keyadm_spddelete(Vars *vars);
static void keyadm_spddelete_usage(Vars *vars);
static int keyadm_spdflush(Vars *vars);
#endif /* #ifdef IPIPSEC_USE_LINUX_PFKEYV2_API */
/*
****************************************************************************
* 7 DATA.
****************************************************************************
*/
static IP_CONST char *keyadm_sa_flags_bitmap[] =
{
"pfs",
"0x2",
"0x4",
"0x8",
"0x10",
"0x20",
"0x40",
"0x80",
"0x100",
"ecn",
"tunnel",
"chaindel",
"0x1000",
"replaceflow",
"ingress",
"randompad",
"noreplay",
"udpencap",
"egress",
"tfc",
"esn",
"srcreq",
"clrdf",
"setdf",
"0x1000000",
"0x2000000",
"0x4000000",
"0x8000000",
"0x10000000",
"nopmtudisc",
"decap_dscp",
"noecn",
""
};
static Ip_u32 sadbmsgseq = 1;
static IP_CONST Command commands[] =
{
/* name, function */
{ "dump", keyadm_dump, IP_NULL, SADB_DUMP },
{ "flush", keyadm_flush, IP_NULL, SADB_FLUSH },
{ "get", keyadm_get, keyadm_get_usage, SADB_GET },
{ "getspi", keyadm_getspi, keyadm_getspi_usage, SADB_GETSPI },
{ "update", keyadm_update, keyadm_update_usage, SADB_UPDATE },
{ "add", keyadm_add, keyadm_add_usage, SADB_ADD },
{ "delete", keyadm_delete, keyadm_delete_usage, SADB_DELETE },
{ "addflow", keyadm_addflow, keyadm_addflow_usage, SADB_X_ADDFLOW },
{ "delflow", keyadm_delflow, keyadm_delflow_usage, SADB_X_DELFLOW },
{ "group", keyadm_grpspis, keyadm_grpspis_usage, SADB_X_GRPSPIS },
{ "findflow", keyadm_findflow, keyadm_findflow_usage, SADB_X_FINDFLOW },
{ "dumpflow", keyadm_dumpflow, IP_NULL, SADB_X_DUMPFLOW },
{ "monitor", keyadm_monitor, IP_NULL, 0 },
{ "register", keyadm_register, IP_NULL, SADB_REGISTER },
#ifdef IPIPSEC_USE_LINUX_PFKEYV2_API
{ "spdadd", keyadm_spdadd, keyadm_spdadd_usage, SADB_X_SPDADD },
{ "spdupdate", keyadm_spdupdate, keyadm_spdupdate_usage, SADB_X_SPDUPDATE },
{ "spddelete", keyadm_spddelete, keyadm_spddelete_usage, SADB_X_SPDDELETE },
{ "spdflush", keyadm_spdflush, IP_NULL, SADB_X_SPDFLUSH },
#endif
{ 0, IP_NULL, IP_NULL, 0 }
};
#define EXT_SADBADDR_SIZE_MIN (int)(sizeof(struct sadb_address) + IP_ROUNDUP(sizeof(struct Ip_sockaddr_in),8))
#define EXT_SADBADDR_SIZE_IN 24 /* same expression as above */
#define EXT_SADBADDR_SIZE_IN6 40 /* 8+sizeof(struct Ip_sockaddr_in6) = 8+28 = 36 -> rounded up = 40 */
#define SOCKADDR_SIZE IP_ROUNDUP(sizeof(struct Ip_sockaddr_in),8)
#define SOCKADDR6_SIZE IP_ROUNDUP(sizeof(struct Ip_sockaddr_in6),8)
static IP_CONST Extbits extbits[SADB_MAX+1] =
{
/* 0 SADB_RESERVED */
{ 0 /* in_req */ },
/* 1 SADB_GETSPI */
{ SEBIT_SPIRANGE | SEBIT_ADDRESS_SRC | SEBIT_ADDRESS_DST },
/* 2 SADB_UPDATE */
{ SEBIT_SA | SEBIT_ADDRESS_SRC | SEBIT_ADDRESS_DST },
/* 3 SADB_ADD */
{ SEBIT_SA | SEBIT_ADDRESS_DST | SEBIT_ADDRESS_SRC },
/* 4 SADB_DELETE */
{ SEBIT_SA | SEBIT_ADDRESS_DST | SEBIT_ADDRESS_SRC },
/* 5 SADB_GET */
{ SEBIT_SA | SEBIT_ADDRESS_SRC | SEBIT_ADDRESS_DST },
/* 6 SADB_ACQUIRE */
{ 0 },
/* 7 SADB_REGISTER */
{ 0 },
/* 8 SADB_EXPIRE */
{ SEBIT_SA | SEBIT_ADDRESS_SRC | SEBIT_ADDRESS_DST },
/* 9 SADB_FLUSH */
{ 0 },
/* 10 SADB_DUMP */
{ 0 },
{ 0 }, /* 11 SADB_LX_PROMISC */
{ 0 }, /* 12 SADB_LX_PCHANGE */
/* 13 SADB_X_SPDUPDATE */
/* NOTE: Acctually SEBIT_ADDRESS_SRC | SEBIT_ADDRESS_DST | SEBIT_LX_POLICY */
{ SEBIT_X_FLOW },
/* 14 SADB_X_SPDADD */
/* Note: Acctually SEBIT_ADDRESS_SRC | SEBIT_ADDRESS_DST | SEBIT_LX_POLICY */
{ SEBIT_X_FLOW },
/* 15 LX_SPDDELETE */
/* Note: Acctually SEBIT_ADDRESS_SRC | SEBIT_ADDRESS_DST | SEBIT_LX_POLICY */
{ SEBIT_X_FLOW },
{ 0 }, /* 16 LX_SPDGET */
{ 0 }, /* 17 LX_SPDACQUIRE */
{ 0 }, /* 18 LX_SPDDUMP */
{ 0 }, /* 19 LX_SPDFLUSH */
{ 0 }, /* 20 LX_SPDSETIDX */
{ 0 }, /* 21 LX_SPDEXPIRE */
{ 0 }, /* 22 LX_SPDDELETE2 */
{ 0 }, /* 23 LX_NAT_T_NEW_MAPPING */
{ 0 }, /* 24 LX_MIGRATE */
{ 0 }, /* 25 */
{ 0 }, /* 26 */
{ 0 }, /* 27 */
{ 0 }, /* 28 */
{ 0 }, /* 29 */
{ 0 }, /* 30 */
{ 0 }, /* 31 */
{ 0 }, /* 32 */
/* 33 SADB_X_PROMISC */
{ 0 },
/* 34 SADB_X_ADDFLOW */
{ SEBIT_X_FLOW },
/* 35 SADB_X_DELFLOW */
{ 0 },
/* 36 SADB_X_GRPSPIS */
{
SEBIT_SA | SEBIT_X_SA2 | SEBIT_X_DST2 | SEBIT_ADDRESS_DST | SEBIT_X_PROTOCOL
},
/* 37 SADB_X_BINDSA */
{
SEBIT_SA | SEBIT_X_SA2 | SEBIT_X_DST2 | SEBIT_ADDRESS_DST | SEBIT_X_PROTOCOL
},
/* 38 SADB_X_FINDFLOW */
{
SEBIT_X_FLOW /* not checked this way: SEBIT_X_PROTOCOL */
},
/* 39 SADB_X_DUMPFLOW */
{ 0 },
/* 40 SADB_X_MIGRATE */
{
SEBIT_X_EXT_KMADDRESS
}
};
static IP_CONST char *ext_types[SADB_EXT_MAX+2] =
{
"RESERVED",
"-spi",
"LIFETIME_CURRENT",
"LIFETIME_HARD",
"LIFETIME_SOFT",
"-src",
"-dst",
"ADDRESS_PROXY",
"KEY_AUTH",
"KEY_ENCRYPT",
"IDENTITY_SRC",
"IDENTITY_DST",
"SENSITIVITY",
"PROPOSAL",
"SUPPORTED",
"SUPPORTED_ENCRYPT",
"-minspi",
"LX_KMPRIVATE",
"LX_POLICY",
"LX_SA2",
"LX_NAT_TYPE",
"LX_NAT_SPORT",
"LX_NAT_DPORT",
"LX_NAT_OA",
"LX_SEC_CTX",
"EXT25",
"EXT26",
"EXT27",
"EXT28",
"EXT29",
"EXT30",
"EXT31",
"EXT32",
"-srcmask",
"-dstmask",
"-proto2",
"-spi2",
"-srcflow",
"-dstflow",
"-dst2",
"-flowopt",
"UDPENCAP",
"-srcmax(port)",
"-dstmax(port)",
"SA_OPTIONS",
"KMADDRESS",
"\n"
};
#define EXT_TYPE(x) ((x > SADB_EXT_MAX) ? "ILLEGAL" : ext_types[x])
#define MSG_TYPE(x) ((x > SADB_MAX) ? "ILLEGAL" : ipipsec_pfkeyv2_command[x])
static IP_CONST char *msg_satypes[SADB_SATYPE_MAX+2] =
{
"NONE",
"UNSPEC_1",
"AH",
"ESP",
"UNSPEC_4",
"RSVP",
"OSPFV2",
"RIPV2",
"MIP",
"IPCOMP",
"IPIP",
"TCPSIGNATURE",
"BYPASS",
"\n"
};
#define MSG_SATYPE(x) ((x > SADB_SATYPE_MAX) ? "ILLEGAL" : msg_satypes[x])
static Ipcom_cmd_int_str_map sa_auth_id_map[] =
{
{ SADB_AALG_NONE, "NONE" },
{ SADB_AALG_MD5HMAC, "MD5" },
{ SADB_AALG_SHA1HMAC, "SHA" },
{ SADB_AALG_SHA1HMAC, "SHA1" },
{ SADB_X_AALG_SHA2_256_HMAC, "SHA256" },
{ SADB_X_AALG_SHA2_384_HMAC, "SHA384" },
{ SADB_X_AALG_SHA2_512_HMAC, "SHA512" },
{ SADB_X_AALG_RIPEMD160HMAC, "RMD160" },
{ SADB_X_AALG_AES_XCBC_MAC, "AESMAC" },
{ SADB_X_AALG_NULL, "NULL" },
{ -1, IP_NULL }
};
#define SADB_AALG_UNSET (SADB_AALG_MAX + 1)
static Ipcom_cmd_int_str_map sa_encrypt_id_map[] =
{
{ SADB_EALG_NONE, "NONE" },
{ SADB_EALG_DESCBC, "DES" },
{ SADB_EALG_3DESCBC, "3DES" },
{ SADB_X_EALG_BLOWFISHCBC, "BLF" },
{ SADB_X_EALG_CASTCBC, "CAST" },
{ SADB_X_EALG_AESCBC, "AES" },
{ SADB_X_EALG_AESCBC, "AESCBC" },
{ SADB_X_EALG_AESCTR, "AESCTR" },
{ SADB_EALG_NULL, "NULL" },
{ -1, IP_NULL }
};
#define SADB_EALG_UNSET (SADB_EALG_MAX + 1)
static IP_CONST char *sa_state[SADB_SASTATE_MAX+2] =
{
"LARVAL",
"MATURE",
"DYING",
"DEAD",
"\n"
};
#define SA_STATE(x) ((x > SADB_SASTATE_MAX) ? "ILLEGAL" : sa_state[x])
static IP_CONST char *flow_types[] =
{
"unspec",
"use",
"acquire",
"require",
"bypass",
"deny",
"dontacq"
};
#define FLOW_TYPE(x) ((x) > 6 ? "ILLEGAL" : flow_types[x])
/*
*===========================================================================
* LINUX vars
*===========================================================================
*/
#ifdef IPIPSEC_USE_LINUX_PFKEYV2_API
static IP_CONST char *ipsec_policy_linux[5] =
{
"discard",
"none",
"ipsec",
"entrust",
"bypass"
};
/* sadb_x_policy_dir; */
static IP_CONST char *ipsec_dir_linux[6] =
{
"any",
"inbound",
"outbound",
"fwd",
"max",
"invalid"
};
#endif /* #ifdef IPIPSEC_USE_LINUX_PFKEYV2_API */
/*
****************************************************************************
* 8 FUNCTIONS.
****************************************************************************
*/
/*
*===========================================================================
* keyadm_printf
*===========================================================================
* Description:
* Parameters:
* Returns:
*/
static void
keyadm_printf(Vars *vars, const char *format, ...)
{
#if IPCOM_USE_SHELL != IPCOM_SHELL_NONE || defined(IP_PORT_LAS)
if (vars->silent == 0)
{
va_list ap;
int retval;
va_start(ap, format);
retval = ipcom_vsprintf(vars->stdoutbuf, format, ap);
va_end(ap);
ip_assert(retval < 512);
if (retval > 0)
{
if (vars->syslog)
IPCOM_LOG1(DEBUG, "%s", vars->stdoutbuf);
else
(void)ipcom_printf(vars->stdoutbuf);
}
}
#else
IPCOM_UNUSED_ARG(vars);
IPCOM_UNUSED_ARG(format);
#endif
}
/*
*===========================================================================
* keyadm_cmd_bits_to_str
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
static IP_CONST char *
keyadm_cmd_bits_to_str(char **map, Ip_u32 bits, char *str, Ip_size_t str_len)
{
int i;
int len = 0;
str[0] = '\0';
for (i = 0; i < 32 && *map[i] != '\0'; i++)
if (IP_BIT_ISSET(bits, 1 << i))
len += ipcom_snprintf(str + len, str_len - len, "%s ", map[i]);
return str;
}
/*
*===========================================================================
* keyadm_strcasecmp
*===========================================================================
*/
static int
keyadm_strcasecmp(IP_CONST char *s1, IP_CONST char *s2)
{
while (ipcom_toupper(*s1) == ipcom_toupper(*s2))
{
if (*s1 == '\0')
return 0;
s1++;
s2++;
}
return ipcom_toupper(*s1) - ipcom_toupper(*s2);
}
/*
*===========================================================================
* keyadm_search_block
*===========================================================================
*/
static int
keyadm_search_block(char *arg, IP_CONST char **list)
{
int i;
for (i = 0; **(list + i) != '\n'; i++)
if (!keyadm_strcasecmp(arg, *(list + i)))
return (i);
return (-1);
}
/*
*===========================================================================
* keyadm_hex_to_long
*===========================================================================
*/
static int
keyadm_hex_to_long(Vars *vars, char *s, int *do_exit)
{
char ss[3];
ss[0] = s[0];
ss[1] = s[1];
ss[2] = 0;
if (!ipcom_isxdigit((int)s[0]) || !ipcom_isxdigit((int)s[1]))
{
keyadm_printf(vars, "keyadm: keys should be specified in hex digits"IP_LF);
*do_exit = 1;
}
else
*do_exit = 0;
return ipcom_strtoul(ss, IP_NULL, 16);
}
/*
*===========================================================================
* keyadm_read_addr
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
static int
keyadm_read_addr(IP_CONST char *string, union Ip_sockaddr_union *sockaddr)
{
int af;
#if defined(IPCOM_USE_INET) && defined(IPCOM_USE_INET6)
if (ipcom_strchr(string, ':'))
af = IP_AF_INET6;
else
af = IP_AF_INET;
#elif defined(IPCOM_USE_INET6)
af = IP_AF_INET6;
#else
af = IP_AF_INET;
#endif
return ipcom_getsockaddrbyaddrname(af, IP_TRUE /* do not use dns */, string, &sockaddr->sa);
}
/*
*===========================================================================
* keyadm_ipaddr_to_extaddr
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
static void
keyadm_ipaddr_to_extaddr(struct sadb_address_full *address, union Ip_sockaddr_union *sockaddr)
{
int addrsize;
#if defined(IPCOM_USE_INET) && defined(IPCOM_USE_INET6)
addrsize = sockaddr->sa.sa_family == IP_AF_INET ? EXT_SADBADDR_SIZE_IN : EXT_SADBADDR_SIZE_IN6;
#elif defined(IPCOM_USE_INET6)
addrsize = EXT_SADBADDR_SIZE_IN6;
#else
addrsize = EXT_SADBADDR_SIZE_IN;
#endif
address->addr.sadb_address_len = (uint16_t)(addrsize >> 3);
address->addr.sadb_address_proto = 0; /*!! non-zero ports -> UDP OR TCP else 0 */
address->addr.sadb_address_prefixlen = 0;
address->addr.sadb_address_reserved = 0;
ipcom_memcpy(&address->sock, sockaddr, sizeof(union Ip_sockaddr_union));
}
/*
*===========================================================================
* keyadm_send_command
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
static int
keyadm_send_command(Vars *vars, Ip_u8 type, Ip_u8 satype)
{
int retval = 0, i, length;
Ip_u8 *orgbuf, *msgbuf;
struct sadb_address_full src, dst, dst2, proxy, srcflow, srcmaxflow, dstflow, dstmaxflow, srcmask, dstmask;
struct sadb_spirange spi;
struct sadb_sa sa, sa2;
struct sadb_protocol proto2;
struct sadb_lifetime ls, lh;
struct sadb_x_flowopt flowopt;
struct sadb_x_saopt saopt;
struct sadb_x_udpencap udpencap;
#ifdef IPIPSEC_USE_LINUX_PFKEYV2_API
struct sadb_x_sa2 lx_sa2;
#endif
/** Auto build some extension headers **/
/* SADB_EXT_SA */
if (IP_BIT_ISSET(vars->extmap, SEBIT_SA))
{
ipcom_memset(&sa, 0, sizeof(struct sadb_sa));
vars->sadb->sa = &sa;
vars->sadb->sa->sadb_sa_len = sizeof(struct sadb_sa) / sizeof(Ip_u64);
vars->sadb->sa->sadb_sa_exttype = SADB_EXT_SA;
vars->sadb->sa->sadb_sa_spi = vars->spi_n;
vars->sadb->sa->sadb_sa_replay = (Ip_u8)vars->replay;
vars->sadb->sa->sadb_sa_auth = vars->auth_type;
if (vars->sadb->sa->sadb_sa_auth == SADB_AALG_UNSET)
vars->sadb->sa->sadb_sa_auth = SADB_AALG_NONE;
vars->sadb->sa->sadb_sa_encrypt = vars->encrypt_type;
if (vars->sadb->sa->sadb_sa_encrypt == SADB_EALG_UNSET)
vars->sadb->sa->sadb_sa_encrypt = SADB_EALG_NONE;
vars->sadb->sa->sadb_sa_flags = vars->sa_flags;
if (type == SADB_UPDATE || type == SADB_ADD)
{
vars->sadb->sa->sadb_sa_state = SADB_SASTATE_MATURE;
if (IP_BIT_ISSET(vars->sa_flags, SADB_X_SAFLAGS_UDPENCAP))
{
vars->sadb->udpencap = (struct sadb_x_udpencap *)&udpencap;
vars->sadb->udpencap->sadb_x_udpencap_len = sizeof(struct sadb_x_udpencap) / sizeof(Ip_u64);
vars->sadb->udpencap->sadb_x_udpencap_exttype = SADB_X_EXT_UDPENCAP;
vars->sadb->udpencap->sadb_x_udpencap_src_port = ip_htons(vars->udpencap_port);
vars->sadb->udpencap->sadb_x_udpencap_dst_port = vars->sadb->udpencap->sadb_x_udpencap_src_port;
}
#ifdef IPIPSEC_USE_LINUX_PFKEYV2_API
if (vars->is_linux)
{
vars->sadb->lx_sa2 = (struct sadb_x_sa2 *)&lx_sa2;
vars->sadb->lx_sa2->sadb_x_sa2_len = sizeof(struct sadb_x_sa2) >> 3;
vars->sadb->lx_sa2->sadb_x_sa2_exttype = SADB_LX_EXT_SA2;
if (IP_BIT_ISSET(vars->sa_flags, SADB_X_SAFLAGS_TUNNEL))
vars->sadb->lx_sa2->sadb_x_sa2_mode = IPSEC_MODE_TUNNEL;
else
vars->sadb->lx_sa2->sadb_x_sa2_mode = IPSEC_MODE_TRANSPORT;
vars->sadb->lx_sa2->sadb_x_sa2_sequence = 0;
vars->sadb->lx_sa2->sadb_x_sa2_reqid = vars->reqid;
}
#endif /* #ifdef IPIPSEC_USE_LINUX_PFKEYV2_API */
}
}
/* SADB_EXT_SPIRANGE */
if (vars->maxspi && IP_BIT_ISSET(vars->extmap, SEBIT_SPIRANGE))
{
vars->sadb->spirange = (struct sadb_spirange *)&spi;
vars->sadb->spirange->sadb_spirange_len = sizeof(struct sadb_spirange) / sizeof(Ip_u64);
vars->sadb->spirange->sadb_spirange_exttype = SADB_EXT_SPIRANGE;
vars->sadb->spirange->sadb_spirange_min = vars->minspi;
vars->sadb->spirange->sadb_spirange_max = vars->maxspi;
vars->sadb->spirange->sadb_spirange_reserved = 0;
}
/* SADB_EXT_ADDRESS_SRC */
if (IP_BIT_ISSET(vars->extmap, SEBIT_ADDRESS_SRC))
{
vars->sadb->address_src = (struct sadb_address *)&src;
keyadm_ipaddr_to_extaddr(&src, &vars->srcaddr);
vars->sadb->address_src->sadb_address_exttype = SADB_EXT_ADDRESS_SRC;
}
/* SADB_EXT_ADDRESS_DST */
if (IP_BIT_ISSET(vars->extmap, SEBIT_ADDRESS_DST))
{
vars->sadb->address_dst = (struct sadb_address *)&dst;
keyadm_ipaddr_to_extaddr(&dst, &vars->dstaddr);
vars->sadb->address_dst->sadb_address_exttype = SADB_EXT_ADDRESS_DST;
}
/* SADB_EXT_ADDRESS_PROXY */
if (IP_BIT_ISSET(vars->extmap, SEBIT_ADDRESS_PROXY))
{
vars->sadb->address_proxy = (struct sadb_address *)&proxy;
keyadm_ipaddr_to_extaddr(&proxy, &vars->proxyaddr);
vars->sadb->address_proxy->sadb_address_exttype = SADB_EXT_ADDRESS_PROXY;
}
/* SADB_EXT_KEY_ENCRYPT */
if (vars->encrypt_bytes > 0)
{
vars->sadb->key_encrypt = &vars->encrypt_sadb;
vars->sadb->key_encrypt->sadb_key_len = (uint16_t)((sizeof(struct sadb_key) + IP_ROUNDUP(vars->encrypt_bytes, 8)) / sizeof(Ip_u64));
vars->sadb->key_encrypt->sadb_key_exttype = SADB_EXT_KEY_ENCRYPT;
vars->sadb->key_encrypt->sadb_key_bits = (uint16_t)(vars->encrypt_bytes * 8);
vars->sadb->key_encrypt->sadb_key_reserved = 0;
}
/* SADB_EXT_KEY_AUTH */
if (vars->auth_bytes > 0)
{
vars->sadb->key_auth = &vars->auth_sadb;
vars->sadb->key_auth->sadb_key_len = (uint16_t)((sizeof(struct sadb_key) + IP_ROUNDUP(vars->auth_bytes, 8)) / sizeof(Ip_u64));
vars->sadb->key_auth->sadb_key_exttype = SADB_EXT_KEY_AUTH;
vars->sadb->key_auth->sadb_key_bits = (uint16_t)(vars->auth_bytes * 8);
vars->sadb->key_auth->sadb_key_reserved = 0;
}
/* SEBIT_X_SRC_FLOW */
if (IP_BIT_ISSET(vars->extmap, SEBIT_X_SRC_FLOW))
{
vars->sadb->src_flow = (struct sadb_address *)&srcflow;
keyadm_ipaddr_to_extaddr(&srcflow, &vars->srcflow);
srcflow.sock.sin.sin_port = vars->srcport_n;
vars->sadb->src_flow->sadb_address_exttype = SADB_X_EXT_SRC_FLOW;
/* SEBIT_X_SRCMAX_FLOW */
if (IP_BIT_ISSET(vars->extmap, SEBIT_X_SRCMAX_FLOW))
{
vars->sadb->srcmax_flow = (struct sadb_address *)&srcmaxflow;
if (ipcom_memcmp(&vars->srcmaxflow, &vars->zeroaddr, sizeof(union Ip_sockaddr_union)))
keyadm_ipaddr_to_extaddr(&srcmaxflow, &vars->srcmaxflow);
else
keyadm_ipaddr_to_extaddr(&srcmaxflow, &vars->srcflow);
if (vars->srcmaxport_n != 0)
srcmaxflow.sock.sin.sin_port = vars->srcmaxport_n;
else
srcmaxflow.sock.sin.sin_port = vars->srcport_n;
vars->sadb->srcmax_flow->sadb_address_exttype = SADB_X_EXT_SRCMAX_FLOW;
}
}
/* SEBIT_X_DST_FLOW */
if (IP_BIT_ISSET(vars->extmap, SEBIT_X_DST_FLOW))
{
vars->sadb->dst_flow = (struct sadb_address *)&dstflow;
keyadm_ipaddr_to_extaddr(&dstflow, &vars->dstflow);
dstflow.sock.sin.sin_port = vars->dstport_n;
vars->sadb->dst_flow->sadb_address_exttype = SADB_X_EXT_DST_FLOW;
/* SEBIT_X_DSTMAX_FLOW */
if (IP_BIT_ISSET(vars->extmap, SEBIT_X_DSTMAX_FLOW))
{
vars->sadb->dstmax_flow = (struct sadb_address *)&dstmaxflow;
if (ipcom_memcmp(&vars->dstmaxflow, &vars->zeroaddr, sizeof(union Ip_sockaddr_union)))
keyadm_ipaddr_to_extaddr(&dstmaxflow, &vars->dstmaxflow);
else
keyadm_ipaddr_to_extaddr(&dstmaxflow, &vars->dstflow);
if (vars->dstmaxport_n != 0)
dstmaxflow.sock.sin.sin_port = vars->dstmaxport_n;
else
dstmaxflow.sock.sin.sin_port = vars->dstport_n;
vars->sadb->dstmax_flow->sadb_address_exttype = SADB_X_EXT_DSTMAX_FLOW;
}
}
/* SEBIT_X_SRC_MASK */
if (IP_BIT_ISSET(vars->extmap, SEBIT_X_SRC_MASK))
{
vars->sadb->src_mask = (struct sadb_address *)&srcmask;
keyadm_ipaddr_to_extaddr(&srcmask, &vars->srcmask);
vars->sadb->src_mask->sadb_address_exttype = SADB_X_EXT_SRC_MASK;
}
/* SEBIT_X_DST_MASK */
if (IP_BIT_ISSET(vars->extmap, SEBIT_X_DST_MASK))
{
vars->sadb->dst_mask = (struct sadb_address *)&dstmask;
keyadm_ipaddr_to_extaddr(&dstmask, &vars->dstmask);
vars->sadb->dst_mask->sadb_address_exttype = SADB_X_EXT_DST_MASK;
}
/* SEBIT_X_DST2 */
if (IP_BIT_ISSET(vars->extmap, SEBIT_X_DST2))
{
vars->sadb->dst2 = (struct sadb_address *)&dst2;
keyadm_ipaddr_to_extaddr(&dst2, &vars->dstaddr2);
vars->sadb->dst2->sadb_address_exttype = SADB_X_EXT_DST2;
}
/* SEBIT_X_SA2 */
if (IP_BIT_ISSET(vars->extmap, SEBIT_X_SA2))
{
ipcom_memset(&sa2, 0, sizeof(struct sadb_sa));
vars->sadb->sa2 = &sa2;
vars->sadb->sa2->sadb_sa_spi = vars->spi2_n;
vars->sadb->sa2->sadb_sa_len = sizeof(struct sadb_sa) / sizeof(Ip_u64);
vars->sadb->sa2->sadb_sa_exttype = SADB_X_EXT_SA2;
vars->sadb->sa2->sadb_sa_state = SADB_SASTATE_MATURE;
}
/* SEBIT_LIFETIME_SOFT - soft lifetime */
if (IP_BIT_ISSET(vars->extmap, SEBIT_LIFETIME_SOFT))
{
ipcom_memset(&ls, 0, sizeof(struct sadb_lifetime));
vars->sadb->lifetime_soft = &ls;
vars->sadb->lifetime_soft->sadb_lifetime_len = sizeof(struct sadb_lifetime) / sizeof(Ip_u64);
vars->sadb->lifetime_soft->sadb_lifetime_exttype = SADB_EXT_LIFETIME_SOFT;
vars->sadb->lifetime_soft->sadb_lifetime_bytes = vars->ls_bytes;
IP_U64_SETLO(vars->sadb->lifetime_soft->sadb_lifetime_addtime, vars->ls_sec);
}
/* SEBIT_LIFETIME_HARD - hard lifetime */
if (IP_BIT_ISSET(vars->extmap, SEBIT_LIFETIME_HARD))
{
ipcom_memset(&lh, 0, sizeof(struct sadb_lifetime));
vars->sadb->lifetime_hard = &lh;
vars->sadb->lifetime_hard->sadb_lifetime_len = sizeof(struct sadb_lifetime) / sizeof(Ip_u64);
vars->sadb->lifetime_hard->sadb_lifetime_exttype = SADB_EXT_LIFETIME_HARD;
vars->sadb->lifetime_hard->sadb_lifetime_bytes = vars->lh_bytes;
IP_U64_SETLO(vars->sadb->lifetime_hard->sadb_lifetime_addtime, vars->lh_sec);
}
/* "-proto2" SEBIT_X_PROTOCOL - security protocol */
if (IP_BIT_ISSET(vars->extmap, SEBIT_X_PROTOCOL))
{
ipcom_memset(&proto2, 0, sizeof(struct sadb_protocol));
vars->sadb->protocol = (struct sadb_protocol *)&proto2;
vars->sadb->protocol->sadb_protocol_len = sizeof(struct sadb_protocol) / sizeof(Ip_u64);
vars->sadb->protocol->sadb_protocol_exttype = SADB_X_EXT_PROTOCOL;
vars->sadb->protocol->sadb_protocol_proto = vars->satype2;
}
/* "-transport" SEBIT_X_PROTOCOL - transport protocol */
else if (vars->have_transport_proto || vars->ports0 || vars->ports1)
{
ipcom_memset(&proto2, 0, sizeof(struct sadb_protocol));
vars->sadb->protocol = (struct sadb_protocol *)&proto2;
vars->sadb->protocol->sadb_protocol_len = sizeof(struct sadb_protocol) / sizeof(Ip_u64);
vars->sadb->protocol->sadb_protocol_exttype = SADB_X_EXT_PROTOCOL;
vars->sadb->protocol->sadb_protocol_proto = vars->transport_proto;
vars->sadb->protocol->sadb_protocol_ports0 = vars->ports0;
vars->sadb->protocol->sadb_protocol_ports1 = vars->ports1;
}
/* SEBIT_X_FLOW_OPTIONS - flow type, id, direction and/or priority */
if ((type == SADB_X_ADDFLOW || type == SADB_X_DELFLOW
|| type == SADB_X_FINDFLOW || type == SADB_X_DUMPFLOW)
&& IP_BIT_ISSET(vars->extmap, SEBIT_X_FLOW_OPTIONS))
{
ipcom_memset(&flowopt, 0, sizeof(struct sadb_x_flowopt));
vars->sadb->flowopt = (struct sadb_x_flowopt *)&flowopt;
vars->sadb->flowopt->sadb_flowopt_len = sizeof(struct sadb_x_flowopt) / sizeof(Ip_u64);
vars->sadb->flowopt->sadb_flowopt_exttype = SADB_X_EXT_FLOW_OPTIONS;
vars->sadb->flowopt->sadb_flowopt_type = vars->flow_type;
if (IP_BIT_ISSET(vars->sa_flags, SADB_X_SAFLAGS_EGRESS_SA))
vars->sadb->flowopt->sadb_flowopt_direction = 2;
if (IP_BIT_ISSET(vars->sa_flags, SADB_X_SAFLAGS_INGRESS_SA))
vars->sadb->flowopt->sadb_flowopt_direction = 1;
vars->sadb->flowopt->sadb_flowopt_priority = (signed char)vars->flow_priority;
vars->sadb->flowopt->sadb_flowopt_dscp = vars->dscp;
vars->sadb->flowopt->sadb_flowopt_id = vars->flow_id;
}
/* SEBIT_X_EXT_SA_OPTIONS */
if (IP_BIT_ISSET(vars->extmap, SEBIT_X_EXT_SA_OPTIONS))
{
ipcom_memset(&saopt, 0, sizeof(struct sadb_x_saopt));
vars->sadb->saopt = (struct sadb_x_saopt *)&saopt;
vars->sadb->saopt->sadb_saopt_len = sizeof(struct sadb_x_saopt) / sizeof(Ip_u64);
vars->sadb->saopt->sadb_saopt_exttype = SADB_X_EXT_SA_OPTIONS;
vars->sadb->saopt->sadb_saopt_priority = (signed char)vars->sa_priority;
}
/* Calculate message length */
for (length = sizeof(struct sadb_msg), i = 1; i <= SADB_EXT_MAX; i++)
if (vars->exthdr[i] != IP_NULL)
length += (((struct sadb_ext *)vars->exthdr[i])->sadb_ext_len * sizeof(Ip_u64));
/* Allocate memory for the PFKEY write */
orgbuf = (Ip_u8 *)ipcom_malloc(length + sizeof(Ip_u64));
if (orgbuf == IP_NULL)
{
keyadm_printf(vars, "keyadm: out of memory"IP_LF);
return -1;
}
msgbuf = IP_PTR_ALIGN(orgbuf, 8); /* 64-bit align msgbuf */
ip_assert(((Ip_ptrdiff_t)msgbuf & 0x7L) == 0);
ipcom_memset(msgbuf, 0, length);
/* Set SADB_MSG */
vars->sadb->msg->sadb_msg_version = PF_KEY_V2;
vars->sadb->msg->sadb_msg_type = type;
vars->sadb->msg->sadb_msg_errno = 0;
vars->sadb->msg->sadb_msg_satype = satype;
vars->sadb->msg->sadb_msg_reserved = 0;
vars->sadb->msg->sadb_msg_len = (uint16_t)(length / sizeof(Ip_u64));
vars->sadb->msg->sadb_msg_seq = sadbmsgseq++;
vars->sadb->msg->sadb_msg_pid = ipcom_getpid();
/* Copy over all headers */
ipcom_memcpy(msgbuf, vars->sadb->msg, sizeof(struct sadb_msg));
for (length = sizeof(struct sadb_msg), i = 1; i <= SADB_EXT_MAX; i++)
if (vars->exthdr[i] != IP_NULL)
{
ipcom_memcpy(msgbuf + length,
vars->exthdr[i],
((struct sadb_ext *)vars->exthdr[i])->sadb_ext_len * sizeof(Ip_u64));
length += ((struct sadb_ext *)vars->exthdr[i])->sadb_ext_len * sizeof(Ip_u64);
}
/* Write the SADB message */
if (ipcom_send(vars->fd, (char*)msgbuf, length, 0) != length)
{
keyadm_printf(vars, "keyadm: ipcom_send() failed: %s (%d)"IP_LF,
ipcom_strerror(ipcom_errno), ipcom_errno);
if (ipcom_errno == IP_ERRNO_EINVAL || ipcom_errno == IP_ERRNO_ENOMEM
|| ipcom_errno == IP_ERRNO_ENOBUFS)
retval = -1;
}
if (orgbuf)
ipcom_free(orgbuf);
return retval;
}
/*
*===========================================================================
* keyadm_send_command_linux
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
#ifdef IPIPSEC_USE_LINUX_PFKEYV2_API
static int
keyadm_send_command_linux(Vars *vars, Ip_u8 type, Ip_u8 satype)
{
int retval = 0, i, length;
Ip_u8 *orgbuf, *msgbuf;
struct sadb_address_full src, dst;
struct policy
{
struct sadb_x_policy policy;
struct sadb_x_ipsecrequest xisr;
union Ip_sockaddr_union sockbuf[2];
} pol;
Ip_u16 policy_type;
/** Auto build some extension headers **/
/* SADB_EXT_ADDRESS_SRC */
if (IP_BIT_ISSET(vars->extmap, SEBIT_X_SRC_FLOW))
{
vars->sadb->address_src = (struct sadb_address *)&src;
keyadm_ipaddr_to_extaddr(&src, &vars->srcflow);
src.sock.sin.sin_port = vars->srcport_n;
vars->sadb->address_src->sadb_address_exttype = SADB_EXT_ADDRESS_SRC;
vars->sadb->address_src->sadb_address_proto = vars->transport_proto;
if (vars->srcmask.sa.sa_family==0)
{
#if defined(IPCOM_USE_INET)
if (vars->srcflow.sa.sa_family == IP_AF_INET)
vars->sadb->address_src->sadb_address_prefixlen=32;
#endif
#if defined(IPCOM_USE_INET6)
if (vars->srcflow.sa.sa_family == IP_AF_INET6)
vars->sadb->address_src->sadb_address_prefixlen=128;
#endif
}
else
{
vars->sadb->address_src->sadb_address_prefixlen = ipcom_sockaddr_to_prefixlen(&vars->srcmask.sa);
}
}
/* SADB_EXT_ADDRESS_DST */
if (IP_BIT_ISSET(vars->extmap, SEBIT_X_DST_FLOW))
{
vars->sadb->address_dst = (struct sadb_address *)&dst;
keyadm_ipaddr_to_extaddr(&dst, &vars->dstflow);
dst.sock.sin.sin_port = vars->dstport_n;
vars->sadb->address_dst->sadb_address_exttype = SADB_EXT_ADDRESS_DST;
vars->sadb->address_dst->sadb_address_proto = vars->transport_proto;
if (vars->dstmask.sa.sa_family==0)
{
#if defined(IPCOM_USE_INET)
if (vars->dstflow.sa.sa_family == IP_AF_INET)
vars->sadb->address_dst->sadb_address_prefixlen=32;
#endif
#if defined(IPCOM_USE_INET6)
if (vars->dstflow.sa.sa_family == IP_AF_INET6)
vars->sadb->address_dst->sadb_address_prefixlen=128;
#endif
}
else
{
vars->sadb->address_dst->sadb_address_prefixlen = ipcom_sockaddr_to_prefixlen(&vars->dstmask.sa);
}
}
/* SADB_X_EXT_POLICY */
ipcom_memset(&pol, 0, sizeof(struct policy));
vars->sadb->lx_policy = &pol.policy;
pol.policy.sadb_x_policy_len = sizeof(struct sadb_x_policy) / sizeof(Ip_u64);
pol.policy.sadb_x_policy_exttype = SADB_X_EXT_POLICY;
switch (vars->flow_type) /*!!WHAT IS? IPSEC_POLICY_ENTRUST*/
{
case SADB_X_FLOW_TYPE_BYPASS: /* Send without applying security, i.e. cleartext */
policy_type = IPSEC_POLICY_BYPASS;
break;
case SADB_X_FLOW_TYPE_DENY: /* Silent discard */
policy_type = IPSEC_POLICY_DISCARD;
break;
case SADB_X_FLOW_TYPE_USE: /* Apply security (standard flow) */
case SADB_X_FLOW_TYPE_ACQUIRE: /* Generate acquire message, send packet in cleartext */
case SADB_X_FLOW_TYPE_REQUIRE: /* Generate require message, discard packet */
default:
policy_type = IPSEC_POLICY_IPSEC;
break;
}
pol.policy.sadb_x_policy_type = policy_type;
if (IP_BIT_ISSET(vars->sa_flags, SADB_X_SAFLAGS_EGRESS_SA))
pol.policy.sadb_x_policy_dir = IPSEC_DIR_OUTBOUND;
else if (IP_BIT_ISSET(vars->sa_flags, SADB_X_SAFLAGS_INGRESS_SA))
pol.policy.sadb_x_policy_dir = IPSEC_DIR_INBOUND;
else
pol.policy.sadb_x_policy_dir = IPSEC_DIR_INVALID;
pol.policy.sadb_x_policy_id = vars->flow_id;
/*!!CHECK: that -127 is negative, i.e. 0x80000000 bit set */
pol.policy.sadb_x_policy_priority = (uint32_t)vars->flow_priority;
/* IPSECREQUEST (Used as a SA-selector) */
pol.xisr.sadb_x_ipsecrequest_len = sizeof(struct sadb_x_ipsecrequest);
/* Protocol */
switch (vars->satype)
{
case SADB_SATYPE_AH:
pol.xisr.sadb_x_ipsecrequest_proto = IP_IPPROTO_AH;
break;
default:
pol.xisr.sadb_x_ipsecrequest_proto = IP_IPPROTO_ESP;
break;
}
if (IP_BIT_ISSET(vars->sa_flags, SADB_X_SAFLAGS_TUNNEL))
pol.xisr.sadb_x_ipsecrequest_mode = IPSEC_MODE_TUNNEL;
else
pol.xisr.sadb_x_ipsecrequest_mode = IPSEC_MODE_TRANSPORT;
/* Mode */
if (vars->reqid != 0)
{
pol.xisr.sadb_x_ipsecrequest_reqid = vars->reqid;
pol.xisr.sadb_x_ipsecrequest_level = IPSEC_LEVEL_UNIQUE;
}
else
{
switch (vars->flow_type)
{
case SADB_X_FLOW_TYPE_REQUIRE: /* Generate require message, discard packet */
pol.xisr.sadb_x_ipsecrequest_level = IPSEC_LEVEL_REQUIRE;
break;
/*!!TODO: support for MODE_ANY */
case SADB_X_FLOW_TYPE_ACQUIRE: /* Generate acquire message, send packet in cleartext */
default:
pol.xisr.sadb_x_ipsecrequest_level = IPSEC_LEVEL_USE;
break;
}
}
if (pol.xisr.sadb_x_ipsecrequest_mode == IPSEC_MODE_TUNNEL)
{
/* Add source&destination tunnel endpoints */
#ifdef IPCOM_USE_INET
if (vars->srctunnel.sa.sa_family == IP_AF_INET
|| vars->dsttunnel.sa.sa_family == IP_AF_INET)
{
struct Ip_sockaddr_in *src_sinp = (struct Ip_sockaddr_in *)&pol.sockbuf;
struct Ip_sockaddr_in *dst_sinp = (struct Ip_sockaddr_in *)((Ip_caddr_t)&pol.sockbuf + sizeof(struct Ip_sockaddr_in));
/* Tunnel source */
src_sinp->sin_len = sizeof(struct Ip_sockaddr_in);
src_sinp->sin_family = IP_AF_INET;
src_sinp->sin_port = vars->srctunnel.sin.sin_port;
src_sinp->sin_addr.s_addr = vars->srctunnel.sin.sin_addr.s_addr;
/* Tunnel destination */
dst_sinp->sin_len = sizeof(struct Ip_sockaddr_in);
dst_sinp->sin_family = IP_AF_INET;
dst_sinp->sin_port = vars->dsttunnel.sin.sin_port;
dst_sinp->sin_addr.s_addr = vars->dsttunnel.sin.sin_addr.s_addr;
pol.xisr.sadb_x_ipsecrequest_len += (2 * sizeof(struct Ip_sockaddr_in));
}
#endif /* IPCOM_USE_INET */
#ifdef IPCOM_USE_INET6
if (vars->srctunnel.sa.sa_family == IP_AF_INET6
|| vars->dsttunnel.sa.sa_family == IP_AF_INET6)
{
struct Ip_sockaddr_in6 *src_sin6p = (struct Ip_sockaddr_in6 *)&pol.sockbuf;
struct Ip_sockaddr_in6 *dst_sin6p = (struct Ip_sockaddr_in6 *)((Ip_caddr_t)&pol.sockbuf + sizeof(struct Ip_sockaddr_in6));
/* Tunnel source */
src_sin6p->sin6_len = sizeof(struct Ip_sockaddr_in6);
src_sin6p->sin6_family = IP_AF_INET6;
src_sin6p->sin6_port = vars->srctunnel.sin6.sin6_port;
ipcom_memcpy(&src_sin6p->sin6_addr, &vars->srctunnel.sin6.sin6_addr, sizeof(struct Ip_in6_addr));
/* Tunnel destination */
dst_sin6p->sin6_len = sizeof(struct Ip_sockaddr_in6);
dst_sin6p->sin6_family = IP_AF_INET6;
dst_sin6p->sin6_port = vars->dsttunnel.sin6.sin6_port;
ipcom_memcpy(&dst_sin6p->sin6_addr, &vars->dsttunnel.sin6.sin6_addr, sizeof(struct Ip_in6_addr));
pol.xisr.sadb_x_ipsecrequest_len += (2 * sizeof(struct Ip_sockaddr_in6));
}
#endif /* IPCOM_USE_INET6 */
}
pol.policy.sadb_x_policy_len += (IP_ROUNDUP(pol.xisr.sadb_x_ipsecrequest_len, 8) / sizeof(Ip_u64));
/* Calculate message length */
for (length = sizeof(struct sadb_msg), i = 1; i <= SADB_EXT_MAX; i++)
if (vars->exthdr[i] != IP_NULL)
length += (((struct sadb_ext *)vars->exthdr[i])->sadb_ext_len * sizeof(Ip_u64));
/* Allocate memory for the PFKEY write */
orgbuf = (Ip_u8 *)ipcom_malloc(length + sizeof(Ip_u64));
if (orgbuf == IP_NULL)
{
keyadm_printf(vars, "keyadm: out of memory"IP_LF);
return -1;
}
msgbuf = IP_PTR_ALIGN(orgbuf, 8); /* 64-bit align msgbuf */
ip_assert(((Ip_ptrdiff_t)msgbuf & 0x7L) == 0);
ipcom_memset(msgbuf, 0, length);
/* Set SADB_MSG */
vars->sadb->msg->sadb_msg_version = PF_KEY_V2;
vars->sadb->msg->sadb_msg_type = type;
vars->sadb->msg->sadb_msg_errno = 0;
vars->sadb->msg->sadb_msg_satype = satype;
vars->sadb->msg->sadb_msg_reserved = 0;
vars->sadb->msg->sadb_msg_len = (uint16_t)(length / sizeof(Ip_u64));
vars->sadb->msg->sadb_msg_seq = sadbmsgseq++;
vars->sadb->msg->sadb_msg_pid = ipcom_getpid();
/* Copy over all headers */
ipcom_memcpy(msgbuf, vars->sadb->msg, sizeof(struct sadb_msg));
for (length = sizeof(struct sadb_msg), i = 1; i <= SADB_EXT_MAX; i++)
if (vars->exthdr[i] != IP_NULL)
{
ipcom_memcpy(msgbuf + length,
vars->exthdr[i],
((struct sadb_ext *)vars->exthdr[i])->sadb_ext_len * sizeof(Ip_u64));
length += ((struct sadb_ext *)vars->exthdr[i])->sadb_ext_len * sizeof(Ip_u64);
}
/* Write the SADB message */
if (ipcom_send(vars->fd, (char*)msgbuf, length, 0) != length)
{
keyadm_printf(vars, "keyadm: ipcom_send() failed: %s (%d)"IP_LF,
ipcom_strerror(ipcom_errno), ipcom_errno);
if (ipcom_errno == IP_ERRNO_EINVAL || ipcom_errno == IP_ERRNO_ENOMEM
|| ipcom_errno == IP_ERRNO_ENOBUFS)
retval = -1;
}
if (orgbuf)
ipcom_free(orgbuf);
return retval;
}
#endif /* #ifdef IPIPSEC_USE_LINUX_PFKEYV2_API */
/*
*===========================================================================
* keyadm_receive_command
*===========================================================================
* Description:
* Parameters: vars and timeout_seconds (0 = block)
* Returns:
*
*/
static int
keyadm_receive_command(Vars *vars, Ip_u32 timeout_seconds)
{
int length;
int retval = -IP_ERRNO_EINVAL;
struct sadb_ext *ext;
/* Release previous memory */
if (vars->orgbuf)
{
ipcom_free(vars->orgbuf);
vars->orgbuf = IP_NULL;
}
/* Prepare ext array */
ipcom_memset(&vars->sadb->sa, 0, SADB_EXT_MAX * sizeof(void*)); /*lint !e419 */
/* Get buffer memory */
vars->orgbuf = (Ip_u8 *)ipcom_malloc(MAX_RCVBUF_SIZE + sizeof(Ip_u64));
if (vars->orgbuf == IP_NULL)
{
keyadm_printf(vars, "keyadm: out of memory, can't receive"IP_LF);
goto leave;
}
vars->msgbuf = IP_PTR_ALIGN(vars->orgbuf, 8); /* 64-bit align msgbuf */
ip_assert(((Ip_ptrdiff_t)vars->msgbuf & 0x7L) == 0);
ipcom_memset(vars->msgbuf, 0, MAX_RCVBUF_SIZE);
if (timeout_seconds != 0)
{
/* Set receive timeout */
struct Ip_timeval tv;
tv.tv_sec = timeout_seconds;
tv.tv_usec = 0;
length = ipcom_setsockopt(vars->fd, IP_SOL_SOCKET, IP_SO_RCVTIMEO, &tv, sizeof(tv));
if (length < 0)
{
keyadm_printf(vars, "ipcom_setsockopt() IP_SO_RCVTIMEO ");
return -IP_ERRNO_EINVAL;
}
}
/* Read a SADB message */
vars->sadb->msg = (struct sadb_msg *)vars->msgbuf;
length = (int)ipcom_recv(vars->fd, (char *)vars->msgbuf, MAX_RCVBUF_SIZE, 0);
if (length < (int)sizeof(struct sadb_msg))
{
if (length < 0)
{
if (ipcom_errno == IP_ERRNO_EWOULDBLOCK)
{
keyadm_printf(vars, "keyadm timeout"IP_LF);
return -IP_ERRNO_EWOULDBLOCK;
}
keyadm_printf(vars, "keyadm: ipcom_recv() failed: %s"IP_LF, ipcom_strerror(ipcom_errno));
keyadm_printf(vars, " (try raise key socket buffer size with -b option)"IP_LF);
}
else if (length >= 3 && vars->sadb->msg->sadb_msg_errno != 0)
keyadm_printf(vars, "keyadm: ipcom_recv() msgerrno=%s"IP_LF, ipcom_strerror(vars->sadb->msg->sadb_msg_errno));
else
keyadm_printf(vars, "keyadm: ipcom_recv() truncated SADB (%d)"IP_LF, length);
goto leave;
}
else if (length == MAX_RCVBUF_SIZE)
keyadm_printf(vars, "keyadm: received too large SADB (%d)"IP_LF, length);
/* Verify the SADB_MSG header */
if (vars->sadb->msg->sadb_msg_version != PF_KEY_V2)
keyadm_printf(vars, "keyadm: illegal sadb_msg_version (%d)"IP_LF, vars->sadb->msg->sadb_msg_version);
else if (vars->sadb->msg->sadb_msg_type > SADB_MAX
|| vars->sadb->msg->sadb_msg_type == SADB_RESERVED)
keyadm_printf(vars, "keyadm: illegal sadb_msg_type (%d)"IP_LF, vars->sadb->msg->sadb_msg_type);
else if (vars->sadb->msg->sadb_msg_reserved != 0)
keyadm_printf(vars, "keyadm: illegal sadb_msg_reserved (%d)"IP_LF, vars->sadb->msg->sadb_msg_reserved);
else if ((int) (vars->sadb->msg->sadb_msg_len * sizeof(Ip_u64)) != length)
keyadm_printf(vars, "keyadm: length mismatch (sadb_msg_len=%d, length=%d)"IP_LF,
vars->sadb->msg->sadb_msg_len * sizeof(Ip_u64), length);
vars->msgbuf += sizeof(struct sadb_msg);
length -= sizeof(struct sadb_msg);
/* Verify the extensions */
for (ext = (struct sadb_ext *)vars->msgbuf;
length >= (int)sizeof(struct sadb_ext);
ext = (struct sadb_ext *)vars->msgbuf)
{
int ext_len;
/* Extension headers must start at 64-bit alignment */
if (((Ip_ptrdiff_t)ext & 0x7L) != 0)
keyadm_printf(vars, "keyadm: bad alignment for extension %d"IP_LF, ext->sadb_ext_type);
ext_len = ext->sadb_ext_len * sizeof(Ip_u64);
if (ext_len == 0 || length < ext_len)
{
keyadm_printf(vars, "keyadm: illegal EXT length (%d)"IP_LF, ext_len);
return -IP_ERRNO_EINVAL;
}
if (ext->sadb_ext_type == SADB_EXT_RESERVED || ext->sadb_ext_type > SADB_EXT_MAX)
{
keyadm_printf(vars, "keyadm: illegal/unknown EXT type (%d)"IP_LF, ext->sadb_ext_type);
return -IP_ERRNO_EINVAL;
}
else
{
/* [2.3] Only one instance of an extension header */
if (vars->exthdr[ext->sadb_ext_type] != IP_NULL)
keyadm_printf(vars, "keyadm: duplicate EXT type (%d)"IP_LF, ext->sadb_ext_type);
else
vars->exthdr[ext->sadb_ext_type] = ext;
/* _Exact_ extension header size check */
if (ipipsec_pfkeyv2_ext_size[ext->sadb_ext_type] > 0
&& ipipsec_pfkeyv2_ext_size[ext->sadb_ext_type] != ext_len)
return -IP_ERRNO_EINVAL;
/* _Minimum_ extension header size check */
if (ipipsec_pfkeyv2_ext_size[ext->sadb_ext_type] < 0
&& ext_len < -ipipsec_pfkeyv2_ext_size[ext->sadb_ext_type])
return -IP_ERRNO_EINVAL;
/* next extension header */
length -= ext_len;
vars->msgbuf += ext_len;
}
}
if (vars->sadb->msg->sadb_msg_errno != 0)
(void)ipcom_errno_set(vars->sadb->msg->sadb_msg_errno);
if (length != 0)
keyadm_printf(vars, "keyadm: trailing SADB bytes (%d)"IP_LF, length);
return 0;
leave:
return retval;
}
/*
*===========================================================================
* keyadm_print_command
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
static int
keyadm_print_command(Vars *vars)
{
union Ip_sockaddr_union *sockaddr;
union Ip_sockaddr_union *sockaddr_max;
char str[128];
int addr_offset;
Ip_time_t addtime, usetime;
Ip_u32 bytes;
Ip_u16 min_port;
Ip_u16 max_port;
ip_assert(vars->sadb);
ip_assert(vars->sadb->msg);
keyadm_printf(vars, "SADB_MSG: msgtype=%s err=%d satype=%s len=%d seq=%d pid=0x%x"IP_LF,
MSG_TYPE(vars->sadb->msg->sadb_msg_type),
vars->sadb->msg->sadb_msg_errno,
MSG_SATYPE(vars->sadb->msg->sadb_msg_satype),
vars->sadb->msg->sadb_msg_len * sizeof(Ip_u64),
vars->sadb->msg->sadb_msg_seq,
vars->sadb->msg->sadb_msg_pid);
if (vars->sadb->msg->sadb_msg_errno)
{
keyadm_printf(vars, " ERRNO: %s (%d)"IP_LF,
ipcom_strerror(vars->sadb->msg->sadb_msg_errno),
vars->sadb->msg->sadb_msg_errno);
}
/* SADB_EXT_SA */
if (vars->sadb->sa)
{
char authbuf[32];
char encryptbuf[32];
keyadm_printf(vars, " SA: spi=%x sta=%s auth=%s enc=%s replay=%d %s"IP_LF,
ip_ntohl(vars->sadb->sa->sadb_sa_spi),
SA_STATE(vars->sadb->sa->sadb_sa_state),
ipcom_cmd_key_to_str(sa_auth_id_map, vars->sadb->sa->sadb_sa_auth,
authbuf, sizeof(authbuf)),
ipcom_cmd_key_to_str(sa_encrypt_id_map, vars->sadb->sa->sadb_sa_encrypt,
encryptbuf, sizeof(encryptbuf)),
(int)vars->sadb->sa->sadb_sa_replay,
keyadm_cmd_bits_to_str((char **)keyadm_sa_flags_bitmap,
vars->sadb->sa->sadb_sa_flags,
str, sizeof(str)));
}
/* SADB_EXT_ADDRESS_SRC */
if (vars->sadb->address_src)
{
sockaddr = (union Ip_sockaddr_union *)((Ip_u8 *)vars->sadb->address_src + sizeof(struct sadb_address));
addr_offset = (sockaddr->sa.sa_family == IP_AF_INET) ? 2 : 6;
keyadm_printf(vars, " SRC: addr=%s",
ipcom_inet_ntop(sockaddr->sa.sa_family,
&sockaddr->sa.sa_data[addr_offset],
str, sizeof(str)));
if (vars->sadb->address_src->sadb_address_proto != 0)
keyadm_printf(vars, " proto=%s",
ipcom_ipproto_name(vars->sadb->address_src->sadb_address_proto));
if (sockaddr->sa.sa_family == IP_AF_INET)
{
if (sockaddr->sin.sin_port)
keyadm_printf(vars, " port=%d",
ip_ntohs(sockaddr->sin.sin_port));
}
#ifdef IPCOM_USE_INET6
if (sockaddr->sa.sa_family == IP_AF_INET6)
{
if (sockaddr->sin6.sin6_port)
keyadm_printf(vars, " port=%d",
ip_ntohs(sockaddr->sin6.sin6_port));
}
#endif
keyadm_printf(vars, IP_LF);
}
/* SADB_EXT_ADDRESS_DST */
if (vars->sadb->address_dst)
{
sockaddr = (union Ip_sockaddr_union *)((Ip_u8 *)vars->sadb->address_dst + sizeof(struct sadb_address));
addr_offset = (sockaddr->sa.sa_family == IP_AF_INET) ? 2 : 6;
if (sockaddr->sa.sa_family)
keyadm_printf(vars, " DST: addr=%s",
ipcom_inet_ntop(sockaddr->sa.sa_family, &sockaddr->sa.sa_data[addr_offset],
str, sizeof(str)));
if (vars->sadb->address_dst->sadb_address_proto != 0)
keyadm_printf(vars, " proto=%s",
ipcom_ipproto_name(vars->sadb->address_dst->sadb_address_proto));
if (sockaddr->sa.sa_family == IP_AF_INET)
{
if (sockaddr->sin.sin_port)
keyadm_printf(vars, " port=%d",
ip_ntohs(sockaddr->sin.sin_port));
}
#ifdef IPCOM_USE_INET6
if (sockaddr->sa.sa_family == IP_AF_INET6)
{
if (sockaddr->sin6.sin6_port)
keyadm_printf(vars, " port=%d",
ip_ntohs(sockaddr->sin6.sin6_port));
}
#endif
keyadm_printf(vars, IP_LF);
}
/* SADB_EXT_ADDRESS_PROXY */
if (vars->sadb->address_proxy)
{
sockaddr = (union Ip_sockaddr_union *)((Ip_u8 *)vars->sadb->address_proxy + sizeof(struct sadb_address));
addr_offset = (sockaddr->sa.sa_family == IP_AF_INET) ? 2 : 6;
keyadm_printf(vars, " PROXY: addr=%s"IP_LF,
ipcom_inet_ntop(sockaddr->sa.sa_family,
&sockaddr->sa.sa_data[addr_offset],
str, sizeof(str)));
}
/* SADB_EXT_KEY_AUTH */
if (vars->sadb->key_auth)
{
keyadm_printf(vars, " AUTHKEY: bits=%d"IP_LF,
(int)vars->sadb->key_auth->sadb_key_bits);
}
/* SADB_EXT_KEY_ENCRYPT */
if (vars->sadb->key_encrypt)
{
keyadm_printf(vars, " ENCKEY: bits=%d"IP_LF,
(int)vars->sadb->key_encrypt->sadb_key_bits);
}
/* SADB_X_EXT_PROTOCOL */
if (vars->sadb->protocol)
{
char port0[16], port1[16];
keyadm_printf(vars, "PROTOCOL: proto=%s",
ipcom_ipproto_name(vars->sadb->protocol->sadb_protocol_proto));
if (vars->sadb->protocol->sadb_protocol_ports0)
ipcom_sprintf(port0, "%d", vars->sadb->protocol->sadb_protocol_ports0);
else
ipcom_strcpy(port0, "any");
if (vars->sadb->protocol->sadb_protocol_ports1)
ipcom_sprintf(port1, "%d", vars->sadb->protocol->sadb_protocol_ports1);
else
ipcom_strcpy(port1, "any");
switch (vars->sadb->protocol->sadb_protocol_proto)
{
case IP_IPPROTO_ICMP:
case IP_IPPROTO_ICMPV6:
keyadm_printf(vars, " type=%s code=%s", port0, port1);
break;
case IP_IPPROTO_MH:
keyadm_printf(vars, " type=%s", port0);
break;
default:
break;
}
keyadm_printf(vars, IP_LF);
}
/* SADB_X_EXT_SRC_FLOW */
if (vars->sadb->src_flow)
{
sockaddr = (union Ip_sockaddr_union *)((Ip_u8 *)vars->sadb->src_flow + sizeof(struct sadb_address));
addr_offset = (sockaddr->sa.sa_family == IP_AF_INET) ? 2 : 6;
min_port = ip_ntohs(sockaddr->sin.sin_port);
if (sockaddr->sa.sa_family)
keyadm_printf(vars, " SRCFLOW: addr=%s",
ipcom_inet_ntop(sockaddr->sa.sa_family, &sockaddr->sa.sa_data[addr_offset],
str, sizeof(str)));
if (vars->sadb->srcmax_flow)
{
sockaddr_max = (union Ip_sockaddr_union *)((Ip_u8 *)vars->sadb->srcmax_flow + sizeof(struct sadb_address));
if (sockaddr_max->sa.sa_family
&& ipcom_memcmp(&sockaddr->sa.sa_data[addr_offset], &sockaddr_max->sa.sa_data[addr_offset],
sockaddr_max->sa.sa_family == IP_AF_INET ? 4 : 16))
keyadm_printf(vars, "-%s",
ipcom_inet_ntop(sockaddr_max->sa.sa_family, &sockaddr_max->sa.sa_data[addr_offset],
str, sizeof(str)));
}
if (vars->sadb->src_mask)
{
sockaddr = (union Ip_sockaddr_union *)((Ip_u8 *)vars->sadb->src_mask + sizeof(struct sadb_address));
addr_offset = (sockaddr->sa.sa_family == IP_AF_INET) ? 2 : 6;
if (sockaddr->sa.sa_family)
keyadm_printf(vars, "/%d",
ipipsec_addrmasklen(sockaddr->sa.sa_family, &sockaddr->sa.sa_data[addr_offset]));
}
if (vars->sadb->srcmax_flow)
{
sockaddr = (union Ip_sockaddr_union *)((Ip_u8 *)vars->sadb->srcmax_flow + sizeof(struct sadb_address));
max_port = ip_ntohs(sockaddr->sin.sin_port);
}
else
max_port = 0;
if (min_port)
{
if (max_port)
keyadm_printf(vars, " ports=%d-%d", min_port, max_port);
else
keyadm_printf(vars, " port=%d", min_port);
}
keyadm_printf(vars, IP_LF);
}
/* SADB_X_EXT_DST_FLOW */
if (vars->sadb->dst_flow)
{
sockaddr = (union Ip_sockaddr_union *)((Ip_u8 *)vars->sadb->dst_flow + sizeof(struct sadb_address));
addr_offset = (sockaddr->sa.sa_family == IP_AF_INET) ? 2 : 6;
min_port = ip_ntohs(sockaddr->sin.sin_port);
if (sockaddr->sa.sa_family)
keyadm_printf(vars, " DSTFLOW: addr=%s",
ipcom_inet_ntop(sockaddr->sa.sa_family, &sockaddr->sa.sa_data[addr_offset],
str, sizeof(str)));
if (vars->sadb->dstmax_flow)
{
sockaddr_max = (union Ip_sockaddr_union *)((Ip_u8 *)vars->sadb->dstmax_flow + sizeof(struct sadb_address));
if (sockaddr_max->sa.sa_family
&& ipcom_memcmp(&sockaddr->sa.sa_data[addr_offset], &sockaddr_max->sa.sa_data[addr_offset],
sockaddr_max->sa.sa_family == IP_AF_INET ? 4 : 16))
keyadm_printf(vars, "-%s",
ipcom_inet_ntop(sockaddr_max->sa.sa_family, &sockaddr_max->sa.sa_data[addr_offset],
str, sizeof(str)));
}
if (vars->sadb->dst_mask)
{
sockaddr = (union Ip_sockaddr_union *)((Ip_u8 *)vars->sadb->dst_mask + sizeof(struct sadb_address));
addr_offset = (sockaddr->sa.sa_family == IP_AF_INET) ? 2 : 6;
if (sockaddr->sa.sa_family)
keyadm_printf(vars, "/%d",
ipipsec_addrmasklen(sockaddr->sa.sa_family, &sockaddr->sa.sa_data[addr_offset]));
}
if (vars->sadb->dstmax_flow)
{
sockaddr = (union Ip_sockaddr_union *)((Ip_u8 *)vars->sadb->dstmax_flow + sizeof(struct sadb_address));
max_port = ip_ntohs(sockaddr->sin.sin_port);
}
else
max_port = 0;
if (min_port)
{
if (max_port)
keyadm_printf(vars, " ports=%d-%d", min_port, max_port);
else
keyadm_printf(vars, " port=%d", min_port);
}
keyadm_printf(vars, IP_LF);
}
/* SADB_X_EXT_FLOW_OPTIONS */
if (vars->sadb->flowopt)
{
keyadm_printf(vars, " FLOWOPT: type=%s prio=%d dscp=0x%x dir=%s id=%d"IP_LF,
FLOW_TYPE(vars->sadb->flowopt->sadb_flowopt_type),
(int)vars->sadb->flowopt->sadb_flowopt_priority,
vars->sadb->flowopt->sadb_flowopt_dscp,
vars->sadb->flowopt->sadb_flowopt_direction == 1 ? "in" :
vars->sadb->flowopt->sadb_flowopt_direction == 2 ? "out" : "?",
(int)vars->sadb->flowopt->sadb_flowopt_id);
}
/* SADB_X_EXT_SA_OPTIONS */
if (vars->sadb->saopt)
{
keyadm_printf(vars, " SAOPT: priority=%d"IP_LF,
vars->sadb->saopt->sadb_saopt_priority);
}
/* SADB_EXT_SPIRANGE */
if (vars->sadb->spirange)
{
keyadm_printf(vars, "SPIRANGE: min=0x%x max=0x%x"IP_LF,
vars->sadb->spirange->sadb_spirange_min,
vars->sadb->spirange->sadb_spirange_max);
}
/* SADB_EXT_LIFETIME_CURRENT */
if (vars->sadb->lifetime_current)
{
addtime = (Ip_time_t)IP_U64_GETLO(vars->sadb->lifetime_current->sadb_lifetime_addtime);
usetime = (Ip_time_t)IP_U64_GETLO(vars->sadb->lifetime_current->sadb_lifetime_usetime);
bytes = IP_U64_GETLO(vars->sadb->lifetime_current->sadb_lifetime_bytes);
#ifdef _WRS_CONFIG_TIME_T_LONG_LONG
keyadm_printf(vars, " CURRENT: addtime=%lld usetime=%lld bytes=%ld"IP_LF,
addtime, usetime, bytes);
#else
keyadm_printf(vars, " CURRENT: addtime=%ld usetime=%ld bytes=%ld"IP_LF,
addtime, usetime, bytes);
#endif
}
/* SADB_EXT_LIFETIME_SOFT */
if (vars->sadb->lifetime_soft)
{
addtime = (Ip_time_t)IP_U64_GETLO(vars->sadb->lifetime_soft->sadb_lifetime_addtime);
usetime = (Ip_time_t)IP_U64_GETLO(vars->sadb->lifetime_soft->sadb_lifetime_usetime);
bytes = IP_U64_GETLO(vars->sadb->lifetime_soft->sadb_lifetime_bytes);
#ifdef _WRS_CONFIG_TIME_T_LONG_LONG
keyadm_printf(vars, " SOFT: addtime=%lld usetime=%lld bytes=%ld"IP_LF,
addtime, usetime, bytes);
#else
keyadm_printf(vars, " SOFT: addtime=%ld usetime=%ld bytes=%ld"IP_LF,
addtime, usetime, bytes);
#endif
}
/* SADB_EXT_LIFETIME_HARD */
if (vars->sadb->lifetime_hard)
{
addtime = (Ip_time_t)IP_U64_GETLO(vars->sadb->lifetime_hard->sadb_lifetime_addtime);
usetime = (Ip_time_t)IP_U64_GETLO(vars->sadb->lifetime_hard->sadb_lifetime_usetime);
bytes = IP_U64_GETLO(vars->sadb->lifetime_hard->sadb_lifetime_bytes);
#ifdef _WRS_CONFIG_TIME_T_LONG_LONG
keyadm_printf(vars, " HARD: addtime=%lld usetime=%lld bytes=%ld"IP_LF,
addtime, usetime, bytes);
#else
keyadm_printf(vars, " HARD: addtime=%ld usetime=%ld bytes=%ld"IP_LF,
addtime, usetime, bytes);
#endif
}
/* SADB_X_SAFLAGS_UDPENCAP */
if (vars->sadb->udpencap)
keyadm_printf(vars, "UDPENCAP: port=%d"IP_LF, ip_ntohs(vars->sadb->udpencap->sadb_x_udpencap_src_port));
#ifdef IPIPSEC_USE_LINUX_PFKEYV2_API
if (vars->sadb->lx_policy)
{
keyadm_printf(vars, " POLICY: type=%s prio=%d dir=%s id=%d"IP_LF,
ipsec_policy_linux[vars->sadb->lx_policy->sadb_x_policy_type],
(int)vars->sadb->lx_policy->sadb_x_policy_priority,
ipsec_dir_linux[vars->sadb->lx_policy->sadb_x_policy_dir],
(int)vars->sadb->lx_policy->sadb_x_policy_id);
if (vars->sadb->lx_policy->sadb_x_policy_len * 8
>= (int)(sizeof(struct sadb_x_policy) + sizeof(struct sadb_x_ipsecrequest)))
{
struct sadb_x_ipsecrequest *xisr;
xisr = (struct sadb_x_ipsecrequest *)(vars->sadb->lx_policy + 1);
keyadm_printf(vars, " len=%d proto=%d mode=%d level=%d reqid=%d"IP_LF,
(int)xisr->sadb_x_ipsecrequest_len,
(int)xisr->sadb_x_ipsecrequest_proto,
(int)xisr->sadb_x_ipsecrequest_mode,
(int)xisr->sadb_x_ipsecrequest_level,
(int)xisr->sadb_x_ipsecrequest_reqid);
if (vars->sadb->lx_policy->sadb_x_policy_len * 8
>= (int)(sizeof(struct sadb_x_policy) + sizeof(struct sadb_x_ipsecrequest) + 2 * sizeof(struct Ip_sockaddr_in)))
{
/* Extract source/tunnel endpoints */
sockaddr = (union Ip_sockaddr_union *)((Ip_caddr_t)xisr + sizeof(*xisr));
#ifdef IPCOM_USE_INET
if (sockaddr->sa.sa_family == IP_AF_INET)
{
keyadm_printf(vars, " srctunnel=%s",
ipcom_inet_ntop(IP_AF_INET, &sockaddr->sin.sin_addr.s_addr,
str, sizeof(str)));
sockaddr = (union Ip_sockaddr_union *)((Ip_caddr_t)sockaddr
+ sizeof(struct Ip_sockaddr_in));
keyadm_printf(vars, " dsttunnel=%s"IP_LF,
ipcom_inet_ntop(IP_AF_INET, &sockaddr->sin.sin_addr.s_addr,
str, sizeof(str)));
}
#endif /* IPCOM_USE_INET */
#ifdef IPCOM_USE_INET6
if (sockaddr->sa.sa_family == IP_AF_INET6)
{
if (vars->sadb->lx_policy->sadb_x_policy_len * 8
>= (int)(sizeof(struct sadb_x_policy) + sizeof(struct sadb_x_ipsecrequest) + 2 * sizeof(struct Ip_sockaddr_in6)))
{
keyadm_printf(vars, " srctunnel=%s",
ipcom_inet_ntop(IP_AF_INET6, &sockaddr->sin6.sin6_addr, str, sizeof(str)));
sockaddr = (union Ip_sockaddr_union *)((Ip_caddr_t)sockaddr
+ sizeof(struct Ip_sockaddr_in6));
keyadm_printf(vars, " dsttunnel=%s"IP_LF,
ipcom_inet_ntop(IP_AF_INET6, &sockaddr->sin6.sin6_addr, str, sizeof(str)));
}
}
#endif /* IPCOM_USE_INET6 */
}
}
}
if (vars->sadb->lx_sa2)
{
keyadm_printf(vars, " SA2: mode=%s reqid=%d"IP_LF,
vars->sadb->lx_sa2->sadb_x_sa2_mode == IPSEC_MODE_ANY ? "any" :
vars->sadb->lx_sa2->sadb_x_sa2_mode == IPSEC_MODE_TRANSPORT ? "transport" :
vars->sadb->lx_sa2->sadb_x_sa2_mode == IPSEC_MODE_TUNNEL ? "tunnel" : "?",
vars->sadb->lx_sa2->sadb_x_sa2_reqid);
}
#endif /* #ifdef IPIPSEC_USE_LINUX_PFKEYV2_API */
keyadm_printf(vars, "------------------------------------------"IP_LF);
return vars->sadb->msg->sadb_msg_errno == 0 ? 0 : -1;
}
/*
*===========================================================================
* keyadm_get_usage
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
static void
keyadm_get_usage(Vars *vars)
{
keyadm_printf(vars,
"Get (info about) a Security Association (SA)"IP_LF
" usage: keyadm get <selectors>"IP_LF);
keyadm_printf(vars,
" mandatory selectors: "IP_LF
" -spi <val> SPI (in hex without the 0x)"IP_LF
" -src <ip> source IP address"IP_LF
" -dst <ip> destination IP address"IP_LF
" -proto <name> security protocol <esp|ah|ipip>"IP_LF
);
keyadm_printf(vars,
" optional selectors: "IP_LF
" -sapri <val> priority (-128=highest to 127=lowest)"IP_LF
" -egress output SA (default)"IP_LF
" -ingress input SA"IP_LF
);
}
/*
*===========================================================================
* keyadm_get
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
static int
keyadm_get(Vars *vars)
{
if (vars->have_satype == 0)
{
keyadm_printf(vars, "keyadm: missing modifier '-proto'"IP_LF);
return -1;
}
if (keyadm_send_command(vars, SADB_GET, vars->satype) == 0)
{
(void)keyadm_receive_command(vars, 0);
return keyadm_print_command(vars);
}
return -1;
}
/*
*===========================================================================
* keyadm_dump
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
static int
keyadm_dump(Vars *vars)
{
if (keyadm_send_command(vars, SADB_DUMP, vars->satype) == 0)
{
struct Ip_timeval tv;
int count = 0;
tv.tv_sec = 3;
tv.tv_usec = 0;
if (ipcom_setsockopt(vars->fd, IP_SOL_SOCKET, IP_SO_RCVTIMEO, &tv, sizeof(tv)) < 0)
{
keyadm_printf(vars, "keyadm: setsockopt(IP_SO_RCVTIMEO,x) failed : %s ",
ipcom_strerror(ipcom_errno));
return 0;
}
do
{
if (keyadm_receive_command(vars, 0) != 0)
break;
if (keyadm_print_command(vars) == 0)
count++;
}
while (vars->sadb->msg->sadb_msg_errno == 0
&& vars->sadb->msg->sadb_msg_seq);
keyadm_printf(vars, "Total of %d security associations"IP_LF, count);
}
return 0;
}
/*
*===========================================================================
* keyadm_flush
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
static int
keyadm_flush(Vars *vars)
{
if (keyadm_send_command(vars, SADB_FLUSH, vars->satype) == 0)
{
(void)keyadm_receive_command(vars, 0);
return keyadm_print_command(vars);
}
return -1;
}
/*
*===========================================================================
* keyadm_getspi_usage
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
static void
keyadm_getspi_usage(Vars *vars)
{
keyadm_printf(vars,
"Create a larval Security Association (SA) with a (random) SPI"IP_LF
" usage: keyadm getspi <selectors> <modifiers>"IP_LF);
keyadm_printf(vars,
" mandatory selectors: "IP_LF
" -src <ip> source IP address"IP_LF
" -dst <ip> destination IP address"IP_LF
" -proto <name> security protocol <esp|ah|ipip>"IP_LF
);
keyadm_printf(vars,
" optional selectors: "IP_LF
" -sapri <val> priority (-128=highest to 127=lowest)"IP_LF
" -egress output SA (default)"IP_LF
" -ingress input SA"IP_LF
);
keyadm_printf(vars,
" mandatory modifiers:"IP_LF
" -minspi <val> min SPI value (in hex)"IP_LF
" -maxspi <val> max SPI value (in hex)"IP_LF
);
}
/*
*===========================================================================
* keyadm_getspi
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
static int
keyadm_getspi(Vars *vars)
{
if (vars->have_satype == 0)
{
keyadm_printf(vars, "keyadm: missing modifier '-proto'"IP_LF);
return -1;
}
if (keyadm_send_command(vars, SADB_GETSPI, vars->satype) == 0)
{
(void)keyadm_receive_command(vars, 0);
return keyadm_print_command(vars);
}
return -1;
}
/*
*===========================================================================
* keyadm_sacheck
*===========================================================================
*/
static int
keyadm_sacheck(Vars *vars, Ip_bool update)
{
if (vars->test)
return 0;
if (vars->have_satype == 0)
{
keyadm_printf(vars, "keyadm: missing modifier '-proto'"IP_LF);
return -1;
}
if (update == IP_FALSE)
{
if (vars->satype == SADB_SATYPE_ESP)
{
if (vars->encrypt_type == SADB_EALG_UNSET)
{
keyadm_printf(vars, "keyadm: missing modifier '-enc'"IP_LF);
return -1;
}
if (vars->encrypt_type > SADB_EALG_NONE
&& vars->encrypt_type <= SADB_EALG_MAX
&& vars->encrypt_bytes == 0)
{
keyadm_printf(vars, "keyadm: missing modifier '-ekey'"IP_LF);
return -1;
}
}
if (vars->satype == SADB_SATYPE_ESP || vars->satype == SADB_SATYPE_AH)
{
if (vars->auth_type == SADB_AALG_UNSET)
{
keyadm_printf(vars, "keyadm: missing modifier '-auth'"IP_LF);
return -1;
}
if (vars->auth_type > SADB_AALG_NONE
&& vars->auth_type <= SADB_AALG_MAX
&& vars->auth_bytes == 0)
{
keyadm_printf(vars, "keyadm: missing modifier '-akey'"IP_LF);
return -1;
}
}
}
return 0;
}
/*
*===========================================================================
* keyadm_update_usage
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
static void
keyadm_update_usage(Vars *vars)
{
keyadm_printf(vars,
"Update a Security Association (SA)"IP_LF
" usage: keyadm update <selectors> <modifiers>"IP_LF);
keyadm_printf(vars,
" mandatory selectors: "IP_LF
" -spi <val> SPI (in hex without the 0x)"IP_LF
" -src <ip> source IP address"IP_LF
" -dst <ip> destination IP address"IP_LF
" -proto <name> security protocol <esp|ah|ipip>"IP_LF
);
keyadm_printf(vars,
" optional selectors: "IP_LF
" -sapri <val> priority (-128=highest to 127=lowest)"IP_LF
" -egress output SA (default)"IP_LF
" -ingress input SA"IP_LF
);
keyadm_printf(vars,
" mandatory modifiers:"IP_LF
" -enc <alg> encryption algorithm <des|3des|blf|cast|aes|aesctr>"IP_LF
" -ekey <key> encryption key (in hex, each char is 4 bits)"IP_LF
" -auth <alg> authentication algorithm <md5|sha1|sha256|sha384|sha512|rmd160|aesmac>"IP_LF
" -akey <key> authentication key (in hex, each char is 4 bits)"IP_LF
);
keyadm_printf(vars,
" optional modifiers:"IP_LF
" -proxy <ip> proxy IP address (for tunneling)"IP_LF
" -replay <val> replay counter (0-255, 0=disabled)"IP_LF
" -forcetunnel force tunneling mode"IP_LF
" -esn enable Extended Sequence Numbers (ESN)"IP_LF
" -srcreq source IP must match in SA lookup"IP_LF
);
keyadm_printf(vars,
" -tfc enable TFC (ESP only)"IP_LF
" -udpencap <port> enable ESP UDP encap using <port> (ESP only)"IP_LF
" -clrdf clear DF-bit on outer IPv4 header"IP_LF
" -setdf set DF-bit on outer IPv4 header"IP_LF
);
keyadm_printf(vars,
" -ls <sec> soft add-lifetime in seconds"IP_LF
" -lh <sec> hard add-lifetime in seconds"IP_LF
" -bs <bytes> soft lifetime in bytes"IP_LF
" -bh <bytes> hard lifetime in bytes"IP_LF
" -ecn enable ECN handling (ESP tunnel mode only)"IP_LF
);
}
/*
*===========================================================================
* keyadm_update
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
static int
keyadm_update(Vars *vars)
{
if (keyadm_sacheck(vars, IP_TRUE) != 0)
return -1;
if (keyadm_send_command(vars, SADB_UPDATE, vars->satype) == 0)
{
(void)keyadm_receive_command(vars, 0);
return keyadm_print_command(vars);
}
return -1;
}
/*
*===========================================================================
* keyadm_add_usage
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
static void
keyadm_add_usage(Vars *vars)
{
keyadm_printf(vars,
"Add a Security Association (SA)"IP_LF
" usage: keyadm add <selectors> <modifiers>"IP_LF);
keyadm_printf(vars,
" mandatory selectors: "IP_LF
" -spi <val> SPI (in hex without the 0x)"IP_LF
" -src <ip> source IP address"IP_LF
" -dst <ip> destination IP address"IP_LF
" -proto <name> security protocol <esp|ah|ipip>"IP_LF
);
keyadm_printf(vars,
" optional selectors: "IP_LF
" -sapri <val> priority (-128=highest to 127=lowest)"IP_LF
" -egress output SA (default)"IP_LF
" -ingress input SA"IP_LF
);
keyadm_printf(vars,
" mandatory modifiers:"IP_LF
" -enc <alg> encryption algorithm <des|3des|blf|cast|aes|aesctr>"IP_LF
" -ekey <key> encryption key (in hex, each char is 4 bits)"IP_LF
" -auth <alg> authentication algorithm <md5|sha1|sha256|sha384|sha512|rmd160|aesmac>"IP_LF
" -akey <key> authentication key (in hex, each char is 4 bits)"IP_LF
);
keyadm_printf(vars,
" optional modifiers:"IP_LF
" -proxy <ip> proxy IP address (for tunneling)"IP_LF
" -replay <val> replay counter (0-255, 0=disabled)"IP_LF
" -forcetunnel force tunneling mode"IP_LF
);
keyadm_printf(vars,
" -ls <sec> soft add-lifetime in seconds"IP_LF
" -lh <sec> hard add-lifetime in seconds"IP_LF
" -bs <bytes> soft lifetime in bytes"IP_LF
" -bh <bytes> hard lifetime in bytes"IP_LF
" -ecn enable ECN handling (ESP tunnel mode only)"IP_LF
" -esn enable ESN (Extended Sequence Numbers)"IP_LF
);
keyadm_printf(vars,
" -srcreq source IP must match in SA lookup"IP_LF
" -tfc enable TFC (ESP only)"IP_LF
" -udpencap <port> enable ESP UDP encap using <port> (ESP only)"IP_LF
" -clrdf clear DF-bit on outer IPv4 header"IP_LF
" -setdf set DF-bit on outer IPv4 header"IP_LF
" -linux enable Linux style SADB_ADD"IP_LF
" -u <id> Linux policy entry identifier"IP_LF
);
}
/*
*===========================================================================
* keyadm_add
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
static int
keyadm_add(Vars *vars)
{
if (keyadm_sacheck(vars, IP_FALSE) != 0)
return -1;
if (keyadm_send_command(vars, SADB_ADD, vars->satype) == 0)
{
(void)keyadm_receive_command(vars, 0);
return keyadm_print_command(vars);
}
return -1;
}
/*
*===========================================================================
* keyadm_delete_usage
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
static void
keyadm_delete_usage(Vars *vars)
{
keyadm_printf(vars,
"Delete a Security Association (SA)"IP_LF
" usage: keyadm delete <selectors | -id <id>> [-chain]"IP_LF);
keyadm_printf(vars,
" mandatory selectors: "IP_LF
" -spi <val> SPI (in hex without the 0x)"IP_LF
" -src <ip> source IP address"IP_LF
" -dst <ip> destination IP address"IP_LF
" -proto <name> security protocol <esp|ah|ipip>"IP_LF
);
keyadm_printf(vars,
" optional selectors: "IP_LF
" -sapri <val> priority (-128=highest to 127=lowest)"IP_LF
" -egress output SA (default)"IP_LF
" -ingress input SA"IP_LF
);
keyadm_printf(vars,
" optional modifier:"IP_LF
" -chain used to remove the whole chain"IP_LF
);
}
/*
*===========================================================================
* keyadm_delete
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
static int
keyadm_delete(Vars *vars)
{
if (vars->test == 0 && vars->have_satype == 0)
{
keyadm_printf(vars, "keyadm: missing modifier '-proto'"IP_LF);
return -1;
}
if (keyadm_send_command(vars, SADB_DELETE, vars->satype) == 0)
{
(void)keyadm_receive_command(vars, 0);
return keyadm_print_command(vars);
}
return -1;
}
/*
*===========================================================================
* keyadm_addflow_usage
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
static void
keyadm_addflow_usage(Vars *vars)
{
keyadm_printf(vars,
"Add a Flow (Security Policy)"IP_LF
" usage: keyadm addflow <selectors> <type> [SA selectors] [-replace]"IP_LF
);
keyadm_printf(vars,
" mandatory selectors:"IP_LF
" -srcflow <ip> source address"IP_LF
" -dstflow <ip> destination address"IP_LF
);
keyadm_printf(vars,
" optional selectors:"IP_LF
" -srcmask <mask> source mask (default all 1's)"IP_LF
" -dstmask <mask> destination mask (default all 1's)"IP_LF
" -egress output flow (default)"IP_LF
" -ingress input flow"IP_LF
);
keyadm_printf(vars,
" -srcmaxflow <ip> source max address (for linear range)"IP_LF
" -dstmaxflow <ip> destination max address (for linear range)"IP_LF
" -flowpri <prio> flow priority (-128 to +127, -128=highest)"IP_LF
" -dscp <val> DSCP value (in hex without the 0x)"IP_LF
);
keyadm_printf(vars,
" optional IP protocol specific selectors:"IP_LF
" -transport <val> IP protocol (ANY=0, TCP=6, UDP=17 etc)"IP_LF
" -srcport <port> UDP/TCP source port"IP_LF
" -dstport <port> UDP/TCP destination port"IP_LF
" -srcmaxport <port> UDP/TCP source max port (for linear range)"IP_LF
" -dstmaxport <port> UDP/TCP destination port (for linear range)"IP_LF
);
keyadm_printf(vars,
" -icmptype <val> ICMP type (specified as value)"IP_LF
" -icmpcode <val> ICMP code (specified as value)"IP_LF
" -mhtype <val> MH type (specified as value)"IP_LF
);
keyadm_printf(vars,
" optional type:"IP_LF
" -use use flow (default)"IP_LF
" -bypass bypass flow"IP_LF
" -deny deny flow"IP_LF
" -acquire acquire flow"IP_LF
" -require require flow"IP_LF
);
keyadm_printf(vars,
" optional SA selectors (for '-use' flows): "IP_LF
" -spi <val> SPI (in hex without the 0x)"IP_LF
" -src <ip> source IP address"IP_LF
" -dst <ip> destination IP address"IP_LF
" -proto <name> security protocol <esp|ah|ipip>"IP_LF
" -sapri <val> priority (-128=highest to 127=lowest)"IP_LF
);
keyadm_printf(vars,
" optional modifier: "IP_LF
" -replace replace flow if duplicate"IP_LF
);
}
/*
*===========================================================================
* keyadm_addflow
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
static int
keyadm_addflow(Vars *vars)
{
if (keyadm_send_command(vars, SADB_X_ADDFLOW, vars->satype) == 0)
{
(void)keyadm_receive_command(vars, 0);
return keyadm_print_command(vars);
}
return -1;
}
/*
*===========================================================================
* keyadm_delflow_usage
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
static void
keyadm_delflow_usage(Vars *vars)
{
keyadm_printf(vars,
"Delete a Flow (Security Policy)"IP_LF
" usage: keyadm delflow <selectors>"IP_LF
" keyadm delflow -id <flowid>"IP_LF
);
keyadm_printf(vars,
" mandatory selectors:"IP_LF
" -srcflow <ip> source flow address"IP_LF
" -srcmask <mask> source flow mask"IP_LF
" -dstflow <ip> destination flow address"IP_LF
" -dstmask <mask> destination flow mask"IP_LF
);
keyadm_printf(vars,
" optional selectors:"IP_LF
" -egress output flow (default)"IP_LF
" -ingress input flow"IP_LF
" -srcmaxflow <ip> source flow max address (for linear range)"IP_LF
" -dstmaxflow <ip> destination flow max address (for linear range)"IP_LF
" -flowpri <prio> flow priority (-128 to +127, -128=highest)"IP_LF
" -dscp <val> DSCP value (in hex without the 0x)"IP_LF
);
keyadm_printf(vars,
" optional IP protocol specific selectors:"IP_LF
" -transport <val> IP protocol (ANY=0, TCP=6, UDP=17 etc)"IP_LF
" -srcport <port> UDP/TCP source port"IP_LF
" -dstport <port> UDP/TCP destination port"IP_LF
" -srcmaxport <port> UDP/TCP source max port (for linear range)"IP_LF
" -dstmaxport <port> UDP/TCP destination port (for linear range)"IP_LF
);
keyadm_printf(vars,
" -icmptype <val> ICMP type (specified as value)"IP_LF
" -icmpcode <val> ICMP code (specified as value)"IP_LF
" -mhtype <val> MH type (specified as value)"IP_LF
);
}
/*
*===========================================================================
* keyadm_delflow
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
static int
keyadm_delflow(Vars *vars)
{
if (!(vars->flow_id != 0
|| ((vars->extmap & SEBIT_X_FLOW) == SEBIT_X_FLOW)))
{
keyadm_printf(vars, "keyadm: missing modifier(s) '-id' or '-srcflow and -dstflow'"IP_LF);
return -1;
}
if (keyadm_send_command(vars, SADB_X_DELFLOW, vars->satype) == 0)
{
(void)keyadm_receive_command(vars, 0);
return keyadm_print_command(vars);
}
return -1;
}
/*
*===========================================================================
* keyadm_findflow_usage
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
static void
keyadm_findflow_usage(Vars *vars)
{
keyadm_printf(vars,
"Lookup a Flow (Security Policy)"IP_LF
" usage: keyadm findflow <selectors>"IP_LF
);
keyadm_printf(vars,
" mandatory selectors:"IP_LF
" -srcflow <ip> source address"IP_LF
" -dstflow <ip> destination address"IP_LF
" -transport <val> IP protocol (ANY=0, TCP=6, UDP=17 etc)"IP_LF
);
keyadm_printf(vars,
" optional selectors:"IP_LF
" -egress output packet (default)"IP_LF
" -ingress input packet "IP_LF
" -dscp <val> DSCP value (in hex without the 0x)"IP_LF
" -srcport <port> UDP/TCP source port"IP_LF
" -dstport <port> UDP/TCP destination port"IP_LF
);
keyadm_printf(vars,
" -icmptype <val> ICMP type (specified as value)"IP_LF
" -icmpcode <val> ICMP code (specified as value)"IP_LF
" -mhtype <val> MH type (specified as value)"IP_LF
);
}
/*
*===========================================================================
* keyadm_findflow
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
static int
keyadm_findflow(Vars *vars)
{
if (vars->have_transport_proto == 0)
{
keyadm_printf(vars, "keyadm: missing modifier '-transport'"IP_LF);
return -1;
}
if (keyadm_send_command(vars, SADB_X_FINDFLOW, vars->satype) == 0)
{
(void)keyadm_receive_command(vars, 0);
return keyadm_print_command(vars);
}
return -1;
}
/*
*===========================================================================
* keyadm_dumpflow
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
static int
keyadm_dumpflow(Vars *vars)
{
if (keyadm_send_command(vars, SADB_X_DUMPFLOW, vars->satype) == 0)
{
struct Ip_timeval tv;
int count = 0;
tv.tv_sec = 3;
tv.tv_usec = 0;
if (ipcom_setsockopt(vars->fd, IP_SOL_SOCKET, IP_SO_RCVTIMEO, &tv, sizeof(tv)) < 0)
{
keyadm_printf(vars, "keyadm: setsockopt(IP_SO_RCVTIMEO,x) failed : %s ",
ipcom_strerror(ipcom_errno));
return 0;
}
do
{
if (keyadm_receive_command(vars, 0) != 0)
break;
if (keyadm_print_command(vars) == 0)
count++;
}
while (vars->sadb->msg->sadb_msg_errno == 0
&& vars->sadb->msg->sadb_msg_seq);
keyadm_printf(vars, "Total of %d flows"IP_LF, count);
}
return 0;
}
/*
*===========================================================================
* keyadm_grpspis_usage
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
static void
keyadm_grpspis_usage(Vars *vars)
{
keyadm_printf(vars,
"Group two Security Associations (SAs)"IP_LF
" usage: keyadm group <SA1 selectors> <SA2 selectors>"IP_LF);
keyadm_printf(vars,
" 1st SA mandatory selectors: "IP_LF
" -spi <val> SPI (in hex without the 0x)"IP_LF
" -src <ip> source IP address"IP_LF
" -dst <ip> destination IP address"IP_LF
" -proto <name> security protocol <esp|ah|ipip>"IP_LF
);
keyadm_printf(vars,
" 1st SA optional selectors: "IP_LF
" -sapri <val> priority (-128=highest to 127=lowest)"IP_LF
" -egress output SA (default)"IP_LF
" -ingress input SA"IP_LF
);
keyadm_printf(vars,
" 2nd SA mandatory selectors: "IP_LF
" -spi2 <val> SPI (in hex without the 0x)"IP_LF
" -dst2 <ip> destination IP address"IP_LF
" -proto2 <name> security protocol <esp|ah|ipip>"IP_LF
" NOTE: SA2 is always outbound"IP_LF
);
}
/*
*===========================================================================
* keyadm_grpspis
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
static int
keyadm_grpspis(Vars *vars)
{
if (vars->test == 0)
{
if (vars->have_satype == 0)
{
keyadm_printf(vars, "keyadm: missing modifier '-proto'"IP_LF);
return -1;
}
if (IP_BIT_ISFALSE(vars->extmap, SEBIT_X_DST2))
{
keyadm_printf(vars, "keyadm: missing modifier '-dst2'"IP_LF);
return -1;
}
}
if (keyadm_send_command(vars, SADB_X_GRPSPIS, vars->satype) == 0)
{
(void)keyadm_receive_command(vars, 0);
return keyadm_print_command(vars);
}
return -1;
}
/*
*===========================================================================
* keyadm_register
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
static int
keyadm_register(Vars *vars)
{
if (vars->have_satype == 0)
{
keyadm_printf(vars, "keyadm: missing modifier '-proto'"IP_LF);
return -1;
}
if (keyadm_send_command(vars, SADB_REGISTER, vars->satype) == 0)
{
(void)keyadm_receive_command(vars, 0);
return keyadm_print_command(vars);
}
return -1;
}
/*
*===========================================================================
* keyadm_monitor
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
static int
keyadm_monitor(Vars *vars)
{
int i;
if (vars->count == 0)
{
keyadm_printf(vars,
"Monitor PFKey kernel messages"IP_LF
" usage: keyadm monitor [-c <count>] [-W <timeout>]"IP_LF
" options: "IP_LF
" -c <count> maximum number of packets received"IP_LF
" -W <timeout> maximum timeout (in seconds) per read"IP_LF
" -proto <name> security protocol <esp|ah|ipip>"IP_LF
);
return 0;
}
if (keyadm_send_command(vars, SADB_REGISTER, vars->satype) == 0)
{
if (keyadm_receive_command(vars, 0) != 0)
{
keyadm_printf(vars, "keyadm: failed to register"IP_LF);
return -1;
}
}
ipcom_printf(IP_LF"Starting MONITOR loop [satype=%s]"IP_LF,
MSG_SATYPE(vars->satype));
for (i = 0; i < vars->count; i++)
{
if (keyadm_receive_command(vars, vars->timeout_seconds) != 0)
break;
(void)keyadm_print_command(vars);
}
return 0;
}
/*
*===========================================================================
* keyadm_run_command
*===========================================================================
*/
static int
keyadm_run_command(int argc, char *name, Vars *vars)
{
int i;
Ip_u64 ext;
for (i = 0; commands[i].name; i++)
if (ipcom_strcmp(name, commands[i].name) == 0)
{
if (argc == 2 && commands[i].usage != IP_NULL)
{
commands[i].usage(vars);
return 0;
}
if (vars->test == 0 && commands[i].type > 0)
{
for (ext = 1; ext < SADB_EXT_MAX; ext++)
if (IP_BIT_ISSET(extbits[commands[i].type].in_req, (1ULL << ext))
&& IP_BIT_ISFALSE(vars->extmap, (1ULL << ext)))
{
keyadm_printf(vars, "keyadm: missing modifier '%s'"IP_LF, EXT_TYPE(ext));
return -1;
}
if (commands[i].type == SADB_GETSPI && vars->maxspi == 0)
{
keyadm_printf(vars, "keyadm: missing modifier '-maxspi'"IP_LF);
return -1;
}
}
return commands[i].func(vars);
}
keyadm_printf(vars, "keyadm: unknown command"IP_LF);
return -1;
}
/*
****************************************************************************
* 9 LINUX FUNCTIONS.
****************************************************************************
*/
#ifdef IPIPSEC_USE_LINUX_PFKEYV2_API
/*
*===========================================================================
* keyadm_spdadd_usage / keyadm_spdupdate_usage
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*
spdadd 10.1.2.90 10.1.2.100 any -P out ipsec esp/transport/10.1.2.90-10.1.2.100/use ah/transport/10.1.2.90-10.1.2.100/use;
spdadd 192.168.0.10/32[5066] 192.168.0.11/32[5064] udp -P in
spdadd ::/0 ::/0 icmp6 135,0 -P in none; "=bypass"
spdadd 10.0.11.0/24[any] 10.0.11.33/32[any] any -P out ipsec esp/tunnel/192.168.0.1[4500]-192.168.1.2[30000]/require ;
keyadm spdadd -srcmask 255.255.255.255 -dstmask 255.255.255.255 -srcflow 10.1.2.110 -dstflow 10.1.2.100 -ingress -use
POLICY: -dst 10.1.2.100 -spi 603 -proto esp
*/
static void
keyadm_spdadd_usage_internal(Vars *vars, int type)
{
if (type == SADB_X_SPDADD)
keyadm_printf(vars,
"Add a Flow (Security Policy) using linux API"IP_LF
" usage: keyadm spdadd <selectors> <type>"IP_LF
);
else
keyadm_printf(vars,
"Update a Flow (Security Policy) using linux API"IP_LF
" usage: keyadm spdupdate <selectors> <type> [SA selectors] [-replace]"IP_LF
);
keyadm_printf(vars,
" mandatory selectors:"IP_LF
" -srcflow <ip> source address"IP_LF
" -dstflow <ip> destination address"IP_LF
" -egress | -ingress flow direction (default out)"IP_LF
);
keyadm_printf(vars,
" optional selectors:"IP_LF
" -srcmask <mask> source mask (default all 1's)"IP_LF
" -dstmask <mask> destination mask (default all 1's)"IP_LF
" -srctunnel <ip> tunnel source address"IP_LF
" -dsttunnel <ip> tunnel destination address"IP_LF
);
keyadm_printf(vars,
" -flowpri <prio> flow priority (-128 to +127, -128=highest)"IP_LF
" -u <id> policy entry identifier"IP_LF
" -proto <ah|esp> desired SA security protocol"IP_LF
);
keyadm_printf(vars,
" optional IP protocol specific selectors:"IP_LF
" -transport <val> IP protocol (ANY=0, TCP=6, UDP=17 etc)"IP_LF
" -srcport <port> UDP/TCP source port"IP_LF
" -dstport <port> UDP/TCP destination port"IP_LF
);
keyadm_printf(vars,
" optional type:"IP_LF
" -use use flow (default)"IP_LF
" -bypass bypass flow"IP_LF
" -deny deny flow"IP_LF
" -acquire acquire flow"IP_LF
" -require require flow"IP_LF
);
}
static void
keyadm_spdadd_usage(Vars *vars)
{
keyadm_spdadd_usage_internal(vars, SADB_X_SPDADD);
}
static void
keyadm_spdupdate_usage(Vars *vars)
{
keyadm_spdadd_usage_internal(vars, SADB_X_SPDUPDATE);
}
/*
*===========================================================================
* keyadm_spdadd
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
static int
keyadm_spdadd(Vars *vars)
{
vars->is_linux = IP_TRUE;
if (keyadm_send_command_linux(vars, SADB_X_SPDADD, vars->satype) == 0)
{
(void)keyadm_receive_command(vars, 0);
return keyadm_print_command(vars);
}
return -1;
}
/*
*===========================================================================
* keyadm_spdupdate
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
static int
keyadm_spdupdate(Vars *vars)
{
vars->is_linux = IP_TRUE;
if (keyadm_send_command_linux(vars, SADB_X_SPDUPDATE, vars->satype) == 0)
{
(void)keyadm_receive_command(vars, 0);
return keyadm_print_command(vars);
}
return -1;
}
/*
*===========================================================================
* keyadm_spddelete_usage
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
static void
keyadm_spddelete_usage(Vars *vars)
{
keyadm_printf(vars,
"Delete a Flow (Security Policy)"IP_LF
" usage: keyadm spddelete <selectors>"IP_LF
);
keyadm_printf(vars,
" mandatory selectors:"IP_LF
" -srcflow <ip> source flow address"IP_LF
" -dstflow <ip> destination flow address"IP_LF
);
keyadm_printf(vars,
" optional selectors:"IP_LF
" -srcmask <mask> source flow mask"IP_LF
" -dstmask <mask> destination flow mask"IP_LF
" -egress output flow (default)"IP_LF
" -ingress input flow"IP_LF
" -flowpri <prio> flow priority (-128 to +127, -128=highest)"IP_LF
);
keyadm_printf(vars,
" optional IP protocol specific selectors:"IP_LF
" -transport <val> IP protocol (ANY=0, TCP=6, UDP=17 etc)"IP_LF
" -srcport <port> UDP/TCP source port"IP_LF
" -dstport <port> UDP/TCP destination port"IP_LF
);
}
/*
*===========================================================================
* keyadm_spddelete
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
static int
keyadm_spddelete(Vars *vars)
{
if (keyadm_send_command_linux(vars, SADB_X_SPDDELETE, vars->satype) == 0)
{
(void)keyadm_receive_command(vars, 0);
return keyadm_print_command(vars);
}
return -1;
}
/*
*===========================================================================
* keyadm_spdflush
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
static int
keyadm_spdflush(Vars *vars)
{
if (keyadm_send_command(vars, SADB_X_SPDFLUSH, 0) == 0)
{
(void)keyadm_receive_command(vars, 0);
return keyadm_print_command(vars);
}
return -1;
}
#endif /* #ifdef IPIPSEC_USE_LINUX_PFKEYV2_API */
/*
****************************************************************************
* 10 PUBLIC FUNCTIONS.
****************************************************************************
*/
/*
*===========================================================================
* ipipsec_cmd_keyadm_private
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC int
ipipsec_cmd_keyadm_private(Vars *vars, int argc, char **argv)
{
int i, c, id, doexit;
int ret = 1;
Ipcom_getopt opt;
static struct Ip_option long_options[] =
{
{"spi", 1, 0, 0},
{"src", 1, 0, 0},
{"dst", 1, 0, 0},
{"proto", 1, 0, 0},
{"minspi", 1, 0, 0},
{"maxspi", 1, 0, 0},
{"ekey", 1, 0, 0},
{"akey", 1, 0, 0},
{"enc", 1, 0, 0},
{"auth", 1, 0, 0},
{"xxxold", 0, 0, 0},
{"xxxhalfiv", 0, 0, 0},
{"forcetunnel", 0, 0, 0},
{"srcmask", 1, 0, 0},
{"dstmask", 1, 0, 0},
{"srcflow", 1, 0, 0},
{"dstflow", 1, 0, 0},
{"spi2", 1, 0, 0},
{"dst2", 1, 0, 0},
{"proto2", 1, 0, 0},
{"new", 0, 0, 0},
{"ingress", 0, 0, 0},
{"srcport", 1, 0, 0},
{"dstport", 1, 0, 0},
{"transport", 1, 0, 0},
{"replace", 0, 0, 0},
{"bypass", 0, 0, 0},
{"replay", 1, 0, 0},
{"chain", 0, 0, 0},
{"proxy", 1, 0, 0},
{"egress", 0, 0, 0},
{"silent", 0, 0, 0},
{"ls", 1, 0, 0},
{"lh", 1, 0, 0},
{"deny", 0, 0, 0},
{"acquire", 0, 0, 0},
{"require", 0, 0, 0},
{"b", 1, 0, 0},
{"srcmaxport", 1, 0, 0},
{"dstmaxport", 1, 0, 0},
{"tfc", 0, 0, 0},
{"esn", 0, 0, 0},
{"flowpri", 1, 0, 0},
{"c", 1, 0, 0},
{"id", 1, 0, 0},
{"srcreq", 0, 0, 0},
{"icmptype", 1, 0, 0},
{"icmpcode", 1, 0, 0},
{"sapri", 1, 0, 0},
{"use", 0, 0, 0},
{"W", 1, 0, 0},
{"mhtype", 1, 0, 0},
{"srcmaxflow", 1, 0, 0},
{"dstmaxflow", 1, 0, 0},
{"setdf", 0, 0, 0},
{"clrdf", 0, 0, 0},
{"dscp", 1, 0, 0},
{"udpencap", 1, 0, 0},
{"srctunnel", 1, 0, 0},
{"dsttunnel", 1, 0, 0},
{"syslog", 0, 0, 0},
{"linux", 0, 0, 0},
{"u", 1, 0, 0},
{"ecn", 0, 0, 0},
{"bs", 1, 0, 0},
{"bh", 1, 0, 0},
{0, 0, 0, 0}
};
/* prepare data */
ipcom_memset(vars, 0, sizeof(Vars));
vars->sadb = (Ipipsec_pfkeyv2_sadb *)vars->exthdr;
vars->sadb->msg = &vars->sadbmsg;
vars->encrypt_type = SADB_EALG_UNSET;
vars->auth_type = SADB_AALG_UNSET;
vars->argc = argc;
vars->argv = argv;
vars->fd = -1;
ipcom_getopt_clear_r(&opt);
/* Check -silent flag first, to disable all prints */
for (i = 0; i < argc; i++)
if (ipcom_strstr(argv[i], "-silent"))
{
vars->silent = 1;
opt.opterr = 0;
break;
}
for (i = 0; i < argc; i++)
if (ipcom_strstr(argv[i], "-syslog"))
{
vars->syslog = 1;
opt.opterr = 0;
break;
}
if (vars->silent == 0)
{
vars->stdoutbuf = ipcom_malloc(512);
if (vars->stdoutbuf == IP_NULL)
return 1;
}
if (argc < 2)
goto usage;
if (vars->syslog)
{
c = ipcom_sprintf(vars->stdoutbuf, "> ");
for (c = 2, i = 0; i < argc; i++)
c += ipcom_sprintf(vars->stdoutbuf + c, "%s ", argv[i]);
IPCOM_LOG1(DEBUG, "%s", vars->stdoutbuf);
}
vars->fd = ipcom_socket(IP_PF_KEY, IP_SOCK_RAW, PF_KEY_V2);
if (vars->fd == IP_SOCKERR)
{
keyadm_printf(vars, "keyadm: ipcom_socket() failed (%s)"IP_LF, ipcom_strerror(ipcom_errno));
goto leave2;
}
opt.long_only = 1;
opt.long_options = long_options;
while ((c = ipcom_getopt_r(argc - 1, argv + 1, "t", &opt)) != -1)
{
switch (c)
{
case 0:
switch(opt.long_index)
{
case 0: /* -spi */
vars->spi_n = ipcom_strtoul(opt.optarg, IP_NULL, 16);
vars->spi_n = ip_htonl(vars->spi_n);
IP_BIT_SET(vars->extmap, SEBIT_SA);
break;
case 1: /* -src */
if (keyadm_read_addr(opt.optarg, &vars->srcaddr) != 0)
{
keyadm_printf(vars, "keyadm: bad '-src' address"IP_LF);
goto leave;
}
IP_BIT_SET(vars->extmap, SEBIT_ADDRESS_SRC);
break;
case 2: /* -dst */
if (keyadm_read_addr(opt.optarg, &vars->dstaddr) != 0)
{
keyadm_printf(vars, "keyadm: bad '-dst' address"IP_LF);
goto leave;
}
IP_BIT_SET(vars->extmap, SEBIT_ADDRESS_DST);
break;
case 3: /* -proto */
if ((vars->satype = (Ip_s8)keyadm_search_block(opt.optarg, msg_satypes)) == -1)
{
keyadm_printf(vars, "keyadm: unknown security protocol type '%s'"IP_LF, opt.optarg);
goto leave;
}
vars->have_satype = 1;
break;
case 4: /* -minspi */
vars->minspi = ipcom_strtoul(opt.optarg, IP_NULL, 16);
IP_BIT_SET(vars->extmap, SEBIT_SPIRANGE);
break;
case 5: /* -maxspi */
vars->maxspi = ipcom_strtoul(opt.optarg, IP_NULL, 16);
break;
case 6: /* -ekey */
if (ipcom_strlen(opt.optarg) > (sizeof(vars->encrypt_key) * 2))
{
keyadm_printf(vars, "keyadm: too long encryption key '%s'"IP_LF, opt.optarg);
goto leave;
}
vars->encrypt_bytes = (Ip_u8)(ipcom_strlen(opt.optarg) / 2);
for (i = 0; i < vars->encrypt_bytes; i++)
{
vars->encrypt_key[i] = (Ip_u8)keyadm_hex_to_long(vars, opt.optarg + 2 * i, &doexit);
if (doexit)
goto leave;
}
break;
case 7: /* -akey */
if (ipcom_strlen(opt.optarg) > (sizeof(vars->auth_key) * 2))
{
keyadm_printf(vars, "keyadm: too long authentication key '%s'"IP_LF, opt.optarg);
goto leave;
}
vars->auth_bytes = (Ip_u8)(ipcom_strlen(opt.optarg) / 2);
for (i = 0; i < vars->auth_bytes; i++)
{
vars->auth_key[i] = (Ip_u8)keyadm_hex_to_long(vars, opt.optarg + 2 * i, &doexit);
if (doexit)
goto leave;
}
break;
case 8: /* -enc */
id = ipcom_cmd_str_to_key(sa_encrypt_id_map, opt.optarg);
if (id == -1)
{
keyadm_printf(vars, "keyadm: unknown encryption algorithm '%s'"IP_LF, opt.optarg);
goto leave;
}
vars->encrypt_type = (Ip_u8)id;
vars->satype = SADB_SATYPE_ESP; /* auto pick ESP */
vars->have_satype = 1;
break;
case 9: /* -auth */
id = ipcom_cmd_str_to_key(sa_auth_id_map, opt.optarg);
if (id == -1)
{
keyadm_printf(vars, "keyadm: unknown authentication algorithm '%s'"IP_LF, opt.optarg);
goto leave;
}
vars->auth_type = (Ip_u8)id;
break;
case 12: /* -forcetunnel */
IP_BIT_SET(vars->sa_flags, SADB_X_SAFLAGS_TUNNEL);
break;
case 13: /* -srcmask */
if (keyadm_read_addr(opt.optarg, &vars->srcmask) != 0)
{
keyadm_printf(vars, "keyadm: bad '-srcmask' mask"IP_LF);
goto leave;
}
IP_BIT_SET(vars->extmap, SEBIT_X_SRC_MASK);
break;
case 14: /* -dstmask */
if (keyadm_read_addr(opt.optarg, &vars->dstmask) != 0)
{
keyadm_printf(vars, "keyadm: bad '-dstmask' mask"IP_LF);
goto leave;
}
IP_BIT_SET(vars->extmap, SEBIT_X_DST_MASK);
break;
case 15: /* -srcflow */
if (keyadm_read_addr(opt.optarg, &vars->srcflow) != 0)
{
keyadm_printf(vars, "keyadm: bad '-srcflow' flow"IP_LF);
goto leave;
}
IP_BIT_SET(vars->extmap, SEBIT_X_SRC_FLOW);
break;
case 16: /* -dstflow */
if (keyadm_read_addr(opt.optarg, &vars->dstflow) != 0)
{
keyadm_printf(vars, "keyadm: bad '-dstflow' flow"IP_LF);
goto leave;
}
IP_BIT_SET(vars->extmap, SEBIT_X_DST_FLOW);
break;
case 17: /* -spi2 */
vars->spi2_n = ipcom_strtoul(opt.optarg, IP_NULL, 16);
vars->spi2_n = ip_htonl(vars->spi2_n);
IP_BIT_SET(vars->extmap, SEBIT_X_SA2);
break;
case 18: /* -dst2 */
if (keyadm_read_addr(opt.optarg, &vars->dstaddr2) != 0)
{
keyadm_printf(vars, "keyadm: bad '-dst2' address"IP_LF);
goto leave;
}
IP_BIT_SET(vars->extmap, SEBIT_X_DST2);
break;
case 19: /* -proto2 */
if ((vars->satype2 = (Ip_s8)keyadm_search_block(opt.optarg, msg_satypes)) == -1)
{
keyadm_printf(vars, "keyadm: unknown security protocol type '%s'"IP_LF, opt.optarg);
goto leave;
}
IP_BIT_SET(vars->extmap, SEBIT_X_PROTOCOL);
break;
case 20: /* new (redundant, included only to simplify scripts) */
break;
case 21: /* -ingress flow/sa */
IP_BIT_SET(vars->sa_flags, SADB_X_SAFLAGS_INGRESS_SA);
IP_BIT_SET(vars->extmap, SEBIT_SA);
break;
case 22: /* -srcport */
if (*opt.optarg < '0' || *opt.optarg > '9')
{
keyadm_printf(vars, "keyadm: flow srcport must be specified by number"IP_LF);
goto leave;
}
vars->srcport_n = (Ip_u16)ipcom_atoi(opt.optarg);
vars->srcport_n = ip_htons(vars->srcport_n);
break;
case 23: /* -dstport */
if (*opt.optarg < '0' || *opt.optarg > '9')
{
keyadm_printf(vars, "keyadm: flow dstport must be specified by number"IP_LF);
goto leave;
}
vars->dstport_n = (Ip_u16)ipcom_atoi(opt.optarg);
vars->dstport_n = ip_htons(vars->dstport_n);
break;
case 24: /* -transport (flow protocol) */
if (*opt.optarg < '0' || *opt.optarg > '9')
{
keyadm_printf(vars, "keyadm: transport protocol must be specified by its protocol number"IP_LF);
goto leave;
}
vars->transport_proto = (Ip_u8)ipcom_atoi(opt.optarg);
vars->have_transport_proto = 1;
break;
case 25: /* -replace flow */
IP_BIT_SET(vars->sa_flags, SADB_X_SAFLAGS_REPLACEFLOW);
break;
case 26: /* -bypass flow */
vars->spi_n = 0;
IP_BIT_SET(vars->extmap, SEBIT_SA); /* spi = 0 */
IP_BIT_SET(vars->extmap, SEBIT_ADDRESS_DST); /* dst = 0.0.0.0 */
vars->satype = SADB_X_SATYPE_BYPASS;
vars->have_satype = 1;
vars->flow_type = SADB_X_FLOW_TYPE_BYPASS;
break;
case 27: /* -replay */
if (*opt.optarg < '0' || *opt.optarg > '9')
{
keyadm_printf(vars, "keyadm: replay counter must be a number"IP_LF);
goto leave;
}
vars->replay = ipcom_atoi(opt.optarg);
vars->replay = IP_ROUNDUP(vars->replay, 8);
if (vars->replay < 0 || vars->replay > 255)
{
keyadm_printf(vars, "keyadm: replay counter must be between 0 and 248"IP_LF);
goto leave;
}
break;
case 28: /* -chain */
IP_BIT_SET(vars->sa_flags, SADB_X_SAFLAGS_CHAINDEL);
break;
case 29: /* -proxy */
if (keyadm_read_addr(opt.optarg, &vars->proxyaddr) != 0)
{
keyadm_printf(vars, "keyadm: bad '-proxy' address"IP_LF);
goto leave;
}
IP_BIT_SET(vars->extmap, SEBIT_ADDRESS_PROXY);
break;
case 30: /* -egress sa */
IP_BIT_SET(vars->sa_flags, SADB_X_SAFLAGS_EGRESS_SA);
IP_BIT_SET(vars->extmap, SEBIT_SA);
break;
case 31: /* -silent mode, no printfs */
break;
case 32: /* -ls = lifetime soft (in time) */
vars->ls_sec = (Ip_u32)ipcom_atoi(opt.optarg);
IP_BIT_SET(vars->extmap, SEBIT_LIFETIME_SOFT);
break;
case 33: /* -lh = lifetime hard (in time) */
vars->lh_sec = (Ip_u32)ipcom_atoi(opt.optarg);
IP_BIT_SET(vars->extmap, SEBIT_LIFETIME_HARD);
break;
case 34: /* -deny flow */
IP_BIT_SET(vars->extmap, SEBIT_X_FLOW_OPTIONS);
vars->flow_type = SADB_X_FLOW_TYPE_DENY;
break;
case 35: /* -acquire flow */
IP_BIT_SET(vars->extmap, SEBIT_X_FLOW_OPTIONS);
vars->flow_type = SADB_X_FLOW_TYPE_ACQUIRE;
break;
case 36: /* -require flow */
IP_BIT_SET(vars->extmap, SEBIT_X_FLOW_OPTIONS);
vars->flow_type = SADB_X_FLOW_TYPE_REQUIRE;
break;
case 37: /* -b = socker buffer size */
{
int sockbufsize = ipcom_atoi(opt.optarg);
if (sockbufsize > 0)
{
if (ipcom_setsockopt(vars->fd, IP_SOL_SOCKET, IP_SO_RCVBUF, (char *)&sockbufsize, sizeof(sockbufsize)) < 0)
keyadm_printf(vars, "keyadm: ipcom_setsockopt(RCVBUF) failed : %s"IP_LF, ipcom_strerror(ipcom_errno));
}
}
break;
case 38: /* -srcmaxport */
if (*opt.optarg < '0' || *opt.optarg > '9')
{
keyadm_printf(vars, "keyadm: flow srcmaxport must be specified by number"IP_LF);
goto leave;
}
vars->srcmaxport_n = (Ip_u16)ipcom_atoi(opt.optarg);
vars->srcmaxport_n = ip_htons(vars->srcmaxport_n);
IP_BIT_SET(vars->extmap, SEBIT_X_SRCMAX_FLOW);
break;
case 39: /* -dstmaxport */
if (*opt.optarg < '0' || *opt.optarg > '9')
{
keyadm_printf(vars, "keyadm: flow dstmaxport must be specified by number"IP_LF);
goto leave;
}
vars->dstmaxport_n = (Ip_u16)ipcom_atoi(opt.optarg);
vars->dstmaxport_n = ip_htons(vars->dstmaxport_n);
IP_BIT_SET(vars->extmap, SEBIT_X_DSTMAX_FLOW);
break;
case 40: /* -tfc */
IP_BIT_SET(vars->sa_flags, SADB_X_SAFLAGS_TFC);
break;
case 41: /* -esn */
IP_BIT_SET(vars->sa_flags, SADB_X_SAFLAGS_ESN);
break;
case 42: /* -flowpri */
vars->flow_priority = ipcom_atoi(opt.optarg);
if (vars->flow_priority < -128 || vars->flow_priority > 127)
{
keyadm_printf(vars, "keyadm: flow priority must be between -128 and 127"IP_LF);
goto leave;
}
IP_BIT_SET(vars->extmap, SEBIT_X_FLOW_OPTIONS);
break;
case 43: /* -c */
vars->count = ipcom_atoi(opt.optarg);
if (vars->count < 1)
{
keyadm_printf(vars, "keyadm: count must be > 0"IP_LF);
goto leave;
}
break;
case 44: /* -id */
vars->flow_id = (Ip_u32)ipcom_atol(opt.optarg);
IP_BIT_SET(vars->extmap, SEBIT_X_FLOW_OPTIONS);
break;
case 45: /* -srcreq */
IP_BIT_SET(vars->sa_flags, SADB_X_SAFLAGS_SRCREQ);
break;
case 46: /* -icmptype */
vars->ports0 = (Ip_u8)ipcom_atoi(opt.optarg);
break;
case 47: /* -icmpcode */
vars->ports1 = (Ip_u8)ipcom_atoi(opt.optarg);
break;
case 48: /* -sapri */
vars->sa_priority = ipcom_atoi(opt.optarg);
if (vars->sa_priority < -128 || vars->sa_priority > 127)
{
keyadm_printf(vars, "keyadm: SA priority must be between -128 and 127"IP_LF);
goto leave;
}
IP_BIT_SET(vars->extmap, SEBIT_X_EXT_SA_OPTIONS);
break;
case 49: /* -use */
/* Use flow -> do not need to do anything */
break;
case 50: /* '-W' */
vars->timeout_seconds = ipcom_atoi(opt.optarg);
break;
case 51: /* -mhtype */
vars->ports0 = (Ip_u8)ipcom_atoi(opt.optarg);
break;
case 52: /* -srcmaxflow */
if (keyadm_read_addr(opt.optarg, &vars->srcmaxflow) != 0)
{
keyadm_printf(vars, "keyadm: bad '-srcmaxflow' flow"IP_LF);
goto leave;
}
IP_BIT_SET(vars->extmap, SEBIT_X_SRCMAX_FLOW);
break;
case 53: /* -dstmaxflow */
if (keyadm_read_addr(opt.optarg, &vars->dstmaxflow) != 0)
{
keyadm_printf(vars, "keyadm: bad '-dstmaxflow' flow"IP_LF);
goto leave;
}
IP_BIT_SET(vars->extmap, SEBIT_X_DSTMAX_FLOW);
break;
case 54: /* -setdf */
IP_BIT_SET(vars->sa_flags, SADB_X_SAFLAGS_SETDF);
break;
case 55: /* -clrdf */
IP_BIT_SET(vars->sa_flags, SADB_X_SAFLAGS_CLRDF);
break;
case 56: /* -dscp */
vars->dscp = (Ip_u8)ipcom_strtoul(opt.optarg, IP_NULL, 16);
IP_BIT_SET(vars->extmap, SEBIT_X_FLOW_OPTIONS);
break;
case 57: /* -udpencap */
if (*opt.optarg < '0' || *opt.optarg > '9')
{
keyadm_printf(vars, "keyadm: udpencap port must be specified by number"IP_LF);
goto leave;
}
vars->udpencap_port = (Ip_u16)ipcom_atoi(opt.optarg);
IP_BIT_SET(vars->sa_flags, SADB_X_SAFLAGS_UDPENCAP);
break;
case 58: /* -srctunnel */
if (keyadm_read_addr(opt.optarg, &vars->srctunnel) != 0)
{
keyadm_printf(vars, "keyadm: bad '-srctunnel' address"IP_LF);
goto leave;
}
IP_BIT_SET(vars->sa_flags, SADB_X_SAFLAGS_TUNNEL);
break;
case 59: /* -dsttunnel */
if (keyadm_read_addr(opt.optarg, &vars->dsttunnel) != 0)
{
keyadm_printf(vars, "keyadm: bad '-dsttunnel' address"IP_LF);
goto leave;
}
IP_BIT_SET(vars->sa_flags, SADB_X_SAFLAGS_TUNNEL);
break;
case 60: /* -syslog */
break;
#ifdef IPIPSEC_USE_LINUX_PFKEYV2_API
case 61: /* -linux */
vars->is_linux = IP_TRUE;
break;
case 62: /* -u */
vars->is_linux = IP_TRUE;
vars->reqid = ipcom_atol(opt.optarg);
break;
#endif
case 63: /* -ecn */
keyadm_printf(vars, "keyadm: Enabling ECN support\n");
IP_BIT_SET(vars->sa_flags, SADB_X_SAFLAGS_ECN);
break;
case 64: /* -bs = bytes soft */
vars->ls_bytes = (Ip_u64)ipcom_atol(opt.optarg);
IP_BIT_SET(vars->extmap, SEBIT_LIFETIME_SOFT);
break;
case 65: /* -bh = bytes hard */
vars->lh_bytes = (Ip_u64)ipcom_atol(opt.optarg);
IP_BIT_SET(vars->extmap, SEBIT_LIFETIME_HARD);
break;
default:
keyadm_printf(vars, "keyadm: unknown option %s", long_options[opt.long_index].name);
if (opt.optarg)
keyadm_printf(vars, " with arg %s", opt.optarg);
keyadm_printf(vars, IP_LF);
goto leave;
}
break;
case 't':
/* testmode */
vars->test = 1;
keyadm_printf(vars, "using testmode"IP_LF);
break;
default:
goto leave;
}
}
/****** Initial checks ******/
if (vars->test == 0)
{
if (IP_BIT_ISSET(vars->sa_flags, SADB_X_SAFLAGS_EGRESS_SA)
&& IP_BIT_ISSET(vars->sa_flags, SADB_X_SAFLAGS_INGRESS_SA))
{
keyadm_printf(vars, "keyadm: cannot specify \"-egress\" and \"-ingress\" simultaneously"IP_LF);
goto leave;
}
if (vars->satype != SADB_SATYPE_ESP && IP_BIT_ISSET(vars->sa_flags, SADB_X_SAFLAGS_TFC))
{
keyadm_printf(vars,
"keyadm: cannot specify \"-tfc\" for SAs using security protocols other than ESP"IP_LF);
goto leave;
}
}
/****** Run the command ******/
ret = keyadm_run_command(argc, argv[1], vars);
goto leave;
/* Generic usage */
usage:
keyadm_printf(vars,
"IPsec PFKey admin command, version 4.0"IP_LF
"Copyright (c) 2000-2010, Interpeak AB <www.interpeak.com>"IP_LF
" usage: keyadm <command> [modifier(s)...]"IP_LF
);
keyadm_printf(vars,
" General commands: "IP_LF
" flush remove all SAs and flows"IP_LF
" monitor monitor PFKey kernel messages"IP_LF
#ifdef IP_DEBUG
" register send register PFkey message"IP_LF
#endif
);
keyadm_printf(vars,
" SA commands: "IP_LF
" add add a Security Association (SA)"IP_LF
" delete delete a Security Association (SA)"IP_LF
" get get (info about) a Security Association (SA)"IP_LF
" getspi create a larval SA with a (random) SPI"IP_LF
" update update a Security Association (SA)"IP_LF
" group group two Security Associations (SAs)"IP_LF
" dump list SA database"IP_LF
);
keyadm_printf(vars,
" Flow commands: "IP_LF
" addflow add a Flow (Security Policy)"IP_LF
" delflow delete a Flow (Security Policy)"IP_LF
" findflow lookup a Flow (Security Policy)"IP_LF
" dumpflow list Flow (Security Policy) database"IP_LF
);
#ifdef IPIPSEC_USE_LINUX_PFKEYV2_API
keyadm_printf(vars,
" Linux PFKEY commands: "IP_LF
" spdadd add policy"IP_LF
" spdupdate update policy"IP_LF
" spddelete delete policy"IP_LF
" spdflush flush policies"IP_LF
);
#endif
keyadm_printf(vars,
" Generic command modifiers: "IP_LF
" -b <size> set pfkey socket receive buffer size"IP_LF
" -silent do not send any output to stdout/stderr"IP_LF
" -syslog send command output to syslog"IP_LF
);
keyadm_printf(vars,
" NOTE:"IP_LF
" Type 'keyadm <command>' for command help menu!"IP_LF
" (except for dump and flush which can be used without args)"IP_LF
);
leave:
if (vars->orgbuf)
ipcom_free(vars->orgbuf);
if (vars->fd != IP_INVALID_SOCKET)
ipcom_socketclose(vars->fd);
leave2:
if (vars->stdoutbuf)
ipcom_free(vars->stdoutbuf);
return ret;
}
/*
*===========================================================================
* ipipsec_cmd_keyadm
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_PUBLIC int
ipipsec_cmd_keyadm(int argc, char **argv)
{
Vars *vars;
int ret;
/* Allocate the vars variable dynamically to reduce
* stack space allocated
*/
vars = ipcom_malloc(sizeof(*vars));
if (vars == IP_NULL)
return -1;
ret = ipipsec_cmd_keyadm_private(vars, argc, argv);
ipcom_free(vars);
return ret;
}
/*
****************************************************************************
* END OF FILE
*===========================================================================
*/