Annotation of embedaddon/strongswan/src/libcharon/plugins/stroke/stroke_control.c, revision 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>