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