2 * Copyright (C) 2009 Martin Willi
3 * Hochschule fuer Technik Rapperswil
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 #include "trap_manager.h"
20 #include <threading/rwlock.h>
21 #include <utils/linked_list.h>
24 typedef struct private_trap_manager_t private_trap_manager_t
;
25 typedef struct trap_listener_t trap_listener_t
;
28 * listener to track acquires
30 struct trap_listener_t
{
33 * Implements listener interface
38 * points to trap_manager
40 private_trap_manager_t
*traps
;
44 * Private data of an trap_manager_t object.
46 struct private_trap_manager_t
{
49 * Public trap_manager_t interface.
51 trap_manager_t
public;
54 * Installed traps, as entry_t
59 * read write lock for traps list
64 * listener to track acquiring IKE_SAs
66 trap_listener_t listener
;
70 * A installed trap entry
73 /** ref to peer_cfg to initiate */
75 /** ref to instanciated CHILD_SA */
77 /** pending IKE_SA connecting upon acquire */
82 * actually uninstall and destroy an installed entry
84 static void destroy_entry(entry_t
*entry
)
86 entry
->child_sa
->destroy(entry
->child_sa
);
87 entry
->peer_cfg
->destroy(entry
->peer_cfg
);
91 METHOD(trap_manager_t
, install
, u_int32_t
,
92 private_trap_manager_t
*this, peer_cfg_t
*peer
, child_cfg_t
*child
)
98 linked_list_t
*my_ts
, *other_ts
;
99 enumerator_t
*enumerator
;
104 /* check if not already done */
105 this->lock
->read_lock(this->lock
);
106 enumerator
= this->traps
->create_enumerator(this->traps
);
107 while (enumerator
->enumerate(enumerator
, &entry
))
109 if (streq(entry
->child_sa
->get_name(entry
->child_sa
),
110 child
->get_name(child
)))
116 enumerator
->destroy(enumerator
);
117 this->lock
->unlock(this->lock
);
120 DBG1(DBG_CFG
, "CHILD_SA named '%s' already routed",
121 child
->get_name(child
));
125 /* try to resolve addresses */
126 ike_cfg
= peer
->get_ike_cfg(peer
);
127 other
= host_create_from_dns(ike_cfg
->get_other_addr(ike_cfg
),
128 0, ike_cfg
->get_other_port(ike_cfg
));
129 if (!other
|| other
->is_anyaddr(other
))
131 DBG1(DBG_CFG
, "installing trap failed, remote address unknown");
134 me
= host_create_from_dns(ike_cfg
->get_my_addr(ike_cfg
),
135 other
->get_family(other
), ike_cfg
->get_my_port(ike_cfg
));
136 if (!me
|| me
->is_anyaddr(me
))
139 me
= hydra
->kernel_interface
->get_source_addr(
140 hydra
->kernel_interface
, other
, NULL
);
143 DBG1(DBG_CFG
, "installing trap failed, local address unknown");
144 other
->destroy(other
);
147 me
->set_port(me
, ike_cfg
->get_my_port(ike_cfg
));
150 /* create and route CHILD_SA */
151 child_sa
= child_sa_create(me
, other
, child
, 0, FALSE
);
152 my_ts
= child
->get_traffic_selectors(child
, TRUE
, NULL
, me
);
153 other_ts
= child
->get_traffic_selectors(child
, FALSE
, NULL
, other
);
155 other
->destroy(other
);
157 /* while we don't know the finally negotiated protocol (ESP|AH), we
158 * could iterate all proposals for a best guess (TODO). But as we
159 * support ESP only for now, we set it here. */
160 child_sa
->set_protocol(child_sa
, PROTO_ESP
);
161 child_sa
->set_mode(child_sa
, child
->get_mode(child
));
162 status
= child_sa
->add_policies(child_sa
, my_ts
, other_ts
);
163 my_ts
->destroy_offset(my_ts
, offsetof(traffic_selector_t
, destroy
));
164 other_ts
->destroy_offset(other_ts
, offsetof(traffic_selector_t
, destroy
));
165 if (status
!= SUCCESS
)
167 child_sa
->destroy(child_sa
);
168 DBG1(DBG_CFG
, "installing trap failed");
172 reqid
= child_sa
->get_reqid(child_sa
);
173 entry
= malloc_thing(entry_t
);
174 entry
->child_sa
= child_sa
;
175 entry
->peer_cfg
= peer
->get_ref(peer
);
176 entry
->pending
= NULL
;
178 this->lock
->write_lock(this->lock
);
179 this->traps
->insert_last(this->traps
, entry
);
180 this->lock
->unlock(this->lock
);
185 METHOD(trap_manager_t
, uninstall
, bool,
186 private_trap_manager_t
*this, u_int32_t reqid
)
188 enumerator_t
*enumerator
;
189 entry_t
*entry
, *found
= NULL
;
191 this->lock
->write_lock(this->lock
);
192 enumerator
= this->traps
->create_enumerator(this->traps
);
193 while (enumerator
->enumerate(enumerator
, &entry
))
195 if (entry
->child_sa
->get_reqid(entry
->child_sa
) == reqid
)
197 this->traps
->remove_at(this->traps
, enumerator
);
202 enumerator
->destroy(enumerator
);
203 this->lock
->unlock(this->lock
);
207 DBG1(DBG_CFG
, "trap %d not found to uninstall", reqid
);
211 destroy_entry(found
);
216 * convert enumerated entries to peer_cfg, child_sa
218 static bool trap_filter(rwlock_t
*lock
, entry_t
**entry
, peer_cfg_t
**peer_cfg
,
219 void *none
, child_sa_t
**child_sa
)
223 *peer_cfg
= (*entry
)->peer_cfg
;
227 *child_sa
= (*entry
)->child_sa
;
232 METHOD(trap_manager_t
, create_enumerator
, enumerator_t
*,
233 private_trap_manager_t
*this)
235 this->lock
->read_lock(this->lock
);
236 return enumerator_create_filter(this->traps
->create_enumerator(this->traps
),
237 (void*)trap_filter
, this->lock
,
238 (void*)this->lock
->unlock
);
241 METHOD(trap_manager_t
, acquire
, void,
242 private_trap_manager_t
*this, u_int32_t reqid
,
243 traffic_selector_t
*src
, traffic_selector_t
*dst
)
245 enumerator_t
*enumerator
;
246 entry_t
*entry
, *found
= NULL
;
251 this->lock
->read_lock(this->lock
);
252 enumerator
= this->traps
->create_enumerator(this->traps
);
253 while (enumerator
->enumerate(enumerator
, &entry
))
255 if (entry
->child_sa
->get_reqid(entry
->child_sa
) == reqid
)
261 enumerator
->destroy(enumerator
);
265 DBG1(DBG_CFG
, "trap not found, unable to acquire reqid %d",reqid
);
267 else if (found
->pending
)
269 DBG1(DBG_CFG
, "ignoring acquire, connection attempt pending");
273 child
= found
->child_sa
->get_config(found
->child_sa
);
274 peer
= found
->peer_cfg
;
275 ike_sa
= charon
->ike_sa_manager
->checkout_by_config(
276 charon
->ike_sa_manager
, peer
);
279 if (ike_sa
->get_peer_cfg(ike_sa
) == NULL
)
281 ike_sa
->set_peer_cfg(ike_sa
, peer
);
283 child
->get_ref(child
);
284 reqid
= found
->child_sa
->get_reqid(found
->child_sa
);
285 if (ike_sa
->initiate(ike_sa
, child
, reqid
, src
, dst
) != DESTROY_ME
)
287 found
->pending
= ike_sa
;
288 charon
->ike_sa_manager
->checkin(charon
->ike_sa_manager
, ike_sa
);
292 charon
->ike_sa_manager
->checkin_and_destroy(
293 charon
->ike_sa_manager
, ike_sa
);
297 this->lock
->unlock(this->lock
);
301 * Complete the acquire, if successful or failed
303 static void complete(private_trap_manager_t
*this, ike_sa_t
*ike_sa
,
304 child_sa_t
*child_sa
)
306 enumerator_t
*enumerator
;
309 this->lock
->read_lock(this->lock
);
310 enumerator
= this->traps
->create_enumerator(this->traps
);
311 while (enumerator
->enumerate(enumerator
, &entry
))
313 if (entry
->pending
!= ike_sa
)
317 if (child_sa
&& child_sa
->get_reqid(child_sa
) !=
318 entry
->child_sa
->get_reqid(entry
->child_sa
))
322 entry
->pending
= NULL
;
324 enumerator
->destroy(enumerator
);
325 this->lock
->unlock(this->lock
);
328 METHOD(listener_t
, ike_state_change
, bool,
329 trap_listener_t
*listener
, ike_sa_t
*ike_sa
, ike_sa_state_t state
)
334 complete(listener
->traps
, ike_sa
, NULL
);
341 METHOD(listener_t
, child_state_change
, bool,
342 trap_listener_t
*listener
, ike_sa_t
*ike_sa
, child_sa_t
*child_sa
,
343 child_sa_state_t state
)
347 case CHILD_INSTALLED
:
348 case CHILD_DESTROYING
:
349 complete(listener
->traps
, ike_sa
, child_sa
);
356 METHOD(trap_manager_t
, flush
, void,
357 private_trap_manager_t
*this)
359 this->traps
->invoke_function(this->traps
, (void*)destroy_entry
);
362 METHOD(trap_manager_t
, destroy
, void,
363 private_trap_manager_t
*this)
365 charon
->bus
->remove_listener(charon
->bus
, &this->listener
.listener
);
366 this->traps
->invoke_function(this->traps
, (void*)destroy_entry
);
367 this->traps
->destroy(this->traps
);
368 this->lock
->destroy(this->lock
);
375 trap_manager_t
*trap_manager_create(void)
377 private_trap_manager_t
*this;
382 .uninstall
= _uninstall
,
383 .create_enumerator
= _create_enumerator
,
391 .ike_state_change
= _ike_state_change
,
392 .child_state_change
= _child_state_change
,
395 .traps
= linked_list_create(),
396 .lock
= rwlock_create(RWLOCK_TYPE_DEFAULT
),
398 charon
->bus
->add_listener(charon
->bus
, &this->listener
.listener
);
400 return &this->public;