2 * Copyright (C) 2011-2017 Tobias Brunner
3 * Copyright (C) 2009 Martin Willi
5 * Copyright (C) secunet Security Networks AG
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>.
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
18 #include "trap_manager.h"
21 #include <threading/mutex.h>
22 #include <threading/rwlock.h>
23 #include <threading/rwlock_condvar.h>
24 #include <collections/linked_list.h>
26 #define INSTALL_DISABLED ((u_int)~0)
28 typedef struct private_trap_manager_t private_trap_manager_t
;
29 typedef struct trap_listener_t trap_listener_t
;
32 * listener to track acquires
34 struct trap_listener_t
{
37 * Implements listener interface
42 * points to trap_manager
44 private_trap_manager_t
*traps
;
48 * Private data of an trap_manager_t object.
50 struct private_trap_manager_t
{
53 * Public trap_manager_t interface.
55 trap_manager_t
public;
58 * Installed traps, as entry_t
63 * read write lock for traps list
68 * listener to track acquiring IKE_SAs
70 trap_listener_t listener
;
73 * list of acquires we currently handle
75 linked_list_t
*acquires
;
78 * mutex for list of acquires
83 * number of threads currently installing trap policies, or INSTALL_DISABLED
88 * condvar to signal trap policy installation
90 rwlock_condvar_t
*condvar
;
93 * Whether to ignore traffic selectors from acquires
95 bool ignore_acquire_ts
;
98 * Current acquire sequence number if not generated by the kernel
100 refcount_t acquire_seq
;
104 * A installed trap entry
107 /** name of the trapped CHILD_SA */
109 /** ref to peer_cfg to initiate */
110 peer_cfg_t
*peer_cfg
;
111 /** ref to instantiated CHILD_SA (i.e the trap policy) */
112 child_sa_t
*child_sa
;
113 /** TRUE in case of wildcard Transport Mode SA */
115 /** TRUE for CHILD_SAs that are externally managed */
123 /** pending IKE_SA connecting upon acquire */
125 /** reqid of pending trap policy */
127 /** destination address (wildcard case) */
129 /** data from the kernel */
130 kernel_acquire_data_t
*data
;
131 /** optional sequence number from the kernel if an acquire is retriggered */
136 * actually uninstall and destroy an installed entry
138 static void destroy_entry(entry_t
*this)
142 this->child_sa
->destroy(this->child_sa
);
144 this->peer_cfg
->destroy(this->peer_cfg
);
150 * destroy a cached acquire entry
152 static void destroy_acquire(acquire_t
*this)
154 DESTROY_IF(this->dst
);
155 kernel_acquire_data_destroy(this->data
);
159 CALLBACK(acquire_by_reqid
, bool,
160 acquire_t
*this, va_list args
)
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
);
170 CALLBACK(acquire_by_dst
, bool,
171 acquire_t
*this, va_list args
)
175 VA_ARGS_VGET(args
, dst
);
176 return this->dst
&& this->dst
->ip_equals(this->dst
, dst
);
180 * Check if any remote TS are dynamic
182 static bool dynamic_remote_ts(child_cfg_t
*child
)
184 enumerator_t
*enumerator
;
185 linked_list_t
*other_ts
;
186 traffic_selector_t
*ts
;
189 other_ts
= child
->get_traffic_selectors(child
, FALSE
, NULL
);
190 enumerator
= other_ts
->create_enumerator(other_ts
);
191 while (enumerator
->enumerate(enumerator
, &ts
))
193 if (ts
->is_dynamic(ts
))
199 enumerator
->destroy(enumerator
);
200 other_ts
->destroy_offset(other_ts
, offsetof(traffic_selector_t
, destroy
));
205 * Install the given trap
207 static status_t
install_trap(child_sa_t
*child_sa
, linked_list_t
*local
,
208 linked_list_t
*remote
)
210 linked_list_t
*my_ts
, *other_ts
, *proposals
;
211 proposal_t
*proposal
;
213 protocol_id_t proto
= PROTO_ESP
;
215 child
= child_sa
->get_config(child_sa
);
217 my_ts
= child
->get_traffic_selectors(child
, TRUE
, local
);
218 other_ts
= child
->get_traffic_selectors(child
, FALSE
, remote
);
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
)
225 proto
= proposal
->get_protocol(proposal
);
227 proposals
->destroy_offset(proposals
, offsetof(proposal_t
, destroy
));
229 child_sa
->set_protocol(child_sa
, proto
);
230 child_sa
->set_mode(child_sa
, child
->get_mode(child
));
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
));
236 return child_sa
->install_policies(child_sa
);
239 METHOD(trap_manager_t
, install
, bool,
240 private_trap_manager_t
*this, peer_cfg_t
*peer
, child_cfg_t
*child
)
242 entry_t
*entry
, *found
= NULL
;
244 child_sa_t
*child_sa
;
246 linked_list_t
*local
, *remote
;
247 enumerator_t
*enumerator
;
249 bool result
= FALSE
, wildcard
= FALSE
;
251 /* try to resolve addresses */
252 ike_cfg
= peer
->get_ike_cfg(peer
);
253 other
= ike_cfg
->resolve_other(ike_cfg
, AF_UNSPEC
);
254 if (other
&& other
->is_anyaddr(other
) &&
255 child
->get_mode(child
) == MODE_TRANSPORT
)
257 /* allow wildcard for Transport Mode SAs */
258 me
= host_create_any(other
->get_family(other
));
261 else if (other
&& other
->is_anyaddr(other
))
263 other
->destroy(other
);
264 DBG1(DBG_CFG
, "installing trap failed, remote address unknown");
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");
277 me
= ike_cfg
->resolve_me(ike_cfg
, other
? other
->get_family(other
)
281 other
= host_create_any(me
? me
->get_family(me
) : AF_INET
);
283 other
->set_port(other
, ike_cfg
->get_other_port(ike_cfg
));
284 if ((!me
|| me
->is_anyaddr(me
)) && !other
->is_anyaddr(other
))
287 me
= charon
->kernel
->get_source_addr(charon
->kernel
, other
, NULL
);
291 me
= host_create_any(other
->get_family(other
));
293 me
->set_port(me
, ike_cfg
->get_my_port(ike_cfg
));
296 this->lock
->write_lock(this->lock
);
297 if (this->installing
== INSTALL_DISABLED
)
298 { /* flush() has been called */
299 this->lock
->unlock(this->lock
);
300 other
->destroy(other
);
304 enumerator
= this->traps
->create_enumerator(this->traps
);
305 while (enumerator
->enumerate(enumerator
, &entry
))
307 if (!entry
->external
&&
308 streq(entry
->name
, child
->get_name(child
)) &&
309 streq(entry
->peer_cfg
->get_name(entry
->peer_cfg
),
310 peer
->get_name(peer
)))
314 { /* replace it with an updated version if already installed */
315 this->traps
->remove_at(this->traps
, enumerator
);
320 enumerator
->destroy(enumerator
);
324 if (!found
->child_sa
)
326 DBG1(DBG_CFG
, "CHILD_SA '%s' is already being routed", found
->name
);
327 this->lock
->unlock(this->lock
);
328 other
->destroy(other
);
332 /* config might have changed so update everything */
333 DBG1(DBG_CFG
, "updating already routed CHILD_SA '%s'", found
->name
);
337 .name
= strdup(child
->get_name(child
)),
338 .peer_cfg
= peer
->get_ref(peer
),
339 .wildcard
= wildcard
,
341 this->traps
->insert_first(this->traps
, entry
);
343 /* don't hold lock while creating CHILD_SA and installing policies */
344 this->lock
->unlock(this->lock
);
346 /* create and route CHILD_SA */
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
),
355 child_sa
= child_sa_create(me
, other
, child
, &child_data
);
357 local
= linked_list_create_with_items(me
, NULL
);
358 remote
= linked_list_create_with_items(other
, NULL
);
360 status
= install_trap(child_sa
, local
, remote
);
362 local
->destroy_offset(local
, offsetof(host_t
, destroy
));
363 remote
->destroy_offset(remote
, offsetof(host_t
, destroy
));
364 if (status
!= SUCCESS
)
366 DBG1(DBG_CFG
, "installing trap failed");
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
);
375 this->lock
->write_lock(this->lock
);
376 entry
->child_sa
= child_sa
;
377 this->lock
->unlock(this->lock
);
382 destroy_entry(found
);
384 this->lock
->write_lock(this->lock
);
385 /* do this at the end, so entries created temporarily are also destroyed */
387 this->condvar
->signal(this->condvar
);
388 this->lock
->unlock(this->lock
);
392 METHOD(trap_manager_t
, uninstall
, bool,
393 private_trap_manager_t
*this, char *peer
, char *child
)
395 enumerator_t
*enumerator
;
396 entry_t
*entry
, *found
= NULL
;
398 this->lock
->write_lock(this->lock
);
399 while (this->installing
)
401 this->condvar
->wait(this->condvar
, this->lock
);
403 enumerator
= this->traps
->create_enumerator(this->traps
);
404 while (enumerator
->enumerate(enumerator
, &entry
))
406 if (!entry
->external
&&
407 streq(entry
->name
, child
) &&
408 (!peer
|| streq(peer
, entry
->peer_cfg
->get_name(entry
->peer_cfg
))))
410 this->traps
->remove_at(this->traps
, enumerator
);
415 enumerator
->destroy(enumerator
);
416 this->lock
->unlock(this->lock
);
422 destroy_entry(found
);
426 METHOD(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
)
432 this->lock
->write_lock(this->lock
);
433 if (this->installing
== INSTALL_DISABLED
)
434 { /* flush() has been called */
435 this->lock
->unlock(this->lock
);
440 .name
= strdup(child
->get_name(child
)),
441 .peer_cfg
= peer
->get_ref(peer
),
445 this->traps
->insert_first(this->traps
, entry
);
446 this->lock
->unlock(this->lock
);
448 if (install_trap(child
, local
, remote
) != SUCCESS
)
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
);
460 METHOD(trap_manager_t
, remove_external
, bool,
461 private_trap_manager_t
*this, child_sa_t
*child
)
463 enumerator_t
*enumerator
;
464 entry_t
*entry
, *found
= NULL
;
466 this->lock
->write_lock(this->lock
);
467 enumerator
= this->traps
->create_enumerator(this->traps
);
468 while (enumerator
->enumerate(enumerator
, &entry
))
470 if (entry
->external
&& entry
->child_sa
== child
)
472 this->traps
->remove_at(this->traps
, enumerator
);
477 enumerator
->destroy(enumerator
);
478 this->lock
->unlock(this->lock
);
484 destroy_entry(found
);
488 CALLBACK(trap_filter
, bool,
489 rwlock_t
*lock
, enumerator_t
*orig
, va_list args
)
492 peer_cfg_t
**peer_cfg
;
493 child_sa_t
**child_sa
;
495 VA_ARGS_VGET(args
, peer_cfg
, child_sa
);
497 while (orig
->enumerate(orig
, &entry
))
499 if (!entry
->child_sa
|| entry
->external
)
500 { /* skip entries that are currently being installed or are managed
506 *peer_cfg
= entry
->peer_cfg
;
510 *child_sa
= entry
->child_sa
;
517 METHOD(trap_manager_t
, create_enumerator
, enumerator_t
*,
518 private_trap_manager_t
*this)
520 this->lock
->read_lock(this->lock
);
521 return enumerator_create_filter(this->traps
->create_enumerator(this->traps
),
522 trap_filter
, this->lock
,
523 (void*)this->lock
->unlock
);
526 METHOD(trap_manager_t
, acquire
, void,
527 private_trap_manager_t
*this, uint32_t reqid
, kernel_acquire_data_t
*data
)
529 enumerator_t
*enumerator
;
530 entry_t
*entry
, *found
= NULL
;
531 acquire_t
*acquire
= NULL
;
536 uint32_t allocated_reqid
, seq
= 0;
539 this->lock
->read_lock(this->lock
);
540 enumerator
= this->traps
->create_enumerator(this->traps
);
541 while (enumerator
->enumerate(enumerator
, &entry
))
543 if (entry
->child_sa
&&
544 entry
->child_sa
->get_reqid(entry
->child_sa
) == reqid
)
550 enumerator
->destroy(enumerator
);
554 DBG1(DBG_CFG
, "trap not found, unable to acquire reqid %d", reqid
);
555 this->lock
->unlock(this->lock
);
558 wildcard
= found
->wildcard
;
560 this->mutex
->lock(this->mutex
);
563 /* for wildcard acquires we check that we don't have a pending acquire
564 * with the same peer */
567 data
->dst
->to_subnet(data
->dst
, &host
, &mask
);
568 if (this->acquires
->find_first(this->acquires
, acquire_by_dst
,
569 (void**)&acquire
, host
))
576 this->acquires
->find_first(this->acquires
, acquire_by_reqid
,
577 (void**)&acquire
, reqid
, data
->cpu
,
585 .data
= kernel_acquire_data_clone(data
),
587 seq
= data
->seq
= data
->seq
?: ref_get_nonzero(&this->acquire_seq
);
588 this->acquires
->insert_last(this->acquires
, acquire
);
590 else if (data
->seq
&& data
->seq
!= acquire
->data
->seq
)
592 /* acquire got retriggered, update to latest sequence number */
593 acquire
->new_seq
= data
->seq
;
595 this->mutex
->unlock(this->mutex
);
598 DBG1(DBG_CFG
, "ignoring acquire for reqid %u, connection attempt "
600 this->lock
->unlock(this->lock
);
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
);
606 /* only pass allocated reqids explicitly, take a reference */
607 allocated_reqid
= found
->child_sa
->get_reqid_ref(found
->child_sa
);
608 /* don't hold the lock while checking out the IKE_SA */
609 this->lock
->unlock(this->lock
);
612 { /* the peer config would match IKE_SAs with other peers */
613 ike_sa
= charon
->ike_sa_manager
->create_new(charon
->ike_sa_manager
,
614 peer
->get_ike_version(peer
), TRUE
);
621 ike_sa
->set_peer_cfg(ike_sa
, peer
);
622 ike_cfg
= ike_sa
->get_ike_cfg(ike_sa
);
624 port
= ike_cfg
->get_other_port(ike_cfg
);
625 data
->dst
->to_subnet(data
->dst
, &host
, &mask
);
626 host
->set_port(host
, port
);
627 ike_sa
->set_other_host(ike_sa
, host
);
629 port
= ike_cfg
->get_my_port(ike_cfg
);
630 data
->src
->to_subnet(data
->src
, &host
, &mask
);
631 host
->set_port(host
, port
);
632 ike_sa
->set_my_host(ike_sa
, host
);
634 charon
->bus
->set_sa(charon
->bus
, ike_sa
);
639 ike_sa
= charon
->ike_sa_manager
->checkout_by_config(
640 charon
->ike_sa_manager
, peer
);
646 child_init_args_t args
= {
647 .reqid
= allocated_reqid
,
651 .label
= data
->label
,
655 if (this->ignore_acquire_ts
|| ike_sa
->get_version(ike_sa
) == IKEV1
)
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. */
658 args
.src
= args
.dst
= NULL
;
661 this->mutex
->lock(this->mutex
);
662 acquire
->ike_sa
= ike_sa
;
663 this->mutex
->unlock(this->mutex
);
665 if (ike_sa
->initiate(ike_sa
, child
, &args
) != DESTROY_ME
)
667 charon
->ike_sa_manager
->checkin(charon
->ike_sa_manager
, ike_sa
);
671 charon
->ike_sa_manager
->checkin_and_destroy(charon
->ike_sa_manager
,
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
);
685 charon
->kernel
->release_reqid(charon
->kernel
, allocated_reqid
);
690 * Update the sequence number of the CHILD_SA before installing it in case
691 * the acquire got retriggered.
693 static void update_acquire_seq(private_trap_manager_t
*this, ike_sa_t
*ike_sa
,
694 child_sa_t
*child_sa
)
696 enumerator_t
*enumerator
;
700 /* ignore trap policies */
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
);
711 !(charon
->kernel
->get_features(charon
->kernel
) & KERNEL_ACQUIRE_SEQ
))
716 this->mutex
->lock(this->mutex
);
717 enumerator
= this->acquires
->create_enumerator(this->acquires
);
718 while (enumerator
->enumerate(enumerator
, &acquire
))
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
,
729 child_sa
->set_acquire_seq(child_sa
, acquire
->data
->seq
);
731 else if (!acquire
->ike_sa
|| seq
!= acquire
->data
->seq
)
735 if (acquire
->new_seq
)
737 child_sa
->set_acquire_seq(child_sa
, acquire
->new_seq
);
738 acquire
->data
->seq
= acquire
->new_seq
;
739 acquire
->new_seq
= 0;
743 enumerator
->destroy(enumerator
);
744 this->mutex
->unlock(this->mutex
);
748 * Complete the acquire, if successful or failed.
750 static void complete(private_trap_manager_t
*this, ike_sa_t
*ike_sa
,
751 child_sa_t
*child_sa
)
753 enumerator_t
*enumerator
;
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
))))
763 this->mutex
->lock(this->mutex
);
764 enumerator
= this->acquires
->create_enumerator(this->acquires
);
765 while (enumerator
->enumerate(enumerator
, &acquire
))
767 /* just look at the sequence number when handling a CHILD_SA event,
768 * otherwise, compare the IKE_SA */
769 if (!acquire
->ike_sa
|| (seq
&& seq
!= acquire
->data
->seq
) ||
770 (!seq
&& acquire
->ike_sa
!= ike_sa
))
774 this->acquires
->remove_at(this->acquires
, enumerator
);
775 destroy_acquire(acquire
);
777 enumerator
->destroy(enumerator
);
778 this->mutex
->unlock(this->mutex
);
781 METHOD(listener_t
, ike_state_change
, bool,
782 trap_listener_t
*listener
, ike_sa_t
*ike_sa
, ike_sa_state_t state
)
787 complete(listener
->traps
, ike_sa
, NULL
);
794 METHOD(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
)
800 case CHILD_INSTALLING
:
801 update_acquire_seq(listener
->traps
, ike_sa
, child_sa
);
803 case CHILD_INSTALLED
:
804 case CHILD_DESTROYING
:
805 complete(listener
->traps
, ike_sa
, child_sa
);
812 METHOD(trap_manager_t
, flush
, void,
813 private_trap_manager_t
*this)
815 this->lock
->write_lock(this->lock
);
816 while (this->installing
)
818 this->condvar
->wait(this->condvar
, this->lock
);
820 this->traps
->destroy_function(this->traps
, (void*)destroy_entry
);
821 this->traps
= linked_list_create();
822 this->installing
= INSTALL_DISABLED
;
823 this->lock
->unlock(this->lock
);
826 METHOD(trap_manager_t
, destroy
, void,
827 private_trap_manager_t
*this)
829 charon
->bus
->remove_listener(charon
->bus
, &this->listener
.listener
);
830 this->traps
->destroy_function(this->traps
, (void*)destroy_entry
);
831 this->acquires
->destroy_function(this->acquires
, (void*)destroy_acquire
);
832 this->condvar
->destroy(this->condvar
);
833 this->mutex
->destroy(this->mutex
);
834 this->lock
->destroy(this->lock
);
841 trap_manager_t
*trap_manager_create(void)
843 private_trap_manager_t
*this;
848 .uninstall
= _uninstall
,
849 .install_external
= _install_external
,
850 .remove_external
= _remove_external
,
851 .create_enumerator
= _create_enumerator
,
859 .ike_state_change
= _ike_state_change
,
860 .child_state_change
= _child_state_change
,
863 .traps
= linked_list_create(),
864 .acquires
= linked_list_create(),
865 .mutex
= mutex_create(MUTEX_TYPE_DEFAULT
),
866 .lock
= rwlock_create(RWLOCK_TYPE_DEFAULT
),
867 .condvar
= rwlock_condvar_create(),
868 .ignore_acquire_ts
= lib
->settings
->get_bool(lib
->settings
,
869 "%s.ignore_acquire_ts", FALSE
, lib
->ns
),
871 charon
->bus
->add_listener(charon
->bus
, &this->listener
.listener
);
873 return &this->public;