xref: /openbsd-src/sbin/isakmpd/dpd.c (revision 6ee513e5aba73254713aefffb1d985e0a57a9b85)
1*6ee513e5Sjca /*	$OpenBSD: dpd.c,v 1.20 2017/12/05 20:31:45 jca Exp $	*/
2c7adf84cSho 
3c7adf84cSho /*
4c7adf84cSho  * Copyright (c) 2004 H�kan Olsson.  All rights reserved.
5c7adf84cSho  *
6c7adf84cSho  * Redistribution and use in source and binary forms, with or without
7c7adf84cSho  * modification, are permitted provided that the following conditions
8c7adf84cSho  * are met:
9c7adf84cSho  * 1. Redistributions of source code must retain the above copyright
10c7adf84cSho  *    notice, this list of conditions and the following disclaimer.
11c7adf84cSho  * 2. Redistributions in binary form must reproduce the above copyright
12c7adf84cSho  *    notice, this list of conditions and the following disclaimer in the
13c7adf84cSho  *    documentation and/or other materials provided with the distribution.
14c7adf84cSho  *
15c7adf84cSho  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16c7adf84cSho  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17c7adf84cSho  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18c7adf84cSho  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19c7adf84cSho  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20c7adf84cSho  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21c7adf84cSho  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22c7adf84cSho  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23c7adf84cSho  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24c7adf84cSho  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25c7adf84cSho  */
26c7adf84cSho 
27c7adf84cSho #include <sys/types.h>
28c7adf84cSho #include <stdlib.h>
295d2dc2c4Sderaadt #include <string.h>
30c7adf84cSho 
31e0d722f1Sho #include "conf.h"
32c7adf84cSho #include "dpd.h"
33c7adf84cSho #include "exchange.h"
34e0d722f1Sho #include "hash.h"
35c7adf84cSho #include "ipsec.h"
36c7adf84cSho #include "isakmp_fld.h"
37c7adf84cSho #include "log.h"
38c7adf84cSho #include "message.h"
393a722197Shshoexer #include "pf_key_v2.h"
40c7adf84cSho #include "sa.h"
41c7adf84cSho #include "timer.h"
42e0d722f1Sho #include "transport.h"
43c7adf84cSho #include "util.h"
44c7adf84cSho 
45c7adf84cSho /* From RFC 3706.  */
46c7adf84cSho #define DPD_MAJOR		0x01
47c7adf84cSho #define DPD_MINOR		0x00
48c7adf84cSho #define DPD_SEQNO_SZ		4
49c7adf84cSho 
508b149709Scloder static const u_int8_t dpd_vendor_id[] = {
51c7adf84cSho 	0xAF, 0xCA, 0xD7, 0x13, 0x68, 0xA1, 0xF1,	/* RFC 3706 */
52c7adf84cSho 	0xC9, 0x6B, 0x86, 0x96, 0xFC, 0x77, 0x57,
53c7adf84cSho 	DPD_MAJOR,
54c7adf84cSho 	DPD_MINOR
55c7adf84cSho };
56c7adf84cSho 
57e0d722f1Sho #define DPD_RETRANS_MAX		5	/* max number of retries.  */
58e0d722f1Sho #define DPD_RETRANS_WAIT	5	/* seconds between retries.  */
59c7adf84cSho 
60e0d722f1Sho /* DPD Timer State */
61e0d722f1Sho enum dpd_tstate { DPD_TIMER_NORMAL, DPD_TIMER_CHECK };
62e0d722f1Sho 
63e0d722f1Sho static void	 dpd_check_event(void *);
64c7adf84cSho static void	 dpd_event(void *);
65e0d722f1Sho static u_int32_t dpd_timer_interval(u_int32_t);
66e0d722f1Sho static void	 dpd_timer_reset(struct sa *, u_int32_t, enum dpd_tstate);
67c7adf84cSho 
68c7adf84cSho /* Add the DPD VENDOR ID payload.  */
69c7adf84cSho int
dpd_add_vendor_payload(struct message * msg)70c7adf84cSho dpd_add_vendor_payload(struct message *msg)
71c7adf84cSho {
72c7adf84cSho 	u_int8_t *buf;
73c7adf84cSho 	size_t buflen = sizeof dpd_vendor_id + ISAKMP_GEN_SZ;
74c7adf84cSho 
75c7adf84cSho 	buf = malloc(buflen);
76c7adf84cSho 	if (!buf) {
77c7adf84cSho 		log_error("dpd_add_vendor_payload: malloc(%lu) failed",
78c7adf84cSho 		    (unsigned long)buflen);
79c7adf84cSho 		return -1;
80c7adf84cSho 	}
81c7adf84cSho 
82c7adf84cSho 	SET_ISAKMP_GEN_LENGTH(buf, buflen);
83c7adf84cSho 	memcpy(buf + ISAKMP_VENDOR_ID_OFF, dpd_vendor_id,
84c7adf84cSho 	    sizeof dpd_vendor_id);
85c7adf84cSho 	if (message_add_payload(msg, ISAKMP_PAYLOAD_VENDOR, buf, buflen, 1)) {
86c7adf84cSho 		free(buf);
87c7adf84cSho 		return -1;
88c7adf84cSho 	}
89c7adf84cSho 
90c7adf84cSho 	return 0;
91c7adf84cSho }
92c7adf84cSho 
93c7adf84cSho /*
94c7adf84cSho  * Check an incoming message for DPD capability markers.
95c7adf84cSho  */
96c7adf84cSho void
dpd_check_vendor_payload(struct message * msg,struct payload * p)97c7adf84cSho dpd_check_vendor_payload(struct message *msg, struct payload *p)
98c7adf84cSho {
99c7adf84cSho 	u_int8_t *pbuf = p->p;
100c7adf84cSho 	size_t vlen;
101c7adf84cSho 
102c7adf84cSho 	/* Already checked? */
103c7adf84cSho 	if (msg->exchange->flags & EXCHANGE_FLAG_DPD_CAP_PEER) {
104c7adf84cSho 		/* Just mark it as handled and return.  */
105c7adf84cSho 		p->flags |= PL_MARK;
106c7adf84cSho 		return;
107c7adf84cSho 	}
108c7adf84cSho 
109c7adf84cSho 	vlen = GET_ISAKMP_GEN_LENGTH(pbuf) - ISAKMP_GEN_SZ;
110c7adf84cSho 	if (vlen != sizeof dpd_vendor_id) {
111c7adf84cSho 		LOG_DBG((LOG_EXCHANGE, 90,
1125d2dc2c4Sderaadt 		    "dpd_check_vendor_payload: bad size %lu != %lu",
1135d2dc2c4Sderaadt 		    (unsigned long)vlen, (unsigned long)sizeof dpd_vendor_id));
114c7adf84cSho 		return;
115c7adf84cSho 	}
116c7adf84cSho 
117c7adf84cSho 	if (memcmp(dpd_vendor_id, pbuf + ISAKMP_GEN_SZ, vlen) == 0) {
118c7adf84cSho 		/* This peer is DPD capable.  */
119e0d722f1Sho 		if (msg->isakmp_sa) {
120c7adf84cSho 			msg->exchange->flags |= EXCHANGE_FLAG_DPD_CAP_PEER;
121c7adf84cSho 			LOG_DBG((LOG_EXCHANGE, 10, "dpd_check_vendor_payload: "
122c7adf84cSho 			    "DPD capable peer detected"));
123e0d722f1Sho 		}
124c7adf84cSho 		p->flags |= PL_MARK;
125e0d722f1Sho 	}
126c7adf84cSho }
127c7adf84cSho 
128c7adf84cSho /*
129a31e0ec4Smarkus  * Arm the DPD timer
130a31e0ec4Smarkus  */
131a31e0ec4Smarkus void
dpd_start(struct sa * isakmp_sa)132a31e0ec4Smarkus dpd_start(struct sa *isakmp_sa)
133a31e0ec4Smarkus {
134a31e0ec4Smarkus 	if (dpd_timer_interval(0) != 0) {
135a31e0ec4Smarkus 		LOG_DBG((LOG_EXCHANGE, 10, "dpd_enable: enabling"));
136a31e0ec4Smarkus 		isakmp_sa->flags |= SA_FLAG_DPD;
137a31e0ec4Smarkus 		dpd_timer_reset(isakmp_sa, 0, DPD_TIMER_NORMAL);
138a31e0ec4Smarkus 	}
139a31e0ec4Smarkus }
140a31e0ec4Smarkus 
141a31e0ec4Smarkus /*
142e0d722f1Sho  * All incoming DPD Notify messages enter here. Message has been validated.
143c7adf84cSho  */
144e0d722f1Sho void
dpd_handle_notify(struct message * msg,struct payload * p)145e0d722f1Sho dpd_handle_notify(struct message *msg, struct payload *p)
146e0d722f1Sho {
147e0d722f1Sho 	struct sa	*isakmp_sa = msg->isakmp_sa;
148e0d722f1Sho 	u_int16_t	 notify = GET_ISAKMP_NOTIFY_MSG_TYPE(p->p);
149e0d722f1Sho 	u_int32_t	 p_seq;
150c7adf84cSho 
151e0d722f1Sho 	/* Extract the sequence number.  */
152e0d722f1Sho 	memcpy(&p_seq, p->p + ISAKMP_NOTIFY_SPI_OFF + ISAKMP_HDR_COOKIES_LEN,
153e0d722f1Sho 	    sizeof p_seq);
154e0d722f1Sho 	p_seq = ntohl(p_seq);
155c7adf84cSho 
156e0d722f1Sho 	LOG_DBG((LOG_MESSAGE, 40, "dpd_handle_notify: got %s seq %u",
157e0d722f1Sho 	    constant_name(isakmp_notify_cst, notify), p_seq));
158e0d722f1Sho 
159e0d722f1Sho 	switch (notify) {
160e0d722f1Sho 	case ISAKMP_NOTIFY_STATUS_DPD_R_U_THERE:
161e0d722f1Sho 		/* The other peer wants to know we're alive.  */
162d650961eSmarkus 		if (p_seq < isakmp_sa->dpd_rseq ||
163d650961eSmarkus 		    (p_seq == isakmp_sa->dpd_rseq &&
164d650961eSmarkus 		    ++isakmp_sa->dpd_rdupcount >= DPD_RETRANS_MAX)) {
165e0d722f1Sho 			log_print("dpd_handle_notify: bad R_U_THERE seqno "
166e0d722f1Sho 			    "%u <= %u", p_seq, isakmp_sa->dpd_rseq);
167e0d722f1Sho 			return;
168e0d722f1Sho 		}
169d650961eSmarkus 		if (isakmp_sa->dpd_rseq != p_seq) {
170d650961eSmarkus 			isakmp_sa->dpd_rdupcount = 0;
171e0d722f1Sho 			isakmp_sa->dpd_rseq = p_seq;
172d650961eSmarkus 		}
173e0d722f1Sho 		message_send_dpd_notify(isakmp_sa,
174e0d722f1Sho 		    ISAKMP_NOTIFY_STATUS_DPD_R_U_THERE_ACK, p_seq);
175e0d722f1Sho 		break;
176e0d722f1Sho 
177e0d722f1Sho 	case ISAKMP_NOTIFY_STATUS_DPD_R_U_THERE_ACK:
178e0d722f1Sho 		/* This should be a response to a R_U_THERE we've sent.  */
179e0d722f1Sho 		if (isakmp_sa->dpd_seq != p_seq) {
180e0d722f1Sho 			log_print("dpd_handle_notify: got bad ACK seqno %u, "
181e0d722f1Sho 			    "expected %u", p_seq, isakmp_sa->dpd_seq);
182e0d722f1Sho 			/* XXX Give up? Retry? */
183e0d722f1Sho 			return;
184e0d722f1Sho 		}
185e0d722f1Sho 		break;
186e0d722f1Sho 	default:
1875d2dc2c4Sderaadt 		break;
188c7adf84cSho 	}
189c7adf84cSho 
190c7adf84cSho 	/* Mark handled.  */
191c7adf84cSho 	p->flags |= PL_MARK;
192c7adf84cSho 
193e0d722f1Sho 	/* The other peer is alive, so we can safely wait a while longer.  */
194e0d722f1Sho 	if (isakmp_sa->flags & SA_FLAG_DPD)
195e0d722f1Sho 		dpd_timer_reset(isakmp_sa, 0, DPD_TIMER_NORMAL);
196c7adf84cSho }
197c7adf84cSho 
198e0d722f1Sho /* Calculate the time until next DPD exchange.  */
199e0d722f1Sho static u_int32_t
dpd_timer_interval(u_int32_t offset)200e0d722f1Sho dpd_timer_interval(u_int32_t offset)
201c7adf84cSho {
202e0d722f1Sho 	int32_t v = 0;
203c7adf84cSho 
204e0d722f1Sho #ifdef notyet
205e0d722f1Sho 	v = ...; /* XXX Per-peer specified DPD intervals?  */
206e0d722f1Sho #endif
207e0d722f1Sho 	if (!v)
208e0d722f1Sho 		v = conf_get_num("General", "DPD-check-interval", 0);
209e0d722f1Sho 	if (v < 1)
210e0d722f1Sho 		return 0;	/* DPD-Check-Interval < 1 means disable DPD */
211e0d722f1Sho 
212e0d722f1Sho 	v -= offset;
213e0d722f1Sho 	return v < 1 ? 1 : v;
214c7adf84cSho }
215c7adf84cSho 
216c7adf84cSho static void
dpd_timer_reset(struct sa * sa,u_int32_t time_passed,enum dpd_tstate mode)217e0d722f1Sho dpd_timer_reset(struct sa *sa, u_int32_t time_passed, enum dpd_tstate mode)
218e0d722f1Sho {
219*6ee513e5Sjca 	struct timespec	ts;
220e0d722f1Sho 
221e0d722f1Sho 	if (sa->dpd_event)
222e0d722f1Sho 		timer_remove_event(sa->dpd_event);
223e0d722f1Sho 
224*6ee513e5Sjca 	clock_gettime(CLOCK_MONOTONIC, &ts);
225e0d722f1Sho 	switch (mode) {
226e0d722f1Sho 	case DPD_TIMER_NORMAL:
227d650961eSmarkus 		sa->dpd_failcount = 0;
228*6ee513e5Sjca 		ts.tv_sec += dpd_timer_interval(time_passed);
229e0d722f1Sho 		sa->dpd_event = timer_add_event("dpd_event", dpd_event, sa,
230*6ee513e5Sjca 		    &ts);
231e0d722f1Sho 		break;
232e0d722f1Sho 	case DPD_TIMER_CHECK:
233*6ee513e5Sjca 		ts.tv_sec += DPD_RETRANS_WAIT;
234e0d722f1Sho 		sa->dpd_event = timer_add_event("dpd_check_event",
235*6ee513e5Sjca 		    dpd_check_event, sa, &ts);
236e0d722f1Sho 		break;
237e0d722f1Sho 	default:
2385d2dc2c4Sderaadt 		break;
239e0d722f1Sho 	}
240e0d722f1Sho 	if (!sa->dpd_event)
241e0d722f1Sho 		log_print("dpd_timer_reset: timer_add_event failed");
242e0d722f1Sho }
243e0d722f1Sho 
244e0d722f1Sho /* Helper function for dpd_exchange_finalization().  */
245e0d722f1Sho static int
dpd_find_sa(struct sa * sa,void * v_sa)246e0d722f1Sho dpd_find_sa(struct sa *sa, void *v_sa)
247e0d722f1Sho {
248e0d722f1Sho 	struct sa	*isakmp_sa = v_sa;
249e0d722f1Sho 
250a78bc56aSmarkus 	if (!isakmp_sa->id_i || !isakmp_sa->id_r)
251151ead9aSho 		return 0;
252e569bb0fSmarkus 	return (sa->phase == 2 && (sa->flags & SA_FLAG_READY) &&
253e0d722f1Sho 	    memcmp(sa->id_i, isakmp_sa->id_i, sa->id_i_len) == 0 &&
254e0d722f1Sho 	    memcmp(sa->id_r, isakmp_sa->id_r, sa->id_r_len) == 0);
255e0d722f1Sho }
256e0d722f1Sho 
257e0d722f1Sho struct dpd_args {
258e0d722f1Sho 	struct sa	*isakmp_sa;
259e0d722f1Sho 	u_int32_t	 interval;
260e0d722f1Sho };
261e0d722f1Sho 
262e0d722f1Sho /* Helper function for dpd_event().  */
263e0d722f1Sho static int
dpd_check_time(struct sa * sa,void * v_arg)264e0d722f1Sho dpd_check_time(struct sa *sa, void *v_arg)
265e0d722f1Sho {
266e0d722f1Sho 	struct dpd_args *args = v_arg;
267e0d722f1Sho 	struct sockaddr *dst;
268e0d722f1Sho 	struct proto *proto;
269e0d722f1Sho 	struct sa_kinfo *ksa;
270*6ee513e5Sjca 	struct timespec ts;
271e0d722f1Sho 
272e0d722f1Sho 	if (sa->phase == 1 || (args->isakmp_sa->flags & SA_FLAG_DPD) == 0 ||
273e0d722f1Sho 	    dpd_find_sa(sa, args->isakmp_sa) == 0)
274e0d722f1Sho 		return 0;
275e0d722f1Sho 
276e0d722f1Sho 	proto = TAILQ_FIRST(&sa->protos);
277e0d722f1Sho 	if (!proto || !proto->data)
278e0d722f1Sho 		return 0;
279e0d722f1Sho 	sa->transport->vtbl->get_src(sa->transport, &dst);
280e0d722f1Sho 
281*6ee513e5Sjca 	clock_gettime(CLOCK_MONOTONIC, &ts);
2823a722197Shshoexer 	ksa = pf_key_v2_get_kernel_sa(proto->spi[1], proto->spi_sz[1],
283e0d722f1Sho 	    proto->proto, dst);
284e0d722f1Sho 
285e0d722f1Sho 	if (!ksa || !ksa->last_used)
286e0d722f1Sho 		return 0;
287e0d722f1Sho 
288e0d722f1Sho 	LOG_DBG((LOG_MESSAGE, 80, "dpd_check_time: "
289e0d722f1Sho 	    "SA %p last use %u second(s) ago", sa,
290*6ee513e5Sjca 	    (u_int32_t)(ts.tv_sec - ksa->last_used)));
291e0d722f1Sho 
292*6ee513e5Sjca 	if ((u_int32_t)(ts.tv_sec - ksa->last_used) < args->interval) {
293*6ee513e5Sjca 		args->interval = (u_int32_t)(ts.tv_sec - ksa->last_used);
294e0d722f1Sho 		return 1;
295e0d722f1Sho 	}
296e0d722f1Sho 	return 0;
297e0d722f1Sho }
298e0d722f1Sho 
299e0d722f1Sho /* Called by the timer.  */
300e0d722f1Sho static void
dpd_event(void * v_sa)301c7adf84cSho dpd_event(void *v_sa)
302c7adf84cSho {
303e0d722f1Sho 	struct sa	*isakmp_sa = v_sa;
304e0d722f1Sho 	struct dpd_args args;
305e0d722f1Sho 	struct sockaddr *dst;
306e0d722f1Sho 	char *addr;
307c7adf84cSho 
308e0d722f1Sho 	isakmp_sa->dpd_event = 0;
309c7adf84cSho 
310e0d722f1Sho 	/* Check if there's been any incoming SA activity since last time.  */
311e0d722f1Sho 	args.isakmp_sa = isakmp_sa;
312e0d722f1Sho 	args.interval = dpd_timer_interval(0);
313e0d722f1Sho 	if (sa_find(dpd_check_time, &args)) {
314e0d722f1Sho 		if (args.interval > dpd_timer_interval(0))
315e0d722f1Sho 			args.interval = 0;
316e0d722f1Sho 		dpd_timer_reset(isakmp_sa, args.interval, DPD_TIMER_NORMAL);
317c7adf84cSho 		return;
318e0d722f1Sho 	}
319c7adf84cSho 
320e0d722f1Sho 	/* No activity seen, do a DPD exchange.  */
321e0d722f1Sho 	if (isakmp_sa->dpd_seq == 0) {
322e0d722f1Sho 		/*
323e0d722f1Sho 		 * RFC 3706: first seq# should be random, with MSB zero,
324e0d722f1Sho 		 * otherwise we just increment it.
325e0d722f1Sho 		 */
326baf9c2dbSderaadt 		arc4random_buf((u_int8_t *)&isakmp_sa->dpd_seq,
327e0d722f1Sho 		    sizeof isakmp_sa->dpd_seq);
328e0d722f1Sho 		isakmp_sa->dpd_seq &= 0x7FFF;
329e0d722f1Sho 	} else
330e0d722f1Sho 		isakmp_sa->dpd_seq++;
331e0d722f1Sho 
332e0d722f1Sho 	isakmp_sa->transport->vtbl->get_dst(isakmp_sa->transport, &dst);
333e0d722f1Sho 	if (sockaddr2text(dst, &addr, 0) == -1)
334e0d722f1Sho 		addr = 0;
335e0d722f1Sho 	LOG_DBG((LOG_MESSAGE, 30, "dpd_event: sending R_U_THERE to %s seq %u",
336e0d722f1Sho 	    addr ? addr : "<unknown>", isakmp_sa->dpd_seq));
337e0d722f1Sho 	free(addr);
338e0d722f1Sho 	message_send_dpd_notify(isakmp_sa, ISAKMP_NOTIFY_STATUS_DPD_R_U_THERE,
339e0d722f1Sho 	    isakmp_sa->dpd_seq);
340e0d722f1Sho 
341e0d722f1Sho 	/* And set the short timer.  */
342e0d722f1Sho 	dpd_timer_reset(isakmp_sa, 0, DPD_TIMER_CHECK);
343e0d722f1Sho }
344e0d722f1Sho 
345e0d722f1Sho /*
346e0d722f1Sho  * Called by the timer. If this function is called, it means we did not
3475678a57aShshoexer  * received any R_U_THERE_ACK confirmation from the other peer.
348e0d722f1Sho  */
349e0d722f1Sho static void
dpd_check_event(void * v_sa)350e0d722f1Sho dpd_check_event(void *v_sa)
351e0d722f1Sho {
352e0d722f1Sho 	struct sa	*isakmp_sa = v_sa;
353e0d722f1Sho 	struct sa	*sa;
354e0d722f1Sho 
355e0d722f1Sho 	isakmp_sa->dpd_event = 0;
356e0d722f1Sho 
357e0d722f1Sho 	if (++isakmp_sa->dpd_failcount < DPD_RETRANS_MAX) {
358e0d722f1Sho 		LOG_DBG((LOG_MESSAGE, 10, "dpd_check_event: "
359e0d722f1Sho 		    "peer not responding, retry %u of %u",
360e0d722f1Sho 		    isakmp_sa->dpd_failcount, DPD_RETRANS_MAX));
361e0d722f1Sho 		message_send_dpd_notify(isakmp_sa,
362e0d722f1Sho 		    ISAKMP_NOTIFY_STATUS_DPD_R_U_THERE, isakmp_sa->dpd_seq);
363e0d722f1Sho 		dpd_timer_reset(isakmp_sa, 0, DPD_TIMER_CHECK);
364e0d722f1Sho 		return;
365e0d722f1Sho 	}
366e0d722f1Sho 
367e0d722f1Sho 	/*
368e0d722f1Sho 	 * Peer is considered dead. Delete all SAs created under isakmp_sa.
369e0d722f1Sho 	 */
370e0d722f1Sho 	LOG_DBG((LOG_MESSAGE, 10, "dpd_check_event: peer is dead, "
371e0d722f1Sho 	    "deleting all SAs connected to SA %p", isakmp_sa));
372e0d722f1Sho 	while ((sa = sa_find(dpd_find_sa, isakmp_sa)) != 0) {
373e0d722f1Sho 		LOG_DBG((LOG_MESSAGE, 30, "dpd_check_event: deleting SA %p",
374e0d722f1Sho 		    sa));
375e0d722f1Sho 		sa_delete(sa, 0);
376e0d722f1Sho 	}
377e0d722f1Sho 	LOG_DBG((LOG_MESSAGE, 30, "dpd_check_event: deleting ISAKMP SA %p",
378e0d722f1Sho 	    isakmp_sa));
379e0d722f1Sho 	sa_delete(isakmp_sa, 0);
380c7adf84cSho }
381