]> git.saurik.com Git - apple/ipsec.git/blame - ipsec-tools/racoon/ike_session.c
ipsec-326.81.1.tar.gz
[apple/ipsec.git] / ipsec-tools / racoon / ike_session.c
CommitLineData
d1e348cf
A
1/*
2 * Copyright (c) 2008 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22
23#include <sys/param.h>
24#include <sys/types.h>
25#include <sys/socket.h>
26#include <string.h>
27
28#include "var.h"
29#include "misc.h"
30#include "vmbuf.h"
31#include "plog.h"
32#include "sockmisc.h"
33#include "debug.h"
65c25746 34#include "fsm.h"
d1e348cf
A
35
36#include "isakmp_var.h"
37#include "isakmp.h"
38#include "ike_session.h"
39#include "handler.h"
40#include "gcmalloc.h"
41#include "nattraversal.h"
42#include "schedule.h"
43#include "pfkey.h"
44#include "ipsec_doi.h"
45#include "ipsecSessionTracer.h"
46#include "ipsecMessageTracer.h"
47#include "isakmp_inf.h"
48#include "localconf.h"
49#include "remoteconf.h"
50#include "vpn_control.h"
85f41bec 51#include "vpn_control_var.h"
47612122
A
52#include "proposal.h"
53#include "sainfo.h"
e8d9021d
A
54#include "power_mgmt.h"
55
56#define GET_SAMPLE_PERIOD(s,m) do { \
57 s = m / 20; \
58 if (s < 3) { \
59 s = 3; \
60 if (m < (s * 2)) { \
61 s = 1; /* bad */\
62 } \
63 } \
64 } while(0);
d1e348cf
A
65
66const char *ike_session_stopped_by_vpn_disconnect = "Stopped by VPN disconnect";
85f41bec 67const char *ike_session_stopped_by_controller_comm_lost = "Stopped by loss of controller communication";
d1e348cf
A
68const char *ike_session_stopped_by_flush = "Stopped by Flush";
69const char *ike_session_stopped_by_idle = "Stopped by Idle";
70const char *ike_session_stopped_by_xauth_timeout = "Stopped by XAUTH timeout";
e8d9021d
A
71const char *ike_session_stopped_by_sleepwake = "Stopped by Sleep-Wake";
72const char *ike_session_stopped_by_assert = "Stopped by Assert";
65c25746 73const char *ike_session_stopped_by_peer = "Stopped by Peer";
d1e348cf 74
65c25746
A
75LIST_HEAD(_ike_session_tree_, ike_session) ike_session_tree = { NULL };
76
77static void ike_session_bindph12(phase1_handle_t *, phase2_handle_t *);
78static void ike_session_rebindph12(phase1_handle_t *, phase2_handle_t *);
79static void ike_session_unbind_all_ph2_from_ph1 (phase1_handle_t *);
80static void ike_session_rebind_all_ph12_to_new_ph1 (phase1_handle_t *, phase1_handle_t *);
d1e348cf
A
81
82static ike_session_t *
83new_ike_session (ike_session_id_t *id)
84{
85 ike_session_t *session;
86
87 if (!id) {
7ebaebe2 88 plog(ASL_LEVEL_ERR, "Invalid parameters in %s.\n", __FUNCTION__);
d1e348cf
A
89 return NULL;
90 }
65c25746 91
d1e348cf
A
92 session = racoon_calloc(1, sizeof(*session));
93 if (session) {
94 bzero(session, sizeof(*session));
95 memcpy(&session->session_id, id, sizeof(*id));
65c25746
A
96 LIST_INIT(&session->ph1tree);
97 LIST_INIT(&session->ph2tree);
d1e348cf 98 LIST_INSERT_HEAD(&ike_session_tree, session, chain);
d1e348cf
A
99 IPSECSESSIONTRACERSTART(session);
100 }
101 return session;
102}
103
104static void
105free_ike_session (ike_session_t *session)
106{
107 int is_failure = TRUE;
108 if (session) {
109 SCHED_KILL(session->traffic_monitor.sc_mon);
110 SCHED_KILL(session->traffic_monitor.sc_idle);
111 SCHED_KILL(session->sc_xauth);
112 if (session->start_timestamp.tv_sec || session->start_timestamp.tv_usec) {
47612122 113 if (!(session->stop_timestamp.tv_sec || session->stop_timestamp.tv_usec)) {
d1e348cf
A
114 gettimeofday(&session->stop_timestamp, NULL);
115 }
116 if (session->term_reason != ike_session_stopped_by_vpn_disconnect ||
85f41bec 117 session->term_reason != ike_session_stopped_by_controller_comm_lost ||
d1e348cf
A
118 session->term_reason != ike_session_stopped_by_flush ||
119 session->term_reason != ike_session_stopped_by_idle) {
120 is_failure = FALSE;
121 }
122 IPSECSESSIONTRACERSTOP(session,
123 is_failure,
124 session->term_reason);
125 }
126 // do MessageTracer cleanup here
7ebaebe2 127 plog(ASL_LEVEL_NOTICE,
d1e348cf
A
128 "Freeing IKE-Session to %s.\n",
129 saddr2str((struct sockaddr *)&session->session_id.remote));
130 LIST_REMOVE(session, chain);
131 racoon_free(session);
132 }
133}
134
d1e348cf
A
135
136void
137ike_session_init (void)
138{
139 LIST_INIT(&ike_session_tree);
140}
141
142u_int
143ike_session_get_rekey_lifetime (int local_spi_is_higher, u_int expiry_lifetime)
144{
145 u_int rekey_lifetime = expiry_lifetime / 10;
146
147 if (rekey_lifetime) {
148 if (local_spi_is_higher) {
149 return (rekey_lifetime * 9);
150 } else {
151 return (rekey_lifetime * 8);
152 }
153 } else {
154 if (local_spi_is_higher) {
155 rekey_lifetime = expiry_lifetime - 1;
156 } else {
157 rekey_lifetime = expiry_lifetime - 2;
158 }
159 }
160 if (rekey_lifetime < expiry_lifetime) {
65c25746 161 return rekey_lifetime;
d1e348cf 162 }
65c25746
A
163 return 0;
164}
165
166ike_session_t *
167ike_session_create_session (ike_session_id_t *session_id)
168{
169 if (!session_id)
170 return NULL;
171
7ebaebe2 172 plog(ASL_LEVEL_NOTICE, "New IKE Session to %s.\n", saddr2str((struct sockaddr *)&session_id->remote));
65c25746
A
173
174 return new_ike_session(session_id);
d1e348cf
A
175}
176
65c25746
A
177void
178ike_session_release_session (ike_session_t *session)
179{
180 while (!LIST_EMPTY(&session->ph2tree)) {
181 phase2_handle_t *phase2 = LIST_FIRST(&session->ph2tree);
182 ike_session_unlink_phase2(phase2);
183 }
184
185 while (!LIST_EMPTY(&session->ph1tree)) {
186 phase1_handle_t *phase1 = LIST_FIRST(&session->ph1tree);
187 ike_session_unlink_phase1(phase1);
188 }
189}
190
191// %%%%%%%%% re-examine this - keep both floated and unfloated port when behind nat
d1e348cf 192ike_session_t *
85f41bec
A
193ike_session_get_session (struct sockaddr_storage *local,
194 struct sockaddr_storage *remote,
1760d65d
A
195 int alloc_if_absent,
196 isakmp_index *optionalIndex)
d1e348cf 197{
65c25746 198 ike_session_t *p = NULL;
d1e348cf
A
199 ike_session_id_t id;
200 ike_session_id_t id_default;
201 ike_session_id_t id_floated_default;
202 ike_session_id_t id_wop;
203 ike_session_t *best_match = NULL;
204 u_int16_t remote_port;
205 int is_isakmp_remote_port;
206
207 if (!local || !remote) {
7ebaebe2 208 plog(ASL_LEVEL_ERR, "invalid parameters in %s.\n", __FUNCTION__);
d1e348cf
A
209 return NULL;
210 }
211
212 remote_port = extract_port(remote);
213 if (remote_port && remote_port != PORT_ISAKMP && remote_port != PORT_ISAKMP_NATT) {
214 is_isakmp_remote_port = 0;
215 } else {
216 is_isakmp_remote_port = 1;
217 }
218
219 /* we will try a couple of matches first: if the exact id isn't found, then we'll try for an id that has zero'd ports */
220 bzero(&id, sizeof(id));
221 bzero(&id_default, sizeof(id_default));
222 bzero(&id_floated_default, sizeof(id_floated_default));
223 bzero(&id_wop, sizeof(id_wop));
85f41bec 224 if (local->ss_family == AF_INET) {
d1e348cf
A
225 memcpy(&id.local, local, sizeof(struct sockaddr_in));
226 memcpy(&id_default.local, local, sizeof(struct sockaddr_in));
227 memcpy(&id_floated_default.local, local, sizeof(struct sockaddr_in));
228 memcpy(&id_wop.local, local, sizeof(struct sockaddr_in));
85f41bec 229 } else if (local->ss_family == AF_INET6) {
d1e348cf
A
230 memcpy(&id.local, local, sizeof(struct sockaddr_in6));
231 memcpy(&id_default.local, local, sizeof(struct sockaddr_in6));
232 memcpy(&id_floated_default.local, local, sizeof(struct sockaddr_in6));
233 memcpy(&id_wop.local, local, sizeof(struct sockaddr_in6));
234 }
85f41bec
A
235 set_port(&id_default.local, PORT_ISAKMP);
236 set_port(&id_floated_default.local, PORT_ISAKMP_NATT);
237 set_port(&id_wop.local, 0);
238 if (remote->ss_family == AF_INET) {
d1e348cf
A
239 memcpy(&id.remote, remote, sizeof(struct sockaddr_in));
240 memcpy(&id_default.remote, remote, sizeof(struct sockaddr_in));
241 memcpy(&id_floated_default.remote, remote, sizeof(struct sockaddr_in));
242 memcpy(&id_wop.remote, remote, sizeof(struct sockaddr_in));
85f41bec 243 } else if (remote->ss_family == AF_INET6) {
d1e348cf
A
244 memcpy(&id.remote, remote, sizeof(struct sockaddr_in6));
245 memcpy(&id_default.remote, remote, sizeof(struct sockaddr_in6));
246 memcpy(&id_floated_default.remote, remote, sizeof(struct sockaddr_in6));
247 memcpy(&id_wop.remote, remote, sizeof(struct sockaddr_in6));
248 }
85f41bec
A
249 set_port(&id_default.remote, PORT_ISAKMP);
250 set_port(&id_floated_default.remote, PORT_ISAKMP_NATT);
251 set_port(&id_wop.remote, 0);
d1e348cf 252
65c25746 253 plog(ASL_LEVEL_DEBUG,
d1e348cf 254 "start search for IKE-Session. target %s.\n",
85f41bec 255 saddr2str((struct sockaddr *)remote));
d1e348cf 256
65c25746
A
257 LIST_FOREACH(p, &ike_session_tree, chain) {
258 plog(ASL_LEVEL_DEBUG,
d1e348cf
A
259 "still search for IKE-Session. this %s.\n",
260 saddr2str((struct sockaddr *)&p->session_id.remote));
261
869d26af
A
262 // for now: ignore any stopped sessions as they will go down
263 if (p->is_dying || p->stopped_by_vpn_controller || p->stop_timestamp.tv_sec || p->stop_timestamp.tv_usec) {
65c25746 264 plog(ASL_LEVEL_DEBUG, "still searching. skipping... session to %s is already stopped, active ph1 %d ph2 %d.\n",
869d26af
A
265 saddr2str((struct sockaddr *)&p->session_id.remote),
266 p->ikev1_state.active_ph1cnt, p->ikev1_state.active_ph2cnt);
267 continue;
268 }
d9c572c0 269
1760d65d
A
270 // Skip if the spi doesn't match
271 if (optionalIndex != NULL && ike_session_getph1byindex(p, optionalIndex) == NULL) {
272 continue;
273 }
869d26af 274
d1e348cf 275 if (memcmp(&p->session_id, &id, sizeof(id)) == 0) {
65c25746 276 plog(ASL_LEVEL_DEBUG,
d1e348cf 277 "Pre-existing IKE-Session to %s. case 1.\n",
85f41bec 278 saddr2str((struct sockaddr *)remote));
d1e348cf
A
279 return p;
280 } else if (is_isakmp_remote_port && memcmp(&p->session_id, &id_default, sizeof(id_default)) == 0) {
65c25746 281 plog(ASL_LEVEL_DEBUG,
d1e348cf 282 "Pre-existing IKE-Session to %s. case 2.\n",
85f41bec 283 saddr2str((struct sockaddr *)remote));
d1e348cf
A
284 return p;
285 } else if (is_isakmp_remote_port && p->ports_floated && memcmp(&p->session_id, &id_floated_default, sizeof(id_floated_default)) == 0) {
65c25746 286 plog(ASL_LEVEL_DEBUG,
d1e348cf 287 "Pre-existing IKE-Session to %s. case 3.\n",
85f41bec 288 saddr2str((struct sockaddr *)remote));
d1e348cf
A
289 return p;
290 } else if (is_isakmp_remote_port && memcmp(&p->session_id, &id_wop, sizeof(id_wop)) == 0) {
291 best_match = p;
1760d65d
A
292 } else if (optionalIndex != NULL) {
293 // If the SPI did match, this one counts as a best match
294 best_match = p;
d1e348cf
A
295 }
296 }
297 if (best_match) {
65c25746 298 plog(ASL_LEVEL_DEBUG,
d1e348cf
A
299 "Best-match IKE-Session to %s.\n",
300 saddr2str((struct sockaddr *)&best_match->session_id.remote));
301 return best_match;
302 }
303 if (alloc_if_absent) {
65c25746 304 plog(ASL_LEVEL_DEBUG,
d1e348cf
A
305 "New IKE-Session to %s.\n",
306 saddr2str((struct sockaddr *)&id.remote));
307 return new_ike_session(&id);
308 } else {
309 return NULL;
310 }
311}
312
313void
65c25746 314ike_session_init_traffic_cop_params (phase1_handle_t *iph1)
d1e348cf
A
315{
316 if (!iph1 ||
317 !iph1->rmconf ||
318 (!iph1->rmconf->idle_timeout && !iph1->rmconf->dpd_interval)) {
319 return;
320 }
321
322 if (!iph1->parent_session->traffic_monitor.interv_idle) {
323 iph1->parent_session->traffic_monitor.interv_idle = iph1->rmconf->idle_timeout;
324 }
7ebaebe2 325
d1e348cf
A
326 if (!iph1->parent_session->traffic_monitor.dir_idle) {
327 iph1->parent_session->traffic_monitor.dir_idle = iph1->rmconf->idle_timeout_dir;
328 }
7ebaebe2 329
d1e348cf
A
330 if (!iph1->parent_session->traffic_monitor.interv_mon) {
331 int min_period, max_period, sample_period = 0;
332
333 /* calculate the sampling interval... half the smaller interval */
334 if (iph1->rmconf->dpd_interval &&
335 (iph1->rmconf->dpd_algo == DPD_ALGO_INBOUND_DETECT ||
336 iph1->rmconf->dpd_algo == DPD_ALGO_BLACKHOLE_DETECT)) {
337 // when certain types of dpd are enabled
338 min_period = MIN(iph1->rmconf->dpd_interval, iph1->rmconf->idle_timeout);
339 max_period = MAX(iph1->rmconf->dpd_interval, iph1->rmconf->idle_timeout);
340 } else if (iph1->rmconf->idle_timeout) {
47612122 341 min_period = max_period = iph1->rmconf->idle_timeout;
d1e348cf
A
342 } else {
343 // DPD_ALGO_DEFAULT is configured and there's no idle timeout... we don't need to monitor traffic
344 return;
345 }
346 if (min_period) {
e8d9021d 347 GET_SAMPLE_PERIOD(sample_period, min_period);
d1e348cf 348 } else {
e8d9021d 349 GET_SAMPLE_PERIOD(sample_period, max_period);
d1e348cf
A
350 }
351 iph1->parent_session->traffic_monitor.interv_mon = sample_period;
352 }
353}
354
d1e348cf 355void
65c25746 356ike_session_update_mode (phase2_handle_t *iph2)
d1e348cf
A
357{
358 if (!iph2 || !iph2->parent_session) {
359 return;
360 }
65c25746
A
361 if (iph2->phase2_type != PHASE2_TYPE_SA)
362 return;
d9c572c0 363
d1e348cf
A
364 // exit early if we already detected cisco-ipsec
365 if (iph2->parent_session->is_cisco_ipsec) {
366 return;
367 }
368
369 if (iph2->approval) {
370 if (!ipsecdoi_any_transportmode(iph2->approval)) {
371 // cisco & btmm ipsec are pure tunnel-mode (but cisco ipsec is detected by ph1)
372 iph2->parent_session->is_cisco_ipsec = 0;
373 iph2->parent_session->is_l2tpvpn_ipsec = 0;
374 iph2->parent_session->is_btmm_ipsec = 1;
375 return;
376 } else if (ipsecdoi_transportmode(iph2->approval)) {
377 iph2->parent_session->is_cisco_ipsec = 0;
378 iph2->parent_session->is_l2tpvpn_ipsec = 1;
379 iph2->parent_session->is_btmm_ipsec = 0;
380 return;
381 }
382 } else if (iph2->proposal) {
383 if (!ipsecdoi_any_transportmode(iph2->proposal)) {
384 // cisco & btmm ipsec are pure tunnel-mode (but cisco ipsec is detected by ph1)
385 iph2->parent_session->is_cisco_ipsec = 0;
386 iph2->parent_session->is_l2tpvpn_ipsec = 0;
387 iph2->parent_session->is_btmm_ipsec = 1;
388 return;
389 } else if (ipsecdoi_transportmode(iph2->proposal)) {
390 iph2->parent_session->is_cisco_ipsec = 0;
391 iph2->parent_session->is_l2tpvpn_ipsec = 1;
392 iph2->parent_session->is_btmm_ipsec = 0;
393 return;
394 }
395 }
396}
397
398static void
399ike_session_cleanup_xauth_timeout (void *arg)
400{
401 ike_session_t *session = (ike_session_t *)arg;
402
403 SCHED_KILL(session->sc_xauth);
404 // if there are no more established ph2s, start a timer to teardown the session
405 if (!ike_session_has_established_ph2(session)) {
406 ike_session_cleanup(session, ike_session_stopped_by_xauth_timeout);
407 } else {
408 session->sc_xauth = sched_new(300 /* 5 mins */,
409 ike_session_cleanup_xauth_timeout,
410 session);
411 }
412}
413
414int
65c25746 415ike_session_link_phase1 (ike_session_t *session, phase1_handle_t *iph1)
d1e348cf 416{
65c25746
A
417
418 if (!session || !iph1) {
7ebaebe2 419 plog(ASL_LEVEL_ERR, "invalid parameters in %s.\n", __FUNCTION__);
d1e348cf
A
420 return -1;
421 }
65c25746
A
422
423 gettimeofday(&session->start_timestamp, NULL);
424
425 if (iph1->started_by_api) {
426 session->is_cisco_ipsec = 1;
427 session->is_l2tpvpn_ipsec = 0;
428 session->is_btmm_ipsec = 0;
429 }
430 iph1->parent_session = session;
431 LIST_INSERT_HEAD(&session->ph1tree, iph1, ph1ofsession_chain);
432 session->ikev1_state.active_ph1cnt++;
433 if ((!session->ikev1_state.ph1cnt &&
434 iph1->side == INITIATOR) ||
435 iph1->started_by_api) {
436 // client initiates the first phase1 or, is started by controller api
437 session->is_client = 1;
438 }
439 if (session->established &&
440 session->ikev1_state.ph1cnt &&
441 iph1->version == ISAKMP_VERSION_NUMBER_IKEV1) {
442 iph1->is_rekey = 1;
443 }
444 session->ikev1_state.ph1cnt++;
445 ike_session_init_traffic_cop_params(iph1);
446
447 return 0;
448}
d1e348cf 449
65c25746
A
450int
451ike_session_link_phase2 (ike_session_t *session, phase2_handle_t *iph2)
452{
453 if (!iph2) {
7ebaebe2 454 plog(ASL_LEVEL_ERR, "Invalid parameters in %s.\n", __FUNCTION__);
d1e348cf
A
455 return -1;
456 }
65c25746
A
457 if (iph2->parent_session) {
458 plog(ASL_LEVEL_ERR, "Phase 2 already linked to session %s.\n", __FUNCTION__);
d1e348cf
A
459 }
460
461 iph2->parent_session = session;
65c25746 462 LIST_INSERT_HEAD(&session->ph2tree, iph2, ph2ofsession_chain);
d1e348cf
A
463 session->ikev1_state.active_ph2cnt++;
464 if (!session->ikev1_state.ph2cnt &&
465 iph2->side == INITIATOR) {
466 // client initiates the first phase2
467 session->is_client = 1;
468 }
65c25746
A
469 if (iph2->phase2_type == PHASE2_TYPE_SA &&
470 session->established &&
471 session->ikev1_state.ph2cnt &&
472 iph2->version == ISAKMP_VERSION_NUMBER_IKEV1) {
d1e348cf
A
473 iph2->is_rekey = 1;
474 }
475 session->ikev1_state.ph2cnt++;
d1e348cf
A
476 ike_session_update_mode(iph2);
477
478 return 0;
479}
480
481int
65c25746
A
482ike_session_link_ph2_to_ph1 (phase1_handle_t *iph1, phase2_handle_t *iph2)
483{
484 struct sockaddr_storage *local;
485 struct sockaddr_storage *remote;
486 int error = 0;
487
488 if (!iph2) {
7ebaebe2 489 plog(ASL_LEVEL_ERR, "Invalid parameters in %s.\n", __FUNCTION__);
65c25746
A
490 return -1;
491 }
492 if (iph2->ph1) {
493 plog(ASL_LEVEL_ERR, "Phase 2 already linked %s.\n", __FUNCTION__);
494 if (iph2->ph1 == iph1)
495 return 0;
496 else
497 return -1; // This shouldn't happen
498 }
499
500 local = iph2->src;
501 remote = iph2->dst;
502
503 if (iph2->parent_session == NULL)
504 if ((error = ike_session_link_phase2(iph1->parent_session, iph2)))
505 return error;
506
507 ike_session_bindph12(iph1, iph2);
508 return 0;
509}
510
511int
512ike_session_unlink_phase1 (phase1_handle_t *iph1)
d1e348cf
A
513{
514 ike_session_t *session;
515
516 if (!iph1 || !iph1->parent_session) {
7ebaebe2 517 plog(ASL_LEVEL_ERR, "invalid parameters in %s.\n", __FUNCTION__);
d1e348cf
A
518 return -1;
519 }
520
65c25746
A
521 if (iph1->version == ISAKMP_VERSION_NUMBER_IKEV1) {
522 if (LIST_FIRST(&iph1->bound_ph2tree)) {
523 // reparent any phase2 that may be hanging on to this phase1
524 ike_session_update_ph1_ph2tree(iph1);
525 }
d1e348cf
A
526 }
527
65c25746 528 sched_scrub_param(iph1);
d1e348cf
A
529 session = iph1->parent_session;
530 LIST_REMOVE(iph1, ph1ofsession_chain);
531 iph1->parent_session = NULL;
532 session->ikev1_state.active_ph1cnt--;
533 if (session->ikev1_state.active_ph1cnt == 0 && session->ikev1_state.active_ph2cnt == 0) {
e8d9021d 534 session->is_dying = 1;
d1e348cf
A
535 free_ike_session(session);
536 }
65c25746 537 ike_session_delph1(iph1);
d1e348cf
A
538 return 0;
539}
540
541int
65c25746 542ike_session_unlink_phase2 (phase2_handle_t *iph2)
d1e348cf
A
543{
544 ike_session_t *session;
545
546 if (!iph2 || !iph2->parent_session) {
7ebaebe2 547 plog(ASL_LEVEL_ERR, "invalid parameters in %s.\n", __FUNCTION__);
d1e348cf
A
548 return -1;
549 }
65c25746
A
550 sched_scrub_param(iph2);
551 ike_session_unbindph12(iph2);
552
553 LIST_REMOVE(iph2, ph2ofsession_chain);
554 session = iph2->parent_session;
555 iph2->parent_session = NULL;
556 session->ikev1_state.active_ph2cnt--;
557 if (session->ikev1_state.active_ph1cnt == 0 && session->ikev1_state.active_ph2cnt == 0) {
558 session->is_dying = 1;
559 free_ike_session(session);
560 }
561 ike_session_delph2(iph2);
562 return 0;
563}
564
565
566phase1_handle_t *
567ike_session_update_ph1_ph2tree (phase1_handle_t *iph1)
568{
569 phase1_handle_t *new_iph1 = NULL;
570
571 if (!iph1) {
7ebaebe2 572 plog(ASL_LEVEL_ERR, "invalid parameters in %s.\n", __FUNCTION__);
65c25746
A
573 return NULL;
574 }
575
576 if (iph1->parent_session) {
577 new_iph1 = ike_session_get_established_ph1(iph1->parent_session);
578
579 if (!new_iph1) {
7ebaebe2 580 plog(ASL_LEVEL_NOTICE, "no ph1bind replacement found. NULL ph1.\n");
65c25746
A
581 ike_session_unbind_all_ph2_from_ph1(iph1);
582 } else if (iph1 == new_iph1) {
7ebaebe2 583 plog(ASL_LEVEL_NOTICE, "no ph1bind replacement found. same ph1.\n");
65c25746
A
584 ike_session_unbind_all_ph2_from_ph1(iph1);
585 } else {
586 ike_session_rebind_all_ph12_to_new_ph1(iph1, new_iph1);
587 }
588 } else {
7ebaebe2 589 plog(ASL_LEVEL_NOTICE, "invalid parent session in %s.\n", __FUNCTION__);
65c25746
A
590 }
591 return new_iph1;
592}
593
594phase1_handle_t *
595ike_session_update_ph2_ph1bind (phase2_handle_t *iph2)
596{
597 phase1_handle_t *iph1;
d1e348cf 598
65c25746 599 if (!iph2 || iph2->phase2_type != PHASE2_TYPE_SA) {
7ebaebe2 600 plog(ASL_LEVEL_ERR, "invalid parameters in %s.\n", __FUNCTION__);
65c25746 601 return NULL;
d1e348cf
A
602 }
603
65c25746
A
604 iph1 = ike_session_get_established_ph1(iph2->parent_session);
605 if (iph1 && iph2->ph1 && iph1 != iph2->ph1) {
606 ike_session_rebindph12(iph1, iph2);
607 } else if (iph1 && !iph2->ph1) {
608 ike_session_bindph12(iph1, iph2);
609 }
610
611 return iph1;
d1e348cf
A
612}
613
65c25746
A
614phase1_handle_t *
615ike_session_get_established_or_negoing_ph1 (ike_session_t *session)
d1e348cf 616{
65c25746
A
617 phase1_handle_t *p, *iph1 = NULL;
618
d1e348cf 619 if (!session) {
7ebaebe2 620 plog(ASL_LEVEL_ERR, "invalid parameters in %s.\n", __FUNCTION__);
65c25746 621 return NULL;
d1e348cf 622 }
65c25746
A
623
624 // look for the most mature ph1 under the session
625 LIST_FOREACH(p, &session->ph1tree, ph1ofsession_chain) {
626 if (!p->is_dying && (FSM_STATE_IS_ESTABLISHED(p->status) || FSM_STATE_IS_NEGOTIATING(p->status))) {
627 if (!iph1 || p->status > iph1->status) {
628 iph1 = p;
629 } else if (iph1 && p->status == iph1->status) {
630 // TODO: pick better one based on farthest rekey/expiry remaining
d1e348cf
A
631 }
632 }
633 }
65c25746
A
634
635 return iph1;
636}
d1e348cf 637
65c25746
A
638phase1_handle_t *
639ike_session_get_established_ph1 (ike_session_t *session)
640{
641 phase1_handle_t *p;
642
643 if (!session) {
7ebaebe2 644 plog(ASL_LEVEL_ERR, "invalid parameters in %s.\n", __FUNCTION__);
65c25746
A
645 return NULL;
646 }
647
648 LIST_FOREACH(p, &session->ph1tree, ph1ofsession_chain) {
649 if (!p->is_dying && FSM_STATE_IS_ESTABLISHED(p->status)) {
650 return p;
651 }
652 }
653
654 return NULL;
d1e348cf
A
655}
656
65c25746 657
d1e348cf 658int
65c25746 659ike_session_has_other_established_ph1 (ike_session_t *session, phase1_handle_t *iph1)
d1e348cf 660{
65c25746
A
661 phase1_handle_t *p;
662
d1e348cf 663 if (!session) {
d1e348cf
A
664 return 0;
665 }
65c25746
A
666
667 LIST_FOREACH(p, &session->ph1tree, ph1ofsession_chain) {
d1e348cf 668 if (iph1 != p && !p->is_dying) {
65c25746 669 if (FSM_STATE_IS_ESTABLISHED(p->status) && p->sce_rekey) {
d1e348cf
A
670 return 1;
671 }
672 }
673 }
65c25746 674
d1e348cf
A
675 return 0;
676}
677
678int
65c25746 679ike_session_has_other_negoing_ph1 (ike_session_t *session, phase1_handle_t *iph1)
d1e348cf 680{
65c25746 681 phase1_handle_t *p;
d1e348cf
A
682
683 if (!session) {
7ebaebe2 684 plog(ASL_LEVEL_ERR, "invalid parameters in %s.\n", __FUNCTION__);
d1e348cf
A
685 return 0;
686 }
687
65c25746
A
688 LIST_FOREACH(p, &session->ph1tree, ph1ofsession_chain) {
689 if (iph1 != p && !p->is_dying) {
690 if (FSM_STATE_IS_NEGOTIATING(p->status)) {
d1e348cf
A
691 return 1;
692 }
693 }
694 }
695
696 return 0;
697}
698
699int
65c25746 700ike_session_has_other_established_ph2 (ike_session_t *session, phase2_handle_t *iph2)
d1e348cf 701{
65c25746 702 phase2_handle_t *p;
d1e348cf
A
703
704 if (!session) {
7ebaebe2 705 plog(ASL_LEVEL_ERR, "invalid parameters in %s.\n", __FUNCTION__);
d1e348cf
A
706 return 0;
707 }
708
65c25746
A
709 LIST_FOREACH(p, &session->ph2tree, ph2ofsession_chain) {
710 if (p->phase2_type == PHASE2_TYPE_SA && iph2 != p && !p->is_dying && iph2->spid == p->spid) {
711 if (FSM_STATE_IS_ESTABLISHED(p->status)) {
d1e348cf
A
712 return 1;
713 }
714 }
715 }
716
717 return 0;
718}
719
65c25746
A
720int
721ike_session_has_other_negoing_ph2 (ike_session_t *session, phase2_handle_t *iph2)
d1e348cf 722{
65c25746 723 phase2_handle_t *p;
d1e348cf 724
65c25746 725 if (!session) {
7ebaebe2 726 plog(ASL_LEVEL_ERR, "invalid parameters in %s.\n", __FUNCTION__);
65c25746 727 return 0;
d1e348cf
A
728 }
729
65c25746
A
730 LIST_FOREACH(p, &session->ph2tree, ph2ofsession_chain) {
731 plog(ASL_LEVEL_DEBUG, "%s: ph2 sub spid %d, db spid %d\n", __FUNCTION__, iph2->spid, p->spid);
732 if (p->phase2_type == PHASE2_TYPE_SA && iph2 != p && !p->is_dying && iph2->spid == p->spid) {
733 if (FSM_STATE_IS_NEGOTIATING(p->status)) {
734 return 1;
735 }
d1e348cf
A
736 }
737 }
65c25746 738
d1e348cf
A
739 return 0;
740}
741
d1e348cf
A
742
743void
65c25746 744ike_session_ikev1_float_ports (phase1_handle_t *iph1)
d1e348cf 745{
85f41bec 746 struct sockaddr_storage *local, *remote;
65c25746 747 phase2_handle_t *p;
d1e348cf
A
748
749 if (iph1->parent_session) {
85f41bec
A
750 local = &iph1->parent_session->session_id.local;
751 remote = &iph1->parent_session->session_id.remote;
d1e348cf
A
752
753 set_port(local, extract_port(iph1->local));
754 set_port(remote, extract_port(iph1->remote));
755 iph1->parent_session->ports_floated = 1;
756
65c25746 757 LIST_FOREACH(p, &iph1->parent_session->ph2tree, ph2ofsession_chain) {
d1e348cf
A
758
759 local = p->src;
760 remote = p->dst;
761
762 set_port(local, extract_port(iph1->local));
763 set_port(remote, extract_port(iph1->remote));
764 }
765 } else {
7ebaebe2 766 plog(ASL_LEVEL_NOTICE, "invalid parent session in %s.\n", __FUNCTION__);
d1e348cf
A
767 }
768}
769
770static void
771ike_session_traffic_cop (void *arg)
772{
773 ike_session_t *session = (__typeof__(session))arg;
774
e8d9021d
A
775 if (session &&
776 (session->established && !session->stopped_by_vpn_controller && !session->stop_timestamp.tv_sec && !session->stop_timestamp.tv_usec)) {
d1e348cf
A
777 SCHED_KILL(session->traffic_monitor.sc_mon);
778 /* get traffic query from kernel */
779 if (pk_sendget_inbound_sastats(session) < 0) {
780 // log message
7ebaebe2 781 plog(ASL_LEVEL_NOTICE, "pk_sendget_inbound_sastats failed in %s.\n", __FUNCTION__);
d1e348cf
A
782 }
783 if (pk_sendget_outbound_sastats(session) < 0) {
784 // log message
7ebaebe2 785 plog(ASL_LEVEL_NOTICE, "pk_sendget_outbound_sastats failed in %s.\n", __FUNCTION__);
d1e348cf
A
786 }
787 session->traffic_monitor.sc_mon = sched_new(session->traffic_monitor.interv_mon,
788 ike_session_traffic_cop,
789 session);
790 } else {
791 // log message
7ebaebe2 792 plog(ASL_LEVEL_ERR, "invalid parameters in %s.\n", __FUNCTION__);
d1e348cf
A
793 }
794}
795
796static void
797ike_session_cleanup_idle (void *arg)
798{
47612122
A
799 ike_session_cleanup((ike_session_t *)arg, ike_session_stopped_by_idle);
800}
801
802static void
803ike_session_monitor_idle (ike_session_t *session)
804{
805 if (!session)
806 return;
d1e348cf
A
807
808 if (session->traffic_monitor.dir_idle == IPSEC_DIR_INBOUND ||
809 session->traffic_monitor.dir_idle == IPSEC_DIR_ANY) {
810 if (session->peer_sent_data_sc_idle) {
7ebaebe2
A
811 plog(ASL_LEVEL_NOTICE, "%s: restart idle-timeout because peer sent data. monitoring dir %d. idle timer %d s\n",
812 __FUNCTION__, session->traffic_monitor.dir_idle, session->traffic_monitor.interv_idle);
d1e348cf 813 SCHED_KILL(session->traffic_monitor.sc_idle);
47612122
A
814 if (session->traffic_monitor.interv_idle) {
815 session->traffic_monitor.sc_idle = sched_new(session->traffic_monitor.interv_idle,
816 ike_session_cleanup_idle,
817 session);
818 }
d1e348cf
A
819 session->peer_sent_data_sc_idle = 0;
820 session->i_sent_data_sc_idle = 0;
821 return;
822 }
823 }
824 if (session->traffic_monitor.dir_idle == IPSEC_DIR_OUTBOUND ||
825 session->traffic_monitor.dir_idle == IPSEC_DIR_ANY) {
826 if (session->i_sent_data_sc_idle) {
7ebaebe2
A
827 plog(ASL_LEVEL_NOTICE, "%s: restart idle-timeout because i sent data. monitoring dir %d. idle times %d s\n",
828 __FUNCTION__, session->traffic_monitor.dir_idle, session->traffic_monitor.interv_idle);
d1e348cf 829 SCHED_KILL(session->traffic_monitor.sc_idle);
47612122
A
830 if (session->traffic_monitor.interv_idle) {
831 session->traffic_monitor.sc_idle = sched_new(session->traffic_monitor.interv_idle,
832 ike_session_cleanup_idle,
833 session);
834 }
d1e348cf
A
835 session->peer_sent_data_sc_idle = 0;
836 session->i_sent_data_sc_idle = 0;
837 return;
838 }
839 }
d1e348cf
A
840}
841
e8d9021d
A
842static void
843ike_session_start_traffic_mon (ike_session_t *session)
844{
845 if (session->traffic_monitor.interv_mon) {
846 session->traffic_monitor.sc_mon = sched_new(session->traffic_monitor.interv_mon,
847 ike_session_traffic_cop,
848 session);
849 }
850 if (session->traffic_monitor.interv_idle) {
851 session->traffic_monitor.sc_idle = sched_new(session->traffic_monitor.interv_idle,
852 ike_session_cleanup_idle,
853 session);
854 }
855}
856
d1e348cf 857void
65c25746 858ike_session_ph2_established (phase2_handle_t *iph2)
d1e348cf 859{
65c25746 860 if (!iph2->parent_session || iph2->phase2_type != PHASE2_TYPE_SA) {
7ebaebe2 861 plog(ASL_LEVEL_ERR, "invalid parameters in %s.\n", __FUNCTION__);
d1e348cf
A
862 return;
863 }
864 SCHED_KILL(iph2->parent_session->sc_xauth);
865 if (!iph2->parent_session->established) {
866 gettimeofday(&iph2->parent_session->estab_timestamp, NULL);
867 iph2->parent_session->established = 1;
e8d9021d
A
868 IPSECSESSIONTRACERESTABLISHED(iph2->parent_session);
869 ike_session_start_traffic_mon(iph2->parent_session);
870 } else if (iph2->parent_session->is_asserted) {
871 ike_session_start_traffic_mon(iph2->parent_session);
d1e348cf 872 }
e8d9021d 873 iph2->parent_session->is_asserted = 0;
d1e348cf
A
874 // nothing happening to this session
875 iph2->parent_session->term_reason = NULL;
876
877 ike_session_update_mode(iph2);
65c25746
A
878 if (iph2->version == ISAKMP_VERSION_NUMBER_IKEV1)
879 ike_session_unbindph12(iph2);
e8d9021d
A
880
881#ifdef ENABLE_VPNCONTROL_PORT
882 vpncontrol_notify_peer_resp_ph2(1, iph2);
883#endif /* ENABLE_VPNCONTROL_PORT */
7ebaebe2 884 plog(ASL_LEVEL_NOTICE, "%s: ph2 established, spid %d\n", __FUNCTION__, iph2->spid);
d1e348cf
A
885}
886
887void
65c25746 888ike_session_cleanup_ph1 (phase1_handle_t *iph1)
d1e348cf 889{
65c25746 890 if (FSM_STATE_IS_EXPIRED(iph1->status)) {
d1e348cf
A
891 // since this got here via ike_session_cleanup_other_established_ph1s, assumes LIST_FIRST(&iph1->ph2tree) == NULL
892 iph1->sce = sched_new(1, isakmp_ph1delete_stub, iph1);
893 return;
894 }
895
896 /* send delete information */
65c25746 897 if (FSM_STATE_IS_ESTABLISHED(iph1->status)) {
d1e348cf
A
898 isakmp_info_send_d1(iph1);
899 }
900
901 isakmp_ph1expire(iph1);
902}
903
904void
905ike_session_cleanup_ph1_stub (void *p)
906{
907
65c25746
A
908 ike_session_cleanup_ph1((phase1_handle_t *)p);
909}
910
911void
912ike_session_replace_other_ph1 (phase1_handle_t *new_iph1,
913 phase1_handle_t *old_iph1)
914{
915 char *local, *remote, *index;
916 ike_session_t *session = NULL;
917
918 if (new_iph1)
919 session = new_iph1->parent_session;
920
921 if (!session || !new_iph1 || !old_iph1 || session != old_iph1->parent_session || new_iph1 == old_iph1) {
7ebaebe2 922 plog(ASL_LEVEL_ERR, "invalid parameters in %s.\n", __FUNCTION__);
65c25746
A
923 return;
924 }
925
926 /*
927 * if we are responder, then we should wait until the server sends a delete notification.
928 */
d9c572c0 929 if (session->is_client &&
65c25746
A
930 new_iph1->side == RESPONDER) {
931 return;
932 }
933
934 SCHED_KILL(old_iph1->sce);
935 SCHED_KILL(old_iph1->sce_rekey);
936 old_iph1->is_dying = 1;
937
938 //log deletion
939 local = racoon_strdup(saddr2str((struct sockaddr *)old_iph1->local));
940 remote = racoon_strdup(saddr2str((struct sockaddr *)old_iph1->remote));
941 index = racoon_strdup(isakmp_pindex(&old_iph1->index, 0));
942 STRDUP_FATAL(local);
943 STRDUP_FATAL(remote);
944 STRDUP_FATAL(index);
7ebaebe2 945 plog(ASL_LEVEL_NOTICE, "ISAKMP-SA %s-%s (spi:%s) needs to be deleted, replaced by (spi:%s)\n", local, remote, index, isakmp_pindex(&new_iph1->index, 0));
65c25746
A
946 racoon_free(local);
947 racoon_free(remote);
948 racoon_free(index);
949
950 // first rebind the children ph2s of this dying ph1 to the new ph1.
951 ike_session_rebind_all_ph12_to_new_ph1 (old_iph1, new_iph1);
952
953 if (old_iph1->side == INITIATOR) {
954 /* everyone deletes old outbound SA */
955 old_iph1->sce = sched_new(5, ike_session_cleanup_ph1_stub, old_iph1);
956 } else {
957 /* responder sets up timer to delete old inbound SAs... say 7 secs later and flags them as rekeyed */
958 old_iph1->sce = sched_new(7, ike_session_cleanup_ph1_stub, old_iph1);
959 }
d1e348cf
A
960}
961
962void
963ike_session_cleanup_other_established_ph1s (ike_session_t *session,
65c25746 964 phase1_handle_t *new_iph1)
d1e348cf 965{
65c25746 966 phase1_handle_t *p, *next;
d1e348cf
A
967 char *local, *remote;
968
969 if (!session || !new_iph1 || session != new_iph1->parent_session) {
7ebaebe2 970 plog(ASL_LEVEL_ERR, "invalid parameters in %s.\n", __FUNCTION__);
d1e348cf
A
971 return;
972 }
973
b8c37798
A
974 /*
975 * if we are responder, then we should wait until the server sends a delete notification.
976 */
d9c572c0 977 if (session->is_client &&
65c25746 978 new_iph1->side == RESPONDER) {
b8c37798
A
979 return;
980 }
981
65c25746 982 LIST_FOREACH_SAFE(p, &session->ph1tree, ph1ofsession_chain, next) {
d1e348cf
A
983 /*
984 * TODO: currently, most recently established SA wins. Need to revisit to see if
985 * alternative selections is better (e.g. largest p->index stays).
986 */
80318cb7 987 if (p != new_iph1 && !p->is_dying) {
d1e348cf
A
988 SCHED_KILL(p->sce);
989 SCHED_KILL(p->sce_rekey);
990 p->is_dying = 1;
991
992 //log deletion
85f41bec
A
993 local = racoon_strdup(saddr2str((struct sockaddr *)p->local));
994 remote = racoon_strdup(saddr2str((struct sockaddr *)p->remote));
d1e348cf
A
995 STRDUP_FATAL(local);
996 STRDUP_FATAL(remote);
7ebaebe2 997 plog(ASL_LEVEL_NOTICE,
d1e348cf
A
998 "ISAKMP-SA needs to be deleted %s-%s spi:%s\n",
999 local, remote, isakmp_pindex(&p->index, 0));
1000 racoon_free(local);
1001 racoon_free(remote);
1002
65c25746
A
1003 // first rebind the children ph2s of this dying ph1 to the new ph1.
1004 ike_session_rebind_all_ph12_to_new_ph1 (p, new_iph1);
d1e348cf
A
1005
1006 if (p->side == INITIATOR) {
1007 /* everyone deletes old outbound SA */
1008 p->sce = sched_new(5, ike_session_cleanup_ph1_stub, p);
1009 } else {
1010 /* responder sets up timer to delete old inbound SAs... say 7 secs later and flags them as rekeyed */
1011 p->sce = sched_new(7, ike_session_cleanup_ph1_stub, p);
1012 }
1013 }
1014 }
1015}
1016
1017void
65c25746 1018ike_session_cleanup_ph2 (phase2_handle_t *iph2)
d1e348cf 1019{
65c25746
A
1020 if (iph2->phase2_type != PHASE2_TYPE_SA)
1021 return;
1022 if (FSM_STATE_IS_EXPIRED(iph2->status)) {
e8d9021d
A
1023 return;
1024 }
d1e348cf 1025
e8d9021d 1026 SCHED_KILL(iph2->sce);
d1e348cf 1027
65c25746 1028 plog(ASL_LEVEL_ERR,
80318cb7
A
1029 "about to cleanup ph2: status %d, seq %d dying %d\n",
1030 iph2->status, iph2->seq, iph2->is_dying);
e8d9021d 1031
d1e348cf 1032 /* send delete information */
65c25746 1033 if (FSM_STATE_IS_ESTABLISHED(iph2->status)) {
d1e348cf 1034 isakmp_info_send_d2(iph2);
d1e348cf 1035
e8d9021d
A
1036 // delete outgoing SAs
1037 if (iph2->approval) {
1038 struct saproto *pr;
1039
1040 for (pr = iph2->approval->head; pr != NULL; pr = pr->next) {
1041 if (pr->ok) {
1042 pfkey_send_delete(lcconf->sock_pfkey,
d1e348cf
A
1043 ipsecdoi2pfkey_proto(pr->proto_id),
1044 IPSEC_MODE_ANY,
1045 iph2->src, iph2->dst, pr->spi_p /* pr->reqid_out */);
e8d9021d
A
1046 }
1047 }
1048 }
1049 }
d1e348cf 1050
e8d9021d 1051 delete_spd(iph2);
65c25746 1052 ike_session_unlink_phase2(iph2);
d1e348cf
A
1053}
1054
1055void
1056ike_session_cleanup_ph2_stub (void *p)
1057{
1058
65c25746 1059 ike_session_cleanup_ph2((phase2_handle_t *)p);
d1e348cf
A
1060}
1061
1062void
1063ike_session_cleanup_other_established_ph2s (ike_session_t *session,
65c25746 1064 phase2_handle_t *new_iph2)
d1e348cf 1065{
65c25746 1066 phase2_handle_t *p, *next;
d1e348cf 1067
65c25746 1068 if (!session || !new_iph2 || session != new_iph2->parent_session || new_iph2->phase2_type != PHASE2_TYPE_SA) {
7ebaebe2 1069 plog(ASL_LEVEL_ERR, "invalid parameters in %s.\n", __FUNCTION__);
d1e348cf
A
1070 return;
1071 }
1072
b8c37798
A
1073 /*
1074 * if we are responder, then we should wait until the server sends a delete notification.
1075 */
1076 if (session->is_client && new_iph2->side == RESPONDER) {
1077 return;
1078 }
1079
65c25746 1080 LIST_FOREACH_SAFE(p, &session->ph2tree, ph2ofsession_chain, next) {
d1e348cf
A
1081 /*
1082 * TODO: currently, most recently established SA wins. Need to revisit to see if
1083 * alternative selections is better.
1084 */
80318cb7 1085 if (p != new_iph2 && p->spid == new_iph2->spid && !p->is_dying) {
d1e348cf
A
1086 SCHED_KILL(p->sce);
1087 p->is_dying = 1;
1088
1089 //log deletion
7ebaebe2 1090 plog(ASL_LEVEL_NOTICE,
d1e348cf
A
1091 "IPsec-SA needs to be deleted: %s\n",
1092 sadbsecas2str(p->src, p->dst,
1093 p->satype, p->spid, 0));
1094
1095 if (p->side == INITIATOR) {
1096 /* responder sets up timer to delete old inbound SAs... say 5 secs later and flags them as rekeyed */
1097 p->sce = sched_new(3, ike_session_cleanup_ph2_stub, p);
1098 } else {
1099 /* responder sets up timer to delete old inbound SAs... say 5 secs later and flags them as rekeyed */
1100 p->sce = sched_new(5, ike_session_cleanup_ph2_stub, p);
1101 }
1102 }
1103 }
1104}
1105
1106void
1107ike_session_stopped_by_controller (ike_session_t *session,
1108 const char *reason)
1109{
1110 if (!session) {
7ebaebe2 1111 plog(ASL_LEVEL_ERR, "invalid parameters in %s.\n", __FUNCTION__);
d1e348cf
A
1112 return;
1113 }
1114 if (session->stop_timestamp.tv_sec ||
1115 session->stop_timestamp.tv_usec) {
7ebaebe2 1116 plog(ASL_LEVEL_NOTICE, "already stopped %s.\n", __FUNCTION__);
d1e348cf
A
1117 return;
1118 }
1119 session->stopped_by_vpn_controller = 1;
1120 gettimeofday(&session->stop_timestamp, NULL);
1121 if (!session->term_reason) {
65c25746 1122 session->term_reason = (__typeof__(session->term_reason))reason;
d1e348cf
A
1123 }
1124}
1125
1126void
85f41bec 1127ike_sessions_stopped_by_controller (struct sockaddr_storage *remote,
d1e348cf
A
1128 int withport,
1129 const char *reason)
1130{
1131 ike_session_t *p = NULL;
65c25746 1132 ike_session_t *next_session = NULL;
d1e348cf
A
1133
1134 if (!remote) {
7ebaebe2 1135 plog(ASL_LEVEL_ERR, "invalid parameters in %s.\n", __FUNCTION__);
d1e348cf
A
1136 return;
1137 }
1138
65c25746
A
1139 LIST_FOREACH_SAFE(p, &ike_session_tree, chain, next_session) {
1140 if ((withport && cmpsaddrstrict(&p->session_id.remote, remote) == 0) ||
1141 (!withport && cmpsaddrwop(&p->session_id.remote, remote) == 0)) {
d1e348cf
A
1142 ike_session_stopped_by_controller(p, reason);
1143 }
1144 }
1145}
1146
d06a7ccb
A
1147void
1148ike_session_purge_ph1s_by_session (ike_session_t *session)
1149{
1150 phase1_handle_t *iph1;
1151 phase1_handle_t *next_iph1 = NULL;
1152
1153 LIST_FOREACH_SAFE(iph1, &session->ph1tree, ph1ofsession_chain, next_iph1) {
7ebaebe2 1154 plog(ASL_LEVEL_NOTICE, "deleteallph1 of given session: got a ph1 handler...\n");
d06a7ccb
A
1155
1156 vpncontrol_notify_ike_failed(VPNCTL_NTYPE_NO_PROPOSAL_CHOSEN, FROM_REMOTE,
1157 iph1_get_remote_v4_address(iph1), 0, NULL);
1158
1159 ike_session_unlink_phase1(iph1);
1160 }
1161}
1162
d1e348cf 1163void
65c25746 1164ike_session_purge_ph2s_by_ph1 (phase1_handle_t *iph1)
d1e348cf 1165{
65c25746 1166 phase2_handle_t *p, *next;
d1e348cf
A
1167
1168 if (!iph1 || !iph1->parent_session) {
7ebaebe2 1169 plog(ASL_LEVEL_ERR, "invalid parameters in %s.\n", __FUNCTION__);
d1e348cf
A
1170 return;
1171 }
1172
65c25746 1173 LIST_FOREACH_SAFE(p, &iph1->parent_session->ph2tree, ph2ofsession_chain, next) {
80318cb7
A
1174 if (p->is_dying) {
1175 continue;
1176 }
d1e348cf
A
1177 SCHED_KILL(p->sce);
1178 p->is_dying = 1;
1179
1180 //log deletion
7ebaebe2 1181 plog(ASL_LEVEL_NOTICE,
d1e348cf
A
1182 "IPsec-SA needs to be purged: %s\n",
1183 sadbsecas2str(p->src, p->dst,
1184 p->satype, p->spid, 0));
1185
1186 ike_session_cleanup_ph2(p);
1187 }
1188}
1189
1190void
65c25746 1191ike_session_update_ph2_ports (phase2_handle_t *iph2)
d1e348cf 1192{
85f41bec
A
1193 struct sockaddr_storage *local;
1194 struct sockaddr_storage *remote;
d1e348cf
A
1195
1196 if (iph2->parent_session) {
85f41bec
A
1197 local = &iph2->parent_session->session_id.local;
1198 remote = &iph2->parent_session->session_id.remote;
d1e348cf
A
1199
1200 set_port(iph2->src, extract_port(local));
1201 set_port(iph2->dst, extract_port(remote));
1202 } else {
7ebaebe2 1203 plog(ASL_LEVEL_NOTICE, "invalid parent session in %s.\n", __FUNCTION__);
d1e348cf
A
1204 }
1205}
1206
1207u_int32_t
1208ike_session_get_sas_for_stats (ike_session_t *session,
1209 u_int8_t dir,
1210 u_int32_t *seq,
1211 struct sastat *stats,
1212 u_int32_t max_stats)
1213{
1214 int found = 0;
65c25746 1215 phase2_handle_t *iph2;
d1e348cf
A
1216
1217 if (!session || !seq || !stats || !max_stats || (dir != IPSEC_DIR_INBOUND && dir != IPSEC_DIR_OUTBOUND)) {
7ebaebe2 1218 plog(ASL_LEVEL_ERR, "invalid args in %s.\n", __FUNCTION__);
d1e348cf
A
1219 return found;
1220 }
1221
1222 *seq = 0;
65c25746 1223 LIST_FOREACH(iph2, &session->ph2tree, ph2ofsession_chain) {
d1e348cf
A
1224 if (iph2->approval) {
1225 struct saproto *pr;
1226
1227 for (pr = iph2->approval->head; pr != NULL; pr = pr->next) {
1228 if (pr->ok && pr->proto_id == IPSECDOI_PROTO_IPSEC_ESP) {
1229 if (!*seq) {
1230 *seq = iph2->seq;
1231 }
1232 if (dir == IPSEC_DIR_INBOUND) {
1233 stats[found].spi = pr->spi;
1234 } else {
1235 stats[found].spi = pr->spi_p;
1236 }
1237 if (++found == max_stats) {
1238 return found;
1239 }
1240 }
1241 }
1242 }
1243 }
1244 return found;
1245}
1246
1247void
1248ike_session_update_traffic_idle_status (ike_session_t *session,
1249 u_int32_t dir,
1250 struct sastat *new_stats,
1251 u_int32_t max_stats)
1252{
1253 int i, j, found = 0, idle = 1;
1254
1255 if (!session || !new_stats || (dir != IPSEC_DIR_INBOUND && dir != IPSEC_DIR_OUTBOUND)) {
7ebaebe2 1256 plog(ASL_LEVEL_ERR, "invalid args in %s.\n", __FUNCTION__);
d1e348cf
A
1257 return;
1258 }
1259
47612122 1260 if (!session->established || session->stopped_by_vpn_controller || session->stop_timestamp.tv_sec || session->stop_timestamp.tv_usec) {
7ebaebe2 1261 plog(ASL_LEVEL_NOTICE, "dropping update on invalid session in %s.\n", __FUNCTION__);
47612122
A
1262 return;
1263 }
1264
d1e348cf
A
1265 for (i = 0; i < max_stats; i++) {
1266 if (dir == IPSEC_DIR_INBOUND) {
1267 for (j = 0; j < session->traffic_monitor.num_in_last_poll; j++) {
1268 if (new_stats[i].spi != session->traffic_monitor.in_last_poll[j].spi) {
1269 continue;
1270 }
1271 found = 1;
1272 if (new_stats[i].lft_c.sadb_lifetime_bytes != session->traffic_monitor.in_last_poll[j].lft_c.sadb_lifetime_bytes) {
1273 idle = 0;
1274 }
1275 }
1276 } else {
1277 for (j = 0; j < session->traffic_monitor.num_out_last_poll; j++) {
1278 if (new_stats[i].spi != session->traffic_monitor.out_last_poll[j].spi) {
1279 continue;
1280 }
1281 found = 1;
1282 if (new_stats[i].lft_c.sadb_lifetime_bytes != session->traffic_monitor.out_last_poll[j].lft_c.sadb_lifetime_bytes) {
1283 idle = 0;
1284 }
1285 }
1286 }
1287 // new SA.... check for any activity
1288 if (!found) {
1289 if (new_stats[i].lft_c.sadb_lifetime_bytes) {
7ebaebe2 1290 plog(ASL_LEVEL_NOTICE, "new SA: dir %d....\n", dir);
d1e348cf
A
1291 idle = 0;
1292 }
1293 }
1294 }
1295 if (dir == IPSEC_DIR_INBOUND) {
1296 // overwrite old stats
1297 bzero(session->traffic_monitor.in_last_poll, sizeof(session->traffic_monitor.in_last_poll));
1298 bcopy(new_stats, session->traffic_monitor.in_last_poll, (max_stats * sizeof(*new_stats)));
1299 session->traffic_monitor.num_in_last_poll = max_stats;
1300 if (!idle) {
65c25746 1301 //plog(ASL_LEVEL_DEBUG, "peer sent data....\n");
d1e348cf
A
1302 session->peer_sent_data_sc_dpd = 1;
1303 session->peer_sent_data_sc_idle = 1;
1304 }
1305 } else {
1306 // overwrite old stats
1307 bzero(session->traffic_monitor.out_last_poll, sizeof(session->traffic_monitor.out_last_poll));
1308 bcopy(new_stats, session->traffic_monitor.out_last_poll, (max_stats * sizeof(*new_stats)));
1309 session->traffic_monitor.num_out_last_poll = max_stats;
1310 if (!idle) {
65c25746 1311 //plog(ASL_LEVEL_DEBUG, "i sent data....\n");
d1e348cf
A
1312 session->i_sent_data_sc_dpd = 1;
1313 session->i_sent_data_sc_idle = 1;
1314 }
1315 }
fce29cd9
A
1316 if (!idle)
1317 session->last_time_data_sc_detected = time(NULL);
47612122
A
1318
1319 ike_session_monitor_idle(session);
d1e348cf
A
1320}
1321
1322void
1323ike_session_cleanup (ike_session_t *session,
1324 const char *reason)
1325{
65c25746
A
1326 phase2_handle_t *iph2 = NULL;
1327 phase2_handle_t *next_iph2 = NULL;
1328 phase1_handle_t *iph1 = NULL;
1329 phase1_handle_t *next_iph1 = NULL;
7ebaebe2 1330 nw_nat64_prefix_t nat64_prefix;
d1e348cf
A
1331
1332 if (!session)
1333 return;
1334
7ebaebe2 1335 memset(&nat64_prefix, 0, sizeof(nat64_prefix));
e8d9021d 1336 session->is_dying = 1;
65c25746 1337 ike_session_stopped_by_controller(session, reason);
e8d9021d 1338
47612122 1339 SCHED_KILL(session->traffic_monitor.sc_idle);
d1e348cf 1340 // do ph2's first... we need the ph1s for notifications
65c25746
A
1341 LIST_FOREACH_SAFE(iph2, &session->ph2tree, ph2ofsession_chain, next_iph2) {
1342 if (FSM_STATE_IS_ESTABLISHED(iph2->status)) {
d1e348cf
A
1343 isakmp_info_send_d2(iph2);
1344 }
1345 isakmp_ph2expire(iph2); // iph2 will go down 1 second later.
d1e348cf
A
1346 }
1347
1348 // do the ph1s last.
65c25746 1349 LIST_FOREACH_SAFE(iph1, &session->ph1tree, ph1ofsession_chain, next_iph1) {
7ebaebe2
A
1350
1351 if (iph1->nat64_prefix.length > 0) {
1352 memcpy(&nat64_prefix, &iph1->nat64_prefix, sizeof(nat64_prefix));
1353 }
1354
65c25746 1355 if (FSM_STATE_IS_ESTABLISHED(iph1->status)) {
d1e348cf
A
1356 isakmp_info_send_d1(iph1);
1357 }
1358 isakmp_ph1expire(iph1);
1359 }
e8d9021d 1360
d1e348cf 1361 // send ipsecManager a notification
85f41bec
A
1362 if (session->is_cisco_ipsec && reason && reason != ike_session_stopped_by_vpn_disconnect
1363 && reason != ike_session_stopped_by_controller_comm_lost) {
7ebaebe2 1364 u_int32_t address = 0;
85f41bec 1365 if ((&session->session_id.remote)->ss_family == AF_INET) {
d1e348cf
A
1366 address = ((struct sockaddr_in *)&session->session_id.remote)->sin_addr.s_addr;
1367 } else {
7ebaebe2
A
1368 if (nat64_prefix.length > 0) {
1369 struct in_addr inaddr;
1370 nw_nat64_extract_v4(&nat64_prefix,
1371 &((struct sockaddr_in6 *)&session->session_id.remote)->sin6_addr,
1372 &inaddr);
1373 address = inaddr.s_addr;
1374 }
d1e348cf 1375 }
e8d9021d
A
1376 // TODO: log
1377 if (reason == ike_session_stopped_by_idle) {
1378 (void)vpncontrol_notify_ike_failed(VPNCTL_NTYPE_IDLE_TIMEOUT, FROM_LOCAL, address, 0, NULL);
1379 } else {
1380 (void)vpncontrol_notify_ike_failed(VPNCTL_NTYPE_INTERNAL_ERROR, FROM_LOCAL, address, 0, NULL);
1381 }
d1e348cf
A
1382 }
1383}
1384
1385int
1386ike_session_has_negoing_ph1 (ike_session_t *session)
1387{
65c25746 1388 phase1_handle_t *p;
d1e348cf
A
1389
1390 if (!session) {
7ebaebe2 1391 plog(ASL_LEVEL_ERR, "invalid parameters in %s.\n", __FUNCTION__);
d1e348cf
A
1392 return 0;
1393 }
1394
65c25746
A
1395 LIST_FOREACH(p, &session->ph1tree, ph1ofsession_chain) {
1396 if (!p->is_dying && FSM_STATE_IS_NEGOTIATING(p->status)) {
d1e348cf
A
1397 return 1;
1398 }
1399 }
1400
1401 return 0;
1402}
1403
e8d9021d
A
1404int
1405ike_session_has_established_ph1 (ike_session_t *session)
1406{
65c25746 1407 phase1_handle_t *p;
e8d9021d
A
1408
1409 if (!session) {
7ebaebe2 1410 plog(ASL_LEVEL_ERR, "invalid parameters in %s.\n", __FUNCTION__);
e8d9021d
A
1411 return 0;
1412 }
1413
65c25746
A
1414 LIST_FOREACH(p, &session->ph1tree, ph1ofsession_chain) {
1415 if (!p->is_dying && FSM_STATE_IS_ESTABLISHED(p->status)) {
e8d9021d
A
1416 return 1;
1417 }
1418 }
1419
1420 return 0;
1421}
1422
d1e348cf
A
1423int
1424ike_session_has_negoing_ph2 (ike_session_t *session)
1425{
65c25746 1426 phase2_handle_t *p;
d1e348cf
A
1427
1428 if (!session) {
7ebaebe2 1429 plog(ASL_LEVEL_ERR, "invalid parameters in %s.\n", __FUNCTION__);
d1e348cf
A
1430 return 0;
1431 }
1432
65c25746
A
1433 LIST_FOREACH(p, &session->ph2tree, ph2ofsession_chain) {
1434 if (!p->is_dying && FSM_STATE_IS_NEGOTIATING(p->status)) {
d1e348cf
A
1435 return 1;
1436 }
1437 }
1438
1439 return 0;
1440}
1441
1442int
1443ike_session_has_established_ph2 (ike_session_t *session)
1444{
65c25746 1445 phase2_handle_t *p;
d1e348cf
A
1446
1447 if (!session) {
7ebaebe2 1448 plog(ASL_LEVEL_ERR, "invalid parameters in %s.\n", __FUNCTION__);
d1e348cf
A
1449 return 0;
1450 }
1451
65c25746
A
1452 LIST_FOREACH(p, &session->ph2tree, ph2ofsession_chain) {
1453 if (!p->is_dying && FSM_STATE_IS_ESTABLISHED(p->status)) {
d1e348cf
A
1454 return 1;
1455 }
1456 }
1457
1458 return 0;
1459}
1460
1461void
65c25746 1462ike_session_cleanup_ph1s_by_ph2 (phase2_handle_t *iph2)
d1e348cf 1463{
65c25746
A
1464 phase1_handle_t *iph1 = NULL;
1465 phase1_handle_t *next_iph1 = NULL;
d1e348cf
A
1466
1467 if (!iph2 || !iph2->parent_session) {
7ebaebe2 1468 plog(ASL_LEVEL_ERR, "invalid parameters in %s.\n", __FUNCTION__);
d1e348cf
A
1469 return;
1470 }
1471
1472 // phase1 is no longer useful
65c25746
A
1473 LIST_FOREACH_SAFE(iph1, &iph2->parent_session->ph1tree, ph1ofsession_chain, next_iph1) {
1474 if (FSM_STATE_IS_ESTABLISHED(iph1->status)) {
d1e348cf
A
1475 isakmp_info_send_d1(iph1);
1476 }
1477 isakmp_ph1expire(iph1);
1478 }
1479}
1480
1481int
65c25746 1482ike_session_is_client_ph2_rekey (phase2_handle_t *iph2)
d1e348cf
A
1483{
1484 if (iph2->parent_session &&
1485 iph2->parent_session->is_client &&
1486 iph2->is_rekey &&
1487 iph2->parent_session->is_cisco_ipsec) {
1488 return 1;
1489 }
1490 return 0;
1491}
1492
1493int
65c25746 1494ike_session_is_client_ph1_rekey (phase1_handle_t *iph1)
d1e348cf
A
1495{
1496 if (iph1->parent_session &&
1497 iph1->parent_session->is_client &&
1498 iph1->is_rekey &&
1499 iph1->parent_session->is_cisco_ipsec) {
1500 return 1;
1501 }
1502 return 0;
1503}
1504
65c25746
A
1505int
1506ike_session_is_client_ph1 (phase1_handle_t *iph1)
1507{
1508 if (iph1->parent_session &&
1509 iph1->parent_session->is_client) {
1510 return 1;
1511 }
1512 return 0;
1513}
1514
1515int
1516ike_session_is_client_ph2 (phase2_handle_t *iph2)
1517{
1518 if (iph2->parent_session &&
1519 iph2->parent_session->is_client) {
1520 return 1;
1521 }
1522 return 0;
1523}
1524
d1e348cf 1525void
65c25746 1526ike_session_start_xauth_timer (phase1_handle_t *iph1)
d1e348cf
A
1527{
1528 // if there are no more established ph2s, start a timer to teardown the session
1529 if (iph1->parent_session &&
1530 iph1->parent_session->is_client &&
1531 iph1->parent_session->is_cisco_ipsec &&
1532 !iph1->parent_session->sc_xauth) {
1533 iph1->parent_session->sc_xauth = sched_new(300 /* 5 mins */,
1534 ike_session_cleanup_xauth_timeout,
1535 iph1->parent_session);
1536 }
1537}
1538
1539void
65c25746 1540ike_session_stop_xauth_timer (phase1_handle_t *iph1)
d1e348cf
A
1541{
1542 if (iph1->parent_session) {
1543 SCHED_KILL(iph1->parent_session->sc_xauth);
1544 }
47612122
A
1545}
1546
1547static int
1548ike_session_is_id_ipany (vchar_t *ext_id)
1549{
1550 struct id {
1551 u_int8_t type; /* ID Type */
1552 u_int8_t proto_id; /* Protocol ID */
1553 u_int16_t port; /* Port */
1554 u_int32_t addr; /* IPv4 address */
1555 u_int32_t mask;
1556 } *id_ptr;
1557
1558 /* ignore protocol and port */
85f41bec 1559 id_ptr = ALIGNED_CAST(struct id *)ext_id->v;
47612122
A
1560 if (id_ptr->type == IPSECDOI_ID_IPV4_ADDR &&
1561 id_ptr->addr == 0) {
1562 return 1;
1563 } else if (id_ptr->type == IPSECDOI_ID_IPV4_ADDR_SUBNET &&
1564 id_ptr->mask == 0 &&
1565 id_ptr->addr == 0) {
1566 return 1;
1567 }
65c25746 1568 plog(ASL_LEVEL_DEBUG, "not ipany_ids in %s: type %d, addr %x, mask %x.\n",
47612122
A
1569 __FUNCTION__, id_ptr->type, id_ptr->addr, id_ptr->mask);
1570 return 0;
1571}
1572
80318cb7
A
1573static int
1574ike_session_is_id_portany (vchar_t *ext_id)
1575{
1576 struct id {
1577 u_int8_t type; /* ID Type */
1578 u_int8_t proto_id; /* Protocol ID */
1579 u_int16_t port; /* Port */
1580 u_int32_t addr; /* IPv4 address */
1581 u_int32_t mask;
1582 } *id_ptr;
1583
1584 /* ignore addr */
85f41bec 1585 id_ptr = ALIGNED_CAST(struct id *)ext_id->v;
80318cb7
A
1586 if (id_ptr->type == IPSECDOI_ID_IPV4_ADDR &&
1587 id_ptr->port == 0) {
1588 return 1;
1589 }
65c25746 1590 plog(ASL_LEVEL_DEBUG, "not portany_ids in %s: type %d, port %x.\n",
80318cb7
A
1591 __FUNCTION__, id_ptr->type, id_ptr->port);
1592 return 0;
1593}
1594
1595static void
1596ike_session_set_id_portany (vchar_t *ext_id)
1597{
1598 struct id {
1599 u_int8_t type; /* ID Type */
1600 u_int8_t proto_id; /* Protocol ID */
1601 u_int16_t port; /* Port */
1602 u_int32_t addr; /* IPv4 address */
1603 u_int32_t mask;
1604 } *id_ptr;
1605
1606 /* ignore addr */
85f41bec 1607 id_ptr = ALIGNED_CAST(struct id *)ext_id->v;
80318cb7
A
1608 if (id_ptr->type == IPSECDOI_ID_IPV4_ADDR) {
1609 id_ptr->port = 0;
1610 return;
1611 }
1612}
1613
47612122
A
1614static int
1615ike_session_cmp_ph2_ids_ipany (vchar_t *ext_id,
1616 vchar_t *ext_id_p)
1617{
1618 if (ike_session_is_id_ipany(ext_id) &&
1619 ike_session_is_id_ipany(ext_id_p)) {
1620 return 1;
1621 }
1622 return 0;
1623}
1624
80318cb7
A
1625/*
1626 * ipsec rekeys for l2tp-over-ipsec fail particularly when client is behind nat because the client's configs and policies don't
1627 * match the server's view of the client's address and port.
1628 * servers behave differently when using this address-port info to generate ids during phase2 rekeys, so try to match the incoming id to
1629 * a variety of info saved in the older phase2.
1630 */
1631int
65c25746
A
1632ike_session_cmp_ph2_ids (phase2_handle_t *iph2,
1633 phase2_handle_t *older_ph2)
47612122 1634{
80318cb7
A
1635 vchar_t *portany_id = NULL;
1636 vchar_t *portany_id_p = NULL;
1637
47612122
A
1638 if (iph2->id && older_ph2->id &&
1639 iph2->id->l == older_ph2->id->l &&
1640 memcmp(iph2->id->v, older_ph2->id->v, iph2->id->l) == 0 &&
1641 iph2->id_p && older_ph2->id_p &&
1642 iph2->id_p->l == older_ph2->id_p->l &&
1643 memcmp(iph2->id_p->v, older_ph2->id_p->v, iph2->id_p->l) == 0) {
1644 return 0;
1645 }
1646 if (iph2->ext_nat_id && older_ph2->ext_nat_id &&
1647 iph2->ext_nat_id->l == older_ph2->ext_nat_id->l &&
1648 memcmp(iph2->ext_nat_id->v, older_ph2->ext_nat_id->v, iph2->ext_nat_id->l) == 0 &&
1649 iph2->ext_nat_id_p && older_ph2->ext_nat_id_p &&
1650 iph2->ext_nat_id_p->l == older_ph2->ext_nat_id_p->l &&
1651 memcmp(iph2->ext_nat_id_p->v, older_ph2->ext_nat_id_p->v, iph2->ext_nat_id_p->l) == 0) {
1652 return 0;
1653 }
1654 if (iph2->id && older_ph2->ext_nat_id &&
1655 iph2->id->l == older_ph2->ext_nat_id->l &&
1656 memcmp(iph2->id->v, older_ph2->ext_nat_id->v, iph2->id->l) == 0 &&
1657 iph2->id_p && older_ph2->ext_nat_id_p &&
1658 iph2->id_p->l == older_ph2->ext_nat_id_p->l &&
1659 memcmp(iph2->id_p->v, older_ph2->ext_nat_id_p->v, iph2->id_p->l) == 0) {
1660 return 0;
1661 }
80318cb7
A
1662 if (iph2->id && older_ph2->ext_nat_id &&
1663 iph2->id->l == older_ph2->ext_nat_id->l &&
1664 memcmp(iph2->id->v, older_ph2->ext_nat_id->v, iph2->id->l) == 0 &&
1665 iph2->id_p && older_ph2->id_p &&
1666 iph2->id_p->l == older_ph2->id_p->l &&
1667 memcmp(iph2->id_p->v, older_ph2->id_p->v, iph2->id_p->l) == 0) {
1668 return 0;
1669 }
1670 if (iph2->id && older_ph2->id &&
1671 iph2->id->l == older_ph2->id->l &&
1672 memcmp(iph2->id->v, older_ph2->id->v, iph2->id->l) == 0 &&
1673 iph2->id_p && older_ph2->ext_nat_id_p &&
1674 iph2->id_p->l == older_ph2->ext_nat_id_p->l &&
1675 memcmp(iph2->id_p->v, older_ph2->ext_nat_id_p->v, iph2->id_p->l) == 0) {
1676 return 0;
1677 }
1678
1679 /* check if the external id has a wildcard port and compare ids accordingly */
1680 if ((older_ph2->ext_nat_id && ike_session_is_id_portany(older_ph2->ext_nat_id)) ||
1681 (older_ph2->ext_nat_id_p && ike_session_is_id_portany(older_ph2->ext_nat_id_p))) {
1682 // try ignoring ports in iph2->id and iph2->id
e8d9021d 1683 if (iph2->id && (portany_id = vdup(iph2->id))) {
80318cb7
A
1684 ike_session_set_id_portany(portany_id);
1685 }
1686 if (iph2->id_p && (portany_id_p = vdup(iph2->id_p))) {
1687 ike_session_set_id_portany(portany_id_p);
1688 }
1689 if (portany_id && older_ph2->ext_nat_id &&
1690 portany_id->l == older_ph2->ext_nat_id->l &&
1691 memcmp(portany_id->v, older_ph2->ext_nat_id->v, portany_id->l) == 0 &&
1692 portany_id_p && older_ph2->ext_nat_id_p &&
1693 portany_id_p->l == older_ph2->ext_nat_id_p->l &&
1694 memcmp(portany_id_p->v, older_ph2->ext_nat_id_p->v, portany_id_p->l) == 0) {
1695 if (portany_id) {
1696 vfree(portany_id);
1697 }
1698 if (portany_id_p) {
1699 vfree(portany_id_p);
1700 }
1701 return 0;
1702 }
e8d9021d 1703 if (portany_id && iph2->id && older_ph2->ext_nat_id &&
80318cb7
A
1704 iph2->id->l == older_ph2->ext_nat_id->l &&
1705 memcmp(portany_id->v, older_ph2->ext_nat_id->v, portany_id->l) == 0 &&
1706 iph2->id_p && older_ph2->id_p &&
1707 iph2->id_p->l == older_ph2->id_p->l &&
1708 memcmp(iph2->id_p->v, older_ph2->id_p->v, iph2->id_p->l) == 0) {
1709 if (portany_id) {
1710 vfree(portany_id);
1711 }
1712 if (portany_id_p) {
1713 vfree(portany_id_p);
1714 }
1715 return 0;
1716 }
e8d9021d 1717 if (portany_id_p && iph2->id && older_ph2->id &&
80318cb7
A
1718 iph2->id->l == older_ph2->id->l &&
1719 memcmp(iph2->id->v, older_ph2->id->v, iph2->id->l) == 0 &&
1720 iph2->id_p && older_ph2->ext_nat_id_p &&
1721 iph2->id_p->l == older_ph2->ext_nat_id_p->l &&
1722 memcmp(portany_id_p->v, older_ph2->ext_nat_id_p->v, portany_id_p->l) == 0) {
1723 if (portany_id) {
1724 vfree(portany_id);
1725 }
1726 if (portany_id_p) {
1727 vfree(portany_id_p);
1728 }
1729 return 0;
1730 }
1731 if (portany_id) {
1732 vfree(portany_id);
1733 }
1734 if (portany_id_p) {
1735 vfree(portany_id_p);
1736 }
1737 }
47612122
A
1738 return -1;
1739}
1740
1741int
65c25746 1742ike_session_get_sainfo_r (phase2_handle_t *iph2)
47612122 1743{
65c25746
A
1744 if (iph2->parent_session &&
1745 iph2->parent_session->is_client &&
1746 iph2->id && iph2->id_p) {
1747 phase2_handle_t *p;
1748 int ipany_ids = ike_session_cmp_ph2_ids_ipany(iph2->id, iph2->id_p);
1749 plog(ASL_LEVEL_DEBUG, "ipany_ids %d in %s.\n", ipany_ids, __FUNCTION__);
1750
1751 LIST_FOREACH(p, &iph2->parent_session->ph2tree, ph2ofsession_chain) {
1752 if (iph2 != p && !p->is_dying && FSM_STATE_IS_ESTABLISHED_OR_EXPIRED(p->status) && p->sainfo) {
1753 plog(ASL_LEVEL_DEBUG, "candidate ph2 found in %s.\n", __FUNCTION__);
1754 if (ipany_ids ||
1755 ike_session_cmp_ph2_ids(iph2, p) == 0) {
1756 plog(ASL_LEVEL_DEBUG, "candidate ph2 matched in %s.\n", __FUNCTION__);
1757 iph2->sainfo = p->sainfo;
1758 if (iph2->sainfo)
1759 retain_sainfo(iph2->sainfo);
1760 if (!iph2->spid) {
1761 iph2->spid = p->spid;
1762 } else {
1763 plog(ASL_LEVEL_DEBUG, "%s: pre-assigned spid %d.\n", __FUNCTION__, iph2->spid);
1764 }
1765 if (p->ext_nat_id) {
1766 if (iph2->ext_nat_id) {
1767 vfree(iph2->ext_nat_id);
1768 }
1769 iph2->ext_nat_id = vdup(p->ext_nat_id);
1770 }
1771 if (p->ext_nat_id_p) {
1772 if (iph2->ext_nat_id_p) {
1773 vfree(iph2->ext_nat_id_p);
1774 }
1775 iph2->ext_nat_id_p = vdup(p->ext_nat_id_p);
1776 }
1777 return 0;
1778 }
1779 }
1780 }
1781 }
1782 return -1;
fce29cd9
A
1783}
1784
80318cb7 1785int
65c25746 1786ike_session_get_proposal_r (phase2_handle_t *iph2)
80318cb7
A
1787{
1788 if (iph2->parent_session &&
1789 iph2->parent_session->is_client &&
1790 iph2->id && iph2->id_p) {
65c25746 1791 phase2_handle_t *p;
80318cb7 1792 int ipany_ids = ike_session_cmp_ph2_ids_ipany(iph2->id, iph2->id_p);
65c25746 1793 plog(ASL_LEVEL_DEBUG, "ipany_ids %d in %s.\n", ipany_ids, __FUNCTION__);
80318cb7 1794
65c25746
A
1795 LIST_FOREACH(p, &iph2->parent_session->ph2tree, ph2ofsession_chain) {
1796 if (iph2 != p && !p->is_dying && FSM_STATE_IS_ESTABLISHED_OR_EXPIRED(p->status) &&
80318cb7 1797 p->approval) {
65c25746 1798 plog(ASL_LEVEL_DEBUG, "candidate ph2 found in %s.\n", __FUNCTION__);
80318cb7
A
1799 if (ipany_ids ||
1800 ike_session_cmp_ph2_ids(iph2, p) == 0) {
65c25746 1801 plog(ASL_LEVEL_DEBUG, "candidate ph2 matched in %s.\n", __FUNCTION__);
80318cb7 1802 iph2->proposal = dupsaprop(p->approval, 1);
b8c37798
A
1803 if (!iph2->spid) {
1804 iph2->spid = p->spid;
1805 } else {
65c25746 1806 plog(ASL_LEVEL_DEBUG, "%s: pre-assigned spid %d.\n", __FUNCTION__, iph2->spid);
b8c37798 1807 }
80318cb7
A
1808 return 0;
1809 }
1810 }
1811 }
1812 }
1813 return -1;
1814}
1815
1816void
65c25746 1817ike_session_update_natt_version (phase1_handle_t *iph1)
80318cb7
A
1818{
1819 if (iph1->parent_session) {
1820 if (iph1->natt_options) {
1821 iph1->parent_session->natt_version = iph1->natt_options->version;
1822 } else {
1823 iph1->parent_session->natt_version = 0;
1824 }
1825 }
1826}
1827
1828int
65c25746 1829ike_session_get_natt_version (phase1_handle_t *iph1)
80318cb7
A
1830{
1831 if (iph1->parent_session) {
1832 return(iph1->parent_session->natt_version);
1833 }
1834 return 0;
1835}
1836
fce29cd9 1837int
e8d9021d 1838ike_session_drop_rekey (ike_session_t *session, ike_session_rekey_type_t rekey_type)
fce29cd9
A
1839{
1840 if (session) {
fce29cd9
A
1841 if (session->is_btmm_ipsec &&
1842 session->last_time_data_sc_detected &&
1843 session->traffic_monitor.interv_mon &&
1844 session->traffic_monitor.interv_idle) {
e8d9021d 1845 // for btmm: drop ph1/ph2 rekey if session is idle
fce29cd9
A
1846 time_t now = time(NULL);
1847
1848 if ((now - session->last_time_data_sc_detected) > (session->traffic_monitor.interv_mon << 1)) {
7ebaebe2 1849 plog(ASL_LEVEL_NOTICE, "btmm session is idle: drop ph%drekey.\n",
e8d9021d
A
1850 rekey_type);
1851 return 1;
1852 }
1853 } else if (!session->is_btmm_ipsec) {
1854 if (rekey_type == IKE_SESSION_REKEY_TYPE_PH1 &&
64c59980 1855 !ike_session_has_negoing_ph2(session) && !ike_session_has_established_ph2(session)) {
e8d9021d 1856 // for vpn: only drop ph1 if there are no more ph2s.
7ebaebe2 1857 plog(ASL_LEVEL_NOTICE, "vpn session is idle: drop ph1 rekey.\n");
fce29cd9
A
1858 return 1;
1859 }
1860 }
1861 }
1862 return 0;
1863}
1864
e8d9021d
A
1865/*
1866 * this is called after racooon receives a 'kIOMessageSystemHasPoweredOn'
1867 * a lot is done to make sure that we don't sweep a session that's already been asserted.
1868 * however, it'll be too bad if the assertion comes after the session has already been swept.
1869 */
1870void
1871ike_session_sweep_sleepwake (void)
1872{
65c25746
A
1873 ike_session_t *p = NULL;
1874 ike_session_t *next_session = NULL;
e8d9021d
A
1875
1876 // flag session as dying if all ph1/ph2 are dead/dying
65c25746 1877 LIST_FOREACH_SAFE(p, &ike_session_tree, chain, next_session) {
e8d9021d 1878 if (p->is_dying) {
7ebaebe2 1879 plog(ASL_LEVEL_NOTICE, "skipping sweep of dying session.\n");
e8d9021d
A
1880 continue;
1881 }
1882 SCHED_KILL(p->sc_xauth);
1883 if (p->is_asserted) {
1884 // for asserted session, traffic monitors will be restared after phase2 becomes established.
1885 SCHED_KILL(p->traffic_monitor.sc_mon);
1886 SCHED_KILL(p->traffic_monitor.sc_idle);
7ebaebe2 1887 plog(ASL_LEVEL_NOTICE, "skipping sweep of asserted session.\n");
e8d9021d
A
1888 continue;
1889 }
869d26af 1890
65c25746
A
1891 // cleanup any stopped sessions as they will go down
1892 if (p->stopped_by_vpn_controller || p->stop_timestamp.tv_sec || p->stop_timestamp.tv_usec) {
7ebaebe2 1893 plog(ASL_LEVEL_NOTICE, "sweeping stopped session.\n");
869d26af
A
1894 ike_session_cleanup(p, ike_session_stopped_by_sleepwake);
1895 continue;
65c25746 1896 }
869d26af 1897
e8d9021d 1898 if (!ike_session_has_established_ph1(p) && !ike_session_has_established_ph2(p)) {
7ebaebe2 1899 plog(ASL_LEVEL_NOTICE, "session died while sleeping.\n");
869d26af 1900 ike_session_cleanup(p, ike_session_stopped_by_sleepwake);
65c25746 1901 continue;
e8d9021d
A
1902 }
1903 if (p->traffic_monitor.sc_mon) {
65c25746
A
1904 time_t xtime;
1905 if (sched_get_time(p->traffic_monitor.sc_mon, &xtime)) {
1906 if (xtime <= swept_at) {
1907 SCHED_KILL(p->traffic_monitor.sc_mon);
1908 if (!p->is_dying && p->traffic_monitor.interv_mon) {
1909 p->traffic_monitor.sc_mon = sched_new(p->traffic_monitor.interv_mon,
e8d9021d
A
1910 ike_session_traffic_cop,
1911 p);
65c25746
A
1912 }
1913 }
e8d9021d
A
1914 }
1915 }
1916 if (p->traffic_monitor.sc_idle) {
65c25746
A
1917 time_t xtime;
1918 if (sched_get_time(p->traffic_monitor.sc_idle, &xtime)) {
1919 if (xtime <= swept_at) {
1920 SCHED_KILL(p->traffic_monitor.sc_idle);
1921 if (!p->is_dying && p->traffic_monitor.interv_idle) {
1922 p->traffic_monitor.sc_idle = sched_new(p->traffic_monitor.interv_idle,
e8d9021d
A
1923 ike_session_cleanup_idle,
1924 p);
65c25746
A
1925 }
1926 }
e8d9021d
A
1927 }
1928 }
1929 }
1930}
1931
1932/*
1933 * this is called after racooon receives an assert command from the controller/pppd.
1934 * this is intended to make racoon prepare to rekey both SAs because a network event occurred.
1935 * in the event of a sleepwake, the assert could happen before or after 'ike_session_sweep_sleepwake'.
1936 */
1937int
1938ike_session_assert_session (ike_session_t *session)
1939{
65c25746
A
1940 phase2_handle_t *iph2 = NULL;
1941 phase2_handle_t *iph2_next = NULL;
1942 phase1_handle_t *iph1 = NULL;
1943 phase1_handle_t *iph1_next = NULL;
e8d9021d
A
1944
1945 if (!session || session->is_dying) {
7ebaebe2 1946 plog(ASL_LEVEL_ERR, "invalid parameters in %s.\n", __FUNCTION__);
e8d9021d
A
1947 return -1;
1948 }
1949
1950 // the goal is to prepare the session for fresh rekeys by silently deleting the currently active phase2s
65c25746
A
1951 LIST_FOREACH_SAFE(iph2, &session->ph2tree, ph2ofsession_chain, iph2_next) {
1952 if (!iph2->is_dying && !FSM_STATE_IS_EXPIRED(iph2->status)) {
e8d9021d
A
1953 SCHED_KILL(iph2->sce);
1954 iph2->is_dying = 1;
1955
1956 // delete SAs (in the kernel)
65c25746 1957 if (FSM_STATE_IS_ESTABLISHED(iph2->status) && iph2->approval) {
e8d9021d
A
1958 struct saproto *pr;
1959
1960 for (pr = iph2->approval->head; pr != NULL; pr = pr->next) {
1961 if (pr->ok) {
1962 //log deletion
7ebaebe2 1963 plog(ASL_LEVEL_NOTICE,
65c25746 1964 "Assert: Phase 2 %s deleted\n",
e8d9021d
A
1965 sadbsecas2str(iph2->src, iph2->dst, iph2->satype, iph2->spid, ipsecdoi2pfkey_mode(pr->encmode)));
1966
1967 pfkey_send_delete(lcconf->sock_pfkey,
1968 ipsecdoi2pfkey_proto(pr->proto_id),
1969 ipsecdoi2pfkey_mode(pr->encmode),
1970 iph2->src, iph2->dst, pr->spi_p);
1971 }
1972 }
1973 }
1974
65c25746 1975 fsm_set_state(&iph2->status, IKEV1_STATE_PHASE2_EXPIRED); // we want to delete SAs without telling the PEER
e8d9021d
A
1976 iph2->sce = sched_new(3, ike_session_cleanup_ph2_stub, iph2);
1977 }
1978 }
1979
1980 // the goal is to prepare the session for fresh rekeys by silently deleting the currently active phase1s
65c25746
A
1981 LIST_FOREACH_SAFE(iph1, &session->ph1tree, ph1ofsession_chain, iph1_next) {
1982 if (!iph1->is_dying && !FSM_STATE_IS_EXPIRED(iph1->status)) {
e8d9021d
A
1983 SCHED_KILL(iph1->sce);
1984 SCHED_KILL(iph1->sce_rekey);
1985 iph1->is_dying = 1;
1986
1987 //log deletion
7ebaebe2 1988 plog(ASL_LEVEL_NOTICE,
65c25746 1989 "Assert: Phase 1 %s deleted\n",
e8d9021d
A
1990 isakmp_pindex(&iph1->index, 0));
1991
65c25746 1992 ike_session_unbind_all_ph2_from_ph1(iph1);
e8d9021d 1993
65c25746 1994 fsm_set_state(&iph1->status, IKEV1_STATE_PHASE1_EXPIRED); // we want to delete SAs without telling the PEER
e8d9021d
A
1995 /* responder sets up timer to delete old inbound SAs... say 7 secs later and flags them as rekeyed */
1996 iph1->sce = sched_new(5, ike_session_cleanup_ph1_stub, iph1);
1997 }
1998 }
1999 session->is_asserted = 1;
2000
2001 return 0;
2002}
2003
2004int
85f41bec
A
2005ike_session_assert (struct sockaddr_storage *local,
2006 struct sockaddr_storage *remote)
e8d9021d
A
2007{
2008 ike_session_t *sess;
2009
2010 if (!local || !remote) {
7ebaebe2 2011 plog(ASL_LEVEL_ERR, "invalid parameters in %s.\n", __FUNCTION__);
e8d9021d
A
2012 return -1;
2013 }
2014
1760d65d 2015 if ((sess = ike_session_get_session(local, remote, FALSE, NULL))) {
e8d9021d
A
2016 return(ike_session_assert_session(sess));
2017 }
2018 return -1;
2019}
2020
fce29cd9 2021void
65c25746 2022ike_session_ph2_retransmits (phase2_handle_t *iph2)
fce29cd9
A
2023{
2024 int num_retransmits;
2025
2026 if (!iph2->is_dying &&
2027 iph2->is_rekey &&
2028 iph2->ph1 &&
65c25746 2029 iph2->ph1->sce_rekey && !sched_is_dead(iph2->ph1->sce_rekey) &&
b8c37798 2030 iph2->side == INITIATOR &&
fce29cd9
A
2031 iph2->parent_session &&
2032 !iph2->parent_session->is_cisco_ipsec && /* not for Cisco */
2033 iph2->parent_session->is_client) {
2034 num_retransmits = iph2->ph1->rmconf->retry_counter - iph2->retry_counter;
2035 if (num_retransmits == 3) {
2036 /*
2037 * phase2 negotiation is stalling on retransmits, inspite of a valid ph1.
2038 * one of the following is possible:
2039 * - (0) severe packet loss.
2040 * - (1) the peer is dead.
2041 * - (2) the peer is out of sync hence dropping this phase2 rekey (and perhaps responding with insecure
2042 * invalid-cookie notifications... but those are untrusted and so we can't rekey phase1 off that)
2043 * (2.1) the peer rebooted (or process restarted) and is now alive.
2044 * (2.2) the peer has deleted phase1 without notifying us (or the notification got dropped somehow).
2045 * (2.3) the peer has a policy/bug stopping this phase2 rekey
2046 *
2047 * in all these cases, one sure way to know is to trigger a phase1 rekey early.
2048 */
7ebaebe2 2049 plog(ASL_LEVEL_NOTICE, "Many Phase 2 retransmits: try Phase 1 rekey and this Phase 2 to quit earlier.\n");
fce29cd9
A
2050 isakmp_ph1rekeyexpire(iph2->ph1, TRUE);
2051 iph2->retry_counter = 0;
2052 }
2053 }
2054}
e8d9021d
A
2055
2056void
65c25746 2057ike_session_ph1_retransmits (phase1_handle_t *iph1)
e8d9021d
A
2058{
2059 int num_retransmits;
2060
2061 if (!iph1->is_dying &&
2062 iph1->is_rekey &&
2063 !iph1->sce_rekey &&
65c25746 2064 FSM_STATE_IS_NEGOTIATING(iph1->status) &&
e8d9021d
A
2065 iph1->side == INITIATOR &&
2066 iph1->parent_session &&
2067 iph1->parent_session->is_client &&
2068 !ike_session_has_other_negoing_ph1(iph1->parent_session, iph1)) {
2069 num_retransmits = iph1->rmconf->retry_counter - iph1->retry_counter;
2070 if (num_retransmits == 3) {
7ebaebe2 2071 plog(ASL_LEVEL_NOTICE, "Many Phase 1 retransmits: try quit earlier.\n");
e8d9021d
A
2072 iph1->retry_counter = 0;
2073 }
2074 }
2075}
65c25746
A
2076
2077static void
2078ike_session_bindph12(phase1_handle_t *iph1, phase2_handle_t *iph2)
2079{
2080 if (iph2->ph1) {
2081 plog(ASL_LEVEL_ERR, "Phase 2 already bound %s.\n", __FUNCTION__);
2082 }
2083 iph2->ph1 = iph1;
2084 LIST_INSERT_HEAD(&iph1->bound_ph2tree, iph2, ph1bind_chain);
2085}
2086
2087void
2088ike_session_unbindph12(phase2_handle_t *iph2)
2089{
2090 if (iph2->ph1 != NULL) {
2091 iph2->ph1 = NULL;
2092 LIST_REMOVE(iph2, ph1bind_chain);
2093 }
2094}
2095
2096static void
2097ike_session_rebindph12(phase1_handle_t *new_ph1, phase2_handle_t *iph2)
2098{
2099 if (!new_ph1) {
2100 return;
2101 }
2102
2103 // reconcile the ph1-to-ph2 binding
2104 ike_session_unbindph12(iph2);
2105 ike_session_bindph12(new_ph1, iph2);
2106 // recalculate ivm since ph1 binding has changed
2107 if (iph2->ivm != NULL) {
2108 oakley_delivm(iph2->ivm);
2109 if (FSM_STATE_IS_ESTABLISHED(new_ph1->status)) {
2110 iph2->ivm = oakley_newiv2(new_ph1, iph2->msgid);
7ebaebe2 2111 plog(ASL_LEVEL_NOTICE, "Phase 1-2 binding changed... recalculated ivm.\n");
65c25746
A
2112 } else {
2113 iph2->ivm = NULL;
2114 }
2115 }
2116}
2117
2118static void
2119ike_session_unbind_all_ph2_from_ph1 (phase1_handle_t *iph1)
2120{
2121 phase2_handle_t *p = NULL;
2122 phase2_handle_t *next = NULL;
2123
2124 LIST_FOREACH_SAFE(p, &iph1->bound_ph2tree, ph1bind_chain, next) {
2125 ike_session_unbindph12(p);
2126 }
2127}
2128
2129static void
2130ike_session_rebind_all_ph12_to_new_ph1 (phase1_handle_t *old_iph1,
2131 phase1_handle_t *new_iph1)
2132{
2133 phase2_handle_t *p = NULL;
2134 phase2_handle_t *next = NULL;
2135
2136 if (old_iph1 == new_iph1 || !old_iph1 || !new_iph1) {
7ebaebe2 2137 plog(ASL_LEVEL_ERR, "invalid parameters in %s.\n", __FUNCTION__);
65c25746
A
2138 return;
2139 }
2140
2141 if (old_iph1->parent_session != new_iph1->parent_session) {
7ebaebe2 2142 plog(ASL_LEVEL_ERR, "Invalid parent sessions in %s.\n", __FUNCTION__);
65c25746
A
2143 return;
2144 }
2145
2146 LIST_FOREACH_SAFE(p, &old_iph1->bound_ph2tree, ph1bind_chain, next) {
2147 if (p->parent_session != new_iph1->parent_session) {
2148 plog(ASL_LEVEL_ERR, "Mismatched parent session in ph1bind replacement.\n");
2149 }
2150 if (p->ph1 == new_iph1) {
2151 plog(ASL_LEVEL_ERR, "Same Phase 2 in ph1bind replacement in %s.\n",__FUNCTION__);
2152 }
2153 ike_session_rebindph12(new_iph1, p);
2154 }
2155}
2156