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 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 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 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 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 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 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 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 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 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 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