split connections with different virtual IPs in different peer_cfgs
[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 /**
61 * helper struct to map bus listener callbacks to interface callbacks
62 */
63 struct interface_bus_listener_t {
64
65 /**
66 * public bus listener interface
67 */
68 bus_listener_t public;
69
70 /**
71 * status of the operation, return to method callers
72 */
73 status_t status;
74
75 /**
76 * IKE SA to filter log output
77 */
78 ike_sa_t *ike_sa;
79
80 /**
81 * interface callback (listener gets redirected to here)
82 */
83 interface_manager_cb_t callback;
84
85 /**
86 * user parameter to pass to callback
87 */
88 void *param;
89
90 /**
91 * child configuration, used for initiate
92 */
93 child_cfg_t *child_cfg;
94
95 /**
96 * peer configuration, used for initiate
97 */
98 peer_cfg_t *peer_cfg;
99
100 /**
101 * unique ID, used for various methods
102 */
103 u_int32_t id;
104 };
105
106
107 typedef struct interface_job_t interface_job_t;
108
109 /**
110 * job for asynchronous listen operations
111 */
112 struct interface_job_t {
113 /**
114 * job interface
115 */
116 job_t public;
117
118 /**
119 * associated listener
120 */
121 interface_bus_listener_t listener;
122 };
123
124 /**
125 * Implements the famous nop operation
126 */
127 static void nop(job_t *job)
128 {
129 /* NOP */
130 }
131
132 /**
133 * Implementation of interface_manager_t.create_ike_sa_iterator.
134 */
135 static iterator_t* create_ike_sa_iterator(interface_manager_t *this)
136 {
137 return charon->ike_sa_manager->create_iterator(charon->ike_sa_manager);
138 }
139
140 /**
141 * listener function for initiate
142 */
143 static bool initiate_listener(interface_bus_listener_t *this, signal_t signal,
144 level_t level, int thread, ike_sa_t *ike_sa,
145 char* format, va_list args)
146 {
147 if (this->ike_sa == ike_sa)
148 {
149 if (!this->callback(this->param, signal, level, ike_sa, format, args))
150 {
151 return FALSE;
152 }
153 switch (signal)
154 {
155 case CHILD_UP_SUCCESS:
156 this->status = SUCCESS;
157 return FALSE;
158 case IKE_UP_FAILED:
159 case CHILD_UP_FAILED:
160 return FALSE;
161 default:
162 break;
163 }
164 }
165 return TRUE;
166 }
167
168 /**
169 * execute function for initiate
170 */
171 static status_t initiate_execute(interface_job_t *job)
172 {
173 ike_sa_t *ike_sa;
174 interface_bus_listener_t *listener = &job->listener;
175 peer_cfg_t *peer_cfg = listener->peer_cfg;
176
177 ike_sa = charon->ike_sa_manager->checkout_by_config(charon->ike_sa_manager,
178 peer_cfg);
179 listener->ike_sa = ike_sa;
180
181 if (ike_sa->get_peer_cfg(ike_sa) == NULL)
182 {
183 ike_sa->set_peer_cfg(ike_sa, peer_cfg);
184 }
185 peer_cfg->destroy(peer_cfg);
186
187 if (ike_sa->initiate(ike_sa, listener->child_cfg) != SUCCESS)
188 {
189 return charon->ike_sa_manager->checkin_and_destroy(
190 charon->ike_sa_manager, ike_sa);
191 }
192 return charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
193 }
194
195 /**
196 * Implementation of interface_manager_t.initiate.
197 */
198 static status_t initiate(private_interface_manager_t *this,
199 peer_cfg_t *peer_cfg, child_cfg_t *child_cfg,
200 interface_manager_cb_t callback, void *param)
201 {
202 interface_job_t job;
203
204 job.listener.public.signal = (void*)initiate_listener;
205 job.listener.ike_sa = NULL;
206 job.listener.callback = callback;
207 job.listener.param = param;
208 job.listener.status = FAILED;
209 job.listener.child_cfg = child_cfg;
210 job.listener.peer_cfg = peer_cfg;
211 job.public.execute = (void*)initiate_execute;
212 job.public.destroy = nop;
213
214 if (callback == NULL)
215 {
216 return initiate_execute(&job);
217 }
218 charon->bus->listen(charon->bus, (bus_listener_t*)&job.listener, (job_t*)&job);
219 return job.listener.status;
220 }
221
222 /**
223 * listener function for terminate_ike
224 */
225 static bool terminate_ike_listener(interface_bus_listener_t *this, signal_t signal,
226 level_t level, int thread, ike_sa_t *ike_sa,
227 char* format, va_list args)
228 {
229 if (this->ike_sa == ike_sa)
230 {
231 if (!this->callback(this->param, signal, level, ike_sa, format, args))
232 {
233 return FALSE;
234 }
235 switch (signal)
236 {
237 case IKE_DOWN_SUCCESS:
238 this->status = SUCCESS;
239 return FALSE;
240 case IKE_DOWN_FAILED:
241 return FALSE;
242 default:
243 break;
244 }
245 }
246 return TRUE;
247 }
248
249 /**
250 * execute function for terminate_ike
251 */
252 static status_t terminate_ike_execute(interface_job_t *job)
253 {
254 ike_sa_t *ike_sa;
255 interface_bus_listener_t *listener = &job->listener;
256
257 ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager,
258 listener->id, FALSE);
259 if (ike_sa == NULL)
260 {
261 SIG(IKE_DOWN_FAILED, "unable to terminate, IKE_SA with "
262 "ID %d not found", listener->id);
263 return NOT_FOUND;
264 }
265 listener->ike_sa = ike_sa;
266
267 if (ike_sa->delete(ike_sa) == DESTROY_ME)
268 {
269 return charon->ike_sa_manager->checkin_and_destroy(
270 charon->ike_sa_manager, ike_sa);
271 }
272 return charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
273 }
274
275 /**
276 * Implementation of interface_manager_t.terminate_ike.
277 */
278 static status_t terminate_ike(interface_manager_t *this, u_int32_t unique_id,
279 interface_manager_cb_t callback, void *param)
280 {
281 interface_job_t job;
282
283 job.listener.public.signal = (void*)terminate_ike_listener;
284 job.listener.ike_sa = NULL;
285 job.listener.callback = callback;
286 job.listener.param = param;
287 job.listener.status = FAILED;
288 job.listener.id = unique_id;
289 job.public.execute = (void*)terminate_ike_execute;
290 job.public.destroy = nop;
291
292 if (callback == NULL)
293 {
294 return terminate_ike_execute(&job);
295 }
296 charon->bus->listen(charon->bus, (bus_listener_t*)&job.listener, (job_t*)&job);
297 return job.listener.status;
298 }
299 /**
300 * listener function for terminate_child
301 */
302 static bool terminate_child_listener(interface_bus_listener_t *this, signal_t signal,
303 level_t level, int thread, ike_sa_t *ike_sa,
304 char* format, va_list args)
305 {
306 if (this->ike_sa == ike_sa)
307 {
308 if (!this->callback(this->param, signal, level, ike_sa, format, args))
309 {
310 return FALSE;
311 }
312 switch (signal)
313 {
314 case CHILD_DOWN_SUCCESS:
315 case IKE_DOWN_SUCCESS:
316 this->status = SUCCESS;
317 return FALSE;
318 case IKE_DOWN_FAILED:
319 case CHILD_DOWN_FAILED:
320 return FALSE;
321 default:
322 break;
323 }
324 }
325 return TRUE;
326 }
327
328 /**
329 * execute function for terminate_child
330 */
331 static status_t terminate_child_execute(interface_job_t *job)
332 {
333 ike_sa_t *ike_sa;
334 child_sa_t *child_sa;
335 iterator_t *iterator;
336 interface_bus_listener_t *listener = &job->listener;
337
338 ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager,
339 listener->id, TRUE);
340 if (ike_sa == NULL)
341 {
342 SIG(CHILD_DOWN_FAILED, "unable to terminate, CHILD_SA with "
343 "ID %d not found", listener->id);
344 return NOT_FOUND;
345 }
346 listener->ike_sa = ike_sa;
347
348 iterator = ike_sa->create_child_sa_iterator(ike_sa);
349 while (iterator->iterate(iterator, (void**)&child_sa))
350 {
351 if (child_sa->get_state(child_sa) != CHILD_ROUTED &&
352 child_sa->get_reqid(child_sa) == listener->id)
353 {
354 break;
355 }
356 child_sa = NULL;
357 }
358 iterator->destroy(iterator);
359
360 if (child_sa == NULL)
361 {
362 SIG(CHILD_DOWN_FAILED, "unable to terminate, established CHILD_SA with "
363 "ID %d not found", listener->id);
364 charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
365 return NOT_FOUND;
366 }
367
368 if (ike_sa->delete_child_sa(ike_sa, child_sa->get_protocol(child_sa),
369 child_sa->get_spi(child_sa, TRUE)) == DESTROY_ME)
370 {
371 return charon->ike_sa_manager->checkin_and_destroy(
372 charon->ike_sa_manager, ike_sa);
373 }
374 return charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
375 }
376
377 /**
378 * Implementation of interface_manager_t.terminate_child.
379 */
380 static status_t terminate_child(interface_manager_t *this, u_int32_t reqid,
381 interface_manager_cb_t callback, void *param)
382 {
383 interface_job_t job;
384
385 job.listener.public.signal = (void*)terminate_child_listener;
386 job.listener.ike_sa = NULL;
387 job.listener.callback = callback;
388 job.listener.param = param;
389 job.listener.status = FAILED;
390 job.listener.id = reqid;
391 job.public.execute = (void*)terminate_child_execute;
392 job.public.destroy = nop;
393
394 if (callback == NULL)
395 {
396 return terminate_child_execute(&job);
397 }
398 charon->bus->listen(charon->bus, (bus_listener_t*)&job.listener, (job_t*)&job);
399 return job.listener.status;
400 }
401
402 /**
403 * listener function for route
404 */
405 static bool route_listener(interface_bus_listener_t *this, signal_t signal,
406 level_t level, int thread, ike_sa_t *ike_sa,
407 char* format, va_list args)
408 {
409 if (this->ike_sa == ike_sa)
410 {
411 if (!this->callback(this->param, signal, level, ike_sa, format, args))
412 {
413 return FALSE;
414 }
415 switch (signal)
416 {
417 case CHILD_ROUTE_SUCCESS:
418 this->status = SUCCESS;
419 return FALSE;
420 case CHILD_ROUTE_FAILED:
421 return FALSE;
422 default:
423 break;
424 }
425 }
426 return TRUE;
427 }
428
429 /**
430 * execute function for route
431 */
432 static status_t route_execute(interface_job_t *job)
433 {
434 ike_sa_t *ike_sa;
435 interface_bus_listener_t *listener = &job->listener;
436 peer_cfg_t *peer_cfg = listener->peer_cfg;
437
438 ike_sa = charon->ike_sa_manager->checkout_by_config(charon->ike_sa_manager,
439 peer_cfg);
440 listener->ike_sa = ike_sa;
441
442 if (ike_sa->get_peer_cfg(ike_sa) == NULL)
443 {
444 ike_sa->set_peer_cfg(ike_sa, peer_cfg);
445 }
446 if (ike_sa->route(ike_sa, listener->child_cfg) == DESTROY_ME)
447 {
448 return charon->ike_sa_manager->checkin_and_destroy(
449 charon->ike_sa_manager, ike_sa);
450 }
451 return charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
452 }
453
454 /**
455 * Implementation of interface_manager_t.route.
456 */
457 static status_t route(interface_manager_t *this,
458 peer_cfg_t *peer_cfg, child_cfg_t *child_cfg,
459 interface_manager_cb_t callback, void *param)
460 {
461 interface_job_t job;
462
463 job.listener.public.signal = (void*)route_listener;
464 job.listener.ike_sa = NULL;
465 job.listener.callback = callback;
466 job.listener.param = param;
467 job.listener.status = FAILED;
468 job.listener.peer_cfg = peer_cfg;
469 job.listener.child_cfg = child_cfg;
470 job.public.execute = (void*)route_execute;
471 job.public.destroy = nop;
472
473 if (callback == NULL)
474 {
475 return route_execute(&job);
476 }
477 charon->bus->listen(charon->bus, (bus_listener_t*)&job.listener, (job_t*)&job);
478 return job.listener.status;
479 }
480
481 /**
482 * listener function for unroute
483 */
484 static bool unroute_listener(interface_bus_listener_t *this, signal_t signal,
485 level_t level, int thread, ike_sa_t *ike_sa,
486 char* format, va_list args)
487 {
488 if (this->ike_sa == ike_sa)
489 {
490 if (!this->callback(this->param, signal, level, ike_sa, format, args))
491 {
492 return FALSE;
493 }
494 switch (signal)
495 {
496 case CHILD_UNROUTE_SUCCESS:
497 this->status = SUCCESS;
498 return FALSE;
499 case CHILD_UNROUTE_FAILED:
500 return FALSE;
501 default:
502 break;
503 }
504 }
505 return TRUE;
506 }
507 /**
508 * execute function for unroute
509 */
510 static status_t unroute_execute(interface_job_t *job)
511 {
512 ike_sa_t *ike_sa;
513 interface_bus_listener_t *listener = &job->listener;
514
515 ike_sa = charon->ike_sa_manager->checkout_by_id(charon->ike_sa_manager,
516 listener->id, TRUE);
517 if (ike_sa == NULL)
518 {
519 SIG(CHILD_DOWN_FAILED, "unable to unroute, CHILD_SA with "
520 "ID %d not found", listener->id);
521 return NOT_FOUND;
522 }
523 listener->ike_sa = ike_sa;
524 if (ike_sa->unroute(ike_sa, listener->id) == DESTROY_ME)
525 {
526 return charon->ike_sa_manager->checkin_and_destroy(
527 charon->ike_sa_manager, ike_sa);
528 }
529 return charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
530 }
531
532 /**
533 * Implementation of interface_manager_t.unroute.
534 */
535 static status_t unroute(interface_manager_t *this, u_int32_t reqid,
536 interface_manager_cb_t callback, void *param)
537 {
538 interface_job_t job;
539
540 job.listener.public.signal = (void*)unroute_listener;
541 job.listener.ike_sa = NULL;
542 job.listener.callback = callback;
543 job.listener.param = param;
544 job.listener.status = FAILED;
545 job.listener.id = reqid;
546 job.public.execute = (void*)unroute_execute;
547 job.public.destroy = nop;
548
549 if (callback == NULL)
550 {
551 return unroute_execute(&job);
552 }
553 charon->bus->listen(charon->bus, (bus_listener_t*)&job.listener, (job_t*)&job);
554 return job.listener.status;
555 }
556
557 /**
558 * load the control interface modules
559 */
560 static void load_interfaces(private_interface_manager_t *this)
561 {
562 struct dirent* entry;
563 DIR* dir;
564
565 dir = opendir(IPSEC_INTERFACEDIR);
566 if (dir == NULL)
567 {
568 DBG1(DBG_CFG, "error opening interface modules directory "IPSEC_INTERFACEDIR);
569 return;
570 }
571
572 DBG1(DBG_CFG, "loading control interface modules from '"IPSEC_INTERFACEDIR"'");
573
574 while ((entry = readdir(dir)) != NULL)
575 {
576 char file[256];
577 interface_t *interface;
578 interface_constructor_t constructor;
579 void *handle;
580 char *ending;
581
582 snprintf(file, sizeof(file), IPSEC_INTERFACEDIR"/%s", entry->d_name);
583
584 ending = entry->d_name + strlen(entry->d_name) - 3;
585 if (ending <= entry->d_name || !streq(ending, ".so"))
586 {
587 /* skip anything which does not look like a library */
588 DBG2(DBG_CFG, " skipping %s, doesn't look like a library",
589 entry->d_name);
590 continue;
591 }
592 /* try to load the library */
593 handle = dlopen(file, RTLD_LAZY);
594 if (handle == NULL)
595 {
596 DBG1(DBG_CFG, " opening control interface module %s failed: %s",
597 entry->d_name, dlerror());
598 continue;
599 }
600 constructor = dlsym(handle, "interface_create");
601 if (constructor == NULL)
602 {
603 DBG1(DBG_CFG, " interface module %s has no interface_create() "
604 "function, skipped", entry->d_name);
605 dlclose(handle);
606 continue;
607 }
608
609 interface = constructor();
610 if (interface == NULL)
611 {
612 DBG1(DBG_CFG, " unable to create instance of interface "
613 "module %s, skipped", entry->d_name);
614 dlclose(handle);
615 continue;
616 }
617 DBG1(DBG_CFG, " loaded control interface module successfully from %s", entry->d_name);
618 this->interfaces->insert_last(this->interfaces, interface);
619 this->handles->insert_last(this->handles, handle);
620 }
621 closedir(dir);
622 }
623
624 /**
625 * See header
626 */
627 bool interface_manager_cb_empty(void *param, signal_t signal, level_t level,
628 ike_sa_t *ike_sa, char *format, va_list args)
629 {
630 return TRUE;
631 }
632
633 /**
634 * Implementation of stroke_t.destroy.
635 */
636 static void destroy(private_interface_manager_t *this)
637 {
638 this->interfaces->destroy_offset(this->interfaces, offsetof(interface_t, destroy));
639 this->handles->destroy_function(this->handles, (void*)dlclose);
640 free(this);
641 }
642
643 /*
644 * Described in header-file
645 */
646 interface_manager_t *interface_manager_create(void)
647 {
648 private_interface_manager_t *this = malloc_thing(private_interface_manager_t);
649
650 this->public.create_ike_sa_iterator = (iterator_t*(*)(interface_manager_t*))create_ike_sa_iterator;
651 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;
652 this->public.terminate_ike = (status_t(*)(interface_manager_t*,u_int32_t,interface_manager_cb_t, void*))terminate_ike;
653 this->public.terminate_child = (status_t(*)(interface_manager_t*,u_int32_t,interface_manager_cb_t, void *param))terminate_child;
654 this->public.route = (status_t(*)(interface_manager_t*,peer_cfg_t*, child_cfg_t*,interface_manager_cb_t,void*))route;
655 this->public.unroute = (status_t(*)(interface_manager_t*,u_int32_t,interface_manager_cb_t,void*))unroute;
656 this->public.destroy = (void (*)(interface_manager_t*))destroy;
657
658 this->interfaces = linked_list_create();
659 this->handles = linked_list_create();
660
661 load_interfaces(this);
662
663 return &this->public;
664 }
665