2 * Copyright (C) 2011-2017 Tobias Brunner
3 * Copyright (C) 2009 Martin Willi
4 * HSR Hochschule fuer Technik Rapperswil
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>.
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
17 #include "trap_manager.h"
20 #include <threading/mutex.h>
21 #include <threading/rwlock.h>
22 #include <threading/rwlock_condvar.h>
23 #include <collections/linked_list.h>
25 #define INSTALL_DISABLED ((u_int)~0)
27 typedef struct private_trap_manager_t private_trap_manager_t
;
28 typedef struct trap_listener_t trap_listener_t
;
31 * listener to track acquires
33 struct trap_listener_t
{
36 * Implements listener interface
41 * points to trap_manager
43 private_trap_manager_t
*traps
;
47 * Private data of an trap_manager_t object.
49 struct private_trap_manager_t
{
52 * Public trap_manager_t interface.
54 trap_manager_t
public;
57 * Installed traps, as entry_t
62 * read write lock for traps list
67 * listener to track acquiring IKE_SAs
69 trap_listener_t listener
;
72 * list of acquires we currently handle
74 linked_list_t
*acquires
;
77 * mutex for list of acquires
82 * number of threads currently installing trap policies, or INSTALL_DISABLED
87 * condvar to signal trap policy installation
89 rwlock_condvar_t
*condvar
;
92 * Whether to ignore traffic selectors from acquires
94 bool ignore_acquire_ts
;
98 * A installed trap entry
101 /** name of the trapped CHILD_SA */
103 /** ref to peer_cfg to initiate */
104 peer_cfg_t
*peer_cfg
;
105 /** ref to instantiated CHILD_SA (i.e the trap policy) */
106 child_sa_t
*child_sa
;
107 /** TRUE in case of wildcard Transport Mode SA */
115 /** pending IKE_SA connecting upon acquire */
117 /** reqid of pending trap policy */
119 /** destination address (wildcard case) */
124 * actually uninstall and destroy an installed entry
126 static void destroy_entry(entry_t
*this)
128 this->child_sa
->destroy(this->child_sa
);
129 this->peer_cfg
->destroy(this->peer_cfg
);
135 * destroy a cached acquire entry
137 static void destroy_acquire(acquire_t
*this)
139 DESTROY_IF(this->dst
);
143 CALLBACK(acquire_by_reqid
, bool,
144 acquire_t
*this, va_list args
)
148 VA_ARGS_VGET(args
, reqid
);
149 return this->reqid
== reqid
;
152 CALLBACK(acquire_by_dst
, bool,
153 acquire_t
*this, va_list args
)
157 VA_ARGS_VGET(args
, dst
);
158 return this->dst
&& this->dst
->ip_equals(this->dst
, dst
);
162 * Check if any remote TS are dynamic
164 static bool dynamic_remote_ts(child_cfg_t
*child
)
166 enumerator_t
*enumerator
;
167 linked_list_t
*other_ts
;
168 traffic_selector_t
*ts
;
171 other_ts
= child
->get_traffic_selectors(child
, FALSE
, NULL
, NULL
, FALSE
);
172 enumerator
= other_ts
->create_enumerator(other_ts
);
173 while (enumerator
->enumerate(enumerator
, &ts
))
175 if (ts
->is_dynamic(ts
))
181 enumerator
->destroy(enumerator
);
182 other_ts
->destroy_offset(other_ts
, offsetof(traffic_selector_t
, destroy
));
186 METHOD(trap_manager_t
, install
, bool,
187 private_trap_manager_t
*this, peer_cfg_t
*peer
, child_cfg_t
*child
)
189 entry_t
*entry
, *found
= NULL
;
191 child_sa_t
*child_sa
;
193 linked_list_t
*my_ts
, *other_ts
, *list
;
194 enumerator_t
*enumerator
;
196 linked_list_t
*proposals
;
197 proposal_t
*proposal
;
198 protocol_id_t proto
= PROTO_ESP
;
199 bool result
= FALSE
, wildcard
= FALSE
;
201 /* try to resolve addresses */
202 ike_cfg
= peer
->get_ike_cfg(peer
);
203 other
= ike_cfg
->resolve_other(ike_cfg
, AF_UNSPEC
);
204 if (other
&& other
->is_anyaddr(other
) &&
205 child
->get_mode(child
) == MODE_TRANSPORT
)
207 /* allow wildcard for Transport Mode SAs */
208 me
= host_create_any(other
->get_family(other
));
211 else if (other
&& other
->is_anyaddr(other
))
213 other
->destroy(other
);
214 DBG1(DBG_CFG
, "installing trap failed, remote address unknown");
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");
227 me
= ike_cfg
->resolve_me(ike_cfg
, other
? other
->get_family(other
)
231 other
= host_create_any(me
? me
->get_family(me
) : AF_INET
);
233 other
->set_port(other
, ike_cfg
->get_other_port(ike_cfg
));
234 if ((!me
|| me
->is_anyaddr(me
)) && !other
->is_anyaddr(other
))
237 me
= charon
->kernel
->get_source_addr(charon
->kernel
, other
, NULL
);
241 me
= host_create_any(other
->get_family(other
));
243 me
->set_port(me
, ike_cfg
->get_my_port(ike_cfg
));
246 this->lock
->write_lock(this->lock
);
247 if (this->installing
== INSTALL_DISABLED
)
248 { /* flush() has been called */
249 this->lock
->unlock(this->lock
);
250 other
->destroy(other
);
254 enumerator
= this->traps
->create_enumerator(this->traps
);
255 while (enumerator
->enumerate(enumerator
, &entry
))
257 if (streq(entry
->name
, child
->get_name(child
)) &&
258 streq(entry
->peer_cfg
->get_name(entry
->peer_cfg
),
259 peer
->get_name(peer
)))
263 { /* replace it with an updated version, if already installed */
264 this->traps
->remove_at(this->traps
, enumerator
);
269 enumerator
->destroy(enumerator
);
273 if (!found
->child_sa
)
275 DBG1(DBG_CFG
, "CHILD_SA '%s' is already being routed", found
->name
);
276 this->lock
->unlock(this->lock
);
277 other
->destroy(other
);
281 /* config might have changed so update everything */
282 DBG1(DBG_CFG
, "updating already routed CHILD_SA '%s'", found
->name
);
286 .name
= strdup(child
->get_name(child
)),
287 .peer_cfg
= peer
->get_ref(peer
),
288 .wildcard
= wildcard
,
290 this->traps
->insert_first(this->traps
, entry
);
292 /* don't hold lock while creating CHILD_SA and installing policies */
293 this->lock
->unlock(this->lock
);
295 /* create and route CHILD_SA */
296 child_sa
= child_sa_create(me
, other
, child
, 0, FALSE
, 0, 0, 0, 0);
298 list
= linked_list_create_with_items(me
, NULL
);
299 my_ts
= child
->get_traffic_selectors(child
, TRUE
, NULL
, list
, FALSE
);
300 list
->destroy_offset(list
, offsetof(host_t
, destroy
));
302 list
= linked_list_create_with_items(other
, NULL
);
303 other_ts
= child
->get_traffic_selectors(child
, FALSE
, NULL
, list
, FALSE
);
304 list
->destroy_offset(list
, offsetof(host_t
, destroy
));
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
)
311 proto
= proposal
->get_protocol(proposal
);
313 proposals
->destroy_offset(proposals
, offsetof(proposal_t
, destroy
));
314 child_sa
->set_protocol(child_sa
, proto
);
315 child_sa
->set_mode(child_sa
, child
->get_mode(child
));
316 child_sa
->set_policies(child_sa
, my_ts
, other_ts
);
317 status
= child_sa
->install_policies(child_sa
);
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
)
322 DBG1(DBG_CFG
, "installing trap failed");
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
);
331 this->lock
->write_lock(this->lock
);
332 entry
->child_sa
= child_sa
;
333 this->lock
->unlock(this->lock
);
338 destroy_entry(found
);
340 this->lock
->write_lock(this->lock
);
341 /* do this at the end, so entries created temporarily are also destroyed */
343 this->condvar
->signal(this->condvar
);
344 this->lock
->unlock(this->lock
);
348 METHOD(trap_manager_t
, uninstall
, bool,
349 private_trap_manager_t
*this, char *peer
, char *child
)
351 enumerator_t
*enumerator
;
352 entry_t
*entry
, *found
= NULL
;
354 this->lock
->write_lock(this->lock
);
355 while (this->installing
)
357 this->condvar
->wait(this->condvar
, this->lock
);
359 enumerator
= this->traps
->create_enumerator(this->traps
);
360 while (enumerator
->enumerate(enumerator
, &entry
))
362 if (streq(entry
->name
, child
) &&
363 (!peer
|| streq(peer
, entry
->peer_cfg
->get_name(entry
->peer_cfg
))))
365 this->traps
->remove_at(this->traps
, enumerator
);
370 enumerator
->destroy(enumerator
);
371 this->lock
->unlock(this->lock
);
377 destroy_entry(found
);
381 CALLBACK(trap_filter
, bool,
382 rwlock_t
*lock
, enumerator_t
*orig
, va_list args
)
385 peer_cfg_t
**peer_cfg
;
386 child_sa_t
**child_sa
;
388 VA_ARGS_VGET(args
, peer_cfg
, child_sa
);
390 while (orig
->enumerate(orig
, &entry
))
392 if (!entry
->child_sa
)
393 { /* skip entries that are currently being installed */
398 *peer_cfg
= entry
->peer_cfg
;
402 *child_sa
= entry
->child_sa
;
409 METHOD(trap_manager_t
, create_enumerator
, enumerator_t
*,
410 private_trap_manager_t
*this)
412 this->lock
->read_lock(this->lock
);
413 return enumerator_create_filter(this->traps
->create_enumerator(this->traps
),
414 trap_filter
, this->lock
,
415 (void*)this->lock
->unlock
);
418 METHOD(trap_manager_t
, acquire
, void,
419 private_trap_manager_t
*this, uint32_t reqid
,
420 traffic_selector_t
*src
, traffic_selector_t
*dst
)
422 enumerator_t
*enumerator
;
423 entry_t
*entry
, *found
= NULL
;
429 bool wildcard
, ignore
= FALSE
;
431 this->lock
->read_lock(this->lock
);
432 enumerator
= this->traps
->create_enumerator(this->traps
);
433 while (enumerator
->enumerate(enumerator
, &entry
))
435 if (entry
->child_sa
&&
436 entry
->child_sa
->get_reqid(entry
->child_sa
) == reqid
)
442 enumerator
->destroy(enumerator
);
446 DBG1(DBG_CFG
, "trap not found, unable to acquire reqid %d", reqid
);
447 this->lock
->unlock(this->lock
);
450 reqid
= found
->child_sa
->get_reqid(found
->child_sa
);
451 wildcard
= found
->wildcard
;
453 this->mutex
->lock(this->mutex
);
455 { /* for wildcard acquires we check that we don't have a pending acquire
456 * with the same peer */
459 dst
->to_subnet(dst
, &host
, &mask
);
460 if (this->acquires
->find_first(this->acquires
, acquire_by_dst
,
461 (void**)&acquire
, host
))
472 this->acquires
->insert_last(this->acquires
, acquire
);
477 if (this->acquires
->find_first(this->acquires
, acquire_by_reqid
,
478 (void**)&acquire
, reqid
))
487 this->acquires
->insert_last(this->acquires
, acquire
);
490 this->mutex
->unlock(this->mutex
);
493 DBG1(DBG_CFG
, "ignoring acquire, connection attempt pending");
494 this->lock
->unlock(this->lock
);
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
);
500 /* don't hold the lock while checking out the IKE_SA */
501 this->lock
->unlock(this->lock
);
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
);
513 ike_sa
->set_peer_cfg(ike_sa
, peer
);
514 ike_cfg
= ike_sa
->get_ike_cfg(ike_sa
);
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
);
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
);
526 charon
->bus
->set_sa(charon
->bus
, ike_sa
);
531 ike_sa
= charon
->ike_sa_manager
->checkout_by_config(
532 charon
->ike_sa_manager
, peer
);
536 if (ike_sa
->get_peer_cfg(ike_sa
) == NULL
)
538 ike_sa
->set_peer_cfg(ike_sa
, peer
);
540 if (this->ignore_acquire_ts
|| ike_sa
->get_version(ike_sa
) == IKEV1
)
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. */
546 this->mutex
->lock(this->mutex
);
547 acquire
->ike_sa
= ike_sa
;
548 this->mutex
->unlock(this->mutex
);
550 if (ike_sa
->initiate(ike_sa
, child
, reqid
, src
, dst
) != DESTROY_ME
)
552 charon
->ike_sa_manager
->checkin(charon
->ike_sa_manager
, ike_sa
);
556 charon
->ike_sa_manager
->checkin_and_destroy(charon
->ike_sa_manager
,
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
);
572 * Complete the acquire, if successful or failed
574 static void complete(private_trap_manager_t
*this, ike_sa_t
*ike_sa
,
575 child_sa_t
*child_sa
)
577 enumerator_t
*enumerator
;
580 this->mutex
->lock(this->mutex
);
581 enumerator
= this->acquires
->create_enumerator(this->acquires
);
582 while (enumerator
->enumerate(enumerator
, &acquire
))
584 if (!acquire
->ike_sa
|| acquire
->ike_sa
!= ike_sa
)
592 /* since every wildcard acquire results in a separate IKE_SA
593 * there is no need to compare the destination address */
595 else if (child_sa
->get_reqid(child_sa
) != acquire
->reqid
)
600 this->acquires
->remove_at(this->acquires
, enumerator
);
601 destroy_acquire(acquire
);
603 enumerator
->destroy(enumerator
);
604 this->mutex
->unlock(this->mutex
);
607 METHOD(listener_t
, ike_state_change
, bool,
608 trap_listener_t
*listener
, ike_sa_t
*ike_sa
, ike_sa_state_t state
)
613 complete(listener
->traps
, ike_sa
, NULL
);
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
)
626 case CHILD_INSTALLED
:
627 case CHILD_DESTROYING
:
628 complete(listener
->traps
, ike_sa
, child_sa
);
635 METHOD(trap_manager_t
, flush
, void,
636 private_trap_manager_t
*this)
638 this->lock
->write_lock(this->lock
);
639 while (this->installing
)
641 this->condvar
->wait(this->condvar
, this->lock
);
643 this->traps
->destroy_function(this->traps
, (void*)destroy_entry
);
644 this->traps
= linked_list_create();
645 this->installing
= INSTALL_DISABLED
;
646 this->lock
->unlock(this->lock
);
649 METHOD(trap_manager_t
, destroy
, void,
650 private_trap_manager_t
*this)
652 charon
->bus
->remove_listener(charon
->bus
, &this->listener
.listener
);
653 this->traps
->destroy_function(this->traps
, (void*)destroy_entry
);
654 this->acquires
->destroy_function(this->acquires
, (void*)destroy_acquire
);
655 this->condvar
->destroy(this->condvar
);
656 this->mutex
->destroy(this->mutex
);
657 this->lock
->destroy(this->lock
);
664 trap_manager_t
*trap_manager_create(void)
666 private_trap_manager_t
*this;
671 .uninstall
= _uninstall
,
672 .create_enumerator
= _create_enumerator
,
680 .ike_state_change
= _ike_state_change
,
681 .child_state_change
= _child_state_change
,
684 .traps
= linked_list_create(),
685 .acquires
= linked_list_create(),
686 .mutex
= mutex_create(MUTEX_TYPE_DEFAULT
),
687 .lock
= rwlock_create(RWLOCK_TYPE_DEFAULT
),
688 .condvar
= rwlock_condvar_create(),
689 .ignore_acquire_ts
= lib
->settings
->get_bool(lib
->settings
,
690 "%s.ignore_acquire_ts", FALSE
, lib
->ns
),
692 charon
->bus
->add_listener(charon
->bus
, &this->listener
.listener
);
694 return &this->public;