]>
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 TB |
117 | /** reqid of pending trap policy */ |
118 | u_int32_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 | */ | |
146 | static bool acquire_by_reqid(acquire_t *this, u_int32_t *reqid) | |
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 | ||
06356a29 | 159 | METHOD(trap_manager_t, install, u_int32_t, |
4c74fa66 TB |
160 | private_trap_manager_t *this, peer_cfg_t *peer, child_cfg_t *child, |
161 | u_int32_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 | { | |
200 | DBG1(DBG_CFG, "installing trap failed, local address unknown"); | |
201 | other->destroy(other); | |
202 | return 0; | |
203 | } | |
204 | me->set_port(me, ike_cfg->get_my_port(ike_cfg)); | |
eb8ed130 | 205 | } |
eb8ed130 | 206 | } |
7daf5226 | 207 | |
21037942 | 208 | this->lock->write_lock(this->lock); |
12b3cdba TB |
209 | if (this->installing == INSTALL_DISABLED) |
210 | { /* flush() has been called */ | |
211 | this->lock->unlock(this->lock); | |
e8f2c13f | 212 | other->destroy(other); |
03024f4c | 213 | me->destroy(me); |
12b3cdba TB |
214 | return 0; |
215 | } | |
21037942 TB |
216 | enumerator = this->traps->create_enumerator(this->traps); |
217 | while (enumerator->enumerate(enumerator, &entry)) | |
218 | { | |
bb492d80 | 219 | if (streq(entry->name, child->get_name(child))) |
21037942 | 220 | { |
21037942 | 221 | found = entry; |
bb492d80 TB |
222 | if (entry->child_sa) |
223 | { /* replace it with an updated version, if already installed */ | |
224 | this->traps->remove_at(this->traps, enumerator); | |
225 | } | |
21037942 TB |
226 | break; |
227 | } | |
228 | } | |
229 | enumerator->destroy(enumerator); | |
2dcfc698 | 230 | |
21037942 | 231 | if (found) |
bb492d80 TB |
232 | { |
233 | if (!found->child_sa) | |
234 | { | |
235 | DBG1(DBG_CFG, "CHILD_SA '%s' is already being routed", found->name); | |
236 | this->lock->unlock(this->lock); | |
e8f2c13f | 237 | other->destroy(other); |
03024f4c | 238 | me->destroy(me); |
bb492d80 TB |
239 | return 0; |
240 | } | |
241 | /* config might have changed so update everything */ | |
242 | DBG1(DBG_CFG, "updating already routed CHILD_SA '%s'", found->name); | |
21037942 TB |
243 | reqid = found->child_sa->get_reqid(found->child_sa); |
244 | } | |
245 | ||
bb492d80 TB |
246 | INIT(entry, |
247 | .name = strdup(child->get_name(child)), | |
248 | .peer_cfg = peer->get_ref(peer), | |
301a0bad | 249 | .wildcard = wildcard, |
bb492d80 TB |
250 | ); |
251 | this->traps->insert_first(this->traps, entry); | |
12b3cdba | 252 | this->installing++; |
bb492d80 TB |
253 | /* don't hold lock while creating CHILD_SA and installing policies */ |
254 | this->lock->unlock(this->lock); | |
255 | ||
eb8ed130 | 256 | /* create and route CHILD_SA */ |
85b23888 | 257 | child_sa = child_sa_create(me, other, child, reqid, FALSE, 0, 0); |
7ee37114 MW |
258 | |
259 | list = linked_list_create_with_items(me, NULL); | |
260 | my_ts = child->get_traffic_selectors(child, TRUE, NULL, list); | |
261 | list->destroy_offset(list, offsetof(host_t, destroy)); | |
262 | ||
263 | list = linked_list_create_with_items(other, NULL); | |
264 | other_ts = child->get_traffic_selectors(child, FALSE, NULL, list); | |
265 | list->destroy_offset(list, offsetof(host_t, destroy)); | |
7daf5226 | 266 | |
5d569e07 MW |
267 | /* We don't know the finally negotiated protocol (ESP|AH), we install |
268 | * the SA with the protocol of the first proposal */ | |
269 | proposals = child->get_proposals(child, TRUE); | |
270 | if (proposals->get_first(proposals, (void**)&proposal) == SUCCESS) | |
271 | { | |
272 | proto = proposal->get_protocol(proposal); | |
273 | } | |
274 | proposals->destroy_offset(proposals, offsetof(proposal_t, destroy)); | |
275 | child_sa->set_protocol(child_sa, proto); | |
eb8ed130 MW |
276 | child_sa->set_mode(child_sa, child->get_mode(child)); |
277 | status = child_sa->add_policies(child_sa, my_ts, other_ts); | |
278 | my_ts->destroy_offset(my_ts, offsetof(traffic_selector_t, destroy)); | |
279 | other_ts->destroy_offset(other_ts, offsetof(traffic_selector_t, destroy)); | |
280 | if (status != SUCCESS) | |
281 | { | |
eb8ed130 | 282 | DBG1(DBG_CFG, "installing trap failed"); |
bb492d80 TB |
283 | this->lock->write_lock(this->lock); |
284 | this->traps->remove(this->traps, entry, NULL); | |
285 | this->lock->unlock(this->lock); | |
286 | entry->child_sa = child_sa; | |
287 | destroy_entry(entry); | |
21037942 TB |
288 | reqid = 0; |
289 | } | |
290 | else | |
291 | { | |
21037942 | 292 | reqid = child_sa->get_reqid(child_sa); |
bb492d80 TB |
293 | this->lock->write_lock(this->lock); |
294 | entry->child_sa = child_sa; | |
295 | this->lock->unlock(this->lock); | |
4eb09d14 | 296 | } |
21037942 TB |
297 | if (found) |
298 | { | |
299 | destroy_entry(found); | |
300 | } | |
12b3cdba TB |
301 | this->lock->write_lock(this->lock); |
302 | /* do this at the end, so entries created temporarily are also destroyed */ | |
303 | this->installing--; | |
304 | this->condvar->signal(this->condvar); | |
305 | this->lock->unlock(this->lock); | |
eb8ed130 MW |
306 | return reqid; |
307 | } | |
308 | ||
06356a29 AS |
309 | METHOD(trap_manager_t, uninstall, bool, |
310 | private_trap_manager_t *this, u_int32_t reqid) | |
eb8ed130 MW |
311 | { |
312 | enumerator_t *enumerator; | |
313 | entry_t *entry, *found = NULL; | |
7daf5226 | 314 | |
fcb06fdb | 315 | this->lock->write_lock(this->lock); |
eb8ed130 MW |
316 | enumerator = this->traps->create_enumerator(this->traps); |
317 | while (enumerator->enumerate(enumerator, &entry)) | |
318 | { | |
bb492d80 TB |
319 | if (entry->child_sa && |
320 | entry->child_sa->get_reqid(entry->child_sa) == reqid) | |
eb8ed130 MW |
321 | { |
322 | this->traps->remove_at(this->traps, enumerator); | |
323 | found = entry; | |
324 | break; | |
325 | } | |
326 | } | |
327 | enumerator->destroy(enumerator); | |
fcb06fdb | 328 | this->lock->unlock(this->lock); |
7daf5226 | 329 | |
eb8ed130 MW |
330 | if (!found) |
331 | { | |
332 | DBG1(DBG_CFG, "trap %d not found to uninstall", reqid); | |
333 | return FALSE; | |
334 | } | |
eb8ed130 MW |
335 | destroy_entry(found); |
336 | return TRUE; | |
337 | } | |
338 | ||
339 | /** | |
340 | * convert enumerated entries to peer_cfg, child_sa | |
341 | */ | |
fcb06fdb | 342 | static bool trap_filter(rwlock_t *lock, entry_t **entry, peer_cfg_t **peer_cfg, |
eb8ed130 MW |
343 | void *none, child_sa_t **child_sa) |
344 | { | |
bb492d80 TB |
345 | if (!(*entry)->child_sa) |
346 | { /* skip entries that are currently being installed */ | |
347 | return FALSE; | |
348 | } | |
eb8ed130 MW |
349 | if (peer_cfg) |
350 | { | |
351 | *peer_cfg = (*entry)->peer_cfg; | |
352 | } | |
353 | if (child_sa) | |
354 | { | |
355 | *child_sa = (*entry)->child_sa; | |
356 | } | |
357 | return TRUE; | |
358 | } | |
359 | ||
06356a29 AS |
360 | METHOD(trap_manager_t, create_enumerator, enumerator_t*, |
361 | private_trap_manager_t *this) | |
eb8ed130 | 362 | { |
fcb06fdb | 363 | this->lock->read_lock(this->lock); |
eb8ed130 | 364 | return enumerator_create_filter(this->traps->create_enumerator(this->traps), |
fcb06fdb MW |
365 | (void*)trap_filter, this->lock, |
366 | (void*)this->lock->unlock); | |
eb8ed130 MW |
367 | } |
368 | ||
2dcfc698 MW |
369 | METHOD(trap_manager_t, find_reqid, u_int32_t, |
370 | private_trap_manager_t *this, child_cfg_t *child) | |
371 | { | |
372 | enumerator_t *enumerator; | |
2dcfc698 MW |
373 | entry_t *entry; |
374 | u_int32_t reqid = 0; | |
375 | ||
376 | this->lock->read_lock(this->lock); | |
377 | enumerator = this->traps->create_enumerator(this->traps); | |
378 | while (enumerator->enumerate(enumerator, &entry)) | |
379 | { | |
bb492d80 | 380 | if (streq(entry->name, child->get_name(child))) |
2dcfc698 | 381 | { |
bb492d80 TB |
382 | if (entry->child_sa) |
383 | { | |
384 | reqid = entry->child_sa->get_reqid(entry->child_sa); | |
385 | } | |
2dcfc698 MW |
386 | break; |
387 | } | |
388 | } | |
389 | enumerator->destroy(enumerator); | |
390 | this->lock->unlock(this->lock); | |
2dcfc698 MW |
391 | return reqid; |
392 | } | |
393 | ||
06356a29 AS |
394 | METHOD(trap_manager_t, acquire, void, |
395 | private_trap_manager_t *this, u_int32_t reqid, | |
396 | traffic_selector_t *src, traffic_selector_t *dst) | |
eb8ed130 MW |
397 | { |
398 | enumerator_t *enumerator; | |
399 | entry_t *entry, *found = NULL; | |
a229bdce | 400 | acquire_t *acquire; |
eb8ed130 MW |
401 | peer_cfg_t *peer; |
402 | child_cfg_t *child; | |
403 | ike_sa_t *ike_sa; | |
301a0bad TB |
404 | host_t *host; |
405 | bool wildcard, ignore = FALSE; | |
7daf5226 | 406 | |
fcb06fdb | 407 | this->lock->read_lock(this->lock); |
eb8ed130 MW |
408 | enumerator = this->traps->create_enumerator(this->traps); |
409 | while (enumerator->enumerate(enumerator, &entry)) | |
410 | { | |
bb492d80 TB |
411 | if (entry->child_sa && |
412 | entry->child_sa->get_reqid(entry->child_sa) == reqid) | |
eb8ed130 MW |
413 | { |
414 | found = entry; | |
415 | break; | |
416 | } | |
417 | } | |
418 | enumerator->destroy(enumerator); | |
7daf5226 | 419 | |
eb8ed130 MW |
420 | if (!found) |
421 | { | |
301a0bad | 422 | DBG1(DBG_CFG, "trap not found, unable to acquire reqid %d", reqid); |
fc726f13 TB |
423 | this->lock->unlock(this->lock); |
424 | return; | |
eb8ed130 | 425 | } |
a229bdce | 426 | reqid = found->child_sa->get_reqid(found->child_sa); |
301a0bad | 427 | wildcard = found->wildcard; |
a229bdce TB |
428 | |
429 | this->mutex->lock(this->mutex); | |
301a0bad TB |
430 | if (wildcard) |
431 | { /* for wildcard acquires we check that we don't have a pending acquire | |
432 | * with the same peer */ | |
433 | u_int8_t mask; | |
434 | ||
435 | dst->to_subnet(dst, &host, &mask); | |
436 | if (this->acquires->find_first(this->acquires, (void*)acquire_by_dst, | |
437 | (void**)&acquire, host) == SUCCESS) | |
438 | { | |
439 | host->destroy(host); | |
440 | ignore = TRUE; | |
441 | } | |
442 | else | |
443 | { | |
444 | INIT(acquire, | |
445 | .dst = host, | |
446 | .reqid = reqid, | |
447 | ); | |
448 | this->acquires->insert_last(this->acquires, acquire); | |
449 | } | |
9d737ecf | 450 | } |
a229bdce TB |
451 | else |
452 | { | |
301a0bad TB |
453 | if (this->acquires->find_first(this->acquires, (void*)acquire_by_reqid, |
454 | (void**)&acquire, &reqid) == SUCCESS) | |
455 | { | |
456 | ignore = TRUE; | |
457 | } | |
458 | else | |
459 | { | |
460 | INIT(acquire, | |
461 | .reqid = reqid, | |
462 | ); | |
463 | this->acquires->insert_last(this->acquires, acquire); | |
464 | } | |
a229bdce TB |
465 | } |
466 | this->mutex->unlock(this->mutex); | |
301a0bad TB |
467 | if (ignore) |
468 | { | |
469 | DBG1(DBG_CFG, "ignoring acquire, connection attempt pending"); | |
470 | this->lock->unlock(this->lock); | |
471 | return; | |
472 | } | |
fc726f13 TB |
473 | peer = found->peer_cfg->get_ref(found->peer_cfg); |
474 | child = found->child_sa->get_config(found->child_sa); | |
475 | child = child->get_ref(child); | |
fc726f13 TB |
476 | /* don't hold the lock while checking out the IKE_SA */ |
477 | this->lock->unlock(this->lock); | |
478 | ||
301a0bad TB |
479 | if (wildcard) |
480 | { /* the peer config would match IKE_SAs with other peers */ | |
481 | ike_sa = charon->ike_sa_manager->checkout_new(charon->ike_sa_manager, | |
482 | peer->get_ike_version(peer), TRUE); | |
483 | if (ike_sa) | |
484 | { | |
485 | ike_cfg_t *ike_cfg; | |
486 | u_int16_t port; | |
487 | u_int8_t mask; | |
488 | ||
489 | ike_sa->set_peer_cfg(ike_sa, peer); | |
490 | ike_cfg = ike_sa->get_ike_cfg(ike_sa); | |
491 | ||
492 | port = ike_cfg->get_other_port(ike_cfg); | |
493 | dst->to_subnet(dst, &host, &mask); | |
494 | host->set_port(host, port); | |
495 | ike_sa->set_other_host(ike_sa, host); | |
496 | ||
497 | port = ike_cfg->get_my_port(ike_cfg); | |
498 | src->to_subnet(src, &host, &mask); | |
499 | host->set_port(host, port); | |
500 | ike_sa->set_my_host(ike_sa, host); | |
501 | ||
502 | charon->bus->set_sa(charon->bus, ike_sa); | |
503 | } | |
504 | } | |
505 | else | |
506 | { | |
507 | ike_sa = charon->ike_sa_manager->checkout_by_config( | |
fc726f13 | 508 | charon->ike_sa_manager, peer); |
301a0bad | 509 | } |
b1f2f05c | 510 | if (ike_sa) |
9d737ecf | 511 | { |
b1f2f05c | 512 | if (ike_sa->get_peer_cfg(ike_sa) == NULL) |
9d737ecf | 513 | { |
b1f2f05c MW |
514 | ike_sa->set_peer_cfg(ike_sa, peer); |
515 | } | |
7fa03b30 | 516 | if (this->ignore_acquire_ts || ike_sa->get_version(ike_sa) == IKEV1) |
777bcdc0 MW |
517 | { /* in IKEv1, don't prepend the acquiring packet TS, as we only |
518 | * have a single TS that we can establish in a Quick Mode. */ | |
519 | src = dst = NULL; | |
520 | } | |
a229bdce TB |
521 | |
522 | this->mutex->lock(this->mutex); | |
523 | acquire->ike_sa = ike_sa; | |
524 | this->mutex->unlock(this->mutex); | |
525 | ||
b1f2f05c MW |
526 | if (ike_sa->initiate(ike_sa, child, reqid, src, dst) != DESTROY_ME) |
527 | { | |
b1f2f05c MW |
528 | charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); |
529 | } | |
530 | else | |
531 | { | |
773fcb16 TB |
532 | charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, |
533 | ike_sa); | |
9d737ecf | 534 | } |
fc726f13 | 535 | } |
a229bdce TB |
536 | else |
537 | { | |
538 | this->mutex->lock(this->mutex); | |
539 | this->acquires->remove(this->acquires, acquire, NULL); | |
540 | this->mutex->unlock(this->mutex); | |
541 | destroy_acquire(acquire); | |
542 | child->destroy(child); | |
543 | } | |
fc726f13 | 544 | peer->destroy(peer); |
9d737ecf MW |
545 | } |
546 | ||
547 | /** | |
991f7ccd | 548 | * Complete the acquire, if successful or failed |
9d737ecf | 549 | */ |
991f7ccd MW |
550 | static void complete(private_trap_manager_t *this, ike_sa_t *ike_sa, |
551 | child_sa_t *child_sa) | |
9d737ecf | 552 | { |
9d737ecf | 553 | enumerator_t *enumerator; |
a229bdce | 554 | acquire_t *acquire; |
7daf5226 | 555 | |
a229bdce TB |
556 | this->mutex->lock(this->mutex); |
557 | enumerator = this->acquires->create_enumerator(this->acquires); | |
558 | while (enumerator->enumerate(enumerator, &acquire)) | |
9d737ecf | 559 | { |
a229bdce | 560 | if (!acquire->ike_sa || acquire->ike_sa != ike_sa) |
991f7ccd MW |
561 | { |
562 | continue; | |
563 | } | |
301a0bad | 564 | if (child_sa) |
9d737ecf | 565 | { |
301a0bad TB |
566 | if (acquire->dst) |
567 | { | |
568 | /* since every wildcard acquire results in a separate IKE_SA | |
569 | * there is no need to compare the destination address */ | |
570 | } | |
571 | else if (child_sa->get_reqid(child_sa) != acquire->reqid) | |
572 | { | |
573 | continue; | |
574 | } | |
9d737ecf | 575 | } |
a229bdce TB |
576 | this->acquires->remove_at(this->acquires, enumerator); |
577 | destroy_acquire(acquire); | |
9d737ecf MW |
578 | } |
579 | enumerator->destroy(enumerator); | |
a229bdce | 580 | this->mutex->unlock(this->mutex); |
991f7ccd MW |
581 | } |
582 | ||
06356a29 AS |
583 | METHOD(listener_t, ike_state_change, bool, |
584 | trap_listener_t *listener, ike_sa_t *ike_sa, ike_sa_state_t state) | |
991f7ccd MW |
585 | { |
586 | switch (state) | |
587 | { | |
588 | case IKE_DESTROYING: | |
589 | complete(listener->traps, ike_sa, NULL); | |
590 | return TRUE; | |
591 | default: | |
592 | return TRUE; | |
593 | } | |
594 | } | |
595 | ||
06356a29 AS |
596 | METHOD(listener_t, child_state_change, bool, |
597 | trap_listener_t *listener, ike_sa_t *ike_sa, child_sa_t *child_sa, | |
598 | child_sa_state_t state) | |
991f7ccd MW |
599 | { |
600 | switch (state) | |
601 | { | |
602 | case CHILD_INSTALLED: | |
603 | case CHILD_DESTROYING: | |
604 | complete(listener->traps, ike_sa, child_sa); | |
605 | return TRUE; | |
606 | default: | |
607 | return TRUE; | |
608 | } | |
eb8ed130 MW |
609 | } |
610 | ||
f8437dd8 MW |
611 | METHOD(trap_manager_t, flush, void, |
612 | private_trap_manager_t *this) | |
613 | { | |
d6656f11 | 614 | this->lock->write_lock(this->lock); |
12b3cdba TB |
615 | while (this->installing) |
616 | { | |
617 | this->condvar->wait(this->condvar, this->lock); | |
618 | } | |
a229bdce | 619 | this->traps->destroy_function(this->traps, (void*)destroy_entry); |
d6656f11 | 620 | this->traps = linked_list_create(); |
12b3cdba | 621 | this->installing = INSTALL_DISABLED; |
d6656f11 | 622 | this->lock->unlock(this->lock); |
f8437dd8 MW |
623 | } |
624 | ||
06356a29 AS |
625 | METHOD(trap_manager_t, destroy, void, |
626 | private_trap_manager_t *this) | |
eb8ed130 | 627 | { |
9d737ecf | 628 | charon->bus->remove_listener(charon->bus, &this->listener.listener); |
d6656f11 | 629 | this->traps->destroy_function(this->traps, (void*)destroy_entry); |
a229bdce | 630 | this->acquires->destroy_function(this->acquires, (void*)destroy_acquire); |
12b3cdba | 631 | this->condvar->destroy(this->condvar); |
a229bdce | 632 | this->mutex->destroy(this->mutex); |
fcb06fdb | 633 | this->lock->destroy(this->lock); |
eb8ed130 MW |
634 | free(this); |
635 | } | |
636 | ||
637 | /** | |
638 | * See header | |
639 | */ | |
06356a29 | 640 | trap_manager_t *trap_manager_create(void) |
eb8ed130 | 641 | { |
06356a29 AS |
642 | private_trap_manager_t *this; |
643 | ||
644 | INIT(this, | |
645 | .public = { | |
646 | .install = _install, | |
647 | .uninstall = _uninstall, | |
648 | .create_enumerator = _create_enumerator, | |
2dcfc698 | 649 | .find_reqid = _find_reqid, |
06356a29 | 650 | .acquire = _acquire, |
f8437dd8 | 651 | .flush = _flush, |
06356a29 AS |
652 | .destroy = _destroy, |
653 | }, | |
6a5c8ee7 MW |
654 | .listener = { |
655 | .traps = this, | |
656 | .listener = { | |
657 | .ike_state_change = _ike_state_change, | |
658 | .child_state_change = _child_state_change, | |
659 | }, | |
660 | }, | |
06356a29 | 661 | .traps = linked_list_create(), |
a229bdce TB |
662 | .acquires = linked_list_create(), |
663 | .mutex = mutex_create(MUTEX_TYPE_DEFAULT), | |
06356a29 | 664 | .lock = rwlock_create(RWLOCK_TYPE_DEFAULT), |
12b3cdba | 665 | .condvar = rwlock_condvar_create(), |
7fa03b30 TB |
666 | .ignore_acquire_ts = lib->settings->get_bool(lib->settings, |
667 | "%s.ignore_acquire_ts", FALSE, lib->ns), | |
06356a29 | 668 | ); |
9d737ecf | 669 | charon->bus->add_listener(charon->bus, &this->listener.listener); |
7daf5226 | 670 | |
eb8ed130 MW |
671 | return &this->public; |
672 | } |