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