]> git.ipfire.org Git - thirdparty/strongswan.git/blame - src/libcharon/sa/trap_manager.c
github: Use tpm2-tss 3.2.3 for tests
[thirdparty/strongswan.git] / src / libcharon / sa / trap_manager.c
CommitLineData
eb8ed130 1/*
ca213e19 2 * Copyright (C) 2011-2017 Tobias Brunner
eb8ed130 3 * Copyright (C) 2009 Martin Willi
19ef2aec
TB
4 *
5 * Copyright (C) secunet Security Networks AG
eb8ed130
MW
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 * for more details.
eb8ed130
MW
16 */
17
18#include "trap_manager.h"
19
20#include <daemon.h>
a229bdce 21#include <threading/mutex.h>
eba64cef 22#include <threading/rwlock.h>
12b3cdba 23#include <threading/rwlock_condvar.h>
12642a68 24#include <collections/linked_list.h>
eb8ed130 25
12b3cdba
TB
26#define INSTALL_DISABLED ((u_int)~0)
27
eb8ed130 28typedef struct private_trap_manager_t private_trap_manager_t;
9d737ecf
MW
29typedef struct trap_listener_t trap_listener_t;
30
31/**
32 * listener to track acquires
33 */
34struct trap_listener_t {
7daf5226 35
9d737ecf
MW
36 /**
37 * Implements listener interface
38 */
39 listener_t listener;
7daf5226 40
9d737ecf
MW
41 /**
42 * points to trap_manager
43 */
44 private_trap_manager_t *traps;
45};
eb8ed130
MW
46
47/**
48 * Private data of an trap_manager_t object.
49 */
50struct private_trap_manager_t {
7daf5226 51
eb8ed130
MW
52 /**
53 * Public trap_manager_t interface.
54 */
55 trap_manager_t public;
7daf5226 56
eb8ed130
MW
57 /**
58 * Installed traps, as entry_t
59 */
60 linked_list_t *traps;
7daf5226 61
eb8ed130 62 /**
fcb06fdb 63 * read write lock for traps list
eb8ed130 64 */
fcb06fdb 65 rwlock_t *lock;
7daf5226 66
9d737ecf
MW
67 /**
68 * listener to track acquiring IKE_SAs
69 */
70 trap_listener_t listener;
7fa03b30 71
a229bdce
TB
72 /**
73 * list of acquires we currently handle
74 */
75 linked_list_t *acquires;
76
77 /**
78 * mutex for list of acquires
79 */
80 mutex_t *mutex;
81
12b3cdba
TB
82 /**
83 * number of threads currently installing trap policies, or INSTALL_DISABLED
84 */
85 u_int installing;
86
87 /**
88 * condvar to signal trap policy installation
89 */
90 rwlock_condvar_t *condvar;
91
7fa03b30
TB
92 /**
93 * Whether to ignore traffic selectors from acquires
94 */
95 bool ignore_acquire_ts;
eb8ed130
MW
96};
97
98/**
99 * A installed trap entry
100 */
101typedef struct {
bb492d80
TB
102 /** name of the trapped CHILD_SA */
103 char *name;
eb8ed130
MW
104 /** ref to peer_cfg to initiate */
105 peer_cfg_t *peer_cfg;
a229bdce 106 /** ref to instantiated CHILD_SA (i.e the trap policy) */
eb8ed130 107 child_sa_t *child_sa;
301a0bad
TB
108 /** TRUE in case of wildcard Transport Mode SA */
109 bool wildcard;
3c65cf64
TB
110 /** TRUE for CHILD_SAs that are externally managed */
111 bool external;
a229bdce
TB
112} entry_t;
113
114/**
115 * A handled acquire
116 */
117typedef struct {
9d737ecf 118 /** pending IKE_SA connecting upon acquire */
fc726f13 119 ike_sa_t *ike_sa;
a229bdce 120 /** reqid of pending trap policy */
b12c53ce 121 uint32_t reqid;
301a0bad
TB
122 /** destination address (wildcard case) */
123 host_t *dst;
0a673794
TB
124 /** security label, if any */
125 sec_label_t *label;
a229bdce 126} acquire_t;
eb8ed130
MW
127
128/**
129 * actually uninstall and destroy an installed entry
130 */
a229bdce
TB
131static void destroy_entry(entry_t *this)
132{
3c65cf64
TB
133 if (!this->external)
134 {
135 this->child_sa->destroy(this->child_sa);
136 }
a229bdce
TB
137 this->peer_cfg->destroy(this->peer_cfg);
138 free(this->name);
139 free(this);
140}
141
142/**
143 * destroy a cached acquire entry
144 */
145static void destroy_acquire(acquire_t *this)
eb8ed130 146{
301a0bad 147 DESTROY_IF(this->dst);
0a673794 148 DESTROY_IF(this->label);
a229bdce
TB
149 free(this);
150}
151
2e4d110d
TB
152CALLBACK(acquire_by_reqid, bool,
153 acquire_t *this, va_list args)
a229bdce 154{
2e4d110d 155 uint32_t reqid;
0a673794 156 sec_label_t *label;
2e4d110d 157
0a673794
TB
158 VA_ARGS_VGET(args, reqid, label);
159 return this->reqid == reqid && sec_labels_equal(this->label, label);
eb8ed130
MW
160}
161
2e4d110d
TB
162CALLBACK(acquire_by_dst, bool,
163 acquire_t *this, va_list args)
301a0bad 164{
2e4d110d
TB
165 host_t *dst;
166
167 VA_ARGS_VGET(args, dst);
301a0bad
TB
168 return this->dst && this->dst->ip_equals(this->dst, dst);
169}
170
1a822642
TB
171/**
172 * Check if any remote TS are dynamic
173 */
174static bool dynamic_remote_ts(child_cfg_t *child)
175{
176 enumerator_t *enumerator;
177 linked_list_t *other_ts;
178 traffic_selector_t *ts;
179 bool found = FALSE;
180
84cdfbc9 181 other_ts = child->get_traffic_selectors(child, FALSE, NULL, NULL, FALSE);
1a822642
TB
182 enumerator = other_ts->create_enumerator(other_ts);
183 while (enumerator->enumerate(enumerator, &ts))
184 {
185 if (ts->is_dynamic(ts))
186 {
187 found = TRUE;
188 break;
189 }
190 }
191 enumerator->destroy(enumerator);
192 other_ts->destroy_offset(other_ts, offsetof(traffic_selector_t, destroy));
193 return found;
194}
195
3c65cf64
TB
196/**
197 * Install the given trap
198 */
199static status_t install_trap(child_sa_t *child_sa, linked_list_t *local,
200 linked_list_t *remote)
201{
202 linked_list_t *my_ts, *other_ts, *proposals;
203 proposal_t *proposal;
204 child_cfg_t *child;
205 protocol_id_t proto = PROTO_ESP;
206
207 child = child_sa->get_config(child_sa);
208
209 my_ts = child->get_traffic_selectors(child, TRUE, NULL, local, FALSE);
210 other_ts = child->get_traffic_selectors(child, FALSE, NULL, remote, FALSE);
211
212 /* we don't know the finally negotiated protocol (ESP|AH), we install
213 * the SA with the protocol of the first proposal */
214 proposals = child->get_proposals(child, TRUE);
215 if (proposals->get_first(proposals, (void**)&proposal) == SUCCESS)
216 {
217 proto = proposal->get_protocol(proposal);
218 }
219 proposals->destroy_offset(proposals, offsetof(proposal_t, destroy));
220
221 child_sa->set_protocol(child_sa, proto);
222 child_sa->set_mode(child_sa, child->get_mode(child));
223
224 child_sa->set_policies(child_sa, my_ts, other_ts);
225 my_ts->destroy_offset(my_ts, offsetof(traffic_selector_t, destroy));
226 other_ts->destroy_offset(other_ts, offsetof(traffic_selector_t, destroy));
227
228 return child_sa->install_policies(child_sa);
229}
230
24fa1bb0
TB
231METHOD(trap_manager_t, install, bool,
232 private_trap_manager_t *this, peer_cfg_t *peer, child_cfg_t *child)
eb8ed130 233{
21037942 234 entry_t *entry, *found = NULL;
eb8ed130
MW
235 ike_cfg_t *ike_cfg;
236 child_sa_t *child_sa;
237 host_t *me, *other;
3c65cf64 238 linked_list_t *local, *remote;
eb8ed130 239 enumerator_t *enumerator;
eb8ed130 240 status_t status;
24fa1bb0 241 bool result = FALSE, wildcard = FALSE;
7daf5226 242
eb8ed130
MW
243 /* try to resolve addresses */
244 ike_cfg = peer->get_ike_cfg(peer);
7446fa28 245 other = ike_cfg->resolve_other(ike_cfg, AF_UNSPEC);
301a0bad
TB
246 if (other && other->is_anyaddr(other) &&
247 child->get_mode(child) == MODE_TRANSPORT)
248 {
249 /* allow wildcard for Transport Mode SAs */
250 me = host_create_any(other->get_family(other));
251 wildcard = TRUE;
252 }
1a822642 253 else if (other && other->is_anyaddr(other))
eb8ed130 254 {
1a822642 255 other->destroy(other);
eb8ed130 256 DBG1(DBG_CFG, "installing trap failed, remote address unknown");
24fa1bb0 257 return FALSE;
eb8ed130 258 }
301a0bad 259 else
1a822642
TB
260 { /* depending on the traffic selectors we don't really need a remote
261 * host yet, but we might fail later if no IP can be resolved */
262 if (!other && dynamic_remote_ts(child))
263 { /* with dynamic TS we do need a host, otherwise 0.0.0.0/0 is used,
264 * which is probably not what users expect*/
265 DBG1(DBG_CFG, "installing trap failed, remote address unknown with "
266 "dynamic traffic selector");
24fa1bb0 267 return FALSE;
1a822642
TB
268 }
269 me = ike_cfg->resolve_me(ike_cfg, other ? other->get_family(other)
270 : AF_UNSPEC);
271 if (!other)
272 {
273 other = host_create_any(me ? me->get_family(me) : AF_INET);
274 }
275 other->set_port(other, ike_cfg->get_other_port(ike_cfg));
276 if ((!me || me->is_anyaddr(me)) && !other->is_anyaddr(other))
eb8ed130 277 {
301a0bad 278 DESTROY_IF(me);
8394ea2a 279 me = charon->kernel->get_source_addr(charon->kernel, other, NULL);
eb8ed130 280 }
1a822642
TB
281 if (!me)
282 {
283 me = host_create_any(other->get_family(other));
284 }
285 me->set_port(me, ike_cfg->get_my_port(ike_cfg));
eb8ed130 286 }
7daf5226 287
21037942 288 this->lock->write_lock(this->lock);
12b3cdba
TB
289 if (this->installing == INSTALL_DISABLED)
290 { /* flush() has been called */
291 this->lock->unlock(this->lock);
e8f2c13f 292 other->destroy(other);
03024f4c 293 me->destroy(me);
24fa1bb0 294 return FALSE;
12b3cdba 295 }
21037942
TB
296 enumerator = this->traps->create_enumerator(this->traps);
297 while (enumerator->enumerate(enumerator, &entry))
298 {
3c65cf64
TB
299 if (!entry->external &&
300 streq(entry->name, child->get_name(child)) &&
f42dd430
TB
301 streq(entry->peer_cfg->get_name(entry->peer_cfg),
302 peer->get_name(peer)))
21037942 303 {
21037942 304 found = entry;
bb492d80 305 if (entry->child_sa)
3c65cf64 306 { /* replace it with an updated version if already installed */
bb492d80
TB
307 this->traps->remove_at(this->traps, enumerator);
308 }
21037942
TB
309 break;
310 }
311 }
312 enumerator->destroy(enumerator);
2dcfc698 313
21037942 314 if (found)
bb492d80
TB
315 {
316 if (!found->child_sa)
317 {
318 DBG1(DBG_CFG, "CHILD_SA '%s' is already being routed", found->name);
319 this->lock->unlock(this->lock);
e8f2c13f 320 other->destroy(other);
03024f4c 321 me->destroy(me);
24fa1bb0 322 return FALSE;
bb492d80
TB
323 }
324 /* config might have changed so update everything */
325 DBG1(DBG_CFG, "updating already routed CHILD_SA '%s'", found->name);
21037942
TB
326 }
327
bb492d80
TB
328 INIT(entry,
329 .name = strdup(child->get_name(child)),
330 .peer_cfg = peer->get_ref(peer),
301a0bad 331 .wildcard = wildcard,
bb492d80
TB
332 );
333 this->traps->insert_first(this->traps, entry);
12b3cdba 334 this->installing++;
bb492d80
TB
335 /* don't hold lock while creating CHILD_SA and installing policies */
336 this->lock->unlock(this->lock);
337
eb8ed130 338 /* create and route CHILD_SA */
fafa7698
TB
339 child_sa_create_t child_data = {
340 /* TODO: no reason to allocate unique interface IDs, there is currently
341 * no event to use them upon trap installation and we'd also have to
342 * pass them in a later initiate() call */
343 .if_id_in_def = peer->get_if_id(peer, TRUE),
344 .if_id_out_def = peer->get_if_id(peer, FALSE),
345 };
346 child_sa = child_sa_create(me, other, child, &child_data);
7ee37114 347
3c65cf64
TB
348 local = linked_list_create_with_items(me, NULL);
349 remote = linked_list_create_with_items(other, NULL);
7ee37114 350
3c65cf64 351 status = install_trap(child_sa, local, remote);
7daf5226 352
3c65cf64
TB
353 local->destroy_offset(local, offsetof(host_t, destroy));
354 remote->destroy_offset(remote, offsetof(host_t, destroy));
eb8ed130
MW
355 if (status != SUCCESS)
356 {
eb8ed130 357 DBG1(DBG_CFG, "installing trap failed");
bb492d80
TB
358 this->lock->write_lock(this->lock);
359 this->traps->remove(this->traps, entry, NULL);
360 this->lock->unlock(this->lock);
361 entry->child_sa = child_sa;
362 destroy_entry(entry);
21037942
TB
363 }
364 else
365 {
bb492d80
TB
366 this->lock->write_lock(this->lock);
367 entry->child_sa = child_sa;
368 this->lock->unlock(this->lock);
24fa1bb0 369 result = TRUE;
4eb09d14 370 }
21037942
TB
371 if (found)
372 {
373 destroy_entry(found);
374 }
12b3cdba
TB
375 this->lock->write_lock(this->lock);
376 /* do this at the end, so entries created temporarily are also destroyed */
377 this->installing--;
378 this->condvar->signal(this->condvar);
379 this->lock->unlock(this->lock);
24fa1bb0 380 return result;
eb8ed130
MW
381}
382
06356a29 383METHOD(trap_manager_t, uninstall, bool,
ca213e19 384 private_trap_manager_t *this, char *peer, char *child)
eb8ed130
MW
385{
386 enumerator_t *enumerator;
387 entry_t *entry, *found = NULL;
7daf5226 388
fcb06fdb 389 this->lock->write_lock(this->lock);
69cbe2ca
SM
390 while (this->installing)
391 {
392 this->condvar->wait(this->condvar, this->lock);
393 }
eb8ed130
MW
394 enumerator = this->traps->create_enumerator(this->traps);
395 while (enumerator->enumerate(enumerator, &entry))
396 {
3c65cf64
TB
397 if (!entry->external &&
398 streq(entry->name, child) &&
399 (!peer || streq(peer, entry->peer_cfg->get_name(entry->peer_cfg))))
400 {
401 this->traps->remove_at(this->traps, enumerator);
402 found = entry;
403 break;
404 }
405 }
406 enumerator->destroy(enumerator);
407 this->lock->unlock(this->lock);
408
409 if (!found)
410 {
411 return FALSE;
412 }
413 destroy_entry(found);
414 return TRUE;
415}
416
417METHOD(trap_manager_t, install_external, bool,
418 private_trap_manager_t *this, peer_cfg_t *peer, child_sa_t *child,
419 linked_list_t *local, linked_list_t *remote)
420{
421 entry_t *entry;
422
423 this->lock->write_lock(this->lock);
424 if (this->installing == INSTALL_DISABLED)
425 { /* flush() has been called */
426 this->lock->unlock(this->lock);
427 return FALSE;
428 }
429
430 INIT(entry,
431 .name = strdup(child->get_name(child)),
432 .peer_cfg = peer->get_ref(peer),
433 .child_sa = child,
434 .external = TRUE,
435 );
436 this->traps->insert_first(this->traps, entry);
437 this->lock->unlock(this->lock);
438
439 if (install_trap(child, local, remote) != SUCCESS)
440 {
441 DBG1(DBG_CFG, "installing trap failed");
442 this->lock->write_lock(this->lock);
443 this->traps->remove(this->traps, entry, NULL);
444 this->lock->unlock(this->lock);
445 destroy_entry(entry);
446 return FALSE;
447 }
448 return TRUE;
449}
450
451METHOD(trap_manager_t, remove_external, bool,
452 private_trap_manager_t *this, child_sa_t *child)
453{
454 enumerator_t *enumerator;
455 entry_t *entry, *found = NULL;
456
457 this->lock->write_lock(this->lock);
458 enumerator = this->traps->create_enumerator(this->traps);
459 while (enumerator->enumerate(enumerator, &entry))
460 {
461 if (entry->external && entry->child_sa == child)
eb8ed130
MW
462 {
463 this->traps->remove_at(this->traps, enumerator);
464 found = entry;
465 break;
466 }
467 }
468 enumerator->destroy(enumerator);
fcb06fdb 469 this->lock->unlock(this->lock);
7daf5226 470
eb8ed130
MW
471 if (!found)
472 {
eb8ed130
MW
473 return FALSE;
474 }
eb8ed130
MW
475 destroy_entry(found);
476 return TRUE;
477}
478
525cc46c
TB
479CALLBACK(trap_filter, bool,
480 rwlock_t *lock, enumerator_t *orig, va_list args)
eb8ed130 481{
525cc46c
TB
482 entry_t *entry;
483 peer_cfg_t **peer_cfg;
484 child_sa_t **child_sa;
485
486 VA_ARGS_VGET(args, peer_cfg, child_sa);
487
488 while (orig->enumerate(orig, &entry))
eb8ed130 489 {
3c65cf64
TB
490 if (!entry->child_sa || entry->external)
491 { /* skip entries that are currently being installed or are managed
492 * externally */
525cc46c
TB
493 continue;
494 }
495 if (peer_cfg)
496 {
497 *peer_cfg = entry->peer_cfg;
498 }
499 if (child_sa)
500 {
501 *child_sa = entry->child_sa;
502 }
503 return TRUE;
eb8ed130 504 }
525cc46c 505 return FALSE;
eb8ed130
MW
506}
507
06356a29
AS
508METHOD(trap_manager_t, create_enumerator, enumerator_t*,
509 private_trap_manager_t *this)
eb8ed130 510{
fcb06fdb 511 this->lock->read_lock(this->lock);
eb8ed130 512 return enumerator_create_filter(this->traps->create_enumerator(this->traps),
525cc46c 513 trap_filter, this->lock,
fcb06fdb 514 (void*)this->lock->unlock);
eb8ed130
MW
515}
516
06356a29 517METHOD(trap_manager_t, acquire, void,
3b699c72 518 private_trap_manager_t *this, uint32_t reqid, kernel_acquire_data_t *data)
eb8ed130
MW
519{
520 enumerator_t *enumerator;
521 entry_t *entry, *found = NULL;
a229bdce 522 acquire_t *acquire;
eb8ed130
MW
523 peer_cfg_t *peer;
524 child_cfg_t *child;
525 ike_sa_t *ike_sa;
301a0bad 526 host_t *host;
04bfe83f 527 uint32_t allocated_reqid;
301a0bad 528 bool wildcard, ignore = FALSE;
7daf5226 529
fcb06fdb 530 this->lock->read_lock(this->lock);
eb8ed130
MW
531 enumerator = this->traps->create_enumerator(this->traps);
532 while (enumerator->enumerate(enumerator, &entry))
533 {
bb492d80
TB
534 if (entry->child_sa &&
535 entry->child_sa->get_reqid(entry->child_sa) == reqid)
eb8ed130
MW
536 {
537 found = entry;
538 break;
539 }
540 }
541 enumerator->destroy(enumerator);
7daf5226 542
eb8ed130
MW
543 if (!found)
544 {
301a0bad 545 DBG1(DBG_CFG, "trap not found, unable to acquire reqid %d", reqid);
fc726f13
TB
546 this->lock->unlock(this->lock);
547 return;
eb8ed130 548 }
301a0bad 549 wildcard = found->wildcard;
a229bdce
TB
550
551 this->mutex->lock(this->mutex);
301a0bad
TB
552 if (wildcard)
553 { /* for wildcard acquires we check that we don't have a pending acquire
554 * with the same peer */
b12c53ce 555 uint8_t mask;
301a0bad 556
3b699c72 557 data->dst->to_subnet(data->dst, &host, &mask);
2e4d110d
TB
558 if (this->acquires->find_first(this->acquires, acquire_by_dst,
559 (void**)&acquire, host))
301a0bad
TB
560 {
561 host->destroy(host);
562 ignore = TRUE;
563 }
564 else
565 {
566 INIT(acquire,
567 .dst = host,
568 .reqid = reqid,
569 );
570 this->acquires->insert_last(this->acquires, acquire);
571 }
9d737ecf 572 }
a229bdce
TB
573 else
574 {
2e4d110d 575 if (this->acquires->find_first(this->acquires, acquire_by_reqid,
0a673794 576 (void**)&acquire, reqid, data->label))
301a0bad
TB
577 {
578 ignore = TRUE;
579 }
580 else
581 {
582 INIT(acquire,
583 .reqid = reqid,
0a673794 584 .label = data->label ? data->label->clone(data->label) : NULL,
301a0bad
TB
585 );
586 this->acquires->insert_last(this->acquires, acquire);
587 }
a229bdce
TB
588 }
589 this->mutex->unlock(this->mutex);
301a0bad
TB
590 if (ignore)
591 {
3b699c72
TB
592 DBG1(DBG_CFG, "ignoring acquire for reqid %u, connection attempt "
593 "pending", reqid);
301a0bad
TB
594 this->lock->unlock(this->lock);
595 return;
596 }
fc726f13
TB
597 peer = found->peer_cfg->get_ref(found->peer_cfg);
598 child = found->child_sa->get_config(found->child_sa);
599 child = child->get_ref(child);
04bfe83f
TB
600 /* only pass allocated reqids explicitly, take a reference */
601 allocated_reqid = found->child_sa->get_reqid_ref(found->child_sa);
fc726f13
TB
602 /* don't hold the lock while checking out the IKE_SA */
603 this->lock->unlock(this->lock);
604
301a0bad
TB
605 if (wildcard)
606 { /* the peer config would match IKE_SAs with other peers */
bde5bd47 607 ike_sa = charon->ike_sa_manager->create_new(charon->ike_sa_manager,
301a0bad
TB
608 peer->get_ike_version(peer), TRUE);
609 if (ike_sa)
610 {
611 ike_cfg_t *ike_cfg;
b12c53ce
AS
612 uint16_t port;
613 uint8_t mask;
301a0bad
TB
614
615 ike_sa->set_peer_cfg(ike_sa, peer);
616 ike_cfg = ike_sa->get_ike_cfg(ike_sa);
617
618 port = ike_cfg->get_other_port(ike_cfg);
3b699c72 619 data->dst->to_subnet(data->dst, &host, &mask);
301a0bad
TB
620 host->set_port(host, port);
621 ike_sa->set_other_host(ike_sa, host);
622
623 port = ike_cfg->get_my_port(ike_cfg);
3b699c72 624 data->src->to_subnet(data->src, &host, &mask);
301a0bad
TB
625 host->set_port(host, port);
626 ike_sa->set_my_host(ike_sa, host);
627
628 charon->bus->set_sa(charon->bus, ike_sa);
629 }
630 }
631 else
632 {
633 ike_sa = charon->ike_sa_manager->checkout_by_config(
fc726f13 634 charon->ike_sa_manager, peer);
301a0bad 635 }
7f6386af
TB
636 peer->destroy(peer);
637
b1f2f05c 638 if (ike_sa)
9d737ecf 639 {
7f30e1ae 640 child_init_args_t args = {
04bfe83f 641 .reqid = allocated_reqid,
3b699c72
TB
642 .src = data->src,
643 .dst = data->dst,
0a673794 644 .label = data->label,
7f30e1ae
TB
645 };
646
7fa03b30 647 if (this->ignore_acquire_ts || ike_sa->get_version(ike_sa) == IKEV1)
777bcdc0
MW
648 { /* in IKEv1, don't prepend the acquiring packet TS, as we only
649 * have a single TS that we can establish in a Quick Mode. */
7f30e1ae 650 args.src = args.dst = NULL;
777bcdc0 651 }
a229bdce
TB
652
653 this->mutex->lock(this->mutex);
654 acquire->ike_sa = ike_sa;
655 this->mutex->unlock(this->mutex);
656
7f30e1ae 657 if (ike_sa->initiate(ike_sa, child, &args) != DESTROY_ME)
b1f2f05c 658 {
b1f2f05c
MW
659 charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
660 }
661 else
662 {
773fcb16
TB
663 charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager,
664 ike_sa);
9d737ecf 665 }
fc726f13 666 }
a229bdce
TB
667 else
668 {
669 this->mutex->lock(this->mutex);
670 this->acquires->remove(this->acquires, acquire, NULL);
671 this->mutex->unlock(this->mutex);
672 destroy_acquire(acquire);
673 child->destroy(child);
674 }
04bfe83f
TB
675 if (allocated_reqid)
676 {
677 charon->kernel->release_reqid(charon->kernel, allocated_reqid);
678 }
9d737ecf
MW
679}
680
681/**
991f7ccd 682 * Complete the acquire, if successful or failed
9d737ecf 683 */
991f7ccd
MW
684static void complete(private_trap_manager_t *this, ike_sa_t *ike_sa,
685 child_sa_t *child_sa)
9d737ecf 686{
9d737ecf 687 enumerator_t *enumerator;
a229bdce 688 acquire_t *acquire;
7daf5226 689
a229bdce
TB
690 this->mutex->lock(this->mutex);
691 enumerator = this->acquires->create_enumerator(this->acquires);
692 while (enumerator->enumerate(enumerator, &acquire))
9d737ecf 693 {
a229bdce 694 if (!acquire->ike_sa || acquire->ike_sa != ike_sa)
991f7ccd
MW
695 {
696 continue;
697 }
301a0bad 698 if (child_sa)
9d737ecf 699 {
301a0bad
TB
700 if (acquire->dst)
701 {
702 /* since every wildcard acquire results in a separate IKE_SA
703 * there is no need to compare the destination address */
704 }
705 else if (child_sa->get_reqid(child_sa) != acquire->reqid)
706 {
707 continue;
708 }
0a673794
TB
709 else if (!sec_labels_equal(acquire->label,
710 child_sa->get_label(child_sa)))
711 {
712 continue;
713 }
9d737ecf 714 }
a229bdce
TB
715 this->acquires->remove_at(this->acquires, enumerator);
716 destroy_acquire(acquire);
9d737ecf
MW
717 }
718 enumerator->destroy(enumerator);
a229bdce 719 this->mutex->unlock(this->mutex);
991f7ccd
MW
720}
721
06356a29
AS
722METHOD(listener_t, ike_state_change, bool,
723 trap_listener_t *listener, ike_sa_t *ike_sa, ike_sa_state_t state)
991f7ccd
MW
724{
725 switch (state)
726 {
727 case IKE_DESTROYING:
728 complete(listener->traps, ike_sa, NULL);
729 return TRUE;
730 default:
731 return TRUE;
732 }
733}
734
06356a29
AS
735METHOD(listener_t, child_state_change, bool,
736 trap_listener_t *listener, ike_sa_t *ike_sa, child_sa_t *child_sa,
737 child_sa_state_t state)
991f7ccd
MW
738{
739 switch (state)
740 {
741 case CHILD_INSTALLED:
742 case CHILD_DESTROYING:
743 complete(listener->traps, ike_sa, child_sa);
744 return TRUE;
745 default:
746 return TRUE;
747 }
eb8ed130
MW
748}
749
f8437dd8
MW
750METHOD(trap_manager_t, flush, void,
751 private_trap_manager_t *this)
752{
d6656f11 753 this->lock->write_lock(this->lock);
12b3cdba
TB
754 while (this->installing)
755 {
756 this->condvar->wait(this->condvar, this->lock);
757 }
a229bdce 758 this->traps->destroy_function(this->traps, (void*)destroy_entry);
d6656f11 759 this->traps = linked_list_create();
12b3cdba 760 this->installing = INSTALL_DISABLED;
d6656f11 761 this->lock->unlock(this->lock);
f8437dd8
MW
762}
763
06356a29
AS
764METHOD(trap_manager_t, destroy, void,
765 private_trap_manager_t *this)
eb8ed130 766{
9d737ecf 767 charon->bus->remove_listener(charon->bus, &this->listener.listener);
d6656f11 768 this->traps->destroy_function(this->traps, (void*)destroy_entry);
a229bdce 769 this->acquires->destroy_function(this->acquires, (void*)destroy_acquire);
12b3cdba 770 this->condvar->destroy(this->condvar);
a229bdce 771 this->mutex->destroy(this->mutex);
fcb06fdb 772 this->lock->destroy(this->lock);
eb8ed130
MW
773 free(this);
774}
775
776/**
777 * See header
778 */
06356a29 779trap_manager_t *trap_manager_create(void)
eb8ed130 780{
06356a29
AS
781 private_trap_manager_t *this;
782
783 INIT(this,
784 .public = {
785 .install = _install,
786 .uninstall = _uninstall,
3c65cf64
TB
787 .install_external = _install_external,
788 .remove_external = _remove_external,
06356a29
AS
789 .create_enumerator = _create_enumerator,
790 .acquire = _acquire,
f8437dd8 791 .flush = _flush,
06356a29
AS
792 .destroy = _destroy,
793 },
6a5c8ee7
MW
794 .listener = {
795 .traps = this,
796 .listener = {
797 .ike_state_change = _ike_state_change,
798 .child_state_change = _child_state_change,
799 },
800 },
06356a29 801 .traps = linked_list_create(),
a229bdce
TB
802 .acquires = linked_list_create(),
803 .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
06356a29 804 .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
12b3cdba 805 .condvar = rwlock_condvar_create(),
7fa03b30
TB
806 .ignore_acquire_ts = lib->settings->get_bool(lib->settings,
807 "%s.ignore_acquire_ts", FALSE, lib->ns),
06356a29 808 );
9d737ecf 809 charon->bus->add_listener(charon->bus, &this->listener.listener);
7daf5226 810
eb8ed130
MW
811 return &this->public;
812}