]> git.ipfire.org Git - thirdparty/strongswan.git/blame - src/charon/sa/trap_manager.c
initiate trapped CHILD_SAs with same reqid
[thirdparty/strongswan.git] / src / charon / sa / trap_manager.c
CommitLineData
eb8ed130
MW
1/*
2 * Copyright (C) 2009 Martin Willi
3 * Hochschule fuer Technik Rapperswil
4 *
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>.
9 *
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
13 * for more details.
eb8ed130
MW
14 */
15
16#include "trap_manager.h"
17
18#include <daemon.h>
19#include <utils/mutex.h>
20#include <utils/linked_list.h>
21
22
23typedef struct private_trap_manager_t private_trap_manager_t;
24
25/**
26 * Private data of an trap_manager_t object.
27 */
28struct private_trap_manager_t {
29
30 /**
31 * Public trap_manager_t interface.
32 */
33 trap_manager_t public;
34
35 /**
36 * Installed traps, as entry_t
37 */
38 linked_list_t *traps;
39
40 /**
41 * mutex to lock traps list
42 */
43 mutex_t *mutex;
44};
45
46/**
47 * A installed trap entry
48 */
49typedef struct {
50 /** ref to peer_cfg to initiate */
51 peer_cfg_t *peer_cfg;
52 /** ref to instanciated CHILD_SA */
53 child_sa_t *child_sa;
54} entry_t;
55
56/**
57 * actually uninstall and destroy an installed entry
58 */
59static void destroy_entry(entry_t *entry)
60{
61 entry->child_sa->destroy(entry->child_sa);
62 entry->peer_cfg->destroy(entry->peer_cfg);
63 free(entry);
64}
65
66/**
67 * Implementation of trap_manager_t.install
68 */
c3626c2c 69static u_int32_t install(private_trap_manager_t *this, peer_cfg_t *peer,
eb8ed130
MW
70 child_cfg_t *child)
71{
72 entry_t *entry;
73 ike_cfg_t *ike_cfg;
74 child_sa_t *child_sa;
75 host_t *me, *other;
76 linked_list_t *my_ts, *other_ts;
77 enumerator_t *enumerator;
78 bool found = FALSE;
79 status_t status;
c3626c2c 80 u_int32_t reqid;
eb8ed130
MW
81
82 /* check if not already done */
83 this->mutex->lock(this->mutex);
84 enumerator = this->traps->create_enumerator(this->traps);
85 while (enumerator->enumerate(enumerator, &entry))
86 {
87 if (streq(entry->child_sa->get_name(entry->child_sa),
88 child->get_name(child)))
89 {
90 found = TRUE;
91 break;
92 }
93 }
94 enumerator->destroy(enumerator);
95 this->mutex->unlock(this->mutex);
96 if (found)
97 {
98 DBG1(DBG_CFG, "CHILD_SA named '%s' already routed",
99 child->get_name(child));
100 return 0;
101 }
102
103 /* try to resolve addresses */
104 ike_cfg = peer->get_ike_cfg(peer);
105 other = host_create_from_dns(ike_cfg->get_other_addr(ike_cfg),
106 0, IKEV2_UDP_PORT);
107 if (!other)
108 {
109 DBG1(DBG_CFG, "installing trap failed, remote address unknown");
110 return 0;
111 }
112 me = host_create_from_dns(ike_cfg->get_my_addr(ike_cfg),
113 other->get_family(other), IKEV2_UDP_PORT);
114 if (!me || me->is_anyaddr(me))
115 {
116 DESTROY_IF(me);
117 me = charon->kernel_interface->get_source_addr(
118 charon->kernel_interface, other, NULL);
119 if (!me)
120 {
121 DBG1(DBG_CFG, "installing trap failed, local address unknown");
122 other->destroy(other);
123 return 0;
124 }
125 me->set_port(me, IKEV2_UDP_PORT);
126 }
127
128 /* create and route CHILD_SA */
129 child_sa = child_sa_create(me, other, child, 0, FALSE);
130 my_ts = child->get_traffic_selectors(child, TRUE, NULL, me);
131 other_ts = child->get_traffic_selectors(child, FALSE, NULL, other);
132 me->destroy(me);
133 other->destroy(other);
134
135 child_sa->set_mode(child_sa, child->get_mode(child));
136 status = child_sa->add_policies(child_sa, my_ts, other_ts);
137 my_ts->destroy_offset(my_ts, offsetof(traffic_selector_t, destroy));
138 other_ts->destroy_offset(other_ts, offsetof(traffic_selector_t, destroy));
139 if (status != SUCCESS)
140 {
141 child_sa->destroy(child_sa);
142 DBG1(DBG_CFG, "installing trap failed");
143 return 0;
144 }
145
146 reqid = child_sa->get_reqid(child_sa);
147 entry = malloc_thing(entry_t);
148 entry->child_sa = child_sa;
149 entry->peer_cfg = peer->get_ref(peer);
150
151 this->mutex->lock(this->mutex);
152 this->traps->insert_last(this->traps, entry);
153 this->mutex->unlock(this->mutex);
154
155 return reqid;
156}
157
158/**
159 * Implementation of trap_manager_t.uninstall
160 */
c3626c2c 161static bool uninstall(private_trap_manager_t *this, u_int32_t reqid)
eb8ed130
MW
162{
163 enumerator_t *enumerator;
164 entry_t *entry, *found = NULL;
165
166 this->mutex->lock(this->mutex);
167 enumerator = this->traps->create_enumerator(this->traps);
168 while (enumerator->enumerate(enumerator, &entry))
169 {
170 if (entry->child_sa->get_reqid(entry->child_sa) == reqid)
171 {
172 this->traps->remove_at(this->traps, enumerator);
173 found = entry;
174 break;
175 }
176 }
177 enumerator->destroy(enumerator);
178 this->mutex->unlock(this->mutex);
179
180 if (!found)
181 {
182 DBG1(DBG_CFG, "trap %d not found to uninstall", reqid);
183 return FALSE;
184 }
185
186 destroy_entry(found);
187 return TRUE;
188}
189
190/**
191 * convert enumerated entries to peer_cfg, child_sa
192 */
193static bool trap_filter(mutex_t *mutex, entry_t **entry, peer_cfg_t **peer_cfg,
194 void *none, child_sa_t **child_sa)
195{
196 if (peer_cfg)
197 {
198 *peer_cfg = (*entry)->peer_cfg;
199 }
200 if (child_sa)
201 {
202 *child_sa = (*entry)->child_sa;
203 }
204 return TRUE;
205}
206
207/**
208 * Implementation of trap_manager_t.create_enumerator
209 */
210static enumerator_t* create_enumerator(private_trap_manager_t *this)
211{
212 this->mutex->lock(this->mutex);
213 return enumerator_create_filter(this->traps->create_enumerator(this->traps),
214 (void*)trap_filter, this->mutex,
215 (void*)this->mutex->unlock);
216}
217
218/**
219 * Implementation of trap_manager_t.acquire
220 */
c3626c2c 221static void acquire(private_trap_manager_t *this, u_int32_t reqid,
eb8ed130
MW
222 traffic_selector_t *src, traffic_selector_t *dst)
223{
224 enumerator_t *enumerator;
225 entry_t *entry, *found = NULL;
226 peer_cfg_t *peer;
227 child_cfg_t *child;
228 ike_sa_t *ike_sa;
229
230 this->mutex->lock(this->mutex);
231 enumerator = this->traps->create_enumerator(this->traps);
232 while (enumerator->enumerate(enumerator, &entry))
233 {
234 if (entry->child_sa->get_reqid(entry->child_sa) == reqid)
235 {
236 found = entry;
237 break;
238 }
239 }
240 enumerator->destroy(enumerator);
241
242 if (!found)
243 {
244 DBG1(DBG_CFG, "trap not found, unable to acquire reqid %d",reqid);
245 return;
246 }
247
248 child = found->child_sa->get_config(found->child_sa);
249 peer = found->peer_cfg;
250 ike_sa = charon->ike_sa_manager->checkout_by_config(charon->ike_sa_manager,
251 peer);
252 if (ike_sa->get_peer_cfg(ike_sa) == NULL)
253 {
254 ike_sa->set_peer_cfg(ike_sa, peer);
255 }
256 child->get_ref(child);
257 this->mutex->unlock(this->mutex);
c3626c2c 258 if (ike_sa->initiate(ike_sa, child, reqid) != DESTROY_ME)
eb8ed130
MW
259 {
260 charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
261 return;
262 }
263 charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa);
264}
265
266/**
267 * Implementation of trap_manager_t.destroy.
268 */
269static void destroy(private_trap_manager_t *this)
270{
271 this->traps->invoke_function(this->traps, (void*)destroy_entry);
272 this->traps->destroy(this->traps);
273 this->mutex->destroy(this->mutex);
274 free(this);
275}
276
277/**
278 * See header
279 */
280trap_manager_t *trap_manager_create()
281{
282 private_trap_manager_t *this = malloc_thing(private_trap_manager_t);
283
c3626c2c
MW
284 this->public.install = (u_int32_t(*)(trap_manager_t*, peer_cfg_t *peer, child_cfg_t *child))install;
285 this->public.uninstall = (bool(*)(trap_manager_t*, u_int32_t id))uninstall;
eb8ed130 286 this->public.create_enumerator = (enumerator_t*(*)(trap_manager_t*))create_enumerator;
c3626c2c 287 this->public.acquire = (void(*)(trap_manager_t*, u_int32_t reqid, traffic_selector_t *src, traffic_selector_t *dst))acquire;
eb8ed130
MW
288 this->public.destroy = (void(*)(trap_manager_t*))destroy;
289
290 this->traps = linked_list_create();
291 this->mutex = mutex_create(MUTEX_DEFAULT);
292
293 return &this->public;
294}
295