]> git.saurik.com Git - apple/ipsec.git/blob - ipsec-tools/racoon/ike_session.c
4f688bfb8de8975f1acd96a6f912cfe2c5c59776
[apple/ipsec.git] / ipsec-tools / racoon / ike_session.c
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"
34
35 #include "isakmp_var.h"
36 #include "isakmp.h"
37 #include "ike_session.h"
38 #include "handler.h"
39 #include "gcmalloc.h"
40 #include "nattraversal.h"
41 #include "schedule.h"
42 #include "pfkey.h"
43 #include "ipsec_doi.h"
44 #include "ipsecSessionTracer.h"
45 #include "ipsecMessageTracer.h"
46 #include "isakmp_inf.h"
47 #include "localconf.h"
48 #include "remoteconf.h"
49 #include "vpn_control.h"
50
51 const char *ike_session_stopped_by_vpn_disconnect = "Stopped by VPN disconnect";
52 const char *ike_session_stopped_by_flush = "Stopped by Flush";
53 const char *ike_session_stopped_by_idle = "Stopped by Idle";
54 const char *ike_session_stopped_by_xauth_timeout = "Stopped by XAUTH timeout";
55
56 static LIST_HEAD(_ike_session_tree_, ike_session) ike_session_tree;
57
58 static ike_session_t *
59 new_ike_session (ike_session_id_t *id)
60 {
61 ike_session_t *session;
62
63 if (!id) {
64 plog(LLV_DEBUG2, LOCATION, NULL, "invalid parameters in %s.\n", __FUNCTION__);
65 return NULL;
66 }
67
68 plog(LLV_DEBUG, LOCATION, NULL, "new parent session.\n");
69 session = racoon_calloc(1, sizeof(*session));
70 if (session) {
71 bzero(session, sizeof(*session));
72 memcpy(&session->session_id, id, sizeof(*id));
73 LIST_INIT(&session->ikev1_state.ph1tree);
74 LIST_INIT(&session->ikev1_state.ph2tree);
75 LIST_INSERT_HEAD(&ike_session_tree, session, chain);
76 session->version = IKE_VERSION_1; // hard-coded for now
77 IPSECSESSIONTRACERSTART(session);
78 }
79 return session;
80 }
81
82 static void
83 free_ike_session (ike_session_t *session)
84 {
85 int is_failure = TRUE;
86 if (session) {
87 SCHED_KILL(session->traffic_monitor.sc_mon);
88 SCHED_KILL(session->traffic_monitor.sc_idle);
89 SCHED_KILL(session->sc_xauth);
90 if (session->start_timestamp.tv_sec || session->start_timestamp.tv_usec) {
91 if (!(session->stop_timestamp.tv_sec || session->start_timestamp.tv_usec)) {
92 gettimeofday(&session->stop_timestamp, NULL);
93 }
94 if (session->term_reason != ike_session_stopped_by_vpn_disconnect ||
95 session->term_reason != ike_session_stopped_by_flush ||
96 session->term_reason != ike_session_stopped_by_idle) {
97 is_failure = FALSE;
98 }
99 IPSECSESSIONTRACERSTOP(session,
100 is_failure,
101 session->term_reason);
102 }
103 // do MessageTracer cleanup here
104 plog(LLV_DEBUG, LOCATION, NULL,
105 "Freeing IKE-Session to %s.\n",
106 saddr2str((struct sockaddr *)&session->session_id.remote));
107 LIST_REMOVE(session, chain);
108 racoon_free(session);
109 }
110 }
111
112 struct ph1handle *
113 ike_session_get_established_or_negoing_ph1 (ike_session_t *session)
114 {
115 struct ph1handle *p, *iph1 = NULL;
116
117 if (!session) {
118 plog(LLV_DEBUG2, LOCATION, NULL, "invalid parameters in %s.\n", __FUNCTION__);
119 return NULL;
120 }
121
122 // look for the most mature ph1 under the session
123 for (p = LIST_FIRST(&session->ikev1_state.ph1tree); p; p = LIST_NEXT(p, ph1ofsession_chain)) {
124 if (!p->is_dying && p->status >= PHASE1ST_START && p->status <= PHASE1ST_ESTABLISHED) {
125 if (!iph1 || p->status > iph1->status) {
126 iph1 = p;
127 } else if (iph1 && p->status == iph1->status) {
128 // TODO: pick better one based on farthest rekey/expiry remaining
129 }
130 }
131 }
132
133 return iph1;
134 }
135
136 struct ph1handle *
137 ike_session_get_established_ph1 (ike_session_t *session)
138 {
139 struct ph1handle *p;
140
141 if (!session) {
142 plog(LLV_DEBUG2, LOCATION, NULL, "invalid parameters in %s.\n", __FUNCTION__);
143 return NULL;
144 }
145
146 for (p = LIST_FIRST(&session->ikev1_state.ph1tree); p; p = LIST_NEXT(p, ph1ofsession_chain)) {
147 if (!p->is_dying && p->status == PHASE1ST_ESTABLISHED) {
148 return p;
149 }
150 }
151
152 return NULL;
153 }
154
155 void
156 ike_session_init (void)
157 {
158 LIST_INIT(&ike_session_tree);
159 }
160
161 u_int
162 ike_session_get_rekey_lifetime (int local_spi_is_higher, u_int expiry_lifetime)
163 {
164 u_int rekey_lifetime = expiry_lifetime / 10;
165
166 if (rekey_lifetime) {
167 if (local_spi_is_higher) {
168 return (rekey_lifetime * 9);
169 } else {
170 return (rekey_lifetime * 8);
171 }
172 } else {
173 if (local_spi_is_higher) {
174 rekey_lifetime = expiry_lifetime - 1;
175 } else {
176 rekey_lifetime = expiry_lifetime - 2;
177 }
178 }
179 if (rekey_lifetime < expiry_lifetime) {
180 return (rekey_lifetime);
181 }
182 return(0);
183 }
184
185 // TODO: optimize this mess later
186 ike_session_t *
187 ike_session_get_session (struct sockaddr *local,
188 struct sockaddr *remote,
189 int alloc_if_absent)
190 {
191 ike_session_t *p;
192 ike_session_id_t id;
193 ike_session_id_t id_default;
194 ike_session_id_t id_floated_default;
195 ike_session_id_t id_wop;
196 ike_session_t *best_match = NULL;
197 u_int16_t remote_port;
198 int is_isakmp_remote_port;
199
200 if (!local || !remote) {
201 plog(LLV_DEBUG2, LOCATION, NULL, "invalid parameters in %s.\n", __FUNCTION__);
202 return NULL;
203 }
204
205 remote_port = extract_port(remote);
206 if (remote_port && remote_port != PORT_ISAKMP && remote_port != PORT_ISAKMP_NATT) {
207 is_isakmp_remote_port = 0;
208 } else {
209 is_isakmp_remote_port = 1;
210 }
211
212 /* 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 */
213 bzero(&id, sizeof(id));
214 bzero(&id_default, sizeof(id_default));
215 bzero(&id_floated_default, sizeof(id_floated_default));
216 bzero(&id_wop, sizeof(id_wop));
217 if (local->sa_family == AF_INET) {
218 memcpy(&id.local, local, sizeof(struct sockaddr_in));
219 memcpy(&id_default.local, local, sizeof(struct sockaddr_in));
220 memcpy(&id_floated_default.local, local, sizeof(struct sockaddr_in));
221 memcpy(&id_wop.local, local, sizeof(struct sockaddr_in));
222 } else if (local->sa_family == AF_INET6) {
223 memcpy(&id.local, local, sizeof(struct sockaddr_in6));
224 memcpy(&id_default.local, local, sizeof(struct sockaddr_in6));
225 memcpy(&id_floated_default.local, local, sizeof(struct sockaddr_in6));
226 memcpy(&id_wop.local, local, sizeof(struct sockaddr_in6));
227 }
228 set_port((struct sockaddr *)&id_default.local, PORT_ISAKMP);
229 set_port((struct sockaddr *)&id_floated_default.local, PORT_ISAKMP_NATT);
230 set_port((struct sockaddr *)&id_wop.local, 0);
231 if (remote->sa_family == AF_INET) {
232 memcpy(&id.remote, remote, sizeof(struct sockaddr_in));
233 memcpy(&id_default.remote, remote, sizeof(struct sockaddr_in));
234 memcpy(&id_floated_default.remote, remote, sizeof(struct sockaddr_in));
235 memcpy(&id_wop.remote, remote, sizeof(struct sockaddr_in));
236 } else if (remote->sa_family == AF_INET6) {
237 memcpy(&id.remote, remote, sizeof(struct sockaddr_in6));
238 memcpy(&id_default.remote, remote, sizeof(struct sockaddr_in6));
239 memcpy(&id_floated_default.remote, remote, sizeof(struct sockaddr_in6));
240 memcpy(&id_wop.remote, remote, sizeof(struct sockaddr_in6));
241 }
242 set_port((struct sockaddr *)&id_default.remote, PORT_ISAKMP);
243 set_port((struct sockaddr *)&id_floated_default.remote, PORT_ISAKMP_NATT);
244 set_port((struct sockaddr *)&id_wop.remote, 0);
245
246 plog(LLV_DEBUG, LOCATION, local,
247 "start search for IKE-Session. target %s.\n",
248 saddr2str(remote));
249
250 for (p = LIST_FIRST(&ike_session_tree); p; p = LIST_NEXT(p, chain)) {
251 plog(LLV_DEBUG, LOCATION, local,
252 "still search for IKE-Session. this %s.\n",
253 saddr2str((struct sockaddr *)&p->session_id.remote));
254
255 if (memcmp(&p->session_id, &id, sizeof(id)) == 0) {
256 plog(LLV_DEBUG, LOCATION, local,
257 "Pre-existing IKE-Session to %s. case 1.\n",
258 saddr2str(remote));
259 return p;
260 } else if (is_isakmp_remote_port && memcmp(&p->session_id, &id_default, sizeof(id_default)) == 0) {
261 plog(LLV_DEBUG, LOCATION, local,
262 "Pre-existing IKE-Session to %s. case 2.\n",
263 saddr2str(remote));
264 return p;
265 } else if (is_isakmp_remote_port && p->ports_floated && memcmp(&p->session_id, &id_floated_default, sizeof(id_floated_default)) == 0) {
266 plog(LLV_DEBUG, LOCATION, local,
267 "Pre-existing IKE-Session to %s. case 3.\n",
268 saddr2str(remote));
269 return p;
270 } else if (is_isakmp_remote_port && memcmp(&p->session_id, &id_wop, sizeof(id_wop)) == 0) {
271 best_match = p;
272 }
273 }
274 if (best_match) {
275 plog(LLV_DEBUG, LOCATION, local,
276 "Best-match IKE-Session to %s.\n",
277 saddr2str((struct sockaddr *)&best_match->session_id.remote));
278 return best_match;
279 }
280 if (alloc_if_absent) {
281 plog(LLV_DEBUG, LOCATION, local,
282 "New IKE-Session to %s.\n",
283 saddr2str((struct sockaddr *)&id.remote));
284 return new_ike_session(&id);
285 } else {
286 return NULL;
287 }
288 }
289
290 void
291 ike_session_init_traffic_cop_params (struct ph1handle *iph1)
292 {
293 if (!iph1 ||
294 !iph1->rmconf ||
295 (!iph1->rmconf->idle_timeout && !iph1->rmconf->dpd_interval)) {
296 return;
297 }
298
299 if (!iph1->parent_session->traffic_monitor.interv_idle) {
300 iph1->parent_session->traffic_monitor.interv_idle = iph1->rmconf->idle_timeout;
301 }
302 if (!iph1->parent_session->traffic_monitor.dir_idle) {
303 iph1->parent_session->traffic_monitor.dir_idle = iph1->rmconf->idle_timeout_dir;
304 }
305
306 if (!iph1->parent_session->traffic_monitor.interv_mon) {
307 int min_period, max_period, sample_period = 0;
308
309 /* calculate the sampling interval... half the smaller interval */
310 if (iph1->rmconf->dpd_interval &&
311 (iph1->rmconf->dpd_algo == DPD_ALGO_INBOUND_DETECT ||
312 iph1->rmconf->dpd_algo == DPD_ALGO_BLACKHOLE_DETECT)) {
313 // when certain types of dpd are enabled
314 min_period = MIN(iph1->rmconf->dpd_interval, iph1->rmconf->idle_timeout);
315 max_period = MAX(iph1->rmconf->dpd_interval, iph1->rmconf->idle_timeout);
316 } else if (iph1->rmconf->idle_timeout) {
317 min_period = max_period = MIN(0, iph1->rmconf->idle_timeout);
318 } else {
319 // DPD_ALGO_DEFAULT is configured and there's no idle timeout... we don't need to monitor traffic
320 return;
321 }
322 if (min_period) {
323 sample_period = min_period >> 1;
324 if (!sample_period)
325 sample_period = 1; // bad
326 } else {
327 sample_period = max_period >> 1;
328 if (!sample_period)
329 sample_period = 1; // bad
330 }
331 iph1->parent_session->traffic_monitor.interv_mon = sample_period;
332 }
333 }
334
335 int
336 ike_session_link_ph1_to_session (struct ph1handle *iph1)
337 {
338 ike_session_t *session;
339
340 if (!iph1) {
341 plog(LLV_DEBUG2, LOCATION, NULL, "invalid parameters in %s.\n", __FUNCTION__);
342 return -1;
343 }
344
345 session = ike_session_get_session(iph1->local, iph1->remote, TRUE);
346 if (!session) {
347 plog(LLV_DEBUG2, LOCATION, NULL, "failed to get session in %s.\n", __FUNCTION__);
348 return -1;
349 }
350
351 // already linked
352 if (iph1->parent_session) {
353 if (session == iph1->parent_session) {
354 return 0;
355 }
356 // undo previous session
357 if (ike_session_unlink_ph1_from_session(iph1) == 0) {
358 plog(LLV_DEBUG2, LOCATION, NULL, "failed to unlink ph1 in %s.\n", __FUNCTION__);
359 free_ike_session(session);
360 return -1;
361 }
362 } else {
363 gettimeofday(&session->start_timestamp, NULL);
364 }
365
366
367 if (iph1->started_by_api) {
368 session->is_cisco_ipsec = 1;
369 session->is_l2tpvpn_ipsec = 0;
370 session->is_btmm_ipsec = 0;
371 }
372 iph1->parent_session = session;
373 LIST_INSERT_HEAD(&session->ikev1_state.ph1tree, iph1, ph1ofsession_chain);
374 session->ikev1_state.active_ph1cnt++;
375 if ((!session->ikev1_state.ph1cnt &&
376 iph1->side == INITIATOR) ||
377 iph1->started_by_api) {
378 // client initiates the first phase1 or, is started by controller api
379 session->is_client = 1;
380 }
381 if (session->established &&
382 session->ikev1_state.ph1cnt) {
383 iph1->is_rekey = 1;
384 }
385 session->ikev1_state.ph1cnt++;
386 ike_session_init_traffic_cop_params(iph1);
387
388 return 0;
389 }
390
391 void
392 ike_session_update_mode (struct ph2handle *iph2)
393 {
394 if (!iph2 || !iph2->parent_session) {
395 return;
396 }
397
398 // exit early if we already detected cisco-ipsec
399 if (iph2->parent_session->is_cisco_ipsec) {
400 return;
401 }
402
403 if (iph2->approval) {
404 if (!ipsecdoi_any_transportmode(iph2->approval)) {
405 // cisco & btmm ipsec are pure tunnel-mode (but cisco ipsec is detected by ph1)
406 iph2->parent_session->is_cisco_ipsec = 0;
407 iph2->parent_session->is_l2tpvpn_ipsec = 0;
408 iph2->parent_session->is_btmm_ipsec = 1;
409 return;
410 } else if (ipsecdoi_transportmode(iph2->approval)) {
411 iph2->parent_session->is_cisco_ipsec = 0;
412 iph2->parent_session->is_l2tpvpn_ipsec = 1;
413 iph2->parent_session->is_btmm_ipsec = 0;
414 return;
415 }
416 } else if (iph2->proposal) {
417 if (!ipsecdoi_any_transportmode(iph2->proposal)) {
418 // cisco & btmm ipsec are pure tunnel-mode (but cisco ipsec is detected by ph1)
419 iph2->parent_session->is_cisco_ipsec = 0;
420 iph2->parent_session->is_l2tpvpn_ipsec = 0;
421 iph2->parent_session->is_btmm_ipsec = 1;
422 return;
423 } else if (ipsecdoi_transportmode(iph2->proposal)) {
424 iph2->parent_session->is_cisco_ipsec = 0;
425 iph2->parent_session->is_l2tpvpn_ipsec = 1;
426 iph2->parent_session->is_btmm_ipsec = 0;
427 return;
428 }
429 }
430 }
431
432 static void
433 ike_session_cleanup_xauth_timeout (void *arg)
434 {
435 ike_session_t *session = (ike_session_t *)arg;
436
437 SCHED_KILL(session->sc_xauth);
438 // if there are no more established ph2s, start a timer to teardown the session
439 if (!ike_session_has_established_ph2(session)) {
440 ike_session_cleanup(session, ike_session_stopped_by_xauth_timeout);
441 } else {
442 session->sc_xauth = sched_new(300 /* 5 mins */,
443 ike_session_cleanup_xauth_timeout,
444 session);
445 }
446 }
447
448 int
449 ike_session_link_ph2_to_session (struct ph2handle *iph2)
450 {
451 struct sockaddr *local;
452 struct sockaddr *remote;
453 ike_session_t *session;
454
455 if (!iph2) {
456 plog(LLV_DEBUG2, LOCATION, NULL, "invalid parameters in %s.\n", __FUNCTION__);
457 return -1;
458 }
459
460 local = iph2->src;
461 remote = iph2->dst;
462
463 session = ike_session_get_session(local, remote, TRUE);
464 if (!session) {
465 plog(LLV_DEBUG2, LOCATION, NULL, "failed to get session in %s.\n", __FUNCTION__);
466 return -1;
467 }
468
469 // already linked
470 if (iph2->parent_session) {
471 if (session == iph2->parent_session) {
472 return 0;
473 }
474 // undo previous session
475 if (ike_session_unlink_ph2_from_session(iph2) == 0) {
476 plog(LLV_DEBUG2, LOCATION, NULL, "failed to unlink ph2 in %s.\n", __FUNCTION__);
477 free_ike_session(session);
478 return -1;
479 }
480 }
481
482 iph2->parent_session = session;
483 LIST_INSERT_HEAD(&session->ikev1_state.ph2tree, iph2, ph2ofsession_chain);
484 session->ikev1_state.active_ph2cnt++;
485 if (!session->ikev1_state.ph2cnt &&
486 iph2->side == INITIATOR) {
487 // client initiates the first phase2
488 session->is_client = 1;
489 }
490 if (session->established &&
491 session->ikev1_state.ph2cnt) {
492 iph2->is_rekey = 1;
493 }
494 session->ikev1_state.ph2cnt++;
495
496 ike_session_update_mode(iph2);
497
498 return 0;
499 }
500
501 int
502 ike_session_unlink_ph1_from_session (struct ph1handle *iph1)
503 {
504 ike_session_t *session;
505
506 if (!iph1 || !iph1->parent_session) {
507 plog(LLV_DEBUG2, LOCATION, NULL, "invalid parameters in %s.\n", __FUNCTION__);
508 return -1;
509 }
510
511 if (LIST_FIRST(&iph1->ph2tree)) {
512 // reparent any phase2 that may be hanging on to this phase1
513 ike_session_update_ph1_ph2tree(iph1);
514 }
515
516 session = iph1->parent_session;
517 LIST_REMOVE(iph1, ph1ofsession_chain);
518 iph1->parent_session = NULL;
519 session->ikev1_state.active_ph1cnt--;
520 if (session->ikev1_state.active_ph1cnt == 0 && session->ikev1_state.active_ph2cnt == 0) {
521 free_ike_session(session);
522 }
523
524 return 0;
525 }
526
527 int
528 ike_session_unlink_ph2_from_session (struct ph2handle *iph2)
529 {
530 ike_session_t *session;
531
532 if (!iph2 || !iph2->parent_session) {
533 plog(LLV_DEBUG2, LOCATION, NULL, "invalid parameters in %s.\n", __FUNCTION__);
534 return -1;
535 }
536
537 LIST_REMOVE(iph2, ph2ofsession_chain);
538 session = iph2->parent_session;
539 iph2->parent_session = NULL;
540 session->ikev1_state.active_ph2cnt--;
541 if (session->ikev1_state.active_ph1cnt == 0 && session->ikev1_state.active_ph2cnt == 0) {
542 free_ike_session(session);
543 }
544
545 return 0;
546 }
547
548 int
549 ike_session_has_other_established_ph1 (ike_session_t *session, struct ph1handle *iph1)
550 {
551 struct ph1handle *p;
552
553 if (!session) {
554 return 0;
555 }
556
557 for (p = LIST_FIRST(&session->ikev1_state.ph1tree); p; p = LIST_NEXT(p, ph1ofsession_chain)) {
558 if (iph1 != p && !p->is_dying) {
559 if (p->status == PHASE1ST_ESTABLISHED && p->sce_rekey) {
560 return 1;
561 }
562 }
563 }
564
565 return 0;
566 }
567
568 int
569 ike_session_has_other_negoing_ph1 (ike_session_t *session, struct ph1handle *iph1)
570 {
571 struct ph1handle *p;
572
573 if (!session) {
574 plog(LLV_DEBUG2, LOCATION, NULL, "invalid parameters in %s.\n", __FUNCTION__);
575 return 0;
576 }
577
578 for (p = LIST_FIRST(&session->ikev1_state.ph1tree); p; p = LIST_NEXT(p, ph1ofsession_chain)) {
579 if (iph1 != p && !p->is_dying) {
580 if (p->status >= PHASE1ST_START && p->status <= PHASE1ST_ESTABLISHED) {
581 return 1;
582 }
583 }
584 }
585
586 return 0;
587 }
588
589 int
590 ike_session_has_other_established_ph2 (ike_session_t *session, struct ph2handle *iph2)
591 {
592 struct ph2handle *p;
593
594 if (!session) {
595 plog(LLV_DEBUG2, LOCATION, NULL, "invalid parameters in %s.\n", __FUNCTION__);
596 return 0;
597 }
598
599 for (p = LIST_FIRST(&session->ikev1_state.ph2tree); p; p = LIST_NEXT(p, ph2ofsession_chain)) {
600 if (iph2 != p && !p->is_dying && iph2->spid == p->spid) {
601 if (p->status == PHASE2ST_ESTABLISHED) {
602 return 1;
603 }
604 }
605 }
606
607 return 0;
608 }
609
610 int
611 ike_session_has_other_negoing_ph2 (ike_session_t *session, struct ph2handle *iph2)
612 {
613 struct ph2handle *p;
614
615 if (!session) {
616 plog(LLV_DEBUG2, LOCATION, NULL, "invalid parameters in %s.\n", __FUNCTION__);
617 return 0;
618 }
619
620 for (p = LIST_FIRST(&session->ikev1_state.ph2tree); p; p = LIST_NEXT(p, ph2ofsession_chain)) {
621 if (iph2 != p && !p->is_dying && iph2->spid == p->spid) {
622 if (p->status >= PHASE2ST_START && p->status < PHASE2ST_ESTABLISHED) {
623 return 1;
624 }
625 }
626 }
627
628 return 0;
629 }
630
631 static void
632 ike_session_unbindph12_from_ph1 (struct ph1handle *iph1)
633 {
634 struct ph2handle *p, *next;
635
636 for (p = LIST_FIRST(&iph1->ph2tree); p; p = next) {
637 // take next pointer now, since unbind and rebind may change the underlying ph2tree list
638 next = LIST_NEXT(p, ph1bind);
639 unbindph12(p);
640 }
641 }
642
643 static void
644 ike_session_rebindph12_from_old_ph1_to_new_ph1 (struct ph1handle *old_iph1,
645 struct ph1handle *new_iph1)
646 {
647 struct ph2handle *p, *next;
648
649 if (old_iph1 == new_iph1 || !old_iph1 || !new_iph1) {
650 plog(LLV_DEBUG2, LOCATION, NULL, "invalid parameters in %s.\n", __FUNCTION__);
651 return;
652 }
653
654 if (old_iph1->parent_session != new_iph1->parent_session) {
655 plog(LLV_DEBUG2, LOCATION, NULL, "invalid parent sessions in %s.\n", __FUNCTION__);
656 return;
657 }
658
659 for (p = LIST_FIRST(&old_iph1->ph2tree); p; p = next) {
660 // take next pointer now, since rebind may change the underlying ph2tree list
661 next = LIST_NEXT(p, ph1bind);
662 if (p->parent_session != new_iph1->parent_session) {
663 plog(LLV_ERROR, LOCATION, NULL, "mismatched parent session in ph1bind replacement.\n");
664 }
665 if (p->ph1 == new_iph1) {
666 plog(LLV_ERROR, LOCATION, NULL, "same phase1 in ph1bind replacement in %s.\n",__FUNCTION__);
667 }
668 rebindph12(new_iph1, p);
669 }
670 }
671
672 int
673 ike_session_verify_ph2_parent_session (struct ph2handle *iph2)
674 {
675 if (!iph2) {
676 plog(LLV_DEBUG2, LOCATION, NULL, "invalid parameters in %s.\n", __FUNCTION__);
677 return -1;
678 }
679
680 if (!iph2->parent_session) {
681 plog(LLV_DEBUG, LOCATION, NULL, "NULL parent session.\n");
682 if (ike_session_link_ph2_to_session(iph2)) {
683 plog(LLV_DEBUG, LOCATION, NULL, "NULL parent session... still failed to link to session.\n");
684 // failed to bind ph2 to session
685 return 1;
686 }
687 }
688 return 0;
689 }
690
691 struct ph1handle *
692 ike_session_update_ph1_ph2tree (struct ph1handle *iph1)
693 {
694 struct ph1handle *new_iph1 = NULL;
695
696 if (!iph1) {
697 plog(LLV_DEBUG2, LOCATION, NULL, "invalid parameters in %s.\n", __FUNCTION__);
698 return NULL;
699 }
700
701 if (iph1->parent_session) {
702 new_iph1 = ike_session_get_established_ph1(iph1->parent_session);
703
704 if (!new_iph1) {
705 plog(LLV_DEBUG2, LOCATION, NULL, "no ph1bind replacement found. NULL ph1.\n");
706 ike_session_unbindph12_from_ph1(iph1);
707 } else if (iph1 == new_iph1) {
708 plog(LLV_DEBUG2, LOCATION, NULL, "no ph1bind replacement found. same ph1.\n");
709 ike_session_unbindph12_from_ph1(iph1);
710 } else {
711 ike_session_rebindph12_from_old_ph1_to_new_ph1(iph1, new_iph1);
712 }
713 } else {
714 plog(LLV_DEBUG2, LOCATION, NULL, "invalid parent session in %s.\n", __FUNCTION__);
715 }
716 return new_iph1;
717 }
718
719 struct ph1handle *
720 ike_session_update_ph2_ph1bind (struct ph2handle *iph2)
721 {
722 struct ph1handle *iph1;
723
724 if (!iph2) {
725 plog(LLV_DEBUG2, LOCATION, NULL, "invalid parameters in %s.\n", __FUNCTION__);
726 return NULL;
727 }
728
729 iph1 = ike_session_get_established_ph1(iph2->parent_session);
730 if (iph1 && iph2->ph1 && iph1 != iph2->ph1) {
731 rebindph12(iph1, iph2);
732 } else if (iph1 && !iph2->ph1) {
733 bindph12(iph1, iph2);
734 }
735
736 return iph1;
737 }
738
739 void
740 ike_session_ikev1_float_ports (struct ph1handle *iph1)
741 {
742 struct sockaddr *local, *remote;
743 struct ph2handle *p;
744
745 if (iph1->parent_session) {
746 local = (struct sockaddr *)&iph1->parent_session->session_id.local;
747 remote = (struct sockaddr *)&iph1->parent_session->session_id.remote;
748
749 set_port(local, extract_port(iph1->local));
750 set_port(remote, extract_port(iph1->remote));
751 iph1->parent_session->ports_floated = 1;
752
753 for (p = LIST_FIRST(&iph1->parent_session->ikev1_state.ph2tree); p; p = LIST_NEXT(p, ph2ofsession_chain)) {
754
755 local = p->src;
756 remote = p->dst;
757
758 set_port(local, extract_port(iph1->local));
759 set_port(remote, extract_port(iph1->remote));
760 }
761 } else {
762 plog(LLV_DEBUG2, LOCATION, NULL, "invalid parent session in %s.\n", __FUNCTION__);
763 }
764 }
765
766 static void
767 ike_session_traffic_cop (void *arg)
768 {
769 ike_session_t *session = (__typeof__(session))arg;
770
771 if (session) {
772 SCHED_KILL(session->traffic_monitor.sc_mon);
773 /* get traffic query from kernel */
774 if (pk_sendget_inbound_sastats(session) < 0) {
775 // log message
776 plog(LLV_DEBUG2, LOCATION, NULL, "pk_sendget_inbound_sastats failed in %s.\n", __FUNCTION__);
777 }
778 if (pk_sendget_outbound_sastats(session) < 0) {
779 // log message
780 plog(LLV_DEBUG2, LOCATION, NULL, "pk_sendget_outbound_sastats failed in %s.\n", __FUNCTION__);
781 }
782 session->traffic_monitor.sc_mon = sched_new(session->traffic_monitor.interv_mon,
783 ike_session_traffic_cop,
784 session);
785 } else {
786 // log message
787 plog(LLV_DEBUG2, LOCATION, NULL, "invalid parameters in %s.\n", __FUNCTION__);
788 }
789 }
790
791 static void
792 ike_session_cleanup_idle (void *arg)
793 {
794 ike_session_t *session = (ike_session_t *)arg;
795
796 if (session->traffic_monitor.dir_idle == IPSEC_DIR_INBOUND ||
797 session->traffic_monitor.dir_idle == IPSEC_DIR_ANY) {
798 if (session->peer_sent_data_sc_idle) {
799 SCHED_KILL(session->traffic_monitor.sc_idle);
800 session->traffic_monitor.sc_idle = sched_new(session->traffic_monitor.interv_idle,
801 ike_session_cleanup_idle,
802 session);
803 session->peer_sent_data_sc_idle = 0;
804 session->i_sent_data_sc_idle = 0;
805 return;
806 }
807 }
808 if (session->traffic_monitor.dir_idle == IPSEC_DIR_OUTBOUND ||
809 session->traffic_monitor.dir_idle == IPSEC_DIR_ANY) {
810 if (session->i_sent_data_sc_idle) {
811 SCHED_KILL(session->traffic_monitor.sc_idle);
812 session->traffic_monitor.sc_idle = sched_new(session->traffic_monitor.interv_idle,
813 ike_session_cleanup_idle,
814 session);
815 session->peer_sent_data_sc_idle = 0;
816 session->i_sent_data_sc_idle = 0;
817 return;
818 }
819 }
820
821 ike_session_cleanup((ike_session_t *)arg, ike_session_stopped_by_idle);
822 }
823
824 void
825 ike_session_ph2_established (struct ph2handle *iph2)
826 {
827 if (!iph2->parent_session) {
828 plog(LLV_DEBUG2, LOCATION, NULL, "invalid parameters in %s.\n", __FUNCTION__);
829 return;
830 }
831 SCHED_KILL(iph2->parent_session->sc_xauth);
832 if (!iph2->parent_session->established) {
833 gettimeofday(&iph2->parent_session->estab_timestamp, NULL);
834 iph2->parent_session->established = 1;
835 IPSECSESSIONTRACERESTABLISHED(iph2->parent_session);
836 if (iph2->parent_session->traffic_monitor.interv_mon) {
837 iph2->parent_session->traffic_monitor.sc_mon = sched_new(iph2->parent_session->traffic_monitor.interv_mon,
838 ike_session_traffic_cop,
839 iph2->parent_session);
840 }
841 if (iph2->parent_session->traffic_monitor.interv_idle) {
842 iph2->parent_session->traffic_monitor.sc_idle = sched_new(iph2->parent_session->traffic_monitor.interv_idle,
843 ike_session_cleanup_idle,
844 iph2->parent_session);
845 }
846 }
847 // nothing happening to this session
848 iph2->parent_session->term_reason = NULL;
849
850 ike_session_update_mode(iph2);
851 }
852
853 void
854 ike_session_cleanup_ph1 (struct ph1handle *iph1)
855 {
856 if (iph1->status == PHASE1ST_EXPIRED) {
857 // since this got here via ike_session_cleanup_other_established_ph1s, assumes LIST_FIRST(&iph1->ph2tree) == NULL
858 iph1->sce = sched_new(1, isakmp_ph1delete_stub, iph1);
859 return;
860 }
861
862 /* send delete information */
863 if (iph1->status == PHASE1ST_ESTABLISHED) {
864 isakmp_info_send_d1(iph1);
865 }
866
867 isakmp_ph1expire(iph1);
868 }
869
870 void
871 ike_session_cleanup_ph1_stub (void *p)
872 {
873
874 ike_session_cleanup_ph1((struct ph1handle *)p);
875 }
876
877 void
878 ike_session_cleanup_other_established_ph1s (ike_session_t *session,
879 struct ph1handle *new_iph1)
880 {
881 struct ph1handle *p, *next;
882 char *local, *remote;
883
884 if (!session || !new_iph1 || session != new_iph1->parent_session) {
885 plog(LLV_DEBUG2, LOCATION, NULL, "invalid parameters in %s.\n", __FUNCTION__);
886 return;
887 }
888
889 for (p = LIST_FIRST(&session->ikev1_state.ph1tree); p; p = next) {
890 // take next pointer now, since delete change the underlying ph1tree list
891 next = LIST_NEXT(p, ph1ofsession_chain);
892 /*
893 * TODO: currently, most recently established SA wins. Need to revisit to see if
894 * alternative selections is better (e.g. largest p->index stays).
895 */
896 if (p != new_iph1) {
897 SCHED_KILL(p->sce);
898 SCHED_KILL(p->sce_rekey);
899 p->is_dying = 1;
900
901 //log deletion
902 local = racoon_strdup(saddr2str(p->local));
903 remote = racoon_strdup(saddr2str(p->remote));
904 STRDUP_FATAL(local);
905 STRDUP_FATAL(remote);
906 plog(LLV_DEBUG, LOCATION, NULL,
907 "ISAKMP-SA needs to be deleted %s-%s spi:%s\n",
908 local, remote, isakmp_pindex(&p->index, 0));
909 racoon_free(local);
910 racoon_free(remote);
911
912 // first rebind the children ph2s of this dying ph1 to the new ph1.
913 ike_session_rebindph12_from_old_ph1_to_new_ph1 (p, new_iph1);
914
915 if (p->side == INITIATOR) {
916 /* everyone deletes old outbound SA */
917 p->sce = sched_new(5, ike_session_cleanup_ph1_stub, p);
918 } else {
919 /* responder sets up timer to delete old inbound SAs... say 7 secs later and flags them as rekeyed */
920 p->sce = sched_new(7, ike_session_cleanup_ph1_stub, p);
921 }
922 }
923 }
924 }
925
926 void
927 ike_session_cleanup_ph2 (struct ph2handle *iph2)
928 {
929 if (iph2->status == PHASE2ST_EXPIRED) {
930 return;
931 }
932
933 SCHED_KILL(iph2->sce);
934
935 /* send delete information */
936 if (iph2->status == PHASE2ST_ESTABLISHED) {
937 isakmp_info_send_d2(iph2);
938 }
939
940 // delete outgoing SAs
941 if (iph2->approval) {
942 struct saproto *pr;
943
944 for (pr = iph2->approval->head; pr != NULL; pr = pr->next) {
945 if (pr->ok) {
946 pfkey_send_delete(lcconf->sock_pfkey,
947 ipsecdoi2pfkey_proto(pr->proto_id),
948 IPSEC_MODE_ANY,
949 iph2->src, iph2->dst, pr->spi_p /* pr->reqid_out */);
950 }
951 }
952 }
953
954 delete_spd(iph2);
955 unbindph12(iph2);
956 remph2(iph2);
957 delph2(iph2);
958 }
959
960 void
961 ike_session_cleanup_ph2_stub (void *p)
962 {
963
964 ike_session_cleanup_ph2((struct ph2handle *)p);
965 }
966
967 void
968 ike_session_cleanup_other_established_ph2s (ike_session_t *session,
969 struct ph2handle *new_iph2)
970 {
971 struct ph2handle *p, *next;
972
973 if (!session || !new_iph2 || session != new_iph2->parent_session) {
974 plog(LLV_DEBUG2, LOCATION, NULL, "invalid parameters in %s.\n", __FUNCTION__);
975 return;
976 }
977
978 for (p = LIST_FIRST(&session->ikev1_state.ph2tree); p; p = next) {
979 // take next pointer now, since delete change the underlying ph2tree list
980 next = LIST_NEXT(p, ph2ofsession_chain);
981 /*
982 * TODO: currently, most recently established SA wins. Need to revisit to see if
983 * alternative selections is better.
984 */
985 if (p != new_iph2 && p->spid == new_iph2->spid) {
986 SCHED_KILL(p->sce);
987 p->is_dying = 1;
988
989 //log deletion
990 plog(LLV_DEBUG, LOCATION, NULL,
991 "IPsec-SA needs to be deleted: %s\n",
992 sadbsecas2str(p->src, p->dst,
993 p->satype, p->spid, 0));
994
995 if (p->side == INITIATOR) {
996 /* responder sets up timer to delete old inbound SAs... say 5 secs later and flags them as rekeyed */
997 p->sce = sched_new(3, ike_session_cleanup_ph2_stub, p);
998 } else {
999 /* responder sets up timer to delete old inbound SAs... say 5 secs later and flags them as rekeyed */
1000 p->sce = sched_new(5, ike_session_cleanup_ph2_stub, p);
1001 }
1002 }
1003 }
1004 }
1005
1006 void
1007 ike_session_stopped_by_controller (ike_session_t *session,
1008 const char *reason)
1009 {
1010 if (!session) {
1011 plog(LLV_DEBUG2, LOCATION, NULL, "invalid parameters in %s.\n", __FUNCTION__);
1012 return;
1013 }
1014 if (session->stop_timestamp.tv_sec ||
1015 session->stop_timestamp.tv_usec) {
1016 plog(LLV_DEBUG2, LOCATION, NULL, "already stopped %s.\n", __FUNCTION__);
1017 return;
1018 }
1019 session->stopped_by_vpn_controller = 1;
1020 gettimeofday(&session->stop_timestamp, NULL);
1021 if (!session->term_reason) {
1022 session->term_reason = reason;
1023 }
1024 }
1025
1026 void
1027 ike_sessions_stopped_by_controller (struct sockaddr *remote,
1028 int withport,
1029 const char *reason)
1030 {
1031 ike_session_t *p = NULL;
1032
1033 if (!remote) {
1034 plog(LLV_DEBUG2, LOCATION, NULL, "invalid parameters in %s.\n", __FUNCTION__);
1035 return;
1036 }
1037
1038 for (p = LIST_FIRST(&ike_session_tree); p; p = LIST_NEXT(p, chain)) {
1039 if (withport && cmpsaddrstrict(&p->session_id.remote, remote) == 0 ||
1040 !withport && cmpsaddrwop(&p->session_id.remote, remote) == 0) {
1041 ike_session_stopped_by_controller(p, reason);
1042 }
1043 }
1044 }
1045
1046 void
1047 ike_session_purge_ph2s_by_ph1 (struct ph1handle *iph1)
1048 {
1049 struct ph2handle *p, *next;
1050
1051 if (!iph1 || !iph1->parent_session) {
1052 plog(LLV_DEBUG2, LOCATION, NULL, "invalid parameters in %s.\n", __FUNCTION__);
1053 return;
1054 }
1055
1056 for (p = LIST_FIRST(&iph1->parent_session->ikev1_state.ph2tree); p; p = next) {
1057 // take next pointer now, since delete change the underlying ph2tree list
1058 next = LIST_NEXT(p, ph2ofsession_chain);
1059 SCHED_KILL(p->sce);
1060 p->is_dying = 1;
1061
1062 //log deletion
1063 plog(LLV_DEBUG, LOCATION, NULL,
1064 "IPsec-SA needs to be purged: %s\n",
1065 sadbsecas2str(p->src, p->dst,
1066 p->satype, p->spid, 0));
1067
1068 ike_session_cleanup_ph2(p);
1069 }
1070 }
1071
1072 void
1073 ike_session_update_ph2_ports (struct ph2handle *iph2)
1074 {
1075 struct sockaddr *local;
1076 struct sockaddr *remote;
1077
1078 if (iph2->parent_session) {
1079 local = (struct sockaddr *)&iph2->parent_session->session_id.local;
1080 remote = (struct sockaddr *)&iph2->parent_session->session_id.remote;
1081
1082 set_port(iph2->src, extract_port(local));
1083 set_port(iph2->dst, extract_port(remote));
1084 } else {
1085 plog(LLV_DEBUG2, LOCATION, NULL, "invalid parent session in %s.\n", __FUNCTION__);
1086 }
1087 }
1088
1089 u_int32_t
1090 ike_session_get_sas_for_stats (ike_session_t *session,
1091 u_int8_t dir,
1092 u_int32_t *seq,
1093 struct sastat *stats,
1094 u_int32_t max_stats)
1095 {
1096 int found = 0;
1097 struct ph2handle *iph2;
1098
1099 if (!session || !seq || !stats || !max_stats || (dir != IPSEC_DIR_INBOUND && dir != IPSEC_DIR_OUTBOUND)) {
1100 plog(LLV_DEBUG2, LOCATION, NULL, "invalid args in %s.\n", __FUNCTION__);
1101 return found;
1102 }
1103
1104 *seq = 0;
1105 for (iph2 = LIST_FIRST(&session->ikev1_state.ph2tree); iph2; iph2 = LIST_NEXT(iph2, ph2ofsession_chain)) {
1106
1107 if (iph2->approval) {
1108 struct saproto *pr;
1109
1110 for (pr = iph2->approval->head; pr != NULL; pr = pr->next) {
1111 if (pr->ok && pr->proto_id == IPSECDOI_PROTO_IPSEC_ESP) {
1112 if (!*seq) {
1113 *seq = iph2->seq;
1114 }
1115 if (dir == IPSEC_DIR_INBOUND) {
1116 stats[found].spi = pr->spi;
1117 } else {
1118 stats[found].spi = pr->spi_p;
1119 }
1120 if (++found == max_stats) {
1121 return found;
1122 }
1123 }
1124 }
1125 }
1126 }
1127 return found;
1128 }
1129
1130 void
1131 ike_session_update_traffic_idle_status (ike_session_t *session,
1132 u_int32_t dir,
1133 struct sastat *new_stats,
1134 u_int32_t max_stats)
1135 {
1136 int i, j, found = 0, idle = 1;
1137
1138 if (!session || !new_stats || (dir != IPSEC_DIR_INBOUND && dir != IPSEC_DIR_OUTBOUND)) {
1139 plog(LLV_DEBUG2, LOCATION, NULL, "invalid args in %s.\n", __FUNCTION__);
1140 return;
1141 }
1142
1143 for (i = 0; i < max_stats; i++) {
1144 if (dir == IPSEC_DIR_INBOUND) {
1145 for (j = 0; j < session->traffic_monitor.num_in_last_poll; j++) {
1146 if (new_stats[i].spi != session->traffic_monitor.in_last_poll[j].spi) {
1147 continue;
1148 }
1149 found = 1;
1150 if (new_stats[i].lft_c.sadb_lifetime_bytes != session->traffic_monitor.in_last_poll[j].lft_c.sadb_lifetime_bytes) {
1151 idle = 0;
1152 }
1153 }
1154 } else {
1155 for (j = 0; j < session->traffic_monitor.num_out_last_poll; j++) {
1156 if (new_stats[i].spi != session->traffic_monitor.out_last_poll[j].spi) {
1157 continue;
1158 }
1159 found = 1;
1160 if (new_stats[i].lft_c.sadb_lifetime_bytes != session->traffic_monitor.out_last_poll[j].lft_c.sadb_lifetime_bytes) {
1161 idle = 0;
1162 }
1163 }
1164 }
1165 // new SA.... check for any activity
1166 if (!found) {
1167 if (new_stats[i].lft_c.sadb_lifetime_bytes) {
1168 plog(LLV_DEBUG, LOCATION, NULL, "new SA: dir %d....\n", dir);
1169 idle = 0;
1170 }
1171 }
1172 }
1173 if (dir == IPSEC_DIR_INBOUND) {
1174 // overwrite old stats
1175 bzero(session->traffic_monitor.in_last_poll, sizeof(session->traffic_monitor.in_last_poll));
1176 bcopy(new_stats, session->traffic_monitor.in_last_poll, (max_stats * sizeof(*new_stats)));
1177 session->traffic_monitor.num_in_last_poll = max_stats;
1178 if (!idle) {
1179 plog(LLV_DEBUG, LOCATION, NULL, "peer sent data....\n");
1180 session->peer_sent_data_sc_dpd = 1;
1181 session->peer_sent_data_sc_idle = 1;
1182 }
1183 } else {
1184 // overwrite old stats
1185 bzero(session->traffic_monitor.out_last_poll, sizeof(session->traffic_monitor.out_last_poll));
1186 bcopy(new_stats, session->traffic_monitor.out_last_poll, (max_stats * sizeof(*new_stats)));
1187 session->traffic_monitor.num_out_last_poll = max_stats;
1188 if (!idle) {
1189 plog(LLV_DEBUG, LOCATION, NULL, "i sent data....\n");
1190 session->i_sent_data_sc_dpd = 1;
1191 session->i_sent_data_sc_idle = 1;
1192 }
1193 }
1194 }
1195
1196 void
1197 ike_session_cleanup (ike_session_t *session,
1198 const char *reason)
1199 {
1200 struct ph2handle *iph2;
1201 struct ph1handle *iph1;
1202
1203 if (!session)
1204 return;
1205
1206 // do ph2's first... we need the ph1s for notifications
1207 for (iph2 = LIST_FIRST(&session->ikev1_state.ph2tree); iph2; iph2 = LIST_NEXT(iph2, ph2ofsession_chain)) {
1208 if (iph2->status == PHASE2ST_ESTABLISHED) {
1209 isakmp_info_send_d2(iph2);
1210 }
1211 isakmp_ph2expire(iph2); // iph2 will go down 1 second later.
1212 ike_session_stopped_by_controller(session, reason);
1213 }
1214
1215 // do the ph1s last.
1216 for (iph1 = LIST_FIRST(&session->ikev1_state.ph1tree); iph1; iph1 = LIST_NEXT(iph1, ph1ofsession_chain)) {
1217 if (iph1->status == PHASE1ST_ESTABLISHED) {
1218 isakmp_info_send_d1(iph1);
1219 }
1220 isakmp_ph1expire(iph1);
1221 }
1222
1223 // send ipsecManager a notification
1224 if (reason == ike_session_stopped_by_idle) {
1225 u_int32_t address;
1226 if (((struct sockaddr *)&session->session_id.remote)->sa_family == AF_INET) {
1227 address = ((struct sockaddr_in *)&session->session_id.remote)->sin_addr.s_addr;
1228 } else {
1229 address = 0;
1230 }
1231 (void)vpncontrol_notify_ike_failed(VPNCTL_NTYPE_IDLE_TIMEOUT, FROM_LOCAL, address, 0, NULL);
1232 }
1233 }
1234
1235 int
1236 ike_session_has_negoing_ph1 (ike_session_t *session)
1237 {
1238 struct ph1handle *p;
1239
1240 if (!session) {
1241 plog(LLV_DEBUG2, LOCATION, NULL, "invalid parameters in %s.\n", __FUNCTION__);
1242 return 0;
1243 }
1244
1245 for (p = LIST_FIRST(&session->ikev1_state.ph1tree); p; p = LIST_NEXT(p, ph1ofsession_chain)) {
1246 if (!p->is_dying && p->status >= PHASE1ST_START && p->status <= PHASE1ST_ESTABLISHED) {
1247 return 1;
1248 }
1249 }
1250
1251 return 0;
1252 }
1253
1254 int
1255 ike_session_has_negoing_ph2 (ike_session_t *session)
1256 {
1257 struct ph2handle *p;
1258
1259 if (!session) {
1260 plog(LLV_DEBUG2, LOCATION, NULL, "invalid parameters in %s.\n", __FUNCTION__);
1261 return 0;
1262 }
1263
1264 for (p = LIST_FIRST(&session->ikev1_state.ph2tree); p; p = LIST_NEXT(p, ph2ofsession_chain)) {
1265 if (!p->is_dying && p->status >= PHASE2ST_START && p->status <= PHASE2ST_ESTABLISHED) {
1266 return 1;
1267 }
1268 }
1269
1270 return 0;
1271 }
1272
1273 int
1274 ike_session_has_established_ph2 (ike_session_t *session)
1275 {
1276 struct ph2handle *p;
1277
1278 if (!session) {
1279 plog(LLV_DEBUG2, LOCATION, NULL, "invalid parameters in %s.\n", __FUNCTION__);
1280 return 0;
1281 }
1282
1283 for (p = LIST_FIRST(&session->ikev1_state.ph2tree); p; p = LIST_NEXT(p, ph2ofsession_chain)) {
1284 if (!p->is_dying && p->status == PHASE2ST_ESTABLISHED) {
1285 return 1;
1286 }
1287 }
1288
1289 return 0;
1290 }
1291
1292 void
1293 ike_session_cleanup_ph1s_by_ph2 (struct ph2handle *iph2)
1294 {
1295 struct ph1handle *iph1;
1296
1297 if (!iph2 || !iph2->parent_session) {
1298 plog(LLV_DEBUG2, LOCATION, NULL, "invalid parameters in %s.\n", __FUNCTION__);
1299 return;
1300 }
1301
1302 // phase1 is no longer useful
1303 for (iph1 = LIST_FIRST(&iph2->parent_session->ikev1_state.ph1tree); iph1; iph1 = LIST_NEXT(iph1, ph1ofsession_chain)) {
1304 if (iph1->status == PHASE1ST_ESTABLISHED) {
1305 isakmp_info_send_d1(iph1);
1306 }
1307 isakmp_ph1expire(iph1);
1308 }
1309 }
1310
1311 int
1312 ike_session_is_client_ph2_rekey (struct ph2handle *iph2)
1313 {
1314 if (iph2->parent_session &&
1315 iph2->parent_session->is_client &&
1316 iph2->is_rekey &&
1317 iph2->parent_session->is_cisco_ipsec) {
1318 return 1;
1319 }
1320 return 0;
1321 }
1322
1323 int
1324 ike_session_is_client_ph1_rekey (struct ph1handle *iph1)
1325 {
1326 if (iph1->parent_session &&
1327 iph1->parent_session->is_client &&
1328 iph1->is_rekey &&
1329 iph1->parent_session->is_cisco_ipsec) {
1330 return 1;
1331 }
1332 return 0;
1333 }
1334
1335 void
1336 ike_session_start_xauth_timer (struct ph1handle *iph1)
1337 {
1338 // if there are no more established ph2s, start a timer to teardown the session
1339 if (iph1->parent_session &&
1340 iph1->parent_session->is_client &&
1341 iph1->parent_session->is_cisco_ipsec &&
1342 !iph1->parent_session->sc_xauth) {
1343 iph1->parent_session->sc_xauth = sched_new(300 /* 5 mins */,
1344 ike_session_cleanup_xauth_timeout,
1345 iph1->parent_session);
1346 }
1347 }
1348
1349 void
1350 ike_session_stop_xauth_timer (struct ph1handle *iph1)
1351 {
1352 if (iph1->parent_session) {
1353 SCHED_KILL(iph1->parent_session->sc_xauth);
1354 }
1355 }