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