Do not install trap policy if remote host is %any.
[strongswan.git] / src / libcharon / sa / trap_manager.c
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.
14 */
15
16 #include "trap_manager.h"
17
18 #include <daemon.h>
19 #include <threading/rwlock.h>
20 #include <utils/linked_list.h>
21
22
23 typedef struct private_trap_manager_t private_trap_manager_t;
24 typedef struct trap_listener_t trap_listener_t;
25
26 /**
27 * listener to track acquires
28 */
29 struct trap_listener_t {
30
31 /**
32 * Implements listener interface
33 */
34 listener_t listener;
35
36 /**
37 * points to trap_manager
38 */
39 private_trap_manager_t *traps;
40 };
41
42 /**
43 * Private data of an trap_manager_t object.
44 */
45 struct private_trap_manager_t {
46
47 /**
48 * Public trap_manager_t interface.
49 */
50 trap_manager_t public;
51
52 /**
53 * Installed traps, as entry_t
54 */
55 linked_list_t *traps;
56
57 /**
58 * read write lock for traps list
59 */
60 rwlock_t *lock;
61
62 /**
63 * listener to track acquiring IKE_SAs
64 */
65 trap_listener_t listener;
66 };
67
68 /**
69 * A installed trap entry
70 */
71 typedef struct {
72 /** ref to peer_cfg to initiate */
73 peer_cfg_t *peer_cfg;
74 /** ref to instanciated CHILD_SA */
75 child_sa_t *child_sa;
76 /** pending IKE_SA connecting upon acquire */
77 ike_sa_t *pending;
78 } entry_t;
79
80 /**
81 * actually uninstall and destroy an installed entry
82 */
83 static void destroy_entry(entry_t *entry)
84 {
85 entry->child_sa->destroy(entry->child_sa);
86 entry->peer_cfg->destroy(entry->peer_cfg);
87 free(entry);
88 }
89
90 /**
91 * Implementation of trap_manager_t.install
92 */
93 static u_int32_t install(private_trap_manager_t *this, peer_cfg_t *peer,
94 child_cfg_t *child)
95 {
96 entry_t *entry;
97 ike_cfg_t *ike_cfg;
98 child_sa_t *child_sa;
99 host_t *me, *other;
100 linked_list_t *my_ts, *other_ts;
101 enumerator_t *enumerator;
102 bool found = FALSE;
103 status_t status;
104 u_int32_t reqid;
105
106 /* check if not already done */
107 this->lock->read_lock(this->lock);
108 enumerator = this->traps->create_enumerator(this->traps);
109 while (enumerator->enumerate(enumerator, &entry))
110 {
111 if (streq(entry->child_sa->get_name(entry->child_sa),
112 child->get_name(child)))
113 {
114 found = TRUE;
115 break;
116 }
117 }
118 enumerator->destroy(enumerator);
119 this->lock->unlock(this->lock);
120 if (found)
121 {
122 DBG1(DBG_CFG, "CHILD_SA named '%s' already routed",
123 child->get_name(child));
124 return 0;
125 }
126
127 /* try to resolve addresses */
128 ike_cfg = peer->get_ike_cfg(peer);
129 other = host_create_from_dns(ike_cfg->get_other_addr(ike_cfg),
130 0, ike_cfg->get_other_port(ike_cfg));
131 if (!other || other->is_anyaddr(other))
132 {
133 DBG1(DBG_CFG, "installing trap failed, remote address unknown");
134 return 0;
135 }
136 me = host_create_from_dns(ike_cfg->get_my_addr(ike_cfg),
137 other->get_family(other), ike_cfg->get_my_port(ike_cfg));
138 if (!me || me->is_anyaddr(me))
139 {
140 DESTROY_IF(me);
141 me = charon->kernel_interface->get_source_addr(
142 charon->kernel_interface, other, NULL);
143 if (!me)
144 {
145 DBG1(DBG_CFG, "installing trap failed, local address unknown");
146 other->destroy(other);
147 return 0;
148 }
149 me->set_port(me, ike_cfg->get_my_port(ike_cfg));
150 }
151
152 /* create and route CHILD_SA */
153 child_sa = child_sa_create(me, other, child, 0, FALSE);
154 my_ts = child->get_traffic_selectors(child, TRUE, NULL, me);
155 other_ts = child->get_traffic_selectors(child, FALSE, NULL, other);
156 me->destroy(me);
157 other->destroy(other);
158
159 /* while we don't know the finally negotiated protocol (ESP|AH), we
160 * could iterate all proposals for a best guest (TODO). But as we
161 * support ESP only for now, we set here. */
162 child_sa->set_protocol(child_sa, PROTO_ESP);
163 child_sa->set_mode(child_sa, child->get_mode(child));
164 status = child_sa->add_policies(child_sa, my_ts, other_ts);
165 my_ts->destroy_offset(my_ts, offsetof(traffic_selector_t, destroy));
166 other_ts->destroy_offset(other_ts, offsetof(traffic_selector_t, destroy));
167 if (status != SUCCESS)
168 {
169 child_sa->destroy(child_sa);
170 DBG1(DBG_CFG, "installing trap failed");
171 return 0;
172 }
173
174 reqid = child_sa->get_reqid(child_sa);
175 entry = malloc_thing(entry_t);
176 entry->child_sa = child_sa;
177 entry->peer_cfg = peer->get_ref(peer);
178 entry->pending = NULL;
179
180 this->lock->write_lock(this->lock);
181 this->traps->insert_last(this->traps, entry);
182 this->lock->unlock(this->lock);
183
184 return reqid;
185 }
186
187 /**
188 * Implementation of trap_manager_t.uninstall
189 */
190 static bool uninstall(private_trap_manager_t *this, u_int32_t reqid)
191 {
192 enumerator_t *enumerator;
193 entry_t *entry, *found = NULL;
194
195 this->lock->write_lock(this->lock);
196 enumerator = this->traps->create_enumerator(this->traps);
197 while (enumerator->enumerate(enumerator, &entry))
198 {
199 if (entry->child_sa->get_reqid(entry->child_sa) == reqid)
200 {
201 this->traps->remove_at(this->traps, enumerator);
202 found = entry;
203 break;
204 }
205 }
206 enumerator->destroy(enumerator);
207 this->lock->unlock(this->lock);
208
209 if (!found)
210 {
211 DBG1(DBG_CFG, "trap %d not found to uninstall", reqid);
212 return FALSE;
213 }
214
215 destroy_entry(found);
216 return TRUE;
217 }
218
219 /**
220 * convert enumerated entries to peer_cfg, child_sa
221 */
222 static bool trap_filter(rwlock_t *lock, entry_t **entry, peer_cfg_t **peer_cfg,
223 void *none, child_sa_t **child_sa)
224 {
225 if (peer_cfg)
226 {
227 *peer_cfg = (*entry)->peer_cfg;
228 }
229 if (child_sa)
230 {
231 *child_sa = (*entry)->child_sa;
232 }
233 return TRUE;
234 }
235
236 /**
237 * Implementation of trap_manager_t.create_enumerator
238 */
239 static enumerator_t* create_enumerator(private_trap_manager_t *this)
240 {
241 this->lock->read_lock(this->lock);
242 return enumerator_create_filter(this->traps->create_enumerator(this->traps),
243 (void*)trap_filter, this->lock,
244 (void*)this->lock->unlock);
245 }
246
247 /**
248 * Implementation of trap_manager_t.acquire
249 */
250 static void acquire(private_trap_manager_t *this, u_int32_t reqid,
251 traffic_selector_t *src, traffic_selector_t *dst)
252 {
253 enumerator_t *enumerator;
254 entry_t *entry, *found = NULL;
255 peer_cfg_t *peer;
256 child_cfg_t *child;
257 ike_sa_t *ike_sa;
258
259 this->lock->read_lock(this->lock);
260 enumerator = this->traps->create_enumerator(this->traps);
261 while (enumerator->enumerate(enumerator, &entry))
262 {
263 if (entry->child_sa->get_reqid(entry->child_sa) == reqid)
264 {
265 found = entry;
266 break;
267 }
268 }
269 enumerator->destroy(enumerator);
270
271 if (!found)
272 {
273 DBG1(DBG_CFG, "trap not found, unable to acquire reqid %d",reqid);
274 }
275 else if (found->pending)
276 {
277 DBG1(DBG_CFG, "ignoring acquire, connection attempt pending");
278 }
279 else
280 {
281 child = found->child_sa->get_config(found->child_sa);
282 peer = found->peer_cfg;
283 ike_sa = charon->ike_sa_manager->checkout_by_config(
284 charon->ike_sa_manager, peer);
285 if (ike_sa->get_peer_cfg(ike_sa) == NULL)
286 {
287 ike_sa->set_peer_cfg(ike_sa, peer);
288 }
289 child->get_ref(child);
290 reqid = found->child_sa->get_reqid(found->child_sa);
291 if (ike_sa->initiate(ike_sa, child, reqid, src, dst) != DESTROY_ME)
292 {
293 found->pending = ike_sa;
294 charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
295 }
296 else
297 {
298 charon->ike_sa_manager->checkin_and_destroy(
299 charon->ike_sa_manager, ike_sa);
300 }
301 }
302 this->lock->unlock(this->lock);
303 }
304
305 /**
306 * Complete the acquire, if successful or failed
307 */
308 static void complete(private_trap_manager_t *this, ike_sa_t *ike_sa,
309 child_sa_t *child_sa)
310 {
311 enumerator_t *enumerator;
312 entry_t *entry;
313
314 this->lock->read_lock(this->lock);
315 enumerator = this->traps->create_enumerator(this->traps);
316 while (enumerator->enumerate(enumerator, &entry))
317 {
318 if (entry->pending != ike_sa)
319 {
320 continue;
321 }
322 if (child_sa && child_sa->get_reqid(child_sa) !=
323 entry->child_sa->get_reqid(entry->child_sa))
324 {
325 continue;
326 }
327 entry->pending = NULL;
328 }
329 enumerator->destroy(enumerator);
330 this->lock->unlock(this->lock);
331 }
332
333 /**
334 * Implementation of listener_t.ike_state_change
335 */
336 static bool ike_state_change(trap_listener_t *listener, ike_sa_t *ike_sa,
337 ike_sa_state_t state)
338 {
339 switch (state)
340 {
341 case IKE_DESTROYING:
342 complete(listener->traps, ike_sa, NULL);
343 return TRUE;
344 default:
345 return TRUE;
346 }
347 }
348
349 /**
350 * Implementation of listener_t.child_state_change
351 */
352 static bool child_state_change(trap_listener_t *listener, ike_sa_t *ike_sa,
353 child_sa_t *child_sa, child_sa_state_t state)
354 {
355 switch (state)
356 {
357 case CHILD_INSTALLED:
358 case CHILD_DESTROYING:
359 complete(listener->traps, ike_sa, child_sa);
360 return TRUE;
361 default:
362 return TRUE;
363 }
364 }
365
366 /**
367 * Implementation of trap_manager_t.destroy.
368 */
369 static void destroy(private_trap_manager_t *this)
370 {
371 charon->bus->remove_listener(charon->bus, &this->listener.listener);
372 this->traps->invoke_function(this->traps, (void*)destroy_entry);
373 this->traps->destroy(this->traps);
374 this->lock->destroy(this->lock);
375 free(this);
376 }
377
378 /**
379 * See header
380 */
381 trap_manager_t *trap_manager_create()
382 {
383 private_trap_manager_t *this = malloc_thing(private_trap_manager_t);
384
385 this->public.install = (u_int(*)(trap_manager_t*, peer_cfg_t *peer, child_cfg_t *child))install;
386 this->public.uninstall = (bool(*)(trap_manager_t*, u_int32_t id))uninstall;
387 this->public.create_enumerator = (enumerator_t*(*)(trap_manager_t*))create_enumerator;
388 this->public.acquire = (void(*)(trap_manager_t*, u_int32_t reqid, traffic_selector_t *src, traffic_selector_t *dst))acquire;
389 this->public.destroy = (void(*)(trap_manager_t*))destroy;
390
391 this->traps = linked_list_create();
392 this->lock = rwlock_create(RWLOCK_TYPE_DEFAULT);
393
394 /* register listener for IKE state changes */
395 this->listener.traps = this;
396 memset(&this->listener.listener, 0, sizeof(listener_t));
397 this->listener.listener.ike_state_change = (void*)ike_state_change;
398 this->listener.listener.child_state_change = (void*)child_state_change;
399 charon->bus->add_listener(charon->bus, &this->listener.listener);
400
401 return &this->public;
402 }
403