summaryrefslogtreecommitdiff
path: root/keyexchange/isakmpd-20041012/dpd.c
diff options
context:
space:
mode:
Diffstat (limited to 'keyexchange/isakmpd-20041012/dpd.c')
-rw-r--r--keyexchange/isakmpd-20041012/dpd.c374
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);
-}