summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sbin/isakmpd/pf_key_v2.c468
1 files changed, 301 insertions, 167 deletions
diff --git a/sbin/isakmpd/pf_key_v2.c b/sbin/isakmpd/pf_key_v2.c
index c5258f13ba2..bae8bef1a40 100644
--- a/sbin/isakmpd/pf_key_v2.c
+++ b/sbin/isakmpd/pf_key_v2.c
@@ -1,5 +1,5 @@
-/* $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 $ */
+/* $OpenBSD: pf_key_v2.c,v 1.2 1999/03/31 01:53:00 niklas Exp $ */
+/* $EOM: pf_key_v2.c,v 1.2 1999/03/31 01:32:57 niklas Exp $ */
/*
* Copyright (c) 1999 Niklas Hallqvist. All rights reserved.
@@ -35,6 +35,7 @@
*/
#include <sys/types.h>
+#include <sys/ioctl.h>
#include <sys/queue.h>
#include <sys/socket.h>
#include <sys/uio.h>
@@ -46,6 +47,7 @@
#include <unistd.h>
#include "conf.h"
+#include "exchange.h"
#include "ipsec.h"
#include "ipsec_num.h"
#include "log.h"
@@ -78,7 +80,6 @@ TAILQ_HEAD (pf_key_v2_msg, pf_key_v2_node);
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);
@@ -358,15 +359,13 @@ pf_key_v2_call (struct pf_key_v2_msg *msg)
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.
- */
+/* 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, struct pf_key_v2_node *ext,
- u_int16_t type)
+pf_key_v2_find_ext (struct pf_key_v2_msg *msg, u_int16_t type)
{
- for (ext = TAILQ_NEXT (ext ? ext : TAILQ_FIRST (msg), link); ext;
+ 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;
@@ -549,7 +548,7 @@ pf_key_v2_get_spi (size_t *sz, u_int8_t proto, struct sockaddr *src,
goto cleanup;
}
- sa = (struct sadb_sa *)pf_key_v2_find_ext (ret, 0, SADB_EXT_SA)->seg;
+ sa = (struct sadb_sa *)pf_key_v2_find_ext (ret, SADB_EXT_SA)->seg;
if (!sa)
{
log_print ("pf_key_v2_get_spi: no SA extension found");
@@ -910,21 +909,25 @@ pf_key_v2_set_spi (struct sa *sa, struct proto *proto, int incoming)
}
/*
- * Delete the IPSec SA represented by the INCOMING direction in protocol PROTO
- * of the IKE security association SA.
+ * Enable/disable a flow.
+ * XXX Assumes OpenBSD {ADD,DEL}FLOW extensions.
+ * Should probably be moved to sysdep.c
*/
-int
-pf_key_v2_delete_spi (struct sa *sa, struct proto *proto, int incoming)
+static int
+pf_key_v2_flow (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, int delete)
{
- struct sadb_msg msg;
+#if defined (SADB_X_ADDFLOW) && defined (SADB_X_DELFLOW)
+ 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;
+ struct pf_key_v2_msg *flow = 0, *ret = 0;
+ size_t len;
+ int err;
- msg.sadb_msg_type = SADB_DELETE;
- switch (proto->proto)
+ 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;
@@ -933,24 +936,30 @@ pf_key_v2_delete_spi (struct sa *sa, struct proto *proto, int incoming)
msg.sadb_msg_satype = SADB_SATYPE_AH;
break;
default:
- log_print ("pf_key_v2_delete_spi: invalid proto %d", proto->proto);
+ log_print ("pf_key_v2_flow: invalid proto %d", proto);
goto cleanup;
}
msg.sadb_msg_seq = 0;
- delete = pf_key_v2_msg_new (&msg, 0);
- if (!delete)
+ flow = pf_key_v2_msg_new (&msg, 0);
+ if (!flow)
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);
+ 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 (pf_key_v2_msg_add (delete, (struct sadb_ext *)&ssa, 0) == -1)
+ /*
+ * 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 (!delete)
+ ssa.sadb_sa_flags |= SADB_SAFLAGS_X_REPLACEFLOW;
+ if (pf_key_v2_msg_add (flow, (struct sadb_ext *)&ssa, 0) == -1)
goto cleanup;
/*
@@ -958,75 +967,145 @@ pf_key_v2_delete_spi (struct sa *sa, struct proto *proto, int incoming)
*
* 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);
+ len = sizeof *addr + PF_KEY_V2_ROUND (sizeof (struct sockaddr_in));
+ if (!delete)
+ {
+ 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 (flow, (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_ADDRESS_SRC;
+ 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;
- memcpy (addr + 1, saddr, saddrlen);
+ 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 (delete, (struct sadb_ext *)addr,
+ if (pf_key_v2_msg_add (flow, (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_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;
- memcpy (addr + 1, saddr, saddrlen);
+ 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 (delete, (struct sadb_ext *)addr,
+ if (pf_key_v2_msg_add (flow, (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;
+ 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 (flow, (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 (flow, (struct sadb_ext *)addr,
+ PF_KEY_V2_NODE_MALLOCED) == -1)
+ goto cleanup;
+ addr = 0;
+
+ log_debug (LOG_SYSDEP, 50, "pf_key_v2_flow: src %x %x dst %x %x",
+ htonl(laddr), htonl(lmask), htonl(raddr), htonl(rmask));
+
+ 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)
{
- log_print ("pf_key_v2_delete_spi: DELETE: %s", strerror (err));
+ log_print ("pf_key_v2_flow: %sFLOW: %s", delete ? "DEL" : "ADD",
+ strerror (err));
goto cleanup;
}
pf_key_v2_msg_free (ret);
- log_debug (LOG_MISC, 50, "pf_key_v2_delete_spi: done");
+ log_debug (LOG_MISC, 50, "pf_key_v2_flow: done");
return 0;
cleanup:
if (addr)
free (addr);
- if (delete)
- pf_key_v2_msg_free (delete);
+ if (flow)
+ pf_key_v2_msg_free (flow);
if (ret)
pf_key_v2_msg_free (ret);
return -1;
+
+#else
+ log_error ("pf_key_v2_flow: not supported in pure PF_KEYv2");
+ return -1;
+#endif
}
/* Enable a flow given a SA. */
@@ -1041,31 +1120,54 @@ pf_key_v2_enable_sa (struct sa *sa)
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);
+ return pf_key_v2_flow (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, 0);
+}
+
+/* Disable a flow given a SA. */
+static int
+pf_key_v2_disable_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_flow (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, 1);
}
/*
- * Enable a flow.
- * XXX Assumes OpenBSD ADDFLOW extension. Should probably be moved to sysdep.c
+ * 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_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)
+pf_key_v2_delete_spi (struct sa *sa, struct proto *proto, int incoming)
{
-#ifdef SADB_X_ADDFLOW
- struct sadb_msg msg;
+ 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;
+ struct sockaddr *saddr;
+ int saddrlen, len, err;
+ struct pf_key_v2_msg *delete = 0, *ret = 0;
- msg.sadb_msg_type = SADB_X_ADDFLOW;
- switch (proto)
+ /*
+ * If the SA was incoming and it has not yet been replaced, remove the
+ * flow associated with it.
+ * We ignore any errors from the disabling of the flow, it does not matter.
+ */
+ if (!incoming && !(sa->flags & SA_FLAG_REPLACED))
+ pf_key_v2_disable_sa (sa);
+
+ msg.sadb_msg_type = SADB_DELETE;
+ switch (proto->proto)
{
case IPSEC_PROTO_IPSEC_ESP:
msg.sadb_msg_satype = SADB_SATYPE_ESP;
@@ -1074,28 +1176,24 @@ pf_key_v2_enable_spi (in_addr_t laddr, in_addr_t lmask, in_addr_t raddr,
msg.sadb_msg_satype = SADB_SATYPE_AH;
break;
default:
- log_print ("pf_key_v2_delete_spi: invalid proto %d", proto);
+ log_print ("pf_key_v2_delete_spi: invalid proto %d", proto->proto);
goto cleanup;
}
msg.sadb_msg_seq = 0;
- addflow = pf_key_v2_msg_new (&msg, 0);
- if (!addflow)
+ 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, spi, sizeof ssa.sadb_sa_spi);
+ 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;
- /*
- * 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)
+ ssa.sadb_sa_flags = 0;
+ if (pf_key_v2_msg_add (delete, (struct sadb_ext *)&ssa, 0) == -1)
goto cleanup;
/*
@@ -1103,144 +1201,79 @@ pf_key_v2_enable_spi (in_addr_t laddr, in_addr_t lmask, in_addr_t raddr,
*
* 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;
-
+ 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_X_DST_FLOW;
+ 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;
- 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;
+ memcpy (addr + 1, saddr, saddrlen);
((struct sockaddr_in *)(addr + 1))->sin_port = 0;
- if (pf_key_v2_msg_add (addflow, (struct sadb_ext *)addr,
+ 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_X_DST_MASK;
+ 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 = rmask;
+ memcpy (addr + 1, saddr, saddrlen);
((struct sockaddr_in *)(addr + 1))->sin_port = 0;
- if (pf_key_v2_msg_add (addflow, (struct sadb_ext *)addr,
+ if (pf_key_v2_msg_add (delete, (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;
+ 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_enable_spi: ADDFLOW: %s", strerror (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_enable_spi: done");
+ log_debug (LOG_MISC, 50, "pf_key_v2_delete_spi: done");
return 0;
cleanup:
if (addr)
free (addr);
- if (addflow)
- pf_key_v2_msg_free (addflow);
+ if (delete)
+ pf_key_v2_msg_free (delete);
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.
+ * Establish an on-demand keying route.
* XXX This is not really belonging in the PF_KEYv2 glue, it should be moved
* to sysdep.c
*/
@@ -1253,12 +1286,98 @@ pf_key_v2_route (in_addr_t laddr, in_addr_t lmask, in_addr_t raddr,
}
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;
+ struct sa *sa;
+ struct pf_key_v2_node *lifenode;
+
+ msg = (struct sadb_msg *)TAILQ_FIRST (pmsg)->seg;
+ ssa = pf_key_v2_find_ext (pmsg, SADB_EXT_SA)->seg;
+ dst = pf_key_v2_find_ext (pmsg, SADB_EXT_ADDRESS_DST)->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);
+ life = lifenode->seg;
+
+ /* XXX IPv4 specific */
+ log_debug (LOG_SYSDEP, 20,
+ "pf_key_v2_expire: %s dst %s SPI %x sproto %d",
+ life->sadb_lifetime_exttype == SADB_EXT_LIFETIME_SOFT ? "SOFT"
+ : "HARD",
+ inet_ntoa (((struct sockaddr_in *)dstaddr)->sin_addr),
+ ntohl (ssa->sadb_sa_spi), msg->sadb_msg_satype);
+
+ /*
+ * 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.
+ *
+ * XXX When anything else than AH and ESP is supported this needs to change.
+ * XXX IPv4 specific.
+ */
+ sa = ipsec_sa_lookup (((struct sockaddr_in *)dstaddr)->sin_addr.s_addr,
+ ssa->sadb_sa_spi,
+ msg->sadb_msg_satype == SADB_SATYPE_ESP
+ ? IPSEC_PROTO_IPSEC_ESP : IPSEC_PROTO_IPSEC_AH);
+
+ /* If the SA is already gone, don't do anything. */
+ if (!sa)
+ return;
+
+ /*
+ * If we want this connection to stay "forever", we should renegotiate
+ * already at the soft expire, and certainly at the hard expire if we
+ * haven't started a negotiation by then. However, do not renegotiate
+ * if this SA is already obsoleted by another.
+ */
+ if ((sa->flags & (SA_FLAG_STAYALIVE | SA_FLAG_REPLACED))
+ == SA_FLAG_STAYALIVE)
+ {
+ /* If we are already renegotiating, don't start over. */
+ if (!exchange_lookup_by_name (sa->name, 2))
+ exchange_establish (sa->name, (void (*) (void *))sa_mark_replaced, sa);
+ }
+
+ if (life->sadb_lifetime_exttype == SADB_EXT_LIFETIME_HARD)
+ {
+ /*
+ * XXX We need to reestablish the on-demand route here. This we need
+ * even if we have started a new negotiation, considering it might
+ * fail.
+ */
+
+ /* Remove the old SA, it isn't useful anymore. */
+ sa_free (sa);
+ }
+}
+
+static void
pf_key_v2_notify (struct pf_key_v2_msg *msg)
{
- log_debug (LOG_SYSDEP, 80, "pf_key_v2_notify: entered");
+ switch (((struct sadb_msg *)TAILQ_FIRST (msg)->seg)->sadb_msg_type)
+ {
+ case SADB_EXPIRE:
+ pf_key_v2_expire (msg);
+ break;
- /* XXX To be implemented. */
+ case SADB_ACQUIRE:
+ log_print ("pf_key_v2_notify: ACQUIRE not yet implemented");
+ /* XXX To be implemented. */
+ 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);
}
@@ -1266,6 +1385,21 @@ void
pf_key_v2_handler (int fd)
{
struct pf_key_v2_msg *msg;
+ 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;
msg = pf_key_v2_read (0);
if (msg)