917470dba319d2c418ee899ec9d98e5ed68ffb46
[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 * dummy callback
243 */
244 static bool dummy_callback(void *param, signal_t signal, level_t level,
245 ike_sa_t *ike_sa, char *format, va_list args)
246 {
247 return TRUE;
248 }
249
250 /**
251 * remove a previously registered listener from the bus
252 */
253 static void remove_listener(interface_bus_listener_t *listener)
254 {
255 charon->bus->remove_listener(charon->bus, &listener->listener);
256 }
257
258 /**
259 * Implementation of interface_manager_t.initiate.
260 */
261 static status_t initiate(private_interface_manager_t *this,
262 peer_cfg_t *peer_cfg, child_cfg_t *child_cfg,
263 interface_manager_cb_t callback, void *param)
264 {
265 ike_sa_t *ike_sa;
266 ike_cfg_t *ike_cfg;
267 status_t retval = FAILED;
268 interface_bus_listener_t listener;
269
270 ike_cfg = peer_cfg->get_ike_cfg(peer_cfg);
271 ike_sa = charon->ike_sa_manager->checkout_by_peer(charon->ike_sa_manager,
272 ike_cfg->get_my_host(ike_cfg), ike_cfg->get_other_host(ike_cfg),
273 peer_cfg->get_my_id(peer_cfg), peer_cfg->get_other_id(peer_cfg));
274
275 if (ike_sa->get_peer_cfg(ike_sa) == NULL)
276 {
277 ike_sa->set_peer_cfg(ike_sa, peer_cfg);
278 }
279 peer_cfg->destroy(peer_cfg);
280
281 listener.listener.signal = (void*)initiate_listener;
282 listener.callback = callback ? callback : (interface_manager_cb_t)dummy_callback;
283 listener.ike_sa = ike_sa;
284 listener.param = param;
285 listener.cancelled = FALSE;
286
287 /* we listen passively to catch the signals we are raising in
288 * ike_sa->initiate(). */
289 charon->bus->add_listener(charon->bus, &listener.listener);
290 charon->bus->set_listen_state(charon->bus, TRUE);
291 if (ike_sa->initiate(ike_sa, child_cfg) != SUCCESS)
292 {
293 charon->bus->set_listen_state(charon->bus, FALSE);
294 charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa);
295 return FAILED;
296 }
297 charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
298
299 if (callback == NULL)
300 {
301 /* don't wait for a result if no callback is specified */
302 charon->bus->set_listen_state(charon->bus, FALSE);
303 return NEED_MORE;
304 }
305
306 /* wait until we get a result */
307 while (TRUE)
308 {
309 level_t level;
310 signal_t signal;
311 int thread;
312 ike_sa_t *current;
313 char* format;
314 va_list args;
315
316 /* stop listening if the passive listener returned FALSE */
317 if (listener.cancelled)
318 {
319 retval = NEED_MORE;
320 break;
321 }
322 pthread_cleanup_push((void*)remove_listener, &listener);
323 signal = charon->bus->listen(charon->bus, &level, &thread,
324 &current, &format, &args);
325 pthread_cleanup_pop(0);
326 /* ike_sa is a valid pointer until we get one of the signals */
327 if (ike_sa == current)
328 {
329 switch (signal)
330 {
331 case CHILD_UP_SUCCESS:
332 retval = SUCCESS;
333 case CHILD_UP_FAILED:
334 case IKE_UP_FAILED:
335 break;
336 default:
337 continue;
338 }
339 break;
340 }
341 }
342 charon->bus->set_listen_state(charon->bus, FALSE);
343 return retval;
344 }
345
346 /**
347 * Implementation of interface_manager_t.terminate_ike.
348 */
349 static status_t terminate_ike(interface_manager_t *this, u_int32_t unique_id,
350 interface_manager_cb_t callback, void *param)
351 {
352 ike_sa_t *ike_sa;
353 status_t status = FAILED;
354 interface_bus_listener_t listener;
355
356 ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager,
357 unique_id, FALSE);
358 if (ike_sa == NULL)
359 {
360 return NOT_FOUND;
361 }
362
363 /* we listen passively to catch the signals we are raising in
364 * ike_sa->delete(). */
365 listener.listener.signal = (void*)terminate_ike_listener;
366 listener.callback = callback ? callback : (interface_manager_cb_t)dummy_callback;
367 listener.ike_sa = ike_sa;
368 listener.param = param;
369 listener.cancelled = FALSE;
370
371 charon->bus->add_listener(charon->bus, &listener.listener);
372 charon->bus->set_listen_state(charon->bus, TRUE);
373 status = ike_sa->delete(ike_sa);
374 if (status == DESTROY_ME)
375 {
376 charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa);
377 }
378 else
379 {
380 charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
381
382 /* wait until IKE_SA is cleanly deleted using a delete message */
383 while (TRUE)
384 {
385 level_t level;
386 signal_t signal;
387 int thread;
388 ike_sa_t *current;
389 char* format;
390 va_list args;
391
392 /* stop listening if the passive listener returned FALSE */
393 if (listener.cancelled)
394 {
395 status = NEED_MORE;
396 break;
397 }
398 pthread_cleanup_push((void*)remove_listener, &listener);
399 signal = charon->bus->listen(charon->bus, &level, &thread,
400 &current, &format, &args);
401 pthread_cleanup_pop(0);
402
403 /* even if we checked in the IKE_SA, the pointer is valid until
404 * we get an IKE_DOWN_... */
405 if (ike_sa == current)
406 {
407 switch (signal)
408 {
409 case IKE_DOWN_FAILED:
410 case IKE_DOWN_SUCCESS:
411 {
412 status = SUCCESS;
413 break;
414 }
415 default:
416 continue;
417 }
418 break;
419 }
420 }
421 }
422 charon->bus->set_listen_state(charon->bus, FALSE);
423
424 return status;
425 }
426
427 /**
428 * Implementation of interface_manager_t.terminate_child.
429 */
430 static status_t terminate_child(interface_manager_t *this, u_int32_t reqid,
431 interface_manager_cb_t callback, void *param)
432 {
433 ike_sa_t *ike_sa;
434 child_sa_t *child_sa;
435 iterator_t *iterator;
436 status_t status = FAILED;
437 interface_bus_listener_t listener;
438
439 ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager,
440 reqid, TRUE);
441 if (ike_sa == NULL)
442 {
443 return NOT_FOUND;
444 }
445
446 iterator = ike_sa->create_child_sa_iterator(ike_sa);
447 while (iterator->iterate(iterator, (void**)&child_sa))
448 {
449 if (child_sa->get_state(child_sa) != CHILD_ROUTED &&
450 child_sa->get_reqid(child_sa) == reqid)
451 {
452 break;
453 }
454 child_sa = NULL;
455 }
456 iterator->destroy(iterator);
457
458 if (child_sa == NULL)
459 {
460 charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
461 return NOT_FOUND;
462 }
463
464 listener.listener.signal = (void*)terminate_child_listener;
465 listener.callback = callback ? callback : (interface_manager_cb_t)dummy_callback;
466 listener.ike_sa = ike_sa;
467 listener.param = param;
468 listener.cancelled = FALSE;
469
470 /* we listen passively to catch the signals we are raising */
471 charon->bus->add_listener(charon->bus, &listener.listener);
472 charon->bus->set_listen_state(charon->bus, TRUE);
473 status = ike_sa->delete_child_sa(ike_sa, child_sa->get_protocol(child_sa),
474 child_sa->get_spi(child_sa, TRUE));
475 if (status == DESTROY_ME)
476 {
477 charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa);
478 }
479 else
480 {
481 charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
482
483 /* wait until CHILD_SA is cleanly deleted using a delete message */
484 while (TRUE)
485 {
486 level_t level;
487 signal_t signal;
488 int thread;
489 ike_sa_t *current;
490 char* format;
491 va_list args;
492
493 /* stop listening if the passive listener returned FALSE */
494 if (listener.cancelled)
495 {
496 status = NEED_MORE;
497 break;
498 }
499 pthread_cleanup_push((void*)remove_listener, &listener);
500 signal = charon->bus->listen(charon->bus, &level, &thread,
501 &current, &format, &args);
502 pthread_cleanup_pop(0);
503 /* even if we checked in the IKE_SA, the pointer is valid until
504 * we get an IKE_DOWN_... */
505 if (ike_sa == current)
506 {
507 switch (signal)
508 {
509 case IKE_DOWN_FAILED:
510 case IKE_DOWN_SUCCESS:
511 case CHILD_DOWN_FAILED:
512 case CHILD_DOWN_SUCCESS:
513 {
514 status = SUCCESS;
515 break;
516 }
517 default:
518 continue;
519 }
520 break;
521 }
522 }
523 }
524 charon->bus->set_listen_state(charon->bus, FALSE);
525
526 return status;
527 }
528
529 /**
530 * Implementation of interface_manager_t.route.
531 */
532 static status_t route(interface_manager_t *this,
533 peer_cfg_t *peer_cfg, child_cfg_t *child_cfg,
534 interface_manager_cb_t callback, void *param)
535 {
536 ike_sa_t *ike_sa;
537 ike_cfg_t *ike_cfg;
538 status_t status = SUCCESS;
539
540 ike_cfg = peer_cfg->get_ike_cfg(peer_cfg);
541
542 ike_sa = charon->ike_sa_manager->checkout_by_peer(charon->ike_sa_manager,
543 ike_cfg->get_my_host(ike_cfg), ike_cfg->get_other_host(ike_cfg),
544 peer_cfg->get_my_id(peer_cfg), peer_cfg->get_other_id(peer_cfg));
545
546 if (ike_sa->get_peer_cfg(ike_sa) == NULL)
547 {
548 ike_sa->set_peer_cfg(ike_sa, peer_cfg);
549 }
550
551 /* we listen passively only, as routing is done by one thread only */
552 interface_bus_listener_t listener;
553
554 listener.listener.signal = (void*)route_listener;
555 listener.callback = callback ? callback : (interface_manager_cb_t)dummy_callback;
556 listener.ike_sa = ike_sa;
557 listener.param = param;
558 listener.cancelled = FALSE;
559 charon->bus->add_listener(charon->bus, &listener.listener);
560
561 if (ike_sa->route(ike_sa, child_cfg) != SUCCESS)
562 {
563 status = FAILED;
564 }
565 charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
566 return status;
567 }
568
569 /**
570 * Implementation of interface_manager_t.unroute.
571 */
572 static status_t unroute(interface_manager_t *this, u_int32_t reqid,
573 interface_manager_cb_t callback, void *param)
574 {
575 ike_sa_t *ike_sa;
576 status_t status;
577
578 ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager,
579 reqid, TRUE);
580 if (ike_sa == NULL)
581 {
582 return NOT_FOUND;
583 }
584
585 /* we listen passively only, as routing is done by one thread only */
586 interface_bus_listener_t listener;
587
588 listener.listener.signal = (void*)unroute_listener;
589 listener.callback = callback ? callback : (interface_manager_cb_t)dummy_callback;
590 listener.ike_sa = ike_sa;
591 listener.param = param;
592 listener.cancelled = FALSE;
593 charon->bus->add_listener(charon->bus, &listener.listener);
594
595 status = ike_sa->unroute(ike_sa, reqid);
596 if (status == DESTROY_ME)
597 {
598 charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa);
599 status = SUCCESS;
600 }
601 else
602 {
603 charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
604 }
605 return status;
606 }
607
608 /**
609 * load the control interface modules
610 */
611 static void load_interfaces(private_interface_manager_t *this)
612 {
613 struct dirent* entry;
614 DIR* dir;
615
616 dir = opendir(IPSEC_INTERFACEDIR);
617 if (dir == NULL)
618 {
619 DBG1(DBG_CFG, "error opening interface modules directory "IPSEC_INTERFACEDIR);
620 return;
621 }
622
623 DBG1(DBG_CFG, "loading control interface modules from '"IPSEC_INTERFACEDIR"'");
624
625 while ((entry = readdir(dir)) != NULL)
626 {
627 char file[256];
628 interface_t *interface;
629 interface_constructor_t constructor;
630 void *handle;
631 char *ending;
632
633 snprintf(file, sizeof(file), IPSEC_INTERFACEDIR"/%s", entry->d_name);
634
635 ending = entry->d_name + strlen(entry->d_name) - 3;
636 if (ending <= entry->d_name || !streq(ending, ".so"))
637 {
638 /* skip anything which does not look like a library */
639 DBG2(DBG_CFG, " skipping %s, doesn't look like a library",
640 entry->d_name);
641 continue;
642 }
643 /* try to load the library */
644 handle = dlopen(file, RTLD_LAZY);
645 if (handle == NULL)
646 {
647 DBG1(DBG_CFG, " opening control interface module %s failed: %s",
648 entry->d_name, dlerror());
649 continue;
650 }
651 constructor = dlsym(handle, "interface_create");
652 if (constructor == NULL)
653 {
654 DBG1(DBG_CFG, " interface module %s has no interface_create() "
655 "function, skipped", entry->d_name);
656 dlclose(handle);
657 continue;
658 }
659
660 interface = constructor();
661 if (interface == NULL)
662 {
663 DBG1(DBG_CFG, " unable to create instance of interface "
664 "module %s, skipped", entry->d_name);
665 dlclose(handle);
666 continue;
667 }
668 DBG1(DBG_CFG, " loaded control interface module successfully from %s", entry->d_name);
669 this->interfaces->insert_last(this->interfaces, interface);
670 this->handles->insert_last(this->handles, handle);
671 }
672 closedir(dir);
673 }
674
675
676 /**
677 * Implementation of stroke_t.destroy.
678 */
679 static void destroy(private_interface_manager_t *this)
680 {
681 this->interfaces->destroy_offset(this->interfaces, offsetof(interface_t, destroy));
682 this->handles->destroy_function(this->handles, (void*)dlclose);
683 free(this);
684 }
685
686 /*
687 * Described in header-file
688 */
689 interface_manager_t *interface_manager_create(void)
690 {
691 private_interface_manager_t *this = malloc_thing(private_interface_manager_t);
692
693 this->public.create_ike_sa_iterator = (iterator_t*(*)(interface_manager_t*))create_ike_sa_iterator;
694 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;
695 this->public.terminate_ike = (status_t(*)(interface_manager_t*,u_int32_t,interface_manager_cb_t, void*))terminate_ike;
696 this->public.terminate_child = (status_t(*)(interface_manager_t*,u_int32_t,interface_manager_cb_t, void *param))terminate_child;
697 this->public.route = (status_t(*)(interface_manager_t*,peer_cfg_t*, child_cfg_t*,interface_manager_cb_t,void*))route;
698 this->public.unroute = (status_t(*)(interface_manager_t*,u_int32_t,interface_manager_cb_t,void*))unroute;
699 this->public.destroy = (void (*)(interface_manager_t*))destroy;
700
701 this->interfaces = linked_list_create();
702 this->handles = linked_list_create();
703
704 load_interfaces(this);
705
706 return &this->public;
707 }
708