allow starter to initiate connections simultaneously (on auto=start)
[strongswan.git] / src / charon / control / interface_manager.c
1 /**
2 * @file interface_manager.c
3 *
4 * @brief Implementation of interface_manager_t.
5 *
6 */
7
8 /*
9 * Copyright (C) 2007 Martin Willi
10 * Hochschule fuer Technik Rapperswil
11 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2 of the License, or (at your
15 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 * for more details.
21 */
22
23 #include "interface_manager.h"
24
25 #include <sys/types.h>
26 #include <dirent.h>
27 #include <sys/stat.h>
28 #include <dlfcn.h>
29
30 #include <daemon.h>
31 #include <library.h>
32 #include <control/interfaces/interface.h>
33
34
35 typedef struct private_interface_manager_t private_interface_manager_t;
36 typedef struct interface_bus_listener_t interface_bus_listener_t;
37
38 /**
39 * Private data of an stroke_t object.
40 */
41 struct private_interface_manager_t {
42
43 /**
44 * Public part of stroke_t object.
45 */
46 interface_manager_t public;
47
48 /**
49 * a list of all loaded interfaces
50 */
51 linked_list_t *interfaces;
52
53 /**
54 * dlopen() handles of interfaces
55 */
56 linked_list_t *handles;
57 };
58
59 /**
60 * helper struct to map bus listener callbacks to interface callbacks
61 */
62 struct interface_bus_listener_t {
63
64 /**
65 * bus listener callback function (called)
66 */
67 bus_listener_t listener;
68
69 /**
70 * IKE_SA to use for message filtering
71 */
72 ike_sa_t *ike_sa;
73
74 /**
75 * interface callback (listener gets redirected to here)
76 */
77 interface_manager_cb_t callback;
78
79 /**
80 * user parameter to pass to callback
81 */
82 void *param;
83
84 /**
85 * caller has cancelled its listening subscription
86 */
87 bool cancelled;
88 };
89
90 /**
91 * Implementation of interface_manager_t.create_ike_sa_iterator.
92 */
93 static iterator_t* create_ike_sa_iterator(interface_manager_t *this)
94 {
95 return charon->ike_sa_manager->create_iterator(charon->ike_sa_manager);
96 }
97
98 /**
99 * listener function for initiate
100 */
101 static bool initiate_listener(interface_bus_listener_t *this, signal_t signal,
102 level_t level, int thread, ike_sa_t *ike_sa,
103 char* format, va_list args)
104 {
105 if (this->ike_sa == ike_sa)
106 {
107 if (!this->callback(this->param, signal, level, ike_sa, format, args))
108 {
109 this->cancelled = TRUE;
110 return FALSE;
111 }
112 switch (signal)
113 {
114 case IKE_UP_FAILED:
115 case CHILD_UP_FAILED:
116 case CHILD_UP_SUCCESS:
117 {
118 return FALSE;
119 }
120 default:
121 break;
122 }
123 }
124 return TRUE;
125 }
126
127 /**
128 * listener function for terminate_ike
129 */
130 static bool terminate_ike_listener(interface_bus_listener_t *this, signal_t signal,
131 level_t level, int thread, ike_sa_t *ike_sa,
132 char* format, va_list args)
133 {
134 if (this->ike_sa == ike_sa)
135 {
136 if (!this->callback(this->param, signal, level, ike_sa, format, args))
137 {
138 this->cancelled = TRUE;
139 return FALSE;
140 }
141 switch (signal)
142 {
143 case IKE_DOWN_FAILED:
144 case IKE_DOWN_SUCCESS:
145 {
146 return FALSE;
147 }
148 default:
149 break;
150 }
151 }
152 return TRUE;
153 }
154
155 /**
156 * listener function for terminate_child
157 */
158 static bool terminate_child_listener(interface_bus_listener_t *this, signal_t signal,
159 level_t level, int thread, ike_sa_t *ike_sa,
160 char* format, va_list args)
161 {
162 if (this->ike_sa == ike_sa)
163 {
164 if (!this->callback(this->param, signal, level, ike_sa, format, args))
165 {
166 this->cancelled = TRUE;
167 return FALSE;
168 }
169 switch (signal)
170 {
171 case IKE_DOWN_FAILED:
172 case IKE_DOWN_SUCCESS:
173 case CHILD_DOWN_FAILED:
174 case CHILD_DOWN_SUCCESS:
175 {
176 return FALSE;
177 }
178 default:
179 break;
180 }
181 }
182 return TRUE;
183 }
184
185 /**
186 * listener function for route
187 */
188 static bool route_listener(interface_bus_listener_t *this, signal_t signal,
189 level_t level, int thread, ike_sa_t *ike_sa,
190 char* format, va_list args)
191 {
192 if (this->ike_sa == ike_sa)
193 {
194 if (!this->callback(this->param, signal, level, ike_sa, format, args))
195 {
196 this->cancelled = TRUE;
197 return FALSE;
198 }
199 switch (signal)
200 {
201 case CHILD_ROUTE_SUCCESS:
202 case CHILD_ROUTE_FAILED:
203 {
204 return FALSE;
205 }
206 default:
207 break;
208 }
209 }
210 return TRUE;
211 }
212
213 /**
214 * listener function for unroute
215 */
216 static bool unroute_listener(interface_bus_listener_t *this, signal_t signal,
217 level_t level, int thread, ike_sa_t *ike_sa,
218 char* format, va_list args)
219 {
220 if (this->ike_sa == ike_sa)
221 {
222 if (!this->callback(this->param, signal, level, ike_sa, format, args))
223 {
224 this->cancelled = TRUE;
225 return FALSE;
226 }
227 switch (signal)
228 {
229 case CHILD_UNROUTE_SUCCESS:
230 case CHILD_UNROUTE_FAILED:
231 {
232 return FALSE;
233 }
234 default:
235 break;
236 }
237 }
238 return TRUE;
239 }
240
241 /**
242 * remove a previously registered listener from the bus
243 */
244 static void remove_listener(interface_bus_listener_t *listener)
245 {
246 charon->bus->remove_listener(charon->bus, &listener->listener);
247 }
248
249 /**
250 * Implementation of interface_manager_t.initiate.
251 */
252 static status_t initiate(private_interface_manager_t *this,
253 peer_cfg_t *peer_cfg, child_cfg_t *child_cfg,
254 interface_manager_cb_t callback, void *param)
255 {
256 ike_sa_t *ike_sa;
257 ike_cfg_t *ike_cfg;
258 status_t retval = FAILED;
259 interface_bus_listener_t listener;
260
261 ike_cfg = peer_cfg->get_ike_cfg(peer_cfg);
262 ike_sa = charon->ike_sa_manager->checkout_by_peer(charon->ike_sa_manager,
263 ike_cfg->get_my_host(ike_cfg), ike_cfg->get_other_host(ike_cfg),
264 peer_cfg->get_my_id(peer_cfg), peer_cfg->get_other_id(peer_cfg));
265
266 if (ike_sa->get_peer_cfg(ike_sa) == NULL)
267 {
268 ike_sa->set_peer_cfg(ike_sa, peer_cfg);
269 }
270 peer_cfg->destroy(peer_cfg);
271
272 listener.listener.signal = (void*)initiate_listener;
273 listener.callback = callback;
274 listener.ike_sa = ike_sa;
275 listener.param = param;
276 listener.cancelled = FALSE;
277
278 /* we listen passively to catch the signals we are raising in
279 * ike_sa->delete(). */
280 if (callback)
281 {
282 charon->bus->add_listener(charon->bus, &listener.listener);
283 }
284 charon->bus->set_listen_state(charon->bus, TRUE);
285 if (ike_sa->initiate(ike_sa, child_cfg) != SUCCESS)
286 {
287 charon->bus->set_listen_state(charon->bus, FALSE);
288 charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa);
289 return FAILED;
290 }
291 charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
292
293 if (callback == NULL)
294 {
295 /* don't wait for a result if no callback is specified */
296 charon->bus->set_listen_state(charon->bus, FALSE);
297 return NEED_MORE;
298 }
299
300 /* wait until we get a result */
301 while (TRUE)
302 {
303 level_t level;
304 signal_t signal;
305 int thread;
306 ike_sa_t *current;
307 char* format;
308 va_list args;
309
310 /* stop listening if the passive listener returned FALSE */
311 if (listener.cancelled)
312 {
313 retval = NEED_MORE;
314 break;
315 }
316 pthread_cleanup_push((void*)remove_listener, &listener);
317 signal = charon->bus->listen(charon->bus, &level, &thread,
318 &current, &format, &args);
319 pthread_cleanup_pop(0);
320 /* ike_sa is a valid pointer until we get one of the signals */
321 if (ike_sa == current)
322 {
323 switch (signal)
324 {
325 case CHILD_UP_SUCCESS:
326 retval = SUCCESS;
327 case CHILD_UP_FAILED:
328 case IKE_UP_FAILED:
329 break;
330 default:
331 continue;
332 }
333 break;
334 }
335 }
336 charon->bus->set_listen_state(charon->bus, FALSE);
337 return retval;
338 }
339
340 /**
341 * Implementation of interface_manager_t.terminate_ike.
342 */
343 static status_t terminate_ike(interface_manager_t *this, u_int32_t unique_id,
344 interface_manager_cb_t callback, void *param)
345 {
346 ike_sa_t *ike_sa;
347 status_t status = FAILED;;
348 interface_bus_listener_t listener;
349
350 ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager,
351 unique_id, FALSE);
352 if (ike_sa == NULL)
353 {
354 return NOT_FOUND;
355 }
356
357 /* we listen passively to catch the signals we are raising in
358 * ike_sa->delete(). */
359 listener.listener.signal = (void*)terminate_ike_listener;
360 listener.callback = callback;
361 listener.ike_sa = ike_sa;
362 listener.param = param;
363 listener.cancelled = FALSE;
364 if (callback)
365 {
366 charon->bus->add_listener(charon->bus, &listener.listener);
367 }
368 charon->bus->set_listen_state(charon->bus, TRUE);
369 status = ike_sa->delete(ike_sa);
370 if (status == DESTROY_ME)
371 {
372 charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa);
373 }
374 else
375 {
376 charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
377
378 /* wait until IKE_SA is cleanly deleted using a delete message */
379 while (TRUE)
380 {
381 level_t level;
382 signal_t signal;
383 int thread;
384 ike_sa_t *current;
385 char* format;
386 va_list args;
387
388 /* stop listening if the passive listener returned FALSE */
389 if (listener.cancelled)
390 {
391 status = NEED_MORE;
392 break;
393 }
394 pthread_cleanup_push((void*)remove_listener, &listener);
395 signal = charon->bus->listen(charon->bus, &level, &thread,
396 &current, &format, &args);
397 pthread_cleanup_pop(0);
398
399 /* even if we checked in the IKE_SA, the pointer is valid until
400 * we get an IKE_DOWN_... */
401 if (ike_sa == current)
402 {
403 switch (signal)
404 {
405 case IKE_DOWN_FAILED:
406 case IKE_DOWN_SUCCESS:
407 {
408 status = SUCCESS;
409 break;
410 }
411 default:
412 continue;
413 }
414 break;
415 }
416 }
417 }
418 charon->bus->set_listen_state(charon->bus, FALSE);
419
420 return status;
421 }
422
423 /**
424 * Implementation of interface_manager_t.terminate_child.
425 */
426 static status_t terminate_child(interface_manager_t *this, u_int32_t reqid,
427 interface_manager_cb_t callback, void *param)
428 {
429 ike_sa_t *ike_sa;
430 child_sa_t *child_sa;
431 iterator_t *iterator;
432 status_t status = FAILED;
433 interface_bus_listener_t listener;
434
435 ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager,
436 reqid, TRUE);
437 if (ike_sa == NULL)
438 {
439 return NOT_FOUND;
440 }
441
442 iterator = ike_sa->create_child_sa_iterator(ike_sa);
443 while (iterator->iterate(iterator, (void**)&child_sa))
444 {
445 if (child_sa->get_state(child_sa) != CHILD_ROUTED &&
446 child_sa->get_reqid(child_sa) == reqid)
447 {
448 break;
449 }
450 child_sa = NULL;
451 }
452 iterator->destroy(iterator);
453
454 if (child_sa == NULL)
455 {
456 charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
457 return NOT_FOUND;
458 }
459
460 listener.listener.signal = (void*)terminate_child_listener;
461 listener.callback = callback;
462 listener.ike_sa = ike_sa;
463 listener.param = param;
464 listener.cancelled = FALSE;
465
466 /* we listen passively to catch the signals we are raising */
467 if (callback)
468 {
469 charon->bus->add_listener(charon->bus, &listener.listener);
470 }
471 charon->bus->set_listen_state(charon->bus, TRUE);
472 status = ike_sa->delete_child_sa(ike_sa, child_sa->get_protocol(child_sa),
473 child_sa->get_spi(child_sa, TRUE));
474 if (status == DESTROY_ME)
475 {
476 charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa);
477 }
478 else
479 {
480 charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
481
482 /* wait until CHILD_SA is cleanly deleted using a delete message */
483 while (TRUE)
484 {
485 level_t level;
486 signal_t signal;
487 int thread;
488 ike_sa_t *current;
489 char* format;
490 va_list args;
491
492 /* stop listening if the passive listener returned FALSE */
493 if (listener.cancelled)
494 {
495 status = NEED_MORE;
496 break;
497 }
498 pthread_cleanup_push((void*)remove_listener, &listener);
499 signal = charon->bus->listen(charon->bus, &level, &thread,
500 &current, &format, &args);
501 pthread_cleanup_pop(0);
502 /* even if we checked in the IKE_SA, the pointer is valid until
503 * we get an IKE_DOWN_... */
504 if (ike_sa == current)
505 {
506 switch (signal)
507 {
508 case IKE_DOWN_FAILED:
509 case IKE_DOWN_SUCCESS:
510 case CHILD_DOWN_FAILED:
511 case CHILD_DOWN_SUCCESS:
512 {
513 status = SUCCESS;
514 break;
515 }
516 default:
517 continue;
518 }
519 break;
520 }
521 }
522 }
523 charon->bus->set_listen_state(charon->bus, FALSE);
524
525 return status;
526 }
527
528 /**
529 * Implementation of interface_manager_t.route.
530 */
531 static status_t route(interface_manager_t *this,
532 peer_cfg_t *peer_cfg, child_cfg_t *child_cfg,
533 interface_manager_cb_t callback, void *param)
534 {
535 ike_sa_t *ike_sa;
536 ike_cfg_t *ike_cfg;
537 status_t status = SUCCESS;
538
539 ike_cfg = peer_cfg->get_ike_cfg(peer_cfg);
540
541 ike_sa = charon->ike_sa_manager->checkout_by_peer(charon->ike_sa_manager,
542 ike_cfg->get_my_host(ike_cfg), ike_cfg->get_other_host(ike_cfg),
543 peer_cfg->get_my_id(peer_cfg), peer_cfg->get_other_id(peer_cfg));
544
545 if (ike_sa->get_peer_cfg(ike_sa) == NULL)
546 {
547 ike_sa->set_peer_cfg(ike_sa, peer_cfg);
548 }
549
550 /* we listen passively only, as routing is done by one thread only */
551 if (callback)
552 {
553 interface_bus_listener_t listener;
554
555 listener.listener.signal = (void*)route_listener;
556 listener.callback = callback;
557 listener.ike_sa = ike_sa;
558 listener.param = param;
559 listener.cancelled = FALSE;
560 charon->bus->add_listener(charon->bus, &listener.listener);
561 }
562
563 if (ike_sa->route(ike_sa, child_cfg) != SUCCESS)
564 {
565 status = FAILED;
566 }
567 charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
568 return status;
569 }
570
571 /**
572 * Implementation of interface_manager_t.unroute.
573 */
574 static status_t unroute(interface_manager_t *this, u_int32_t reqid,
575 interface_manager_cb_t callback, void *param)
576 {
577 ike_sa_t *ike_sa;
578 status_t status;
579
580 ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager,
581 reqid, TRUE);
582 if (ike_sa == NULL)
583 {
584 return NOT_FOUND;
585 }
586
587 /* we listen passively only, as routing is done by one thread only */
588 if (callback)
589 {
590 interface_bus_listener_t listener;
591
592 listener.listener.signal = (void*)unroute_listener;
593 listener.callback = callback;
594 listener.ike_sa = ike_sa;
595 listener.param = param;
596 listener.cancelled = FALSE;
597 charon->bus->add_listener(charon->bus, &listener.listener);
598 }
599 status = ike_sa->unroute(ike_sa, reqid);
600 if (status == DESTROY_ME)
601 {
602 charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa);
603 status = SUCCESS;
604 }
605 else
606 {
607 charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
608 }
609 return status;
610 }
611
612 /**
613 * load the control interface modules
614 */
615 static void load_interfaces(private_interface_manager_t *this)
616 {
617 struct dirent* entry;
618 DIR* dir;
619
620 dir = opendir(IPSEC_INTERFACEDIR);
621 if (dir == NULL)
622 {
623 DBG1(DBG_CFG, "error opening interface modules directory "IPSEC_INTERFACEDIR);
624 return;
625 }
626
627 DBG1(DBG_CFG, "loading control interface modules from '"IPSEC_INTERFACEDIR"'");
628
629 while ((entry = readdir(dir)) != NULL)
630 {
631 char file[256];
632 interface_t *interface;
633 interface_constructor_t constructor;
634 void *handle;
635 char *ending;
636
637 snprintf(file, sizeof(file), IPSEC_INTERFACEDIR"/%s", entry->d_name);
638
639 ending = entry->d_name + strlen(entry->d_name) - 3;
640 if (ending <= entry->d_name || !streq(ending, ".so"))
641 {
642 /* skip anything which does not look like a library */
643 DBG2(DBG_CFG, " skipping %s, doesn't look like a library",
644 entry->d_name);
645 continue;
646 }
647 /* try to load the library */
648 handle = dlopen(file, RTLD_LAZY);
649 if (handle == NULL)
650 {
651 DBG1(DBG_CFG, " opening control interface module %s failed: %s",
652 entry->d_name, dlerror());
653 continue;
654 }
655 constructor = dlsym(handle, "interface_create");
656 if (constructor == NULL)
657 {
658 DBG1(DBG_CFG, " interface module %s has no interface_create() "
659 "function, skipped", entry->d_name);
660 dlclose(handle);
661 continue;
662 }
663
664 interface = constructor();
665 if (interface == NULL)
666 {
667 DBG1(DBG_CFG, " unable to create instance of interface "
668 "module %s, skipped", entry->d_name);
669 dlclose(handle);
670 continue;
671 }
672 DBG1(DBG_CFG, " loaded control interface module successfully from %s", entry->d_name);
673 this->interfaces->insert_last(this->interfaces, interface);
674 this->handles->insert_last(this->handles, handle);
675 }
676 closedir(dir);
677 }
678
679
680 /**
681 * Implementation of stroke_t.destroy.
682 */
683 static void destroy(private_interface_manager_t *this)
684 {
685 this->interfaces->destroy_offset(this->interfaces, offsetof(interface_t, destroy));
686 this->handles->destroy_function(this->handles, (void*)dlclose);
687 free(this);
688 }
689
690 /*
691 * Described in header-file
692 */
693 interface_manager_t *interface_manager_create(void)
694 {
695 private_interface_manager_t *this = malloc_thing(private_interface_manager_t);
696
697 this->public.create_ike_sa_iterator = (iterator_t*(*)(interface_manager_t*))create_ike_sa_iterator;
698 this->public.initiate = (status_t(*)(interface_manager_t*,peer_cfg_t*,child_cfg_t*,bool(*)(void*,signal_t,level_t,ike_sa_t*,char*,va_list),void*))initiate;
699 this->public.terminate_ike = (status_t(*)(interface_manager_t*,u_int32_t,interface_manager_cb_t, void*))terminate_ike;
700 this->public.terminate_child = (status_t(*)(interface_manager_t*,u_int32_t,interface_manager_cb_t, void *param))terminate_child;
701 this->public.route = (status_t(*)(interface_manager_t*,peer_cfg_t*, child_cfg_t*,interface_manager_cb_t,void*))route;
702 this->public.unroute = (status_t(*)(interface_manager_t*,u_int32_t,interface_manager_cb_t,void*))unroute;
703 this->public.destroy = (void (*)(interface_manager_t*))destroy;
704
705 this->interfaces = linked_list_create();
706 this->handles = linked_list_create();
707
708 load_interfaces(this);
709
710 return &this->public;
711 }
712