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