Return to stroke_control.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / libcharon / plugins / stroke |
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: }