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