src/sbin/ipsecctl/pfkdump.c

942 lines
26 KiB
C

/* $OpenBSD: pfkdump.c,v 1.58 2023/10/10 16:16:16 tobhe Exp $ */
/*
* Copyright (c) 2003 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/sysctl.h>
#include <sys/queue.h>
#include <net/pfkeyv2.h>
#include <netinet/ip_ipsp.h>
#include <netdb.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <err.h>
#include <errno.h>
#include "ipsecctl.h"
#include "pfkey.h"
static void print_proto(struct sadb_ext *, struct sadb_msg *, int);
static void print_flow(struct sadb_ext *, struct sadb_msg *, int);
static void print_supp(struct sadb_ext *, struct sadb_msg *, int);
static void print_prop(struct sadb_ext *, struct sadb_msg *, int);
static void print_sens(struct sadb_ext *, struct sadb_msg *, int);
static void print_spir(struct sadb_ext *, struct sadb_msg *, int);
static void print_policy(struct sadb_ext *, struct sadb_msg *, int);
static void print_sa(struct sadb_ext *, struct sadb_msg *, int);
static void print_addr(struct sadb_ext *, struct sadb_msg *, int);
static void print_key(struct sadb_ext *, struct sadb_msg *, int);
static void print_life(struct sadb_ext *, struct sadb_msg *, int);
static void print_ident(struct sadb_ext *, struct sadb_msg *, int);
static void print_udpenc(struct sadb_ext *, struct sadb_msg *, int);
static void print_tag(struct sadb_ext *, struct sadb_msg *, int);
static void print_rdomain(struct sadb_ext *, struct sadb_msg *, int);
static void print_replay(struct sadb_ext *, struct sadb_msg *, int);
static void print_mtu(struct sadb_ext *, struct sadb_msg *, int);
static void print_tap(struct sadb_ext *, struct sadb_msg *, int);
static void print_satype(struct sadb_ext *, struct sadb_msg *, int);
static void print_counter(struct sadb_ext *, struct sadb_msg *, int);
static void print_iface(struct sadb_ext *, struct sadb_msg *, int);
static struct idname *lookup(struct idname *, u_int32_t);
static char *lookup_name(struct idname *, u_int32_t);
static void print_ext(struct sadb_ext *, struct sadb_msg *, int);
void pfkey_print_raw(u_int8_t *, ssize_t);
static char *print_flags(uint32_t);
struct sadb_ext *extensions[SADB_EXT_MAX + 1];
struct idname {
u_int32_t id;
char *name;
void (*func)(struct sadb_ext *, struct sadb_msg *, int);
};
struct idname ext_types[] = {
{ SADB_EXT_RESERVED, "reserved", NULL },
{ SADB_EXT_SA, "sa", print_sa },
{ SADB_EXT_LIFETIME_CURRENT, "lifetime_cur", print_life },
{ SADB_EXT_LIFETIME_HARD, "lifetime_hard", print_life },
{ SADB_EXT_LIFETIME_SOFT, "lifetime_soft", print_life },
{ SADB_EXT_ADDRESS_SRC, "address_src", print_addr },
{ SADB_EXT_ADDRESS_DST, "address_dst", print_addr },
{ SADB_EXT_ADDRESS_PROXY, "address_proxy", print_addr },
{ SADB_EXT_KEY_AUTH, "key_auth", print_key },
{ SADB_EXT_KEY_ENCRYPT, "key_encrypt", print_key },
{ SADB_EXT_IDENTITY_SRC, "identity_src", print_ident },
{ SADB_EXT_IDENTITY_DST, "identity_dst", print_ident },
{ SADB_EXT_SENSITIVITY, "sensitivity", print_sens },
{ SADB_EXT_PROPOSAL, "proposal", print_prop },
{ SADB_EXT_SUPPORTED_AUTH, "supported_auth", print_supp },
{ SADB_EXT_SUPPORTED_ENCRYPT, "supported_encrypt", print_supp },
{ SADB_EXT_SPIRANGE, "spirange", print_spir },
{ SADB_X_EXT_SRC_MASK, "src_mask", print_addr },
{ SADB_X_EXT_DST_MASK, "dst_mask", print_addr },
{ SADB_X_EXT_PROTOCOL, "protocol", print_proto },
{ SADB_X_EXT_FLOW_TYPE, "flow_type", print_flow },
{ SADB_X_EXT_SRC_FLOW, "src_flow", print_addr },
{ SADB_X_EXT_DST_FLOW, "dst_flow", print_addr },
{ SADB_X_EXT_SA2, "sa2", print_sa },
{ SADB_X_EXT_DST2, "dst2", print_addr },
{ SADB_X_EXT_POLICY, "policy", print_policy },
{ SADB_X_EXT_SUPPORTED_COMP, "supported_comp", print_supp },
{ SADB_X_EXT_UDPENCAP, "udpencap", print_udpenc },
{ SADB_X_EXT_LIFETIME_LASTUSE, "lifetime_lastuse", print_life },
{ SADB_X_EXT_TAG, "tag", print_tag },
{ SADB_X_EXT_RDOMAIN, "rdomain", print_rdomain },
{ SADB_X_EXT_REPLAY, "replay", print_replay },
{ SADB_X_EXT_MTU, "mtu", print_mtu },
{ SADB_X_EXT_TAP, "tap", print_tap },
{ SADB_X_EXT_SATYPE2, "satype2", print_satype },
{ SADB_X_EXT_COUNTER, "counter", print_counter },
{ SADB_X_EXT_IFACE, "interface", print_iface },
{ 0, NULL, NULL }
};
struct idname msg_types[] = {
{ SADB_ACQUIRE, "sadb_acquire", NULL },
{ SADB_ADD, "sadb_add", NULL },
{ SADB_DELETE, "sadb_delete", NULL },
{ SADB_DUMP, "sadb_dump", NULL },
{ SADB_EXPIRE, "sadb_expire", NULL },
{ SADB_FLUSH, "sadb_flush", NULL },
{ SADB_GET, "sadb_get", NULL },
{ SADB_GETSPI, "sadb_getspi", NULL },
{ SADB_REGISTER, "sadb_register", NULL },
{ SADB_UPDATE, "sadb_update", NULL },
{ SADB_X_ADDFLOW, "sadb_addflow", NULL },
{ SADB_X_ASKPOLICY, "sadb_askpolicy", NULL },
{ SADB_X_DELFLOW, "sadb_delflow", NULL },
{ SADB_X_GRPSPIS, "sadb_grpspis", NULL },
{ SADB_X_PROMISC, "sadb_promisc", NULL },
{ 0, NULL, NULL },
};
struct idname sa_types[] = {
{ SADB_SATYPE_UNSPEC, "unspec", NULL },
{ SADB_SATYPE_AH, "ah", NULL },
{ SADB_SATYPE_ESP, "esp", NULL },
{ SADB_SATYPE_RSVP, "rsvp", NULL },
{ SADB_SATYPE_OSPFV2, "ospfv2", NULL },
{ SADB_SATYPE_RIPV2, "ripv2", NULL },
{ SADB_SATYPE_MIP, "mip", NULL },
{ SADB_X_SATYPE_IPIP, "ipip", NULL },
{ SADB_X_SATYPE_TCPSIGNATURE, "tcpmd5", NULL },
{ SADB_X_SATYPE_IPCOMP, "ipcomp", NULL },
{ 0, NULL, NULL }
};
struct idname auth_types[] = {
{ SADB_AALG_NONE, "none", NULL },
{ SADB_AALG_MD5HMAC, "hmac-md5", NULL },
{ SADB_X_AALG_RIPEMD160HMAC, "hmac-ripemd160", NULL },
{ SADB_AALG_SHA1HMAC, "hmac-sha1", NULL },
{ SADB_X_AALG_SHA2_256, "hmac-sha2-256", NULL },
{ SADB_X_AALG_SHA2_384, "hmac-sha2-384", NULL },
{ SADB_X_AALG_SHA2_512, "hmac-sha2-512", NULL },
{ SADB_X_AALG_AES128GMAC, "gmac-aes-128", NULL },
{ SADB_X_AALG_AES192GMAC, "gmac-aes-192", NULL },
{ SADB_X_AALG_AES256GMAC, "gmac-aes-256", NULL },
{ SADB_X_AALG_CHACHA20POLY1305, "chacha20-poly1305", NULL },
{ 0, NULL, NULL }
};
struct idname enc_types[] = {
{ SADB_EALG_NONE, "none", NULL },
{ SADB_EALG_3DESCBC, "3des-cbc", NULL },
{ SADB_X_EALG_AES, "aes", NULL },
{ SADB_X_EALG_AESCTR, "aesctr", NULL },
{ SADB_X_EALG_AESGCM16, "aes-gcm", NULL },
{ SADB_X_EALG_AESGMAC, "aes-gmac", NULL },
{ SADB_X_EALG_BLF, "blowfish", NULL },
{ SADB_X_EALG_CAST, "cast128", NULL },
{ SADB_EALG_NULL, "null", NULL },
{ SADB_X_EALG_CHACHA20POLY1305, "chacha20-poly1305", NULL },
{ 0, NULL, NULL }
};
struct idname comp_types[] = {
{ SADB_X_CALG_NONE, "none", NULL },
{ SADB_X_CALG_OUI, "oui", NULL },
{ SADB_X_CALG_DEFLATE, "deflate", NULL },
{ 0, NULL, NULL }
};
struct idname flag_types[] = {
{ SADB_SAFLAGS_PFS, "pfs", NULL },
{ SADB_X_SAFLAGS_TUNNEL, "tunnel", NULL },
{ SADB_X_SAFLAGS_CHAINDEL, "chaindel", NULL },
{ SADB_X_SAFLAGS_UDPENCAP, "udpencap", NULL },
{ SADB_X_SAFLAGS_ESN, "esn", NULL },
{ 0, NULL, NULL }
};
struct idname identity_types[] = {
{ SADB_IDENTTYPE_RESERVED, "reserved", NULL },
{ SADB_IDENTTYPE_PREFIX, "prefix", NULL },
{ SADB_IDENTTYPE_FQDN, "fqdn", NULL },
{ SADB_IDENTTYPE_USERFQDN, "ufqdn", NULL },
{ SADB_IDENTTYPE_ASN1_DN, "asn1_dn", NULL },
{ 0, NULL, NULL }
};
struct idname flow_types[] = {
{ SADB_X_FLOW_TYPE_USE, "use", NULL },
{ SADB_X_FLOW_TYPE_ACQUIRE, "acquire", NULL },
{ SADB_X_FLOW_TYPE_REQUIRE, "require", NULL },
{ SADB_X_FLOW_TYPE_BYPASS, "bypass", NULL },
{ SADB_X_FLOW_TYPE_DENY, "deny", NULL },
{ SADB_X_FLOW_TYPE_DONTACQ, "dontacq", NULL },
{ 0, NULL, NULL }
};
struct idname states[] = {
{ SADB_SASTATE_LARVAL, "larval", NULL },
{ SADB_SASTATE_MATURE, "mature", NULL },
{ SADB_SASTATE_DYING, "dying", NULL },
{ SADB_SASTATE_DEAD, "dead", NULL },
{ 0, NULL, NULL }
};
static struct idname *
lookup(struct idname *tab, u_int32_t id)
{
struct idname *entry;
for (entry = tab; entry->name; entry++)
if (entry->id == id)
return (entry);
return (NULL);
}
static char *
lookup_name(struct idname *tab, u_int32_t id)
{
struct idname *entry;
entry = lookup(tab, id);
return (entry ? entry->name : "unknown");
}
static void
print_ext(struct sadb_ext *ext, struct sadb_msg *msg, int opts)
{
struct idname *entry;
if ((entry = lookup(ext_types, ext->sadb_ext_type)) == NULL) {
printf("unknown ext: type %u len %u\n",
ext->sadb_ext_type, ext->sadb_ext_len);
return;
}
printf("\t%s: ", entry->name);
if (entry->func != NULL)
(*entry->func)(ext, msg, opts);
else
printf("type %u len %u",
ext->sadb_ext_type, ext->sadb_ext_len);
printf("\n");
}
static char *
print_flags(uint32_t flags)
{
static char fstr[80];
struct idname *entry;
int len;
int i, comma = 0, n;
len = snprintf(fstr, sizeof(fstr), "%#x<", flags);
if (len < 0 || (size_t)len >= sizeof(fstr))
return (NULL);
for (i = 0; i < 32; i++) {
if ((flags & (1 << i)) == 0 ||
(entry = lookup(flag_types, 1 << i)) == NULL)
continue;
n = snprintf(fstr + len, sizeof(fstr) - len - 1,
comma ? ",%s" : "%s", entry->name);
if (n < 0 || (size_t)n >= sizeof(fstr) - len - 1)
return (NULL);
len += n;
comma = 1;
}
strlcat(fstr, ">", sizeof(fstr));
return (fstr);
}
static void
print_sa(struct sadb_ext *ext, struct sadb_msg *msg, int opts)
{
struct sadb_sa *sa = (struct sadb_sa *)ext;
if (msg->sadb_msg_satype == SADB_X_SATYPE_IPCOMP)
printf("cpi 0x%8.8x comp %s\n",
ntohl(sa->sadb_sa_spi),
lookup_name(comp_types, sa->sadb_sa_encrypt));
else
printf("spi 0x%8.8x auth %s enc %s\n",
ntohl(sa->sadb_sa_spi),
lookup_name(auth_types, sa->sadb_sa_auth),
lookup_name(enc_types, sa->sadb_sa_encrypt));
printf("\t\tstate %s replay %u flags %s",
lookup_name(states, sa->sadb_sa_state),
sa->sadb_sa_replay, print_flags(sa->sadb_sa_flags));
}
static void
print_addr(struct sadb_ext *ext, struct sadb_msg *msg, int opts)
{
struct sadb_address *addr = (struct sadb_address *)ext;
struct sockaddr *sa;
struct sockaddr_in *sin4;
struct sockaddr_in6 *sin6;
char hbuf[NI_MAXHOST];
sa = (struct sockaddr *)(addr + 1);
if (sa->sa_family == 0)
printf("<any>");
else if (getnameinfo(sa, sa->sa_len, hbuf, sizeof(hbuf), NULL, 0,
NI_NUMERICHOST))
printf("<could not get numeric hostname>");
else
printf("%s", hbuf);
switch (sa->sa_family) {
case AF_INET:
sin4 = (struct sockaddr_in *)sa;
if (sin4->sin_port)
printf(" port %u", ntohs(sin4->sin_port));
break;
case AF_INET6:
sin6 = (struct sockaddr_in6 *)sa;
if (sin6->sin6_port)
printf(" port %u", ntohs(sin6->sin6_port));
break;
}
}
static void
print_key(struct sadb_ext *ext, struct sadb_msg *msg, int opts)
{
struct sadb_key *key = (struct sadb_key *)ext;
u_int8_t *data;
int i;
printf("bits %u: ", key->sadb_key_bits);
data = (u_int8_t *)(key + 1);
for (i = 0; i < key->sadb_key_bits / 8; i++) {
printf("%2.2x", data[i]);
data[i] = 0x00; /* clear sensitive data */
}
}
static void
print_life(struct sadb_ext *ext, struct sadb_msg *msg, int opts)
{
struct sadb_lifetime *life = (struct sadb_lifetime *)ext;
printf("alloc %u bytes %llu add %llu first %llu",
life->sadb_lifetime_allocations,
life->sadb_lifetime_bytes,
life->sadb_lifetime_addtime,
life->sadb_lifetime_usetime);
}
static void
print_proto(struct sadb_ext *ext, struct sadb_msg *msg, int opts)
{
struct sadb_protocol *proto = (struct sadb_protocol *)ext;
/* overloaded */
if (msg->sadb_msg_type == SADB_X_GRPSPIS)
printf("satype %s flags %x",
lookup_name(sa_types, proto->sadb_protocol_proto),
proto->sadb_protocol_flags);
else
printf("proto %u flags %x",
proto->sadb_protocol_proto, proto->sadb_protocol_flags);
}
static void
print_flow(struct sadb_ext *ext, struct sadb_msg *msg, int opts)
{
struct sadb_protocol *proto = (struct sadb_protocol *)ext;
char *dir = "unknown";
switch (proto->sadb_protocol_direction) {
case IPSP_DIRECTION_IN:
dir = "in";
break;
case IPSP_DIRECTION_OUT:
dir = "out";
break;
}
printf("type %s direction %s",
lookup_name(flow_types, proto->sadb_protocol_proto), dir);
}
static void
print_tag(struct sadb_ext *ext, struct sadb_msg *msg, int opts)
{
struct sadb_x_tag *stag = (struct sadb_x_tag *)ext;
char *p;
int plen;
p = (char *)(stag + 1);
plen = stag->sadb_x_tag_len * 8 - sizeof(*stag);
printf("%.*s", plen, p);
}
static void
print_replay(struct sadb_ext *ext, struct sadb_msg *msg, int opts)
{
struct sadb_x_replay *sreplay = (struct sadb_x_replay *)ext;
printf("rpl %llu", sreplay->sadb_x_replay_count);
}
static void
print_mtu(struct sadb_ext *ext, struct sadb_msg *msg, int opts)
{
struct sadb_x_mtu *smtu = (struct sadb_x_mtu *)ext;
printf("mtu %u", smtu->sadb_x_mtu_mtu);
}
static void
print_tap(struct sadb_ext *ext, struct sadb_msg *msg, int opts)
{
struct sadb_x_tap *stap = (struct sadb_x_tap *)ext;
printf("enc%u", stap->sadb_x_tap_unit);
}
static void
print_satype(struct sadb_ext *ext, struct sadb_msg *msg, int opts)
{
struct sadb_protocol *proto = (struct sadb_protocol *)ext;
printf("type %s", lookup_name(sa_types, proto->sadb_protocol_proto));
}
static void
print_counter(struct sadb_ext *ext, struct sadb_msg *msg, int opts)
{
struct sadb_x_counter *scnt = (struct sadb_x_counter *)ext;
printf("\n");
#define plural(n) ((n) != 1 ? "s" : "")
#define p(f, m) if (scnt->f || opts & IPSECCTL_OPT_VERBOSE2) \
printf(m, scnt->f, plural(scnt->f))
p(sadb_x_counter_ipackets, "\t\t%llu input packet%s\n");
p(sadb_x_counter_opackets, "\t\t%llu output packet%s\n");
p(sadb_x_counter_ibytes, "\t\t%llu input byte%s\n");
p(sadb_x_counter_obytes, "\t\t%llu output byte%s\n");
p(sadb_x_counter_idecompbytes, "\t\t%llu input byte%s, decompressed\n");
p(sadb_x_counter_ouncompbytes,"\t\t%llu output byte%s, uncompressed\n");
p(sadb_x_counter_idrops, "\t\t%llu packet%s dropped on input\n");
p(sadb_x_counter_odrops, "\t\t%llu packet%s dropped on output\n");
#undef p
#undef plural
}
static void
print_iface(struct sadb_ext *ext, struct sadb_msg *msg, int opts)
{
struct sadb_x_iface *siface = (struct sadb_x_iface *)ext;
const char *dir = "unknown";
switch (siface->sadb_x_iface_direction) {
case IPSP_DIRECTION_IN:
dir = "in";
break;
case IPSP_DIRECTION_OUT:
dir = "out";
break;
}
printf("sec%u direction %s", siface->sadb_x_iface_unit, dir);
}
static char *
alg_by_ext(u_int8_t ext_type, u_int8_t id)
{
switch (ext_type) {
case SADB_EXT_SUPPORTED_ENCRYPT:
return lookup_name(enc_types, id);
case SADB_EXT_SUPPORTED_AUTH:
return lookup_name(auth_types, id);
case SADB_X_EXT_SUPPORTED_COMP:
return lookup_name(comp_types, id);
default:
return "unknown";
}
}
static void
print_alg(struct sadb_alg *alg, u_int8_t ext_type)
{
printf("\t\t%s iv %u min %u max %u",
alg_by_ext(ext_type, alg->sadb_alg_id), alg->sadb_alg_ivlen,
alg->sadb_alg_minbits, alg->sadb_alg_maxbits);
}
static void
print_supp(struct sadb_ext *ext, struct sadb_msg *msg, int opts)
{
struct sadb_supported *supported = (struct sadb_supported *)ext;
struct sadb_alg *alg;
printf("\n");
for (alg = (struct sadb_alg *)(supported + 1);
(size_t)((u_int8_t *)alg - (u_int8_t *)ext) <
ext->sadb_ext_len * PFKEYV2_CHUNK;
alg++) {
struct sadb_alg *next = alg + 1;
print_alg(alg, ext->sadb_ext_type);
if ((size_t)((u_int8_t *)next - (u_int8_t *)ext) <
ext->sadb_ext_len * PFKEYV2_CHUNK)
printf("\n");
}
}
static void
print_comb(struct sadb_comb *comb, struct sadb_msg *msg, int opts)
{
printf("\t\tauth %s min %u max %u\n"
"\t\tenc %s min %u max %u\n"
"\t\taddtime hard %llu soft %llu\n"
"\t\tusetime hard %llu soft %llu",
lookup_name(auth_types, comb->sadb_comb_auth),
comb->sadb_comb_auth_minbits,
comb->sadb_comb_auth_maxbits,
lookup_name(enc_types, comb->sadb_comb_encrypt),
comb->sadb_comb_encrypt_minbits,
comb->sadb_comb_encrypt_maxbits,
comb->sadb_comb_soft_addtime,
comb->sadb_comb_hard_addtime,
comb->sadb_comb_soft_usetime,
comb->sadb_comb_hard_usetime);
#if 0
comb->sadb_comb_flags,
comb->sadb_comb_reserved,
comb->sadb_comb_soft_allocations,
comb->sadb_comb_hard_allocations,
comb->sadb_comb_soft_bytes,
comb->sadb_comb_hard_bytes,
#endif
}
static void
print_prop(struct sadb_ext *ext, struct sadb_msg *msg, int opts)
{
struct sadb_prop *prop = (struct sadb_prop *)ext;
struct sadb_comb *comb;
printf("replay %u\n", prop->sadb_prop_replay);
for (comb = (struct sadb_comb *)(prop + 1);
(size_t)((u_int8_t *)comb - (u_int8_t *)ext) <
ext->sadb_ext_len * PFKEYV2_CHUNK;
comb++)
print_comb(comb, msg, opts);
}
static void
print_sens(struct sadb_ext *ext, struct sadb_msg *msg, int opts)
{
struct sadb_sens *sens = (struct sadb_sens *)ext;
printf("dpd %u sens_level %u integ_level %u",
sens->sadb_sens_dpd,
sens->sadb_sens_sens_level,
sens->sadb_sens_integ_level);
}
static void
print_spir(struct sadb_ext *ext, struct sadb_msg *msg, int opts)
{
struct sadb_spirange *spirange = (struct sadb_spirange *)ext;
printf("min 0x%8.8x max 0x%8.8x",
spirange->sadb_spirange_min, spirange->sadb_spirange_max);
}
static void
print_ident(struct sadb_ext *ext, struct sadb_msg *msg, int opts)
{
struct sadb_ident *ident = (struct sadb_ident *)ext;
int ilen;
ilen = ident->sadb_ident_len * 8 - sizeof(*ident);
printf("type %s id %llu: %.*s",
lookup_name(identity_types, ident->sadb_ident_type),
ident->sadb_ident_id, ilen, (char *)(ident + 1));
}
static void
print_policy(struct sadb_ext *ext, struct sadb_msg *msg, int opts)
{
struct sadb_x_policy *x_policy = (struct sadb_x_policy *)ext;
printf("seq %u", x_policy->sadb_x_policy_seq);
}
static void
print_udpenc(struct sadb_ext *ext, struct sadb_msg *msg, int opts)
{
struct sadb_x_udpencap *x_udpencap = (struct sadb_x_udpencap *)ext;
printf("udpencap port %u", ntohs(x_udpencap->sadb_x_udpencap_port));
}
static void
print_rdomain(struct sadb_ext *ext, struct sadb_msg *msg, int opts)
{
struct sadb_x_rdomain *srdomain = (struct sadb_x_rdomain *)ext;
printf("%d/%d", srdomain->sadb_x_rdomain_dom1,
srdomain->sadb_x_rdomain_dom2);
}
static void
setup_extensions(struct sadb_msg *msg)
{
struct sadb_ext *ext;
bzero(extensions, sizeof(extensions));
if (msg->sadb_msg_len == 0)
return;
for (ext = (struct sadb_ext *)(msg + 1);
(size_t)((u_int8_t *)ext - (u_int8_t *)msg) <
msg->sadb_msg_len * PFKEYV2_CHUNK && ext->sadb_ext_len > 0;
ext = (struct sadb_ext *)((u_int8_t *)ext +
ext->sadb_ext_len * PFKEYV2_CHUNK))
extensions[ext->sadb_ext_type] = ext;
}
static void
parse_addr(struct sadb_ext *ext, struct ipsec_addr_wrap *ipa)
{
struct sadb_address *addr = (struct sadb_address *)ext;
struct sockaddr *sa;
if (addr == NULL)
return;
sa = (struct sockaddr *)(addr + 1);
switch (sa->sa_family) {
case AF_INET:
ipa->address.v4 = ((struct sockaddr_in *)sa)->sin_addr;
set_ipmask(ipa, 32);
break;
case AF_INET6:
ipa->address.v6 = ((struct sockaddr_in6 *)sa)->sin6_addr;
set_ipmask(ipa, 128);
break;
}
ipa->af = sa->sa_family;
ipa->next = NULL;
ipa->tail = ipa;
}
static void
parse_key(struct sadb_ext *ext, struct ipsec_key *ikey)
{
struct sadb_key *key = (struct sadb_key *)ext;
u_int8_t *data;
if (key == NULL)
return;
data = (u_int8_t *)(key + 1);
ikey->data = data;
ikey->len = key->sadb_key_bits / 8;
}
static void
parse_satype(struct sadb_ext *ext, u_int8_t *satype)
{
struct sadb_protocol *proto = (struct sadb_protocol *)ext;
if (proto == NULL)
return;
switch (proto->sadb_protocol_proto) {
case SADB_SATYPE_ESP:
*satype = IPSEC_ESP;
break;
case SADB_SATYPE_AH:
*satype = IPSEC_AH;
break;
case SADB_X_SATYPE_IPCOMP:
*satype = IPSEC_IPCOMP;
break;
case SADB_X_SATYPE_IPIP:
*satype = IPSEC_IPIP;
break;
default:
return;
}
}
u_int32_t
pfkey_get_spi(struct sadb_msg *msg)
{
struct sadb_sa *sa;
setup_extensions(msg);
sa = (struct sadb_sa *)extensions[SADB_EXT_SA];
return (ntohl(sa->sadb_sa_spi));
}
/* opposite of pfkey_sa() */
void
pfkey_print_sa(struct sadb_msg *msg, int opts)
{
int i;
struct ipsec_rule r;
struct ipsec_key enckey, authkey;
struct ipsec_transforms xfs;
struct ipsec_addr_wrap src, dst, dst2;
struct sadb_sa *sa, *sa2;
setup_extensions(msg);
sa = (struct sadb_sa *)extensions[SADB_EXT_SA];
bzero(&r, sizeof r);
r.type |= RULE_SA;
r.tmode = (msg->sadb_msg_satype != SADB_X_SATYPE_TCPSIGNATURE) &&
(sa->sadb_sa_flags & SADB_X_SAFLAGS_TUNNEL) ?
IPSEC_TUNNEL : IPSEC_TRANSPORT;
r.spi = ntohl(sa->sadb_sa_spi);
switch (msg->sadb_msg_satype) {
case SADB_SATYPE_AH:
r.satype = IPSEC_AH;
break;
case SADB_SATYPE_ESP:
r.satype = IPSEC_ESP;
break;
case SADB_X_SATYPE_IPCOMP:
r.satype = IPSEC_IPCOMP;
break;
case SADB_X_SATYPE_TCPSIGNATURE:
r.satype = IPSEC_TCPMD5;
break;
case SADB_X_SATYPE_IPIP:
r.satype = IPSEC_IPIP;
break;
default:
return;
}
bzero(&dst, sizeof dst);
bzero(&src, sizeof src);
parse_addr(extensions[SADB_EXT_ADDRESS_SRC], &src);
parse_addr(extensions[SADB_EXT_ADDRESS_DST], &dst);
r.src = &src;
r.dst = &dst;
if (r.satype == IPSEC_IPCOMP) {
if (sa->sadb_sa_encrypt) {
bzero(&xfs, sizeof xfs);
r.xfs = &xfs;
switch (sa->sadb_sa_encrypt) {
case SADB_X_CALG_DEFLATE:
xfs.compxf = &compxfs[COMPXF_DEFLATE];
break;
}
}
} else if (r.satype == IPSEC_TCPMD5) {
bzero(&authkey, sizeof authkey);
parse_key(extensions[SADB_EXT_KEY_AUTH], &authkey);
r.authkey = &authkey;
} else if (sa->sadb_sa_encrypt || sa->sadb_sa_auth) {
bzero(&xfs, sizeof xfs);
r.xfs = &xfs;
if (sa->sadb_sa_encrypt) {
bzero(&enckey, sizeof enckey);
parse_key(extensions[SADB_EXT_KEY_ENCRYPT], &enckey);
r.enckey = &enckey;
switch (sa->sadb_sa_encrypt) {
case SADB_EALG_3DESCBC:
xfs.encxf = &encxfs[ENCXF_3DES_CBC];
break;
case SADB_X_EALG_AES:
switch (r.enckey->len) {
case 192/8:
xfs.encxf = &encxfs[ENCXF_AES_192];
break;
case 256/8:
xfs.encxf = &encxfs[ENCXF_AES_256];
break;
default:
xfs.encxf = &encxfs[ENCXF_AES];
break;
}
break;
case SADB_X_EALG_AESCTR:
switch (r.enckey->len) {
case 28:
xfs.encxf = &encxfs[ENCXF_AES_192_CTR];
break;
case 36:
xfs.encxf = &encxfs[ENCXF_AES_256_CTR];
break;
default:
xfs.encxf = &encxfs[ENCXF_AESCTR];
break;
}
break;
case SADB_X_EALG_AESGCM16:
switch (r.enckey->len) {
case 28:
xfs.encxf = &encxfs[ENCXF_AES_192_GCM];
break;
case 36:
xfs.encxf = &encxfs[ENCXF_AES_256_GCM];
break;
default:
xfs.encxf = &encxfs[ENCXF_AES_128_GCM];
break;
}
break;
case SADB_X_EALG_AESGMAC:
switch (r.enckey->len) {
case 28:
xfs.encxf = &encxfs[ENCXF_AES_192_GMAC];
break;
case 36:
xfs.encxf = &encxfs[ENCXF_AES_256_GMAC];
break;
default:
xfs.encxf = &encxfs[ENCXF_AES_128_GMAC];
break;
}
break;
case SADB_X_EALG_BLF:
xfs.encxf = &encxfs[ENCXF_BLOWFISH];
break;
case SADB_X_EALG_CAST:
xfs.encxf = &encxfs[ENCXF_CAST128];
break;
case SADB_X_EALG_CHACHA20POLY1305:
xfs.encxf = &encxfs[ENCXF_CHACHA20_POLY1305];
break;
case SADB_EALG_NULL:
xfs.encxf = &encxfs[ENCXF_NULL];
break;
}
}
if (sa->sadb_sa_auth) {
bzero(&authkey, sizeof authkey);
parse_key(extensions[SADB_EXT_KEY_AUTH], &authkey);
r.authkey = &authkey;
switch (sa->sadb_sa_auth) {
case SADB_AALG_MD5HMAC:
xfs.authxf = &authxfs[AUTHXF_HMAC_MD5];
break;
case SADB_X_AALG_RIPEMD160HMAC:
xfs.authxf = &authxfs[AUTHXF_HMAC_RIPEMD160];
break;
case SADB_AALG_SHA1HMAC:
xfs.authxf = &authxfs[AUTHXF_HMAC_SHA1];
break;
case SADB_X_AALG_SHA2_256:
xfs.authxf = &authxfs[AUTHXF_HMAC_SHA2_256];
break;
case SADB_X_AALG_SHA2_384:
xfs.authxf = &authxfs[AUTHXF_HMAC_SHA2_384];
break;
case SADB_X_AALG_SHA2_512:
xfs.authxf = &authxfs[AUTHXF_HMAC_SHA2_512];
break;
}
}
}
if (!(opts & IPSECCTL_OPT_SHOWKEY)) {
bzero(&enckey, sizeof enckey);
bzero(&authkey, sizeof authkey);
extensions[SADB_EXT_KEY_AUTH] = NULL;
extensions[SADB_EXT_KEY_ENCRYPT] = NULL;
}
if (extensions[SADB_X_EXT_SA2]) {
r.type |= RULE_BUNDLE;
sa2 = (struct sadb_sa *)extensions[SADB_X_EXT_SA2];
r.spi2 = ntohl(sa2->sadb_sa_spi);
parse_addr(extensions[SADB_X_EXT_DST2], &dst2);
r.dst2 = &dst2;
parse_satype(extensions[SADB_X_EXT_SATYPE2], &r.proto2);
r.proto = r.satype;
}
ipsecctl_print_rule(&r, opts);
if (opts & IPSECCTL_OPT_VERBOSE) {
for (i = 0; i <= SADB_EXT_MAX; i++)
if (extensions[i])
print_ext(extensions[i], msg, opts);
}
fflush(stdout);
}
void
pfkey_monitor_sa(struct sadb_msg *msg, int opts)
{
int i;
setup_extensions(msg);
printf("%s: satype %s vers %u len %u seq %u pid %u\n",
lookup_name(msg_types, msg->sadb_msg_type),
lookup_name(sa_types, msg->sadb_msg_satype),
msg->sadb_msg_version, msg->sadb_msg_len,
msg->sadb_msg_seq,
msg->sadb_msg_pid);
if (msg->sadb_msg_errno)
printf("\terrno %u: %s\n", msg->sadb_msg_errno,
strerror(msg->sadb_msg_errno));
for (i = 0; i <= SADB_EXT_MAX; i++)
if (extensions[i])
print_ext(extensions[i], msg, opts);
fflush(stdout);
}
void
pfkey_print_raw(u_int8_t *data, ssize_t len)
{
int i;
const u_int8_t *sp = (const u_int8_t *)data;
printf("RAW PFKEYV2 MESSAGE:\n");
for (i = 0; i < len; i++) {
if ((i % 8 == 0) && (i != 0))
printf("\n");
printf("%02x ", *sp);
sp++;
}
printf("\n");
}