Annotation of embedaddon/strongswan/src/libcharon/plugins/stroke/stroke_control.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (C) 2013-2015 Tobias Brunner
3: * Copyright (C) 2008 Martin Willi
4: * HSR Hochschule fuer Technik Rapperswil
5: *
6: * This program is free software; you can redistribute it and/or modify it
7: * under the terms of the GNU General Public License as published by the
8: * Free Software Foundation; either version 2 of the License, or (at your
9: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10: *
11: * This program is distributed in the hope that it will be useful, but
12: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14: * for more details.
15: */
16:
17: #include "stroke_control.h"
18:
19: #include <daemon.h>
20:
21: #include <processing/jobs/delete_ike_sa_job.h>
22: #include <processing/jobs/rekey_ike_sa_job.h>
23: #include <processing/jobs/rekey_child_sa_job.h>
24:
25: typedef struct private_stroke_control_t private_stroke_control_t;
26:
27: /**
28: * private data of stroke_control
29: */
30: struct private_stroke_control_t {
31:
32: /**
33: * public functions
34: */
35: stroke_control_t public;
36:
37: /**
38: * Timeout for stroke commands, im ms
39: */
40: u_int timeout;
41: };
42:
43:
44: typedef struct stroke_log_info_t stroke_log_info_t;
45:
46: /**
47: * helper struct to say what and where to log when using controller callback
48: */
49: struct stroke_log_info_t {
50:
51: /**
52: * level to log up to
53: */
54: level_t level;
55:
56: /**
57: * where to write log
58: */
59: FILE* out;
60: };
61:
62: /**
63: * logging to the stroke interface
64: */
65: static bool stroke_log(stroke_log_info_t *info, debug_t group, level_t level,
66: ike_sa_t *ike_sa, char *message)
67: {
68: if (level <= info->level)
69: {
70: if (fprintf(info->out, "%s", message) < 0 ||
71: fprintf(info->out, "\n") < 0 ||
72: fflush(info->out) != 0)
73: {
74: return FALSE;
75: }
76: }
77: return TRUE;
78: }
79:
80: /**
81: * get the child_cfg with the same name as the peer cfg
82: */
83: static child_cfg_t* get_child_from_peer(peer_cfg_t *peer_cfg, char *name)
84: {
85: child_cfg_t *current, *found = NULL;
86: enumerator_t *enumerator;
87:
88: enumerator = peer_cfg->create_child_cfg_enumerator(peer_cfg);
89: while (enumerator->enumerate(enumerator, ¤t))
90: {
91: if (streq(current->get_name(current), name))
92: {
93: found = current;
94: found->get_ref(found);
95: break;
96: }
97: }
98: enumerator->destroy(enumerator);
99: return found;
100: }
101:
102: /**
103: * call the charon controller to initiate the connection
104: */
105: static void charon_initiate(private_stroke_control_t *this, peer_cfg_t *peer_cfg,
106: child_cfg_t *child_cfg, stroke_msg_t *msg, FILE *out)
107: {
108: if (msg->output_verbosity < 0)
109: {
110: charon->controller->initiate(charon->controller, peer_cfg, child_cfg,
111: NULL, NULL, 0, FALSE);
112: }
113: else
114: {
115: stroke_log_info_t info = { msg->output_verbosity, out };
116: status_t status;
117:
118: status = charon->controller->initiate(charon->controller,
119: peer_cfg, child_cfg, (controller_cb_t)stroke_log,
120: &info, this->timeout, FALSE);
121: switch (status)
122: {
123: case SUCCESS:
124: fprintf(out, "connection '%s' established successfully\n",
125: msg->initiate.name);
126: break;
127: case OUT_OF_RES:
128: fprintf(out, "connection '%s' not established after %dms, "
129: "detaching\n", msg->initiate.name, this->timeout);
130: break;
131: default:
132: case FAILED:
133: fprintf(out, "establishing connection '%s' failed\n",
134: msg->initiate.name);
135: break;
136: }
137: }
138: }
139:
140: METHOD(stroke_control_t, initiate, void,
141: private_stroke_control_t *this, stroke_msg_t *msg, FILE *out)
142: {
143: child_cfg_t *child_cfg = NULL;
144: peer_cfg_t *peer_cfg;
145: enumerator_t *enumerator;
146: bool empty = TRUE;
147:
148: peer_cfg = charon->backends->get_peer_cfg_by_name(charon->backends,
149: msg->initiate.name);
150: if (peer_cfg)
151: {
152: child_cfg = get_child_from_peer(peer_cfg, msg->initiate.name);
153: if (child_cfg == NULL)
154: {
155: enumerator = peer_cfg->create_child_cfg_enumerator(peer_cfg);
156: while (enumerator->enumerate(enumerator, &child_cfg))
157: {
158: empty = FALSE;
159: charon_initiate(this, peer_cfg->get_ref(peer_cfg),
160: child_cfg->get_ref(child_cfg), msg, out);
161: }
162: enumerator->destroy(enumerator);
163:
164: if (empty)
165: {
166: DBG1(DBG_CFG, "no child config named '%s'", msg->initiate.name);
167: fprintf(out, "no child config named '%s'\n", msg->initiate.name);
168: }
169: peer_cfg->destroy(peer_cfg);
170: return;
171: }
172: }
173: else
174: {
175: enumerator = charon->backends->create_peer_cfg_enumerator(
176: charon->backends, NULL, NULL, NULL, NULL, IKE_ANY);
177: while (enumerator->enumerate(enumerator, &peer_cfg))
178: {
179: child_cfg = get_child_from_peer(peer_cfg, msg->initiate.name);
180: if (child_cfg)
181: {
182: peer_cfg->get_ref(peer_cfg);
183: break;
184: }
185: }
186: enumerator->destroy(enumerator);
187:
188: if (child_cfg == NULL)
189: {
190: DBG1(DBG_CFG, "no config named '%s'", msg->initiate.name);
191: fprintf(out, "no config named '%s'\n", msg->initiate.name);
192: return;
193: }
194: }
195: charon_initiate(this, peer_cfg, child_cfg, msg, out);
196: }
197:
198: /**
199: * Parse a terminate/rekey specifier
200: */
201: static bool parse_specifier(char *string, uint32_t *id,
202: char **name, bool *child, bool *all)
203: {
204: int len;
205: char *pos = NULL;
206:
207: *id = 0;
208: *name = NULL;
209: *all = FALSE;
210:
211: len = strlen(string);
212: if (len < 1)
213: {
214: return FALSE;
215: }
216: switch (string[len-1])
217: {
218: case '}':
219: *child = TRUE;
220: pos = strchr(string, '{');
221: break;
222: case ']':
223: *child = FALSE;
224: pos = strchr(string, '[');
225: break;
226: default:
227: *name = string;
228: *child = FALSE;
229: break;
230: }
231:
232: if (*name)
233: {
234: /* is a single name */
235: }
236: else if (pos == string + len - 2)
237: { /* is name[] or name{} */
238: string[len-2] = '\0';
239: *name = string;
240: }
241: else
242: {
243: if (!pos)
244: {
245: return FALSE;
246: }
247: if (*(pos + 1) == '*')
248: { /* is name[*] */
249: *all = TRUE;
250: *pos = '\0';
251: *name = string;
252: }
253: else
254: { /* is name[123] or name{23} */
255: *id = atoi(pos + 1);
256: if (*id == 0)
257: {
258: return FALSE;
259: }
260: }
261: }
262: return TRUE;
263: }
264:
265: /**
266: * Report the result of a terminate() call to console
267: */
268: static void report_terminate_status(private_stroke_control_t *this,
269: status_t status, FILE *out, uint32_t id, bool child)
270: {
271: char *prefix, *postfix;
272:
273: if (child)
274: {
275: prefix = "CHILD_SA {";
276: postfix = "}";
277: }
278: else
279: {
280: prefix = "IKE_SA [";
281: postfix = "]";
282: }
283:
284: switch (status)
285: {
286: case SUCCESS:
287: fprintf(out, "%s%d%s closed successfully\n", prefix, id, postfix);
288: break;
289: case OUT_OF_RES:
290: fprintf(out, "%s%d%s not closed after %dms, detaching\n",
291: prefix, id, postfix, this->timeout);
292: break;
293: default:
294: case FAILED:
295: fprintf(out, "closing %s%d%s failed\n", prefix, id, postfix);
296: break;
297: }
298: }
299:
300: /**
301: * Call the charon controller to terminate a CHILD_SA
302: */
303: static void charon_terminate(private_stroke_control_t *this, uint32_t id,
304: stroke_msg_t *msg, FILE *out, bool child)
305: {
306: if (msg->output_verbosity >= 0)
307: {
308: stroke_log_info_t info = { msg->output_verbosity, out };
309: status_t status;
310:
311: if (child)
312: {
313: status = charon->controller->terminate_child(charon->controller, id,
314: (controller_cb_t)stroke_log, &info, this->timeout);
315: }
316: else
317: {
318: status = charon->controller->terminate_ike(charon->controller, id,
319: FALSE, (controller_cb_t)stroke_log, &info,
320: this->timeout);
321: }
322: report_terminate_status(this, status, out, id, child);
323: }
324: else if (child)
325: {
326: charon->controller->terminate_child(charon->controller, id,
327: NULL, NULL, 0);
328: }
329: else
330: {
331: charon->controller->terminate_ike(charon->controller, id, FALSE,
332: NULL, NULL, 0);
333: }
334: }
335:
336: METHOD(stroke_control_t, terminate, void,
337: private_stroke_control_t *this, stroke_msg_t *msg, FILE *out)
338: {
339: char *name;
340: uint32_t id;
341: bool child, all;
342: ike_sa_t *ike_sa;
343: enumerator_t *enumerator;
344: linked_list_t *ike_list, *child_list;
345: uintptr_t del;
346:
347: if (!parse_specifier(msg->terminate.name, &id, &name, &child, &all))
348: {
349: DBG1(DBG_CFG, "error parsing specifier string");
350: return;
351: }
352:
353: if (id)
354: {
355: return charon_terminate(this, id, msg, out, child);
356: }
357:
358: ike_list = linked_list_create();
359: child_list = linked_list_create();
360: enumerator = charon->controller->create_ike_sa_enumerator(
361: charon->controller, TRUE);
362: while (enumerator->enumerate(enumerator, &ike_sa))
363: {
364: child_sa_t *child_sa;
365: enumerator_t *children;
366:
367: if (child)
368: {
369: children = ike_sa->create_child_sa_enumerator(ike_sa);
370: while (children->enumerate(children, (void**)&child_sa))
371: {
372: if (streq(name, child_sa->get_name(child_sa)))
373: {
374: child_list->insert_last(child_list,
375: (void*)(uintptr_t)child_sa->get_unique_id(child_sa));
376: if (!all)
377: {
378: break;
379: }
380: }
381: }
382: children->destroy(children);
383: if (child_list->get_count(child_list) && !all)
384: {
385: break;
386: }
387: }
388: else if (streq(name, ike_sa->get_name(ike_sa)))
389: {
390: ike_list->insert_last(ike_list,
391: (void*)(uintptr_t)ike_sa->get_unique_id(ike_sa));
392: if (!all)
393: {
394: break;
395: }
396: }
397: }
398: enumerator->destroy(enumerator);
399:
400: enumerator = child_list->create_enumerator(child_list);
401: while (enumerator->enumerate(enumerator, &del))
402: {
403: charon_terminate(this, del, msg, out, TRUE);
404: }
405: enumerator->destroy(enumerator);
406:
407: enumerator = ike_list->create_enumerator(ike_list);
408: while (enumerator->enumerate(enumerator, &del))
409: {
410: charon_terminate(this, del, msg, out, FALSE);
411: }
412: enumerator->destroy(enumerator);
413:
414: if (child_list->get_count(child_list) == 0 &&
415: ike_list->get_count(ike_list) == 0)
416: {
417: DBG1(DBG_CFG, "no %s_SA named '%s' found",
418: child ? "CHILD" : "IKE", name);
419: }
420: ike_list->destroy(ike_list);
421: child_list->destroy(child_list);
422: }
423:
424: METHOD(stroke_control_t, rekey, void,
425: private_stroke_control_t *this, stroke_msg_t *msg, FILE *out)
426: {
427: char *name;
428: uint32_t id;
429: bool child, all, finished = FALSE;
430: ike_sa_t *ike_sa;
431: enumerator_t *enumerator;
432:
433: if (!parse_specifier(msg->terminate.name, &id, &name, &child, &all))
434: {
435: DBG1(DBG_CFG, "error parsing specifier string");
436: return;
437: }
438: enumerator = charon->controller->create_ike_sa_enumerator(
439: charon->controller, TRUE);
440: while (enumerator->enumerate(enumerator, &ike_sa))
441: {
442: child_sa_t *child_sa;
443: enumerator_t *children;
444:
445: if (child)
446: {
447: children = ike_sa->create_child_sa_enumerator(ike_sa);
448: while (children->enumerate(children, (void**)&child_sa))
449: {
450: if ((name && streq(name, child_sa->get_name(child_sa))) ||
451: (id && id == child_sa->get_unique_id(child_sa)))
452: {
453: lib->processor->queue_job(lib->processor,
454: (job_t*)rekey_child_sa_job_create(
455: child_sa->get_protocol(child_sa),
456: child_sa->get_spi(child_sa, TRUE),
457: ike_sa->get_my_host(ike_sa)));
458: if (!all)
459: {
460: finished = TRUE;
461: break;
462: }
463: }
464: }
465: children->destroy(children);
466: }
467: else if ((name && streq(name, ike_sa->get_name(ike_sa))) ||
468: (id && id == ike_sa->get_unique_id(ike_sa)))
469: {
470: lib->processor->queue_job(lib->processor,
471: (job_t*)rekey_ike_sa_job_create(ike_sa->get_id(ike_sa), FALSE));
472: if (!all)
473: {
474: finished = TRUE;
475: }
476: }
477: if (finished)
478: {
479: break;
480: }
481: }
482: enumerator->destroy(enumerator);
483: }
484:
485: METHOD(stroke_control_t, terminate_srcip, void,
486: private_stroke_control_t *this, stroke_msg_t *msg, FILE *out)
487: {
488: enumerator_t *enumerator, *vips;
489: ike_sa_t *ike_sa;
490: host_t *start = NULL, *end = NULL, *vip;
491: chunk_t chunk_start, chunk_end = chunk_empty, chunk;
492:
493: if (msg->terminate_srcip.start)
494: {
495: start = host_create_from_string(msg->terminate_srcip.start, 0);
496: }
497: if (!start)
498: {
499: DBG1(DBG_CFG, "invalid start address: %s", msg->terminate_srcip.start);
500: return;
501: }
502: chunk_start = start->get_address(start);
503: if (msg->terminate_srcip.end)
504: {
505: end = host_create_from_string(msg->terminate_srcip.end, 0);
506: if (!end)
507: {
508: DBG1(DBG_CFG, "invalid end address: %s", msg->terminate_srcip.end);
509: start->destroy(start);
510: return;
511: }
512: chunk_end = end->get_address(end);
513: }
514:
515: enumerator = charon->controller->create_ike_sa_enumerator(
516: charon->controller, TRUE);
517: while (enumerator->enumerate(enumerator, &ike_sa))
518: {
519: bool match = FALSE;
520:
521: vips = ike_sa->create_virtual_ip_enumerator(ike_sa, FALSE);
522: while (vips->enumerate(vips, &vip))
523: {
524: if (!end)
525: {
526: if (vip->ip_equals(vip, start))
527: {
528: match = TRUE;
529: break;
530: }
531: }
532: else
533: {
534: chunk = vip->get_address(vip);
535: if (chunk.len == chunk_start.len &&
536: chunk.len == chunk_end.len &&
537: memcmp(chunk.ptr, chunk_start.ptr, chunk.len) >= 0 &&
538: memcmp(chunk.ptr, chunk_end.ptr, chunk.len) <= 0)
539: {
540: match = TRUE;
541: break;
542: }
543: }
544: }
545: vips->destroy(vips);
546:
547: if (match)
548: {
549: /* schedule delete asynchronously */
550: lib->processor->queue_job(lib->processor, (job_t*)
551: delete_ike_sa_job_create(ike_sa->get_id(ike_sa), TRUE));
552: }
553: }
554: enumerator->destroy(enumerator);
555: start->destroy(start);
556: DESTROY_IF(end);
557: }
558:
559: METHOD(stroke_control_t, purge_ike, void,
560: private_stroke_control_t *this, stroke_msg_t *msg, FILE *out)
561: {
562: enumerator_t *enumerator, *children;
563: ike_sa_t *ike_sa;
564: child_sa_t *child_sa;
565: linked_list_t *list;
566: uintptr_t del;
567:
568: list = linked_list_create();
569: enumerator = charon->controller->create_ike_sa_enumerator(
570: charon->controller, TRUE);
571: while (enumerator->enumerate(enumerator, &ike_sa))
572: {
573: children = ike_sa->create_child_sa_enumerator(ike_sa);
574: if (!children->enumerate(children, (void**)&child_sa))
575: {
576: list->insert_last(list,
577: (void*)(uintptr_t)ike_sa->get_unique_id(ike_sa));
578: }
579: children->destroy(children);
580: }
581: enumerator->destroy(enumerator);
582:
583: enumerator = list->create_enumerator(list);
584: while (enumerator->enumerate(enumerator, &del))
585: {
586: charon_terminate(this, del, msg, out, FALSE);
587: }
588: enumerator->destroy(enumerator);
589: list->destroy(list);
590: }
591:
592: /**
593: * call charon to install a shunt or trap
594: */
595: static void charon_route(peer_cfg_t *peer_cfg, child_cfg_t *child_cfg,
596: char *name, FILE *out)
597: {
598: ipsec_mode_t mode;
599:
600: mode = child_cfg->get_mode(child_cfg);
601: if (mode == MODE_PASS || mode == MODE_DROP)
602: {
603: if (charon->shunts->install(charon->shunts,
604: peer_cfg->get_name(peer_cfg), child_cfg))
605: {
606: fprintf(out, "'%s' shunt %N policy installed\n",
607: name, ipsec_mode_names, mode);
608: }
609: else
610: {
611: fprintf(out, "'%s' shunt %N policy installation failed\n",
612: name, ipsec_mode_names, mode);
613: }
614: }
615: else
616: {
617: if (charon->traps->install(charon->traps, peer_cfg, child_cfg))
618: {
619: fprintf(out, "'%s' routed\n", name);
620: }
621: else
622: {
623: fprintf(out, "routing '%s' failed\n", name);
624: }
625: }
626: }
627:
628: METHOD(stroke_control_t, route, void,
629: private_stroke_control_t *this, stroke_msg_t *msg, FILE *out)
630: {
631: child_cfg_t *child_cfg = NULL;
632: peer_cfg_t *peer_cfg;
633: enumerator_t *enumerator;
634: bool empty = TRUE;
635:
636: peer_cfg = charon->backends->get_peer_cfg_by_name(charon->backends,
637: msg->route.name);
638: if (peer_cfg)
639: {
640: child_cfg = get_child_from_peer(peer_cfg, msg->route.name);
641: if (child_cfg == NULL)
642: {
643: enumerator = peer_cfg->create_child_cfg_enumerator(peer_cfg);
644: while (enumerator->enumerate(enumerator, &child_cfg))
645: {
646: empty = FALSE;
647: charon_route(peer_cfg, child_cfg, child_cfg->get_name(child_cfg),
648: out);
649: }
650: enumerator->destroy(enumerator);
651:
652: if (empty)
653: {
654: DBG1(DBG_CFG, "no child config named '%s'", msg->route.name);
655: fprintf(out, "no child config named '%s'\n", msg->route.name);
656: }
657: peer_cfg->destroy(peer_cfg);
658: return;
659: }
660: }
661: else
662: {
663: enumerator = charon->backends->create_peer_cfg_enumerator(
664: charon->backends, NULL, NULL, NULL, NULL, IKE_ANY);
665: while (enumerator->enumerate(enumerator, &peer_cfg))
666: {
667: child_cfg = get_child_from_peer(peer_cfg, msg->route.name);
668: if (child_cfg)
669: {
670: peer_cfg->get_ref(peer_cfg);
671: break;
672: }
673: }
674: enumerator->destroy(enumerator);
675:
676: if (child_cfg == NULL)
677: {
678: DBG1(DBG_CFG, "no config named '%s'", msg->route.name);
679: fprintf(out, "no config named '%s'\n", msg->route.name);
680: return;
681: }
682: }
683: charon_route(peer_cfg, child_cfg, msg->route.name, out);
684: peer_cfg->destroy(peer_cfg);
685: child_cfg->destroy(child_cfg);
686: }
687:
688: METHOD(stroke_control_t, unroute, void,
689: private_stroke_control_t *this, stroke_msg_t *msg, FILE *out)
690: {
691: if (charon->shunts->uninstall(charon->shunts, NULL, msg->unroute.name))
692: {
693: fprintf(out, "shunt policy '%s' uninstalled\n", msg->unroute.name);
694: }
695: else if (charon->traps->uninstall(charon->traps, NULL, msg->unroute.name))
696: {
697: fprintf(out, "trap policy '%s' unrouted\n", msg->unroute.name);
698: }
699: else
700: {
701: fprintf(out, "configuration '%s' not found\n", msg->unroute.name);
702: }
703: }
704:
705: METHOD(stroke_control_t, destroy, void,
706: private_stroke_control_t *this)
707: {
708: free(this);
709: }
710:
711: /*
712: * see header file
713: */
714: stroke_control_t *stroke_control_create()
715: {
716: private_stroke_control_t *this;
717:
718: INIT(this,
719: .public = {
720: .initiate = _initiate,
721: .terminate = _terminate,
722: .terminate_srcip = _terminate_srcip,
723: .rekey = _rekey,
724: .purge_ike = _purge_ike,
725: .route = _route,
726: .unroute = _unroute,
727: .destroy = _destroy,
728: },
729: .timeout = lib->settings->get_int(lib->settings,
730: "%s.plugins.stroke.timeout", 0, lib->ns),
731: );
732:
733: return &this->public;
734: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>