summaryrefslogtreecommitdiff
path: root/sbin/iked/ikev2.c
diff options
context:
space:
mode:
Diffstat (limited to 'sbin/iked/ikev2.c')
-rw-r--r--sbin/iked/ikev2.c79
1 files changed, 72 insertions, 7 deletions
diff --git a/sbin/iked/ikev2.c b/sbin/iked/ikev2.c
index 7e72f8b48b8..5b2150b39ea 100644
--- a/sbin/iked/ikev2.c
+++ b/sbin/iked/ikev2.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ikev2.c,v 1.88 2013/12/09 15:22:32 markus Exp $ */
+/* $OpenBSD: ikev2.c,v 1.89 2014/01/22 09:25:41 markus Exp $ */
/*
* Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org>
@@ -76,6 +76,7 @@ int ikev2_send_create_child_sa(struct iked *, struct iked_sa *,
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_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 *);
@@ -1017,8 +1018,11 @@ ikev2_init_done(struct iked *env, struct iked_sa *sa)
ret = ikev2_childsa_negotiate(env, sa, sa->sa_hdr.sh_initiator);
if (ret == 0)
ret = ikev2_childsa_enable(env, sa);
- if (ret == 0)
+ if (ret == 0) {
sa_state(env, sa, IKEV2_STATE_ESTABLISHED);
+ timer_initialize(env, &sa->sa_timer, ikev2_ike_sa_alive, sa);
+ timer_register(env, &sa->sa_timer, IKED_IKE_SA_ALIVE_TIMEOUT);
+ }
if (ret)
ikev2_childsa_delete(env, sa, 0, 0, NULL, 1);
@@ -1780,6 +1784,14 @@ ikev2_resp_recv(struct iked *env, struct iked_message *msg,
case IKEV2_EXCHANGE_CREATE_CHILD_SA:
(void)ikev2_resp_create_child_sa(env, msg);
break;
+ case IKEV2_EXCHANGE_INFORMATIONAL:
+ if (!msg->msg_responded && !msg->msg_error) {
+ (void)ikev2_send_ike_e(env, sa, NULL,
+ IKEV2_PAYLOAD_NONE, IKEV2_EXCHANGE_INFORMATIONAL,
+ 1);
+ msg->msg_responded = 1;
+ }
+ break;
default:
break;
}
@@ -2056,8 +2068,11 @@ ikev2_resp_ike_auth(struct iked *env, struct iked_sa *sa)
IKEV2_EXCHANGE_IKE_AUTH, firstpayload, 1);
if (ret == 0)
ret = ikev2_childsa_enable(env, sa);
- if (ret == 0)
+ if (ret == 0) {
sa_state(env, sa, IKEV2_STATE_ESTABLISHED);
+ timer_initialize(env, &sa->sa_timer, ikev2_ike_sa_alive, sa);
+ timer_register(env, &sa->sa_timer, IKED_IKE_SA_ALIVE_TIMEOUT);
+ }
done:
if (ret)
@@ -2164,11 +2179,15 @@ ikev2_send_ike_e(struct iked *env, struct iked_sa *sa, struct ibuf *buf,
if ((pld = ikev2_add_payload(e)) == NULL)
goto done;
- if (ibuf_cat(e, buf) != 0)
- goto done;
- if (ikev2_next_payload(pld, ibuf_size(buf), IKEV2_PAYLOAD_NONE) == -1)
- goto done;
+ if (buf) {
+ if (ibuf_cat(e, buf) != 0)
+ goto done;
+
+ if (ikev2_next_payload(pld, ibuf_size(buf),
+ IKEV2_PAYLOAD_NONE) == -1)
+ goto done;
+ }
ret = ikev2_msg_send_encrypt(env, sa, &e, exchange, firstpayload,
response);
@@ -2606,8 +2625,13 @@ ikev2_resp_create_child_sa(struct iked *env, struct iked_message *msg)
log_debug("%s: activating new IKE SA", __func__);
sa_state(env, nsa, IKEV2_STATE_ESTABLISHED);
+ timer_initialize(env, &nsa->sa_timer, ikev2_ike_sa_alive, nsa);
+ timer_register(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_deregister(env, &sa->sa_timer);
timer_initialize(env, &sa->sa_timer, ikev2_ike_sa_timeout, sa);
timer_register(env, &sa->sa_timer, IKED_IKE_SA_REKEY_TIMEOUT);
} else
@@ -2629,6 +2653,47 @@ ikev2_ike_sa_timeout(struct iked *env, void *arg)
sa_free(env, sa);
}
+void
+ikev2_ike_sa_alive(struct iked *env, void *arg)
+{
+ struct iked_sa *sa = arg;
+ struct iked_childsa *csa = NULL;
+ struct timeval tv;
+ u_int64_t last_used, diff;
+ int foundin = 0, foundout = 0;
+
+ /* check for incoming traffic on any child SA */
+ TAILQ_FOREACH(csa, &sa->sa_childsas, csa_entry) {
+ if (pfkey_sa_last_used(env->sc_pfkey, csa, &last_used) != 0)
+ continue;
+ gettimeofday(&tv, NULL);
+ diff = (u_int32_t)(tv.tv_sec - last_used);
+ log_debug("%s: %s CHILD SA spi %s last used %u second(s) ago",
+ __func__,
+ csa->csa_dir == IPSP_DIRECTION_IN ? "incoming" : "outgoing",
+ print_spi(csa->csa_spi.spi, csa->csa_spi.spi_size), diff);
+ if (diff < IKED_IKE_SA_ALIVE_TIMEOUT) {
+ if (csa->csa_dir == IPSP_DIRECTION_IN) {
+ foundin = 1;
+ break;
+ } else {
+ foundout = 1;
+ }
+ }
+ }
+
+ /* send probe if any outging SA has been used, but no incoming SA */
+ if (!foundin && foundout) {
+ log_debug("%s: sending alive check", __func__);
+ ikev2_send_ike_e(env, sa, NULL, IKEV2_PAYLOAD_NONE,
+ IKEV2_EXCHANGE_INFORMATIONAL, 0);
+ sa->sa_stateflags |= IKED_REQ_INF;
+ }
+
+ /* re-register */
+ timer_register(env, &sa->sa_timer, IKED_IKE_SA_ALIVE_TIMEOUT);
+}
+
int
ikev2_send_informational(struct iked *env, struct iked_message *msg)
{