diff options
author | Niklas Hallqvist <niklas@cvs.openbsd.org> | 1999-03-24 14:37:14 +0000 |
---|---|---|
committer | Niklas Hallqvist <niklas@cvs.openbsd.org> | 1999-03-24 14:37:14 +0000 |
commit | f9e1002627580f882d68dcec3192f42efc39d143 (patch) | |
tree | 7f6de1e19d2b9e647240fcb21aa575769194d6e5 /sbin | |
parent | e263dd4b22b9777876cf4bf6413c0e949230ccd9 (diff) |
Initial PF_KEYv2 support
Diffstat (limited to 'sbin')
-rw-r--r-- | sbin/isakmpd/pf_key_v2.c | 1429 | ||||
-rw-r--r-- | sbin/isakmpd/pf_key_v2.h | 61 |
2 files changed, 1490 insertions, 0 deletions
diff --git a/sbin/isakmpd/pf_key_v2.c b/sbin/isakmpd/pf_key_v2.c new file mode 100644 index 00000000000..c5258f13ba2 --- /dev/null +++ b/sbin/isakmpd/pf_key_v2.c @@ -0,0 +1,1429 @@ +/* $OpenBSD: pf_key_v2.c,v 1.1 1999/03/24 14:37:13 niklas Exp $ */ +/* $EOM: pf_key_v2.c,v 1.1 1999/03/24 11:09:18 niklas Exp $ */ + +/* + * Copyright (c) 1999 Niklas Hallqvist. 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Ericsson Radio Systems. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * 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. + */ + +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/socket.h> +#include <sys/uio.h> +#include <net/pfkeyv2.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "conf.h" +#include "ipsec.h" +#include "ipsec_num.h" +#include "log.h" +#include "pf_key_v2.h" +#include "sa.h" +#include "timer.h" +#include "transport.h" + +/* Rounding needed for PF_ROUTE. XXX Really OpenBSD-specific. */ +#define ROUNDUP(a) \ + ((a) > 0 ? (1 + (((a) - 1) | (sizeof (long) - 1))) : sizeof (long)) + +#define PF_KEY_V2_CHUNK 8 +#define PF_KEY_V2_ROUND(x) \ + (((x) + PF_KEY_V2_CHUNK - 1) & ~(PF_KEY_V2_CHUNK - 1)) + +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 + +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 *, + struct pf_key_v2_node *, + 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 *); + +/* The socket to use for PF_KEY interactions. */ +static int pf_key_v2_socket; + +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, *next; + + for (np = TAILQ_FIRST (msg); np; np = next) + { + next = TAILQ_NEXT (np, link); + if (np->flags & PF_KEY_V2_NODE_MALLOCED) + free (np->seg); + free (np); + } + free (msg); +} + +/* Just return a new sequence number. */ +static u_int32_t +pf_key_v2_seq () +{ + 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 untile 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 now; + + while (1) + { + 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 " + "(%d bytes)", + pf_key_v2_socket, n); + goto cleanup; + } + + n = hdr.sadb_msg_len * PF_KEY_V2_CHUNK; + buf = malloc (n); + if (!buf) + { + log_error ("pf_key_v2_read: malloc (%d) failed", 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 ((size_t)n != hdr.sadb_msg_len * PF_KEY_V2_CHUNK) + { + log_print ("pf_key_v2_read: read (%d, ...) returned short packet " + "(%d bytes)", + pf_key_v2_socket, n); + goto cleanup; + } + + log_debug_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 != getpid ())) + { + if (seq) + { + free (buf); + buf = 0; + continue; + } + else + { + log_debug (LOG_SYSDEP, 90, + "pf_key_v2_read:" + "bad version (%d) or PID (%d, mine is %d), ignored", + msg->sadb_msg_version, msg->sadb_msg_pid, 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 != getpid () || msg->sadb_msg_seq != seq)) + { + gettimeofday (&now, 0); + timer_add_event ("pf_key_v2_notify", + (void (*) (void *))pf_key_v2_notify, ret, &now); + 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 (%d) failed", cnt * 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++) + { + sprintf (header, "pf_key_v2_write: iov[%d]", i); + log_debug_buf (LOG_SYSDEP, 80, header, (u_int8_t *)iov[i].iov_base, + iov[i].iov_len); + } + + n = writev (pf_key_v2_socket, iov, cnt); + if (n == -1) + { + log_error ("pf_key_v2_write: writev (%d, 0x%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 (%d)", + pf_key_v2_socket, 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 next TYPE extension in MSG starting from EXT, unless EXT is zero + * which means find the first. Return zero if none found. + */ +static struct pf_key_v2_node * +pf_key_v2_find_ext (struct pf_key_v2_msg *msg, struct pf_key_v2_node *ext, + u_int16_t type) +{ + for (ext = TAILQ_NEXT (ext ? ext : 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 () +{ + int fd = -1, err; + struct sadb_msg msg; + struct pf_key_v2_msg *regmsg = 0, *ret = 0; + + /* Open the socket we use to speak to IPSec. */ + pf_key_v2_socket = -1; + fd = socket (PF_KEY, SOCK_RAW, PF_KEY_V2); + if (fd == -1) + { + log_error ("pf_key_v2_open: " + "socket (PF_KEY, SOCK_RAW, PF_KEY_V2) failed"); + goto cleanup; + } + 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); + 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, + int srclen, struct sockaddr *dst, int dstlen) +{ + 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; + u_int8_t *spi = 0; + int len, err; + + 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; + default: + log_print ("pf_key_v2_get_spi: invalid proto %d", proto); + goto cleanup; + } + /* + * XXX When we have acquires working, the sequence number have to be set + * from the acquire message. + */ + msg.sadb_msg_seq = 0; + getspi = pf_key_v2_msg_new (&msg, 0); + if (!getspi) + goto cleanup; + + /* Setup the ADDRESS extensions. */ + len = sizeof (struct sadb_address) + PF_KEY_V2_ROUND (srclen); + addr = malloc (len); + if (!addr) + goto cleanup; + addr->sadb_address_exttype = SADB_EXT_ADDRESS_SRC; + addr->sadb_address_len = len / PF_KEY_V2_CHUNK; +#if 0 + addr->sadb_address_proto = 0; + addr->sadb_address_prefixlen = 0; +#endif + addr->sadb_address_reserved = 0; + memcpy (addr + 1, src, srclen); + /* XXX IPv4-specific. */ + ((struct sockaddr_in *)(addr + 1))->sin_port = 0; + 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 (dstlen); + addr = malloc (len); + if (!addr) + goto cleanup; + addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST; + addr->sadb_address_len = len / PF_KEY_V2_CHUNK; +#if 0 + addr->sadb_address_proto = 0; + addr->sadb_address_prefixlen = 0; +#endif + addr->sadb_address_reserved = 0; + memcpy (addr + 1, dst, dstlen); + /* XXX IPv4-specific. */ + ((struct sockaddr_in *)(addr + 1))->sin_port = 0; + 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; + 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; + } + + sa = (struct sadb_sa *)pf_key_v2_find_ext (ret, 0, SADB_EXT_SA)->seg; + if (!sa) + { + log_print ("pf_key_v2_get_spi: no SA extension found"); + goto cleanup; + } + + *sz = sizeof sa->sadb_sa_spi; + spi = malloc (*sz); + if (!spi) + goto cleanup; + memcpy (spi, &sa->sadb_sa_spi, *sz); + pf_key_v2_msg_free (ret); + + log_debug_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; +} + +/* + * 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 sadb_msg msg; + struct sadb_sa ssa; + struct sadb_lifetime *life = 0; + struct sadb_address *addr = 0; + struct sadb_key *key = 0; + struct sockaddr *src, *dst; + int dstlen, srclen, keylen, hashlen, err; + struct pf_key_v2_msg *update = 0, *ret = 0; + struct ipsec_proto *iproto = proto->data; + size_t len; + + 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_EALG_X_CAST + case IPSEC_ESP_CAST: + ssa.sadb_sa_encrypt = SADB_EALG_X_CAST; + break; +#endif + +#ifdef SADB_EALG_X_BLF + case IPSEC_ESP_BLOWFISH: + ssa.sadb_sa_encrypt = SADB_EALG_X_BLF; + break; +#endif + + default: + /* XXX Log? */ + return -1; + } + + switch (iproto->auth) + { + case IPSEC_AUTH_HMAC_MD5: + ssa.sadb_sa_auth = SADB_AALG_MD5HMAC96; + break; + + case IPSEC_AUTH_HMAC_SHA: + ssa.sadb_sa_auth = SADB_AALG_SHA1HMAC96; + break; + + case IPSEC_AUTH_DES_MAC: + case IPSEC_AUTH_KPDK: + /* XXX Log? */ + 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: + ssa.sadb_sa_auth = SADB_AALG_MD5HMAC96; + break; + + case IPSEC_AH_SHA: + ssa.sadb_sa_auth = SADB_AALG_SHA1HMAC96; + break; + + default: + /* XXX Log? */ + goto cleanup; + } + break; + + default: + log_print ("pf_key_v2_set_spi: invalid proto %d", proto->proto); + goto cleanup; + } + msg.sadb_msg_seq = 0; + update = pf_key_v2_msg_new (&msg, 0); + if (!update) + goto cleanup; + + /* Setup the rest of 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 + = conf_get_str ("General", "Shared-SADB") ? 0 : iproto->replay_window; + ssa.sadb_sa_state = SADB_SASTATE_MATURE; + ssa.sadb_sa_flags = 0; + 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 reaaly 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 reaaly 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. + * + * XXX Addresses has to be thought through. Assumes IPv4. + */ + if (incoming) + sa->transport->vtbl->get_dst (sa->transport, &src, &srclen); + else + sa->transport->vtbl->get_src (sa->transport, &src, &srclen); + len = sizeof *addr + PF_KEY_V2_ROUND (srclen); + addr = malloc (len); + if (!addr) + goto cleanup; + addr->sadb_address_exttype = SADB_EXT_ADDRESS_SRC; + addr->sadb_address_len = len / PF_KEY_V2_CHUNK; +#if 0 + addr->sadb_address_proto = 0; + addr->sadb_address_prefixlen = 0; +#endif + addr->sadb_address_reserved = 0; + memcpy (addr + 1, src, srclen); + ((struct sockaddr_in *)(addr + 1))->sin_port = 0; + if (pf_key_v2_msg_add (update, (struct sadb_ext *)addr, + PF_KEY_V2_NODE_MALLOCED) == -1) + goto cleanup; + addr = 0; + + if (incoming) + sa->transport->vtbl->get_src (sa->transport, &dst, &dstlen); + else + sa->transport->vtbl->get_dst (sa->transport, &dst, &dstlen); + len = sizeof *addr + PF_KEY_V2_ROUND (dstlen); + addr = malloc (len); + if (!addr) + goto cleanup; + addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST; + addr->sadb_address_len = len / PF_KEY_V2_CHUNK; +#if 0 + addr->sadb_address_proto = 0; + addr->sadb_address_prefixlen = 0; +#endif + addr->sadb_address_reserved = 0; + memcpy (addr + 1, dst, dstlen); + ((struct sockaddr_in *)(addr + 1))->sin_port = 0; + 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 (dstlen); + addr = malloc (len); + if (!addr) + goto cleanup; + addr->sadb_address_exttype = SADB_EXT_ADDRESS_PROXY; + addr->sadb_address_len = len / PF_KEY_V2_CHUNK; +#if 0 + addr->sadb_address_proto = 0; + addr->sadb_address_prefixlen = 0; +#endif + addr->sadb_address_reserved = 0; + memcpy (addr + 1, dst, dstlen); + ((struct sockaddr_in *)(addr + 1))->sin_port = 0; + 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 + + /* Setup the KEY extensions. */ + 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; + + 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; + + /* XXX Here can identity and sensitivity extensions be setup. */ + + /* XXX IPv4 specific. */ + log_debug (LOG_SYSDEP, 10, "pf_key_v2_set_spi: satype %d dst %s SPI 0x%x", + msg.sadb_msg_satype, + inet_ntoa (((struct sockaddr_in *)dst)->sin_addr), + ntohl (ssa.sadb_sa_spi)); + + 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_debug (LOG_SYSDEP, 50, "pf_key_v2_set_spi: done"); + + return 0; + + cleanup: + 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; +} + +/* + * Delete the IPSec SA represented by the INCOMING direction in protocol PROTO + * of the IKE security association SA. + */ +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 saddrlen, len, err; + struct pf_key_v2_msg *delete = 0, *ret = 0; + + 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; + 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; + + /* + * Setup the ADDRESS extensions. + * + * XXX Addresses has to be thought through. Assumes IPv4. + */ + if (incoming) + sa->transport->vtbl->get_dst (sa->transport, &saddr, &saddrlen); + else + sa->transport->vtbl->get_src (sa->transport, &saddr, &saddrlen); + len = sizeof *addr + PF_KEY_V2_ROUND (saddrlen); + addr = malloc (len); + if (!addr) + goto cleanup; + addr->sadb_address_exttype = SADB_EXT_ADDRESS_SRC; + addr->sadb_address_len = len / PF_KEY_V2_CHUNK; +#if 0 + addr->sadb_address_proto = 0; + addr->sadb_address_prefixlen = 0; +#endif + addr->sadb_address_reserved = 0; + memcpy (addr + 1, saddr, saddrlen); + ((struct sockaddr_in *)(addr + 1))->sin_port = 0; + 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, &saddrlen); + else + sa->transport->vtbl->get_dst (sa->transport, &saddr, &saddrlen); + len = sizeof *addr + PF_KEY_V2_ROUND (saddrlen); + addr = malloc (len); + if (!addr) + goto cleanup; + addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST; + addr->sadb_address_len = len / PF_KEY_V2_CHUNK; +#if 0 + addr->sadb_address_proto = 0; + addr->sadb_address_prefixlen = 0; +#endif + addr->sadb_address_reserved = 0; + memcpy (addr + 1, saddr, saddrlen); + ((struct sockaddr_in *)(addr + 1))->sin_port = 0; + 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_print ("pf_key_v2_delete_spi: DELETE: %s", strerror (err)); + goto cleanup; + } + pf_key_v2_msg_free (ret); + + log_debug (LOG_MISC, 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; +} + +/* Enable a flow given a SA. */ +int +pf_key_v2_enable_sa (struct sa *sa) +{ + struct ipsec_sa *isa = sa->data; + struct sockaddr *dst; + int dstlen; + struct proto *proto = TAILQ_FIRST (&sa->protos); + + sa->transport->vtbl->get_dst (sa->transport, &dst, &dstlen); + + /* XXX Check why byte ordering is backwards. */ + return pf_key_v2_enable_spi (htonl (isa->src_net), htonl (isa->src_mask), + htonl (isa->dst_net), htonl (isa->dst_mask), + proto->spi[0], proto->proto, + ((struct sockaddr_in *)dst)->sin_addr.s_addr); +} + +/* + * Enable a flow. + * XXX Assumes OpenBSD ADDFLOW extension. Should probably be moved to sysdep.c + */ +int +pf_key_v2_enable_spi (in_addr_t laddr, in_addr_t lmask, in_addr_t raddr, + in_addr_t rmask, u_int8_t *spi, u_int8_t proto, + in_addr_t dst) +{ +#ifdef SADB_X_ADDFLOW + struct sadb_msg msg; + struct sadb_sa ssa; + struct sadb_address *addr = 0; + struct pf_key_v2_msg *addflow = 0, *ret = 0; + size_t len; + int err; + + msg.sadb_msg_type = 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; + default: + log_print ("pf_key_v2_delete_spi: invalid proto %d", proto); + goto cleanup; + } + msg.sadb_msg_seq = 0; + addflow = pf_key_v2_msg_new (&msg, 0); + if (!addflow) + 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, 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; + /* + * XXX The LOCALFLOW flag should only be set if this machine is part of the + * source subnet. + */ + ssa.sadb_sa_flags = SADB_SAFLAGS_X_LOCALFLOW; + if (pf_key_v2_msg_add (addflow, (struct sadb_ext *)&ssa, 0) == -1) + goto cleanup; + + /* + * Setup the ADDRESS extensions. + * + * XXX Addresses has to be thought through. Assumes IPv4. + */ + len = sizeof *addr + PF_KEY_V2_ROUND (sizeof (struct sockaddr_in)); + addr = malloc (len); + if (!addr) + goto cleanup; + addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST; + addr->sadb_address_len = len / PF_KEY_V2_CHUNK; +#if 0 + addr->sadb_address_proto = 0; + addr->sadb_address_prefixlen = 0; +#endif + addr->sadb_address_reserved = 0; + memset (addr + 1, '\0', sizeof (struct sockaddr_in)); + ((struct sockaddr_in *)(addr + 1))->sin_len = sizeof (struct sockaddr_in); + ((struct sockaddr_in *)(addr + 1))->sin_family = AF_INET; + ((struct sockaddr_in *)(addr + 1))->sin_addr.s_addr = dst; + ((struct sockaddr_in *)(addr + 1))->sin_port = 0; + if (pf_key_v2_msg_add (addflow, (struct sadb_ext *)addr, + PF_KEY_V2_NODE_MALLOCED) == -1) + goto cleanup; + addr = 0; + + addr = malloc (len); + if (!addr) + goto cleanup; + addr->sadb_address_exttype = SADB_EXT_X_SRC_FLOW; + addr->sadb_address_len = len / PF_KEY_V2_CHUNK; +#if 0 + addr->sadb_address_proto = 0; + addr->sadb_address_prefixlen = 0; +#endif + addr->sadb_address_reserved = 0; + memset (addr + 1, '\0', sizeof (struct sockaddr_in)); + ((struct sockaddr_in *)(addr + 1))->sin_len = sizeof (struct sockaddr_in); + ((struct sockaddr_in *)(addr + 1))->sin_family = AF_INET; + ((struct sockaddr_in *)(addr + 1))->sin_addr.s_addr = laddr; + ((struct sockaddr_in *)(addr + 1))->sin_port = 0; + if (pf_key_v2_msg_add (addflow, (struct sadb_ext *)addr, + PF_KEY_V2_NODE_MALLOCED) == -1) + goto cleanup; + addr = 0; + + addr = malloc (len); + if (!addr) + goto cleanup; + addr->sadb_address_exttype = SADB_EXT_X_SRC_MASK; + addr->sadb_address_len = len / PF_KEY_V2_CHUNK; +#if 0 + addr->sadb_address_proto = 0; + addr->sadb_address_prefixlen = 0; +#endif + addr->sadb_address_reserved = 0; + memset (addr + 1, '\0', sizeof (struct sockaddr_in)); + ((struct sockaddr_in *)(addr + 1))->sin_len = sizeof (struct sockaddr_in); + ((struct sockaddr_in *)(addr + 1))->sin_family = AF_INET; + ((struct sockaddr_in *)(addr + 1))->sin_addr.s_addr = lmask; + ((struct sockaddr_in *)(addr + 1))->sin_port = 0; + if (pf_key_v2_msg_add (addflow, (struct sadb_ext *)addr, + PF_KEY_V2_NODE_MALLOCED) == -1) + goto cleanup; + addr = 0; + + addr = malloc (len); + if (!addr) + goto cleanup; + addr->sadb_address_exttype = SADB_EXT_X_DST_FLOW; + addr->sadb_address_len = len / PF_KEY_V2_CHUNK; +#if 0 + addr->sadb_address_proto = 0; + addr->sadb_address_prefixlen = 0; +#endif + addr->sadb_address_reserved = 0; + memset (addr + 1, '\0', sizeof (struct sockaddr_in)); + ((struct sockaddr_in *)(addr + 1))->sin_len = sizeof (struct sockaddr_in); + ((struct sockaddr_in *)(addr + 1))->sin_family = AF_INET; + ((struct sockaddr_in *)(addr + 1))->sin_addr.s_addr = raddr; + ((struct sockaddr_in *)(addr + 1))->sin_port = 0; + if (pf_key_v2_msg_add (addflow, (struct sadb_ext *)addr, + PF_KEY_V2_NODE_MALLOCED) == -1) + goto cleanup; + addr = 0; + + addr = malloc (len); + if (!addr) + goto cleanup; + addr->sadb_address_exttype = SADB_EXT_X_DST_MASK; + addr->sadb_address_len = len / PF_KEY_V2_CHUNK; +#if 0 + addr->sadb_address_proto = 0; + addr->sadb_address_prefixlen = 0; +#endif + addr->sadb_address_reserved = 0; + memset (addr + 1, '\0', sizeof (struct sockaddr_in)); + ((struct sockaddr_in *)(addr + 1))->sin_len = sizeof (struct sockaddr_in); + ((struct sockaddr_in *)(addr + 1))->sin_family = AF_INET; + ((struct sockaddr_in *)(addr + 1))->sin_addr.s_addr = rmask; + ((struct sockaddr_in *)(addr + 1))->sin_port = 0; + if (pf_key_v2_msg_add (addflow, (struct sadb_ext *)addr, + PF_KEY_V2_NODE_MALLOCED) == -1) + goto cleanup; + addr = 0; + + log_debug (LOG_SYSDEP, 50, "pf_key_v2_enable_spi: src %x %x dst %x %x", + laddr, lmask, raddr, rmask); + + ret = pf_key_v2_call (addflow); + pf_key_v2_msg_free (addflow); + addflow = 0; + if (!ret) + goto cleanup; + err = ((struct sadb_msg *)TAILQ_FIRST (ret)->seg)->sadb_msg_errno; + if (err) + { + log_print ("pf_key_v2_enable_spi: ADDFLOW: %s", strerror (err)); + goto cleanup; + } + pf_key_v2_msg_free (ret); + + log_debug (LOG_MISC, 50, "pf_key_v2_enable_spi: done"); + + return 0; + + cleanup: + if (addr) + free (addr); + if (addflow) + pf_key_v2_msg_free (addflow); + if (ret) + pf_key_v2_msg_free (ret); + return -1; + +#else + log_error ("pf_key_v2_enable_spi: not supported in pure PF_KEYv2"); + return -1; +#endif +} + +/* + * Establish an encap route. + * XXX This is not really belonging in the PF_KEYv2 glue, it should be moved + * to sysdep.c + */ +int +pf_key_v2_route (in_addr_t laddr, in_addr_t lmask, in_addr_t raddr, + in_addr_t rmask, u_int32_t spi, in_addr_t dst, char *conn) +{ + log_print ("pf_key_v2_route: not implemented"); + return -1; +} + +static void +pf_key_v2_notify (struct pf_key_v2_msg *msg) +{ + log_debug (LOG_SYSDEP, 80, "pf_key_v2_notify: entered"); + + /* XXX To be implemented. */ + + pf_key_v2_msg_free (msg); +} + +void +pf_key_v2_handler (int fd) +{ + struct pf_key_v2_msg *msg; + + 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) +{ +#ifdef 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 saddrlen, err; + size_t len; + + 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; + 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; + + sa2.sadb_sa_exttype = SADB_EXT_X_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; + + /* + * Setup the ADDRESS extensions. + * + * XXX Addresses has to be thought through. Assumes IPv4. + */ + if (incoming) + sa->transport->vtbl->get_src (sa->transport, &saddr, &saddrlen); + else + sa->transport->vtbl->get_dst (sa->transport, &saddr, &saddrlen); + len = sizeof *addr + PF_KEY_V2_ROUND (saddrlen); + addr = malloc (len); + if (!addr) + goto cleanup; + addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST; + addr->sadb_address_len = len / PF_KEY_V2_CHUNK; +#if 0 + addr->sadb_address_proto = 0; + addr->sadb_address_prefixlen = 0; +#endif + addr->sadb_address_reserved = 0; + memcpy (addr + 1, saddr, saddrlen); + ((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 = malloc (len); + if (!addr) + goto cleanup; + addr->sadb_address_exttype = SADB_EXT_X_DST2; + addr->sadb_address_len = len / PF_KEY_V2_CHUNK; +#if 0 + addr->sadb_address_proto = 0; + addr->sadb_address_prefixlen = 0; +#endif + addr->sadb_address_reserved = 0; + memcpy (addr + 1, saddr, saddrlen); + ((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_EXT_X_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; + default: + log_print ("pf_key_v2_group_spis: invalid proto %d", proto2->proto); + goto cleanup; + } + protocol.sadb_protocol_reserved1 = 0; + 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_debug (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 + log_error ("pf_key_v2_group_spis: not supported in pure PF_KEYv2"); + return -1; +#endif +} diff --git a/sbin/isakmpd/pf_key_v2.h b/sbin/isakmpd/pf_key_v2.h new file mode 100644 index 00000000000..a90564ec0ad --- /dev/null +++ b/sbin/isakmpd/pf_key_v2.h @@ -0,0 +1,61 @@ +/* $OpenBSD: pf_key_v2.h,v 1.1 1999/03/24 14:37:13 niklas Exp $ */ +/* $EOM: pf_key_v2.h,v 1.1 1999/03/24 11:09:19 niklas Exp $ */ + +/* + * Copyright (c) 1999 Niklas Hallqvist. 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Ericsson Radio Systems. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * 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. + */ + +#ifndef _PF_KEY_V2_H_ +#define _PF_KEY_V2_H_ + +#include <sys/types.h> +#include <sys/queue.h> + +struct proto; +struct sa; +struct sockaddr; + +extern int pf_key_v2_delete_spi (struct sa *, struct proto *, int); +extern int pf_key_v2_enable_sa (struct sa *); +extern int pf_key_v2_enable_spi (in_addr_t, in_addr_t, in_addr_t, in_addr_t, + u_int8_t *, u_int8_t, in_addr_t); +extern u_int8_t *pf_key_v2_get_spi (size_t *, u_int8_t, struct sockaddr *, int, + struct sockaddr *, int); +extern int pf_key_v2_group_spis (struct sa *, struct proto *, struct proto *, + int); +extern void pf_key_v2_handler (int); +extern int pf_key_v2_open (void); +extern int pf_key_v2_route (in_addr_t, in_addr_t, in_addr_t, in_addr_t, + u_int32_t, in_addr_t, char *); +extern int pf_key_v2_set_spi (struct sa *, struct proto *, int); + +#endif /* _PF_KEY_V2_H_ */ |