diff options
Diffstat (limited to 'keyexchange/isakmpd-20041012/dpd.c')
-rw-r--r-- | keyexchange/isakmpd-20041012/dpd.c | 374 |
1 files changed, 0 insertions, 374 deletions
diff --git a/keyexchange/isakmpd-20041012/dpd.c b/keyexchange/isakmpd-20041012/dpd.c deleted file mode 100644 index 4351637..0000000 --- a/keyexchange/isakmpd-20041012/dpd.c +++ /dev/null @@ -1,374 +0,0 @@ -/* $OpenBSD: dpd.c,v 1.4 2004/08/10 15:59:10 ho Exp $ */ - -/* - * Copyright (c) 2004 Håkan Olsson. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <sys/types.h> -#include <stdlib.h> -#include <memory.h> - -#include "sysdep.h" - -#include "conf.h" -#include "dpd.h" -#include "exchange.h" -#include "hash.h" -#include "ipsec.h" -#include "isakmp_fld.h" -#include "log.h" -#include "message.h" -#include "sa.h" -#include "timer.h" -#include "transport.h" -#include "util.h" - -/* From RFC 3706. */ -#define DPD_MAJOR 0x01 -#define DPD_MINOR 0x00 -#define DPD_SEQNO_SZ 4 - -static const char dpd_vendor_id[] = { - 0xAF, 0xCA, 0xD7, 0x13, 0x68, 0xA1, 0xF1, /* RFC 3706 */ - 0xC9, 0x6B, 0x86, 0x96, 0xFC, 0x77, 0x57, - DPD_MAJOR, - DPD_MINOR -}; - -#define DPD_RETRANS_MAX 5 /* max number of retries. */ -#define DPD_RETRANS_WAIT 5 /* seconds between retries. */ - -/* DPD Timer State */ -enum dpd_tstate { DPD_TIMER_NORMAL, DPD_TIMER_CHECK }; - -static void dpd_check_event(void *); -static void dpd_event(void *); -static u_int32_t dpd_timer_interval(u_int32_t); -static void dpd_timer_reset(struct sa *, u_int32_t, enum dpd_tstate); - -/* Add the DPD VENDOR ID payload. */ -int -dpd_add_vendor_payload(struct message *msg) -{ - u_int8_t *buf; - size_t buflen = sizeof dpd_vendor_id + ISAKMP_GEN_SZ; - - buf = malloc(buflen); - if (!buf) { - log_error("dpd_add_vendor_payload: malloc(%lu) failed", - (unsigned long)buflen); - return -1; - } - - SET_ISAKMP_GEN_LENGTH(buf, buflen); - memcpy(buf + ISAKMP_VENDOR_ID_OFF, dpd_vendor_id, - sizeof dpd_vendor_id); - if (message_add_payload(msg, ISAKMP_PAYLOAD_VENDOR, buf, buflen, 1)) { - free(buf); - return -1; - } - - return 0; -} - -/* - * Check an incoming message for DPD capability markers. - */ -void -dpd_check_vendor_payload(struct message *msg, struct payload *p) -{ - u_int8_t *pbuf = p->p; - size_t vlen; - - /* Already checked? */ - if (msg->exchange->flags & EXCHANGE_FLAG_DPD_CAP_PEER) { - /* Just mark it as handled and return. */ - p->flags |= PL_MARK; - return; - } - - vlen = GET_ISAKMP_GEN_LENGTH(pbuf) - ISAKMP_GEN_SZ; - if (vlen != sizeof dpd_vendor_id) { - LOG_DBG((LOG_EXCHANGE, 90, - "dpd_check_vendor_payload: bad size %d != %d", vlen, - sizeof dpd_vendor_id)); - return; - } - - if (memcmp(dpd_vendor_id, pbuf + ISAKMP_GEN_SZ, vlen) == 0) { - /* This peer is DPD capable. */ - if (msg->isakmp_sa) { - msg->exchange->flags |= EXCHANGE_FLAG_DPD_CAP_PEER; - LOG_DBG((LOG_EXCHANGE, 10, "dpd_check_vendor_payload: " - "DPD capable peer detected")); - if (dpd_timer_interval(0) != 0) { - LOG_DBG((LOG_EXCHANGE, 10, - "dpd_check_vendor_payload: enabling")); - msg->isakmp_sa->flags |= SA_FLAG_DPD; - dpd_timer_reset(msg->isakmp_sa, 0, - DPD_TIMER_NORMAL); - } - } - p->flags |= PL_MARK; - } - return; -} - -/* - * All incoming DPD Notify messages enter here. Message has been validated. - */ -void -dpd_handle_notify(struct message *msg, struct payload *p) -{ - struct sa *isakmp_sa = msg->isakmp_sa; - u_int16_t notify = GET_ISAKMP_NOTIFY_MSG_TYPE(p->p); - u_int32_t p_seq; - - /* Extract the sequence number. */ - memcpy(&p_seq, p->p + ISAKMP_NOTIFY_SPI_OFF + ISAKMP_HDR_COOKIES_LEN, - sizeof p_seq); - p_seq = ntohl(p_seq); - - LOG_DBG((LOG_MESSAGE, 40, "dpd_handle_notify: got %s seq %u", - constant_name(isakmp_notify_cst, notify), p_seq)); - - switch (notify) { - case ISAKMP_NOTIFY_STATUS_DPD_R_U_THERE: - /* The other peer wants to know we're alive. */ - if (p_seq <= isakmp_sa->dpd_rseq) { - log_print("dpd_handle_notify: bad R_U_THERE seqno " - "%u <= %u", p_seq, isakmp_sa->dpd_rseq); - return; - } - isakmp_sa->dpd_rseq = p_seq; - message_send_dpd_notify(isakmp_sa, - ISAKMP_NOTIFY_STATUS_DPD_R_U_THERE_ACK, p_seq); - break; - - case ISAKMP_NOTIFY_STATUS_DPD_R_U_THERE_ACK: - /* This should be a response to a R_U_THERE we've sent. */ - if (isakmp_sa->dpd_seq != p_seq) { - log_print("dpd_handle_notify: got bad ACK seqno %u, " - "expected %u", p_seq, isakmp_sa->dpd_seq); - /* XXX Give up? Retry? */ - return; - } - break; - default: - ; - } - - /* Mark handled. */ - p->flags |= PL_MARK; - - /* The other peer is alive, so we can safely wait a while longer. */ - if (isakmp_sa->flags & SA_FLAG_DPD) - dpd_timer_reset(isakmp_sa, 0, DPD_TIMER_NORMAL); -} - -/* Calculate the time until next DPD exchange. */ -static u_int32_t -dpd_timer_interval(u_int32_t offset) -{ - int32_t v = 0; - -#ifdef notyet - v = ...; /* XXX Per-peer specified DPD intervals? */ -#endif - if (!v) - v = conf_get_num("General", "DPD-check-interval", 0); - if (v < 1) - return 0; /* DPD-Check-Interval < 1 means disable DPD */ - - v -= offset; - return v < 1 ? 1 : v; -} - -static void -dpd_timer_reset(struct sa *sa, u_int32_t time_passed, enum dpd_tstate mode) -{ - struct timeval tv; - - if (sa->dpd_event) - timer_remove_event(sa->dpd_event); - - gettimeofday(&tv, 0); - switch (mode) { - case DPD_TIMER_NORMAL: - tv.tv_sec += dpd_timer_interval(time_passed); - sa->dpd_event = timer_add_event("dpd_event", dpd_event, sa, - &tv); - break; - case DPD_TIMER_CHECK: - tv.tv_sec += DPD_RETRANS_WAIT; - sa->dpd_event = timer_add_event("dpd_check_event", - dpd_check_event, sa, &tv); - break; - default: - ; - } - if (!sa->dpd_event) - log_print("dpd_timer_reset: timer_add_event failed"); -} - -/* Helper function for dpd_exchange_finalization(). */ -static int -dpd_find_sa(struct sa *sa, void *v_sa) -{ - struct sa *isakmp_sa = v_sa; - - return (sa->phase == 2 && - memcmp(sa->id_i, isakmp_sa->id_i, sa->id_i_len) == 0 && - memcmp(sa->id_r, isakmp_sa->id_r, sa->id_r_len) == 0); -} - -struct dpd_args { - struct sa *isakmp_sa; - u_int32_t interval; -}; - -/* Helper function for dpd_event(). */ -static int -dpd_check_time(struct sa *sa, void *v_arg) -{ - struct dpd_args *args = v_arg; - struct sockaddr *dst; - struct proto *proto; - struct sa_kinfo *ksa; - struct timeval tv; - - if (sa->phase == 1 || (args->isakmp_sa->flags & SA_FLAG_DPD) == 0 || - dpd_find_sa(sa, args->isakmp_sa) == 0) - return 0; - - proto = TAILQ_FIRST(&sa->protos); - if (!proto || !proto->data) - return 0; - sa->transport->vtbl->get_src(sa->transport, &dst); - - gettimeofday(&tv, 0); - ksa = sysdep_ipsec_get_kernel_sa(proto->spi[1], proto->spi_sz[1], - proto->proto, dst); - - if (!ksa || !ksa->last_used) - return 0; - - LOG_DBG((LOG_MESSAGE, 80, "dpd_check_time: " - "SA %p last use %u second(s) ago", sa, - (u_int32_t)(tv.tv_sec - ksa->last_used))); - - if ((u_int32_t)(tv.tv_sec - ksa->last_used) < args->interval) { - args->interval = (u_int32_t)(tv.tv_sec - ksa->last_used); - return 1; - } - - return 0; -} - -/* Called by the timer. */ -static void -dpd_event(void *v_sa) -{ - struct sa *isakmp_sa = v_sa; - struct dpd_args args; -#if defined (USE_DEBUG) - struct sockaddr *dst; - char *addr; -#endif - - isakmp_sa->dpd_event = 0; - - /* Check if there's been any incoming SA activity since last time. */ - args.isakmp_sa = isakmp_sa; - args.interval = dpd_timer_interval(0); - if (sa_find(dpd_check_time, &args)) { - if (args.interval > dpd_timer_interval(0)) - args.interval = 0; - dpd_timer_reset(isakmp_sa, args.interval, DPD_TIMER_NORMAL); - return; - } - - /* No activity seen, do a DPD exchange. */ - if (isakmp_sa->dpd_seq == 0) { - /* - * RFC 3706: first seq# should be random, with MSB zero, - * otherwise we just increment it. - */ - getrandom((u_int8_t *)&isakmp_sa->dpd_seq, - sizeof isakmp_sa->dpd_seq); - isakmp_sa->dpd_seq &= 0x7FFF; - } else - isakmp_sa->dpd_seq++; - -#if defined (USE_DEBUG) - isakmp_sa->transport->vtbl->get_dst(isakmp_sa->transport, &dst); - if (sockaddr2text(dst, &addr, 0) == -1) - addr = 0; - LOG_DBG((LOG_MESSAGE, 30, "dpd_event: sending R_U_THERE to %s seq %u", - addr ? addr : "<unknown>", isakmp_sa->dpd_seq)); - if (addr) - free(addr); -#endif - message_send_dpd_notify(isakmp_sa, ISAKMP_NOTIFY_STATUS_DPD_R_U_THERE, - isakmp_sa->dpd_seq); - - /* And set the short timer. */ - dpd_timer_reset(isakmp_sa, 0, DPD_TIMER_CHECK); -} - -/* - * Called by the timer. If this function is called, it means we did not - * recieve any R_U_THERE_ACK confirmation from the other peer. - */ -static void -dpd_check_event(void *v_sa) -{ - struct sa *isakmp_sa = v_sa; - struct sa *sa; - - isakmp_sa->dpd_event = 0; - - if (++isakmp_sa->dpd_failcount < DPD_RETRANS_MAX) { - LOG_DBG((LOG_MESSAGE, 10, "dpd_check_event: " - "peer not responding, retry %u of %u", - isakmp_sa->dpd_failcount, DPD_RETRANS_MAX)); - message_send_dpd_notify(isakmp_sa, - ISAKMP_NOTIFY_STATUS_DPD_R_U_THERE, isakmp_sa->dpd_seq); - dpd_timer_reset(isakmp_sa, 0, DPD_TIMER_CHECK); - return; - } - - /* - * Peer is considered dead. Delete all SAs created under isakmp_sa. - */ - LOG_DBG((LOG_MESSAGE, 10, "dpd_check_event: peer is dead, " - "deleting all SAs connected to SA %p", isakmp_sa)); - while ((sa = sa_find(dpd_find_sa, isakmp_sa)) != 0) { - LOG_DBG((LOG_MESSAGE, 30, "dpd_check_event: deleting SA %p", - sa)); - sa_delete(sa, 0); - } - LOG_DBG((LOG_MESSAGE, 30, "dpd_check_event: deleting ISAKMP SA %p", - isakmp_sa)); - sa_delete(isakmp_sa, 0); -} |