summaryrefslogtreecommitdiff
path: root/keyexchange/isakmpd-20041012/pf_key_v2.c
diff options
context:
space:
mode:
Diffstat (limited to 'keyexchange/isakmpd-20041012/pf_key_v2.c')
-rw-r--r--keyexchange/isakmpd-20041012/pf_key_v2.c4472
1 files changed, 0 insertions, 4472 deletions
diff --git a/keyexchange/isakmpd-20041012/pf_key_v2.c b/keyexchange/isakmpd-20041012/pf_key_v2.c
deleted file mode 100644
index 2614b7e..0000000
--- a/keyexchange/isakmpd-20041012/pf_key_v2.c
+++ /dev/null
@@ -1,4472 +0,0 @@
-/* $OpenBSD: pf_key_v2.c,v 1.150 2004/09/17 13:53:08 ho Exp $ */
-/* $EOM: pf_key_v2.c,v 1.79 2000/12/12 00:33:19 niklas Exp $ */
-
-/*
- * Copyright (c) 1999, 2000, 2001 Niklas Hallqvist. All rights reserved.
- * Copyright (c) 1999, 2000, 2001 Angelos D. Keromytis. All rights reserved.
- * Copyright (c) 2001 Håkan Olsson. 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.
- */
-
-/*
- * This code was written under funding by Ericsson Radio Systems.
- */
-
-// TODO Check this
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <stdlib.h>
-#include <stdio.h>
-//---
-
-#include <sys/stat.h>
-#include <fcntl.h>
-
-#include <sys/types.h>
-#include <sys/ioctl.h>
-#include <sys/queue.h>
-#include <sys/socket.h>
-#include <sys/time.h>
-#include <sys/uio.h>
-
-#include "sysdep.h"
-
-#if !defined (LINUX_IPSEC)
-#include <net/pfkeyv2.h>
-#endif
-#include <netinet/in.h>
-#ifdef SADB_X_EXT_FLOW_TYPE
-#include <sys/mbuf.h>
-#include <netinet/ip_ipsp.h>
-#endif
-#include <arpa/inet.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <pwd.h>
-#include <errno.h>
-#include <bitstring.h>
-
-#include "cert.h"
-#include "conf.h"
-#include "exchange.h"
-#include "ipsec.h"
-#include "ipsec_num.h"
-#include "key.h"
-#include "log.h"
-#include "pf_key_v2.h"
-#include "sa.h"
-#include "timer.h"
-#include "transport.h"
-#include "util.h"
-
-#if defined (USE_KEYNOTE)
-#include "policy.h"
-#endif
-
-#if defined (USE_NAT_TRAVERSAL)
-#include "udp_encap.h"
-#endif
-
-#define IN6_IS_ADDR_FULL(a) \
- ((*(u_int32_t *)(void *)(&(a)->s6_addr[0]) == 0xffff) && \
- (*(u_int32_t *)(void *)(&(a)->s6_addr[4]) == 0xffff) && \
- (*(u_int32_t *)(void *)(&(a)->s6_addr[8]) == 0xffff) && \
- (*(u_int32_t *)(void *)(&(a)->s6_addr[12]) == 0xffff))
-
-#define ADDRESS_MAX sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"
-
-/*
- * PF_KEY v2 always work with 64-bit entities and aligns on 64-bit boundaries.
- */
-#define PF_KEY_V2_CHUNK 8
-#define PF_KEY_V2_ROUND(x) \
- (((x) + PF_KEY_V2_CHUNK - 1) & ~(PF_KEY_V2_CHUNK - 1))
-
-/* How many microseconds we will wait for a reply from the PF_KEY socket. */
-#define PF_KEY_REPLY_TIMEOUT 1000
-
-struct pf_key_v2_node {
- TAILQ_ENTRY(pf_key_v2_node) link;
- void *seg;
- size_t sz;
- int cnt;
- u_int16_t type;
- u_int8_t flags;
-};
-
-TAILQ_HEAD(pf_key_v2_msg, pf_key_v2_node);
-
-#define PF_KEY_V2_NODE_MALLOCED 1
-#define PF_KEY_V2_NODE_MARK 2
-
-#define PF_KEY_V2_SOCK_PATH "/var/run/pkkey"
-
-/* Used to derive "unique" connection identifiers. */
-int connection_seq = 0;
-
-#ifdef KAME
-/*
- * KAME requires the sadb_msg_seq of an UPDATE be the same of that of the
- * GETSPI creating the larval SA.
- */
-struct pf_key_v2_sa_seq {
- TAILQ_ENTRY(pf_key_v2_sa_seq) link;
- u_int8_t *spi;
- size_t sz;
- u_int8_t proto;
- struct sockaddr *dst;
- int dstlen;
- u_int32_t seq;
-};
-
-TAILQ_HEAD(, pf_key_v2_sa_seq) pf_key_v2_sa_seq_map;
-#endif
-
-#ifndef KAME
-static u_int8_t *pf_key_v2_convert_id(u_int8_t *, int, size_t *, int *);
-#endif
-static struct pf_key_v2_msg *pf_key_v2_call(struct pf_key_v2_msg *);
-static struct pf_key_v2_node *pf_key_v2_find_ext(struct pf_key_v2_msg *,
- u_int16_t);
-static void pf_key_v2_notify(struct pf_key_v2_msg *);
-static struct pf_key_v2_msg *pf_key_v2_read(u_int32_t);
-static u_int32_t pf_key_v2_seq(void);
-static u_int32_t pf_key_v2_write(struct pf_key_v2_msg *);
-static int pf_key_v2_remove_conf(char *);
-static int pf_key_v2_conf_refhandle(int, char *);
-
-#ifdef SADB_X_ASKPOLICY
-static int pf_key_v2_conf_refinc(int, char *);
-#endif
-
-/* The socket to use for PF_KEY interactions. */
-int pf_key_v2_socket;
-
-#ifdef KAME
-static int
-pf_key_v2_register_sa_seq(u_int8_t *spi, size_t sz, u_int8_t proto,
- struct sockaddr *dst, int dstlen, u_int32_t seq)
-{
- struct pf_key_v2_sa_seq *node = 0;
-
- node = malloc(sizeof *node);
- if (!node)
- goto cleanup;
- memset(node, '0', sizeof *node);
- node->spi = malloc(sz);
- if (!node->spi)
- goto cleanup;
- node->dst = malloc(sysdep_sa_len(dst));
- if (!node->dst)
- goto cleanup;
- memcpy(node->dst, dst, sysdep_sa_len(dst));
- node->dstlen = sysdep_sa_len(dst);
- memcpy(node->spi, spi, sz);
- node->sz = sz;
- node->proto = proto;
- node->seq = seq;
- TAILQ_INSERT_TAIL(&pf_key_v2_sa_seq_map, node, link);
- return 1;
-
-cleanup:
- if (node->dst)
- free(node->dst);
- if (node)
- free(node);
- return 0;
-}
-
-static u_int32_t
-pf_key_v2_seq_by_sa(u_int8_t *spi, size_t sz, u_int8_t proto,
- struct sockaddr *dst, int dstlen)
-{
- struct pf_key_v2_sa_seq *node;
-
- for (node = TAILQ_FIRST(&pf_key_v2_sa_seq_map); node;
- node = TAILQ_NEXT(node, link))
- if (node->proto == proto &&
- node->sz == sz && memcmp(node->spi, spi, sz) == 0 &&
- node->dstlen == sysdep_sa_len(dst) &&
- memcmp(node->dst, dst, sysdep_sa_len(dst)) == 0)
- return node->seq;
- return 0;
-}
-#endif
-
-static struct pf_key_v2_msg *
-pf_key_v2_msg_new(struct sadb_msg *msg, int flags)
-{
- struct pf_key_v2_node *node = 0;
- struct pf_key_v2_msg *ret;
-
- node = malloc(sizeof *node);
- if (!node)
- goto cleanup;
- ret = malloc(sizeof *ret);
- if (!ret)
- goto cleanup;
- TAILQ_INIT(ret);
- node->seg = msg;
- node->sz = sizeof *msg;
- node->type = 0;
- node->cnt = 1;
- node->flags = flags;
- TAILQ_INSERT_HEAD(ret, node, link);
- return ret;
-
-cleanup:
- if (node)
- free(node);
- return 0;
-}
-
-/* Add a SZ sized segment SEG to the PF_KEY message MSG. */
-static int
-pf_key_v2_msg_add(struct pf_key_v2_msg *msg, struct sadb_ext *ext, int flags)
-{
- struct pf_key_v2_node *node;
-
- node = malloc(sizeof *node);
- if (!node)
- return -1;
- node->seg = ext;
- node->sz = ext->sadb_ext_len * PF_KEY_V2_CHUNK;
- node->type = ext->sadb_ext_type;
- node->flags = flags;
- TAILQ_FIRST(msg)->cnt++;
- TAILQ_INSERT_TAIL(msg, node, link);
- return 0;
-}
-
-/* Deallocate the PF_KEY message MSG. */
-static void
-pf_key_v2_msg_free(struct pf_key_v2_msg *msg)
-{
- struct pf_key_v2_node *np;
-
- np = TAILQ_FIRST(msg);
- while (np) {
- TAILQ_REMOVE(msg, np, link);
- if (np->flags & PF_KEY_V2_NODE_MALLOCED)
- free(np->seg);
- free(np);
- np = TAILQ_FIRST(msg);
- }
- free(msg);
-}
-
-/* Just return a new sequence number. */
-static u_int32_t
-pf_key_v2_seq(void)
-{
- static u_int32_t seq = 0;
-
- return ++seq;
-}
-
-/*
- * Read a PF_KEY packet with SEQ as the sequence number, looping if necessary.
- * If SEQ is zero just read the first message we see, otherwise we queue
- * messages up until both the PID and the sequence number match.
- */
-static struct pf_key_v2_msg *
-pf_key_v2_read(u_int32_t seq)
-{
- ssize_t n;
- u_int8_t *buf = 0;
- struct pf_key_v2_msg *ret = 0;
- struct sadb_msg *msg;
- struct sadb_msg hdr;
- struct sadb_ext *ext;
- struct timeval tv;
- fd_set *fds;
-
- while (1) {
- /*
- * If this is a read of a reply we should actually expect the
- * reply to get lost as PF_KEY is an unreliable service per
- * the specs. Currently we do this by setting a short timeout,
- * and if it is not readable in that time, we fail the read.
- */
- if (seq) {
- fds = calloc(howmany(pf_key_v2_socket + 1, NFDBITS),
- sizeof(fd_mask));
- if (!fds) {
- log_error("pf_key_v2_read: "
- "calloc (%lu, %lu) failed",
- (unsigned long) howmany(pf_key_v2_socket + 1,
- NFDBITS),
- (unsigned long) sizeof(fd_mask));
- goto cleanup;
- }
- FD_SET(pf_key_v2_socket, fds);
- tv.tv_sec = 0;
- tv.tv_usec = PF_KEY_REPLY_TIMEOUT;
- n = select(pf_key_v2_socket + 1, fds, 0, 0, &tv);
- free(fds);
- if (n == -1) {
- log_error("pf_key_v2_read: "
- "select (%d, fds, 0, 0, &tv) failed",
- pf_key_v2_socket + 1);
- goto cleanup;
- }
- if (!n) {
- log_print("pf_key_v2_read: "
- "no reply from PF_KEY");
- goto cleanup;
- }
- }
- n = recv(pf_key_v2_socket, &hdr, sizeof hdr, MSG_PEEK);
- if (n == -1) {
- log_error("pf_key_v2_read: recv (%d, ...) failed",
- pf_key_v2_socket);
- goto cleanup;
- }
- if (n != sizeof hdr) {
- log_error("pf_key_v2_read: recv (%d, ...) "
- "returned short packet (%lu bytes)",
- pf_key_v2_socket, (unsigned long) n);
- goto cleanup;
- }
- n = hdr.sadb_msg_len * PF_KEY_V2_CHUNK;
- buf = malloc(n);
- if (!buf) {
- log_error("pf_key_v2_read: malloc (%lu) failed",
- (unsigned long) n);
- goto cleanup;
- }
- n = read(pf_key_v2_socket, buf, n);
- if (n == -1) {
- log_error("pf_key_v2_read: read (%d, ...) failed",
- pf_key_v2_socket);
- goto cleanup;
- }
- if (n != hdr.sadb_msg_len * PF_KEY_V2_CHUNK) {
- log_print("pf_key_v2_read: read (%d, ...) "
- "returned short packet (%lu bytes)",
- pf_key_v2_socket, (unsigned long) n);
- goto cleanup;
- }
- LOG_DBG_BUF((LOG_SYSDEP, 80, "pf_key_v2_read: msg", buf, n));
-
- /* We drop all messages that is not what we expect. */
- msg = (struct sadb_msg *) buf;
- if (msg->sadb_msg_version != PF_KEY_V2 ||
- (msg->sadb_msg_pid != 0 &&
- msg->sadb_msg_pid != (u_int32_t) getpid())) {
- if (seq) {
- free(buf);
- buf = 0;
- continue;
- } else {
- LOG_DBG((LOG_SYSDEP, 90, "pf_key_v2_read:"
- "bad version (%d) or PID (%d, mine is "
- "%ld), ignored", msg->sadb_msg_version,
- msg->sadb_msg_pid, (long) getpid()));
- goto cleanup;
- }
- }
- /* Parse the message. */
- ret = pf_key_v2_msg_new(msg, PF_KEY_V2_NODE_MALLOCED);
- if (!ret)
- goto cleanup;
- buf = 0;
- for (ext = (struct sadb_ext *) (msg + 1);
- (u_int8_t *) ext - (u_int8_t *) msg <
- msg->sadb_msg_len * PF_KEY_V2_CHUNK;
- ext = (struct sadb_ext *) ((u_int8_t *) ext +
- ext->sadb_ext_len * PF_KEY_V2_CHUNK))
- pf_key_v2_msg_add(ret, ext, 0);
-
- /*
- * If the message is not the one we are waiting for, queue it
- * up.
- */
- if (seq && (msg->sadb_msg_pid != (u_int32_t) getpid() ||
- msg->sadb_msg_seq != seq)) {
- gettimeofday(&tv, 0);
- timer_add_event("pf_key_v2_notify",
- (void (*) (void *)) pf_key_v2_notify, ret, &tv);
- ret = 0;
- continue;
- }
- return ret;
- }
-
-cleanup:
- if (buf)
- free(buf);
- if (ret)
- pf_key_v2_msg_free(ret);
- return 0;
-}
-
-/* Write the message in PMSG to the PF_KEY socket. */
-u_int32_t
-pf_key_v2_write(struct pf_key_v2_msg *pmsg)
-{
- struct iovec *iov = 0;
- ssize_t n;
- size_t len;
- int i, cnt = TAILQ_FIRST(pmsg)->cnt;
- char header[80];
- struct sadb_msg *msg = TAILQ_FIRST(pmsg)->seg;
- struct pf_key_v2_node *np = TAILQ_FIRST(pmsg);
-
- iov = (struct iovec *) malloc(cnt * sizeof *iov);
- if (!iov) {
- log_error("pf_key_v2_write: malloc (%lu) failed",
- cnt * (unsigned long) sizeof *iov);
- return 0;
- }
- msg->sadb_msg_version = PF_KEY_V2;
- msg->sadb_msg_errno = 0;
- msg->sadb_msg_reserved = 0;
- msg->sadb_msg_pid = getpid();
- if (!msg->sadb_msg_seq)
- msg->sadb_msg_seq = pf_key_v2_seq();
-
- /* Compute the iovec segments as well as the message length. */
- len = 0;
- for (i = 0; i < cnt; i++) {
- iov[i].iov_base = np->seg;
- len += iov[i].iov_len = np->sz;
-
- /*
- * XXX One can envision setting specific extension fields, like
- * *_reserved ones here. For now we require them to be set by the
- * caller.
- */
-
- np = TAILQ_NEXT(np, link);
- }
- msg->sadb_msg_len = len / PF_KEY_V2_CHUNK;
-
- for (i = 0; i < cnt; i++) {
- snprintf(header, sizeof header, "pf_key_v2_write: iov[%d]", i);
- LOG_DBG_BUF((LOG_SYSDEP, 80, header,
- (u_int8_t *) iov[i].iov_base, iov[i].iov_len));
- }
-
- n = writev(pf_key_v4_socket, iov, cnt);
- if (n == -1) {
- log_error("pf_key_v2_write: writev (%d, %p, %d) failed",
- pf_key_v2_socket, iov, cnt);
- goto cleanup;
- }
- if ((size_t) n != len) {
- log_error("pf_key_v2_write: "
- "writev (%d, ...) returned prematurely (%lu)",
- pf_key_v2_socket, (unsigned long) n);
- goto cleanup;
- }
- free(iov);
- return msg->sadb_msg_seq;
-
-cleanup:
- if (iov)
- free(iov);
- return 0;
-}
-
-/*
- * Do a PF_KEY "call", i.e. write a message MSG, read the reply and return
- * it to the caller.
- */
-static struct pf_key_v2_msg *
-pf_key_v2_call(struct pf_key_v2_msg *msg)
-{
- u_int32_t seq;
-
- seq = pf_key_v2_write(msg);
- if (!seq)
- return 0;
- return pf_key_v2_read(seq);
-}
-
-/* Find the TYPE extension in MSG. Return zero if none found. */
-static struct pf_key_v2_node *
-pf_key_v2_find_ext(struct pf_key_v2_msg *msg, u_int16_t type)
-{
- struct pf_key_v2_node *ext;
-
- for (ext = TAILQ_NEXT(TAILQ_FIRST(msg), link); ext;
- ext = TAILQ_NEXT(ext, link))
- if (ext->type == type)
- return ext;
- return 0;
-}
-
-/*
- * Open the PF_KEYv2 sockets and return the descriptor used for notifies.
- * Return -1 for failure and -2 if no notifies will show up.
- */
-int
-pf_key_v2_open(void)
-{
- int fd = -1, err;
- struct sadb_msg msg;
- struct pf_key_v2_msg *regmsg = 0, *ret = 0;
- struct sockaddr_un addr;
- socklen_t addrLength = sizeof(addr);
-
- /* Open the socket we use to speak to IPsec. */
- pf_key_v2_socket = -1;
-
- fd = socket(PF_UNIX, SOCK_RAW, 0);
-
- if (fd == -1) {
- log_error("pf_key_v2_open: "
- "socket (PF_KEY, SOCK_RAW, PF_KEY_V2) failed");
- goto cleanup;
- }
-
- memset(&addr, 0, sizeof(struct sockaddr_un));
- /* Clear structure */
- addr.sun_family = AF_UNIX;
- strncpy(addr.sun_path, PF_KEY_V2_SOCK_PATH,
- sizeof(addr.sun_path) - 1);
-
- if (connect(fd, (struct sockaddr *) &addr,
- sizeof(struct sockaddr_un)) == -1) {
- perror("bind");
- exit(EXIT_FAILURE);
- }
-
-
- pf_key_v2_socket = fd;
-
- /* Register it to get ESP and AH acquires from the kernel. */
- msg.sadb_msg_seq = 0;
- msg.sadb_msg_type = SADB_REGISTER;
- msg.sadb_msg_satype = SADB_SATYPE_ESP;
- regmsg = pf_key_v2_msg_new(&msg, 0);
- if (!regmsg)
- goto cleanup;
- ret = pf_key_v2_call(regmsg);
- pf_key_v2_msg_free(regmsg);
- if (!ret)
- goto cleanup;
- err = ((struct sadb_msg *)TAILQ_FIRST(ret)->seg)->sadb_msg_errno;
- if (err) {
- log_print("pf_key_v2_open: REGISTER: %s", strerror(err));
- goto cleanup;
- }
- /* XXX Register the accepted transforms. */
-
- pf_key_v2_msg_free(ret);
- ret = 0;
-
- msg.sadb_msg_seq = 0;
- msg.sadb_msg_type = SADB_REGISTER;
- msg.sadb_msg_satype = SADB_SATYPE_AH;
- regmsg = pf_key_v2_msg_new(&msg, 0);
- if (!regmsg)
- goto cleanup;
- ret = pf_key_v2_call(regmsg);
- pf_key_v2_msg_free(regmsg);
- if (!ret)
- goto cleanup;
- err = ((struct sadb_msg *)TAILQ_FIRST(ret)->seg)->sadb_msg_errno;
- if (err) {
- log_print("pf_key_v2_open: REGISTER: %s", strerror(err));
- goto cleanup;
- }
- /* XXX Register the accepted transforms. */
-
- pf_key_v2_msg_free(ret);
- ret = 0;
-
-#ifdef SADB_X_SATYPE_IPCOMP
- msg.sadb_msg_seq = 0;
- msg.sadb_msg_type = SADB_REGISTER;
- msg.sadb_msg_satype = SADB_X_SATYPE_IPCOMP;
- regmsg = pf_key_v2_msg_new(&msg, 0);
- if (!regmsg)
- goto cleanup;
- ret = pf_key_v2_call(regmsg);
- pf_key_v2_msg_free(regmsg);
- if (!ret)
- goto cleanup;
- err = ((struct sadb_msg *)TAILQ_FIRST(ret)->seg)->sadb_msg_errno;
- if (err) {
- log_print("pf_key_v2_open: REGISTER: %s", strerror(err));
- goto cleanup;
- }
- /* XXX Register the accepted transforms. */
-
- pf_key_v2_msg_free(ret);
-#endif /* SADB_X_SATYPE_IPCOMP */
-
-#ifdef KAME
- TAILQ_INIT(&pf_key_v2_sa_seq_map);
-#endif
-
- return fd;
-
-cleanup:
- if (pf_key_v2_socket != -1) {
- close(pf_key_v2_socket);
- pf_key_v2_socket = -1;
- }
- if (ret)
- pf_key_v2_msg_free(ret);
- return -1;
-}
-
-/*
- * Generate a SPI for protocol PROTO and the source/destination pair given by
- * SRC, SRCLEN, DST & DSTLEN. Stash the SPI size in SZ.
- */
-u_int8_t *
-pf_key_v2_get_spi(size_t *sz, u_int8_t proto, struct sockaddr *src,
- struct sockaddr *dst, u_int32_t seq)
-{
- struct sadb_msg msg;
- struct sadb_sa *sa;
- struct sadb_address *addr = 0;
- struct sadb_spirange spirange;
- struct pf_key_v2_msg *getspi = 0, *ret = 0;
- struct pf_key_v2_node *ext;
- u_int8_t *spi = 0;
- int len, err;
-#ifdef KAME
- struct sadb_x_sa2 ssa2;
-#endif
-
- msg.sadb_msg_type = SADB_GETSPI;
- switch (proto) {
- case IPSEC_PROTO_IPSEC_ESP:
- msg.sadb_msg_satype = SADB_SATYPE_ESP;
- break;
- case IPSEC_PROTO_IPSEC_AH:
- msg.sadb_msg_satype = SADB_SATYPE_AH;
- break;
-#ifdef SADB_X_SATYPE_IPCOMP
- case IPSEC_PROTO_IPCOMP:
- msg.sadb_msg_satype = SADB_X_SATYPE_IPCOMP;
- break;
-#endif
- default:
- log_print("pf_key_v2_get_spi: invalid proto %d", proto);
- goto cleanup;
- }
-
- /* Set the sequence number from the ACQUIRE message. */
- msg.sadb_msg_seq = seq;
- getspi = pf_key_v2_msg_new(&msg, 0);
- if (!getspi)
- goto cleanup;
-
-#ifdef KAME
- memset(&ssa2, 0, sizeof ssa2);
- ssa2.sadb_x_sa2_exttype = SADB_X_EXT_SA2;
- ssa2.sadb_x_sa2_len = sizeof ssa2 / PF_KEY_V2_CHUNK;
- ssa2.sadb_x_sa2_mode = 0;
- if (pf_key_v2_msg_add(getspi, (struct sadb_ext *)&ssa2, 0) == -1)
- goto cleanup;
-#endif
-
- /* Setup the ADDRESS extensions. */
- len =
- sizeof(struct sadb_address) + PF_KEY_V2_ROUND(sysdep_sa_len(src));
- addr = calloc(1, len);
- if (!addr)
- goto cleanup;
- addr->sadb_address_exttype = SADB_EXT_ADDRESS_SRC;
- addr->sadb_address_len = len / PF_KEY_V2_CHUNK;
-#ifndef __OpenBSD__
- addr->sadb_address_proto = 0;
- addr->sadb_address_prefixlen = 0;
-#endif
- addr->sadb_address_reserved = 0;
- memcpy(addr + 1, src, sysdep_sa_len(src));
- switch (((struct sockaddr *) (addr + 1))->sa_family) {
- case AF_INET:
- ((struct sockaddr_in *) (addr + 1))->sin_port = 0;
- break;
- case AF_INET6:
- ((struct sockaddr_in6 *) (addr + 1))->sin6_port = 0;
- break;
- }
- if (pf_key_v2_msg_add(getspi, (struct sadb_ext *) addr,
- PF_KEY_V2_NODE_MALLOCED) == -1)
- goto cleanup;
- addr = 0;
-
- len =
- sizeof(struct sadb_address) + PF_KEY_V2_ROUND(sysdep_sa_len(dst));
- addr = calloc(1, len);
- if (!addr)
- goto cleanup;
- addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST;
- addr->sadb_address_len = len / PF_KEY_V2_CHUNK;
-#ifndef __OpenBSD__
- addr->sadb_address_proto = 0;
- addr->sadb_address_prefixlen = 0;
-#endif
- addr->sadb_address_reserved = 0;
- memcpy(addr + 1, dst, sysdep_sa_len(dst));
- switch (((struct sockaddr *) (addr + 1))->sa_family) {
- case AF_INET:
- ((struct sockaddr_in *) (addr + 1))->sin_port = 0;
- break;
- case AF_INET6:
- ((struct sockaddr_in6 *) (addr + 1))->sin6_port = 0;
- break;
- }
- if (pf_key_v2_msg_add(getspi, (struct sadb_ext *) addr,
- PF_KEY_V2_NODE_MALLOCED) == -1)
- goto cleanup;
- addr = 0;
-
- /* Setup the SPIRANGE extension. */
- spirange.sadb_spirange_exttype = SADB_EXT_SPIRANGE;
- spirange.sadb_spirange_len = sizeof spirange / PF_KEY_V2_CHUNK;
- if (proto == IPSEC_PROTO_IPCOMP) {
- spirange.sadb_spirange_min = CPI_RESERVED_MAX + 1;
- spirange.sadb_spirange_max = CPI_PRIVATE_MIN - 1;
- } else {
- spirange.sadb_spirange_min = IPSEC_SPI_LOW;
- spirange.sadb_spirange_max = 0xffffffff;
- }
- spirange.sadb_spirange_reserved = 0;
- if (pf_key_v2_msg_add(getspi, (struct sadb_ext *)&spirange, 0) == -1)
- goto cleanup;
-
- ret = pf_key_v2_call(getspi);
- pf_key_v2_msg_free(getspi);
- getspi = 0;
- if (!ret)
- goto cleanup;
- err = ((struct sadb_msg *)TAILQ_FIRST(ret)->seg)->sadb_msg_errno;
- if (err) {
- log_print("pf_key_v2_get_spi: GETSPI: %s", strerror(err));
- goto cleanup;
- }
- ext = pf_key_v2_find_ext(ret, SADB_EXT_SA);
- if (!ext) {
- log_print("pf_key_v2_get_spi: no SA extension found");
- goto cleanup;
- }
- sa = ext->seg;
-
- /* IPCOMP CPIs are only 16 bits long. */
- *sz = (proto == IPSEC_PROTO_IPCOMP) ? sizeof(u_int16_t)
- : sizeof sa->sadb_sa_spi;
- spi = malloc(*sz);
- if (!spi)
- goto cleanup;
- /* XXX This is ugly. */
- if (proto == IPSEC_PROTO_IPCOMP) {
- u_int32_t tspi = ntohl(sa->sadb_sa_spi);
- *(u_int16_t *) spi = htons((u_int16_t) tspi);
- } else
- memcpy(spi, &sa->sadb_sa_spi, *sz);
-
-#ifdef KAME
- if (!pf_key_v2_register_sa_seq(spi, *sz, proto, dst,
- sysdep_sa_len(dst),
- ((struct sadb_msg *) (TAILQ_FIRST(ret)->seg))->sadb_msg_seq))
- goto cleanup;
-#endif
- pf_key_v2_msg_free(ret);
-
- LOG_DBG_BUF((LOG_SYSDEP, 50, "pf_key_v2_get_spi: spi", spi, *sz));
- return spi;
-
-cleanup:
- if (spi)
- free(spi);
- if (addr)
- free(addr);
- if (getspi)
- pf_key_v2_msg_free(getspi);
- if (ret)
- pf_key_v2_msg_free(ret);
- return 0;
-}
-
-/* Fetch SA information from the kernel. XXX OpenBSD only? */
-struct sa_kinfo *
-pf_key_v2_get_kernel_sa(u_int8_t *spi, size_t spi_sz, u_int8_t proto,
- struct sockaddr *dst)
-{
- struct sadb_msg msg;
- struct sadb_sa *ssa;
- struct sadb_address *addr = 0;
- struct sockaddr *sa;
- struct sadb_lifetime *life;
- struct pf_key_v2_msg *gettdb = 0, *ret = 0;
- struct pf_key_v2_node *ext;
- static struct sa_kinfo ksa;
-#if defined (SADB_X_EXT_UDPENCAP)
- struct sadb_x_udpencap *udpencap;
-#endif
- int len, err;
-
- if (spi_sz != sizeof (ssa->sadb_sa_spi))
- return 0;
-
- msg.sadb_msg_type = SADB_GET;
- switch (proto) {
- case IPSEC_PROTO_IPSEC_ESP:
- msg.sadb_msg_satype = SADB_SATYPE_ESP;
- break;
- case IPSEC_PROTO_IPSEC_AH:
- msg.sadb_msg_satype = SADB_SATYPE_AH;
- break;
-#ifdef SADB_X_SATYPE_IPCOMP
- case IPSEC_PROTO_IPCOMP:
- msg.sadb_msg_satype = SADB_X_SATYPE_IPCOMP;
- break;
-#endif
- default:
- log_print("pf_key_v2_get_kernel_sa: invalid proto %d", proto);
- goto cleanup;
- }
-
- gettdb = pf_key_v2_msg_new(&msg, 0);
- if (!gettdb)
- goto cleanup;
-
- /* SPI */
- ssa = (struct sadb_sa *)calloc(1, sizeof *ssa);
- if (!ssa) {
- log_print("pf_key_v2_get_kernel_sa: calloc(1, %lu) failed",
- (unsigned long)sizeof *ssa);
- goto cleanup;
- }
-
- ssa->sadb_sa_exttype = SADB_EXT_SA;
- ssa->sadb_sa_len = sizeof *ssa / PF_KEY_V2_CHUNK;
- memcpy(&ssa->sadb_sa_spi, spi, sizeof ssa->sadb_sa_spi);
- ssa->sadb_sa_state = SADB_SASTATE_MATURE;
- if (pf_key_v2_msg_add(gettdb, (struct sadb_ext *)ssa,
- PF_KEY_V2_NODE_MALLOCED) == -1)
- goto cleanup;
- ssa = 0;
-
- /* XXX KAME SADB_X_EXT_xyz here? */
-
- /* Address */
- len =
- sizeof(struct sadb_address) + PF_KEY_V2_ROUND(sysdep_sa_len(dst));
- addr = calloc(1, len);
- if (!addr)
- goto cleanup;
- addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST;
- addr->sadb_address_len = len / PF_KEY_V2_CHUNK;
-#ifndef __OpenBSD__
- addr->sadb_address_proto = 0;
- addr->sadb_address_prefixlen = 0;
-#endif
- addr->sadb_address_reserved = 0;
- memcpy(addr + 1, dst, sysdep_sa_len(dst));
- switch (((struct sockaddr *) (addr + 1))->sa_family) {
- case AF_INET:
- ((struct sockaddr_in *) (addr + 1))->sin_port = 0;
- break;
- case AF_INET6:
- ((struct sockaddr_in6 *) (addr + 1))->sin6_port = 0;
- break;
- }
- if (pf_key_v2_msg_add(gettdb, (struct sadb_ext *)addr,
- PF_KEY_V2_NODE_MALLOCED) == -1)
- goto cleanup;
- addr = 0;
-
- ret = pf_key_v2_call(gettdb);
- pf_key_v2_msg_free(gettdb);
- gettdb = 0;
- if (!ret)
- goto cleanup;
- err = ((struct sadb_msg *)TAILQ_FIRST(ret)->seg)->sadb_msg_errno;
- if (err) {
- log_print("pf_key_v2_get_kernel_sa: SADB_GET: %s",
- strerror(err));
- goto cleanup;
- }
-
- /* Extract the data. */
- memset(&ksa, 0, sizeof ksa);
-
- ext = pf_key_v2_find_ext(ret, SADB_EXT_SA);
- if (!ext)
- goto cleanup;
-
- ssa = (struct sadb_sa *)ext;
- ksa.spi = ssa->sadb_sa_spi;
- ksa.wnd = ssa->sadb_sa_replay;
- ksa.flags = ssa->sadb_sa_flags;
-
- ext = pf_key_v2_find_ext(ret, SADB_EXT_LIFETIME_CURRENT);
- if (ext) {
- life = (struct sadb_lifetime *)ext->seg;
- ksa.cur_allocations = life->sadb_lifetime_allocations;
- ksa.cur_bytes = life->sadb_lifetime_bytes;
- ksa.first_use = life->sadb_lifetime_usetime;
- ksa.established = life->sadb_lifetime_addtime;
- }
-
- ext = pf_key_v2_find_ext(ret, SADB_EXT_LIFETIME_SOFT);
- if (ext) {
- life = (struct sadb_lifetime *)ext->seg;
- ksa.soft_allocations = life->sadb_lifetime_allocations;
- ksa.soft_bytes = life->sadb_lifetime_bytes;
- ksa.soft_timeout = life->sadb_lifetime_addtime;
- ksa.soft_first_use = life->sadb_lifetime_usetime;
- }
-
- ext = pf_key_v2_find_ext(ret, SADB_EXT_LIFETIME_HARD);
- if (ext) {
- life = (struct sadb_lifetime *)ext->seg;
- ksa.exp_allocations = life->sadb_lifetime_allocations;
- ksa.exp_bytes = life->sadb_lifetime_bytes;
- ksa.exp_timeout = life->sadb_lifetime_addtime;
- ksa.exp_first_use = life->sadb_lifetime_usetime;
- }
-
-#if defined (SADB_X_EXT_LIFETIME_LASTUSE)
- ext = pf_key_v2_find_ext(ret, SADB_X_EXT_LIFETIME_LASTUSE);
- if (ext) {
- life = (struct sadb_lifetime *)ext->seg;
- ksa.last_used = life->sadb_lifetime_usetime;
- }
-#endif
-
- ext = pf_key_v2_find_ext(ret, SADB_EXT_ADDRESS_SRC);
- if (ext) {
- sa = (struct sockaddr *)ext->seg;
- memcpy(&ksa.src, sa,
- sa->sa_family == AF_INET ? sizeof(struct sockaddr_in) :
- sizeof(struct sockaddr_in6));
- }
-
- ext = pf_key_v2_find_ext(ret, SADB_EXT_ADDRESS_DST);
- if (ext) {
- sa = (struct sockaddr *)ext->seg;
- memcpy(&ksa.dst, sa,
- sa->sa_family == AF_INET ? sizeof(struct sockaddr_in) :
- sizeof(struct sockaddr_in6));
- }
-
- ext = pf_key_v2_find_ext(ret, SADB_EXT_ADDRESS_PROXY);
- if (ext) {
- sa = (struct sockaddr *)ext->seg;
- memcpy(sa, &ksa.proxy,
- sa->sa_family == AF_INET ? sizeof(struct sockaddr_in) :
- sizeof(struct sockaddr_in6));
- }
-
-#if defined (SADB_X_EXT_UDPENCAP)
- ext = pf_key_v2_find_ext(ret, SADB_X_EXT_UDPENCAP);
- if (ext) {
- udpencap = (struct sadb_x_udpencap *)ext->seg;
- ksa.udpencap_port = udpencap->sadb_x_udpencap_port;
- }
-#endif
-
- pf_key_v2_msg_free(ret);
-
- LOG_DBG_BUF((LOG_SYSDEP, 50, "pf_key_v2_get_kernel_sa: spi", spi,
- spi_sz));
-
- return &ksa;
-
- cleanup:
- if (addr)
- free (addr);
- if (gettdb)
- pf_key_v2_msg_free(gettdb);
- if (ret)
- pf_key_v2_msg_free(ret);
- return 0;
-}
-
-static void
-pf_key_v2_setup_sockaddr(void *res, struct sockaddr *src,
- struct sockaddr *dst, in_port_t port, int ingress)
-{
- struct sockaddr_in *ip4_sa;
- struct sockaddr_in6 *ip6_sa;
- u_int8_t *p;
-
- switch (src->sa_family) {
- case AF_INET:
- ip4_sa = (struct sockaddr_in *) res;
- ip4_sa->sin_family = AF_INET;
-#ifndef USE_OLD_SOCKADDR
- ip4_sa->sin_len = sizeof *ip4_sa;
-#endif
- ip4_sa->sin_port = port;
- if (dst)
- p = (u_int8_t *) (ingress ?
- &((struct sockaddr_in *)src)->sin_addr.s_addr :
- &((struct sockaddr_in *)dst)->sin_addr.s_addr);
- else
- p = (u_int8_t *)&((struct sockaddr_in *)src)->sin_addr.s_addr;
- ip4_sa->sin_addr.s_addr = *((in_addr_t *) p);
- break;
-
- case AF_INET6:
- ip6_sa = (struct sockaddr_in6 *) res;
- ip6_sa->sin6_family = AF_INET6;
-#ifndef USE_OLD_SOCKADDR
- ip6_sa->sin6_len = sizeof *ip6_sa;
-#endif
- ip6_sa->sin6_port = port;
- if (dst)
- p = (u_int8_t *) (ingress ?
- &((struct sockaddr_in6 *)src)->sin6_addr.s6_addr :
- &((struct sockaddr_in6 *)dst)->sin6_addr.s6_addr);
- else
- p = (u_int8_t *)&((struct sockaddr_in6 *)src)->sin6_addr.s6_addr;
- memcpy(ip6_sa->sin6_addr.s6_addr, p, sizeof(struct in6_addr));
- break;
-
- default:
- log_print("pf_key_v2_setup_sockaddr: unknown family %d\n",
- src->sa_family);
- break;
- }
-}
-
-/*
- * Store/update a PF_KEY_V2 security association with full information from the
- * IKE SA and PROTO into the kernel. INCOMING is set if we are setting the
- * parameters for the incoming SA, and cleared otherwise.
- */
-int
-pf_key_v2_set_spi(struct sa *sa, struct proto *proto, int incoming,
- struct sa *isakmp_sa)
-{
- struct sadb_msg msg;
- struct sadb_sa ssa;
- struct sadb_lifetime *life = 0;
- struct sadb_address *addr = 0;
- struct sadb_key *key = 0;
- struct sadb_ident *sid = 0;
- struct sockaddr *src, *dst;
- struct pf_key_v2_msg *update = 0, *ret = 0;
- struct ipsec_proto *iproto = proto->data;
- size_t len;
- int keylen, hashlen, err;
-#ifndef KAME
- u_int8_t *pp;
- int idtype;
-#else /* KAME */
- struct sadb_x_sa2 ssa2;
-#endif
-#if defined (SADB_X_CREDTYPE_NONE) || defined (SADB_X_AUTHTYPE_NONE)
- struct ipsec_sa *isa = sa->data;
- struct sadb_x_cred *cred;
- struct sadb_protocol flowtype, tprotocol;
-#endif
-#if defined (USE_NAT_TRAVERSAL) && defined (SADB_X_EXT_UDPENCAP)
- struct sadb_x_udpencap udpencap;
-#elif defined (USE_NAT_TRAVERSAL) && defined (SADB_X_EXT_NAT_T_TYPE)
- struct sadb_x_nat_t_type nat_t_type;
- struct sadb_x_nat_t_port nat_t_sport;
- struct sadb_x_nat_t_port nat_t_dport;
-#endif
-#ifdef USE_DEBUG
- char *addr_str;
-#endif
-
- msg.sadb_msg_type = incoming ? SADB_UPDATE : SADB_ADD;
- switch (proto->proto) {
- case IPSEC_PROTO_IPSEC_ESP:
- msg.sadb_msg_satype = SADB_SATYPE_ESP;
- keylen = ipsec_esp_enckeylength(proto);
- hashlen = ipsec_esp_authkeylength(proto);
-
- switch (proto->id) {
- case IPSEC_ESP_DES:
- case IPSEC_ESP_DES_IV32:
- case IPSEC_ESP_DES_IV64:
- ssa.sadb_sa_encrypt = SADB_EALG_DESCBC;
- break;
-
- case IPSEC_ESP_3DES:
- ssa.sadb_sa_encrypt = SADB_EALG_3DESCBC;
- break;
-
-#ifdef SADB_X_EALG_AES
- case IPSEC_ESP_AES:
- /* case IPSEC_ESP_AES_128_CTR: */
- ssa.sadb_sa_encrypt = SADB_X_EALG_AES;
- break;
-#endif
-
-#ifdef SADB_X_EALG_CAST
- case IPSEC_ESP_CAST:
- ssa.sadb_sa_encrypt = SADB_X_EALG_CAST;
- break;
-#endif
-
-#ifdef SADB_X_EALG_BLF
- case IPSEC_ESP_BLOWFISH:
- ssa.sadb_sa_encrypt = SADB_X_EALG_BLF;
- break;
-#endif
-
- default:
- LOG_DBG((LOG_SYSDEP, 50, "pf_key_v2_set_spi: "
- "unknown encryption algorithm %d", proto->id));
- return -1;
- }
-
- switch (iproto->auth) {
- case IPSEC_AUTH_HMAC_MD5:
-#ifdef SADB_AALG_MD5HMAC96
- ssa.sadb_sa_auth = SADB_AALG_MD5HMAC96;
-#else
- ssa.sadb_sa_auth = SADB_AALG_MD5HMAC;
-#endif
- break;
-
- case IPSEC_AUTH_HMAC_SHA:
-#ifdef SADB_AALG_SHA1HMAC96
- ssa.sadb_sa_auth = SADB_AALG_SHA1HMAC96;
-#else
- ssa.sadb_sa_auth = SADB_AALG_SHA1HMAC;
-#endif
- break;
-
-#ifndef KAME
- case IPSEC_AUTH_HMAC_RIPEMD:
-#ifdef SADB_X_AALG_RIPEMD160HMAC96
- ssa.sadb_sa_auth = SADB_X_AALG_RIPEMD160HMAC96;
-#elif defined (SADB_X_AALG_RIPEMD160HMAC)
- ssa.sadb_sa_auth = SADB_X_AALG_RIPEMD160HMAC;
-#elif defined (SADB_X_AALG_RIPEMD160)
- ssa.sadb_sa_auth = SADB_X_AALG_RIPEMD160;
-#else
- ssa.sadb_sa_auth = SADB_AALG_RIPEMD160HMAC;
-#endif
- break;
-#endif
-
-#ifdef SADB_X_AALG_SHA2_256
- case IPSEC_AUTH_HMAC_SHA2_256:
- ssa.sadb_sa_auth = SADB_X_AALG_SHA2_256;
- break;
-#endif
-
-#ifdef SADB_X_AALG_SHA2_384
- case IPSEC_AUTH_HMAC_SHA2_384:
- ssa.sadb_sa_auth = SADB_X_AALG_SHA2_384;
- break;
-#endif
-
-#ifdef SADB_X_AALG_SHA2_512
- case IPSEC_AUTH_HMAC_SHA2_512:
- ssa.sadb_sa_auth = SADB_X_AALG_SHA2_512;
- break;
-#endif
-
- case IPSEC_AUTH_DES_MAC:
- case IPSEC_AUTH_KPDK:
- /* XXX We should be supporting KPDK */
- LOG_DBG((LOG_SYSDEP, 50, "pf_key_v2_set_spi: "
- "unknown authentication algorithm %d",
- iproto->auth));
- return -1;
-
- default:
- ssa.sadb_sa_auth = SADB_AALG_NONE;
- }
- break;
-
- case IPSEC_PROTO_IPSEC_AH:
- msg.sadb_msg_satype = SADB_SATYPE_AH;
- hashlen = ipsec_ah_keylength(proto);
- keylen = 0;
-
- ssa.sadb_sa_encrypt = SADB_EALG_NONE;
- switch (proto->id) {
- case IPSEC_AH_MD5:
-#ifdef SADB_AALG_MD5HMAC96
- ssa.sadb_sa_auth = SADB_AALG_MD5HMAC96;
-#else
- ssa.sadb_sa_auth = SADB_AALG_MD5HMAC;
-#endif
- break;
-
- case IPSEC_AH_SHA:
-#ifdef SADB_AALG_SHA1HMAC96
- ssa.sadb_sa_auth = SADB_AALG_SHA1HMAC96;
-#else
- ssa.sadb_sa_auth = SADB_AALG_SHA1HMAC;
-#endif
- break;
-
-#ifndef KAME
- case IPSEC_AH_RIPEMD:
-#ifdef SADB_X_AALG_RIPEMD160HMAC96
- ssa.sadb_sa_auth = SADB_X_AALG_RIPEMD160HMAC96;
-#elif defined (SADB_X_AALG_RIPEMD160HMAC)
- ssa.sadb_sa_auth = SADB_X_AALG_RIPEMD160HMAC;
-#elif defined (SADB_X_AALG_RIPEMD160)
- ssa.sadb_sa_auth = SADB_X_AALG_RIPEMD160;
-#else
- ssa.sadb_sa_auth = SADB_AALG_RIPEMD160HMAC;
-#endif
- break;
-#endif
-
-#ifdef SADB_X_AALG_SHA2_256
- case IPSEC_AH_SHA2_256:
- ssa.sadb_sa_auth = SADB_X_AALG_SHA2_256;
- break;
-#endif
-
-#ifdef SADB_X_AALG_SHA2_384
- case IPSEC_AH_SHA2_384:
- ssa.sadb_sa_auth = SADB_X_AALG_SHA2_384;
- break;
-#endif
-
-#ifdef SADB_X_AALG_SHA2_512
- case IPSEC_AH_SHA2_512:
- ssa.sadb_sa_auth = SADB_X_AALG_SHA2_512;
- break;
-#endif
-
- default:
- LOG_DBG((LOG_SYSDEP, 50, "pf_key_v2_set_spi: "
- "unknown authentication algorithm %d", proto->id));
- goto cleanup;
- }
- break;
-
-#ifdef SADB_X_SATYPE_IPCOMP
- case IPSEC_PROTO_IPCOMP:
- msg.sadb_msg_satype = SADB_X_SATYPE_IPCOMP;
- ssa.sadb_sa_auth = SADB_AALG_NONE;
- keylen = 0;
- hashlen = 0;
-
- /*
- * Put compression algorithm type in the sadb_sa_encrypt
- * field.
- */
- switch (proto->id) {
-#ifdef SADB_X_CALG_OUI
- case IPSEC_IPCOMP_OUI:
- ssa.sadb_sa_encrypt = SADB_X_CALG_OUI;
- break;
-#endif
-
-#ifdef SADB_X_CALG_DEFLATE
- case IPSEC_IPCOMP_DEFLATE:
- ssa.sadb_sa_encrypt = SADB_X_CALG_DEFLATE;
- break;
-#endif
-
-#ifdef SADB_X_CALG_LZS
- case IPSEC_IPCOMP_LZS:
- ssa.sadb_sa_encrypt = SADB_X_CALG_LZS;
- break;
-#endif
-
-#ifdef SADB_X_CALG_V42BIS
- case IPSEC_IPCOMP_V42BIS:
- ssa.sadb_sa_encrypt = SADB_X_CALG_V42BIS;
- break;
-#endif
-
- default:
- break;
- }
- break;
-#endif /* SADB_X_SATYPE_IPCOMP */
-
- default:
- log_print("pf_key_v2_set_spi: invalid proto %d", proto->proto);
- goto cleanup;
- }
- if (incoming) {
- sa->transport->vtbl->get_src(sa->transport, &dst);
- sa->transport->vtbl->get_dst(sa->transport, &src);
- }
- else {
- sa->transport->vtbl->get_dst(sa->transport, &dst);
- sa->transport->vtbl->get_src(sa->transport, &src);
- }
-
-#ifdef KAME
- msg.sadb_msg_seq = (incoming ?
- pf_key_v2_seq_by_sa(proto->spi[incoming], sizeof ssa.sadb_sa_spi,
- proto->proto, dst, sysdep_sa_len(dst)) : 0);
-#else
- msg.sadb_msg_seq = sa->seq;
-#endif
- update = pf_key_v2_msg_new(&msg, 0);
- if (!update)
- goto cleanup;
-
-#ifdef KAME
- memset(&ssa2, 0, sizeof ssa2);
- ssa2.sadb_x_sa2_exttype = SADB_X_EXT_SA2;
- ssa2.sadb_x_sa2_len = sizeof ssa2 / PF_KEY_V2_CHUNK;
-#if defined (LINUX_IPSEC)
- if (iproto->encap_mode == IPSEC_ENCAP_TUNNEL)
- ssa2.sadb_x_sa2_mode = IPSEC_MODE_TUNNEL;
- else
- ssa2.sadb_x_sa2_mode = IPSEC_MODE_TRANSPORT;
-#else
- ssa2.sadb_x_sa2_mode = 0;
-#endif
- if (pf_key_v2_msg_add(update, (struct sadb_ext *)&ssa2, 0) == -1)
- goto cleanup;
-#endif
-
- /* Setup the rest of the SA extension. */
- ssa.sadb_sa_exttype = SADB_EXT_SA;
- ssa.sadb_sa_len = sizeof ssa / PF_KEY_V2_CHUNK;
- if (proto->spi_sz[incoming] == 2) /* IPCOMP uses 16bit CPIs. */
- ssa.sadb_sa_spi = htonl(proto->spi[incoming][0] << 8 |
- proto->spi[incoming][1]);
- else
- memcpy(&ssa.sadb_sa_spi, proto->spi[incoming],
- sizeof ssa.sadb_sa_spi);
- ssa.sadb_sa_replay = conf_get_str("General", "Shared-SADB") ? 0 :
- iproto->replay_window;
- ssa.sadb_sa_state = SADB_SASTATE_MATURE;
- ssa.sadb_sa_flags = 0;
-#ifdef SADB_X_SAFLAGS_TUNNEL
- if (iproto->encap_mode == IPSEC_ENCAP_TUNNEL ||
- iproto->encap_mode == IPSEC_ENCAP_UDP_ENCAP_TUNNEL ||
- iproto->encap_mode == IPSEC_ENCAP_UDP_ENCAP_TUNNEL_DRAFT)
- ssa.sadb_sa_flags = SADB_X_SAFLAGS_TUNNEL;
-#endif
-
- if (isakmp_sa->flags & SA_FLAG_NAT_T_ENABLE) {
-#if defined (USE_NAT_TRAVERSAL) && defined (SADB_X_EXT_UDPENCAP)
- memset(&udpencap, 0, sizeof udpencap);
- ssa.sadb_sa_flags |= SADB_X_SAFLAGS_UDPENCAP;
- udpencap.sadb_x_udpencap_exttype = SADB_X_EXT_UDPENCAP;
- udpencap.sadb_x_udpencap_len =
- sizeof udpencap / PF_KEY_V2_CHUNK;
- udpencap.sadb_x_udpencap_port = sockaddr_port(dst);
- if (pf_key_v2_msg_add(update, (struct sadb_ext *)&udpencap, 0)
- == -1)
- goto cleanup;
-#elif defined (USE_NAT_TRAVERSAL) && defined (SADB_X_EXT_NAT_T_TYPE)
-#ifndef UDP_ENCAP_ESPINUDP
-#define UDP_ENCAP_ESPINUDP 2
-#endif
- memset(&nat_t_type, 0, sizeof nat_t_type);
- memset(&nat_t_sport, 0, sizeof nat_t_sport);
- memset(&nat_t_dport, 0, sizeof nat_t_dport);
-
- /* type = draft-udp-encap-06 */
- nat_t_type.sadb_x_nat_t_type_len = sizeof nat_t_type / PF_KEY_V2_CHUNK;
- nat_t_type.sadb_x_nat_t_type_exttype = SADB_X_EXT_NAT_T_TYPE;
- nat_t_type.sadb_x_nat_t_type_type = UDP_ENCAP_ESPINUDP;
- if(pf_key_v2_msg_add(update, (struct sadb_ext *)&nat_t_type, 0) == -1)
- goto cleanup;
-
- /* source port */
- nat_t_sport.sadb_x_nat_t_port_len = sizeof nat_t_sport /
- PF_KEY_V2_CHUNK;
- nat_t_sport.sadb_x_nat_t_port_exttype = SADB_X_EXT_NAT_T_SPORT;
- nat_t_sport.sadb_x_nat_t_port_port = sockaddr_port(src);
- if(pf_key_v2_msg_add(update, (struct sadb_ext *)&nat_t_sport, 0) == -1)
- goto cleanup;
-
- /* destination port */
- nat_t_dport.sadb_x_nat_t_port_len = sizeof nat_t_dport /
- PF_KEY_V2_CHUNK;
- nat_t_dport.sadb_x_nat_t_port_exttype = SADB_X_EXT_NAT_T_DPORT;
- nat_t_dport.sadb_x_nat_t_port_port = sockaddr_port(dst);
- if(pf_key_v2_msg_add(update, (struct sadb_ext *)&nat_t_dport, 0) == -1)
- goto cleanup;
-
- /* original address (transport mode checksum missing info) goes here */
-#endif
- }
-
- if (pf_key_v2_msg_add(update, (struct sadb_ext *)&ssa, 0) == -1)
- goto cleanup;
-
- if (sa->seconds || sa->kilobytes) {
- /* Setup the hard limits. */
- life = malloc(sizeof *life);
- if (!life)
- goto cleanup;
- life->sadb_lifetime_len = sizeof *life / PF_KEY_V2_CHUNK;
- life->sadb_lifetime_exttype = SADB_EXT_LIFETIME_HARD;
- life->sadb_lifetime_allocations = 0;
- life->sadb_lifetime_bytes = sa->kilobytes * 1024;
- /*
- * XXX I am not sure which one is best in security respect.
- * Maybe the RFCs actually mandate what a lifetime really is.
- */
-#if 0
- life->sadb_lifetime_addtime = 0;
- life->sadb_lifetime_usetime = sa->seconds;
-#else
- life->sadb_lifetime_addtime = sa->seconds;
- life->sadb_lifetime_usetime = 0;
-#endif
- if (pf_key_v2_msg_add(update, (struct sadb_ext *) life,
- PF_KEY_V2_NODE_MALLOCED) == -1)
- goto cleanup;
- life = 0;
-
- /*
- * Setup the soft limits, we use 90 % of the hard ones.
- * XXX A configurable ratio would be better.
- */
- life = malloc(sizeof *life);
- if (!life)
- goto cleanup;
- life->sadb_lifetime_len = sizeof *life / PF_KEY_V2_CHUNK;
- life->sadb_lifetime_exttype = SADB_EXT_LIFETIME_SOFT;
- life->sadb_lifetime_allocations = 0;
- life->sadb_lifetime_bytes = sa->kilobytes * 1024 * 9 / 10;
- /*
- * XXX I am not sure which one is best in security respect.
- * Maybe the RFCs actually mandate what a lifetime really is.
- */
-#if 0
- life->sadb_lifetime_addtime = 0;
- life->sadb_lifetime_usetime = sa->seconds * 9 / 10;
-#else
- life->sadb_lifetime_addtime = sa->seconds * 9 / 10;
- life->sadb_lifetime_usetime = 0;
-#endif
- if (pf_key_v2_msg_add(update, (struct sadb_ext *) life,
- PF_KEY_V2_NODE_MALLOCED) == -1)
- goto cleanup;
- life = 0;
- }
- /*
- * Setup the ADDRESS extensions.
- */
- len = sizeof *addr + PF_KEY_V2_ROUND(sysdep_sa_len(src));
- addr = calloc(1, len);
- if (!addr)
- goto cleanup;
- addr->sadb_address_exttype = SADB_EXT_ADDRESS_SRC;
- addr->sadb_address_len = len / PF_KEY_V2_CHUNK;
-#ifndef __OpenBSD__
- addr->sadb_address_proto = 0;
- addr->sadb_address_prefixlen = 0;
-#endif
- addr->sadb_address_reserved = 0;
- memcpy(addr + 1, src, sysdep_sa_len(src));
- switch (((struct sockaddr *) (addr + 1))->sa_family) {
- case AF_INET:
- ((struct sockaddr_in *) (addr + 1))->sin_port = 0;
- break;
- case AF_INET6:
- ((struct sockaddr_in6 *) (addr + 1))->sin6_port = 0;
- break;
- }
- if (pf_key_v2_msg_add(update, (struct sadb_ext *) addr,
- PF_KEY_V2_NODE_MALLOCED) == -1)
- goto cleanup;
- addr = 0;
-
- len = sizeof *addr + PF_KEY_V2_ROUND(sysdep_sa_len(dst));
- addr = calloc(1, len);
- if (!addr)
- goto cleanup;
- addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST;
- addr->sadb_address_len = len / PF_KEY_V2_CHUNK;
-#ifndef __OpenBSD__
- addr->sadb_address_proto = 0;
- addr->sadb_address_prefixlen = 0;
-#endif
- addr->sadb_address_reserved = 0;
- memcpy(addr + 1, dst, sysdep_sa_len(dst));
- switch (((struct sockaddr *) (addr + 1))->sa_family) {
- case AF_INET:
- ((struct sockaddr_in *) (addr + 1))->sin_port = 0;
- break;
- case AF_INET6:
- ((struct sockaddr_in6 *) (addr + 1))->sin6_port = 0;
- break;
- }
- if (pf_key_v2_msg_add(update, (struct sadb_ext *) addr,
- PF_KEY_V2_NODE_MALLOCED) == -1)
- goto cleanup;
- addr = 0;
-
-#if 0
- /* XXX I am not sure about what to do here just yet. */
- if (iproto->encap_mode == IPSEC_ENCAP_TUNNEL) {
- len = sizeof *addr + PF_KEY_V2_ROUND(sysdep_sa_len(dst));
- addr = calloc(1, len);
- if (!addr)
- goto cleanup;
- addr->sadb_address_exttype = SADB_EXT_ADDRESS_PROXY;
- addr->sadb_address_len = len / PF_KEY_V2_CHUNK;
-#ifndef __OpenBSD__
- addr->sadb_address_proto = 0;
- addr->sadb_address_prefixlen = 0;
-#endif
- addr->sadb_address_reserved = 0;
- memcpy(addr + 1, dst, sysdep_sa_len(dst));
- switch (((struct sockaddr *) (addr + 1))->sa_family) {
- case AF_INET:
- ((struct sockaddr_in *) (addr + 1))->sin_port = 0;
- break;
- case AF_INET6:
- ((struct sockaddr_in6 *) (addr + 1))->sin6_port = 0;
- break;
- }
- if (pf_key_v2_msg_add(update, (struct sadb_ext *) addr,
- PF_KEY_V2_NODE_MALLOCED) == -1)
- goto cleanup;
- addr = 0;
-#if 0
- msg->em_odst = msg->em_dst;
- msg->em_osrc = msg->em_src;
-#endif
- }
-#endif
-
- if (proto->proto != IPSEC_PROTO_IPCOMP) {
- /* Setup the KEY extensions. */
- if (hashlen) {
- len = sizeof *key + PF_KEY_V2_ROUND(hashlen);
- key = malloc(len);
- if (!key)
- goto cleanup;
- key->sadb_key_exttype = SADB_EXT_KEY_AUTH;
- key->sadb_key_len = len / PF_KEY_V2_CHUNK;
- key->sadb_key_bits = hashlen * 8;
- key->sadb_key_reserved = 0;
- memcpy(key + 1,
- iproto->keymat[incoming] +
- (proto->proto ==
- IPSEC_PROTO_IPSEC_ESP ? keylen : 0),
- hashlen);
- if (pf_key_v2_msg_add(update, (struct sadb_ext *) key,
- PF_KEY_V2_NODE_MALLOCED) == -1)
- goto cleanup;
- key = 0;
- }
- if (keylen) {
- len = sizeof *key + PF_KEY_V2_ROUND(keylen);
- key = malloc(len);
- if (!key)
- goto cleanup;
- key->sadb_key_exttype = SADB_EXT_KEY_ENCRYPT;
- key->sadb_key_len = len / PF_KEY_V2_CHUNK;
- key->sadb_key_bits = keylen * 8;
- key->sadb_key_reserved = 0;
- memcpy(key + 1, iproto->keymat[incoming], keylen);
- if (pf_key_v2_msg_add(update, (struct sadb_ext *) key,
- PF_KEY_V2_NODE_MALLOCED) == -1)
- goto cleanup;
- key = 0;
- }
- }
-#ifndef KAME
- /* Setup identity extensions. */
- if (isakmp_sa->id_i) {
- pp = pf_key_v2_convert_id(isakmp_sa->id_i, isakmp_sa->id_i_len,
- &len, &idtype);
- if (!pp)
- goto nosid;
-
- sid = calloc(PF_KEY_V2_ROUND(len + 1) + sizeof *sid,
- sizeof(u_int8_t));
- if (!sid) {
- free(pp);
- goto cleanup;
- }
- sid->sadb_ident_type = idtype;
- sid->sadb_ident_len = ((sizeof *sid) / PF_KEY_V2_CHUNK) +
- PF_KEY_V2_ROUND(len + 1) / PF_KEY_V2_CHUNK;
- if ((isakmp_sa->initiator && !incoming) ||
- (!isakmp_sa->initiator && incoming))
- sid->sadb_ident_exttype = SADB_EXT_IDENTITY_SRC;
- else
- sid->sadb_ident_exttype = SADB_EXT_IDENTITY_DST;
-
- memcpy(sid + 1, pp, len);
- free(pp);
-
- if (pf_key_v2_msg_add(update, (struct sadb_ext *) sid,
- PF_KEY_V2_NODE_MALLOCED) == -1)
- goto cleanup;
- sid = 0;
-
-nosid:
- if (sid)
- free(sid);
- sid = 0;
- }
- if (isakmp_sa->id_r) {
- pp = pf_key_v2_convert_id(isakmp_sa->id_r, isakmp_sa->id_r_len,
- &len, &idtype);
- if (!pp)
- goto nodid;
-
- sid = calloc(PF_KEY_V2_ROUND(len + 1) + sizeof *sid,
- sizeof(u_int8_t));
- if (!sid) {
- free(pp);
- goto cleanup;
- }
- sid->sadb_ident_type = idtype;
- sid->sadb_ident_len = ((sizeof *sid) / PF_KEY_V2_CHUNK) +
- PF_KEY_V2_ROUND(len + 1) / PF_KEY_V2_CHUNK;
- if ((isakmp_sa->initiator && !incoming) ||
- (!isakmp_sa->initiator && incoming))
- sid->sadb_ident_exttype = SADB_EXT_IDENTITY_DST;
- else
- sid->sadb_ident_exttype = SADB_EXT_IDENTITY_SRC;
-
- memcpy(sid + 1, pp, len);
- free(pp);
-
- if (pf_key_v2_msg_add(update, (struct sadb_ext *) sid,
- PF_KEY_V2_NODE_MALLOCED) == -1)
- goto cleanup;
- sid = 0;
-
-nodid:
- if (sid)
- free(sid);
- sid = 0;
- }
-#endif /* KAME */
-
-#ifdef SADB_X_CREDTYPE_NONE
- /*
- * Send received credentials to the kernel. We don't bother with
- * our credentials, since the process either knows them (if it
- * specified them with setsockopt()), or has no business looking at
- * them (e.g., system wide certs).
- */
- if (isakmp_sa->recv_cert) {
- switch (isakmp_sa->recv_certtype) {
- case ISAKMP_CERTENC_NONE:
- /* Nothing to be done here. */
- break;
-
-#if defined (USE_KEYNOTE) && defined (SADB_X_EXT_REMOTE_CREDENTIALS)
- case ISAKMP_CERTENC_KEYNOTE:
- len = strlen(isakmp_sa->recv_cert);
- cred = calloc(PF_KEY_V2_ROUND(len) + sizeof *cred,
- sizeof(u_int8_t));
- if (!cred)
- goto cleanup;
-
- cred->sadb_x_cred_len =
- ((sizeof *cred) / PF_KEY_V2_CHUNK) +
- PF_KEY_V2_ROUND(len) / PF_KEY_V2_CHUNK;
- cred->sadb_x_cred_exttype =
- SADB_X_EXT_REMOTE_CREDENTIALS;
- cred->sadb_x_cred_type = SADB_X_CREDTYPE_KEYNOTE;
- memcpy(cred + 1, isakmp_sa->recv_cert, len);
-
- if (pf_key_v2_msg_add(update, (struct sadb_ext *) cred,
- PF_KEY_V2_NODE_MALLOCED) == -1)
- goto cleanup;
- break;
-#endif /* USE_KEYNOTE */
-
-#if defined (USE_X509) && defined (SADB_X_EXT_REMOTE_CREDENTIALS)
- case ISAKMP_CERTENC_X509_SIG:
- {
- u_int8_t *data;
- u_int32_t datalen;
- struct cert_handler *handler;
-
- /* We do it this way to avoid weird includes.*/
- handler = cert_get(ISAKMP_CERTENC_X509_SIG);
- if (!handler)
- break;
- handler->cert_serialize(isakmp_sa->recv_cert,
- &data, &datalen);
- if (!data)
- break;
-
- len = datalen;
- cred =
- calloc(PF_KEY_V2_ROUND(len) + sizeof *cred,
- sizeof(u_int8_t));
- if (!cred) {
- free(data);
- goto cleanup;
- }
- cred->sadb_x_cred_len =
- ((sizeof *cred) / PF_KEY_V2_CHUNK) +
- PF_KEY_V2_ROUND(len) / PF_KEY_V2_CHUNK;
- cred->sadb_x_cred_exttype =
- SADB_X_EXT_REMOTE_CREDENTIALS;
- cred->sadb_x_cred_type = SADB_X_CREDTYPE_X509;
- memcpy(cred + 1, data, len);
- free(data);
-
- if (pf_key_v2_msg_add(update,
- (struct sadb_ext *) cred,
- PF_KEY_V2_NODE_MALLOCED) == -1)
- goto cleanup;
- }
- break;
-#endif /* USE_X509 */
- }
- }
-#endif /* SADB_X_CREDTYPE_NONE */
-
-#ifdef SADB_X_AUTHTYPE_NONE
- /*
- * Tell the kernel what the peer used to authenticate, unless it was a
- * passphrase.
- */
- if (isakmp_sa->recv_key) {
- u_int8_t *data;
-
- /*
- * If it's a private key, we shouldn't pass it to the kernel
- * for processes to see; successful authentication of Phase 1
- * implies that the process already knew the passphrase. On
- * the other hand, we don't want to reveal to processes any
- * system-wide passphrases used for authentication with remote
- * systems. Same reason we don't send up the key (private or
- * passphrase) we used to authenticate with the peer.
- */
- if (isakmp_sa->recv_keytype == ISAKMP_KEY_PASSPHRASE)
- goto doneauth;
-
- key_serialize(isakmp_sa->recv_keytype, ISAKMP_KEYTYPE_PUBLIC,
- isakmp_sa->recv_key, &data, &len);
- if (!data)
- goto cleanup;
-
- cred = calloc(PF_KEY_V2_ROUND(len) + sizeof *cred,
- sizeof(u_int8_t));
- if (!cred) {
- free(data);
- goto cleanup;
- }
- cred->sadb_x_cred_len = ((sizeof *cred) / PF_KEY_V2_CHUNK) +
- PF_KEY_V2_ROUND(len) / PF_KEY_V2_CHUNK;
- cred->sadb_x_cred_exttype = SADB_X_EXT_REMOTE_AUTH;
- memcpy(cred + 1, data, len);
- free(data);
-
- switch (isakmp_sa->recv_keytype) {
- case ISAKMP_KEY_RSA:
- cred->sadb_x_cred_type = SADB_X_AUTHTYPE_RSA;
- break;
-
- default:
- log_print("pf_key_v2_set_spi: "
- "unknown received key type %d",
- isakmp_sa->recv_keytype);
- free(cred);
- goto cleanup;
- }
-
- if (pf_key_v2_msg_add(update, (struct sadb_ext *) cred,
- PF_KEY_V2_NODE_MALLOCED) == -1)
- goto cleanup;
- }
-doneauth:
-#endif /* SADB_X_AUTHTYPE_NONE */
-
-#ifdef SADB_X_EXT_FLOW_TYPE
- /* Setup the flow type extension. */
- bzero(&flowtype, sizeof flowtype);
- flowtype.sadb_protocol_exttype = SADB_X_EXT_FLOW_TYPE;
- flowtype.sadb_protocol_len = sizeof flowtype / PF_KEY_V2_CHUNK;
- flowtype.sadb_protocol_direction = incoming ?
- IPSP_DIRECTION_IN : IPSP_DIRECTION_OUT;
-
- if (pf_key_v2_msg_add(update, (struct sadb_ext *)&flowtype, 0) == -1)
- goto cleanup;
-
- bzero(&tprotocol, sizeof tprotocol);
- tprotocol.sadb_protocol_exttype = SADB_X_EXT_PROTOCOL;
- tprotocol.sadb_protocol_len = sizeof tprotocol / PF_KEY_V2_CHUNK;
- tprotocol.sadb_protocol_proto = isa->tproto;
-
- if (pf_key_v2_msg_add(update, (struct sadb_ext *)&tprotocol,
- 0) == -1)
- goto cleanup;
-
- len = sizeof *addr + PF_KEY_V2_ROUND(sysdep_sa_len(isa->src_net));
- addr = calloc(1, len);
- if (!addr)
- goto cleanup;
- addr->sadb_address_exttype = incoming ?
- SADB_X_EXT_DST_FLOW : SADB_X_EXT_SRC_FLOW;
- addr->sadb_address_len = len / PF_KEY_V2_CHUNK;
- addr->sadb_address_reserved = 0;
- pf_key_v2_setup_sockaddr(addr + 1, isa->src_net, 0, isa->sport, 0);
- if (pf_key_v2_msg_add(update, (struct sadb_ext *) addr,
- PF_KEY_V2_NODE_MALLOCED) == -1)
- goto cleanup;
- addr = 0;
-
- addr = calloc(1, len);
- if (!addr)
- goto cleanup;
- addr->sadb_address_exttype =
- incoming ? SADB_X_EXT_DST_MASK : SADB_X_EXT_SRC_MASK;
- addr->sadb_address_len = len / PF_KEY_V2_CHUNK;
- addr->sadb_address_reserved = 0;
- pf_key_v2_setup_sockaddr(addr + 1, isa->src_mask, 0,
- isa->sport ? 0xffff : 0, 0);
- if (pf_key_v2_msg_add(update, (struct sadb_ext *) addr,
- PF_KEY_V2_NODE_MALLOCED) == -1)
- goto cleanup;
- addr = 0;
-
- addr = calloc(1, len);
- if (!addr)
- goto cleanup;
- addr->sadb_address_exttype = incoming ?
- SADB_X_EXT_SRC_FLOW : SADB_X_EXT_DST_FLOW;
- addr->sadb_address_len = len / PF_KEY_V2_CHUNK;
- addr->sadb_address_reserved = 0;
- pf_key_v2_setup_sockaddr(addr + 1, isa->dst_net, 0, isa->dport, 0);
- if (pf_key_v2_msg_add(update, (struct sadb_ext *) addr,
- PF_KEY_V2_NODE_MALLOCED) == -1)
- goto cleanup;
- addr = 0;
-
- addr = calloc(1, len);
- if (!addr)
- goto cleanup;
- addr->sadb_address_exttype =
- incoming ? SADB_X_EXT_SRC_MASK : SADB_X_EXT_DST_MASK;
- addr->sadb_address_len = len / PF_KEY_V2_CHUNK;
- addr->sadb_address_reserved = 0;
- pf_key_v2_setup_sockaddr(addr + 1, isa->dst_mask, 0,
- isa->dport ? 0xffff : 0, 0);
- if (pf_key_v2_msg_add(update, (struct sadb_ext *) addr,
- PF_KEY_V2_NODE_MALLOCED) == -1)
- goto cleanup;
- addr = 0;
-#endif /* SADB_X_EXT_FLOW_TYPE */
-
- /* XXX Here can sensitivity extensions be setup. */
-
-#ifdef USE_DEBUG
- if (sockaddr2text(dst, &addr_str, 0))
- addr_str = 0;
-
- LOG_DBG((LOG_SYSDEP, 10, "pf_key_v2_set_spi: "
- "satype %d dst %s SPI 0x%x", msg.sadb_msg_satype,
- addr_str ? addr_str : "unknown", ntohl(ssa.sadb_sa_spi)));
-
- if (addr_str)
- free(addr_str);
-#endif /* USE_DEBUG */
-
- /*
- * Although PF_KEY knows about expirations, it is unreliable per the
- * specs thus we need to do them inside isakmpd as well.
- */
- if (sa->seconds)
- if (sa_setup_expirations(sa))
- goto cleanup;
-
- ret = pf_key_v2_call(update);
- pf_key_v2_msg_free(update);
- update = 0;
- if (!ret)
- goto cleanup;
- err = ((struct sadb_msg *)TAILQ_FIRST(ret)->seg)->sadb_msg_errno;
- pf_key_v2_msg_free(ret);
- ret = 0;
-
- /*
- * If we are doing an addition into an SADB shared with our peer,
- * errors here are to be expected as the peer will already have
- * created the SA, and can thus be ignored.
- */
- if (err && !(msg.sadb_msg_type == SADB_ADD &&
- conf_get_str("General", "Shared-SADB"))) {
- log_print("pf_key_v2_set_spi: %s: %s",
- msg.sadb_msg_type == SADB_ADD ? "ADD" : "UPDATE",
- strerror(err));
- goto cleanup;
- }
- LOG_DBG((LOG_SYSDEP, 50, "pf_key_v2_set_spi: done"));
-
- return 0;
-
-cleanup:
- if (sid)
- free(sid);
- if (addr)
- free(addr);
- if (life)
- free(life);
- if (key)
- free(key);
- if (update)
- pf_key_v2_msg_free(update);
- if (ret)
- pf_key_v2_msg_free(ret);
- return -1;
-}
-
-static __inline__ int
-pf_key_v2_mask_to_bits(u_int32_t mask)
-{
- u_int32_t hmask = ntohl(mask);
-
- return (33 - ffs(~hmask + 1)) % 33;
-}
-
-static int
-pf_key_v2_mask6_to_bits(u_int8_t * mask)
-{
- int n;
-
- bit_ffc(mask, 128, &n);
- return n == -1 ? 128 : n;
-}
-
-/*
- * Enable/disable a flow.
- * XXX Assumes OpenBSD {ADD,DEL}FLOW extensions.
- * Should probably be moved to sysdep.c
- */
-static int
-pf_key_v2_flow(struct sockaddr *laddr, struct sockaddr *lmask,
- struct sockaddr *raddr, struct sockaddr *rmask,
- u_int8_t tproto, u_int16_t sport, u_int16_t dport,
- u_int8_t *spi, u_int8_t proto, struct sockaddr *dst,
- struct sockaddr *src, int delete, int ingress,
- u_int8_t srcid_type, u_int8_t *srcid, int srcid_len,
- u_int8_t dstid_type, u_int8_t *dstid, int dstid_len,
- struct ipsec_proto *iproto)
-{
-#ifdef USE_DEBUG
- char *laddr_str, *lmask_str, *raddr_str, *rmask_str;
-#endif
-
-#if defined (SADB_X_ADDFLOW) && defined (SADB_X_DELFLOW)
- struct sadb_msg msg;
-#if defined (SADB_X_EXT_FLOW_TYPE)
- struct sadb_protocol flowtype;
- struct sadb_ident *sid = 0;
-#else
- struct sadb_sa ssa;
-#endif
- struct sadb_address *addr = 0;
- struct sadb_protocol tprotocol;
- struct pf_key_v2_msg *flow = 0, *ret = 0;
- size_t len;
- int err;
-
-#if !defined (SADB_X_SAFLAGS_INGRESS_FLOW) && !defined (SADB_X_EXT_FLOW_TYPE)
- if (ingress)
- return 0;
-#endif
-
- msg.sadb_msg_type = delete ? SADB_X_DELFLOW : SADB_X_ADDFLOW;
- switch (proto) {
- case IPSEC_PROTO_IPSEC_ESP:
- msg.sadb_msg_satype = SADB_SATYPE_ESP;
- break;
- case IPSEC_PROTO_IPSEC_AH:
- msg.sadb_msg_satype = SADB_SATYPE_AH;
- break;
- case IPSEC_PROTO_IPCOMP:
- msg.sadb_msg_satype = SADB_X_SATYPE_IPCOMP;
- break;
- default:
- log_print("pf_key_v2_flow: invalid proto %d", proto);
- goto cleanup;
- }
- msg.sadb_msg_seq = 0;
- flow = pf_key_v2_msg_new(&msg, 0);
- if (!flow)
- goto cleanup;
-
-#if defined (SADB_X_EXT_FLOW_TYPE)
- if (!delete) {
- /* Setup the source ID, if provided. */
- if (srcid) {
- sid = calloc(
- PF_KEY_V2_ROUND(srcid_len + 1) + sizeof *sid,
- sizeof(u_int8_t));
- if (!sid)
- goto cleanup;
-
- sid->sadb_ident_len = ((sizeof *sid) / PF_KEY_V2_CHUNK)
- + PF_KEY_V2_ROUND(srcid_len + 1) / PF_KEY_V2_CHUNK;
- sid->sadb_ident_exttype = SADB_EXT_IDENTITY_SRC;
- sid->sadb_ident_type = srcid_type;
-
- memcpy(sid + 1, srcid, srcid_len);
-
- if (pf_key_v2_msg_add(flow, (struct sadb_ext *) sid,
- PF_KEY_V2_NODE_MALLOCED) == -1)
- goto cleanup;
-
- sid = 0;
- }
- /* Setup the destination ID, if provided. */
- if (dstid) {
- sid = calloc(
- PF_KEY_V2_ROUND(dstid_len + 1) + sizeof *sid,
- sizeof(u_int8_t));
- if (!sid)
- goto cleanup;
-
- sid->sadb_ident_len = ((sizeof *sid) / PF_KEY_V2_CHUNK)
- + PF_KEY_V2_ROUND(dstid_len + 1) / PF_KEY_V2_CHUNK;
- sid->sadb_ident_exttype = SADB_EXT_IDENTITY_DST;
- sid->sadb_ident_type = dstid_type;
-
- memcpy(sid + 1, dstid, dstid_len);
-
- if (pf_key_v2_msg_add(flow, (struct sadb_ext *) sid,
- PF_KEY_V2_NODE_MALLOCED) == -1)
- goto cleanup;
-
- sid = 0;
- }
- }
- /* Setup the flow type extension. */
- bzero(&flowtype, sizeof flowtype);
- flowtype.sadb_protocol_exttype = SADB_X_EXT_FLOW_TYPE;
- flowtype.sadb_protocol_len = sizeof flowtype / PF_KEY_V2_CHUNK;
- flowtype.sadb_protocol_direction =
- ingress ? IPSP_DIRECTION_IN : IPSP_DIRECTION_OUT;
- flowtype.sadb_protocol_proto =
- ingress ? SADB_X_FLOW_TYPE_USE : SADB_X_FLOW_TYPE_REQUIRE;
-
- if (pf_key_v2_msg_add(flow, (struct sadb_ext *)&flowtype, 0) == -1)
- goto cleanup;
-#else /* SADB_X_EXT_FLOW_TYPE */
- /* Setup the SA extension. */
- ssa.sadb_sa_exttype = SADB_EXT_SA;
- ssa.sadb_sa_len = sizeof ssa / PF_KEY_V2_CHUNK;
- memcpy(&ssa.sadb_sa_spi, spi, sizeof ssa.sadb_sa_spi);
- ssa.sadb_sa_replay = 0;
- ssa.sadb_sa_state = 0;
- ssa.sadb_sa_auth = 0;
- ssa.sadb_sa_encrypt = 0;
- ssa.sadb_sa_flags = 0;
-#if defined (SADB_X_SAFLAGS_INGRESS_FLOW)
- if (ingress)
- ssa.sadb_sa_flags |= SADB_X_SAFLAGS_INGRESS_FLOW;
-#endif
-#if defined (SADB_X_SAFLAGS_REPLACEFLOW)
- if (!delete && !ingress)
- ssa.sadb_sa_flags |= SADB_X_SAFLAGS_REPLACEFLOW;
-#endif
-
- if (pf_key_v2_msg_add(flow, (struct sadb_ext *)&ssa, 0) == -1)
- goto cleanup;
-#endif /* SADB_X_EXT_FLOW_TYPE */
-
- /*
- * Setup the ADDRESS extensions.
- */
- len = sizeof *addr + PF_KEY_V2_ROUND(sysdep_sa_len(src));
-#if !defined (SADB_X_EXT_FLOW_TYPE)
- if (!delete || ingress)
-#else
- if (!delete)
-#endif /* SADB_X_EXT_FLOW_TYPE */
- {
- addr = calloc(1, len);
- if (!addr)
- goto cleanup;
- addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST;
- addr->sadb_address_len = len / PF_KEY_V2_CHUNK;
- addr->sadb_address_reserved = 0;
-#if defined (SADB_X_EXT_FLOW_TYPE)
- pf_key_v2_setup_sockaddr(addr + 1, src, dst, 0, ingress);
-#else
- pf_key_v2_setup_sockaddr(addr + 1, dst, 0, 0, 0);
-#endif
- if (pf_key_v2_msg_add(flow, (struct sadb_ext *) addr,
- PF_KEY_V2_NODE_MALLOCED) == -1)
- goto cleanup;
- addr = 0;
- }
- len = sizeof *addr + PF_KEY_V2_ROUND(sysdep_sa_len(laddr));
- addr = calloc(1, len);
- if (!addr)
- goto cleanup;
- addr->sadb_address_exttype = SADB_X_EXT_SRC_FLOW;
- addr->sadb_address_len = len / PF_KEY_V2_CHUNK;
- addr->sadb_address_reserved = 0;
- pf_key_v2_setup_sockaddr(addr + 1, laddr, 0, sport, 0);
- if (pf_key_v2_msg_add(flow, (struct sadb_ext *) addr,
- PF_KEY_V2_NODE_MALLOCED) == -1)
- goto cleanup;
- addr = 0;
-
- addr = calloc(1, len);
- if (!addr)
- goto cleanup;
- addr->sadb_address_exttype = SADB_X_EXT_SRC_MASK;
- addr->sadb_address_len = len / PF_KEY_V2_CHUNK;
- addr->sadb_address_reserved = 0;
- pf_key_v2_setup_sockaddr(addr + 1, lmask, 0, sport ? 0xffff : 0, 0);
- if (pf_key_v2_msg_add(flow, (struct sadb_ext *) addr,
- PF_KEY_V2_NODE_MALLOCED) == -1)
- goto cleanup;
- addr = 0;
-
- addr = calloc(1, len);
- if (!addr)
- goto cleanup;
- addr->sadb_address_exttype = SADB_X_EXT_DST_FLOW;
- addr->sadb_address_len = len / PF_KEY_V2_CHUNK;
- addr->sadb_address_reserved = 0;
- pf_key_v2_setup_sockaddr(addr + 1, raddr, 0, dport, 0);
- if (pf_key_v2_msg_add(flow, (struct sadb_ext *) addr,
- PF_KEY_V2_NODE_MALLOCED) == -1)
- goto cleanup;
- addr = 0;
-
- addr = calloc(1, len);
- if (!addr)
- goto cleanup;
- addr->sadb_address_exttype = SADB_X_EXT_DST_MASK;
- addr->sadb_address_len = len / PF_KEY_V2_CHUNK;
- addr->sadb_address_reserved = 0;
- pf_key_v2_setup_sockaddr(addr + 1, rmask, 0, dport ? 0xffff : 0, 0);
- if (pf_key_v2_msg_add(flow, (struct sadb_ext *) addr,
- PF_KEY_V2_NODE_MALLOCED) == -1)
- goto cleanup;
- addr = 0;
-
- /* Setup the protocol extension. */
- bzero(&tprotocol, sizeof tprotocol);
- tprotocol.sadb_protocol_exttype = SADB_X_EXT_PROTOCOL;
- tprotocol.sadb_protocol_len = sizeof tprotocol / PF_KEY_V2_CHUNK;
- tprotocol.sadb_protocol_proto = tproto;
-
- if (pf_key_v2_msg_add(flow, (struct sadb_ext *)&tprotocol, 0) == -1)
- goto cleanup;
-
-#ifdef USE_DEBUG
- if (sockaddr2text(laddr, &laddr_str, 0))
- laddr_str = 0;
- if (sockaddr2text(lmask, &lmask_str, 0))
- lmask_str = 0;
- if (sockaddr2text(raddr, &raddr_str, 0))
- raddr_str = 0;
- if (sockaddr2text(rmask, &rmask_str, 0))
- rmask_str = 0;
-
- LOG_DBG((LOG_SYSDEP, 50,
- "pf_key_v2_flow: src %s %s dst %s %s proto %u sport %u dport %u",
- laddr_str ? laddr_str : "<??\?>", lmask_str ? lmask_str : "<??\?>",
- raddr_str ? raddr_str : "<??\?>", rmask_str ? rmask_str : "<??\?>",
- tproto, ntohs(sport), ntohs(dport)));
-
- if (laddr_str)
- free(laddr_str);
- if (lmask_str)
- free(lmask_str);
- if (raddr_str)
- free(raddr_str);
- if (rmask_str)
- free(rmask_str);
-#endif /* USE_DEBUG */
-
- ret = pf_key_v2_call(flow);
- pf_key_v2_msg_free(flow);
- flow = 0;
- if (!ret)
- goto cleanup;
- err = ((struct sadb_msg *)TAILQ_FIRST(ret)->seg)->sadb_msg_errno;
- if (err) {
- if (err == ESRCH) /* These are common and usually
- * harmless. */
- LOG_DBG((LOG_SYSDEP, 10, "pf_key_v2_flow: %sFLOW: %s",
- delete ? "DEL" : "ADD", strerror(err)));
- else
- log_print("pf_key_v2_flow: %sFLOW: %s",
- delete ? "DEL" : "ADD", strerror(err));
- goto cleanup;
- }
- pf_key_v2_msg_free(ret);
-
- LOG_DBG((LOG_MISC, 50, "pf_key_v2_flow: %sFLOW: done",
- delete ? "DEL" : "ADD"));
-
- return 0;
-
-cleanup:
-#if defined (SADB_X_EXT_FLOW_TYPE)
- if (sid)
- free(sid);
-#endif /* SADB_X_EXT_FLOW_TYPE */
- if (addr)
- free(addr);
- if (flow)
- pf_key_v2_msg_free(flow);
- if (ret)
- pf_key_v2_msg_free(ret);
- return -1;
-
-#elif defined (SADB_X_SPDUPDATE) && defined (SADB_X_SPDDELETE)
- struct sadb_msg msg;
- struct sadb_x_policy *policy = 0;
- struct sadb_x_ipsecrequest *ipsecrequest;
- struct sadb_x_sa2 ssa2;
- struct sadb_address *addr = 0;
- struct sockaddr *saddr;
- struct pf_key_v2_msg *flow = 0, *ret = 0;
- u_int8_t *policy_buf;
- size_t len;
- int err;
- struct sockaddr_in *ip4_sa;
- struct sockaddr_in6 *ip6_sa;
-
- msg.sadb_msg_type = delete ? SADB_X_SPDDELETE : SADB_X_SPDUPDATE;
- msg.sadb_msg_satype = SADB_SATYPE_UNSPEC;
- msg.sadb_msg_seq = 0;
- flow = pf_key_v2_msg_new(&msg, 0);
- if (!flow)
- goto cleanup;
-
- memset(&ssa2, 0, sizeof ssa2);
- ssa2.sadb_x_sa2_exttype = SADB_X_EXT_SA2;
- ssa2.sadb_x_sa2_len = sizeof ssa2 / PF_KEY_V2_CHUNK;
- ssa2.sadb_x_sa2_mode = 0;
- if (pf_key_v2_msg_add(flow, (struct sadb_ext *)&ssa2, 0) == -1)
- goto cleanup;
-
- /*
- * Setup the ADDRESS extensions.
- */
- len = sizeof *addr + PF_KEY_V2_ROUND(sysdep_sa_len(src));
- addr = calloc(1, len);
- if (!addr)
- goto cleanup;
- addr->sadb_address_exttype = SADB_EXT_ADDRESS_SRC;
- addr->sadb_address_len = len / PF_KEY_V2_CHUNK;
-#ifdef LINUX_IPSEC
- addr->sadb_address_proto = tproto;
-#else
- addr->sadb_address_proto = IPSEC_ULPROTO_ANY;
-#endif
- addr->sadb_address_reserved = 0;
-#ifdef LINUX_IPSEC
- pf_key_v2_setup_sockaddr(addr + 1, laddr, 0, sport, 0);
-#else
- pf_key_v2_setup_sockaddr(addr + 1, laddr, 0, IPSEC_PORT_ANY, 0);
-#endif
- switch (laddr->sa_family) {
- case AF_INET:
- ip4_sa = (struct sockaddr_in *) lmask;
- addr->sadb_address_prefixlen
- = pf_key_v2_mask_to_bits(ip4_sa->sin_addr.s_addr);
- break;
- case AF_INET6:
- ip6_sa = (struct sockaddr_in6 *) lmask;
- addr->sadb_address_prefixlen =
- pf_key_v2_mask6_to_bits(&ip6_sa->sin6_addr.s6_addr[0]);
- break;
- }
- if (pf_key_v2_msg_add(flow, (struct sadb_ext *) addr,
- PF_KEY_V2_NODE_MALLOCED) == -1)
- goto cleanup;
- addr = 0;
-
- len = sizeof *addr + PF_KEY_V2_ROUND(sysdep_sa_len(raddr));
- addr = calloc(1, len);
- if (!addr)
- goto cleanup;
- addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST;
- addr->sadb_address_len = len / PF_KEY_V2_CHUNK;
-#ifdef LINUX_IPSEC
- addr->sadb_address_proto = tproto;
-#else
- addr->sadb_address_proto = IPSEC_ULPROTO_ANY;
-#endif
- addr->sadb_address_reserved = 0;
-#ifdef LINUX_IPSEC
- pf_key_v2_setup_sockaddr(addr + 1, raddr, 0, dport, 0);
-#else
- pf_key_v2_setup_sockaddr(addr + 1, raddr, 0, IPSEC_PORT_ANY, 0);
-#endif
- switch (raddr->sa_family) {
- case AF_INET:
- ip4_sa = (struct sockaddr_in *) rmask;
- addr->sadb_address_prefixlen
- = pf_key_v2_mask_to_bits(ip4_sa->sin_addr.s_addr);
- break;
- case AF_INET6:
- ip6_sa = (struct sockaddr_in6 *) rmask;
- addr->sadb_address_prefixlen =
- pf_key_v2_mask6_to_bits(&ip6_sa->sin6_addr.s6_addr[0]);
- break;
- }
- if (pf_key_v2_msg_add(flow, (struct sadb_ext *) addr,
- PF_KEY_V2_NODE_MALLOCED) == -1)
- goto cleanup;
- addr = 0;
-
- /* Setup the POLICY extension. */
- len = sizeof *policy + sizeof *ipsecrequest +
- 2 * PF_KEY_V2_ROUND(sysdep_sa_len(src));
- policy_buf = (u_int8_t *) calloc(1, len);
- if (!policy_buf) {
- log_error("pf_key_v2_flow: calloc %lu failed",
- (unsigned long) len);
- goto cleanup;
- }
- policy = (struct sadb_x_policy *) policy_buf;
- policy->sadb_x_policy_exttype = SADB_X_EXT_POLICY;
- policy->sadb_x_policy_len = len / PF_KEY_V2_CHUNK;
- policy->sadb_x_policy_type = IPSEC_POLICY_IPSEC;
- if (ingress)
- policy->sadb_x_policy_dir = IPSEC_DIR_INBOUND;
- else
- policy->sadb_x_policy_dir = IPSEC_DIR_OUTBOUND;
- policy->sadb_x_policy_reserved = 0;
-
- /* Setup the IPSECREQUEST extension part. */
- ipsecrequest = (struct sadb_x_ipsecrequest *) (policy + 1);
- ipsecrequest->sadb_x_ipsecrequest_len = len - sizeof *policy;
- switch (proto) {
- case IPSEC_PROTO_IPSEC_ESP:
- ipsecrequest->sadb_x_ipsecrequest_proto = IPPROTO_ESP;
- break;
- case IPSEC_PROTO_IPSEC_AH:
- ipsecrequest->sadb_x_ipsecrequest_proto = IPPROTO_AH;
- break;
- default:
- log_print("pf_key_v2_flow: invalid proto %d", proto);
- goto cleanup;
- }
-#if defined (LINUX_IPSEC)
- if (iproto->encap_mode == IPSEC_ENCAP_TUNNEL)
- ipsecrequest->sadb_x_ipsecrequest_mode = IPSEC_MODE_TUNNEL;
- else
- ipsecrequest->sadb_x_ipsecrequest_mode = IPSEC_MODE_TRANSPORT;
-#else
- ipsecrequest->sadb_x_ipsecrequest_mode = IPSEC_MODE_TUNNEL; /* XXX */
-#endif
- ipsecrequest->sadb_x_ipsecrequest_level
- = ingress ? IPSEC_LEVEL_USE : IPSEC_LEVEL_REQUIRE;
- ipsecrequest->sadb_x_ipsecrequest_reqid = 0; /* XXX */
-
- /* Add source and destination addresses. */
- saddr = (struct sockaddr *)(ipsecrequest + 1);
- pf_key_v2_setup_sockaddr(saddr, src, 0, 0, 0);
- switch (src->sa_family) {
- case AF_INET:
- saddr = (struct sockaddr *)((struct sockaddr_in *)saddr + 1);
- break;
- case AF_INET6:
- saddr = (struct sockaddr *)((struct sockaddr_in6 *)saddr + 1);
- break;
- }
- pf_key_v2_setup_sockaddr(saddr, dst, 0, 0, 0);
- if (pf_key_v2_msg_add(flow, (struct sadb_ext *)policy,
- PF_KEY_V2_NODE_MALLOCED) == -1)
- goto cleanup;
- policy = 0;
-
-#ifdef USE_DEBUG
- if (sockaddr2text(laddr, &laddr_str, 0))
- laddr_str = 0;
- if (sockaddr2text(lmask, &lmask_str, 0))
- lmask_str = 0;
- if (sockaddr2text(raddr, &raddr_str, 0))
- raddr_str = 0;
- if (sockaddr2text(rmask, &rmask_str, 0))
- rmask_str = 0;
-
- LOG_DBG((LOG_SYSDEP, 50, "pf_key_v2_flow: src %s %s dst %s %s",
- laddr_str ? laddr_str : "<??\?>", lmask_str ? lmask_str : "<??\?>",
- raddr_str ? raddr_str : "<??\?>",
- rmask_str ? rmask_str : "<??\?>"));
-
- if (laddr_str)
- free(laddr_str);
- if (lmask_str)
- free(lmask_str);
- if (raddr_str)
- free(raddr_str);
- if (rmask_str)
- free(rmask_str);
-#endif
-
- ret = pf_key_v2_call(flow);
- pf_key_v2_msg_free(flow);
- flow = 0;
- if (!ret)
- goto cleanup;
- err = ((struct sadb_msg *)TAILQ_FIRST(ret)->seg)->sadb_msg_errno;
- if (!delete && err == EEXIST) {
- LOG_DBG((LOG_SYSDEP, 50, "pf_key_v2_flow: "
- "SPDADD returns EEXIST"));
- } else if (err) {
- log_print("pf_key_v2_flow: SPD%s: %s",
- delete ? "DELETE" : "ADD", strerror(err));
- goto cleanup;
- }
- pf_key_v2_msg_free(ret);
-
- LOG_DBG((LOG_SYSDEP, 50, "pf_key_v2_flow: SPD%s: done",
- delete ? "DELETE" : "ADD"));
-
- return 0;
-
-cleanup:
- if (addr)
- free(addr);
- if (policy)
- free(policy);
- if (flow)
- pf_key_v2_msg_free(flow);
- if (ret)
- pf_key_v2_msg_free(ret);
- return -1;
-
-#else
- log_print("pf_key_v2_flow: not supported in pure PF_KEYv2");
- return -1;
-#endif
-}
-
-#ifndef KAME
-static u_int8_t *
-pf_key_v2_convert_id(u_int8_t * id, int idlen, size_t * reslen, int *idtype)
-{
- u_int8_t *addr, *res = 0;
- char addrbuf[ADDRESS_MAX + 5];
-
- switch (id[0]) {
- case IPSEC_ID_FQDN:
- res = calloc(idlen - ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ,
- sizeof(u_int8_t));
- if (!res)
- return 0;
-
- *reslen = idlen - ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ;
- memcpy(res, id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ, *reslen);
- *idtype = SADB_IDENTTYPE_FQDN;
- LOG_DBG((LOG_SYSDEP, 40, "pf_key_v2_convert_id: FQDN %.*s",
- (int) *reslen, res));
- return res;
-
- case IPSEC_ID_USER_FQDN:
- res = calloc(idlen - ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ,
- sizeof(u_int8_t));
- if (!res)
- return 0;
-
- *reslen = idlen - ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ;
- memcpy(res, id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ, *reslen);
- *idtype = SADB_IDENTTYPE_USERFQDN;
- LOG_DBG((LOG_SYSDEP, 40, "pf_key_v2_convert_id: UFQDN %.*s",
- (int) *reslen, res));
- return res;
-
- case IPSEC_ID_IPV4_ADDR: /* XXX CONNECTION ? */
- if (inet_ntop(AF_INET, id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ,
- addrbuf, ADDRESS_MAX) == NULL)
- return 0;
- *reslen = strlen(addrbuf) + 3;
- strlcat(addrbuf, "/32", ADDRESS_MAX + 5);
- res = (u_int8_t *) strdup(addrbuf);
- if (!res)
- return 0;
- *idtype = SADB_IDENTTYPE_PREFIX;
- LOG_DBG((LOG_SYSDEP, 40, "pf_key_v2_convert_id: "
- "IPv4 address %s", res));
- return res;
-
- case IPSEC_ID_IPV6_ADDR: /* XXX CONNECTION ? */
- if (inet_ntop(AF_INET6,
- id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ,
- addrbuf, ADDRESS_MAX) == NULL)
- return 0;
- *reslen = strlen(addrbuf) + 4;
- strlcat(addrbuf, "/128", ADDRESS_MAX + 5);
- res = (u_int8_t *) strdup(addrbuf);
- if (!res)
- return 0;
- LOG_DBG((LOG_SYSDEP, 40, "pf_key_v2_convert_id: "
- "IPv6 address %s", res));
- *idtype = SADB_IDENTTYPE_PREFIX;
- return res;
-
- case IPSEC_ID_IPV4_ADDR_SUBNET: /* XXX PREFIX */
- addr = id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ;
- if (inet_ntop(AF_INET, addr, addrbuf, ADDRESS_MAX) == NULL)
- return 0;
- snprintf(addrbuf + strlen(addrbuf),
- ADDRESS_MAX - strlen(addrbuf), "/%d",
- pf_key_v2_mask_to_bits(*(u_int32_t *)(addr +
- sizeof(struct in_addr))));
- *reslen = strlen(addrbuf);
- res = (u_int8_t *) strdup(addrbuf);
- if (!res)
- return 0;
- *idtype = SADB_IDENTTYPE_PREFIX;
- LOG_DBG((LOG_SYSDEP, 40, "pf_key_v2_convert_id: "
- "IPv4 subnet %s", res));
- return res;
-
- case IPSEC_ID_IPV6_ADDR_SUBNET: /* XXX PREFIX */
- addr = id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ;
- if (inet_ntop(AF_INET6, addr, addrbuf, ADDRESS_MAX) == NULL)
- return 0;
- snprintf(addrbuf + strlen(addrbuf),
- ADDRESS_MAX - strlen(addrbuf), "/%d",
- pf_key_v2_mask6_to_bits(addr +
- sizeof(struct in6_addr)));
- *reslen = strlen(addrbuf);
- res = (u_int8_t *) strdup(addrbuf);
- if (!res)
- return 0;
- LOG_DBG((LOG_SYSDEP, 40, "pf_key_v2_convert_id: "
- "IPv6 subnet %s", res));
- *idtype = SADB_IDENTTYPE_PREFIX;
- return res;
-
- case IPSEC_ID_IPV4_RANGE:
- case IPSEC_ID_IPV6_RANGE:
- case IPSEC_ID_DER_ASN1_DN:
- case IPSEC_ID_DER_ASN1_GN:
- case IPSEC_ID_KEY_ID:
- /* XXX Not implemented yet. */
- return 0;
- }
-
- return 0;
-}
-#endif
-
-/* Enable a flow given an SA. */
-int
-pf_key_v2_enable_sa(struct sa *sa, struct sa *isakmp_sa)
-{
- struct ipsec_sa *isa = sa->data;
- struct sockaddr *dst, *src;
- int error;
- struct proto *proto = TAILQ_FIRST(&sa->protos);
- int sidtype = 0, didtype = 0;
- size_t sidlen = 0, didlen = 0;
- u_int8_t *sid = 0, *did = 0;
-#if !defined (SADB_X_EXT_FLOW_TYPE)
- struct sockaddr_storage hostmask_storage;
- struct sockaddr *hostmask = (struct sockaddr *)&hostmask_storage;
-#endif /* SADB_X_EXT_FLOW_TYPE */
-
- sa->transport->vtbl->get_dst(sa->transport, &dst);
- sa->transport->vtbl->get_src(sa->transport, &src);
-
-#if defined (SADB_X_EXT_FLOW_TYPE)
- if (isakmp_sa->id_i) {
- if (isakmp_sa->initiator)
- sid = pf_key_v2_convert_id(isakmp_sa->id_i,
- isakmp_sa->id_i_len, &sidlen, &sidtype);
- else
- did = pf_key_v2_convert_id(isakmp_sa->id_i,
- isakmp_sa->id_i_len, &didlen, &didtype);
- }
- if (isakmp_sa->id_r) {
- if (isakmp_sa->initiator)
- did = pf_key_v2_convert_id(isakmp_sa->id_r,
- isakmp_sa->id_r_len, &didlen, &didtype);
- else
- sid = pf_key_v2_convert_id(isakmp_sa->id_r,
- isakmp_sa->id_r_len, &sidlen, &sidtype);
- }
-#endif /* SADB_X_EXT_FLOW_TYPE */
-
- error = pf_key_v2_flow(isa->src_net, isa->src_mask, isa->dst_net,
- isa->dst_mask, isa->tproto, isa->sport, isa->dport,
- proto->spi[0], proto->proto, dst, src, 0, 0,
- sidtype, sid, sidlen, didtype, did, didlen,
- proto->data);
- if (error)
- goto cleanup;
-
-#if !defined (SADB_X_EXT_FLOW_TYPE)
- /* Set hostmask to '-1'. */
- switch (dst->sa_family) {
- case AF_INET:
- ((struct sockaddr_in *) hostmask)->sin_family = AF_INET;
-#ifndef USE_OLD_SOCKADDR
- ((struct sockaddr_in *) hostmask)->sin_len =
- sizeof(struct in_addr);
-#endif
- memset(&((struct sockaddr_in *) hostmask)->sin_addr.s_addr,
- 0xff, sizeof(struct in_addr));
- break;
- case AF_INET6:
- ((struct sockaddr_in6 *) hostmask)->sin6_family = AF_INET6;
-#ifndef USE_OLD_SOCKADDR
- ((struct sockaddr_in6 *) hostmask)->sin6_len =
- sizeof(struct in6_addr);
-#endif
- memset(&((struct sockaddr_in6 *) hostmask)->sin6_addr.s6_addr,
- 0xff, sizeof(struct in6_addr));
- break;
- }
-
- /* Ingress flows, handling SA bundles. */
- while (TAILQ_NEXT(proto, link)) {
- error = pf_key_v2_flow(dst, hostmask, src, hostmask, 0, 0, 0,
- proto->spi[1], proto->proto, src, dst,
- 0, 1, 0, 0, 0, 0, 0, 0, proto->data);
- if (error)
- goto cleanup;
- proto = TAILQ_NEXT(proto, link);
- }
-#endif /* SADB_X_EXT_FLOW_TYPE */
-
- error = pf_key_v2_flow(isa->dst_net, isa->dst_mask, isa->src_net,
- isa->src_mask, isa->tproto, isa->dport, isa->sport,
- proto->spi[1], proto->proto, src, dst, 0, 1,
- sidtype, sid, sidlen, didtype, did, didlen,
- proto->data);
-
-cleanup:
-#if defined (SADB_X_EXT_FLOW_TYPE)
- if (sid)
- free(sid);
- if (did)
- free(did);
-#endif /* SADB_X_EXT_FLOW_TYPE */
-
- return error;
-}
-
-#if defined (SADB_X_ASKPOLICY)
-/* Increase reference count of refcounted sections. */
-static int
-pf_key_v2_conf_refinc(int af, char *section)
-{
- char conn[22];
- int num;
-
- if (!section)
- return 0;
-
- num = conf_get_num(section, "Refcount", 0);
- if (num == 0)
- return 0;
-
- snprintf(conn, sizeof conn, "%d", num + 1);
- conf_set(af, section, "Refcount", conn, 1, 0);
- return 0;
-}
-#endif
-
-/*
- * Return 0 if the section didn't exist or was removed, non-zero otherwise.
- * Don't touch non-refcounted (statically defined) sections.
- */
-static int
-pf_key_v2_conf_refhandle(int af, char *section)
-{
- char conn[22];
- int num;
-
- if (!section)
- return 0;
-
- num = conf_get_num(section, "Refcount", 0);
- if (num == 1) {
- conf_remove_section(af, section);
- num--;
- } else if (num != 0) {
- snprintf(conn, sizeof conn, "%d", num - 1);
- conf_set(af, section, "Refcount", conn, 1, 0);
- }
- return num;
-}
-
-/* Remove all dynamically-established configuration entries. */
-static int
-pf_key_v2_remove_conf(char *section)
-{
- char *ikepeer, *localid, *remoteid, *configname;
- struct conf_list_node *attr;
- struct conf_list *attrs;
- int af;
-
- if (!section)
- return 0;
-
- if (!conf_get_str(section, "Phase"))
- return 0;
-
- /* Only remove dynamically-established entries. */
- attrs = conf_get_list(section, "Flags");
- if (attrs) {
- for (attr = TAILQ_FIRST(&attrs->fields); attr;
- attr = TAILQ_NEXT(attr, link))
- if (!strcasecmp(attr->field, "__ondemand"))
- goto passed;
-
- conf_free_list(attrs);
- }
- return 0;
-
-passed:
- conf_free_list(attrs);
-
- af = conf_begin();
-
- configname = conf_get_str(section, "Configuration");
- conf_remove_section(af, configname);
-
- /* These are the Phase 2 Local/Remote IDs. */
- localid = conf_get_str(section, "Local-ID");
- pf_key_v2_conf_refhandle(af, localid);
-
- remoteid = conf_get_str(section, "Remote-ID");
- pf_key_v2_conf_refhandle(af, remoteid);
-
- ikepeer = conf_get_str(section, "ISAKMP-peer");
-
- pf_key_v2_conf_refhandle(af, section);
-
- if (ikepeer) {
- remoteid = conf_get_str(ikepeer, "Remote-ID");
- localid = conf_get_str(ikepeer, "ID");
- configname = conf_get_str(ikepeer, "Configuration");
-
- pf_key_v2_conf_refhandle(af, ikepeer);
- pf_key_v2_conf_refhandle(af, configname);
-
- /* Phase 1 IDs */
- pf_key_v2_conf_refhandle(af, localid);
- pf_key_v2_conf_refhandle(af, remoteid);
- }
- conf_end(af, 1);
- return 0;
-}
-
-/* Disable a flow given a SA. */
-static int
-pf_key_v2_disable_sa(struct sa *sa, int incoming)
-{
- struct ipsec_sa *isa = sa->data;
- struct sockaddr *dst, *src;
- struct proto *proto = TAILQ_FIRST(&sa->protos);
-#if !defined (SADB_X_EXT_FLOW_TYPE)
- struct sockaddr_storage hostmask_storage;
- struct sockaddr *hostmask = (struct sockaddr *)&hostmask_storage;
- int error;
-#endif /* SADB_X_EXT_FLOW_TYPE */
-
- sa->transport->vtbl->get_dst(sa->transport, &dst);
- sa->transport->vtbl->get_src(sa->transport, &src);
-
- if (!incoming)
- return pf_key_v2_flow(isa->src_net, isa->src_mask,
- isa->dst_net, isa->dst_mask, isa->tproto, isa->sport,
- isa->dport, proto->spi[0], proto->proto, src, dst, 1, 0,
- 0, 0, 0, 0, 0, 0, proto->data);
- else {
-#if !defined (SADB_X_EXT_FLOW_TYPE)
- /* Set hostmask to '-1'. */
- switch (dst->sa_family) {
- case AF_INET:
- ((struct sockaddr_in *) hostmask)->sin_family =
- AF_INET;
-#ifndef USE_OLD_SOCKADDR
- ((struct sockaddr_in *) hostmask)->sin_len =
- sizeof(struct in_addr);
-#endif
- memset(&((struct sockaddr_in *) hostmask)->sin_addr.s_addr,
- 0xff, sizeof(struct in_addr));
- break;
- case AF_INET6:
- ((struct sockaddr_in6 *) hostmask)->sin6_family =
- AF_INET6;
-#ifndef USE_OLD_SOCKADDR
- ((struct sockaddr_in6 *) hostmask)->sin6_len =
- sizeof(struct in6_addr);
-#endif
- memset(&((struct sockaddr_in6 *) hostmask)->sin6_addr.s6_addr,
- 0xff, sizeof(struct in6_addr));
- break;
- }
-
- /* Ingress flow --- SA bundles */
- while (TAILQ_NEXT(proto, link)) {
- error = pf_key_v2_flow(dst, hostmask, src, hostmask,
- 0, 0, 0, proto->spi[1], proto->proto, src, dst,
- 1, 1, 0, 0, 0, 0, 0, 0, proto->data);
- if (error)
- return error;
- proto = TAILQ_NEXT(proto, link);
- }
-#endif /* SADB_X_EXT_FLOW_TYPE */
-
- return pf_key_v2_flow(isa->dst_net, isa->dst_mask,
- isa->src_net, isa->src_mask, isa->tproto, isa->dport,
- isa->sport, proto->spi[1], proto->proto, src, dst, 1, 1,
- 0, 0, 0, 0, 0, 0, proto->data);
- }
-}
-
-/*
- * Delete the IPsec SA represented by the INCOMING direction in protocol PROTO
- * of the IKE security association SA. Also delete potential flows tied to it.
- */
-int
-pf_key_v2_delete_spi(struct sa *sa, struct proto *proto, int incoming)
-{
- struct sadb_msg msg;
- struct sadb_sa ssa;
- struct sadb_address *addr = 0;
- struct sockaddr *saddr;
- int len, err;
- struct pf_key_v2_msg *delete = 0, *ret = 0;
-#ifdef KAME
- struct sadb_x_sa2 ssa2;
-#endif
-
- /* If it's not an established SA, don't proceed. */
- if (!(sa->flags & SA_FLAG_READY))
- return 0;
-
- /*
- * If the SA was not replaced and was not one acquired through the
- * kernel (ACQUIRE message), remove the flow associated with it.
- * We ignore any errors from the disabling of the flow.
- */
- if (!(sa->flags & SA_FLAG_REPLACED)
- && !(sa->flags & SA_FLAG_ONDEMAND))
- pf_key_v2_disable_sa(sa, incoming);
-
- if (sa->name && !(sa->flags & SA_FLAG_REPLACED)) {
- LOG_DBG((LOG_SYSDEP, 50,
- "pf_key_v2_delete_spi: removing configuration %s",
- sa->name));
- pf_key_v2_remove_conf(sa->name);
- }
- msg.sadb_msg_type = SADB_DELETE;
- switch (proto->proto) {
- case IPSEC_PROTO_IPSEC_ESP:
- msg.sadb_msg_satype = SADB_SATYPE_ESP;
- break;
- case IPSEC_PROTO_IPSEC_AH:
- msg.sadb_msg_satype = SADB_SATYPE_AH;
- break;
-#if defined (SADB_X_SATYPE_IPCOMP)
- case IPSEC_PROTO_IPCOMP:
- msg.sadb_msg_satype = SADB_X_SATYPE_IPCOMP;
- break;
-#endif
- default:
- log_print("pf_key_v2_delete_spi: invalid proto %d",
- proto->proto);
- goto cleanup;
- }
- msg.sadb_msg_seq = 0;
- delete = pf_key_v2_msg_new(&msg, 0);
- if (!delete)
- goto cleanup;
-
- /* Setup the SA extension. */
- ssa.sadb_sa_exttype = SADB_EXT_SA;
- ssa.sadb_sa_len = sizeof ssa / PF_KEY_V2_CHUNK;
- memcpy(&ssa.sadb_sa_spi, proto->spi[incoming], sizeof ssa.sadb_sa_spi);
- ssa.sadb_sa_replay = 0;
- ssa.sadb_sa_state = 0;
- ssa.sadb_sa_auth = 0;
- ssa.sadb_sa_encrypt = 0;
- ssa.sadb_sa_flags = 0;
- if (pf_key_v2_msg_add(delete, (struct sadb_ext *)&ssa, 0) == -1)
- goto cleanup;
-
-#ifdef KAME
- memset(&ssa2, 0, sizeof ssa2);
- ssa2.sadb_x_sa2_exttype = SADB_X_EXT_SA2;
- ssa2.sadb_x_sa2_len = sizeof ssa2 / PF_KEY_V2_CHUNK;
- ssa2.sadb_x_sa2_mode = 0;
- if (pf_key_v2_msg_add(delete, (struct sadb_ext *)&ssa2, 0) == -1)
- goto cleanup;
-#endif
-
- /*
- * Setup the ADDRESS extensions.
- */
- if (incoming)
- sa->transport->vtbl->get_dst(sa->transport, &saddr);
- else
- sa->transport->vtbl->get_src(sa->transport, &saddr);
- len = sizeof *addr + PF_KEY_V2_ROUND(sysdep_sa_len(saddr));
- addr = calloc(1, len);
- if (!addr)
- goto cleanup;
- addr->sadb_address_exttype = SADB_EXT_ADDRESS_SRC;
- addr->sadb_address_len = len / PF_KEY_V2_CHUNK;
-#ifndef __OpenBSD__
- addr->sadb_address_proto = 0;
- addr->sadb_address_prefixlen = 0;
-#endif
- addr->sadb_address_reserved = 0;
- memcpy(addr + 1, saddr, sysdep_sa_len(saddr));
- switch (saddr->sa_family) {
- case AF_INET:
- ((struct sockaddr_in *) (addr + 1))->sin_port = 0;
- break;
- case AF_INET6:
- ((struct sockaddr_in6 *) (addr + 1))->sin6_port = 0;
- break;
- }
- if (pf_key_v2_msg_add(delete, (struct sadb_ext *) addr,
- PF_KEY_V2_NODE_MALLOCED) == -1)
- goto cleanup;
- addr = 0;
-
- if (incoming)
- sa->transport->vtbl->get_src(sa->transport, &saddr);
- else
- sa->transport->vtbl->get_dst(sa->transport, &saddr);
- len = sizeof *addr + PF_KEY_V2_ROUND(sysdep_sa_len(saddr));
- addr = calloc(1, len);
- if (!addr)
- goto cleanup;
- addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST;
- addr->sadb_address_len = len / PF_KEY_V2_CHUNK;
-#ifndef __OpenBSD__
- addr->sadb_address_proto = 0;
- addr->sadb_address_prefixlen = 0;
-#endif
- addr->sadb_address_reserved = 0;
- memcpy(addr + 1, saddr, sysdep_sa_len(saddr));
- switch (saddr->sa_family) {
- case AF_INET:
- ((struct sockaddr_in *) (addr + 1))->sin_port = 0;
- break;
- case AF_INET6:
- ((struct sockaddr_in6 *) (addr + 1))->sin6_port = 0;
- break;
- }
- if (pf_key_v2_msg_add(delete, (struct sadb_ext *) addr,
- PF_KEY_V2_NODE_MALLOCED) == -1)
- goto cleanup;
- addr = 0;
-
- ret = pf_key_v2_call(delete);
- pf_key_v2_msg_free(delete);
- delete = 0;
- if (!ret)
- goto cleanup;
- err = ((struct sadb_msg *)TAILQ_FIRST(ret)->seg)->sadb_msg_errno;
- if (err) {
- LOG_DBG((LOG_SYSDEP, 10, "pf_key_v2_delete_spi: DELETE: %s",
- strerror(err)));
- goto cleanup;
- }
- pf_key_v2_msg_free(ret);
-
- LOG_DBG((LOG_SYSDEP, 50, "pf_key_v2_delete_spi: done"));
-
- return 0;
-
-cleanup:
- if (addr)
- free(addr);
- if (delete)
- pf_key_v2_msg_free(delete);
- if (ret)
- pf_key_v2_msg_free(ret);
- return -1;
-}
-
-static void
-pf_key_v2_stayalive(struct exchange *exchange, void *vconn, int fail)
-{
- char *conn = vconn;
- struct sa *sa;
-
- /* XXX What if it is phase 1 ? */
- sa = sa_lookup_by_name(conn, 2);
- if (sa)
- sa->flags |= SA_FLAG_STAYALIVE;
-
- /*
- * Remove failed configuration entry -- call twice because it is
- * created with a Refcount of 2.
- */
- if (fail && (!exchange || exchange->name)) {
- pf_key_v2_remove_conf(conn);
- pf_key_v2_remove_conf(conn);
- }
-}
-
-/* Check if a connection CONN exists, otherwise establish it. */
-void
-pf_key_v2_connection_check(char *conn)
-{
- if (!sa_lookup_by_name(conn, 2)) {
- LOG_DBG((LOG_SYSDEP, 70,
- "pf_key_v2_connection_check: SA for %s missing", conn));
- exchange_establish(conn, pf_key_v2_stayalive, conn);
- } else
- LOG_DBG((LOG_SYSDEP, 70, "pf_key_v2_connection_check: "
- "SA for %s exists", conn));
-}
-
-/* Handle a PF_KEY lifetime expiration message PMSG. */
-static void
-pf_key_v2_expire(struct pf_key_v2_msg *pmsg)
-{
- struct sadb_msg *msg;
- struct sadb_sa *ssa;
- struct sadb_address *dst;
- struct sockaddr *dstaddr;
- struct sadb_lifetime *life, *lifecurrent;
- struct sa *sa;
- struct pf_key_v2_node *lifenode, *ext;
-#ifdef USE_DEBUG
- char *dst_str;
-#endif
-
- msg = (struct sadb_msg *)TAILQ_FIRST(pmsg)->seg;
- ext = pf_key_v2_find_ext(pmsg, SADB_EXT_SA);
- if (!ext) {
- log_print("pf_key_v2_expire: no SA extension found");
- return;
- }
- ssa = ext->seg;
- ext = pf_key_v2_find_ext(pmsg, SADB_EXT_ADDRESS_DST);
- if (!ext) {
- log_print("pf_key_v2_expire: "
- "no destination address extension found");
- return;
- }
- dst = ext->seg;
- dstaddr = (struct sockaddr *) (dst + 1);
- lifenode = pf_key_v2_find_ext(pmsg, SADB_EXT_LIFETIME_HARD);
- if (!lifenode)
- lifenode = pf_key_v2_find_ext(pmsg, SADB_EXT_LIFETIME_SOFT);
- if (!lifenode) {
- log_print("pf_key_v2_expire: no lifetime extension found");
- return;
- }
- life = lifenode->seg;
-
- lifenode = pf_key_v2_find_ext(pmsg, SADB_EXT_LIFETIME_CURRENT);
- if (!lifenode) {
- log_print("pf_key_v2_expire: "
- "no current lifetime extension found");
- return;
- }
- lifecurrent = lifenode->seg;
-
-#ifdef USE_DEBUG
-
- if (sockaddr2text(dstaddr, &dst_str, 0))
- dst_str = 0;
-
- LOG_DBG((LOG_SYSDEP, 20, "pf_key_v2_expire: "
- "%s dst %s SPI %x sproto %d",
- life->sadb_lifetime_exttype == SADB_EXT_LIFETIME_SOFT ? "SOFT"
- : "HARD", dst_str ? dst_str : "<unknown>",
- ntohl(ssa->sadb_sa_spi), msg->sadb_msg_satype));
-
- if (dst_str)
- free(dst_str);
-
-#endif /* USE_DEBUG */
-
- /*
- * Find the IPsec SA. The IPsec stack has two SAs for every IKE SA,
- * one outgoing and one incoming, we regard expirations for any of
- * them as an expiration of the full IKE SA. Likewise, in
- * protection suites consisting of more than one protocol, any
- * expired individual IPsec stack SA will be seen as an expiration
- * of the full suite.
- */
- switch (msg->sadb_msg_satype) {
- case SADB_SATYPE_ESP:
- sa = ipsec_sa_lookup(dstaddr, ssa->sadb_sa_spi,
- IPSEC_PROTO_IPSEC_ESP);
- break;
-
- case SADB_SATYPE_AH:
- sa = ipsec_sa_lookup(dstaddr, ssa->sadb_sa_spi,
- IPSEC_PROTO_IPSEC_AH);
- break;
-
-#ifdef SADB_X_SATYPE_IPCOMP
- case SADB_X_SATYPE_IPCOMP:
- sa = ipsec_sa_lookup(dstaddr, ssa->sadb_sa_spi,
- IPSEC_PROTO_IPCOMP);
- break;
-#endif
-
- default:
- /* XXX Log? */
- sa = 0;
- break;
- }
-
- /* If the SA is already gone, don't do anything. */
- if (!sa)
- return;
-
- /*
- * If we got a notification, try to renegotiate the SA -- unless of
- * course it has already been replaced by another.
- * Also, ignore SAs that were not dynamically established, or that
- * did not see any use.
- */
- if (!(sa->flags & SA_FLAG_REPLACED) &&
- (sa->flags & SA_FLAG_ONDEMAND) &&
- lifecurrent->sadb_lifetime_bytes)
- exchange_establish(sa->name, 0, 0);
-
- if (life->sadb_lifetime_exttype == SADB_EXT_LIFETIME_HARD) {
- /* Remove the old SA, it isn't useful anymore. */
- sa_free(sa);
- }
-}
-
-/* Handle a PF_KEY SA ACQUIRE message PMSG. */
-static void
-pf_key_v2_acquire(struct pf_key_v2_msg *pmsg)
-{
-#if defined (SADB_X_ASKPOLICY)
- struct sadb_msg *msg, askpolicy_msg;
- struct pf_key_v2_msg *askpolicy = 0, *ret = 0;
- struct sadb_x_policy policy;
- struct sadb_address *dst = 0, *src = 0;
- struct sockaddr *dstaddr, *srcaddr = 0;
- struct sadb_comb *scmb = 0;
- struct sadb_prop *sprp = 0;
- struct sadb_ident *srcident = 0, *dstident = 0;
- char dstbuf[ADDRESS_MAX], srcbuf[ADDRESS_MAX], *peer = 0,
- *conn = 0;
- char confname[120];
- char *srcid = 0, *dstid = 0, *prefstring = 0;
- int slen, af, afamily, masklen, buflen;
- struct sockaddr *smask, *sflow, *dmask, *dflow;
- struct sadb_protocol *sproto;
- char ssflow[ADDRESS_MAX], sdflow[ADDRESS_MAX];
- char sdmask[ADDRESS_MAX], ssmask[ADDRESS_MAX];
- char *sidtype = 0, *didtype = 0;
- char lname[100], dname[100], configname[30];
- int shostflag = 0, dhostflag = 0;
- struct pf_key_v2_node *ext;
- struct passwd *pwd = 0;
- u_int16_t sport = 0, dport = 0;
- u_int8_t tproto = 0;
- char tmbuf[sizeof sport * 3 + 1], *xform;
- int connlen;
-#if defined (SADB_X_CREDTYPE_NONE)
- struct sadb_x_cred *cred = 0, *sauth = 0;
-#endif
-
- /* This needs to be dynamically allocated. */
- connlen = 22;
- conn = malloc(connlen);
- if (!conn) {
- log_error("pf_key_v2_acquire: malloc (%d) failed", connlen);
- return;
- }
- msg = (struct sadb_msg *)TAILQ_FIRST(pmsg)->seg;
-
- ext = pf_key_v2_find_ext(pmsg, SADB_EXT_ADDRESS_DST);
- if (!ext) {
- log_print("pf_key_v2_acquire: "
- "no destination address specified");
- return;
- }
- dst = ext->seg;
-
- ext = pf_key_v2_find_ext(pmsg, SADB_EXT_ADDRESS_SRC);
- if (ext)
- src = ext->seg;
-
- ext = pf_key_v2_find_ext(pmsg, SADB_EXT_PROPOSAL);
- if (ext) {
- sprp = ext->seg;
- scmb = (struct sadb_comb *) (sprp + 1);
- }
- ext = pf_key_v2_find_ext(pmsg, SADB_EXT_IDENTITY_SRC);
- if (ext)
- srcident = ext->seg;
-
- ext = pf_key_v2_find_ext(pmsg, SADB_EXT_IDENTITY_DST);
- if (ext)
- dstident = ext->seg;
-
- /* Ask the kernel for the matching policy. */
- bzero(&askpolicy_msg, sizeof askpolicy_msg);
- askpolicy_msg.sadb_msg_type = SADB_X_ASKPOLICY;
- askpolicy = pf_key_v2_msg_new(&askpolicy_msg, 0);
- if (!askpolicy)
- goto fail;
-
- policy.sadb_x_policy_exttype = SADB_X_EXT_POLICY;
- policy.sadb_x_policy_len = sizeof policy / PF_KEY_V2_CHUNK;
- policy.sadb_x_policy_seq = msg->sadb_msg_seq;
- if (pf_key_v2_msg_add(askpolicy, (struct sadb_ext *)&policy, 0) == -1)
- goto fail;
-
- ret = pf_key_v2_call(askpolicy);
- if (!ret)
- goto fail;
-
- /* Now we have all the information needed. */
-
- ext = pf_key_v2_find_ext(ret, SADB_X_EXT_SRC_FLOW);
- if (!ext) {
- log_print("pf_key_v2_acquire: no source flow extension found");
- goto fail;
- }
- sflow = (struct sockaddr *) (((struct sadb_address *) ext->seg) + 1);
-
- ext = pf_key_v2_find_ext(ret, SADB_X_EXT_DST_FLOW);
- if (!ext) {
- log_print("pf_key_v2_acquire: "
- "no destination flow extension found");
- goto fail;
- }
- dflow = (struct sockaddr *) (((struct sadb_address *) ext->seg) + 1);
- ext = pf_key_v2_find_ext(ret, SADB_X_EXT_SRC_MASK);
- if (!ext) {
- log_print("pf_key_v2_acquire: no source mask extension found");
- goto fail;
- }
- smask = (struct sockaddr *) (((struct sadb_address *) ext->seg) + 1);
-
- ext = pf_key_v2_find_ext(ret, SADB_X_EXT_DST_MASK);
- if (!ext) {
- log_print("pf_key_v2_acquire: "
- "no destination mask extension found");
- goto fail;
- }
- dmask = (struct sockaddr *) (((struct sadb_address *) ext->seg) + 1);
-
- ext = pf_key_v2_find_ext(ret, SADB_X_EXT_FLOW_TYPE);
- if (!ext) {
- log_print("pf_key_v2_acquire: no flow type extension found");
- goto fail;
- }
- sproto = ext->seg;
- tproto = sproto->sadb_protocol_proto;
-
-#if defined (SADB_X_EXT_LOCAL_CREDENTIALS)
- ext = pf_key_v2_find_ext(pmsg, SADB_X_EXT_LOCAL_CREDENTIALS);
- if (ext)
- cred = (struct sadb_x_cred *) ext->seg;
- else
- cred = 0;
-#endif
-
-#if defined (SADB_X_EXT_LOCAL_AUTH)
- ext = pf_key_v2_find_ext(pmsg, SADB_X_EXT_LOCAL_AUTH);
- if (ext)
- sauth = (struct sadb_x_cred *) ext->seg;
- else
- sauth = 0;
-#endif
-
- bzero(ssflow, sizeof ssflow);
- bzero(sdflow, sizeof sdflow);
- bzero(ssmask, sizeof ssmask);
- bzero(sdmask, sizeof sdmask);
-
- sidtype = didtype = "IPV4_ADDR_SUBNET"; /* default */
-
- switch (sflow->sa_family) {
- case AF_INET:
- if (inet_ntop(AF_INET,
- &((struct sockaddr_in *) sflow)->sin_addr, ssflow,
- ADDRESS_MAX) == NULL) {
- log_print("pf_key_v2_acquire: inet_ntop failed");
- goto fail;
- }
- sport = ((struct sockaddr_in *) sflow)->sin_port;
- if (inet_ntop(AF_INET,
- &((struct sockaddr_in *) dflow)->sin_addr, sdflow,
- ADDRESS_MAX) == NULL) {
- log_print("pf_key_v2_acquire: inet_ntop failed");
- goto fail;
- }
- dport = ((struct sockaddr_in *) dflow)->sin_port;
- if (inet_ntop(AF_INET,
- &((struct sockaddr_in *) smask)->sin_addr, ssmask,
- ADDRESS_MAX) == NULL) {
- log_print("pf_key_v2_acquire: inet_ntop failed");
- goto fail;
- }
- if (inet_ntop(AF_INET,
- &((struct sockaddr_in *) dmask)->sin_addr, sdmask,
- ADDRESS_MAX) == NULL) {
- log_print("pf_key_v2_acquire: inet_ntop failed");
- goto fail;
- }
- if (((struct sockaddr_in *) smask)->sin_addr.s_addr ==
- INADDR_BROADCAST) {
- shostflag = 1;
- sidtype = "IPV4_ADDR";
- }
- if (((struct sockaddr_in *) dmask)->sin_addr.s_addr ==
- INADDR_BROADCAST) {
- dhostflag = 1;
- didtype = "IPV4_ADDR";
- }
- break;
-
- case AF_INET6:
- if (inet_ntop(AF_INET6,
- &((struct sockaddr_in6 *) sflow)->sin6_addr,
- ssflow, ADDRESS_MAX) == NULL) {
- log_print("pf_key_v2_acquire: inet_ntop failed");
- goto fail;
- }
- sport = ((struct sockaddr_in6 *) sflow)->sin6_port;
- if (inet_ntop(AF_INET6,
- &((struct sockaddr_in6 *) dflow)->sin6_addr,
- sdflow, ADDRESS_MAX) == NULL) {
- log_print("pf_key_v2_acquire: inet_ntop failed");
- goto fail;
- }
- dport = ((struct sockaddr_in6 *) dflow)->sin6_port;
- if (inet_ntop(AF_INET6,
- &((struct sockaddr_in6 *) smask)->sin6_addr,
- ssmask, ADDRESS_MAX) == NULL) {
- log_print("pf_key_v2_acquire: inet_ntop failed");
- goto fail;
- }
- if (inet_ntop(AF_INET6,
- &((struct sockaddr_in6 *) dmask)->sin6_addr,
- sdmask, ADDRESS_MAX) == NULL) {
- log_print("pf_key_v2_acquire: inet_ntop failed");
- goto fail;
- }
- sidtype = didtype = "IPV6_ADDR_SUBNET";
- if (IN6_IS_ADDR_FULL(&((struct sockaddr_in6 *)smask)->sin6_addr)) {
- shostflag = 1;
- sidtype = "IPV6_ADDR";
- }
- if (IN6_IS_ADDR_FULL(&((struct sockaddr_in6 *)dmask)->sin6_addr)) {
- dhostflag = 1;
- didtype = "IPV6_ADDR";
- }
- break;
- }
-
- dstaddr = (struct sockaddr *)(dst + 1);
- bzero(dstbuf, sizeof dstbuf);
- bzero(srcbuf, sizeof srcbuf);
-
- if (dstaddr->sa_family == 0) {
- /*
- * Destination was not specified in the flow -- can we derive
- * it?
- */
- if (dhostflag == 0) {
- log_print("pf_key_v2_acquire: "
- "Cannot determine precise destination");
- goto fail;
- }
- dstaddr = dflow;
- }
- switch (dstaddr->sa_family) {
- case AF_INET:
- if (inet_ntop(AF_INET,
- &((struct sockaddr_in *) dstaddr)->sin_addr,
- dstbuf, ADDRESS_MAX) == NULL) {
- log_print("pf_key_v2_acquire: inet_ntop failed");
- goto fail;
- }
- LOG_DBG((LOG_SYSDEP, 20,
- "pf_key_v2_acquire: dst=%s sproto %d", dstbuf,
- msg->sadb_msg_satype));
- break;
-
- case AF_INET6:
- if (inet_ntop(AF_INET6,
- &((struct sockaddr_in6 *) dstaddr)->sin6_addr,
- dstbuf, ADDRESS_MAX) == NULL) {
- log_print("pf_key_v2_acquire: inet_ntop failed");
- goto fail;
- }
- LOG_DBG((LOG_SYSDEP, 20,
- "pf_key_v2_acquire: dst=%s sproto %d", dstbuf,
- msg->sadb_msg_satype));
- break;
- }
-
- if (src) {
- srcaddr = (struct sockaddr *) (src + 1);
-
- switch (srcaddr->sa_family) {
- case AF_INET:
- if (inet_ntop(AF_INET,
- &((struct sockaddr_in *) srcaddr)->sin_addr,
- srcbuf, ADDRESS_MAX) == NULL) {
- log_print("pf_key_v2_acquire: "
- "inet_ntop failed");
- goto fail;
- }
- break;
-
- case AF_INET6:
- if (inet_ntop(AF_INET6,
- &((struct sockaddr_in6 *)srcaddr)->sin6_addr,
- srcbuf, ADDRESS_MAX) == NULL) {
- log_print("pf_key_v2_acquire: "
- "inet_ntop failed");
- goto fail;
- }
- break;
-
- default:
- /*
- * The kernel will pass an all '0' EXT_ADDRESS_SRC if
- * it wasn't specified for the flow. In that case, do
- * NOT specify the srcaddr in the Peer-name below
- */
- srcbuf[0] = 0;
- srcaddr = NULL;
- break;
- }
- }
- /* Insert source ID. */
- if (srcident) {
- slen = (srcident->sadb_ident_len * sizeof(u_int64_t))
- - sizeof(struct sadb_ident);
- if (((unsigned char *) (srcident + 1))[slen - 1] != '\0') {
- log_print("pf_key_v2_acquire: "
- "source identity not NUL-terminated");
- goto fail;
- }
- /* Check for valid type. */
- switch (srcident->sadb_ident_type) {
-#if defined (SADB_X_IDENTTYPE_CONNECTION)
- case SADB_X_IDENTTYPE_CONNECTION:
- /* XXX */
- break;
-#endif
-
- case SADB_IDENTTYPE_PREFIX:
- /* Determine what the address family is. */
- srcid = memchr(srcident + 1, ':', slen);
- if (srcid)
- afamily = AF_INET6;
- else
- afamily = AF_INET;
-
- srcid = memchr(srcident + 1, '/', slen);
- if (!srcid) {
- log_print("pf_key_v2_acquire: "
- "badly formatted PREFIX identity");
- goto fail;
- }
- masklen = atoi(srcid + 1);
-
- /* XXX We only support host addresses. */
- if ((afamily == AF_INET6 && masklen != 128)
- || (afamily == AF_INET && masklen != 32)) {
- log_print("pf_key_v2_acquire: "
- "non-host address specified in source "
- "identity (mask length %d), ignoring "
- "request", masklen);
- goto fail;
- }
- /*
- * NUL-terminate the PREFIX string at the separator,
- * then dup.
- */
- *srcid = '\0';
- slen = strlen((char *) (srcident + 1)) +
- sizeof "ID:Address/";
- srcid = malloc(slen);
- if (!srcid) {
- log_error("pf_key_v2_acquire: "
- "malloc (%d) failed", slen);
- goto fail;
- }
- snprintf(srcid, slen, "ID:Address/%s",
- (char *) (srcident + 1));
-
- /* Set the section if it doesn't already exist. */
- af = conf_begin();
- if (!conf_get_str(srcid, "ID-type")) {
- if (conf_set(af, srcid, "ID-type",
- afamily == AF_INET ? "IPV4_ADDR" :
- "IPV6_ADDR", 1, 0)
- || conf_set(af, srcid, "Refcount", "1", 1,
- 0)
- || conf_set(af, srcid, "Address",
- (char *) (srcident + 1), 1, 0)) {
- conf_end(af, 0);
- goto fail;
- }
- } else
- pf_key_v2_conf_refinc(af, srcid);
- conf_end(af, 1);
- break;
-
- case SADB_IDENTTYPE_FQDN:
- prefstring = "FQDN";
- /* Fall through */
- case SADB_IDENTTYPE_USERFQDN:
- if (!prefstring) {
- prefstring = "USER_FQDN";
-
- /*
- * Check whether there is a string following
- * the header; if no, that there is a user ID
- * (and acquire the login name). If there is
- * both a string and a user ID, check that
- * they match.
- */
- if ((slen == 0) &&
- (srcident->sadb_ident_id == 0)) {
- log_print("pf_key_v2_acquire: "
- "no user FQDN or ID provided");
- goto fail;
- }
- if (srcident->sadb_ident_id) {
- pwd =
- getpwuid(srcident->sadb_ident_id);
- if (!pwd) {
- log_error("pf_key_v2_acquire: "
- "could not acquire "
- "username from provided "
- "ID %llu",
- srcident->sadb_ident_id);
- goto fail;
- }
- if (slen != 0)
- if (strcmp(pwd->pw_name,
- (char *) (srcident + 1))
- != 0) {
- log_print("pf_key_v2_acquire: "
- "provided user "
- "name and ID do "
- "not match (%s != "
- "%s)",
- (char *) (srcident + 1),
- pwd->pw_name);
- /*
- * String has
- * precedence, per
- * RFC 2367.
- */
- }
- }
- }
- buflen = (slen ? slen : strlen(pwd->pw_name)) +
- strlen(prefstring) + sizeof "ID:/";
- srcid = malloc(buflen);
- if (!srcid) {
- log_error("pf_key_v2_acquire: "
- "malloc (%d) failed", buflen);
- goto fail;
- }
- snprintf(srcid, buflen, "ID:%s/", prefstring);
- if (slen != 0)
- strlcat(srcid,
- (char *) (srcident + 1), buflen);
- else
- strlcat(srcid, pwd->pw_name, buflen);
- pwd = 0;
-
- /* Set the section if it doesn't already exist. */
- af = conf_begin();
- if (!conf_get_str(srcid, "ID-type")) {
- if (conf_set(af, srcid, "ID-type", prefstring,
- 1, 0)
- || conf_set(af, srcid, "Refcount", "1", 1,
- 0)
- || conf_set(af, srcid, "Name",
- srcid + sizeof "ID:/" - 1 +
- strlen(prefstring), 1, 0)) {
- conf_end(af, 0);
- goto fail;
- }
- } else
- pf_key_v2_conf_refinc(af, srcid);
- conf_end(af, 1);
- break;
-
- default:
- LOG_DBG((LOG_SYSDEP, 20,
- "pf_key_v2_acquire: invalid source ID type %d",
- srcident->sadb_ident_type));
- goto fail;
- }
-
- LOG_DBG((LOG_SYSDEP, 50,
- "pf_key_v2_acquire: constructed source ID \"%s\"", srcid));
- prefstring = 0;
- }
- /* Insert destination ID. */
- if (dstident) {
- slen = (dstident->sadb_ident_len * sizeof(u_int64_t))
- - sizeof(struct sadb_ident);
-
- /* Check for valid type. */
- switch (dstident->sadb_ident_type) {
-#if defined (SADB_X_IDENTTYPE_CONNECTION)
- case SADB_X_IDENTTYPE_CONNECTION:
- /* XXX */
- break;
-#endif
-
- case SADB_IDENTTYPE_PREFIX:
- /* Determine what the address family is. */
- dstid = memchr(dstident + 1, ':', slen);
- if (dstid)
- afamily = AF_INET6;
- else
- afamily = AF_INET;
-
- dstid = memchr(dstident + 1, '/', slen);
- if (!dstid) {
- log_print("pf_key_v2_acquire: "
- "badly formatted PREFIX identity");
- goto fail;
- }
- masklen = atoi(dstid + 1);
-
- /* XXX We only support host addresses. */
- if ((afamily == AF_INET6 && masklen != 128)
- || (afamily == AF_INET && masklen != 32)) {
- log_print("pf_key_v2_acquire: "
- "non-host address specified in "
- "destination identity (mask length %d), "
- "ignoring request", masklen);
- goto fail;
- }
- /*
- * NUL-terminate the PREFIX string at the separator,
- * then dup.
- */
- *dstid = '\0';
- slen = strlen((char *) (dstident + 1)) +
- sizeof "ID:Address/";
- dstid = malloc(slen);
- if (!dstid) {
- log_error("pf_key_v2_acquire: "
- "malloc (%d) failed", slen);
- goto fail;
- }
- snprintf(dstid, slen, "ID:Address/%s",
- (char *) (dstident + 1));
-
- /* Set the section if it doesn't already exist. */
- af = conf_begin();
- if (!conf_get_str(dstid, "ID-type")) {
- if (conf_set(af, dstid, "ID-type",
- afamily == AF_INET ? "IPV4_ADDR" :
- "IPV6_ADDR", 1, 0)
- || conf_set(af, dstid, "Refcount", "1", 1,
- 0)
- || conf_set(af, dstid, "Address",
- (char *) (dstident + 1), 1, 0)) {
- conf_end(af, 0);
- goto fail;
- }
- } else
- pf_key_v2_conf_refinc(af, dstid);
- conf_end(af, 1);
- break;
-
- case SADB_IDENTTYPE_FQDN:
- prefstring = "FQDN";
- /* Fall through */
-
- case SADB_IDENTTYPE_USERFQDN:
- if (!prefstring) {
- prefstring = "USER_FQDN";
-
- /*
- * Check whether there is a string following
- * the header; if no, that there is a user ID
- * (and acquire the login name). If there is
- * both a string and a user ID, check that
- * they match.
- */
- if (slen == 0 &&
- dstident->sadb_ident_id == 0) {
- log_print("pf_key_v2_acquire: "
- "no user FQDN or ID provided");
- goto fail;
- }
- if (dstident->sadb_ident_id) {
- pwd = getpwuid(dstident->sadb_ident_id);
- if (!pwd) {
- log_error("pf_key_v2_acquire: "
- "could not acquire "
- "username from provided "
- "ID %llu",
- dstident->sadb_ident_id);
- goto fail;
- }
- if (slen != 0)
- if (strcmp(pwd->pw_name,
- (char *) (dstident + 1))
- != 0) {
- log_print("pf_key_v2_acquire: "
- "provided user "
- "name and ID do "
- "not match (%s != "
- "%s)",
- (char *) (dstident + 1),
- pwd->pw_name);
- /*
- * String has
- * precedence, per RF
- * 2367.
- */
- }
- }
- }
- buflen = (slen ? slen : strlen(pwd->pw_name)) +
- strlen(prefstring) + sizeof "ID:/";
- dstid = malloc(buflen);
- if (!dstid) {
- log_error("pf_key_v2_acquire: "
- "malloc (%d) failed", buflen);
- goto fail;
- }
- snprintf(dstid, buflen, "ID:%s/", prefstring);
- if (slen != 0)
- strlcat(dstid, (char *) (dstident + 1),
- buflen);
- else
- strlcat(dstid, pwd->pw_name, buflen);
- pwd = 0;
-
- /* Set the section if it doesn't already exist. */
- af = conf_begin();
- if (!conf_get_str(dstid, "ID-type")) {
- if (conf_set(af, dstid, "ID-type", prefstring,
- 1, 0)
- || conf_set(af, dstid, "Refcount", "1", 1,
- 0)
- || conf_set(af, dstid, "Name",
- dstid + sizeof "ID:/" - 1 +
- strlen(prefstring), 1, 0)) {
- conf_end(af, 0);
- goto fail;
- }
- } else
- pf_key_v2_conf_refinc(af, dstid);
- conf_end(af, 1);
- break;
-
- default:
- LOG_DBG((LOG_SYSDEP, 20, "pf_key_v2_acquire: "
- "invalid destination ID type %d",
- dstident->sadb_ident_type));
- goto fail;
- }
-
- LOG_DBG((LOG_SYSDEP, 50,
- "pf_key_v2_acquire: constructed destination ID \"%s\"",
- dstid));
- }
- /* Now we've placed the necessary IDs in the configuration space. */
-
- /* Get a new connection sequence number. */
- for (;; connection_seq++) {
- snprintf(conn, connlen, "Connection-%u", connection_seq);
- snprintf(configname, sizeof configname, "Config-Phase2-%u",
- connection_seq);
-
- /* Does it exist ? */
- if (!conf_get_str(conn, "Phase")
- && !conf_get_str(configname, "Suites"))
- break;
- }
-
- /*
- * Set the IPsec connection entry. In particular, the following fields:
- * - Phase
- * - ISAKMP-peer
- * - Local-ID/Remote-ID (if provided)
- * - Acquire-ID (sequence number of kernel message, e.g., PF_KEYv2)
- * - Configuration
- *
- * Also set the following section:
- * [Peer-dstaddr(/srcaddr)(-srcid)(/dstid)]
- * with these fields:
- * - Phase
- * - ID (if provided)
- * - Remote-ID (if provided)
- * - Local-address (if provided)
- * - Address
- * - Configuration (if an entry ISAKMP-configuration-dstaddr(/srcaddr)
- * exists -- otherwise use the defaults)
- */
-
- slen = strlen(dstbuf) + strlen(srcbuf) + (srcid ? strlen(srcid) : 0)
- + (dstid ? strlen(dstid) : 0) + sizeof "Peer-/-/";
- peer = malloc(slen);
- if (!peer)
- goto fail;
-
- /*
- * The various cases:
- * - Peer-dstaddr
- * - Peer-dstaddr/srcaddr
- * - Peer-dstaddr/srcaddr-srcid
- * - Peer-dstaddr/srcaddr-srcid/dstid
- * - Peer-dstaddr/srcaddr-/dstid
- * - Peer-dstaddr-srcid/dstid
- * - Peer-dstaddr-/dstid
- * - Peer-dstaddr-srcid
- */
- snprintf(peer, slen, "Peer-%s%s%s%s%s%s%s", dstbuf, srcaddr ? "/" : "",
- srcaddr ? srcbuf : "", srcid ? "-" : "", srcid ? srcid : "",
- dstid ? (srcid ? "/" : "-/") : "", dstid ? dstid : "");
-
- /*
- * Set the IPsec connection section. Refcount is set to 2, because
- * it will be linked both to the incoming and the outgoing SA.
- */
- af = conf_begin();
- if (conf_set(af, conn, "Phase", "2", 0, 0)
- || conf_set(af, conn, "Flags", "__ondemand", 0, 0)
- || conf_set(af, conn, "Refcount", "2", 0, 0)
- || conf_set(af, conn, "ISAKMP-peer", peer, 0, 0)) {
- conf_end(af, 0);
- goto fail;
- }
- /* Set the sequence number. */
- snprintf(lname, sizeof lname, "%u", msg->sadb_msg_seq);
- if (conf_set(af, conn, "Acquire-ID", lname, 0, 0)) {
- conf_end(af, 0);
- goto fail;
- }
- /* Set Phase 2 IDs -- this is the Local-ID section. */
- snprintf(lname, sizeof lname, "Phase2-ID:%s/%s/%u/%u", ssflow, ssmask,
- tproto, sport);
- if (conf_set(af, conn, "Local-ID", lname, 0, 0)) {
- conf_end(af, 0);
- goto fail;
- }
- if (!conf_get_str(lname, "ID-type")) {
- if (conf_set(af, lname, "Refcount", "1", 0, 0)) {
- conf_end(af, 0);
- goto fail;
- }
- if (shostflag) {
- if (conf_set(af, lname, "ID-type", sidtype, 0, 0)
- || conf_set(af, lname, "Address", ssflow, 0, 0)) {
- conf_end(af, 0);
- goto fail;
- }
- } else {
- if (conf_set(af, lname, "ID-type", sidtype, 0, 0)
- || conf_set(af, lname, "Network", ssflow, 0, 0)
- || conf_set(af, lname, "Netmask", ssmask, 0, 0)) {
- conf_end(af, 0);
- goto fail;
- }
- }
- if (tproto) {
- snprintf(tmbuf, sizeof sport * 3 + 1, "%u", tproto);
- if (conf_set(af, lname, "Protocol", tmbuf, 0, 0)) {
- conf_end(af, 0);
- goto fail;
- }
- if (sport) {
- snprintf(tmbuf, sizeof sport * 3 + 1, "%u",
- ntohs(sport));
- if (conf_set(af, lname, "Port", tmbuf, 0, 0)) {
- conf_end(af, 0);
- goto fail;
- }
- }
- }
- } else
- pf_key_v2_conf_refinc(af, lname);
-
- /* Set Remote-ID section. */
- snprintf(dname, sizeof dname, "Phase2-ID:%s/%s/%u/%u", sdflow, sdmask,
- tproto, dport);
- if (conf_set(af, conn, "Remote-ID", dname, 0, 0)) {
- conf_end(af, 0);
- goto fail;
- }
- if (!conf_get_str(dname, "ID-type")) {
- if (conf_set(af, dname, "Refcount", "1", 0, 0)) {
- conf_end(af, 0);
- goto fail;
- }
- if (dhostflag) {
- if (conf_set(af, dname, "ID-type", didtype, 0, 0)
- || conf_set(af, dname, "Address", sdflow, 0, 0)) {
- conf_end(af, 0);
- goto fail;
- }
- } else {
- if (conf_set(af, dname, "ID-type", didtype, 0, 0)
- || conf_set(af, dname, "Network", sdflow, 0, 0)
- || conf_set(af, dname, "Netmask", sdmask, 0, 0)) {
- conf_end(af, 0);
- goto fail;
- }
- }
-
- if (tproto) {
- snprintf(tmbuf, sizeof dport * 3 + 1, "%u", tproto);
- if (conf_set(af, dname, "Protocol", tmbuf, 0, 0)) {
- conf_end(af, 0);
- goto fail;
- }
- if (dport) {
- snprintf(tmbuf, sizeof dport * 3 + 1, "%u",
- ntohs(dport));
- if (conf_set(af, dname, "Port", tmbuf, 0, 0)) {
- conf_end(af, 0);
- goto fail;
- }
- }
- }
- } else
- pf_key_v2_conf_refinc(af, dname);
-
- /*
- * XXX
- * We should be using information from the proposal to set this up.
- * At least, we should make this selectable.
- */
-
- /* Phase 2 configuration. */
- if (conf_set(af, conn, "Configuration", configname, 0, 0)) {
- conf_end(af, 0);
- goto fail;
- }
- if (conf_set(af, configname, "Exchange_type", "Quick_mode", 0, 0)
- || conf_set(af, configname, "DOI", "IPSEC", 0, 0)) {
- conf_end(af, 0);
- goto fail;
- }
- if (conf_get_str("General", "Default-phase-2-suites")) {
- if (conf_set(af, configname, "Suites",
- conf_get_str("General", "Default-phase-2-suites"), 0, 0)) {
- conf_end(af, 0);
- goto fail;
- }
- } else {
- if (conf_set(af, configname, "Suites",
- "QM-ESP-3DES-SHA-PFS-SUITE", 0, 0)) {
- conf_end(af, 0);
- goto fail;
- }
- }
-
- /* Set the ISAKMP-peer section. */
- if (!conf_get_str(peer, "Phase")) {
- if (conf_set(af, peer, "Phase", "1", 0, 0)
- || conf_set(af, peer, "Refcount", "1", 0, 0)
- || conf_set(af, peer, "Address", dstbuf, 0, 0)) {
- conf_end(af, 0);
- goto fail;
- }
- if (srcaddr && conf_set(af, peer, "Local-address", srcbuf, 0,
- 0)) {
- conf_end(af, 0);
- goto fail;
- }
- snprintf(confname, sizeof confname, "ISAKMP-Configuration-%s",
- peer);
- if (conf_set(af, peer, "Configuration", confname, 0, 0)) {
- conf_end(af, 0);
- goto fail;
- }
-#if defined (SADB_X_CREDTYPE_NONE)
- /* Store any credentials passed to us. */
- if (cred) {
- struct cert_handler *handler = 0;
- void *cert;
- char num[12], *certprint;
-
- /* Convert to bytes in-place. */
- cred->sadb_x_cred_len *= PF_KEY_V2_CHUNK;
-
- if (cred->sadb_x_cred_len <= sizeof *cred) {
- log_print("pf_key_v2_acquire: "
- "zero-length credentials, aborting SA "
- "acquisition");
- conf_end(af, 0);
- goto fail;
- }
- switch (cred->sadb_x_cred_type) {
- case SADB_X_CREDTYPE_X509:
- snprintf(num, sizeof num, "%d",
- ISAKMP_CERTENC_X509_SIG);
- handler = cert_get(ISAKMP_CERTENC_X509_SIG);
- break;
- case SADB_X_CREDTYPE_KEYNOTE:
- snprintf(num, sizeof num, "%d",
- ISAKMP_CERTENC_KEYNOTE);
- handler = cert_get(ISAKMP_CERTENC_KEYNOTE);
- break;
- default:
- log_print("pf_key_v2_acquire: "
- "unknown credential type %d",
- cred->sadb_x_cred_type);
- conf_end(af, 0);
- goto fail;
- }
-
- if (!handler) {
- log_print("pf_key_v2_acquire: "
- "cert_get (%s) failed", num);
- conf_end(af, 0);
- goto fail;
- }
- /* Set the credential type as a number. */
- if (conf_set(af, peer, "Credential_type", num, 0, 0)) {
- conf_end(af, 0);
- goto fail;
- }
- /* Get the certificate. */
- cert = handler->cert_get((u_int8_t *) (cred + 1),
- cred->sadb_x_cred_len - sizeof *cred);
-
- /* Now convert to printable format. */
- certprint = handler->cert_printable(cert);
- handler->cert_free(cert);
- if (!certprint
- || conf_set(af, peer, "Credentials", certprint, 0,
- 0)) {
- if (certprint)
- free(certprint);
- conf_end(af, 0);
- goto fail;
- }
- free(certprint);
- }
-#endif /* SADB_X_CREDTYPE_NONE */
-
- /* Phase 1 configuration. */
- if (!conf_get_str(confname, "exchange_type")) {
-#if defined (SADB_X_EXT_LOCAL_AUTH)
- /*
- * We may have been provided with authentication
- * material.
- */
- if (sauth) {
- char *authm;
-
- /* Convert to bytes in-place. */
- sauth->sadb_x_cred_len *= PF_KEY_V2_CHUNK;
-
- switch (sauth->sadb_x_cred_type) {
- case SADB_X_AUTHTYPE_PASSPHRASE:
- if (conf_set(af, confname,
- "Transforms", "3DES-SHA", 0, 0)) {
- conf_end(af, 0);
- goto fail;
- }
- if (sauth->sadb_x_cred_len <=
- sizeof *sauth) {
- log_print("pf_key_v2_acquire: "
- "zero-length passphrase, "
- "aborting SA acquisition");
- conf_end(af, 0);
- goto fail;
- }
- authm = malloc(sauth->sadb_x_cred_len -
- sizeof *sauth + 1);
- if (!authm) {
- log_error("pf_key_v2_acquire: "
- "malloc (%lu) failed",
- sauth->sadb_x_cred_len -
- (unsigned long) sizeof *sauth + 1);
- conf_end(af, 0);
- goto fail;
- }
- memcpy(authm, sauth + 1,
- sauth->sadb_x_cred_len -
- sizeof *sauth + 1);
-
- /* Set the passphrase in the peer. */
- if (conf_set(af, peer,
- "Authentication", authm, 0, 0)) {
- free(authm);
- conf_end(af, 0);
- goto fail;
- }
- free(authm);
- break;
-
- case SADB_X_AUTHTYPE_RSA:
- if (conf_set(af, confname,
- "Transforms", "3DES-SHA-RSA_SIG",
- 0, 0)) {
- conf_end(af, 0);
- goto fail;
- }
- if (sauth->sadb_x_cred_len <=
- sizeof *sauth) {
- log_print("pf_key_v2_acquire: "
- "zero-length RSA key, "
- "aborting SA acquisition");
- conf_end(af, 0);
- goto fail;
- }
- authm = key_printable(ISAKMP_KEY_RSA,
- ISAKMP_KEYTYPE_PRIVATE,
- (u_int8_t *) sauth + 1,
- sauth->sadb_x_cred_len -
- sizeof *sauth);
- if (!authm) {
- log_print("pf_key_v2_acquire: "
- "failed to convert "
- "private key to printable "
- "format (size %lu)",
- sauth->sadb_x_cred_len -
- (unsigned long) sizeof *sauth);
- conf_end(af, 0);
- goto fail;
- }
- /*
- * Set the key in the peer. We don't
- * use "Authentication" to avoid
- * potential conflicts with file-based
- * configurations that use public key
- * authentication but still specify
- * an "Authentication" tag (typically
- * as a remnant of passphrase-based
- * testing).
- */
- if (conf_set(af, peer,
- "PKAuthentication", authm, 0, 0)) {
- free(authm);
- conf_end(af, 0);
- goto fail;
- }
- free(authm);
- break;
-
- default:
- log_print("pf_key_v2_acquire: "
- "unknown authentication "
- "material type %d received from "
- "kernel", sauth->sadb_x_cred_type);
- conf_end(af, 0);
- goto fail;
- }
- } else /* Fall through */
-#endif /* SADB_X_EXT_LOCAL_AUTH */
- {
- xform = conf_get_str(
- "Default-phase-1-configuration",
- "Transforms");
- if (conf_set(af, confname, "Transforms",
- xform ? xform : "3DES-SHA-RSA_SIG", 0,
- 0)) {
- conf_end(af, 0);
- goto fail;
- }
- }
-
- if (conf_set(af, confname, "Exchange_Type", "ID_PROT",
- 0, 0)
- || conf_set(af, confname, "DOI", "IPSEC", 0, 0)
- || conf_set(af, confname, "Refcount", "1", 0, 0)) {
- conf_end(af, 0);
- goto fail;
- }
- } else
- pf_key_v2_conf_refinc(af, confname);
-
- /* The ID we should use in Phase 1. */
- if (srcid && conf_set(af, peer, "ID", srcid, 0, 0)) {
- conf_end(af, 0);
- goto fail;
- }
- /* The ID the other side should use in Phase 1. */
- if (dstid && conf_set(af, peer, "Remote-ID", dstid, 0, 0)) {
- conf_end(af, 0);
- goto fail;
- }
- } else
- pf_key_v2_conf_refinc(af, peer);
-
- /* All done. */
- conf_end(af, 1);
-
- /* Let's rock 'n roll. */
- pf_key_v2_connection_check(conn);
- conn = 0;
-
- /* Fall-through to cleanup. */
-fail:
- if (ret)
- pf_key_v2_msg_free(ret);
- if (askpolicy)
- pf_key_v2_msg_free(askpolicy);
- if (srcid)
- free(srcid);
- if (dstid)
- free(dstid);
- if (peer)
- free(peer);
- if (conn)
- free(conn);
- return;
-#else
- /* acquire not supported */
- return;
-#endif /* SADB_X_ASKPOLICY */
-}
-
-static void
-pf_key_v2_notify(struct pf_key_v2_msg *msg)
-{
- switch (((struct sadb_msg *)TAILQ_FIRST(msg)->seg)->sadb_msg_type) {
- case SADB_EXPIRE:
- pf_key_v2_expire(msg);
- break;
-
- case SADB_ACQUIRE:
- pf_key_v2_acquire(msg);
- break;
-
- default:
- log_print("pf_key_v2_notify: unexpected message type (%d)",
- ((struct sadb_msg *)TAILQ_FIRST(msg)->seg)->sadb_msg_type);
- }
- pf_key_v2_msg_free(msg);
-}
-
-void
-pf_key_v2_handler(int fd)
-{
- struct pf_key_v2_msg *msg;
-#if !defined (LINUX_IPSEC)
- int n;
-
- /*
- * As synchronous read/writes to the socket can have taken place
- * between the select(2) call of the main loop and this handler, we
- * need to recheck the readability.
- */
- if (ioctl(pf_key_v2_socket, FIONREAD, &n) == -1) {
- log_error("pf_key_v2_handler: ioctl (%d, FIONREAD, &n) failed",
- pf_key_v2_socket);
- return;
- }
- if (!n)
- return;
-#endif /* LINUX_IPSEC */
-
- msg = pf_key_v2_read(0);
- if (msg)
- pf_key_v2_notify(msg);
-}
-
-/*
- * Group 2 IPsec SAs given by the PROTO1 and PROTO2 protocols of the SA IKE
- * security association in a chain.
- * XXX Assumes OpenBSD GRPSPIS extension. Should probably be moved to sysdep.c
- */
-int
-pf_key_v2_group_spis(struct sa *sa, struct proto *proto1,
- struct proto *proto2, int incoming)
-{
-#if defined (SADB_X_GRPSPIS)
- struct sadb_msg msg;
- struct sadb_sa sa1, sa2;
- struct sadb_address *addr = 0;
- struct sadb_protocol protocol;
- struct pf_key_v2_msg *grpspis = 0, *ret = 0;
- struct sockaddr *saddr;
- int err;
- size_t len;
-#ifdef KAME
- struct sadb_x_sa2 kamesa2;
-#endif
-
- msg.sadb_msg_type = SADB_X_GRPSPIS;
- switch (proto1->proto) {
- case IPSEC_PROTO_IPSEC_ESP:
- msg.sadb_msg_satype = SADB_SATYPE_ESP;
- break;
- case IPSEC_PROTO_IPSEC_AH:
- msg.sadb_msg_satype = SADB_SATYPE_AH;
- break;
-#if defined (SADB_X_SATYPE_IPCOMP)
- case IPSEC_PROTO_IPCOMP:
- msg.sadb_msg_satype = SADB_X_SATYPE_IPCOMP;
- break;
-#endif
- default:
- log_print("pf_key_v2_group_spis: invalid proto %d",
- proto1->proto);
- goto cleanup;
- }
- msg.sadb_msg_seq = 0;
- grpspis = pf_key_v2_msg_new(&msg, 0);
- if (!grpspis)
- goto cleanup;
-
- /* Setup the SA extensions. */
- sa1.sadb_sa_exttype = SADB_EXT_SA;
- sa1.sadb_sa_len = sizeof sa1 / PF_KEY_V2_CHUNK;
- memcpy(&sa1.sadb_sa_spi, proto1->spi[incoming],
- sizeof sa1.sadb_sa_spi);
- sa1.sadb_sa_replay = 0;
- sa1.sadb_sa_state = 0;
- sa1.sadb_sa_auth = 0;
- sa1.sadb_sa_encrypt = 0;
- sa1.sadb_sa_flags = 0;
- if (pf_key_v2_msg_add(grpspis, (struct sadb_ext *)&sa1, 0) == -1)
- goto cleanup;
-
-#ifndef KAME
- sa2.sadb_sa_exttype = SADB_X_EXT_SA2;
- sa2.sadb_sa_len = sizeof sa2 / PF_KEY_V2_CHUNK;
- memcpy(&sa2.sadb_sa_spi, proto2->spi[incoming],
- sizeof sa2.sadb_sa_spi);
- sa2.sadb_sa_replay = 0;
- sa2.sadb_sa_state = 0;
- sa2.sadb_sa_auth = 0;
- sa2.sadb_sa_encrypt = 0;
- sa2.sadb_sa_flags = 0;
- if (pf_key_v2_msg_add(grpspis, (struct sadb_ext *)&sa2, 0) == -1)
- goto cleanup;
-#else
- memset(&kamesa2, 0, sizeof kamesa2);
- kamesa2.sadb_x_sa2_exttype = SADB_X_EXT_SA2;
- kamesa2.sadb_x_sa2_len = sizeof kamesa2 / PF_KEY_V2_CHUNK;
- kamesa2.sadb_x_sa2_mode = 0;
- if (pf_key_v2_msg_add(grpspis, (struct sadb_ext *)&kamesa2, 0) == -1)
- goto cleanup;
-#endif
-
- /*
- * Setup the ADDRESS extensions.
- */
- if (incoming)
- sa->transport->vtbl->get_src(sa->transport, &saddr);
- else
- sa->transport->vtbl->get_dst(sa->transport, &saddr);
- len = sizeof *addr + PF_KEY_V2_ROUND(sysdep_sa_len(saddr));
- addr = calloc(1, len);
- if (!addr)
- goto cleanup;
- addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST;
- addr->sadb_address_len = len / PF_KEY_V2_CHUNK;
-#ifndef __OpenBSD__
- addr->sadb_address_proto = 0;
- addr->sadb_address_prefixlen = 0;
-#endif
- addr->sadb_address_reserved = 0;
- memcpy(addr + 1, saddr, sysdep_sa_len(saddr));
- ((struct sockaddr_in *) (addr + 1))->sin_port = 0;
- if (pf_key_v2_msg_add(grpspis, (struct sadb_ext *) addr,
- PF_KEY_V2_NODE_MALLOCED) == -1)
- goto cleanup;
- addr = 0;
-
- addr = calloc(1, len);
- if (!addr)
- goto cleanup;
- addr->sadb_address_exttype = SADB_X_EXT_DST2;
- addr->sadb_address_len = len / PF_KEY_V2_CHUNK;
-#ifndef __OpenBSD__
- addr->sadb_address_proto = 0;
- addr->sadb_address_prefixlen = 0;
-#endif
- addr->sadb_address_reserved = 0;
- memcpy(addr + 1, saddr, sysdep_sa_len(saddr));
- ((struct sockaddr_in *) (addr + 1))->sin_port = 0;
- if (pf_key_v2_msg_add(grpspis, (struct sadb_ext *) addr,
- PF_KEY_V2_NODE_MALLOCED) == -1)
- goto cleanup;
- addr = 0;
-
- /* Setup the PROTOCOL extension. */
- protocol.sadb_protocol_exttype = SADB_X_EXT_PROTOCOL;
- protocol.sadb_protocol_len = sizeof protocol / PF_KEY_V2_CHUNK;
- switch (proto2->proto) {
- case IPSEC_PROTO_IPSEC_ESP:
- protocol.sadb_protocol_proto = SADB_SATYPE_ESP;
- break;
- case IPSEC_PROTO_IPSEC_AH:
- protocol.sadb_protocol_proto = SADB_SATYPE_AH;
- break;
-#if defined (SADB_X_SATYPE_IPCOMP)
- case IPSEC_PROTO_IPCOMP:
- protocol.sadb_protocol_proto = SADB_X_SATYPE_IPCOMP;
- break;
-#endif
- default:
- log_print("pf_key_v2_group_spis: invalid proto %d",
- proto2->proto);
- goto cleanup;
- }
- protocol.sadb_protocol_reserved2 = 0;
- if (pf_key_v2_msg_add(grpspis,
- (struct sadb_ext *)&protocol, 0) == -1)
- goto cleanup;
-
- ret = pf_key_v2_call(grpspis);
- pf_key_v2_msg_free(grpspis);
- grpspis = 0;
- if (!ret)
- goto cleanup;
- err = ((struct sadb_msg *)TAILQ_FIRST(ret)->seg)->sadb_msg_errno;
- if (err) {
- log_print("pf_key_v2_group_spis: GRPSPIS: %s", strerror(err));
- goto cleanup;
- }
- pf_key_v2_msg_free(ret);
-
- LOG_DBG((LOG_SYSDEP, 50, "pf_key_v2_group_spis: done"));
-
- return 0;
-
-cleanup:
- if (addr)
- free(addr);
- if (grpspis)
- pf_key_v2_msg_free(grpspis);
- if (ret)
- pf_key_v2_msg_free(ret);
- return -1;
-
-#else /* SADB_X_GRPSPIS */
- log_print("pf_key_v2_group_spis: not supported in pure PF_KEYv2");
- return -1;
-#endif
-}