2 * Copyright (c) 2008 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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.
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
20 * @APPLE_LICENSE_HEADER_END@
23 #include <sys/param.h>
24 #include <sys/types.h>
25 #include <sys/socket.h>
35 #include "isakmp_var.h"
37 #include "ike_session.h"
40 #include "nattraversal.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"
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";
56 static LIST_HEAD(_ike_session_tree_
, ike_session
) ike_session_tree
;
58 static ike_session_t
*
59 new_ike_session (ike_session_id_t
*id
)
61 ike_session_t
*session
;
64 plog(LLV_DEBUG2
, LOCATION
, NULL
, "invalid parameters in %s.\n", __FUNCTION__
);
68 plog(LLV_DEBUG
, LOCATION
, NULL
, "new parent session.\n");
69 session
= racoon_calloc(1, sizeof(*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
);
83 free_ike_session (ike_session_t
*session
)
85 int is_failure
= TRUE
;
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
);
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
) {
99 IPSECSESSIONTRACERSTOP(session
,
101 session
->term_reason
);
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
);
113 ike_session_get_established_or_negoing_ph1 (ike_session_t
*session
)
115 struct ph1handle
*p
, *iph1
= NULL
;
118 plog(LLV_DEBUG2
, LOCATION
, NULL
, "invalid parameters in %s.\n", __FUNCTION__
);
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
) {
127 } else if (iph1
&& p
->status
== iph1
->status
) {
128 // TODO: pick better one based on farthest rekey/expiry remaining
137 ike_session_get_established_ph1 (ike_session_t
*session
)
142 plog(LLV_DEBUG2
, LOCATION
, NULL
, "invalid parameters in %s.\n", __FUNCTION__
);
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
) {
156 ike_session_init (void)
158 LIST_INIT(&ike_session_tree
);
162 ike_session_get_rekey_lifetime (int local_spi_is_higher
, u_int expiry_lifetime
)
164 u_int rekey_lifetime
= expiry_lifetime
/ 10;
166 if (rekey_lifetime
) {
167 if (local_spi_is_higher
) {
168 return (rekey_lifetime
* 9);
170 return (rekey_lifetime
* 8);
173 if (local_spi_is_higher
) {
174 rekey_lifetime
= expiry_lifetime
- 1;
176 rekey_lifetime
= expiry_lifetime
- 2;
179 if (rekey_lifetime
< expiry_lifetime
) {
180 return (rekey_lifetime
);
185 // TODO: optimize this mess later
187 ike_session_get_session (struct sockaddr
*local
,
188 struct sockaddr
*remote
,
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
;
200 if (!local
|| !remote
) {
201 plog(LLV_DEBUG2
, LOCATION
, NULL
, "invalid parameters in %s.\n", __FUNCTION__
);
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;
209 is_isakmp_remote_port
= 1;
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
));
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
));
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);
246 plog(LLV_DEBUG
, LOCATION
, local
,
247 "start search for IKE-Session. target %s.\n",
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
));
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",
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",
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",
270 } else if (is_isakmp_remote_port
&& memcmp(&p
->session_id
, &id_wop
, sizeof(id_wop
)) == 0) {
275 plog(LLV_DEBUG
, LOCATION
, local
,
276 "Best-match IKE-Session to %s.\n",
277 saddr2str((struct sockaddr
*)&best_match
->session_id
.remote
));
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
);
291 ike_session_init_traffic_cop_params (struct ph1handle
*iph1
)
295 (!iph1
->rmconf
->idle_timeout
&& !iph1
->rmconf
->dpd_interval
)) {
299 if (!iph1
->parent_session
->traffic_monitor
.interv_idle
) {
300 iph1
->parent_session
->traffic_monitor
.interv_idle
= iph1
->rmconf
->idle_timeout
;
302 if (!iph1
->parent_session
->traffic_monitor
.dir_idle
) {
303 iph1
->parent_session
->traffic_monitor
.dir_idle
= iph1
->rmconf
->idle_timeout_dir
;
306 if (!iph1
->parent_session
->traffic_monitor
.interv_mon
) {
307 int min_period
, max_period
, sample_period
= 0;
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
);
319 // DPD_ALGO_DEFAULT is configured and there's no idle timeout... we don't need to monitor traffic
323 sample_period
= min_period
>> 1;
325 sample_period
= 1; // bad
327 sample_period
= max_period
>> 1;
329 sample_period
= 1; // bad
331 iph1
->parent_session
->traffic_monitor
.interv_mon
= sample_period
;
336 ike_session_link_ph1_to_session (struct ph1handle
*iph1
)
338 ike_session_t
*session
;
341 plog(LLV_DEBUG2
, LOCATION
, NULL
, "invalid parameters in %s.\n", __FUNCTION__
);
345 session
= ike_session_get_session(iph1
->local
, iph1
->remote
, TRUE
);
347 plog(LLV_DEBUG2
, LOCATION
, NULL
, "failed to get session in %s.\n", __FUNCTION__
);
352 if (iph1
->parent_session
) {
353 if (session
== iph1
->parent_session
) {
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
);
363 gettimeofday(&session
->start_timestamp
, NULL
);
367 if (iph1
->started_by_api
) {
368 session
->is_cisco_ipsec
= 1;
369 session
->is_l2tpvpn_ipsec
= 0;
370 session
->is_btmm_ipsec
= 0;
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;
381 if (session
->established
&&
382 session
->ikev1_state
.ph1cnt
) {
385 session
->ikev1_state
.ph1cnt
++;
386 ike_session_init_traffic_cop_params(iph1
);
392 ike_session_update_mode (struct ph2handle
*iph2
)
394 if (!iph2
|| !iph2
->parent_session
) {
398 // exit early if we already detected cisco-ipsec
399 if (iph2
->parent_session
->is_cisco_ipsec
) {
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;
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;
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;
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;
433 ike_session_cleanup_xauth_timeout (void *arg
)
435 ike_session_t
*session
= (ike_session_t
*)arg
;
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
);
442 session
->sc_xauth
= sched_new(300 /* 5 mins */,
443 ike_session_cleanup_xauth_timeout
,
449 ike_session_link_ph2_to_session (struct ph2handle
*iph2
)
451 struct sockaddr
*local
;
452 struct sockaddr
*remote
;
453 ike_session_t
*session
;
456 plog(LLV_DEBUG2
, LOCATION
, NULL
, "invalid parameters in %s.\n", __FUNCTION__
);
463 session
= ike_session_get_session(local
, remote
, TRUE
);
465 plog(LLV_DEBUG2
, LOCATION
, NULL
, "failed to get session in %s.\n", __FUNCTION__
);
470 if (iph2
->parent_session
) {
471 if (session
== iph2
->parent_session
) {
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
);
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;
490 if (session
->established
&&
491 session
->ikev1_state
.ph2cnt
) {
494 session
->ikev1_state
.ph2cnt
++;
496 ike_session_update_mode(iph2
);
502 ike_session_unlink_ph1_from_session (struct ph1handle
*iph1
)
504 ike_session_t
*session
;
506 if (!iph1
|| !iph1
->parent_session
) {
507 plog(LLV_DEBUG2
, LOCATION
, NULL
, "invalid parameters in %s.\n", __FUNCTION__
);
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
);
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
);
528 ike_session_unlink_ph2_from_session (struct ph2handle
*iph2
)
530 ike_session_t
*session
;
532 if (!iph2
|| !iph2
->parent_session
) {
533 plog(LLV_DEBUG2
, LOCATION
, NULL
, "invalid parameters in %s.\n", __FUNCTION__
);
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
);
549 ike_session_has_other_established_ph1 (ike_session_t
*session
, struct ph1handle
*iph1
)
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
) {
569 ike_session_has_other_negoing_ph1 (ike_session_t
*session
, struct ph1handle
*iph1
)
574 plog(LLV_DEBUG2
, LOCATION
, NULL
, "invalid parameters in %s.\n", __FUNCTION__
);
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
) {
590 ike_session_has_other_established_ph2 (ike_session_t
*session
, struct ph2handle
*iph2
)
595 plog(LLV_DEBUG2
, LOCATION
, NULL
, "invalid parameters in %s.\n", __FUNCTION__
);
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
) {
611 ike_session_has_other_negoing_ph2 (ike_session_t
*session
, struct ph2handle
*iph2
)
616 plog(LLV_DEBUG2
, LOCATION
, NULL
, "invalid parameters in %s.\n", __FUNCTION__
);
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
) {
632 ike_session_unbindph12_from_ph1 (struct ph1handle
*iph1
)
634 struct ph2handle
*p
, *next
;
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
);
644 ike_session_rebindph12_from_old_ph1_to_new_ph1 (struct ph1handle
*old_iph1
,
645 struct ph1handle
*new_iph1
)
647 struct ph2handle
*p
, *next
;
649 if (old_iph1
== new_iph1
|| !old_iph1
|| !new_iph1
) {
650 plog(LLV_DEBUG2
, LOCATION
, NULL
, "invalid parameters in %s.\n", __FUNCTION__
);
654 if (old_iph1
->parent_session
!= new_iph1
->parent_session
) {
655 plog(LLV_DEBUG2
, LOCATION
, NULL
, "invalid parent sessions in %s.\n", __FUNCTION__
);
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");
665 if (p
->ph1
== new_iph1
) {
666 plog(LLV_ERROR
, LOCATION
, NULL
, "same phase1 in ph1bind replacement in %s.\n",__FUNCTION__
);
668 rebindph12(new_iph1
, p
);
673 ike_session_verify_ph2_parent_session (struct ph2handle
*iph2
)
676 plog(LLV_DEBUG2
, LOCATION
, NULL
, "invalid parameters in %s.\n", __FUNCTION__
);
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
692 ike_session_update_ph1_ph2tree (struct ph1handle
*iph1
)
694 struct ph1handle
*new_iph1
= NULL
;
697 plog(LLV_DEBUG2
, LOCATION
, NULL
, "invalid parameters in %s.\n", __FUNCTION__
);
701 if (iph1
->parent_session
) {
702 new_iph1
= ike_session_get_established_ph1(iph1
->parent_session
);
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
);
711 ike_session_rebindph12_from_old_ph1_to_new_ph1(iph1
, new_iph1
);
714 plog(LLV_DEBUG2
, LOCATION
, NULL
, "invalid parent session in %s.\n", __FUNCTION__
);
720 ike_session_update_ph2_ph1bind (struct ph2handle
*iph2
)
722 struct ph1handle
*iph1
;
725 plog(LLV_DEBUG2
, LOCATION
, NULL
, "invalid parameters in %s.\n", __FUNCTION__
);
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
);
740 ike_session_ikev1_float_ports (struct ph1handle
*iph1
)
742 struct sockaddr
*local
, *remote
;
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
;
749 set_port(local
, extract_port(iph1
->local
));
750 set_port(remote
, extract_port(iph1
->remote
));
751 iph1
->parent_session
->ports_floated
= 1;
753 for (p
= LIST_FIRST(&iph1
->parent_session
->ikev1_state
.ph2tree
); p
; p
= LIST_NEXT(p
, ph2ofsession_chain
)) {
758 set_port(local
, extract_port(iph1
->local
));
759 set_port(remote
, extract_port(iph1
->remote
));
762 plog(LLV_DEBUG2
, LOCATION
, NULL
, "invalid parent session in %s.\n", __FUNCTION__
);
767 ike_session_traffic_cop (void *arg
)
769 ike_session_t
*session
= (__typeof__(session
))arg
;
772 SCHED_KILL(session
->traffic_monitor
.sc_mon
);
773 /* get traffic query from kernel */
774 if (pk_sendget_inbound_sastats(session
) < 0) {
776 plog(LLV_DEBUG2
, LOCATION
, NULL
, "pk_sendget_inbound_sastats failed in %s.\n", __FUNCTION__
);
778 if (pk_sendget_outbound_sastats(session
) < 0) {
780 plog(LLV_DEBUG2
, LOCATION
, NULL
, "pk_sendget_outbound_sastats failed in %s.\n", __FUNCTION__
);
782 session
->traffic_monitor
.sc_mon
= sched_new(session
->traffic_monitor
.interv_mon
,
783 ike_session_traffic_cop
,
787 plog(LLV_DEBUG2
, LOCATION
, NULL
, "invalid parameters in %s.\n", __FUNCTION__
);
792 ike_session_cleanup_idle (void *arg
)
794 ike_session_t
*session
= (ike_session_t
*)arg
;
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
,
803 session
->peer_sent_data_sc_idle
= 0;
804 session
->i_sent_data_sc_idle
= 0;
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
,
815 session
->peer_sent_data_sc_idle
= 0;
816 session
->i_sent_data_sc_idle
= 0;
821 ike_session_cleanup((ike_session_t
*)arg
, ike_session_stopped_by_idle
);
825 ike_session_ph2_established (struct ph2handle
*iph2
)
827 if (!iph2
->parent_session
) {
828 plog(LLV_DEBUG2
, LOCATION
, NULL
, "invalid parameters in %s.\n", __FUNCTION__
);
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
);
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
);
847 // nothing happening to this session
848 iph2
->parent_session
->term_reason
= NULL
;
850 ike_session_update_mode(iph2
);
854 ike_session_cleanup_ph1 (struct ph1handle
*iph1
)
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
);
862 /* send delete information */
863 if (iph1
->status
== PHASE1ST_ESTABLISHED
) {
864 isakmp_info_send_d1(iph1
);
867 isakmp_ph1expire(iph1
);
871 ike_session_cleanup_ph1_stub (void *p
)
874 ike_session_cleanup_ph1((struct ph1handle
*)p
);
878 ike_session_cleanup_other_established_ph1s (ike_session_t
*session
,
879 struct ph1handle
*new_iph1
)
881 struct ph1handle
*p
, *next
;
882 char *local
, *remote
;
884 if (!session
|| !new_iph1
|| session
!= new_iph1
->parent_session
) {
885 plog(LLV_DEBUG2
, LOCATION
, NULL
, "invalid parameters in %s.\n", __FUNCTION__
);
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
);
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).
898 SCHED_KILL(p
->sce_rekey
);
902 local
= racoon_strdup(saddr2str(p
->local
));
903 remote
= racoon_strdup(saddr2str(p
->remote
));
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));
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
);
915 if (p
->side
== INITIATOR
) {
916 /* everyone deletes old outbound SA */
917 p
->sce
= sched_new(5, ike_session_cleanup_ph1_stub
, p
);
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
);
927 ike_session_cleanup_ph2 (struct ph2handle
*iph2
)
929 if (iph2
->status
== PHASE2ST_EXPIRED
) {
933 SCHED_KILL(iph2
->sce
);
935 /* send delete information */
936 if (iph2
->status
== PHASE2ST_ESTABLISHED
) {
937 isakmp_info_send_d2(iph2
);
940 // delete outgoing SAs
941 if (iph2
->approval
) {
944 for (pr
= iph2
->approval
->head
; pr
!= NULL
; pr
= pr
->next
) {
946 pfkey_send_delete(lcconf
->sock_pfkey
,
947 ipsecdoi2pfkey_proto(pr
->proto_id
),
949 iph2
->src
, iph2
->dst
, pr
->spi_p
/* pr->reqid_out */);
961 ike_session_cleanup_ph2_stub (void *p
)
964 ike_session_cleanup_ph2((struct ph2handle
*)p
);
968 ike_session_cleanup_other_established_ph2s (ike_session_t
*session
,
969 struct ph2handle
*new_iph2
)
971 struct ph2handle
*p
, *next
;
973 if (!session
|| !new_iph2
|| session
!= new_iph2
->parent_session
) {
974 plog(LLV_DEBUG2
, LOCATION
, NULL
, "invalid parameters in %s.\n", __FUNCTION__
);
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
);
982 * TODO: currently, most recently established SA wins. Need to revisit to see if
983 * alternative selections is better.
985 if (p
!= new_iph2
&& p
->spid
== new_iph2
->spid
) {
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));
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
);
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
);
1007 ike_session_stopped_by_controller (ike_session_t
*session
,
1011 plog(LLV_DEBUG2
, LOCATION
, NULL
, "invalid parameters in %s.\n", __FUNCTION__
);
1014 if (session
->stop_timestamp
.tv_sec
||
1015 session
->stop_timestamp
.tv_usec
) {
1016 plog(LLV_DEBUG2
, LOCATION
, NULL
, "already stopped %s.\n", __FUNCTION__
);
1019 session
->stopped_by_vpn_controller
= 1;
1020 gettimeofday(&session
->stop_timestamp
, NULL
);
1021 if (!session
->term_reason
) {
1022 session
->term_reason
= reason
;
1027 ike_sessions_stopped_by_controller (struct sockaddr
*remote
,
1031 ike_session_t
*p
= NULL
;
1034 plog(LLV_DEBUG2
, LOCATION
, NULL
, "invalid parameters in %s.\n", __FUNCTION__
);
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
);
1047 ike_session_purge_ph2s_by_ph1 (struct ph1handle
*iph1
)
1049 struct ph2handle
*p
, *next
;
1051 if (!iph1
|| !iph1
->parent_session
) {
1052 plog(LLV_DEBUG2
, LOCATION
, NULL
, "invalid parameters in %s.\n", __FUNCTION__
);
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
);
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));
1068 ike_session_cleanup_ph2(p
);
1073 ike_session_update_ph2_ports (struct ph2handle
*iph2
)
1075 struct sockaddr
*local
;
1076 struct sockaddr
*remote
;
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
;
1082 set_port(iph2
->src
, extract_port(local
));
1083 set_port(iph2
->dst
, extract_port(remote
));
1085 plog(LLV_DEBUG2
, LOCATION
, NULL
, "invalid parent session in %s.\n", __FUNCTION__
);
1090 ike_session_get_sas_for_stats (ike_session_t
*session
,
1093 struct sastat
*stats
,
1094 u_int32_t max_stats
)
1097 struct ph2handle
*iph2
;
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__
);
1105 for (iph2
= LIST_FIRST(&session
->ikev1_state
.ph2tree
); iph2
; iph2
= LIST_NEXT(iph2
, ph2ofsession_chain
)) {
1107 if (iph2
->approval
) {
1110 for (pr
= iph2
->approval
->head
; pr
!= NULL
; pr
= pr
->next
) {
1111 if (pr
->ok
&& pr
->proto_id
== IPSECDOI_PROTO_IPSEC_ESP
) {
1115 if (dir
== IPSEC_DIR_INBOUND
) {
1116 stats
[found
].spi
= pr
->spi
;
1118 stats
[found
].spi
= pr
->spi_p
;
1120 if (++found
== max_stats
) {
1131 ike_session_update_traffic_idle_status (ike_session_t
*session
,
1133 struct sastat
*new_stats
,
1134 u_int32_t max_stats
)
1136 int i
, j
, found
= 0, idle
= 1;
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__
);
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
) {
1150 if (new_stats
[i
].lft_c
.sadb_lifetime_bytes
!= session
->traffic_monitor
.in_last_poll
[j
].lft_c
.sadb_lifetime_bytes
) {
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
) {
1160 if (new_stats
[i
].lft_c
.sadb_lifetime_bytes
!= session
->traffic_monitor
.out_last_poll
[j
].lft_c
.sadb_lifetime_bytes
) {
1165 // new SA.... check for any activity
1167 if (new_stats
[i
].lft_c
.sadb_lifetime_bytes
) {
1168 plog(LLV_DEBUG
, LOCATION
, NULL
, "new SA: dir %d....\n", dir
);
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
;
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;
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
;
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;
1197 ike_session_cleanup (ike_session_t
*session
,
1200 struct ph2handle
*iph2
;
1201 struct ph1handle
*iph1
;
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
);
1211 isakmp_ph2expire(iph2
); // iph2 will go down 1 second later.
1212 ike_session_stopped_by_controller(session
, reason
);
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
);
1220 isakmp_ph1expire(iph1
);
1223 // send ipsecManager a notification
1224 if (reason
== ike_session_stopped_by_idle
) {
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
;
1231 (void)vpncontrol_notify_ike_failed(VPNCTL_NTYPE_IDLE_TIMEOUT
, FROM_LOCAL
, address
, 0, NULL
);
1236 ike_session_has_negoing_ph1 (ike_session_t
*session
)
1238 struct ph1handle
*p
;
1241 plog(LLV_DEBUG2
, LOCATION
, NULL
, "invalid parameters in %s.\n", __FUNCTION__
);
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
) {
1255 ike_session_has_negoing_ph2 (ike_session_t
*session
)
1257 struct ph2handle
*p
;
1260 plog(LLV_DEBUG2
, LOCATION
, NULL
, "invalid parameters in %s.\n", __FUNCTION__
);
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
) {
1274 ike_session_has_established_ph2 (ike_session_t
*session
)
1276 struct ph2handle
*p
;
1279 plog(LLV_DEBUG2
, LOCATION
, NULL
, "invalid parameters in %s.\n", __FUNCTION__
);
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
) {
1293 ike_session_cleanup_ph1s_by_ph2 (struct ph2handle
*iph2
)
1295 struct ph1handle
*iph1
;
1297 if (!iph2
|| !iph2
->parent_session
) {
1298 plog(LLV_DEBUG2
, LOCATION
, NULL
, "invalid parameters in %s.\n", __FUNCTION__
);
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
);
1307 isakmp_ph1expire(iph1
);
1312 ike_session_is_client_ph2_rekey (struct ph2handle
*iph2
)
1314 if (iph2
->parent_session
&&
1315 iph2
->parent_session
->is_client
&&
1317 iph2
->parent_session
->is_cisco_ipsec
) {
1324 ike_session_is_client_ph1_rekey (struct ph1handle
*iph1
)
1326 if (iph1
->parent_session
&&
1327 iph1
->parent_session
->is_client
&&
1329 iph1
->parent_session
->is_cisco_ipsec
) {
1336 ike_session_start_xauth_timer (struct ph1handle
*iph1
)
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
);
1350 ike_session_stop_xauth_timer (struct ph1handle
*iph1
)
1352 if (iph1
->parent_session
) {
1353 SCHED_KILL(iph1
->parent_session
->sc_xauth
);