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