]>
Commit | Line | Data |
---|---|---|
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 | ||
23 | typedef struct private_trap_manager_t private_trap_manager_t; | |
24 | ||
25 | /** | |
26 | * Private data of an trap_manager_t object. | |
27 | */ | |
28 | struct 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 | */ | |
49 | typedef 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 | */ | |
59 | static 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 | 69 | static 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 | 161 | static 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 | */ | |
193 | static 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 | */ | |
210 | static 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 | 221 | static 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 | */ | |
269 | static 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 | */ | |
280 | trap_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 |