]> git.saurik.com Git - apple/ipsec.git/blob - ipsec-tools/racoon/ike_session.c
ipsec-93.13.tar.gz
[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 && !p->is_dying) {
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 plog(LLV_ERROR, LOCATION, NULL,
947 "about to cleanup ph2: status %d, seq %d dying %d\n",
948 iph2->status, iph2->seq, iph2->is_dying);
949
950 /* send delete information */
951 if (iph2->status == PHASE2ST_ESTABLISHED) {
952 isakmp_info_send_d2(iph2);
953 }
954
955 // delete outgoing SAs
956 if (iph2->approval) {
957 struct saproto *pr;
958
959 for (pr = iph2->approval->head; pr != NULL; pr = pr->next) {
960 if (pr->ok) {
961 pfkey_send_delete(lcconf->sock_pfkey,
962 ipsecdoi2pfkey_proto(pr->proto_id),
963 IPSEC_MODE_ANY,
964 iph2->src, iph2->dst, pr->spi_p /* pr->reqid_out */);
965 }
966 }
967 }
968
969 delete_spd(iph2);
970 unbindph12(iph2);
971 remph2(iph2);
972 delph2(iph2);
973 }
974
975 void
976 ike_session_cleanup_ph2_stub (void *p)
977 {
978
979 ike_session_cleanup_ph2((struct ph2handle *)p);
980 }
981
982 void
983 ike_session_cleanup_other_established_ph2s (ike_session_t *session,
984 struct ph2handle *new_iph2)
985 {
986 struct ph2handle *p, *next;
987
988 if (!session || !new_iph2 || session != new_iph2->parent_session) {
989 plog(LLV_DEBUG2, LOCATION, NULL, "invalid parameters in %s.\n", __FUNCTION__);
990 return;
991 }
992
993 for (p = LIST_FIRST(&session->ikev1_state.ph2tree); p; p = next) {
994 // take next pointer now, since delete change the underlying ph2tree list
995 next = LIST_NEXT(p, ph2ofsession_chain);
996 /*
997 * TODO: currently, most recently established SA wins. Need to revisit to see if
998 * alternative selections is better.
999 */
1000 if (p != new_iph2 && p->spid == new_iph2->spid && !p->is_dying) {
1001 SCHED_KILL(p->sce);
1002 p->is_dying = 1;
1003
1004 //log deletion
1005 plog(LLV_DEBUG, LOCATION, NULL,
1006 "IPsec-SA needs to be deleted: %s\n",
1007 sadbsecas2str(p->src, p->dst,
1008 p->satype, p->spid, 0));
1009
1010 if (p->side == INITIATOR) {
1011 /* responder sets up timer to delete old inbound SAs... say 5 secs later and flags them as rekeyed */
1012 p->sce = sched_new(3, ike_session_cleanup_ph2_stub, p);
1013 } else {
1014 /* responder sets up timer to delete old inbound SAs... say 5 secs later and flags them as rekeyed */
1015 p->sce = sched_new(5, ike_session_cleanup_ph2_stub, p);
1016 }
1017 }
1018 }
1019 }
1020
1021 void
1022 ike_session_stopped_by_controller (ike_session_t *session,
1023 const char *reason)
1024 {
1025 if (!session) {
1026 plog(LLV_DEBUG2, LOCATION, NULL, "invalid parameters in %s.\n", __FUNCTION__);
1027 return;
1028 }
1029 if (session->stop_timestamp.tv_sec ||
1030 session->stop_timestamp.tv_usec) {
1031 plog(LLV_DEBUG2, LOCATION, NULL, "already stopped %s.\n", __FUNCTION__);
1032 return;
1033 }
1034 session->stopped_by_vpn_controller = 1;
1035 gettimeofday(&session->stop_timestamp, NULL);
1036 if (!session->term_reason) {
1037 session->term_reason = reason;
1038 }
1039 }
1040
1041 void
1042 ike_sessions_stopped_by_controller (struct sockaddr *remote,
1043 int withport,
1044 const char *reason)
1045 {
1046 ike_session_t *p = NULL;
1047
1048 if (!remote) {
1049 plog(LLV_DEBUG2, LOCATION, NULL, "invalid parameters in %s.\n", __FUNCTION__);
1050 return;
1051 }
1052
1053 for (p = LIST_FIRST(&ike_session_tree); p; p = LIST_NEXT(p, chain)) {
1054 if (withport && cmpsaddrstrict(&p->session_id.remote, remote) == 0 ||
1055 !withport && cmpsaddrwop(&p->session_id.remote, remote) == 0) {
1056 ike_session_stopped_by_controller(p, reason);
1057 }
1058 }
1059 }
1060
1061 void
1062 ike_session_purge_ph2s_by_ph1 (struct ph1handle *iph1)
1063 {
1064 struct ph2handle *p, *next;
1065
1066 if (!iph1 || !iph1->parent_session) {
1067 plog(LLV_DEBUG2, LOCATION, NULL, "invalid parameters in %s.\n", __FUNCTION__);
1068 return;
1069 }
1070
1071 for (p = LIST_FIRST(&iph1->parent_session->ikev1_state.ph2tree); p; p = next) {
1072 // take next pointer now, since delete change the underlying ph2tree list
1073 next = LIST_NEXT(p, ph2ofsession_chain);
1074 if (p->is_dying) {
1075 continue;
1076 }
1077 SCHED_KILL(p->sce);
1078 p->is_dying = 1;
1079
1080 //log deletion
1081 plog(LLV_DEBUG, LOCATION, NULL,
1082 "IPsec-SA needs to be purged: %s\n",
1083 sadbsecas2str(p->src, p->dst,
1084 p->satype, p->spid, 0));
1085
1086 ike_session_cleanup_ph2(p);
1087 }
1088 }
1089
1090 void
1091 ike_session_update_ph2_ports (struct ph2handle *iph2)
1092 {
1093 struct sockaddr *local;
1094 struct sockaddr *remote;
1095
1096 if (iph2->parent_session) {
1097 local = (struct sockaddr *)&iph2->parent_session->session_id.local;
1098 remote = (struct sockaddr *)&iph2->parent_session->session_id.remote;
1099
1100 set_port(iph2->src, extract_port(local));
1101 set_port(iph2->dst, extract_port(remote));
1102 } else {
1103 plog(LLV_DEBUG2, LOCATION, NULL, "invalid parent session in %s.\n", __FUNCTION__);
1104 }
1105 }
1106
1107 u_int32_t
1108 ike_session_get_sas_for_stats (ike_session_t *session,
1109 u_int8_t dir,
1110 u_int32_t *seq,
1111 struct sastat *stats,
1112 u_int32_t max_stats)
1113 {
1114 int found = 0;
1115 struct ph2handle *iph2;
1116
1117 if (!session || !seq || !stats || !max_stats || (dir != IPSEC_DIR_INBOUND && dir != IPSEC_DIR_OUTBOUND)) {
1118 plog(LLV_DEBUG2, LOCATION, NULL, "invalid args in %s.\n", __FUNCTION__);
1119 return found;
1120 }
1121
1122 *seq = 0;
1123 for (iph2 = LIST_FIRST(&session->ikev1_state.ph2tree); iph2; iph2 = LIST_NEXT(iph2, ph2ofsession_chain)) {
1124
1125 if (iph2->approval) {
1126 struct saproto *pr;
1127
1128 for (pr = iph2->approval->head; pr != NULL; pr = pr->next) {
1129 if (pr->ok && pr->proto_id == IPSECDOI_PROTO_IPSEC_ESP) {
1130 if (!*seq) {
1131 *seq = iph2->seq;
1132 }
1133 if (dir == IPSEC_DIR_INBOUND) {
1134 stats[found].spi = pr->spi;
1135 } else {
1136 stats[found].spi = pr->spi_p;
1137 }
1138 if (++found == max_stats) {
1139 return found;
1140 }
1141 }
1142 }
1143 }
1144 }
1145 return found;
1146 }
1147
1148 void
1149 ike_session_update_traffic_idle_status (ike_session_t *session,
1150 u_int32_t dir,
1151 struct sastat *new_stats,
1152 u_int32_t max_stats)
1153 {
1154 int i, j, found = 0, idle = 1;
1155
1156 if (!session || !new_stats || (dir != IPSEC_DIR_INBOUND && dir != IPSEC_DIR_OUTBOUND)) {
1157 plog(LLV_DEBUG2, LOCATION, NULL, "invalid args in %s.\n", __FUNCTION__);
1158 return;
1159 }
1160
1161 if (!session->established || session->stopped_by_vpn_controller || session->stop_timestamp.tv_sec || session->stop_timestamp.tv_usec) {
1162 plog(LLV_DEBUG2, LOCATION, NULL, "dropping update on invalid session.\n", __FUNCTION__);
1163 return;
1164 }
1165
1166 for (i = 0; i < max_stats; i++) {
1167 if (dir == IPSEC_DIR_INBOUND) {
1168 for (j = 0; j < session->traffic_monitor.num_in_last_poll; j++) {
1169 if (new_stats[i].spi != session->traffic_monitor.in_last_poll[j].spi) {
1170 continue;
1171 }
1172 found = 1;
1173 if (new_stats[i].lft_c.sadb_lifetime_bytes != session->traffic_monitor.in_last_poll[j].lft_c.sadb_lifetime_bytes) {
1174 idle = 0;
1175 }
1176 }
1177 } else {
1178 for (j = 0; j < session->traffic_monitor.num_out_last_poll; j++) {
1179 if (new_stats[i].spi != session->traffic_monitor.out_last_poll[j].spi) {
1180 continue;
1181 }
1182 found = 1;
1183 if (new_stats[i].lft_c.sadb_lifetime_bytes != session->traffic_monitor.out_last_poll[j].lft_c.sadb_lifetime_bytes) {
1184 idle = 0;
1185 }
1186 }
1187 }
1188 // new SA.... check for any activity
1189 if (!found) {
1190 if (new_stats[i].lft_c.sadb_lifetime_bytes) {
1191 plog(LLV_DEBUG, LOCATION, NULL, "new SA: dir %d....\n", dir);
1192 idle = 0;
1193 }
1194 }
1195 }
1196 if (dir == IPSEC_DIR_INBOUND) {
1197 // overwrite old stats
1198 bzero(session->traffic_monitor.in_last_poll, sizeof(session->traffic_monitor.in_last_poll));
1199 bcopy(new_stats, session->traffic_monitor.in_last_poll, (max_stats * sizeof(*new_stats)));
1200 session->traffic_monitor.num_in_last_poll = max_stats;
1201 if (!idle) {
1202 plog(LLV_DEBUG, LOCATION, NULL, "peer sent data....\n");
1203 session->peer_sent_data_sc_dpd = 1;
1204 session->peer_sent_data_sc_idle = 1;
1205 }
1206 } else {
1207 // overwrite old stats
1208 bzero(session->traffic_monitor.out_last_poll, sizeof(session->traffic_monitor.out_last_poll));
1209 bcopy(new_stats, session->traffic_monitor.out_last_poll, (max_stats * sizeof(*new_stats)));
1210 session->traffic_monitor.num_out_last_poll = max_stats;
1211 if (!idle) {
1212 plog(LLV_DEBUG, LOCATION, NULL, "i sent data....\n");
1213 session->i_sent_data_sc_dpd = 1;
1214 session->i_sent_data_sc_idle = 1;
1215 }
1216 }
1217 if (!idle)
1218 session->last_time_data_sc_detected = time(NULL);
1219
1220 ike_session_monitor_idle(session);
1221 }
1222
1223 void
1224 ike_session_cleanup (ike_session_t *session,
1225 const char *reason)
1226 {
1227 struct ph2handle *iph2;
1228 struct ph1handle *iph1;
1229
1230 if (!session)
1231 return;
1232
1233 SCHED_KILL(session->traffic_monitor.sc_idle);
1234 // do ph2's first... we need the ph1s for notifications
1235 for (iph2 = LIST_FIRST(&session->ikev1_state.ph2tree); iph2; iph2 = LIST_NEXT(iph2, ph2ofsession_chain)) {
1236 if (iph2->status == PHASE2ST_ESTABLISHED) {
1237 isakmp_info_send_d2(iph2);
1238 }
1239 isakmp_ph2expire(iph2); // iph2 will go down 1 second later.
1240 ike_session_stopped_by_controller(session, reason);
1241 }
1242
1243 // do the ph1s last.
1244 for (iph1 = LIST_FIRST(&session->ikev1_state.ph1tree); iph1; iph1 = LIST_NEXT(iph1, ph1ofsession_chain)) {
1245 if (iph1->status == PHASE1ST_ESTABLISHED) {
1246 isakmp_info_send_d1(iph1);
1247 }
1248 isakmp_ph1expire(iph1);
1249 }
1250
1251 // send ipsecManager a notification
1252 if (reason == ike_session_stopped_by_idle) {
1253 u_int32_t address;
1254 if (((struct sockaddr *)&session->session_id.remote)->sa_family == AF_INET) {
1255 address = ((struct sockaddr_in *)&session->session_id.remote)->sin_addr.s_addr;
1256 } else {
1257 address = 0;
1258 }
1259 (void)vpncontrol_notify_ike_failed(VPNCTL_NTYPE_IDLE_TIMEOUT, FROM_LOCAL, address, 0, NULL);
1260 }
1261 }
1262
1263 int
1264 ike_session_has_negoing_ph1 (ike_session_t *session)
1265 {
1266 struct ph1handle *p;
1267
1268 if (!session) {
1269 plog(LLV_DEBUG2, LOCATION, NULL, "invalid parameters in %s.\n", __FUNCTION__);
1270 return 0;
1271 }
1272
1273 for (p = LIST_FIRST(&session->ikev1_state.ph1tree); p; p = LIST_NEXT(p, ph1ofsession_chain)) {
1274 if (!p->is_dying && p->status >= PHASE1ST_START && p->status <= PHASE1ST_ESTABLISHED) {
1275 return 1;
1276 }
1277 }
1278
1279 return 0;
1280 }
1281
1282 int
1283 ike_session_has_negoing_ph2 (ike_session_t *session)
1284 {
1285 struct ph2handle *p;
1286
1287 if (!session) {
1288 plog(LLV_DEBUG2, LOCATION, NULL, "invalid parameters in %s.\n", __FUNCTION__);
1289 return 0;
1290 }
1291
1292 for (p = LIST_FIRST(&session->ikev1_state.ph2tree); p; p = LIST_NEXT(p, ph2ofsession_chain)) {
1293 if (!p->is_dying && p->status >= PHASE2ST_START && p->status <= PHASE2ST_ESTABLISHED) {
1294 return 1;
1295 }
1296 }
1297
1298 return 0;
1299 }
1300
1301 int
1302 ike_session_has_established_ph2 (ike_session_t *session)
1303 {
1304 struct ph2handle *p;
1305
1306 if (!session) {
1307 plog(LLV_DEBUG2, LOCATION, NULL, "invalid parameters in %s.\n", __FUNCTION__);
1308 return 0;
1309 }
1310
1311 for (p = LIST_FIRST(&session->ikev1_state.ph2tree); p; p = LIST_NEXT(p, ph2ofsession_chain)) {
1312 if (!p->is_dying && p->status == PHASE2ST_ESTABLISHED) {
1313 return 1;
1314 }
1315 }
1316
1317 return 0;
1318 }
1319
1320 void
1321 ike_session_cleanup_ph1s_by_ph2 (struct ph2handle *iph2)
1322 {
1323 struct ph1handle *iph1;
1324
1325 if (!iph2 || !iph2->parent_session) {
1326 plog(LLV_DEBUG2, LOCATION, NULL, "invalid parameters in %s.\n", __FUNCTION__);
1327 return;
1328 }
1329
1330 // phase1 is no longer useful
1331 for (iph1 = LIST_FIRST(&iph2->parent_session->ikev1_state.ph1tree); iph1; iph1 = LIST_NEXT(iph1, ph1ofsession_chain)) {
1332 if (iph1->status == PHASE1ST_ESTABLISHED) {
1333 isakmp_info_send_d1(iph1);
1334 }
1335 isakmp_ph1expire(iph1);
1336 }
1337 }
1338
1339 int
1340 ike_session_is_client_ph2_rekey (struct ph2handle *iph2)
1341 {
1342 if (iph2->parent_session &&
1343 iph2->parent_session->is_client &&
1344 iph2->is_rekey &&
1345 iph2->parent_session->is_cisco_ipsec) {
1346 return 1;
1347 }
1348 return 0;
1349 }
1350
1351 int
1352 ike_session_is_client_ph1_rekey (struct ph1handle *iph1)
1353 {
1354 if (iph1->parent_session &&
1355 iph1->parent_session->is_client &&
1356 iph1->is_rekey &&
1357 iph1->parent_session->is_cisco_ipsec) {
1358 return 1;
1359 }
1360 return 0;
1361 }
1362
1363 void
1364 ike_session_start_xauth_timer (struct ph1handle *iph1)
1365 {
1366 // if there are no more established ph2s, start a timer to teardown the session
1367 if (iph1->parent_session &&
1368 iph1->parent_session->is_client &&
1369 iph1->parent_session->is_cisco_ipsec &&
1370 !iph1->parent_session->sc_xauth) {
1371 iph1->parent_session->sc_xauth = sched_new(300 /* 5 mins */,
1372 ike_session_cleanup_xauth_timeout,
1373 iph1->parent_session);
1374 }
1375 }
1376
1377 void
1378 ike_session_stop_xauth_timer (struct ph1handle *iph1)
1379 {
1380 if (iph1->parent_session) {
1381 SCHED_KILL(iph1->parent_session->sc_xauth);
1382 }
1383 }
1384
1385 static int
1386 ike_session_is_id_ipany (vchar_t *ext_id)
1387 {
1388 struct id {
1389 u_int8_t type; /* ID Type */
1390 u_int8_t proto_id; /* Protocol ID */
1391 u_int16_t port; /* Port */
1392 u_int32_t addr; /* IPv4 address */
1393 u_int32_t mask;
1394 } *id_ptr;
1395
1396 /* ignore protocol and port */
1397 id_ptr = (struct id *)ext_id->v;
1398 if (id_ptr->type == IPSECDOI_ID_IPV4_ADDR &&
1399 id_ptr->addr == 0) {
1400 return 1;
1401 } else if (id_ptr->type == IPSECDOI_ID_IPV4_ADDR_SUBNET &&
1402 id_ptr->mask == 0 &&
1403 id_ptr->addr == 0) {
1404 return 1;
1405 }
1406 plog(LLV_DEBUG2, LOCATION, NULL, "not ipany_ids in %s: type %d, addr %x, mask %x.\n",
1407 __FUNCTION__, id_ptr->type, id_ptr->addr, id_ptr->mask);
1408 return 0;
1409 }
1410
1411 static int
1412 ike_session_is_id_portany (vchar_t *ext_id)
1413 {
1414 struct id {
1415 u_int8_t type; /* ID Type */
1416 u_int8_t proto_id; /* Protocol ID */
1417 u_int16_t port; /* Port */
1418 u_int32_t addr; /* IPv4 address */
1419 u_int32_t mask;
1420 } *id_ptr;
1421
1422 /* ignore addr */
1423 id_ptr = (struct id *)ext_id->v;
1424 if (id_ptr->type == IPSECDOI_ID_IPV4_ADDR &&
1425 id_ptr->port == 0) {
1426 return 1;
1427 }
1428 plog(LLV_DEBUG2, LOCATION, NULL, "not portany_ids in %s: type %d, port %x.\n",
1429 __FUNCTION__, id_ptr->type, id_ptr->port);
1430 return 0;
1431 }
1432
1433 static void
1434 ike_session_set_id_portany (vchar_t *ext_id)
1435 {
1436 struct id {
1437 u_int8_t type; /* ID Type */
1438 u_int8_t proto_id; /* Protocol ID */
1439 u_int16_t port; /* Port */
1440 u_int32_t addr; /* IPv4 address */
1441 u_int32_t mask;
1442 } *id_ptr;
1443
1444 /* ignore addr */
1445 id_ptr = (struct id *)ext_id->v;
1446 if (id_ptr->type == IPSECDOI_ID_IPV4_ADDR) {
1447 id_ptr->port = 0;
1448 return;
1449 }
1450 }
1451
1452 static int
1453 ike_session_cmp_ph2_ids_ipany (vchar_t *ext_id,
1454 vchar_t *ext_id_p)
1455 {
1456 if (ike_session_is_id_ipany(ext_id) &&
1457 ike_session_is_id_ipany(ext_id_p)) {
1458 return 1;
1459 }
1460 return 0;
1461 }
1462
1463 /*
1464 * ipsec rekeys for l2tp-over-ipsec fail particularly when client is behind nat because the client's configs and policies don't
1465 * match the server's view of the client's address and port.
1466 * servers behave differently when using this address-port info to generate ids during phase2 rekeys, so try to match the incoming id to
1467 * a variety of info saved in the older phase2.
1468 */
1469 int
1470 ike_session_cmp_ph2_ids (struct ph2handle *iph2,
1471 struct ph2handle *older_ph2)
1472 {
1473 vchar_t *portany_id = NULL;
1474 vchar_t *portany_id_p = NULL;
1475
1476 if (iph2->id && older_ph2->id &&
1477 iph2->id->l == older_ph2->id->l &&
1478 memcmp(iph2->id->v, older_ph2->id->v, iph2->id->l) == 0 &&
1479 iph2->id_p && older_ph2->id_p &&
1480 iph2->id_p->l == older_ph2->id_p->l &&
1481 memcmp(iph2->id_p->v, older_ph2->id_p->v, iph2->id_p->l) == 0) {
1482 return 0;
1483 }
1484 if (iph2->ext_nat_id && older_ph2->ext_nat_id &&
1485 iph2->ext_nat_id->l == older_ph2->ext_nat_id->l &&
1486 memcmp(iph2->ext_nat_id->v, older_ph2->ext_nat_id->v, iph2->ext_nat_id->l) == 0 &&
1487 iph2->ext_nat_id_p && older_ph2->ext_nat_id_p &&
1488 iph2->ext_nat_id_p->l == older_ph2->ext_nat_id_p->l &&
1489 memcmp(iph2->ext_nat_id_p->v, older_ph2->ext_nat_id_p->v, iph2->ext_nat_id_p->l) == 0) {
1490 return 0;
1491 }
1492 if (iph2->id && older_ph2->ext_nat_id &&
1493 iph2->id->l == older_ph2->ext_nat_id->l &&
1494 memcmp(iph2->id->v, older_ph2->ext_nat_id->v, iph2->id->l) == 0 &&
1495 iph2->id_p && older_ph2->ext_nat_id_p &&
1496 iph2->id_p->l == older_ph2->ext_nat_id_p->l &&
1497 memcmp(iph2->id_p->v, older_ph2->ext_nat_id_p->v, iph2->id_p->l) == 0) {
1498 return 0;
1499 }
1500 if (iph2->id && older_ph2->ext_nat_id &&
1501 iph2->id->l == older_ph2->ext_nat_id->l &&
1502 memcmp(iph2->id->v, older_ph2->ext_nat_id->v, iph2->id->l) == 0 &&
1503 iph2->id_p && older_ph2->id_p &&
1504 iph2->id_p->l == older_ph2->id_p->l &&
1505 memcmp(iph2->id_p->v, older_ph2->id_p->v, iph2->id_p->l) == 0) {
1506 return 0;
1507 }
1508 if (iph2->id && older_ph2->id &&
1509 iph2->id->l == older_ph2->id->l &&
1510 memcmp(iph2->id->v, older_ph2->id->v, iph2->id->l) == 0 &&
1511 iph2->id_p && older_ph2->ext_nat_id_p &&
1512 iph2->id_p->l == older_ph2->ext_nat_id_p->l &&
1513 memcmp(iph2->id_p->v, older_ph2->ext_nat_id_p->v, iph2->id_p->l) == 0) {
1514 return 0;
1515 }
1516
1517 /* check if the external id has a wildcard port and compare ids accordingly */
1518 if ((older_ph2->ext_nat_id && ike_session_is_id_portany(older_ph2->ext_nat_id)) ||
1519 (older_ph2->ext_nat_id_p && ike_session_is_id_portany(older_ph2->ext_nat_id_p))) {
1520 // try ignoring ports in iph2->id and iph2->id
1521 if (iph2->id && (portany_id = vdup(iph2->id))) {
1522 ike_session_set_id_portany(portany_id);
1523 }
1524 if (iph2->id_p && (portany_id_p = vdup(iph2->id_p))) {
1525 ike_session_set_id_portany(portany_id_p);
1526 }
1527 if (portany_id && older_ph2->ext_nat_id &&
1528 portany_id->l == older_ph2->ext_nat_id->l &&
1529 memcmp(portany_id->v, older_ph2->ext_nat_id->v, portany_id->l) == 0 &&
1530 portany_id_p && older_ph2->ext_nat_id_p &&
1531 portany_id_p->l == older_ph2->ext_nat_id_p->l &&
1532 memcmp(portany_id_p->v, older_ph2->ext_nat_id_p->v, portany_id_p->l) == 0) {
1533 if (portany_id) {
1534 vfree(portany_id);
1535 }
1536 if (portany_id_p) {
1537 vfree(portany_id_p);
1538 }
1539 return 0;
1540 }
1541 if (iph2->id && older_ph2->ext_nat_id &&
1542 iph2->id->l == older_ph2->ext_nat_id->l &&
1543 memcmp(portany_id->v, older_ph2->ext_nat_id->v, portany_id->l) == 0 &&
1544 iph2->id_p && older_ph2->id_p &&
1545 iph2->id_p->l == older_ph2->id_p->l &&
1546 memcmp(iph2->id_p->v, older_ph2->id_p->v, iph2->id_p->l) == 0) {
1547 if (portany_id) {
1548 vfree(portany_id);
1549 }
1550 if (portany_id_p) {
1551 vfree(portany_id_p);
1552 }
1553 return 0;
1554 }
1555 if (iph2->id && older_ph2->id &&
1556 iph2->id->l == older_ph2->id->l &&
1557 memcmp(iph2->id->v, older_ph2->id->v, iph2->id->l) == 0 &&
1558 iph2->id_p && older_ph2->ext_nat_id_p &&
1559 iph2->id_p->l == older_ph2->ext_nat_id_p->l &&
1560 memcmp(portany_id_p->v, older_ph2->ext_nat_id_p->v, portany_id_p->l) == 0) {
1561 if (portany_id) {
1562 vfree(portany_id);
1563 }
1564 if (portany_id_p) {
1565 vfree(portany_id_p);
1566 }
1567 return 0;
1568 }
1569 if (portany_id) {
1570 vfree(portany_id);
1571 }
1572 if (portany_id_p) {
1573 vfree(portany_id_p);
1574 }
1575 }
1576 return -1;
1577 }
1578
1579 int
1580 ike_session_get_sainfo_r (struct ph2handle *iph2)
1581 {
1582 if (iph2->parent_session &&
1583 iph2->parent_session->is_client &&
1584 iph2->id && iph2->id_p) {
1585 struct ph2handle *p;
1586 int ipany_ids = ike_session_cmp_ph2_ids_ipany(iph2->id, iph2->id_p);
1587 plog(LLV_DEBUG2, LOCATION, NULL, "ipany_ids %d in %s.\n", ipany_ids, __FUNCTION__);
1588
1589 for (p = LIST_FIRST(&iph2->parent_session->ikev1_state.ph2tree); p; p = LIST_NEXT(p, ph2ofsession_chain)) {
1590 if (iph2 != p && !p->is_dying && p->status >= PHASE2ST_ESTABLISHED &&
1591 p->sainfo && !p->sainfo->to_delete && !p->sainfo->to_remove) {
1592 plog(LLV_DEBUG2, LOCATION, NULL, "candidate ph2 found in %s.\n", __FUNCTION__);
1593 if (ipany_ids ||
1594 ike_session_cmp_ph2_ids(iph2, p) == 0) {
1595 plog(LLV_DEBUG2, LOCATION, NULL, "candidate ph2 matched in %s.\n", __FUNCTION__);
1596 iph2->sainfo = p->sainfo;
1597 if (p->ext_nat_id) {
1598 if (iph2->ext_nat_id) {
1599 vfree(iph2->ext_nat_id);
1600 }
1601 iph2->ext_nat_id = vdup(p->ext_nat_id);
1602 }
1603 if (p->ext_nat_id_p) {
1604 if (iph2->ext_nat_id_p) {
1605 vfree(iph2->ext_nat_id_p);
1606 }
1607 iph2->ext_nat_id_p = vdup(p->ext_nat_id_p);
1608 }
1609 return 0;
1610 }
1611 }
1612 }
1613 }
1614 return -1;
1615 }
1616
1617 int
1618 ike_session_get_proposal_r (struct ph2handle *iph2)
1619 {
1620 if (iph2->parent_session &&
1621 iph2->parent_session->is_client &&
1622 iph2->id && iph2->id_p) {
1623 struct ph2handle *p;
1624 int ipany_ids = ike_session_cmp_ph2_ids_ipany(iph2->id, iph2->id_p);
1625 plog(LLV_DEBUG2, LOCATION, NULL, "ipany_ids %d in %s.\n", ipany_ids, __FUNCTION__);
1626
1627 for (p = LIST_FIRST(&iph2->parent_session->ikev1_state.ph2tree); p; p = LIST_NEXT(p, ph2ofsession_chain)) {
1628 if (iph2 != p && !p->is_dying && p->status >= PHASE2ST_ESTABLISHED &&
1629 p->approval) {
1630 plog(LLV_DEBUG2, LOCATION, NULL, "candidate ph2 found in %s.\n", __FUNCTION__);
1631 if (ipany_ids ||
1632 ike_session_cmp_ph2_ids(iph2, p) == 0) {
1633 plog(LLV_DEBUG2, LOCATION, NULL, "candidate ph2 matched in %s.\n", __FUNCTION__);
1634 iph2->proposal = dupsaprop(p->approval, 1);
1635 return 0;
1636 }
1637 }
1638 }
1639 }
1640 return -1;
1641 }
1642
1643 void
1644 ike_session_update_natt_version (struct ph1handle *iph1)
1645 {
1646 if (iph1->parent_session) {
1647 if (iph1->natt_options) {
1648 iph1->parent_session->natt_version = iph1->natt_options->version;
1649 } else {
1650 iph1->parent_session->natt_version = 0;
1651 }
1652 }
1653 }
1654
1655 int
1656 ike_session_get_natt_version (struct ph1handle *iph1)
1657 {
1658 if (iph1->parent_session) {
1659 return(iph1->parent_session->natt_version);
1660 }
1661 return 0;
1662 }
1663
1664 int
1665 ike_session_drop_rekey (ike_session_t *session)
1666 {
1667 if (session) {
1668 // drop if btmm session is idle) {
1669 if (session->is_btmm_ipsec &&
1670 session->last_time_data_sc_detected &&
1671 session->traffic_monitor.interv_mon &&
1672 session->traffic_monitor.interv_idle) {
1673 time_t now = time(NULL);
1674
1675 if ((now - session->last_time_data_sc_detected) > (session->traffic_monitor.interv_mon << 1)) {
1676 plog(LLV_DEBUG2, LOCATION, NULL, "session is idle: drop rekey.\n");
1677 return 1;
1678 }
1679 }
1680 }
1681 return 0;
1682 }
1683
1684 void
1685 ike_session_ph2_retransmits (struct ph2handle *iph2)
1686 {
1687 int num_retransmits;
1688
1689 if (!iph2->is_dying &&
1690 iph2->is_rekey &&
1691 iph2->ph1 &&
1692 iph2->ph1->sce_rekey && !iph2->ph1->sce_rekey->dead &&
1693 iph2->parent_session &&
1694 !iph2->parent_session->is_cisco_ipsec && /* not for Cisco */
1695 iph2->parent_session->is_client) {
1696 num_retransmits = iph2->ph1->rmconf->retry_counter - iph2->retry_counter;
1697 if (num_retransmits == 3) {
1698 /*
1699 * phase2 negotiation is stalling on retransmits, inspite of a valid ph1.
1700 * one of the following is possible:
1701 * - (0) severe packet loss.
1702 * - (1) the peer is dead.
1703 * - (2) the peer is out of sync hence dropping this phase2 rekey (and perhaps responding with insecure
1704 * invalid-cookie notifications... but those are untrusted and so we can't rekey phase1 off that)
1705 * (2.1) the peer rebooted (or process restarted) and is now alive.
1706 * (2.2) the peer has deleted phase1 without notifying us (or the notification got dropped somehow).
1707 * (2.3) the peer has a policy/bug stopping this phase2 rekey
1708 *
1709 * in all these cases, one sure way to know is to trigger a phase1 rekey early.
1710 */
1711 plog(LLV_DEBUG2, LOCATION, NULL, "many phase2 retransmits: try phase1 rekey and this phase2 to quit earlier.\n");
1712 isakmp_ph1rekeyexpire(iph2->ph1, TRUE);
1713 iph2->retry_counter = 0;
1714 }
1715 }
1716 }