]> git.ipfire.org Git - thirdparty/strongswan.git/blame - src/libcharon/sa/trap_manager.c
nm: Don't set DL_LIBS to 'none required' in configure script
[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;
84da4160
TB
96
97 /**
98 * Current acquire sequence number if not generated by the kernel
99 */
100 refcount_t acquire_seq;
eb8ed130
MW
101};
102
103/**
104 * A installed trap entry
105 */
106typedef struct {
bb492d80
TB
107 /** name of the trapped CHILD_SA */
108 char *name;
eb8ed130
MW
109 /** ref to peer_cfg to initiate */
110 peer_cfg_t *peer_cfg;
a229bdce 111 /** ref to instantiated CHILD_SA (i.e the trap policy) */
eb8ed130 112 child_sa_t *child_sa;
301a0bad
TB
113 /** TRUE in case of wildcard Transport Mode SA */
114 bool wildcard;
3c65cf64
TB
115 /** TRUE for CHILD_SAs that are externally managed */
116 bool external;
a229bdce
TB
117} entry_t;
118
119/**
120 * A handled acquire
121 */
122typedef struct {
9d737ecf 123 /** pending IKE_SA connecting upon acquire */
fc726f13 124 ike_sa_t *ike_sa;
a229bdce 125 /** reqid of pending trap policy */
b12c53ce 126 uint32_t reqid;
301a0bad
TB
127 /** destination address (wildcard case) */
128 host_t *dst;
79815b4e
TB
129 /** data from the kernel */
130 kernel_acquire_data_t *data;
84da4160
TB
131 /** optional sequence number from the kernel if an acquire is retriggered */
132 uint32_t new_seq;
a229bdce 133} acquire_t;
eb8ed130
MW
134
135/**
136 * actually uninstall and destroy an installed entry
137 */
a229bdce
TB
138static void destroy_entry(entry_t *this)
139{
3c65cf64
TB
140 if (!this->external)
141 {
142 this->child_sa->destroy(this->child_sa);
143 }
a229bdce
TB
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 */
152static void destroy_acquire(acquire_t *this)
eb8ed130 153{
301a0bad 154 DESTROY_IF(this->dst);
79815b4e 155 kernel_acquire_data_destroy(this->data);
a229bdce
TB
156 free(this);
157}
158
2e4d110d
TB
159CALLBACK(acquire_by_reqid, bool,
160 acquire_t *this, va_list args)
a229bdce 161{
4a595508 162 uint32_t reqid, cpu;
0a673794 163 sec_label_t *label;
2e4d110d 164
4a595508
TB
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);
eb8ed130
MW
168}
169
2e4d110d
TB
170CALLBACK(acquire_by_dst, bool,
171 acquire_t *this, va_list args)
301a0bad 172{
2e4d110d
TB
173 host_t *dst;
174
175 VA_ARGS_VGET(args, dst);
301a0bad
TB
176 return this->dst && this->dst->ip_equals(this->dst, dst);
177}
178
1a822642
TB
179/**
180 * Check if any remote TS are dynamic
181 */
182static 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
c5b2a8ea 189 other_ts = child->get_traffic_selectors(child, FALSE, NULL);
1a822642
TB
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
3c65cf64
TB
204/**
205 * Install the given trap
206 */
207static 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
c5b2a8ea
TB
217 my_ts = child->get_traffic_selectors(child, TRUE, local);
218 other_ts = child->get_traffic_selectors(child, FALSE, remote);
3c65cf64
TB
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
24fa1bb0
TB
239METHOD(trap_manager_t, install, bool,
240 private_trap_manager_t *this, peer_cfg_t *peer, child_cfg_t *child)
eb8ed130 241{
21037942 242 entry_t *entry, *found = NULL;
eb8ed130
MW
243 ike_cfg_t *ike_cfg;
244 child_sa_t *child_sa;
245 host_t *me, *other;
3c65cf64 246 linked_list_t *local, *remote;
eb8ed130 247 enumerator_t *enumerator;
eb8ed130 248 status_t status;
24fa1bb0 249 bool result = FALSE, wildcard = FALSE;
7daf5226 250
eb8ed130
MW
251 /* try to resolve addresses */
252 ike_cfg = peer->get_ike_cfg(peer);
7446fa28 253 other = ike_cfg->resolve_other(ike_cfg, AF_UNSPEC);
301a0bad
TB
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 }
1a822642 261 else if (other && other->is_anyaddr(other))
eb8ed130 262 {
1a822642 263 other->destroy(other);
eb8ed130 264 DBG1(DBG_CFG, "installing trap failed, remote address unknown");
24fa1bb0 265 return FALSE;
eb8ed130 266 }
301a0bad 267 else
1a822642
TB
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");
24fa1bb0 275 return FALSE;
1a822642
TB
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))
eb8ed130 285 {
301a0bad 286 DESTROY_IF(me);
8394ea2a 287 me = charon->kernel->get_source_addr(charon->kernel, other, NULL);
eb8ed130 288 }
1a822642
TB
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));
eb8ed130 294 }
7daf5226 295
21037942 296 this->lock->write_lock(this->lock);
12b3cdba
TB
297 if (this->installing == INSTALL_DISABLED)
298 { /* flush() has been called */
299 this->lock->unlock(this->lock);
e8f2c13f 300 other->destroy(other);
03024f4c 301 me->destroy(me);
24fa1bb0 302 return FALSE;
12b3cdba 303 }
21037942
TB
304 enumerator = this->traps->create_enumerator(this->traps);
305 while (enumerator->enumerate(enumerator, &entry))
306 {
3c65cf64
TB
307 if (!entry->external &&
308 streq(entry->name, child->get_name(child)) &&
f42dd430
TB
309 streq(entry->peer_cfg->get_name(entry->peer_cfg),
310 peer->get_name(peer)))
21037942 311 {
21037942 312 found = entry;
bb492d80 313 if (entry->child_sa)
3c65cf64 314 { /* replace it with an updated version if already installed */
bb492d80
TB
315 this->traps->remove_at(this->traps, enumerator);
316 }
21037942
TB
317 break;
318 }
319 }
320 enumerator->destroy(enumerator);
2dcfc698 321
21037942 322 if (found)
bb492d80
TB
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);
e8f2c13f 328 other->destroy(other);
03024f4c 329 me->destroy(me);
24fa1bb0 330 return FALSE;
bb492d80
TB
331 }
332 /* config might have changed so update everything */
333 DBG1(DBG_CFG, "updating already routed CHILD_SA '%s'", found->name);
21037942
TB
334 }
335
bb492d80
TB
336 INIT(entry,
337 .name = strdup(child->get_name(child)),
338 .peer_cfg = peer->get_ref(peer),
301a0bad 339 .wildcard = wildcard,
bb492d80
TB
340 );
341 this->traps->insert_first(this->traps, entry);
12b3cdba 342 this->installing++;
bb492d80
TB
343 /* don't hold lock while creating CHILD_SA and installing policies */
344 this->lock->unlock(this->lock);
345
eb8ed130 346 /* create and route CHILD_SA */
fafa7698
TB
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),
a505f4b9 353 .cpu = CPU_ID_MAX,
fafa7698
TB
354 };
355 child_sa = child_sa_create(me, other, child, &child_data);
7ee37114 356
3c65cf64
TB
357 local = linked_list_create_with_items(me, NULL);
358 remote = linked_list_create_with_items(other, NULL);
7ee37114 359
3c65cf64 360 status = install_trap(child_sa, local, remote);
7daf5226 361
3c65cf64
TB
362 local->destroy_offset(local, offsetof(host_t, destroy));
363 remote->destroy_offset(remote, offsetof(host_t, destroy));
eb8ed130
MW
364 if (status != SUCCESS)
365 {
eb8ed130 366 DBG1(DBG_CFG, "installing trap failed");
bb492d80
TB
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);
21037942
TB
372 }
373 else
374 {
bb492d80
TB
375 this->lock->write_lock(this->lock);
376 entry->child_sa = child_sa;
377 this->lock->unlock(this->lock);
24fa1bb0 378 result = TRUE;
4eb09d14 379 }
21037942
TB
380 if (found)
381 {
382 destroy_entry(found);
383 }
12b3cdba
TB
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);
24fa1bb0 389 return result;
eb8ed130
MW
390}
391
06356a29 392METHOD(trap_manager_t, uninstall, bool,
ca213e19 393 private_trap_manager_t *this, char *peer, char *child)
eb8ed130
MW
394{
395 enumerator_t *enumerator;
396 entry_t *entry, *found = NULL;
7daf5226 397
fcb06fdb 398 this->lock->write_lock(this->lock);
69cbe2ca
SM
399 while (this->installing)
400 {
401 this->condvar->wait(this->condvar, this->lock);
402 }
eb8ed130
MW
403 enumerator = this->traps->create_enumerator(this->traps);
404 while (enumerator->enumerate(enumerator, &entry))
405 {
3c65cf64
TB
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
426METHOD(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
460METHOD(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)
eb8ed130
MW
471 {
472 this->traps->remove_at(this->traps, enumerator);
473 found = entry;
474 break;
475 }
476 }
477 enumerator->destroy(enumerator);
fcb06fdb 478 this->lock->unlock(this->lock);
7daf5226 479
eb8ed130
MW
480 if (!found)
481 {
eb8ed130
MW
482 return FALSE;
483 }
eb8ed130
MW
484 destroy_entry(found);
485 return TRUE;
486}
487
525cc46c
TB
488CALLBACK(trap_filter, bool,
489 rwlock_t *lock, enumerator_t *orig, va_list args)
eb8ed130 490{
525cc46c
TB
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))
eb8ed130 498 {
3c65cf64
TB
499 if (!entry->child_sa || entry->external)
500 { /* skip entries that are currently being installed or are managed
501 * externally */
525cc46c
TB
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;
eb8ed130 513 }
525cc46c 514 return FALSE;
eb8ed130
MW
515}
516
06356a29
AS
517METHOD(trap_manager_t, create_enumerator, enumerator_t*,
518 private_trap_manager_t *this)
eb8ed130 519{
fcb06fdb 520 this->lock->read_lock(this->lock);
eb8ed130 521 return enumerator_create_filter(this->traps->create_enumerator(this->traps),
525cc46c 522 trap_filter, this->lock,
fcb06fdb 523 (void*)this->lock->unlock);
eb8ed130
MW
524}
525
06356a29 526METHOD(trap_manager_t, acquire, void,
3b699c72 527 private_trap_manager_t *this, uint32_t reqid, kernel_acquire_data_t *data)
eb8ed130
MW
528{
529 enumerator_t *enumerator;
530 entry_t *entry, *found = NULL;
84da4160 531 acquire_t *acquire = NULL;
eb8ed130
MW
532 peer_cfg_t *peer;
533 child_cfg_t *child;
534 ike_sa_t *ike_sa;
84da4160 535 host_t *host = NULL;
84da4160
TB
536 uint32_t allocated_reqid, seq = 0;
537 bool wildcard;
7daf5226 538
fcb06fdb 539 this->lock->read_lock(this->lock);
eb8ed130
MW
540 enumerator = this->traps->create_enumerator(this->traps);
541 while (enumerator->enumerate(enumerator, &entry))
542 {
bb492d80
TB
543 if (entry->child_sa &&
544 entry->child_sa->get_reqid(entry->child_sa) == reqid)
eb8ed130
MW
545 {
546 found = entry;
547 break;
548 }
549 }
550 enumerator->destroy(enumerator);
7daf5226 551
eb8ed130
MW
552 if (!found)
553 {
301a0bad 554 DBG1(DBG_CFG, "trap not found, unable to acquire reqid %d", reqid);
fc726f13
TB
555 this->lock->unlock(this->lock);
556 return;
eb8ed130 557 }
301a0bad 558 wildcard = found->wildcard;
a229bdce
TB
559
560 this->mutex->lock(this->mutex);
301a0bad 561 if (wildcard)
84da4160
TB
562 {
563 /* for wildcard acquires we check that we don't have a pending acquire
301a0bad 564 * with the same peer */
b12c53ce 565 uint8_t mask;
301a0bad 566
3b699c72 567 data->dst->to_subnet(data->dst, &host, &mask);
2e4d110d 568 if (this->acquires->find_first(this->acquires, acquire_by_dst,
84da4160 569 (void**)&acquire, host))
301a0bad
TB
570 {
571 host->destroy(host);
301a0bad 572 }
9d737ecf 573 }
79815b4e 574 else
a229bdce 575 {
79815b4e 576 this->acquires->find_first(this->acquires, acquire_by_reqid,
4a595508
TB
577 (void**)&acquire, reqid, data->cpu,
578 data->label);
84da4160
TB
579 }
580 if (!acquire)
581 {
84da4160
TB
582 INIT(acquire,
583 .dst = host,
584 .reqid = reqid,
79815b4e 585 .data = kernel_acquire_data_clone(data),
84da4160 586 );
79815b4e 587 seq = data->seq = data->seq ?: ref_get_nonzero(&this->acquire_seq);
84da4160
TB
588 this->acquires->insert_last(this->acquires, acquire);
589 }
79815b4e 590 else if (data->seq && data->seq != acquire->data->seq)
84da4160
TB
591 {
592 /* acquire got retriggered, update to latest sequence number */
593 acquire->new_seq = data->seq;
a229bdce
TB
594 }
595 this->mutex->unlock(this->mutex);
84da4160 596 if (!seq)
301a0bad 597 {
3b699c72
TB
598 DBG1(DBG_CFG, "ignoring acquire for reqid %u, connection attempt "
599 "pending", reqid);
301a0bad
TB
600 this->lock->unlock(this->lock);
601 return;
602 }
fc726f13
TB
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);
04bfe83f
TB
606 /* only pass allocated reqids explicitly, take a reference */
607 allocated_reqid = found->child_sa->get_reqid_ref(found->child_sa);
fc726f13
TB
608 /* don't hold the lock while checking out the IKE_SA */
609 this->lock->unlock(this->lock);
610
301a0bad
TB
611 if (wildcard)
612 { /* the peer config would match IKE_SAs with other peers */
bde5bd47 613 ike_sa = charon->ike_sa_manager->create_new(charon->ike_sa_manager,
301a0bad
TB
614 peer->get_ike_version(peer), TRUE);
615 if (ike_sa)
616 {
617 ike_cfg_t *ike_cfg;
b12c53ce
AS
618 uint16_t port;
619 uint8_t mask;
301a0bad
TB
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);
3b699c72 625 data->dst->to_subnet(data->dst, &host, &mask);
301a0bad
TB
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);
3b699c72 630 data->src->to_subnet(data->src, &host, &mask);
301a0bad
TB
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(
fc726f13 640 charon->ike_sa_manager, peer);
301a0bad 641 }
7f6386af
TB
642 peer->destroy(peer);
643
b1f2f05c 644 if (ike_sa)
9d737ecf 645 {
7f30e1ae 646 child_init_args_t args = {
04bfe83f 647 .reqid = allocated_reqid,
4a595508 648 .cpu = data->cpu,
3b699c72
TB
649 .src = data->src,
650 .dst = data->dst,
0a673794 651 .label = data->label,
84da4160 652 .seq = seq,
7f30e1ae
TB
653 };
654
7fa03b30 655 if (this->ignore_acquire_ts || ike_sa->get_version(ike_sa) == IKEV1)
777bcdc0
MW
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. */
7f30e1ae 658 args.src = args.dst = NULL;
777bcdc0 659 }
a229bdce
TB
660
661 this->mutex->lock(this->mutex);
662 acquire->ike_sa = ike_sa;
663 this->mutex->unlock(this->mutex);
664
7f30e1ae 665 if (ike_sa->initiate(ike_sa, child, &args) != DESTROY_ME)
b1f2f05c 666 {
b1f2f05c
MW
667 charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
668 }
669 else
670 {
773fcb16
TB
671 charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager,
672 ike_sa);
9d737ecf 673 }
fc726f13 674 }
a229bdce
TB
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 }
04bfe83f
TB
683 if (allocated_reqid)
684 {
685 charon->kernel->release_reqid(charon->kernel, allocated_reqid);
686 }
9d737ecf
MW
687}
688
689/**
84da4160
TB
690 * Update the sequence number of the CHILD_SA before installing it in case
691 * the acquire got retriggered.
9d737ecf 692 */
84da4160
TB
693static void update_acquire_seq(private_trap_manager_t *this, ike_sa_t *ike_sa,
694 child_sa_t *child_sa)
9d737ecf 695{
9d737ecf 696 enumerator_t *enumerator;
a229bdce 697 acquire_t *acquire;
84da4160
TB
698 uint32_t seq;
699
79815b4e
TB
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))
84da4160
TB
712 {
713 return;
714 }
7daf5226 715
a229bdce
TB
716 this->mutex->lock(this->mutex);
717 enumerator = this->acquires->create_enumerator(this->acquires);
718 while (enumerator->enumerate(enumerator, &acquire))
9d737ecf 719 {
79815b4e
TB
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)
991f7ccd
MW
732 {
733 continue;
734 }
84da4160 735 if (acquire->new_seq)
9d737ecf 736 {
84da4160 737 child_sa->set_acquire_seq(child_sa, acquire->new_seq);
79815b4e 738 acquire->data->seq = acquire->new_seq;
84da4160
TB
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 */
750static 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 */
79815b4e 769 if (!acquire->ike_sa || (seq && seq != acquire->data->seq) ||
84da4160
TB
770 (!seq && acquire->ike_sa != ike_sa))
771 {
772 continue;
9d737ecf 773 }
a229bdce
TB
774 this->acquires->remove_at(this->acquires, enumerator);
775 destroy_acquire(acquire);
9d737ecf
MW
776 }
777 enumerator->destroy(enumerator);
a229bdce 778 this->mutex->unlock(this->mutex);
991f7ccd
MW
779}
780
06356a29
AS
781METHOD(listener_t, ike_state_change, bool,
782 trap_listener_t *listener, ike_sa_t *ike_sa, ike_sa_state_t state)
991f7ccd
MW
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
06356a29
AS
794METHOD(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)
991f7ccd
MW
797{
798 switch (state)
799 {
84da4160
TB
800 case CHILD_INSTALLING:
801 update_acquire_seq(listener->traps, ike_sa, child_sa);
802 return TRUE;
991f7ccd
MW
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 }
eb8ed130
MW
810}
811
f8437dd8
MW
812METHOD(trap_manager_t, flush, void,
813 private_trap_manager_t *this)
814{
d6656f11 815 this->lock->write_lock(this->lock);
12b3cdba
TB
816 while (this->installing)
817 {
818 this->condvar->wait(this->condvar, this->lock);
819 }
a229bdce 820 this->traps->destroy_function(this->traps, (void*)destroy_entry);
d6656f11 821 this->traps = linked_list_create();
12b3cdba 822 this->installing = INSTALL_DISABLED;
d6656f11 823 this->lock->unlock(this->lock);
f8437dd8
MW
824}
825
06356a29
AS
826METHOD(trap_manager_t, destroy, void,
827 private_trap_manager_t *this)
eb8ed130 828{
9d737ecf 829 charon->bus->remove_listener(charon->bus, &this->listener.listener);
d6656f11 830 this->traps->destroy_function(this->traps, (void*)destroy_entry);
a229bdce 831 this->acquires->destroy_function(this->acquires, (void*)destroy_acquire);
12b3cdba 832 this->condvar->destroy(this->condvar);
a229bdce 833 this->mutex->destroy(this->mutex);
fcb06fdb 834 this->lock->destroy(this->lock);
eb8ed130
MW
835 free(this);
836}
837
838/**
839 * See header
840 */
06356a29 841trap_manager_t *trap_manager_create(void)
eb8ed130 842{
06356a29
AS
843 private_trap_manager_t *this;
844
845 INIT(this,
846 .public = {
847 .install = _install,
848 .uninstall = _uninstall,
3c65cf64
TB
849 .install_external = _install_external,
850 .remove_external = _remove_external,
06356a29
AS
851 .create_enumerator = _create_enumerator,
852 .acquire = _acquire,
f8437dd8 853 .flush = _flush,
06356a29
AS
854 .destroy = _destroy,
855 },
6a5c8ee7
MW
856 .listener = {
857 .traps = this,
858 .listener = {
859 .ike_state_change = _ike_state_change,
860 .child_state_change = _child_state_change,
861 },
862 },
06356a29 863 .traps = linked_list_create(),
a229bdce
TB
864 .acquires = linked_list_create(),
865 .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
06356a29 866 .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
12b3cdba 867 .condvar = rwlock_condvar_create(),
7fa03b30
TB
868 .ignore_acquire_ts = lib->settings->get_bool(lib->settings,
869 "%s.ignore_acquire_ts", FALSE, lib->ns),
06356a29 870 );
9d737ecf 871 charon->bus->add_listener(charon->bus, &this->listener.listener);
7daf5226 872
eb8ed130
MW
873 return &this->public;
874}