summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormarkus <markus@openbsd.org>2014-05-06 10:24:22 +0000
committermarkus <markus@openbsd.org>2014-05-06 10:24:22 +0000
commit6e1880a370e900a61835ebbc2c8987bf2809accd (patch)
tree7b425683ec02f678fb17d1c1a6e2ab7583dc824b
parentFix a memleak when lookup of SA fails during forwarding of encrypted IPv6 (diff)
downloadwireguard-openbsd-6e1880a370e900a61835ebbc2c8987bf2809accd.tar.xz
wireguard-openbsd-6e1880a370e900a61835ebbc2c8987bf2809accd.zip
initiate ike sa rekeying (ikesalifetime keyword), re-queue pfkey
events while we are busy initiating child-SAs; ok mikeb@
-rw-r--r--sbin/iked/config.c3
-rw-r--r--sbin/iked/iked.conf.512
-rw-r--r--sbin/iked/iked.h16
-rw-r--r--sbin/iked/ikev2.c410
-rw-r--r--sbin/iked/ikev2.h5
-rw-r--r--sbin/iked/ikev2_msg.c18
-rw-r--r--sbin/iked/ikev2_pld.c10
-rw-r--r--sbin/iked/parse.y30
-rw-r--r--sbin/iked/pfkey.c81
-rw-r--r--sbin/iked/policy.c18
10 files changed, 469 insertions, 134 deletions
diff --git a/sbin/iked/config.c b/sbin/iked/config.c
index 1c6ee7c4756..00f0b9de7d7 100644
--- a/sbin/iked/config.c
+++ b/sbin/iked/config.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: config.c,v 1.29 2014/05/06 09:48:40 markus Exp $ */
+/* $OpenBSD: config.c,v 1.30 2014/05/06 10:24:22 markus Exp $ */
/*
* Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org>
@@ -79,6 +79,7 @@ void
config_free_sa(struct iked *env, struct iked_sa *sa)
{
timer_del(env, &sa->sa_timer);
+ timer_del(env, &sa->sa_rekey);
config_free_proposals(&sa->sa_proposals, 0);
config_free_childsas(env, &sa->sa_childsas, NULL, NULL);
diff --git a/sbin/iked/iked.conf.5 b/sbin/iked/iked.conf.5
index 0428f89a672..efaa51896ab 100644
--- a/sbin/iked/iked.conf.5
+++ b/sbin/iked/iked.conf.5
@@ -1,4 +1,4 @@
-.\" $OpenBSD: iked.conf.5,v 1.30 2014/04/28 16:23:19 jmc Exp $
+.\" $OpenBSD: iked.conf.5,v 1.31 2014/05/06 10:24:22 markus Exp $
.\"
.\" Copyright (c) 2010 - 2014 Reyk Floeter <reyk@openbsd.org>
.\" Copyright (c) 2004 Mathieu Sauve-Frankel All rights reserved.
@@ -15,7 +15,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: April 28 2014 $
+.Dd $Mdocdate: May 6 2014 $
.Dt IKED.CONF 5
.Os
.Sh NAME
@@ -435,6 +435,14 @@ is similar to
.Ic srcid ,
but instead specifies the ID to be used
by the remote peer.
+.It Ic ikelifetime Ar time
+The optional
+.Ic ikelifetime
+parameter defines the IKE SA expiration timeout by the
+.Ar time
+SA was in created.
+A zero value disables active IKE SA rekeying.
+This is the default.
.It Ic lifetime Ar time Op Ic bytes Ar bytes
The optional
.Ic lifetime
diff --git a/sbin/iked/iked.h b/sbin/iked/iked.h
index 59321aedc6a..a386ded6873 100644
--- a/sbin/iked/iked.h
+++ b/sbin/iked/iked.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: iked.h,v 1.75 2014/05/06 07:24:37 markus Exp $ */
+/* $OpenBSD: iked.h,v 1.76 2014/05/06 10:24:22 markus Exp $ */
/*
* Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org>
@@ -274,7 +274,8 @@ struct iked_policy {
struct iked_cfg pol_cfg[IKED_CFG_MAX];
u_int pol_ncfg;
- struct iked_lifetime pol_lifetime;
+ u_int32_t pol_rekey; /* ike SA lifetime */
+ struct iked_lifetime pol_lifetime; /* child SA lifetime */
struct iked_sapeers pol_sapeers;
@@ -411,6 +412,7 @@ struct iked_sa {
struct iked_childsas sa_childsas; /* IPSec Child SAs */
struct iked_saflows sa_flows; /* IPSec flows */
+ struct iked_sa *sa_next; /* IKE SA rekeying */
u_int64_t sa_rekeyspi; /* peerspi for rekey*/
u_int8_t sa_ipcomp; /* IPcomp transform */
@@ -418,9 +420,11 @@ struct iked_sa {
u_int16_t sa_cpi_in; /* IPcomp incoming*/
struct iked_timer sa_timer; /* SA timeouts */
-#define IKED_IKE_SA_REKEY_TIMEOUT 300 /* 5 minutes */
+#define IKED_IKE_SA_DELETE_TIMEOUT 300 /* 5 minutes */
#define IKED_IKE_SA_ALIVE_TIMEOUT 60 /* 1 minute */
+ struct iked_timer sa_rekey; /* rekey timeout */
+
struct iked_msgqueue sa_requests; /* request queue */
#define IKED_RETRANSMIT_TIMEOUT 2 /* 2 seconds */
@@ -751,10 +755,10 @@ struct ikev2_payload *
ikev2_add_payload(struct ibuf *);
int ikev2_next_payload(struct ikev2_payload *, size_t,
u_int8_t);
-void ikev2_acquire_sa(struct iked *, struct iked_flow *);
+int ikev2_acquire_sa(struct iked *, struct iked_flow *);
void ikev2_disable_rekeying(struct iked *, struct iked_sa *);
-void ikev2_rekey_sa(struct iked *, struct iked_spi *);
-void ikev2_drop_sa(struct iked *, struct iked_spi *);
+int ikev2_rekey_sa(struct iked *, struct iked_spi *);
+int ikev2_drop_sa(struct iked *, struct iked_spi *);
int ikev2_print_id(struct iked_id *, char *, size_t);
/* ikev2_msg.c */
diff --git a/sbin/iked/ikev2.c b/sbin/iked/ikev2.c
index 02fdf026d09..c4fce4d69bc 100644
--- a/sbin/iked/ikev2.c
+++ b/sbin/iked/ikev2.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ikev2.c,v 1.106 2014/05/06 09:48:40 markus Exp $ */
+/* $OpenBSD: ikev2.c,v 1.107 2014/05/06 10:24:22 markus Exp $ */
/*
* Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org>
@@ -73,13 +73,16 @@ int ikev2_resp_ike_eap(struct iked *, struct iked_sa *, struct ibuf *);
int ikev2_send_create_child_sa(struct iked *, struct iked_sa *,
struct iked_spi *, u_int8_t);
+int ikev2_ikesa_enable(struct iked *, struct iked_sa *, struct iked_sa *);
+void ikev2_ikesa_delete(struct iked *, struct iked_sa *, int);
int ikev2_init_create_child_sa(struct iked *, struct iked_message *);
int ikev2_resp_create_child_sa(struct iked *, struct iked_message *);
+void ikev2_ike_sa_rekey(struct iked *, void *);
void ikev2_ike_sa_timeout(struct iked *env, void *);
void ikev2_ike_sa_alive(struct iked *, void *);
int ikev2_sa_initiator(struct iked *, struct iked_sa *,
- struct iked_message *);
+ struct iked_sa *, struct iked_message *);
int ikev2_sa_responder(struct iked *, struct iked_sa *, struct iked_sa *,
struct iked_message *);
int ikev2_sa_initiator_dh(struct iked_sa *, struct iked_message *, u_int);
@@ -787,7 +790,7 @@ ikev2_init_ike_sa_peer(struct iked *env, struct iked_policy *pol,
/* XXX free old sa_dhgroup ? */
sa->sa_dhgroup = pol->pol_peerdh;
- if (ikev2_sa_initiator(env, sa, NULL) == -1)
+ if (ikev2_sa_initiator(env, sa, NULL, NULL) == -1)
goto done;
if (pol->pol_local.addr.ss_family == AF_UNSPEC) {
@@ -932,7 +935,7 @@ ikev2_init_auth(struct iked *env, struct iked_message *msg)
if (sa == NULL)
return (-1);
- if (ikev2_sa_initiator(env, sa, msg) == -1) {
+ if (ikev2_sa_initiator(env, sa, NULL, msg) == -1) {
log_debug("%s: failed to get IKE keys", __func__);
return (-1);
}
@@ -1082,6 +1085,9 @@ ikev2_init_done(struct iked *env, struct iked_sa *sa)
sa_state(env, sa, IKEV2_STATE_ESTABLISHED);
timer_set(env, &sa->sa_timer, ikev2_ike_sa_alive, sa);
timer_add(env, &sa->sa_timer, IKED_IKE_SA_ALIVE_TIMEOUT);
+ timer_set(env, &sa->sa_rekey, ikev2_ike_sa_rekey, sa);
+ if (sa->sa_policy->pol_rekey)
+ timer_add(env, &sa->sa_rekey, sa->sa_policy->pol_rekey);
}
if (ret)
@@ -2212,6 +2218,9 @@ ikev2_resp_ike_auth(struct iked *env, struct iked_sa *sa)
sa_state(env, sa, IKEV2_STATE_ESTABLISHED);
timer_set(env, &sa->sa_timer, ikev2_ike_sa_alive, sa);
timer_add(env, &sa->sa_timer, IKED_IKE_SA_ALIVE_TIMEOUT);
+ timer_set(env, &sa->sa_rekey, ikev2_ike_sa_rekey, sa);
+ if (sa->sa_policy->pol_rekey)
+ timer_add(env, &sa->sa_rekey, sa->sa_policy->pol_rekey);
}
done:
@@ -2389,6 +2398,13 @@ ikev2_send_create_child_sa(struct iked *env, struct iked_sa *sa,
else
log_debug("%s: creating new CHILD SAs", __func__);
+ /* XXX cannot initiate multiple concurrent CREATE_CHILD_SA exchanges */
+ if (sa->sa_stateflags & IKED_REQ_CHILDSA) {
+ log_debug("%s: another CREATE_CHILD_SA exchange already active",
+ __func__);
+ return (-1);
+ }
+
sa->sa_rekeyspi = 0; /* clear rekey spi */
initiator = sa->sa_hdr.sh_initiator ? 1 : 0;
@@ -2524,12 +2540,110 @@ done:
return (ret);
}
+void
+ikev2_ike_sa_rekey(struct iked *env, void *arg)
+{
+ struct iked_sa *sa = arg;
+ struct iked_sa *nsa = NULL;
+ struct ikev2_payload *pld = NULL;
+ struct ikev2_keyexchange *ke;
+ struct group *group;
+ struct ibuf *e = NULL, *nonce = NULL;
+ ssize_t len = 0;
+ int ret = -1;
+
+ log_debug("%s: called for IKE SA %p", __func__, sa);
+
+ if (sa->sa_stateflags & IKED_REQ_CHILDSA) {
+ /*
+ * We cannot initiate multiple concurrent CREATE_CHILD_SA
+ * exchanges, so retry in one minute.
+ */
+ timer_add(env, &sa->sa_rekey, 60);
+ return;
+ }
+
+ if ((nsa = sa_new(env, 0, 0, 1, sa->sa_policy)) == NULL) {
+ log_debug("%s: failed to get new SA", __func__);
+ goto done;
+ }
+
+ if (ikev2_sa_initiator(env, nsa, sa, NULL)) {
+ log_debug("%s: failed to setup DH", __func__);
+ goto done;
+ }
+ sa_state(env, nsa, IKEV2_STATE_AUTH_SUCCESS);
+ nonce = nsa->sa_inonce;
+
+ if ((e = ibuf_static()) == NULL)
+ goto done;
+
+ /* SA payload */
+ if ((pld = ikev2_add_payload(e)) == NULL)
+ goto done;
+
+ /* just reuse the old IKE SA proposals */
+ if ((len = ikev2_add_proposals(env, nsa, e, &sa->sa_proposals,
+ IKEV2_SAPROTO_IKE, 1, 1)) == -1)
+ goto done;
+
+ if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_NONCE) == -1)
+ goto done;
+
+ /* NONCE payload */
+ if ((pld = ikev2_add_payload(e)) == NULL)
+ goto done;
+ if (ikev2_add_buf(e, nonce) == -1)
+ goto done;
+ len = ibuf_size(nonce);
+
+ if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_KE) == -1)
+ goto done;
+
+ /* KE payload */
+ if ((pld = ikev2_add_payload(e)) == NULL)
+ goto done;
+ if ((ke = ibuf_advance(e, sizeof(*ke))) == NULL)
+ goto done;
+ if ((group = nsa->sa_dhgroup) == NULL) {
+ log_debug("%s: invalid dh", __func__);
+ goto done;
+ }
+ ke->kex_dhgroup = htobe16(group->id);
+ if (ikev2_add_buf(e, nsa->sa_dhiexchange) == -1)
+ goto done;
+ len = sizeof(*ke) + dh_getlen(group);
+
+ if (ikev2_next_payload(pld, len, IKEV2_PAYLOAD_NONE) == -1)
+ goto done;
+
+ ret = ikev2_msg_send_encrypt(env, sa, &e,
+ IKEV2_EXCHANGE_CREATE_CHILD_SA, IKEV2_PAYLOAD_SA, 0);
+ if (ret == 0) {
+ sa->sa_stateflags |= IKED_REQ_CHILDSA;
+ sa->sa_next = nsa;
+ nsa = NULL;
+ }
+done:
+ if (nsa)
+ sa_free(env, nsa);
+ ibuf_release(e);
+
+ if (ret == 0)
+ log_debug("%s: create child SA sent", __func__);
+ else
+ log_debug("%s: could not send create child SA", __func__);
+ /* XXX should we try again in case of ret != 0 ? */
+}
+
int
ikev2_init_create_child_sa(struct iked *env, struct iked_message *msg)
{
struct iked_childsa *csa = NULL;
struct iked_proposal *prop;
struct iked_sa *sa = msg->msg_sa;
+ struct iked_sa *nsa;
+ struct iked_spi *spi;
struct ikev2_delete *del;
struct ibuf *buf = NULL;
u_int32_t spi32;
@@ -2561,6 +2675,33 @@ ikev2_init_create_child_sa(struct iked *env, struct iked_message *msg)
return (-1);
}
+ /* IKE SA rekeying */
+ if (prop->prop_protoid == IKEV2_SAPROTO_IKE) {
+ if (sa->sa_next == NULL) {
+ log_debug("%s: missing IKE SA for rekeying", __func__);
+ return (-1);
+ }
+ /* Update the responder SPI */
+ spi = &msg->msg_prop->prop_peerspi;
+ if ((nsa = sa_new(env, sa->sa_next->sa_hdr.sh_ispi,
+ spi->spi, 1, NULL)) == NULL || nsa != sa->sa_next) {
+ log_debug("%s: invalid rekey SA", __func__);
+ if (nsa)
+ sa_free(env, nsa);
+ sa_free(env, sa->sa_next);
+ sa->sa_next = NULL;
+ return (-1);
+ }
+ if (ikev2_sa_initiator(env, nsa, sa, msg) == -1) {
+ log_debug("%s: failed to get IKE keys", __func__);
+ return (-1);
+ }
+ sa->sa_stateflags &= ~IKED_REQ_CHILDSA;
+ sa->sa_next = NULL;
+ return (ikev2_ikesa_enable(env, sa, nsa));
+ }
+
+ /* Child SA rekeying */
if (sa->sa_rekeyspi &&
(csa = childsa_lookup(sa, sa->sa_rekeyspi, prop->prop_protoid))
!= NULL) {
@@ -2635,11 +2776,163 @@ done:
}
int
-ikev2_resp_create_child_sa(struct iked *env, struct iked_message *msg)
+ikev2_ikesa_enable(struct iked *env, struct iked_sa *sa, struct iked_sa *nsa)
{
struct iked_childsa *csa, *nextcsa;
struct iked_flow *flow, *nextflow;
struct iked_proposal *prop, *nextprop;
+ int initiator;
+
+ log_debug("%s: IKE SA %p ispi %s rspi %s replaced"
+ " by SA %p ispi %s rspi %s ",
+ __func__, sa,
+ print_spi(sa->sa_hdr.sh_ispi, 8),
+ print_spi(sa->sa_hdr.sh_rspi, 8),
+ nsa,
+ print_spi(nsa->sa_hdr.sh_ispi, 8),
+ print_spi(nsa->sa_hdr.sh_rspi, 8));
+
+ /*
+ * Transfer policy and address:
+ * - Remember if we initiated the original IKE-SA because of our policy.
+ * - Note that sa_address() will insert the new SA when we set sa_peer.
+ */
+ initiator = !memcmp(&sa->sa_polpeer, &sa->sa_policy->pol_peer,
+ sizeof(sa->sa_polpeer));
+ nsa->sa_policy = sa->sa_policy;
+ RB_REMOVE(iked_sapeers, &sa->sa_policy->pol_sapeers, sa);
+ sa->sa_policy = NULL;
+ if (sa_address(nsa, &nsa->sa_peer, &sa->sa_peer.addr,
+ initiator) == -1 ||
+ sa_address(nsa, &nsa->sa_local, &sa->sa_local.addr,
+ initiator) == -1) {
+ /* reinsert old SA :/ */
+ sa->sa_policy = nsa->sa_policy;
+ if (RB_FIND(iked_sapeers, &nsa->sa_policy->pol_sapeers, nsa))
+ RB_REMOVE(iked_sapeers, &nsa->sa_policy->pol_sapeers, nsa);
+ RB_INSERT(iked_sapeers, &sa->sa_policy->pol_sapeers, sa);
+ nsa->sa_policy = NULL;
+ return (-1);
+ }
+
+ /* Transfer socket and NAT information */
+ nsa->sa_fd = sa->sa_fd;
+ nsa->sa_natt = sa->sa_natt;
+ nsa->sa_udpencap = sa->sa_udpencap;
+
+ /* Transfer all Child SAs and flows from the old IKE SA */
+ for (flow = TAILQ_FIRST(&sa->sa_flows); flow != NULL;
+ flow = nextflow) {
+ nextflow = TAILQ_NEXT(flow, flow_entry);
+ TAILQ_REMOVE(&sa->sa_flows, flow, flow_entry);
+ TAILQ_INSERT_TAIL(&nsa->sa_flows, flow,
+ flow_entry);
+ flow->flow_ikesa = nsa;
+ flow->flow_local = &nsa->sa_local;
+ flow->flow_peer = &nsa->sa_peer;
+ }
+ for (csa = TAILQ_FIRST(&sa->sa_childsas); csa != NULL;
+ csa = nextcsa) {
+ nextcsa = TAILQ_NEXT(csa, csa_entry);
+ TAILQ_REMOVE(&sa->sa_childsas, csa, csa_entry);
+ TAILQ_INSERT_TAIL(&nsa->sa_childsas, csa,
+ csa_entry);
+ csa->csa_ikesa = nsa;
+ if (csa->csa_dir == IPSP_DIRECTION_IN) {
+ csa->csa_local = &nsa->sa_peer;
+ csa->csa_peer = &nsa->sa_local;
+ } else {
+ csa->csa_local = &nsa->sa_local;
+ csa->csa_peer = &nsa->sa_peer;
+ }
+ }
+ /* Transfer all non-IKE proposals */
+ for (prop = TAILQ_FIRST(&sa->sa_proposals); prop != NULL;
+ prop = nextprop) {
+ nextprop = TAILQ_NEXT(prop, prop_entry);
+ if (prop->prop_protoid == IKEV2_SAPROTO_IKE)
+ continue;
+ TAILQ_REMOVE(&sa->sa_proposals, prop, prop_entry);
+ TAILQ_INSERT_TAIL(&nsa->sa_proposals, prop,
+ prop_entry);
+ }
+
+ /* Preserve ID information */
+ if (sa->sa_hdr.sh_initiator == nsa->sa_hdr.sh_initiator) {
+ nsa->sa_iid = sa->sa_iid;
+ nsa->sa_rid = sa->sa_rid;
+ } else {
+ /* initiator and responder role swapped */
+ nsa->sa_iid = sa->sa_rid;
+ nsa->sa_rid = sa->sa_iid;
+ }
+ /* duplicate the actual buffer */
+ nsa->sa_iid.id_buf = ibuf_dup(nsa->sa_iid.id_buf);
+ nsa->sa_rid.id_buf = ibuf_dup(nsa->sa_rid.id_buf);
+
+ /* Transfer sa_addrpool address */
+ if (sa->sa_addrpool) {
+ RB_REMOVE(iked_addrpool, &env->sc_addrpool, sa);
+ nsa->sa_addrpool = sa->sa_addrpool;
+ sa->sa_addrpool = NULL;
+ RB_INSERT(iked_addrpool, &env->sc_addrpool, nsa);
+ }
+
+ log_debug("%s: activating new IKE SA", __func__);
+ sa_state(env, nsa, IKEV2_STATE_ESTABLISHED);
+ timer_set(env, &nsa->sa_timer, ikev2_ike_sa_alive, nsa);
+ timer_add(env, &nsa->sa_timer, IKED_IKE_SA_ALIVE_TIMEOUT);
+ timer_set(env, &nsa->sa_rekey, ikev2_ike_sa_rekey, nsa);
+ if (nsa->sa_policy->pol_rekey)
+ timer_add(env, &nsa->sa_rekey, nsa->sa_policy->pol_rekey);
+ nsa->sa_stateflags = nsa->sa_statevalid; /* XXX */
+
+ /* unregister DPD keep alive timer & rekey first */
+ if (sa->sa_state == IKEV2_STATE_ESTABLISHED) {
+ timer_del(env, &sa->sa_rekey);
+ timer_del(env, &sa->sa_timer);
+ }
+
+ ikev2_ikesa_delete(env, sa, nsa->sa_hdr.sh_initiator);
+ return (0);
+}
+
+void
+ikev2_ikesa_delete(struct iked *env, struct iked_sa *sa, int initiator)
+{
+ struct ibuf *buf = NULL;
+ struct ikev2_delete *del;
+
+ if (initiator) {
+ /* Send PAYLOAD_DELETE */
+ if ((buf = ibuf_static()) == NULL)
+ goto done;
+ if ((del = ibuf_advance(buf, sizeof(*del))) == NULL)
+ goto done;
+ del->del_protoid = IKEV2_SAPROTO_IKE;
+ del->del_spisize = 0;
+ del->del_nspi = 0;
+ if (ikev2_send_ike_e(env, sa, buf, IKEV2_PAYLOAD_DELETE,
+ IKEV2_EXCHANGE_INFORMATIONAL, 0) == -1)
+ goto done;
+ log_debug("%s: sent delete, closing SA", __func__);
+done:
+ ibuf_release(buf);
+ sa_state(env, sa, IKEV2_STATE_CLOSED);
+ } else {
+ sa_state(env, sa, IKEV2_STATE_CLOSING);
+ }
+
+ /* Remove IKE-SA after timeout, e.g. if we don't get a delete */
+ timer_set(env, &sa->sa_timer, ikev2_ike_sa_timeout, sa);
+ timer_add(env, &sa->sa_timer, IKED_IKE_SA_DELETE_TIMEOUT);
+}
+
+int
+ikev2_resp_create_child_sa(struct iked *env, struct iked_message *msg)
+{
+ struct iked_childsa *csa;
+ struct iked_proposal *prop;
struct iked_sa *nsa = NULL, *sa = msg->msg_sa;
struct iked_spi *spi, *rekey = &msg->msg_rekey;
struct ikev2_keyexchange *ke;
@@ -2838,60 +3131,9 @@ ikev2_resp_create_child_sa(struct iked *env, struct iked_message *msg)
IKEV2_EXCHANGE_CREATE_CHILD_SA, firstpayload, 1)) == -1)
goto done;
- if (protoid == IKEV2_SAPROTO_IKE) {
- /* Transfer all Child SAs and flows from the old IKE SA */
- for (flow = TAILQ_FIRST(&sa->sa_flows); flow != NULL;
- flow = nextflow) {
- nextflow = TAILQ_NEXT(flow, flow_entry);
- TAILQ_REMOVE(&sa->sa_flows, flow, flow_entry);
- TAILQ_INSERT_TAIL(&nsa->sa_flows, flow,
- flow_entry);
- flow->flow_ikesa = nsa;
- }
- for (csa = TAILQ_FIRST(&sa->sa_childsas); csa != NULL;
- csa = nextcsa) {
- nextcsa = TAILQ_NEXT(csa, csa_entry);
- TAILQ_REMOVE(&sa->sa_childsas, csa, csa_entry);
- TAILQ_INSERT_TAIL(&nsa->sa_childsas, csa,
- csa_entry);
- csa->csa_ikesa = nsa;
- }
- /* Transfer all non-IKE proposals */
- for (prop = TAILQ_FIRST(&sa->sa_proposals); prop != NULL;
- prop = nextprop) {
- nextprop = TAILQ_NEXT(prop, prop_entry);
- if (prop->prop_protoid == IKEV2_SAPROTO_IKE)
- continue;
- TAILQ_REMOVE(&sa->sa_proposals, prop, prop_entry);
- TAILQ_INSERT_TAIL(&nsa->sa_proposals, prop,
- prop_entry);
- }
- /* Preserve ID information */
- nsa->sa_iid = sa->sa_iid;
- nsa->sa_iid.id_buf = ibuf_dup(sa->sa_iid.id_buf);
- nsa->sa_rid = sa->sa_rid;
- nsa->sa_rid.id_buf = ibuf_dup(sa->sa_rid.id_buf);
-
- log_debug("%s: activating new IKE SA", __func__);
- sa_state(env, nsa, IKEV2_STATE_ESTABLISHED);
- timer_set(env, &nsa->sa_timer, ikev2_ike_sa_alive, nsa);
- timer_add(env, &nsa->sa_timer, IKED_IKE_SA_ALIVE_TIMEOUT);
- nsa->sa_stateflags = sa->sa_statevalid; /* XXX */
-
- /* unregister DPD keep alive timer first */
- if (sa->sa_state == IKEV2_STATE_ESTABLISHED)
- timer_del(env, &sa->sa_timer);
- timer_set(env, &sa->sa_timer, ikev2_ike_sa_timeout, sa);
- timer_add(env, &sa->sa_timer, IKED_IKE_SA_REKEY_TIMEOUT);
-
- if (sa->sa_addrpool) {
- /* transfer sa_addrpool address */
- RB_REMOVE(iked_addrpool, &env->sc_addrpool, sa);
- nsa->sa_addrpool = sa->sa_addrpool;
- sa->sa_addrpool = NULL;
- RB_INSERT(iked_addrpool, &env->sc_addrpool, nsa);
- }
- } else
+ if (protoid == IKEV2_SAPROTO_IKE)
+ ret = ikev2_ikesa_enable(env, sa, nsa);
+ else
ret = ikev2_childsa_enable(env, sa);
done:
@@ -3290,7 +3532,7 @@ ikev2_sa_initiator_dh(struct iked_sa *sa, struct iked_message *msg, u_int proto)
int
ikev2_sa_initiator(struct iked *env, struct iked_sa *sa,
- struct iked_message *msg)
+ struct iked_sa *osa, struct iked_message *msg)
{
struct iked_transform *xform;
@@ -3374,7 +3616,7 @@ ikev2_sa_initiator(struct iked *env, struct iked_sa *sa,
return (-1);
}
- return (ikev2_sa_keys(env, sa, NULL));
+ return (ikev2_sa_keys(env, sa, osa ? osa->sa_key_d : NULL));
}
int
@@ -4457,7 +4699,8 @@ ikev2_valid_proposal(struct iked_proposal *prop,
return (0);
}
-void
+/* return 0 if processed, -1 if busy */
+int
ikev2_acquire_sa(struct iked *env, struct iked_flow *acquire)
{
struct iked_flow *flow;
@@ -4465,7 +4708,7 @@ ikev2_acquire_sa(struct iked *env, struct iked_flow *acquire)
struct iked_policy pol, *p = NULL;
if (env->sc_passive)
- return;
+ return (0);
/* First try to find an active flow with IKE SA */
flow = RB_FIND(iked_flows, &env->sc_activeflows, acquire);
@@ -4482,7 +4725,7 @@ ikev2_acquire_sa(struct iked *env, struct iked_flow *acquire)
if ((p = policy_test(env, &pol)) == NULL) {
log_warnx("%s: flow wasn't found", __func__);
- return;
+ return (0);
}
log_debug("%s: found matching policy '%s'", __func__,
@@ -4496,14 +4739,16 @@ ikev2_acquire_sa(struct iked *env, struct iked_flow *acquire)
if ((sa = flow->flow_ikesa) == NULL) {
log_warnx("%s: flow without SA", __func__);
- return;
+ return (0);
}
-
+ if (sa->sa_stateflags & IKED_REQ_CHILDSA)
+ return (-1); /* busy, retry later */
if (ikev2_send_create_child_sa(env, sa, NULL,
flow->flow_saproto) != 0)
log_warnx("%s: failed to initiate a "
"CREATE_CHILD_SA exchange", __func__);
}
+ return (0);
}
void
@@ -4519,7 +4764,8 @@ ikev2_disable_rekeying(struct iked *env, struct iked_sa *sa)
(void)ikev2_childsa_delete(env, sa, 0, 0, NULL, 1);
}
-void
+/* return 0 if processed, -1 if busy */
+int
ikev2_rekey_sa(struct iked *env, struct iked_spi *rekey)
{
struct iked_childsa *csa, key;
@@ -4528,28 +4774,32 @@ ikev2_rekey_sa(struct iked *env, struct iked_spi *rekey)
key.csa_spi = *rekey;
csa = RB_FIND(iked_activesas, &env->sc_activesas, &key);
if (!csa)
- return;
+ return (0);
if (csa->csa_rekey) /* See if it's already taken care of */
- return;
+ return (0);
if ((sa = csa->csa_ikesa) == NULL) {
log_warnx("%s: SA %s doesn't have a parent SA", __func__,
print_spi(rekey->spi, rekey->spi_size));
- return;
+ return (0);
}
if (!sa_stateok(sa, IKEV2_STATE_ESTABLISHED)) {
log_warnx("%s: SA %s is not established", __func__,
print_spi(rekey->spi, rekey->spi_size));
- return;
+ return (0);
}
+ if (sa->sa_stateflags & IKED_REQ_CHILDSA)
+ return (-1); /* busy, retry later */
if (csa->csa_allocated) /* Peer SPI died first, get the local one */
rekey->spi = csa->csa_peerspi;
if (ikev2_send_create_child_sa(env, sa, rekey, rekey->spi_protoid))
log_warnx("%s: failed to initiate a CREATE_CHILD_SA exchange",
__func__);
+ return (0);
}
-void
+/* return 0 if processed, -1 if busy */
+int
ikev2_drop_sa(struct iked *env, struct iked_spi *drop)
{
struct ibuf *buf = NULL;
@@ -4561,12 +4811,18 @@ ikev2_drop_sa(struct iked *env, struct iked_spi *drop)
key.csa_spi = *drop;
csa = RB_FIND(iked_activesas, &env->sc_activesas, &key);
if (!csa || csa->csa_rekey)
- return;
+ return (0);
+
+ sa = csa->csa_ikesa;
+ if (sa && (sa->sa_stateflags & IKED_REQ_CHILDSA))
+ return (-1); /* busy, retry later */
+
RB_REMOVE(iked_activesas, &env->sc_activesas, csa);
csa->csa_loaded = 0;
- if ((sa = csa->csa_ikesa) == NULL) {
+ csa->csa_rekey = 1; /* prevent re-loading */
+ if (sa == NULL) {
log_debug("%s: failed to find a parent SA", __func__);
- return;
+ return (0);
}
if (csa->csa_allocated)
@@ -4582,7 +4838,7 @@ ikev2_drop_sa(struct iked *env, struct iked_spi *drop)
/* Send PAYLOAD_DELETE */
if ((buf = ibuf_static()) == NULL)
- return;
+ return (0);
if ((del = ibuf_advance(buf, sizeof(*del))) == NULL)
goto done;
del->del_protoid = drop->spi_protoid;
@@ -4604,7 +4860,7 @@ ikev2_drop_sa(struct iked *env, struct iked_spi *drop)
done:
ibuf_release(buf);
- return;
+ return (0);
}
int
diff --git a/sbin/iked/ikev2.h b/sbin/iked/ikev2.h
index a1daf478d94..652cf875bea 100644
--- a/sbin/iked/ikev2.h
+++ b/sbin/iked/ikev2.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ikev2.h,v 1.14 2014/04/29 11:51:13 markus Exp $ */
+/* $OpenBSD: ikev2.h,v 1.15 2014/05/06 10:24:22 markus Exp $ */
/*
* Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org>
@@ -37,7 +37,8 @@
#define IKEV2_STATE_VALID 6 /* authenticated AND validated certs */
#define IKEV2_STATE_EAP_VALID 7 /* EAP validated */
#define IKEV2_STATE_ESTABLISHED 8 /* active IKE SA */
-#define IKEV2_STATE_CLOSED 9 /* delete this SA */
+#define IKEV2_STATE_CLOSING 9 /* expect delete for this SA */
+#define IKEV2_STATE_CLOSED 10 /* delete this SA */
extern struct iked_constmap ikev2_state_map[];
diff --git a/sbin/iked/ikev2_msg.c b/sbin/iked/ikev2_msg.c
index 29f609dcc17..85a91d8edeb 100644
--- a/sbin/iked/ikev2_msg.c
+++ b/sbin/iked/ikev2_msg.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ikev2_msg.c,v 1.33 2014/05/05 16:14:37 markus Exp $ */
+/* $OpenBSD: ikev2_msg.c,v 1.34 2014/05/06 10:24:22 markus Exp $ */
/*
* Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org>
@@ -190,8 +190,22 @@ ikev2_msg_valid_ike_sa(struct iked *env, struct ike_header *oldhdr,
struct iked_sa sa;
#endif
- if (msg->msg_sa != NULL && msg->msg_policy != NULL)
+ if (msg->msg_sa != NULL && msg->msg_policy != NULL) {
+ /*
+ * Only permit informational requests from initiator
+ * on closing SAs (for DELETE).
+ */
+ if (msg->msg_sa->sa_state == IKEV2_STATE_CLOSING) {
+ if (((oldhdr->ike_flags &
+ (IKEV2_FLAG_INITIATOR|IKEV2_FLAG_RESPONSE)) ==
+ IKEV2_FLAG_INITIATOR) &&
+ (oldhdr->ike_exchange ==
+ IKEV2_EXCHANGE_INFORMATIONAL))
+ return (0);
+ return (-1);
+ }
return (0);
+ }
#if 0
/*
diff --git a/sbin/iked/ikev2_pld.c b/sbin/iked/ikev2_pld.c
index e46da1b13d5..951085f9d3e 100644
--- a/sbin/iked/ikev2_pld.c
+++ b/sbin/iked/ikev2_pld.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ikev2_pld.c,v 1.44 2014/05/06 09:21:50 markus Exp $ */
+/* $OpenBSD: ikev2_pld.c,v 1.45 2014/05/06 10:24:22 markus Exp $ */
/*
* Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org>
@@ -1340,9 +1340,13 @@ ikev2_pld_delete(struct iked *env, struct ikev2_payload *pld,
msg->msg_parent->msg_responded = 1;
ibuf_release(resp);
sa_state(env, sa, IKEV2_STATE_CLOSED);
- return (ret);
+ } else {
+ /*
+ * We're sending a delete message. Upper layer
+ * must deal with deletion of the IKE SA.
+ */
+ ret = 0;
}
- log_debug("%s: invalid SPI size", __func__);
return (ret);
}
diff --git a/sbin/iked/parse.y b/sbin/iked/parse.y
index 1d5ab4f34dd..24cfe6bf9c4 100644
--- a/sbin/iked/parse.y
+++ b/sbin/iked/parse.y
@@ -1,4 +1,4 @@
-/* $OpenBSD: parse.y,v 1.37 2014/02/17 15:07:23 markus Exp $ */
+/* $OpenBSD: parse.y,v 1.38 2014/05/06 10:24:22 markus Exp $ */
/*
* Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org>
@@ -321,7 +321,8 @@ void copy_transforms(u_int, const struct ipsec_xf *,
int create_ike(char *, int, u_int8_t, struct ipsec_hosts *,
struct ipsec_hosts *, struct ipsec_mode *,
struct ipsec_mode *, u_int8_t,
- u_int8_t, char *, char *, struct iked_lifetime *,
+ u_int8_t, char *, char *,
+ u_int32_t, struct iked_lifetime *,
struct iked_auth *, struct ipsec_filters *,
struct ipsec_addr_wrap *);
int create_user(const char *, const char *);
@@ -370,7 +371,7 @@ typedef struct {
%token PASSIVE ACTIVE ANY TAG TAP PROTO LOCAL GROUP NAME CONFIG EAP USER
%token IKEV1 FLOW SA TCPMD5 TUNNEL TRANSPORT COUPLE DECOUPLE SET
%token INCLUDE LIFETIME BYTES INET INET6 QUICK SKIP DEFAULT
-%token IPCOMP OCSP
+%token IPCOMP OCSP IKELIFETIME
%token <v.string> STRING
%token <v.number> NUMBER
%type <v.string> string
@@ -392,7 +393,7 @@ typedef struct {
%type <v.ikekey> keyspec
%type <v.mode> ike_sa child_sa
%type <v.lifetime> lifetime
-%type <v.number> byte_spec time_spec
+%type <v.number> byte_spec time_spec ikelifetime
%type <v.string> name
%type <v.cfg> cfg ikecfg ikecfgvals
%%
@@ -446,9 +447,9 @@ user : USER STRING STRING {
;
ikev2rule : IKEV2 name ikeflags satype af proto hosts_list peers
- ike_sa child_sa ids lifetime ikeauth ikecfg filters {
+ ike_sa child_sa ids ikelifetime lifetime ikeauth ikecfg filters {
if (create_ike($2, $5, $6, $7, &$8, $9, $10, $4, $3,
- $11.srcid, $11.dstid, &$12, &$13, $15, $14) == -1)
+ $11.srcid, $11.dstid, $12, &$13, &$14, $16, $15) == -1)
YYERROR;
}
;
@@ -895,6 +896,13 @@ lifetime : /* empty */ {
}
;
+ikelifetime : /* empty */ {
+ $$ = 0;
+ }
+ | IKELIFETIME time_spec {
+ $$ = $2;
+ }
+
keyspec : STRING {
u_int8_t *hex;
@@ -1084,6 +1092,7 @@ lookup(char *s)
{ "from", FROM },
{ "group", GROUP },
{ "ike", IKEV1 },
+ { "ikelifetime", IKELIFETIME },
{ "ikesa", IKESA },
{ "ikev2", IKEV2 },
{ "include", INCLUDE },
@@ -2312,6 +2321,9 @@ print_policy(struct iked_policy *pol)
if (pol->pol_peerid.id_length != 0)
print_verbose(" dstid %s", pol->pol_peerid.id_data);
+ if (pol->pol_rekey)
+ print_verbose(" ikelifetime %u", pol->pol_rekey);
+
print_verbose(" lifetime %llu bytes %llu",
pol->pol_lifetime.lt_seconds, pol->pol_lifetime.lt_bytes);
@@ -2382,7 +2394,8 @@ int
create_ike(char *name, int af, u_int8_t ipproto, struct ipsec_hosts *hosts,
struct ipsec_hosts *peers, struct ipsec_mode *ike_sa,
struct ipsec_mode *ipsec_sa, u_int8_t saproto,
- u_int8_t flags, char *srcid, char *dstid, struct iked_lifetime *lt,
+ u_int8_t flags, char *srcid, char *dstid,
+ u_int32_t ikelifetime, struct iked_lifetime *lt,
struct iked_auth *authtype, struct ipsec_filters *filter,
struct ipsec_addr_wrap *ikecfg)
{
@@ -2508,6 +2521,9 @@ create_ike(char *name, int af, u_int8_t ipproto, struct ipsec_hosts *hosts,
pol.pol_af = ipb->af;
}
+ if (ikelifetime)
+ pol.pol_rekey = ikelifetime;
+
if (lt)
pol.pol_lifetime = *lt;
else
diff --git a/sbin/iked/pfkey.c b/sbin/iked/pfkey.c
index 892d3d03303..af360cad789 100644
--- a/sbin/iked/pfkey.c
+++ b/sbin/iked/pfkey.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfkey.c,v 1.33 2014/05/05 18:50:36 markus Exp $ */
+/* $OpenBSD: pfkey.c,v 1.34 2014/05/06 10:24:22 markus Exp $ */
/*
* Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org>
@@ -59,7 +59,7 @@ struct pfkey_message {
u_int8_t *pm_data;
ssize_t pm_length;
};
-SIMPLEQ_HEAD(, pfkey_message) pfkey_postponed =
+SIMPLEQ_HEAD(, pfkey_message) pfkey_retry, pfkey_postponed =
SIMPLEQ_HEAD_INITIALIZER(pfkey_postponed);
struct pfkey_constmap {
@@ -120,7 +120,7 @@ struct sadb_ident *
void *pfkey_find_ext(u_int8_t *, ssize_t, int);
void pfkey_timer_cb(int, short, void *);
-void pfkey_process(struct iked *, struct pfkey_message *);
+int pfkey_process(struct iked *, struct pfkey_message *);
int
pfkey_couple(int sd, struct iked_sas *sas, int couple)
@@ -1493,7 +1493,7 @@ void
pfkey_dispatch(int sd, short event, void *arg)
{
struct iked *env = (struct iked *)arg;
- struct pfkey_message pm;
+ struct pfkey_message pm, *pmp;
struct sadb_msg hdr;
ssize_t len;
u_int8_t *data;
@@ -1521,9 +1521,17 @@ pfkey_dispatch(int sd, short event, void *arg)
pm.pm_data = data;
pm.pm_length = len;
- pfkey_process(env, &pm);
- free(data);
+ if (pfkey_process(env, &pm) == -1 &&
+ (pmp = calloc(1, sizeof(*pmp))) != NULL) {
+ pmp->pm_data = data;
+ pmp->pm_length = len;
+ log_debug("%s: pfkey_process is busy, retry later", __func__);
+ SIMPLEQ_INSERT_TAIL(&pfkey_postponed, pmp, pm_entry);
+ evtimer_add(&pfkey_timer_ev, &pfkey_timer_tv);
+ } else {
+ free(data);
+ }
}
void
@@ -1532,16 +1540,32 @@ pfkey_timer_cb(int unused, short event, void *arg)
struct iked *env = arg;
struct pfkey_message *pm;
+ SIMPLEQ_INIT(&pfkey_retry);
while (!SIMPLEQ_EMPTY(&pfkey_postponed)) {
pm = SIMPLEQ_FIRST(&pfkey_postponed);
SIMPLEQ_REMOVE_HEAD(&pfkey_postponed, pm_entry);
- pfkey_process(env, pm);
- free(pm->pm_data);
- free(pm);
+ if (pfkey_process(env, pm) == -1) {
+ log_debug("%s: pfkey_process is busy, retry later",
+ __func__);
+ SIMPLEQ_INSERT_TAIL(&pfkey_retry, pm, pm_entry);
+ } else {
+ free(pm->pm_data);
+ free(pm);
+ }
+ }
+ while ((pm = SIMPLEQ_FIRST(&pfkey_retry)) != NULL) {
+ SIMPLEQ_REMOVE_HEAD(&pfkey_retry, pm_entry);
+ SIMPLEQ_INSERT_TAIL(&pfkey_postponed, pm, pm_entry);
}
+ if (!SIMPLEQ_EMPTY(&pfkey_postponed))
+ evtimer_add(&pfkey_timer_ev, &pfkey_timer_tv);
}
-void
+/*
+ * pfkey_process returns 0 if the message has been processed and -1 if
+ * the system is busy and the the message should be passed again, later.
+ */
+int
pfkey_process(struct iked *env, struct pfkey_message *pm)
{
struct iked_spi spi;
@@ -1556,7 +1580,7 @@ pfkey_process(struct iked *env, struct pfkey_message *pm)
struct sadb_x_policy sa_pol;
struct sockaddr *ssrc, *sdst, *smask, *dmask, *speer;
struct iovec iov[IOV_CNT];
- int iov_cnt, sd;
+ int ret = 0, iov_cnt, sd;
u_int8_t *reply;
ssize_t rlen;
const char *errmsg = NULL;
@@ -1565,7 +1589,7 @@ pfkey_process(struct iked *env, struct pfkey_message *pm)
size_t slen;
if (!env || !data || !len)
- return;
+ return (0);
sd = env->sc_pfkey;
hdr = (struct sadb_msg *)data;
@@ -1578,20 +1602,20 @@ pfkey_process(struct iked *env, struct pfkey_message *pm)
if ((sa_addr = pfkey_find_ext(data, len,
SADB_EXT_ADDRESS_DST)) == NULL) {
log_debug("%s: no peer address", __func__);
- return;
+ return (0);
}
speer = (struct sockaddr *)(sa_addr + 1);
peer.addr_af = speer->sa_family;
peer.addr_port = htons(socket_getport(speer));
if ((slen = speer->sa_len) > sizeof(peer.addr)) {
log_debug("%s: invalid peer address len", __func__);
- return;
+ return (0);
}
memcpy(&peer.addr, speer, slen);
if (socket_af((struct sockaddr *)&peer.addr,
peer.addr_port) == -1) {
log_debug("%s: invalid address", __func__);
- return;
+ return (0);
}
flow.flow_peer = &peer;
@@ -1624,7 +1648,7 @@ pfkey_process(struct iked *env, struct pfkey_message *pm)
if (pfkey_write(sd, &smsg, iov, iov_cnt, &reply, &rlen)) {
log_warnx("%s: failed to get a policy", __func__);
- return;
+ return (0);
}
if ((sa_addr = pfkey_find_ext(reply, rlen,
@@ -1637,13 +1661,13 @@ pfkey_process(struct iked *env, struct pfkey_message *pm)
flow.flow_src.addr_port = htons(socket_getport(ssrc));
if ((slen = ssrc->sa_len) > sizeof(flow.flow_src.addr)) {
log_debug("%s: invalid src address len", __func__);
- return;
+ return (0);
}
memcpy(&flow.flow_src.addr, ssrc, slen);
if (socket_af((struct sockaddr *)&flow.flow_src.addr,
flow.flow_src.addr_port) == -1) {
log_debug("%s: invalid address", __func__);
- return;
+ return (0);
}
if ((sa_addr = pfkey_find_ext(reply, rlen,
@@ -1656,13 +1680,13 @@ pfkey_process(struct iked *env, struct pfkey_message *pm)
flow.flow_dst.addr_port = htons(socket_getport(sdst));
if ((slen = sdst->sa_len) > sizeof(flow.flow_dst.addr)) {
log_debug("%s: invalid dst address len", __func__);
- return;
+ return (0);
}
memcpy(&flow.flow_dst.addr, sdst, slen);
if (socket_af((struct sockaddr *)&flow.flow_dst.addr,
flow.flow_dst.addr_port) == -1) {
log_debug("%s: invalid address", __func__);
- return;
+ return (0);
}
if ((sa_addr = pfkey_find_ext(reply, rlen,
@@ -1687,7 +1711,7 @@ pfkey_process(struct iked *env, struct pfkey_message *pm)
default:
log_debug("%s: bad address family", __func__);
free(reply);
- return;
+ return (0);
}
if ((sa_addr = pfkey_find_ext(reply, rlen,
@@ -1712,7 +1736,7 @@ pfkey_process(struct iked *env, struct pfkey_message *pm)
default:
log_debug("%s: bad address family", __func__);
free(reply);
- return;
+ return (0);
}
if ((sa_proto = pfkey_find_ext(reply, rlen,
@@ -1728,7 +1752,7 @@ pfkey_process(struct iked *env, struct pfkey_message *pm)
print_host(sdst, NULL, 0), print_host(dmask, NULL, 0),
print_host(speer, NULL, 0));
- ikev2_acquire_sa(env, &flow);
+ ret = ikev2_acquire_sa(env, &flow);
out:
if (errmsg)
@@ -1739,7 +1763,7 @@ out:
case SADB_EXPIRE:
if ((sa = pfkey_find_ext(data, len, SADB_EXT_SA)) == NULL) {
log_warnx("%s: SA extension wasn't found", __func__);
- return;
+ return (0);
}
if ((sa_ltime = pfkey_find_ext(data, len,
SADB_EXT_LIFETIME_SOFT)) == NULL &&
@@ -1747,7 +1771,7 @@ out:
SADB_EXT_LIFETIME_HARD)) == NULL) {
log_warnx("%s: lifetime extension wasn't found",
__func__);
- return;
+ return (0);
}
spi.spi = ntohl(sa->sadb_sa_spi);
spi.spi_size = 4;
@@ -1762,7 +1786,7 @@ out:
log_warnx("%s: usupported SA type %d spi %s",
__func__, hdr->sadb_msg_satype,
print_spi(spi.spi, spi.spi_size));
- return;
+ return (0);
}
log_debug("%s: SA %s is expired, pending %s", __func__,
@@ -1771,9 +1795,10 @@ out:
"rekeying" : "deletion");
if (sa_ltime->sadb_lifetime_exttype == SADB_EXT_LIFETIME_SOFT)
- ikev2_rekey_sa(env, &spi);
+ ret = ikev2_rekey_sa(env, &spi);
else
- ikev2_drop_sa(env, &spi);
+ ret = ikev2_drop_sa(env, &spi);
break;
}
+ return (ret);
}
diff --git a/sbin/iked/policy.c b/sbin/iked/policy.c
index e5c553ec69e..635e0051f90 100644
--- a/sbin/iked/policy.c
+++ b/sbin/iked/policy.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: policy.c,v 1.33 2014/05/06 09:48:40 markus Exp $ */
+/* $OpenBSD: policy.c,v 1.34 2014/05/06 10:24:22 markus Exp $ */
/*
* Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org>
@@ -242,7 +242,8 @@ sa_state(struct iked *env, struct iked_sa *sa, int state)
NULL, 0),
print_host((struct sockaddr *)&sa->sa_local.addr,
NULL, 0),
- sa->sa_policy->pol_name);
+ sa->sa_policy ? sa->sa_policy->pol_name :
+ "<unknown>");
break;
default:
log_debug("%s: %s -> %s", __func__, a, b);
@@ -372,6 +373,11 @@ sa_free(struct iked *env, struct iked_sa *sa)
print_spi(sa->sa_hdr.sh_ispi, 8),
print_spi(sa->sa_hdr.sh_rspi, 8));
+ /* IKE rekeying running? */
+ if (sa->sa_next) {
+ RB_REMOVE(iked_sas, &env->sc_sas, sa->sa_next);
+ config_free_sa(env, sa->sa_next);
+ }
RB_REMOVE(iked_sas, &env->sc_sas, sa);
config_free_sa(env, sa);
}
@@ -401,8 +407,8 @@ sa_address(struct iked_sa *sa, struct iked_addr *addr,
{
struct iked_policy *pol = sa->sa_policy;
- if (pol == NULL) {
- log_debug("%s: invalid policy", __func__);
+ if (sa->sa_state != IKEV2_STATE_CLOSING && pol == NULL) {
+ log_debug("%s: missing policy", __func__);
return (-1);
}
@@ -415,7 +421,7 @@ sa_address(struct iked_sa *sa, struct iked_addr *addr,
return (-1);
}
- if (addr == &sa->sa_peer) {
+ if (addr == &sa->sa_peer && pol) {
/* XXX Re-insert node into the tree */
RB_REMOVE(iked_sapeers, &pol->pol_sapeers, sa);
memcpy(&sa->sa_polpeer, initiator ? &pol->pol_peer :
@@ -471,7 +477,7 @@ sa_lookup(struct iked *env, u_int64_t ispi, u_int64_t rspi,
struct iked_sa *sa, key;
key.sa_hdr.sh_ispi = ispi;
- key.sa_hdr.sh_rspi = rspi;
+ /* key.sa_hdr.sh_rspi = rspi; */
key.sa_hdr.sh_initiator = initiator;
if ((sa = RB_FIND(iked_sas, &env->sc_sas, &key)) != NULL) {