Annotation of embedaddon/strongswan/src/libcharon/sa/ikev2/tasks/child_create.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2008-2019 Tobias Brunner
! 3: * Copyright (C) 2005-2008 Martin Willi
! 4: * Copyright (C) 2005 Jan Hutter
! 5: * HSR Hochschule fuer Technik Rapperswil
! 6: *
! 7: * This program is free software; you can redistribute it and/or modify it
! 8: * under the terms of the GNU General Public License as published by the
! 9: * Free Software Foundation; either version 2 of the License, or (at your
! 10: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
! 11: *
! 12: * This program is distributed in the hope that it will be useful, but
! 13: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
! 14: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
! 15: * for more details.
! 16: */
! 17:
! 18: #include "child_create.h"
! 19:
! 20: #include <daemon.h>
! 21: #include <sa/ikev2/keymat_v2.h>
! 22: #include <crypto/diffie_hellman.h>
! 23: #include <credentials/certificates/x509.h>
! 24: #include <encoding/payloads/sa_payload.h>
! 25: #include <encoding/payloads/ke_payload.h>
! 26: #include <encoding/payloads/ts_payload.h>
! 27: #include <encoding/payloads/nonce_payload.h>
! 28: #include <encoding/payloads/notify_payload.h>
! 29: #include <encoding/payloads/delete_payload.h>
! 30: #include <processing/jobs/delete_ike_sa_job.h>
! 31: #include <processing/jobs/inactivity_job.h>
! 32: #include <processing/jobs/initiate_tasks_job.h>
! 33:
! 34: typedef struct private_child_create_t private_child_create_t;
! 35:
! 36: /**
! 37: * Private members of a child_create_t task.
! 38: */
! 39: struct private_child_create_t {
! 40:
! 41: /**
! 42: * Public methods and task_t interface.
! 43: */
! 44: child_create_t public;
! 45:
! 46: /**
! 47: * Assigned IKE_SA.
! 48: */
! 49: ike_sa_t *ike_sa;
! 50:
! 51: /**
! 52: * Are we the initiator?
! 53: */
! 54: bool initiator;
! 55:
! 56: /**
! 57: * nonce chosen by us
! 58: */
! 59: chunk_t my_nonce;
! 60:
! 61: /**
! 62: * nonce chosen by peer
! 63: */
! 64: chunk_t other_nonce;
! 65:
! 66: /**
! 67: * nonce generator
! 68: */
! 69: nonce_gen_t *nonceg;
! 70:
! 71: /**
! 72: * config to create the CHILD_SA from
! 73: */
! 74: child_cfg_t *config;
! 75:
! 76: /**
! 77: * list of proposal candidates
! 78: */
! 79: linked_list_t *proposals;
! 80:
! 81: /**
! 82: * selected proposal to use for CHILD_SA
! 83: */
! 84: proposal_t *proposal;
! 85:
! 86: /**
! 87: * traffic selectors for initiators side
! 88: */
! 89: linked_list_t *tsi;
! 90:
! 91: /**
! 92: * traffic selectors for responders side
! 93: */
! 94: linked_list_t *tsr;
! 95:
! 96: /**
! 97: * source of triggering packet
! 98: */
! 99: traffic_selector_t *packet_tsi;
! 100:
! 101: /**
! 102: * destination of triggering packet
! 103: */
! 104: traffic_selector_t *packet_tsr;
! 105:
! 106: /**
! 107: * optional diffie hellman exchange
! 108: */
! 109: diffie_hellman_t *dh;
! 110:
! 111: /**
! 112: * Applying DH public value failed?
! 113: */
! 114: bool dh_failed;
! 115:
! 116: /**
! 117: * group used for DH exchange
! 118: */
! 119: diffie_hellman_group_t dh_group;
! 120:
! 121: /**
! 122: * IKE_SAs keymat
! 123: */
! 124: keymat_v2_t *keymat;
! 125:
! 126: /**
! 127: * mode the new CHILD_SA uses (transport/tunnel/beet)
! 128: */
! 129: ipsec_mode_t mode;
! 130:
! 131: /**
! 132: * peer accepts TFC padding for this SA
! 133: */
! 134: bool tfcv3;
! 135:
! 136: /**
! 137: * IPComp transform to use
! 138: */
! 139: ipcomp_transform_t ipcomp;
! 140:
! 141: /**
! 142: * IPComp transform proposed or accepted by the other peer
! 143: */
! 144: ipcomp_transform_t ipcomp_received;
! 145:
! 146: /**
! 147: * IPsec protocol
! 148: */
! 149: protocol_id_t proto;
! 150:
! 151: /**
! 152: * Own allocated SPI
! 153: */
! 154: uint32_t my_spi;
! 155:
! 156: /**
! 157: * SPI received in proposal
! 158: */
! 159: uint32_t other_spi;
! 160:
! 161: /**
! 162: * Own allocated Compression Parameter Index (CPI)
! 163: */
! 164: uint16_t my_cpi;
! 165:
! 166: /**
! 167: * Other Compression Parameter Index (CPI), received via IPCOMP_SUPPORTED
! 168: */
! 169: uint16_t other_cpi;
! 170:
! 171: /**
! 172: * Data collected to create the CHILD_SA
! 173: */
! 174: child_sa_create_t child;
! 175:
! 176: /**
! 177: * CHILD_SA which gets established
! 178: */
! 179: child_sa_t *child_sa;
! 180:
! 181: /**
! 182: * successfully established the CHILD?
! 183: */
! 184: bool established;
! 185:
! 186: /**
! 187: * whether the CHILD_SA rekeys an existing one
! 188: */
! 189: bool rekey;
! 190:
! 191: /**
! 192: * whether we are retrying with another DH group
! 193: */
! 194: bool retry;
! 195: };
! 196:
! 197: /**
! 198: * Schedule a retry if creating the CHILD_SA temporary failed
! 199: */
! 200: static void schedule_delayed_retry(private_child_create_t *this)
! 201: {
! 202: child_create_t *task;
! 203: uint32_t retry;
! 204:
! 205: retry = RETRY_INTERVAL - (random() % RETRY_JITTER);
! 206:
! 207: task = child_create_create(this->ike_sa,
! 208: this->config->get_ref(this->config), FALSE,
! 209: this->packet_tsi, this->packet_tsr);
! 210: task->use_reqid(task, this->child.reqid);
! 211: task->use_marks(task, this->child.mark_in, this->child.mark_out);
! 212: task->use_if_ids(task, this->child.if_id_in, this->child.if_id_out);
! 213:
! 214: DBG1(DBG_IKE, "creating CHILD_SA failed, trying again in %d seconds",
! 215: retry);
! 216: this->ike_sa->queue_task_delayed(this->ike_sa, (task_t*)task, retry);
! 217: }
! 218:
! 219: /**
! 220: * get the nonce from a message
! 221: */
! 222: static status_t get_nonce(message_t *message, chunk_t *nonce)
! 223: {
! 224: nonce_payload_t *payload;
! 225:
! 226: payload = (nonce_payload_t*)message->get_payload(message, PLV2_NONCE);
! 227: if (payload == NULL)
! 228: {
! 229: return FAILED;
! 230: }
! 231: *nonce = payload->get_nonce(payload);
! 232: return NEED_MORE;
! 233: }
! 234:
! 235: /**
! 236: * generate a new nonce to include in a CREATE_CHILD_SA message
! 237: */
! 238: static bool generate_nonce(private_child_create_t *this)
! 239: {
! 240: this->nonceg = this->keymat->keymat.create_nonce_gen(&this->keymat->keymat);
! 241: if (!this->nonceg)
! 242: {
! 243: DBG1(DBG_IKE, "no nonce generator found to create nonce");
! 244: return FALSE;
! 245: }
! 246: if (!this->nonceg->allocate_nonce(this->nonceg, NONCE_SIZE,
! 247: &this->my_nonce))
! 248: {
! 249: DBG1(DBG_IKE, "nonce allocation failed");
! 250: return FALSE;
! 251: }
! 252: return TRUE;
! 253: }
! 254:
! 255: /**
! 256: * Check a list of traffic selectors if any selector belongs to host
! 257: */
! 258: static bool ts_list_is_host(linked_list_t *list, host_t *host)
! 259: {
! 260: traffic_selector_t *ts;
! 261: bool is_host = TRUE;
! 262: enumerator_t *enumerator = list->create_enumerator(list);
! 263:
! 264: while (is_host && enumerator->enumerate(enumerator, (void**)&ts))
! 265: {
! 266: is_host = is_host && ts->is_host(ts, host);
! 267: }
! 268: enumerator->destroy(enumerator);
! 269: return is_host;
! 270: }
! 271:
! 272: /**
! 273: * Allocate local SPI
! 274: */
! 275: static bool allocate_spi(private_child_create_t *this)
! 276: {
! 277: proposal_t *proposal;
! 278:
! 279: if (this->initiator)
! 280: {
! 281: this->proto = PROTO_ESP;
! 282: /* we just get a SPI for the first protocol. TODO: If we ever support
! 283: * proposal lists with mixed protocols, we'd need multiple SPIs */
! 284: if (this->proposals->get_first(this->proposals,
! 285: (void**)&proposal) == SUCCESS)
! 286: {
! 287: this->proto = proposal->get_protocol(proposal);
! 288: }
! 289: }
! 290: else
! 291: {
! 292: this->proto = this->proposal->get_protocol(this->proposal);
! 293: }
! 294: this->my_spi = this->child_sa->alloc_spi(this->child_sa, this->proto);
! 295: return this->my_spi != 0;
! 296: }
! 297:
! 298: /**
! 299: * Update the proposals with the allocated SPIs as initiator and check the DH
! 300: * group and promote it if necessary
! 301: */
! 302: static bool update_and_check_proposals(private_child_create_t *this)
! 303: {
! 304: enumerator_t *enumerator;
! 305: proposal_t *proposal;
! 306: linked_list_t *other_dh_groups;
! 307: bool found = FALSE;
! 308:
! 309: other_dh_groups = linked_list_create();
! 310: enumerator = this->proposals->create_enumerator(this->proposals);
! 311: while (enumerator->enumerate(enumerator, &proposal))
! 312: {
! 313: proposal->set_spi(proposal, this->my_spi);
! 314:
! 315: /* move the selected DH group to the front, if any */
! 316: if (this->dh_group != MODP_NONE)
! 317: { /* proposals that don't contain the selected group are
! 318: * moved to the back */
! 319: if (!proposal->promote_dh_group(proposal, this->dh_group))
! 320: {
! 321: this->proposals->remove_at(this->proposals, enumerator);
! 322: other_dh_groups->insert_last(other_dh_groups, proposal);
! 323: }
! 324: else
! 325: {
! 326: found = TRUE;
! 327: }
! 328: }
! 329: }
! 330: enumerator->destroy(enumerator);
! 331: enumerator = other_dh_groups->create_enumerator(other_dh_groups);
! 332: while (enumerator->enumerate(enumerator, (void**)&proposal))
! 333: { /* no need to remove from the list as we destroy it anyway*/
! 334: this->proposals->insert_last(this->proposals, proposal);
! 335: }
! 336: enumerator->destroy(enumerator);
! 337: other_dh_groups->destroy(other_dh_groups);
! 338:
! 339: return this->dh_group == MODP_NONE || found;
! 340: }
! 341:
! 342: /**
! 343: * Schedule inactivity timeout for CHILD_SA with reqid, if enabled
! 344: */
! 345: static void schedule_inactivity_timeout(private_child_create_t *this)
! 346: {
! 347: uint32_t timeout, id;
! 348: bool close_ike;
! 349:
! 350: timeout = this->config->get_inactivity(this->config);
! 351: if (timeout)
! 352: {
! 353: close_ike = lib->settings->get_bool(lib->settings,
! 354: "%s.inactivity_close_ike", FALSE, lib->ns);
! 355: id = this->child_sa->get_unique_id(this->child_sa);
! 356: lib->scheduler->schedule_job(lib->scheduler, (job_t*)
! 357: inactivity_job_create(id, timeout, close_ike), timeout);
! 358: }
! 359: }
! 360:
! 361: /**
! 362: * Check if we have a an address pool configured
! 363: */
! 364: static bool have_pool(ike_sa_t *ike_sa)
! 365: {
! 366: enumerator_t *enumerator;
! 367: peer_cfg_t *peer_cfg;
! 368: char *pool;
! 369: bool found = FALSE;
! 370:
! 371: peer_cfg = ike_sa->get_peer_cfg(ike_sa);
! 372: if (peer_cfg)
! 373: {
! 374: enumerator = peer_cfg->create_pool_enumerator(peer_cfg);
! 375: if (enumerator->enumerate(enumerator, &pool))
! 376: {
! 377: found = TRUE;
! 378: }
! 379: enumerator->destroy(enumerator);
! 380: }
! 381: return found;
! 382: }
! 383:
! 384: /**
! 385: * Get hosts to use for dynamic traffic selectors
! 386: */
! 387: static linked_list_t *get_dynamic_hosts(ike_sa_t *ike_sa, bool local)
! 388: {
! 389: enumerator_t *enumerator;
! 390: linked_list_t *list;
! 391: host_t *host;
! 392:
! 393: list = linked_list_create();
! 394: enumerator = ike_sa->create_virtual_ip_enumerator(ike_sa, local);
! 395: while (enumerator->enumerate(enumerator, &host))
! 396: {
! 397: list->insert_last(list, host);
! 398: }
! 399: enumerator->destroy(enumerator);
! 400:
! 401: if (list->get_count(list) == 0)
! 402: { /* no virtual IPs assigned */
! 403: if (local)
! 404: {
! 405: host = ike_sa->get_my_host(ike_sa);
! 406: list->insert_last(list, host);
! 407: }
! 408: else if (!have_pool(ike_sa))
! 409: { /* use host only if we don't have a pool configured */
! 410: host = ike_sa->get_other_host(ike_sa);
! 411: list->insert_last(list, host);
! 412: }
! 413: }
! 414: return list;
! 415: }
! 416:
! 417: /**
! 418: * Substitute any host address with NATed address in traffic selector
! 419: */
! 420: static linked_list_t* get_transport_nat_ts(private_child_create_t *this,
! 421: bool local, linked_list_t *in)
! 422: {
! 423: enumerator_t *enumerator;
! 424: linked_list_t *out;
! 425: traffic_selector_t *ts;
! 426: host_t *ike, *first = NULL;
! 427: uint8_t mask;
! 428:
! 429: if (local)
! 430: {
! 431: ike = this->ike_sa->get_my_host(this->ike_sa);
! 432: }
! 433: else
! 434: {
! 435: ike = this->ike_sa->get_other_host(this->ike_sa);
! 436: }
! 437:
! 438: out = linked_list_create();
! 439:
! 440: enumerator = in->create_enumerator(in);
! 441: while (enumerator->enumerate(enumerator, &ts))
! 442: {
! 443: /* require that all selectors match the first "host" selector */
! 444: if (ts->is_host(ts, first))
! 445: {
! 446: if (!first)
! 447: {
! 448: ts->to_subnet(ts, &first, &mask);
! 449: }
! 450: ts = ts->clone(ts);
! 451: ts->set_address(ts, ike);
! 452: out->insert_last(out, ts);
! 453: }
! 454: }
! 455: enumerator->destroy(enumerator);
! 456: DESTROY_IF(first);
! 457:
! 458: return out;
! 459: }
! 460:
! 461: /**
! 462: * Narrow received traffic selectors with configuration
! 463: */
! 464: static linked_list_t* narrow_ts(private_child_create_t *this, bool local,
! 465: linked_list_t *in)
! 466: {
! 467: linked_list_t *hosts, *nat, *ts;
! 468: ike_condition_t cond;
! 469:
! 470: cond = local ? COND_NAT_HERE : COND_NAT_THERE;
! 471: hosts = get_dynamic_hosts(this->ike_sa, local);
! 472:
! 473: if (this->mode == MODE_TRANSPORT &&
! 474: this->ike_sa->has_condition(this->ike_sa, cond))
! 475: {
! 476: nat = get_transport_nat_ts(this, local, in);
! 477: ts = this->config->get_traffic_selectors(this->config, local, nat,
! 478: hosts, TRUE);
! 479: nat->destroy_offset(nat, offsetof(traffic_selector_t, destroy));
! 480: }
! 481: else
! 482: {
! 483: ts = this->config->get_traffic_selectors(this->config, local, in,
! 484: hosts, TRUE);
! 485: }
! 486:
! 487: hosts->destroy(hosts);
! 488:
! 489: return ts;
! 490: }
! 491:
! 492: /**
! 493: * Check if requested mode is acceptable
! 494: */
! 495: static bool check_mode(private_child_create_t *this, host_t *i, host_t *r)
! 496: {
! 497: switch (this->mode)
! 498: {
! 499: case MODE_TRANSPORT:
! 500: if (!this->config->has_option(this->config, OPT_PROXY_MODE) &&
! 501: (!ts_list_is_host(this->tsi, i) ||
! 502: !ts_list_is_host(this->tsr, r))
! 503: )
! 504: {
! 505: DBG1(DBG_IKE, "not using transport mode, not host-to-host");
! 506: return FALSE;
! 507: }
! 508: if (this->config->get_mode(this->config) != MODE_TRANSPORT)
! 509: {
! 510: return FALSE;
! 511: }
! 512: break;
! 513: case MODE_BEET:
! 514: if (!ts_list_is_host(this->tsi, NULL) ||
! 515: !ts_list_is_host(this->tsr, NULL))
! 516: {
! 517: DBG1(DBG_IKE, "not using BEET mode, not host-to-host");
! 518: return FALSE;
! 519: }
! 520: if (this->config->get_mode(this->config) != MODE_BEET)
! 521: {
! 522: return FALSE;
! 523: }
! 524: break;
! 525: default:
! 526: break;
! 527: }
! 528: return TRUE;
! 529: }
! 530:
! 531: /**
! 532: * Install a CHILD_SA for usage, return value:
! 533: * - FAILED: no acceptable proposal
! 534: * - INVALID_ARG: diffie hellman group unacceptable
! 535: * - NOT_FOUND: TS unacceptable
! 536: */
! 537: static status_t select_and_install(private_child_create_t *this,
! 538: bool no_dh, bool ike_auth)
! 539: {
! 540: status_t status, status_i, status_o;
! 541: child_sa_outbound_state_t out_state;
! 542: chunk_t nonce_i, nonce_r;
! 543: chunk_t encr_i = chunk_empty, encr_r = chunk_empty;
! 544: chunk_t integ_i = chunk_empty, integ_r = chunk_empty;
! 545: linked_list_t *my_ts, *other_ts;
! 546: host_t *me, *other;
! 547: proposal_selection_flag_t flags = 0;
! 548:
! 549: if (this->proposals == NULL)
! 550: {
! 551: DBG1(DBG_IKE, "SA payload missing in message");
! 552: return FAILED;
! 553: }
! 554: if (this->tsi == NULL || this->tsr == NULL)
! 555: {
! 556: DBG1(DBG_IKE, "TS payloads missing in message");
! 557: return NOT_FOUND;
! 558: }
! 559:
! 560: me = this->ike_sa->get_my_host(this->ike_sa);
! 561: other = this->ike_sa->get_other_host(this->ike_sa);
! 562:
! 563: if (no_dh)
! 564: {
! 565: flags |= PROPOSAL_SKIP_DH;
! 566: }
! 567: if (!this->ike_sa->supports_extension(this->ike_sa, EXT_STRONGSWAN) &&
! 568: !lib->settings->get_bool(lib->settings, "%s.accept_private_algs",
! 569: FALSE, lib->ns))
! 570: {
! 571: flags |= PROPOSAL_SKIP_PRIVATE;
! 572: }
! 573: if (!lib->settings->get_bool(lib->settings,
! 574: "%s.prefer_configured_proposals", TRUE, lib->ns))
! 575: {
! 576: flags |= PROPOSAL_PREFER_SUPPLIED;
! 577: }
! 578: this->proposal = this->config->select_proposal(this->config,
! 579: this->proposals, flags);
! 580: if (this->proposal == NULL)
! 581: {
! 582: DBG1(DBG_IKE, "no acceptable proposal found");
! 583: charon->bus->alert(charon->bus, ALERT_PROPOSAL_MISMATCH_CHILD,
! 584: this->proposals);
! 585: return FAILED;
! 586: }
! 587: this->other_spi = this->proposal->get_spi(this->proposal);
! 588:
! 589: if (!this->initiator)
! 590: {
! 591: if (!allocate_spi(this))
! 592: {
! 593: /* responder has no SPI allocated yet */
! 594: DBG1(DBG_IKE, "allocating SPI failed");
! 595: return FAILED;
! 596: }
! 597: this->proposal->set_spi(this->proposal, this->my_spi);
! 598: }
! 599: this->child_sa->set_proposal(this->child_sa, this->proposal);
! 600:
! 601: if (!this->proposal->has_dh_group(this->proposal, this->dh_group))
! 602: {
! 603: uint16_t group;
! 604:
! 605: if (this->proposal->get_algorithm(this->proposal, DIFFIE_HELLMAN_GROUP,
! 606: &group, NULL))
! 607: {
! 608: DBG1(DBG_IKE, "DH group %N unacceptable, requesting %N",
! 609: diffie_hellman_group_names, this->dh_group,
! 610: diffie_hellman_group_names, group);
! 611: this->dh_group = group;
! 612: return INVALID_ARG;
! 613: }
! 614: /* the selected proposal does not use a DH group */
! 615: DBG1(DBG_IKE, "ignoring KE exchange, agreed on a non-PFS proposal");
! 616: DESTROY_IF(this->dh);
! 617: this->dh = NULL;
! 618: this->dh_group = MODP_NONE;
! 619: }
! 620:
! 621: if (this->initiator)
! 622: {
! 623: nonce_i = this->my_nonce;
! 624: nonce_r = this->other_nonce;
! 625: my_ts = narrow_ts(this, TRUE, this->tsi);
! 626: other_ts = narrow_ts(this, FALSE, this->tsr);
! 627: }
! 628: else
! 629: {
! 630: nonce_r = this->my_nonce;
! 631: nonce_i = this->other_nonce;
! 632: my_ts = narrow_ts(this, TRUE, this->tsr);
! 633: other_ts = narrow_ts(this, FALSE, this->tsi);
! 634: }
! 635:
! 636: if (this->initiator)
! 637: {
! 638: if (ike_auth)
! 639: {
! 640: charon->bus->narrow(charon->bus, this->child_sa,
! 641: NARROW_INITIATOR_POST_NOAUTH, my_ts, other_ts);
! 642: }
! 643: else
! 644: {
! 645: charon->bus->narrow(charon->bus, this->child_sa,
! 646: NARROW_INITIATOR_POST_AUTH, my_ts, other_ts);
! 647: }
! 648: }
! 649: else
! 650: {
! 651: charon->bus->narrow(charon->bus, this->child_sa,
! 652: NARROW_RESPONDER, my_ts, other_ts);
! 653: }
! 654:
! 655: if (my_ts->get_count(my_ts) == 0 || other_ts->get_count(other_ts) == 0)
! 656: {
! 657: charon->bus->alert(charon->bus, ALERT_TS_MISMATCH, this->tsi, this->tsr);
! 658: my_ts->destroy_offset(my_ts, offsetof(traffic_selector_t, destroy));
! 659: other_ts->destroy_offset(other_ts, offsetof(traffic_selector_t, destroy));
! 660: DBG1(DBG_IKE, "no acceptable traffic selectors found");
! 661: return NOT_FOUND;
! 662: }
! 663:
! 664: this->tsr->destroy_offset(this->tsr, offsetof(traffic_selector_t, destroy));
! 665: this->tsi->destroy_offset(this->tsi, offsetof(traffic_selector_t, destroy));
! 666: if (this->initiator)
! 667: {
! 668: this->tsi = my_ts;
! 669: this->tsr = other_ts;
! 670:
! 671: if (!check_mode(this, me, other))
! 672: {
! 673: DBG1(DBG_IKE, "%N mode requested by responder is unacceptable",
! 674: ipsec_mode_names, this->mode);
! 675: return FAILED;
! 676: }
! 677: }
! 678: else
! 679: {
! 680: this->tsr = my_ts;
! 681: this->tsi = other_ts;
! 682:
! 683: if (!check_mode(this, other, me))
! 684: {
! 685: this->mode = MODE_TUNNEL;
! 686: }
! 687: }
! 688:
! 689: if (!this->initiator)
! 690: {
! 691: /* use a copy of the traffic selectors, as the POST hook should not
! 692: * change payloads */
! 693: my_ts = this->tsr->clone_offset(this->tsr,
! 694: offsetof(traffic_selector_t, clone));
! 695: other_ts = this->tsi->clone_offset(this->tsi,
! 696: offsetof(traffic_selector_t, clone));
! 697: charon->bus->narrow(charon->bus, this->child_sa,
! 698: NARROW_RESPONDER_POST, my_ts, other_ts);
! 699:
! 700: if (my_ts->get_count(my_ts) == 0 || other_ts->get_count(other_ts) == 0)
! 701: {
! 702: my_ts->destroy_offset(my_ts,
! 703: offsetof(traffic_selector_t, destroy));
! 704: other_ts->destroy_offset(other_ts,
! 705: offsetof(traffic_selector_t, destroy));
! 706: return NOT_FOUND;
! 707: }
! 708: }
! 709:
! 710: this->child_sa->set_policies(this->child_sa, my_ts, other_ts);
! 711: if (!this->initiator)
! 712: {
! 713: my_ts->destroy_offset(my_ts,
! 714: offsetof(traffic_selector_t, destroy));
! 715: other_ts->destroy_offset(other_ts,
! 716: offsetof(traffic_selector_t, destroy));
! 717: }
! 718:
! 719: this->child_sa->set_state(this->child_sa, CHILD_INSTALLING);
! 720: this->child_sa->set_ipcomp(this->child_sa, this->ipcomp);
! 721: this->child_sa->set_mode(this->child_sa, this->mode);
! 722: this->child_sa->set_protocol(this->child_sa,
! 723: this->proposal->get_protocol(this->proposal));
! 724:
! 725: if (this->my_cpi == 0 || this->other_cpi == 0 || this->ipcomp == IPCOMP_NONE)
! 726: {
! 727: this->my_cpi = this->other_cpi = 0;
! 728: this->ipcomp = IPCOMP_NONE;
! 729: }
! 730: status_i = status_o = FAILED;
! 731: if (this->keymat->derive_child_keys(this->keymat, this->proposal,
! 732: this->dh, nonce_i, nonce_r, &encr_i, &integ_i, &encr_r, &integ_r))
! 733: {
! 734: if (this->initiator)
! 735: {
! 736: status_i = this->child_sa->install(this->child_sa, encr_r, integ_r,
! 737: this->my_spi, this->my_cpi, this->initiator,
! 738: TRUE, this->tfcv3);
! 739: }
! 740: else
! 741: {
! 742: status_i = this->child_sa->install(this->child_sa, encr_i, integ_i,
! 743: this->my_spi, this->my_cpi, this->initiator,
! 744: TRUE, this->tfcv3);
! 745: }
! 746: if (this->rekey)
! 747: { /* during rekeyings we install the outbound SA and/or policies
! 748: * separately: as responder when we receive the delete for the old
! 749: * SA, as initiator pretty much immediately in the ike-rekey task,
! 750: * unless there was a rekey collision that we lost */
! 751: if (this->initiator)
! 752: {
! 753: status_o = this->child_sa->register_outbound(this->child_sa,
! 754: encr_i, integ_i, this->other_spi, this->other_cpi,
! 755: this->tfcv3);
! 756: }
! 757: else
! 758: {
! 759: status_o = this->child_sa->register_outbound(this->child_sa,
! 760: encr_r, integ_r, this->other_spi, this->other_cpi,
! 761: this->tfcv3);
! 762: }
! 763: }
! 764: else if (this->initiator)
! 765: {
! 766: status_o = this->child_sa->install(this->child_sa, encr_i, integ_i,
! 767: this->other_spi, this->other_cpi, this->initiator,
! 768: FALSE, this->tfcv3);
! 769: }
! 770: else
! 771: {
! 772: status_o = this->child_sa->install(this->child_sa, encr_r, integ_r,
! 773: this->other_spi, this->other_cpi, this->initiator,
! 774: FALSE, this->tfcv3);
! 775: }
! 776: }
! 777:
! 778: if (status_i != SUCCESS || status_o != SUCCESS)
! 779: {
! 780: DBG1(DBG_IKE, "unable to install %s%s%sIPsec SA (SAD) in kernel",
! 781: (status_i != SUCCESS) ? "inbound " : "",
! 782: (status_i != SUCCESS && status_o != SUCCESS) ? "and ": "",
! 783: (status_o != SUCCESS) ? "outbound " : "");
! 784: charon->bus->alert(charon->bus, ALERT_INSTALL_CHILD_SA_FAILED,
! 785: this->child_sa);
! 786: status = FAILED;
! 787: }
! 788: else
! 789: {
! 790: status = this->child_sa->install_policies(this->child_sa);
! 791:
! 792: if (status != SUCCESS)
! 793: {
! 794: DBG1(DBG_IKE, "unable to install IPsec policies (SPD) in kernel");
! 795: charon->bus->alert(charon->bus, ALERT_INSTALL_CHILD_POLICY_FAILED,
! 796: this->child_sa);
! 797: status = NOT_FOUND;
! 798: }
! 799: else
! 800: {
! 801: charon->bus->child_derived_keys(charon->bus, this->child_sa,
! 802: this->initiator, encr_i, encr_r,
! 803: integ_i, integ_r);
! 804: }
! 805: }
! 806: chunk_clear(&integ_i);
! 807: chunk_clear(&integ_r);
! 808: chunk_clear(&encr_i);
! 809: chunk_clear(&encr_r);
! 810:
! 811: if (status != SUCCESS)
! 812: {
! 813: return status;
! 814: }
! 815:
! 816: charon->bus->child_keys(charon->bus, this->child_sa, this->initiator,
! 817: this->dh, nonce_i, nonce_r);
! 818:
! 819: my_ts = linked_list_create_from_enumerator(
! 820: this->child_sa->create_ts_enumerator(this->child_sa, TRUE));
! 821: other_ts = linked_list_create_from_enumerator(
! 822: this->child_sa->create_ts_enumerator(this->child_sa, FALSE));
! 823: out_state = this->child_sa->get_outbound_state(this->child_sa);
! 824:
! 825: DBG0(DBG_IKE, "%sCHILD_SA %s{%d} established "
! 826: "with SPIs %.8x_i %.8x_o and TS %#R === %#R",
! 827: (out_state == CHILD_OUTBOUND_INSTALLED) ? "" : "inbound ",
! 828: this->child_sa->get_name(this->child_sa),
! 829: this->child_sa->get_unique_id(this->child_sa),
! 830: ntohl(this->child_sa->get_spi(this->child_sa, TRUE)),
! 831: ntohl(this->child_sa->get_spi(this->child_sa, FALSE)),
! 832: my_ts, other_ts);
! 833:
! 834: my_ts->destroy(my_ts);
! 835: other_ts->destroy(other_ts);
! 836:
! 837: this->child_sa->set_state(this->child_sa, CHILD_INSTALLED);
! 838: this->ike_sa->add_child_sa(this->ike_sa, this->child_sa);
! 839: this->established = TRUE;
! 840:
! 841: schedule_inactivity_timeout(this);
! 842: return SUCCESS;
! 843: }
! 844:
! 845: /**
! 846: * build the payloads for the message
! 847: */
! 848: static bool build_payloads(private_child_create_t *this, message_t *message)
! 849: {
! 850: sa_payload_t *sa_payload;
! 851: nonce_payload_t *nonce_payload;
! 852: ke_payload_t *ke_payload;
! 853: ts_payload_t *ts_payload;
! 854: kernel_feature_t features;
! 855:
! 856: /* add SA payload */
! 857: if (this->initiator)
! 858: {
! 859: sa_payload = sa_payload_create_from_proposals_v2(this->proposals);
! 860: }
! 861: else
! 862: {
! 863: sa_payload = sa_payload_create_from_proposal_v2(this->proposal);
! 864: }
! 865: message->add_payload(message, (payload_t*)sa_payload);
! 866:
! 867: /* add nonce payload if not in IKE_AUTH */
! 868: if (message->get_exchange_type(message) == CREATE_CHILD_SA)
! 869: {
! 870: nonce_payload = nonce_payload_create(PLV2_NONCE);
! 871: nonce_payload->set_nonce(nonce_payload, this->my_nonce);
! 872: message->add_payload(message, (payload_t*)nonce_payload);
! 873: }
! 874:
! 875: /* diffie hellman exchange, if PFS enabled */
! 876: if (this->dh)
! 877: {
! 878: ke_payload = ke_payload_create_from_diffie_hellman(PLV2_KEY_EXCHANGE,
! 879: this->dh);
! 880: if (!ke_payload)
! 881: {
! 882: DBG1(DBG_IKE, "creating KE payload failed");
! 883: return FALSE;
! 884: }
! 885: message->add_payload(message, (payload_t*)ke_payload);
! 886: }
! 887:
! 888: /* add TSi/TSr payloads */
! 889: ts_payload = ts_payload_create_from_traffic_selectors(TRUE, this->tsi);
! 890: message->add_payload(message, (payload_t*)ts_payload);
! 891: ts_payload = ts_payload_create_from_traffic_selectors(FALSE, this->tsr);
! 892: message->add_payload(message, (payload_t*)ts_payload);
! 893:
! 894: /* add a notify if we are not in tunnel mode */
! 895: switch (this->mode)
! 896: {
! 897: case MODE_TRANSPORT:
! 898: message->add_notify(message, FALSE, USE_TRANSPORT_MODE, chunk_empty);
! 899: break;
! 900: case MODE_BEET:
! 901: message->add_notify(message, FALSE, USE_BEET_MODE, chunk_empty);
! 902: break;
! 903: default:
! 904: break;
! 905: }
! 906:
! 907: features = charon->kernel->get_features(charon->kernel);
! 908: if (!(features & KERNEL_ESP_V3_TFC))
! 909: {
! 910: message->add_notify(message, FALSE, ESP_TFC_PADDING_NOT_SUPPORTED,
! 911: chunk_empty);
! 912: }
! 913: return TRUE;
! 914: }
! 915:
! 916: /**
! 917: * Adds an IPCOMP_SUPPORTED notify to the message, allocating a CPI
! 918: */
! 919: static void add_ipcomp_notify(private_child_create_t *this,
! 920: message_t *message, uint8_t ipcomp)
! 921: {
! 922: this->my_cpi = this->child_sa->alloc_cpi(this->child_sa);
! 923: if (this->my_cpi)
! 924: {
! 925: this->ipcomp = ipcomp;
! 926: message->add_notify(message, FALSE, IPCOMP_SUPPORTED,
! 927: chunk_cata("cc", chunk_from_thing(this->my_cpi),
! 928: chunk_from_thing(ipcomp)));
! 929: }
! 930: else
! 931: {
! 932: DBG1(DBG_IKE, "unable to allocate a CPI from kernel, IPComp disabled");
! 933: }
! 934: }
! 935:
! 936: /**
! 937: * handle a received notify payload
! 938: */
! 939: static void handle_notify(private_child_create_t *this, notify_payload_t *notify)
! 940: {
! 941: switch (notify->get_notify_type(notify))
! 942: {
! 943: case USE_TRANSPORT_MODE:
! 944: this->mode = MODE_TRANSPORT;
! 945: break;
! 946: case USE_BEET_MODE:
! 947: if (this->ike_sa->supports_extension(this->ike_sa, EXT_STRONGSWAN))
! 948: { /* handle private use notify only if we know its meaning */
! 949: this->mode = MODE_BEET;
! 950: }
! 951: else
! 952: {
! 953: DBG1(DBG_IKE, "received a notify strongSwan uses for BEET "
! 954: "mode, but peer implementation unknown, skipped");
! 955: }
! 956: break;
! 957: case IPCOMP_SUPPORTED:
! 958: {
! 959: ipcomp_transform_t ipcomp;
! 960: uint16_t cpi;
! 961: chunk_t data;
! 962:
! 963: data = notify->get_notification_data(notify);
! 964: cpi = *(uint16_t*)data.ptr;
! 965: ipcomp = (ipcomp_transform_t)(*(data.ptr + 2));
! 966: switch (ipcomp)
! 967: {
! 968: case IPCOMP_DEFLATE:
! 969: this->other_cpi = cpi;
! 970: this->ipcomp_received = ipcomp;
! 971: break;
! 972: case IPCOMP_LZS:
! 973: case IPCOMP_LZJH:
! 974: default:
! 975: DBG1(DBG_IKE, "received IPCOMP_SUPPORTED notify with a "
! 976: "transform ID we don't support %N",
! 977: ipcomp_transform_names, ipcomp);
! 978: break;
! 979: }
! 980: break;
! 981: }
! 982: case ESP_TFC_PADDING_NOT_SUPPORTED:
! 983: DBG1(DBG_IKE, "received %N, not using ESPv3 TFC padding",
! 984: notify_type_names, notify->get_notify_type(notify));
! 985: this->tfcv3 = FALSE;
! 986: break;
! 987: default:
! 988: break;
! 989: }
! 990: }
! 991:
! 992: /**
! 993: * Read payloads from message
! 994: */
! 995: static void process_payloads(private_child_create_t *this, message_t *message)
! 996: {
! 997: enumerator_t *enumerator;
! 998: payload_t *payload;
! 999: sa_payload_t *sa_payload;
! 1000: ke_payload_t *ke_payload;
! 1001: ts_payload_t *ts_payload;
! 1002:
! 1003: /* defaults to TUNNEL mode */
! 1004: this->mode = MODE_TUNNEL;
! 1005:
! 1006: enumerator = message->create_payload_enumerator(message);
! 1007: while (enumerator->enumerate(enumerator, &payload))
! 1008: {
! 1009: switch (payload->get_type(payload))
! 1010: {
! 1011: case PLV2_SECURITY_ASSOCIATION:
! 1012: sa_payload = (sa_payload_t*)payload;
! 1013: this->proposals = sa_payload->get_proposals(sa_payload);
! 1014: break;
! 1015: case PLV2_KEY_EXCHANGE:
! 1016: ke_payload = (ke_payload_t*)payload;
! 1017: if (!this->initiator)
! 1018: {
! 1019: this->dh_group = ke_payload->get_dh_group_number(ke_payload);
! 1020: this->dh = this->keymat->keymat.create_dh(
! 1021: &this->keymat->keymat, this->dh_group);
! 1022: }
! 1023: else if (this->dh)
! 1024: {
! 1025: this->dh_failed = this->dh->get_dh_group(this->dh) !=
! 1026: ke_payload->get_dh_group_number(ke_payload);
! 1027: }
! 1028: if (this->dh && !this->dh_failed)
! 1029: {
! 1030: this->dh_failed = !this->dh->set_other_public_value(this->dh,
! 1031: ke_payload->get_key_exchange_data(ke_payload));
! 1032: }
! 1033: break;
! 1034: case PLV2_TS_INITIATOR:
! 1035: ts_payload = (ts_payload_t*)payload;
! 1036: this->tsi = ts_payload->get_traffic_selectors(ts_payload);
! 1037: break;
! 1038: case PLV2_TS_RESPONDER:
! 1039: ts_payload = (ts_payload_t*)payload;
! 1040: this->tsr = ts_payload->get_traffic_selectors(ts_payload);
! 1041: break;
! 1042: case PLV2_NOTIFY:
! 1043: handle_notify(this, (notify_payload_t*)payload);
! 1044: break;
! 1045: default:
! 1046: break;
! 1047: }
! 1048: }
! 1049: enumerator->destroy(enumerator);
! 1050: }
! 1051:
! 1052: /**
! 1053: * Check if we should defer the creation of this CHILD_SA until after the
! 1054: * IKE_SA has been established childless.
! 1055: */
! 1056: static status_t defer_child_sa(private_child_create_t *this)
! 1057: {
! 1058: ike_cfg_t *ike_cfg;
! 1059:
! 1060: ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa);
! 1061:
! 1062: if (this->ike_sa->supports_extension(this->ike_sa, EXT_IKE_CHILDLESS))
! 1063: {
! 1064: if (ike_cfg->childless(ike_cfg) == CHILDLESS_FORCE)
! 1065: {
! 1066: return NEED_MORE;
! 1067: }
! 1068: }
! 1069: else if (ike_cfg->childless(ike_cfg) == CHILDLESS_FORCE)
! 1070: {
! 1071: DBG1(DBG_IKE, "peer does not support childless IKE_SA initiation");
! 1072: return DESTROY_ME;
! 1073: }
! 1074: return NOT_SUPPORTED;
! 1075: }
! 1076:
! 1077: METHOD(task_t, build_i, status_t,
! 1078: private_child_create_t *this, message_t *message)
! 1079: {
! 1080: enumerator_t *enumerator;
! 1081: host_t *vip;
! 1082: peer_cfg_t *peer_cfg;
! 1083: linked_list_t *list;
! 1084:
! 1085: switch (message->get_exchange_type(message))
! 1086: {
! 1087: case IKE_SA_INIT:
! 1088: return get_nonce(message, &this->my_nonce);
! 1089: case CREATE_CHILD_SA:
! 1090: if (!generate_nonce(this))
! 1091: {
! 1092: message->add_notify(message, FALSE, NO_PROPOSAL_CHOSEN,
! 1093: chunk_empty);
! 1094: return SUCCESS;
! 1095: }
! 1096: if (!this->retry && this->dh_group == MODP_NONE)
! 1097: { /* during a rekeying the group might already be set */
! 1098: this->dh_group = this->config->get_dh_group(this->config);
! 1099: }
! 1100: break;
! 1101: case IKE_AUTH:
! 1102: if (message->get_message_id(message) != 1)
! 1103: {
! 1104: /* send only in the first request, not in subsequent rounds */
! 1105: return NEED_MORE;
! 1106: }
! 1107: switch (defer_child_sa(this))
! 1108: {
! 1109: case DESTROY_ME:
! 1110: /* config mismatch */
! 1111: return DESTROY_ME;
! 1112: case NEED_MORE:
! 1113: /* defer until after IKE_SA has been established */
! 1114: chunk_free(&this->my_nonce);
! 1115: return NEED_MORE;
! 1116: default:
! 1117: /* just continue to establish the CHILD_SA */
! 1118: break;
! 1119: }
! 1120: break;
! 1121: default:
! 1122: break;
! 1123: }
! 1124:
! 1125: /* check if we want a virtual IP, but don't have one */
! 1126: list = linked_list_create();
! 1127: peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
! 1128: if (!this->rekey)
! 1129: {
! 1130: enumerator = peer_cfg->create_virtual_ip_enumerator(peer_cfg);
! 1131: while (enumerator->enumerate(enumerator, &vip))
! 1132: {
! 1133: /* propose a 0.0.0.0/0 or ::/0 subnet when we use virtual ip */
! 1134: vip = host_create_any(vip->get_family(vip));
! 1135: list->insert_last(list, vip);
! 1136: }
! 1137: enumerator->destroy(enumerator);
! 1138: }
! 1139: if (list->get_count(list))
! 1140: {
! 1141: this->tsi = this->config->get_traffic_selectors(this->config,
! 1142: TRUE, NULL, list, TRUE);
! 1143: list->destroy_offset(list, offsetof(host_t, destroy));
! 1144: }
! 1145: else
! 1146: { /* no virtual IPs configured */
! 1147: list->destroy(list);
! 1148: list = get_dynamic_hosts(this->ike_sa, TRUE);
! 1149: this->tsi = this->config->get_traffic_selectors(this->config,
! 1150: TRUE, NULL, list, TRUE);
! 1151: list->destroy(list);
! 1152: }
! 1153: list = get_dynamic_hosts(this->ike_sa, FALSE);
! 1154: this->tsr = this->config->get_traffic_selectors(this->config,
! 1155: FALSE, NULL, list, TRUE);
! 1156: list->destroy(list);
! 1157:
! 1158: if (this->packet_tsi)
! 1159: {
! 1160: this->tsi->insert_first(this->tsi,
! 1161: this->packet_tsi->clone(this->packet_tsi));
! 1162: }
! 1163: if (this->packet_tsr)
! 1164: {
! 1165: this->tsr->insert_first(this->tsr,
! 1166: this->packet_tsr->clone(this->packet_tsr));
! 1167: }
! 1168: this->proposals = this->config->get_proposals(this->config,
! 1169: this->dh_group == MODP_NONE);
! 1170: this->mode = this->config->get_mode(this->config);
! 1171:
! 1172: this->child.if_id_in_def = this->ike_sa->get_if_id(this->ike_sa, TRUE);
! 1173: this->child.if_id_out_def = this->ike_sa->get_if_id(this->ike_sa, FALSE);
! 1174: this->child.encap = this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY);
! 1175: this->child_sa = child_sa_create(this->ike_sa->get_my_host(this->ike_sa),
! 1176: this->ike_sa->get_other_host(this->ike_sa),
! 1177: this->config, &this->child);
! 1178:
! 1179: if (this->child.reqid)
! 1180: {
! 1181: DBG0(DBG_IKE, "establishing CHILD_SA %s{%d} reqid %d",
! 1182: this->child_sa->get_name(this->child_sa),
! 1183: this->child_sa->get_unique_id(this->child_sa), this->child.reqid);
! 1184: }
! 1185: else
! 1186: {
! 1187: DBG0(DBG_IKE, "establishing CHILD_SA %s{%d}",
! 1188: this->child_sa->get_name(this->child_sa),
! 1189: this->child_sa->get_unique_id(this->child_sa));
! 1190: }
! 1191:
! 1192: if (!allocate_spi(this))
! 1193: {
! 1194: DBG1(DBG_IKE, "unable to allocate SPIs from kernel");
! 1195: return FAILED;
! 1196: }
! 1197:
! 1198: if (!update_and_check_proposals(this))
! 1199: {
! 1200: DBG1(DBG_IKE, "requested DH group %N not contained in any of our "
! 1201: "proposals",
! 1202: diffie_hellman_group_names, this->dh_group);
! 1203: return FAILED;
! 1204: }
! 1205:
! 1206: if (this->dh_group != MODP_NONE)
! 1207: {
! 1208: this->dh = this->keymat->keymat.create_dh(&this->keymat->keymat,
! 1209: this->dh_group);
! 1210: }
! 1211:
! 1212: if (this->config->has_option(this->config, OPT_IPCOMP))
! 1213: {
! 1214: /* IPCOMP_DEFLATE is the only transform we support at the moment */
! 1215: add_ipcomp_notify(this, message, IPCOMP_DEFLATE);
! 1216: }
! 1217:
! 1218: if (message->get_exchange_type(message) == IKE_AUTH)
! 1219: {
! 1220: charon->bus->narrow(charon->bus, this->child_sa,
! 1221: NARROW_INITIATOR_PRE_NOAUTH, this->tsi, this->tsr);
! 1222: }
! 1223: else
! 1224: {
! 1225: charon->bus->narrow(charon->bus, this->child_sa,
! 1226: NARROW_INITIATOR_PRE_AUTH, this->tsi, this->tsr);
! 1227: }
! 1228:
! 1229: if (!build_payloads(this, message))
! 1230: {
! 1231: return FAILED;
! 1232: }
! 1233:
! 1234: this->tsi->destroy_offset(this->tsi, offsetof(traffic_selector_t, destroy));
! 1235: this->tsr->destroy_offset(this->tsr, offsetof(traffic_selector_t, destroy));
! 1236: this->proposals->destroy_offset(this->proposals, offsetof(proposal_t, destroy));
! 1237: this->tsi = NULL;
! 1238: this->tsr = NULL;
! 1239: this->proposals = NULL;
! 1240:
! 1241: return NEED_MORE;
! 1242: }
! 1243:
! 1244: METHOD(task_t, process_r, status_t,
! 1245: private_child_create_t *this, message_t *message)
! 1246: {
! 1247: switch (message->get_exchange_type(message))
! 1248: {
! 1249: case IKE_SA_INIT:
! 1250: return get_nonce(message, &this->other_nonce);
! 1251: case CREATE_CHILD_SA:
! 1252: get_nonce(message, &this->other_nonce);
! 1253: break;
! 1254: case IKE_AUTH:
! 1255: if (message->get_message_id(message) != 1)
! 1256: {
! 1257: /* only handle first AUTH payload, not additional rounds */
! 1258: return NEED_MORE;
! 1259: }
! 1260: default:
! 1261: break;
! 1262: }
! 1263:
! 1264: process_payloads(this, message);
! 1265:
! 1266: return NEED_MORE;
! 1267: }
! 1268:
! 1269: /**
! 1270: * handle CHILD_SA setup failure
! 1271: */
! 1272: static void handle_child_sa_failure(private_child_create_t *this,
! 1273: message_t *message)
! 1274: {
! 1275: bool is_first;
! 1276:
! 1277: is_first = message->get_exchange_type(message) == IKE_AUTH;
! 1278: if (is_first &&
! 1279: lib->settings->get_bool(lib->settings,
! 1280: "%s.close_ike_on_child_failure", FALSE, lib->ns))
! 1281: {
! 1282: /* we delay the delete for 100ms, as the IKE_AUTH response must arrive
! 1283: * first */
! 1284: DBG1(DBG_IKE, "closing IKE_SA due CHILD_SA setup failure");
! 1285: lib->scheduler->schedule_job_ms(lib->scheduler, (job_t*)
! 1286: delete_ike_sa_job_create(this->ike_sa->get_id(this->ike_sa), TRUE),
! 1287: 100);
! 1288: }
! 1289: else
! 1290: {
! 1291: DBG1(DBG_IKE, "failed to establish CHILD_SA, keeping IKE_SA");
! 1292: charon->bus->alert(charon->bus, ALERT_KEEP_ON_CHILD_SA_FAILURE,
! 1293: is_first);
! 1294: }
! 1295: }
! 1296:
! 1297: /**
! 1298: * Substitute transport mode NAT selectors, if applicable
! 1299: */
! 1300: static linked_list_t* get_ts_if_nat_transport(private_child_create_t *this,
! 1301: bool local, linked_list_t *in)
! 1302: {
! 1303: linked_list_t *out = NULL;
! 1304: ike_condition_t cond;
! 1305:
! 1306: if (this->mode == MODE_TRANSPORT)
! 1307: {
! 1308: cond = local ? COND_NAT_HERE : COND_NAT_THERE;
! 1309: if (this->ike_sa->has_condition(this->ike_sa, cond))
! 1310: {
! 1311: out = get_transport_nat_ts(this, local, in);
! 1312: if (out->get_count(out) == 0)
! 1313: {
! 1314: out->destroy(out);
! 1315: out = NULL;
! 1316: }
! 1317: }
! 1318: }
! 1319: return out;
! 1320: }
! 1321:
! 1322: /**
! 1323: * Select a matching CHILD config as responder
! 1324: */
! 1325: static child_cfg_t* select_child_cfg(private_child_create_t *this)
! 1326: {
! 1327: peer_cfg_t *peer_cfg;
! 1328: child_cfg_t *child_cfg = NULL;;
! 1329:
! 1330: peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
! 1331: if (peer_cfg && this->tsi && this->tsr)
! 1332: {
! 1333: linked_list_t *listr, *listi, *tsr, *tsi;
! 1334:
! 1335: tsr = get_ts_if_nat_transport(this, TRUE, this->tsr);
! 1336: tsi = get_ts_if_nat_transport(this, FALSE, this->tsi);
! 1337:
! 1338: listr = get_dynamic_hosts(this->ike_sa, TRUE);
! 1339: listi = get_dynamic_hosts(this->ike_sa, FALSE);
! 1340: child_cfg = peer_cfg->select_child_cfg(peer_cfg,
! 1341: tsr ?: this->tsr, tsi ?: this->tsi,
! 1342: listr, listi);
! 1343: if ((tsi || tsr) && child_cfg &&
! 1344: child_cfg->get_mode(child_cfg) != MODE_TRANSPORT)
! 1345: {
! 1346: /* found a CHILD config, but it doesn't use transport mode */
! 1347: child_cfg->destroy(child_cfg);
! 1348: child_cfg = NULL;
! 1349: }
! 1350: if (!child_cfg && (tsi || tsr))
! 1351: {
! 1352: /* no match for the substituted NAT selectors, try it without */
! 1353: child_cfg = peer_cfg->select_child_cfg(peer_cfg,
! 1354: this->tsr, this->tsi, listr, listi);
! 1355: }
! 1356: listr->destroy(listr);
! 1357: listi->destroy(listi);
! 1358: DESTROY_OFFSET_IF(tsi, offsetof(traffic_selector_t, destroy));
! 1359: DESTROY_OFFSET_IF(tsr, offsetof(traffic_selector_t, destroy));
! 1360: }
! 1361:
! 1362: return child_cfg;
! 1363: }
! 1364:
! 1365: /**
! 1366: * Check how to handle a possibly childless IKE_SA
! 1367: */
! 1368: static status_t handle_childless(private_child_create_t *this)
! 1369: {
! 1370: ike_cfg_t *ike_cfg;
! 1371:
! 1372: ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa);
! 1373:
! 1374: if (!this->proposals && !this->tsi && !this->tsr)
! 1375: {
! 1376: /* looks like a childless IKE_SA, check if we allow it */
! 1377: if (ike_cfg->childless(ike_cfg) == CHILDLESS_NEVER)
! 1378: {
! 1379: /* we don't allow childless initiation */
! 1380: DBG1(DBG_IKE, "peer tried to initiate a childless IKE_SA");
! 1381: return INVALID_STATE;
! 1382: }
! 1383: return SUCCESS;
! 1384: }
! 1385:
! 1386: /* the peer apparently wants to create a regular IKE_SA */
! 1387: if (ike_cfg->childless(ike_cfg) == CHILDLESS_FORCE)
! 1388: {
! 1389: /* reject it if we only allow childless initiation */
! 1390: DBG1(DBG_IKE, "peer did not initiate a childless IKE_SA");
! 1391: return INVALID_STATE;
! 1392: }
! 1393: return NOT_SUPPORTED;
! 1394: }
! 1395:
! 1396: METHOD(task_t, build_r, status_t,
! 1397: private_child_create_t *this, message_t *message)
! 1398: {
! 1399: payload_t *payload;
! 1400: enumerator_t *enumerator;
! 1401: bool no_dh = TRUE, ike_auth = FALSE;
! 1402:
! 1403: switch (message->get_exchange_type(message))
! 1404: {
! 1405: case IKE_SA_INIT:
! 1406: return get_nonce(message, &this->my_nonce);
! 1407: case CREATE_CHILD_SA:
! 1408: if (!generate_nonce(this))
! 1409: {
! 1410: message->add_notify(message, FALSE, NO_PROPOSAL_CHOSEN,
! 1411: chunk_empty);
! 1412: return SUCCESS;
! 1413: }
! 1414: if (this->dh_failed)
! 1415: {
! 1416: DBG1(DBG_IKE, "applying DH public value failed");
! 1417: message->add_notify(message, FALSE, NO_PROPOSAL_CHOSEN,
! 1418: chunk_empty);
! 1419: return SUCCESS;
! 1420: }
! 1421: no_dh = FALSE;
! 1422: break;
! 1423: case IKE_AUTH:
! 1424: if (this->ike_sa->get_state(this->ike_sa) != IKE_ESTABLISHED)
! 1425: { /* wait until all authentication round completed */
! 1426: return NEED_MORE;
! 1427: }
! 1428: if (this->ike_sa->has_condition(this->ike_sa, COND_REDIRECTED))
! 1429: { /* no CHILD_SA is created for redirected SAs */
! 1430: return SUCCESS;
! 1431: }
! 1432: switch (handle_childless(this))
! 1433: {
! 1434: case SUCCESS:
! 1435: /* no CHILD_SA built */
! 1436: return SUCCESS;
! 1437: case INVALID_STATE:
! 1438: message->add_notify(message, FALSE, INVALID_SYNTAX,
! 1439: chunk_empty);
! 1440: return FAILED;
! 1441: default:
! 1442: /* continue with regular initiation */
! 1443: break;
! 1444: }
! 1445: ike_auth = TRUE;
! 1446: default:
! 1447: break;
! 1448: }
! 1449:
! 1450: if (this->ike_sa->get_state(this->ike_sa) == IKE_REKEYING)
! 1451: {
! 1452: DBG1(DBG_IKE, "unable to create CHILD_SA while rekeying IKE_SA");
! 1453: message->add_notify(message, TRUE, TEMPORARY_FAILURE, chunk_empty);
! 1454: return SUCCESS;
! 1455: }
! 1456: if (this->ike_sa->get_state(this->ike_sa) == IKE_DELETING)
! 1457: {
! 1458: DBG1(DBG_IKE, "unable to create CHILD_SA while deleting IKE_SA");
! 1459: message->add_notify(message, TRUE, TEMPORARY_FAILURE, chunk_empty);
! 1460: return SUCCESS;
! 1461: }
! 1462:
! 1463: if (this->config == NULL)
! 1464: {
! 1465: this->config = select_child_cfg(this);
! 1466: }
! 1467: if (this->config == NULL)
! 1468: {
! 1469: DBG1(DBG_IKE, "traffic selectors %#R === %#R unacceptable",
! 1470: this->tsr, this->tsi);
! 1471: charon->bus->alert(charon->bus, ALERT_TS_MISMATCH, this->tsi, this->tsr);
! 1472: message->add_notify(message, FALSE, TS_UNACCEPTABLE, chunk_empty);
! 1473: handle_child_sa_failure(this, message);
! 1474: return SUCCESS;
! 1475: }
! 1476:
! 1477: /* check if ike_config_t included non-critical error notifies */
! 1478: enumerator = message->create_payload_enumerator(message);
! 1479: while (enumerator->enumerate(enumerator, &payload))
! 1480: {
! 1481: if (payload->get_type(payload) == PLV2_NOTIFY)
! 1482: {
! 1483: notify_payload_t *notify = (notify_payload_t*)payload;
! 1484:
! 1485: switch (notify->get_notify_type(notify))
! 1486: {
! 1487: case INTERNAL_ADDRESS_FAILURE:
! 1488: case FAILED_CP_REQUIRED:
! 1489: {
! 1490: DBG1(DBG_IKE,"configuration payload negotiation "
! 1491: "failed, no CHILD_SA built");
! 1492: enumerator->destroy(enumerator);
! 1493: handle_child_sa_failure(this, message);
! 1494: return SUCCESS;
! 1495: }
! 1496: default:
! 1497: break;
! 1498: }
! 1499: }
! 1500: }
! 1501: enumerator->destroy(enumerator);
! 1502:
! 1503: this->child.if_id_in_def = this->ike_sa->get_if_id(this->ike_sa, TRUE);
! 1504: this->child.if_id_out_def = this->ike_sa->get_if_id(this->ike_sa, FALSE);
! 1505: this->child.encap = this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY);
! 1506: this->child_sa = child_sa_create(this->ike_sa->get_my_host(this->ike_sa),
! 1507: this->ike_sa->get_other_host(this->ike_sa),
! 1508: this->config, &this->child);
! 1509:
! 1510: if (this->ipcomp_received != IPCOMP_NONE)
! 1511: {
! 1512: if (this->config->has_option(this->config, OPT_IPCOMP))
! 1513: {
! 1514: add_ipcomp_notify(this, message, this->ipcomp_received);
! 1515: }
! 1516: else
! 1517: {
! 1518: DBG1(DBG_IKE, "received %N notify but IPComp is disabled, ignoring",
! 1519: notify_type_names, IPCOMP_SUPPORTED);
! 1520: }
! 1521: }
! 1522:
! 1523: switch (select_and_install(this, no_dh, ike_auth))
! 1524: {
! 1525: case SUCCESS:
! 1526: break;
! 1527: case NOT_FOUND:
! 1528: message->add_notify(message, FALSE, TS_UNACCEPTABLE, chunk_empty);
! 1529: handle_child_sa_failure(this, message);
! 1530: return SUCCESS;
! 1531: case INVALID_ARG:
! 1532: {
! 1533: uint16_t group = htons(this->dh_group);
! 1534: message->add_notify(message, FALSE, INVALID_KE_PAYLOAD,
! 1535: chunk_from_thing(group));
! 1536: return SUCCESS;
! 1537: }
! 1538: case FAILED:
! 1539: default:
! 1540: message->add_notify(message, FALSE, NO_PROPOSAL_CHOSEN, chunk_empty);
! 1541: handle_child_sa_failure(this, message);
! 1542: return SUCCESS;
! 1543: }
! 1544:
! 1545: if (!build_payloads(this, message))
! 1546: {
! 1547: message->add_notify(message, FALSE, NO_PROPOSAL_CHOSEN, chunk_empty);
! 1548: handle_child_sa_failure(this, message);
! 1549: return SUCCESS;
! 1550: }
! 1551:
! 1552: if (!this->rekey)
! 1553: { /* invoke the child_up() hook if we are not rekeying */
! 1554: charon->bus->child_updown(charon->bus, this->child_sa, TRUE);
! 1555: }
! 1556: return SUCCESS;
! 1557: }
! 1558:
! 1559: /**
! 1560: * Raise alerts for received notify errors
! 1561: */
! 1562: static void raise_alerts(private_child_create_t *this, notify_type_t type)
! 1563: {
! 1564: linked_list_t *list;
! 1565:
! 1566: switch (type)
! 1567: {
! 1568: case NO_PROPOSAL_CHOSEN:
! 1569: list = this->config->get_proposals(this->config, FALSE);
! 1570: charon->bus->alert(charon->bus, ALERT_PROPOSAL_MISMATCH_CHILD, list);
! 1571: list->destroy_offset(list, offsetof(proposal_t, destroy));
! 1572: break;
! 1573: default:
! 1574: break;
! 1575: }
! 1576: }
! 1577:
! 1578: METHOD(task_t, build_i_delete, status_t,
! 1579: private_child_create_t *this, message_t *message)
! 1580: {
! 1581: message->set_exchange_type(message, INFORMATIONAL);
! 1582: if (this->my_spi && this->proto)
! 1583: {
! 1584: delete_payload_t *del;
! 1585:
! 1586: del = delete_payload_create(PLV2_DELETE, this->proto);
! 1587: del->add_spi(del, this->my_spi);
! 1588: message->add_payload(message, (payload_t*)del);
! 1589:
! 1590: DBG1(DBG_IKE, "sending DELETE for %N CHILD_SA with SPI %.8x",
! 1591: protocol_id_names, this->proto, ntohl(this->my_spi));
! 1592: }
! 1593: return NEED_MORE;
! 1594: }
! 1595:
! 1596: /**
! 1597: * Change task to delete the failed CHILD_SA as initiator
! 1598: */
! 1599: static status_t delete_failed_sa(private_child_create_t *this)
! 1600: {
! 1601: if (this->my_spi && this->proto)
! 1602: {
! 1603: this->public.task.build = _build_i_delete;
! 1604: this->public.task.process = (void*)return_success;
! 1605: return NEED_MORE;
! 1606: }
! 1607: return SUCCESS;
! 1608: }
! 1609:
! 1610: METHOD(task_t, process_i, status_t,
! 1611: private_child_create_t *this, message_t *message)
! 1612: {
! 1613: enumerator_t *enumerator;
! 1614: payload_t *payload;
! 1615: bool no_dh = TRUE, ike_auth = FALSE;
! 1616:
! 1617: switch (message->get_exchange_type(message))
! 1618: {
! 1619: case IKE_SA_INIT:
! 1620: return get_nonce(message, &this->other_nonce);
! 1621: case CREATE_CHILD_SA:
! 1622: get_nonce(message, &this->other_nonce);
! 1623: no_dh = FALSE;
! 1624: break;
! 1625: case IKE_AUTH:
! 1626: if (this->ike_sa->get_state(this->ike_sa) != IKE_ESTABLISHED)
! 1627: { /* wait until all authentication round completed */
! 1628: return NEED_MORE;
! 1629: }
! 1630: if (defer_child_sa(this) == NEED_MORE)
! 1631: { /* defer until after IKE_SA has been established */
! 1632: chunk_free(&this->other_nonce);
! 1633: return NEED_MORE;
! 1634: }
! 1635: ike_auth = TRUE;
! 1636: default:
! 1637: break;
! 1638: }
! 1639:
! 1640: /* check for erroneous notifies */
! 1641: enumerator = message->create_payload_enumerator(message);
! 1642: while (enumerator->enumerate(enumerator, &payload))
! 1643: {
! 1644: if (payload->get_type(payload) == PLV2_NOTIFY)
! 1645: {
! 1646: notify_payload_t *notify = (notify_payload_t*)payload;
! 1647: notify_type_t type = notify->get_notify_type(notify);
! 1648:
! 1649: switch (type)
! 1650: {
! 1651: /* handle notify errors related to CHILD_SA only */
! 1652: case NO_PROPOSAL_CHOSEN:
! 1653: case SINGLE_PAIR_REQUIRED:
! 1654: case NO_ADDITIONAL_SAS:
! 1655: case INTERNAL_ADDRESS_FAILURE:
! 1656: case FAILED_CP_REQUIRED:
! 1657: case TS_UNACCEPTABLE:
! 1658: case INVALID_SELECTORS:
! 1659: {
! 1660: DBG1(DBG_IKE, "received %N notify, no CHILD_SA built",
! 1661: notify_type_names, type);
! 1662: enumerator->destroy(enumerator);
! 1663: raise_alerts(this, type);
! 1664: handle_child_sa_failure(this, message);
! 1665: /* an error in CHILD_SA creation is not critical */
! 1666: return SUCCESS;
! 1667: }
! 1668: case TEMPORARY_FAILURE:
! 1669: {
! 1670: DBG1(DBG_IKE, "received %N notify, will retry later",
! 1671: notify_type_names, type);
! 1672: enumerator->destroy(enumerator);
! 1673: if (!this->rekey)
! 1674: { /* the rekey task will retry itself if necessary */
! 1675: schedule_delayed_retry(this);
! 1676: }
! 1677: return SUCCESS;
! 1678: }
! 1679: case INVALID_KE_PAYLOAD:
! 1680: {
! 1681: chunk_t data;
! 1682: uint16_t group = MODP_NONE;
! 1683:
! 1684: data = notify->get_notification_data(notify);
! 1685: if (data.len == sizeof(group))
! 1686: {
! 1687: memcpy(&group, data.ptr, data.len);
! 1688: group = ntohs(group);
! 1689: }
! 1690: if (this->retry)
! 1691: {
! 1692: DBG1(DBG_IKE, "already retried with DH group %N, "
! 1693: "ignore requested %N", diffie_hellman_group_names,
! 1694: this->dh_group, diffie_hellman_group_names, group);
! 1695: handle_child_sa_failure(this, message);
! 1696: /* an error in CHILD_SA creation is not critical */
! 1697: return SUCCESS;
! 1698: }
! 1699: DBG1(DBG_IKE, "peer didn't accept DH group %N, "
! 1700: "it requested %N", diffie_hellman_group_names,
! 1701: this->dh_group, diffie_hellman_group_names, group);
! 1702: this->retry = TRUE;
! 1703: this->dh_group = group;
! 1704: this->child_sa->set_state(this->child_sa, CHILD_RETRYING);
! 1705: this->public.task.migrate(&this->public.task, this->ike_sa);
! 1706: enumerator->destroy(enumerator);
! 1707: return NEED_MORE;
! 1708: }
! 1709: default:
! 1710: {
! 1711: if (message->get_exchange_type(message) == CREATE_CHILD_SA)
! 1712: { /* handle notifies if not handled in IKE_AUTH */
! 1713: if (type <= 16383)
! 1714: {
! 1715: DBG1(DBG_IKE, "received %N notify error",
! 1716: notify_type_names, type);
! 1717: enumerator->destroy(enumerator);
! 1718: return SUCCESS;
! 1719: }
! 1720: DBG2(DBG_IKE, "received %N notify",
! 1721: notify_type_names, type);
! 1722: }
! 1723: break;
! 1724: }
! 1725: }
! 1726: }
! 1727: }
! 1728: enumerator->destroy(enumerator);
! 1729:
! 1730: process_payloads(this, message);
! 1731:
! 1732: if (this->ipcomp == IPCOMP_NONE && this->ipcomp_received != IPCOMP_NONE)
! 1733: {
! 1734: DBG1(DBG_IKE, "received an IPCOMP_SUPPORTED notify without requesting"
! 1735: " one, no CHILD_SA built");
! 1736: handle_child_sa_failure(this, message);
! 1737: return delete_failed_sa(this);
! 1738: }
! 1739: else if (this->ipcomp != IPCOMP_NONE && this->ipcomp_received == IPCOMP_NONE)
! 1740: {
! 1741: DBG1(DBG_IKE, "peer didn't accept our proposed IPComp transforms, "
! 1742: "IPComp is disabled");
! 1743: this->ipcomp = IPCOMP_NONE;
! 1744: }
! 1745: else if (this->ipcomp != IPCOMP_NONE && this->ipcomp != this->ipcomp_received)
! 1746: {
! 1747: DBG1(DBG_IKE, "received an IPCOMP_SUPPORTED notify we didn't propose, "
! 1748: "no CHILD_SA built");
! 1749: handle_child_sa_failure(this, message);
! 1750: return delete_failed_sa(this);
! 1751: }
! 1752:
! 1753: if (this->dh_failed)
! 1754: {
! 1755: DBG1(DBG_IKE, "applying DH public value failed");
! 1756: handle_child_sa_failure(this, message);
! 1757: return delete_failed_sa(this);
! 1758: }
! 1759:
! 1760: if (select_and_install(this, no_dh, ike_auth) == SUCCESS)
! 1761: {
! 1762: if (!this->rekey)
! 1763: { /* invoke the child_up() hook if we are not rekeying */
! 1764: charon->bus->child_updown(charon->bus, this->child_sa, TRUE);
! 1765: }
! 1766: }
! 1767: else
! 1768: {
! 1769: handle_child_sa_failure(this, message);
! 1770: return delete_failed_sa(this);
! 1771: }
! 1772: return SUCCESS;
! 1773: }
! 1774:
! 1775: METHOD(child_create_t, use_reqid, void,
! 1776: private_child_create_t *this, uint32_t reqid)
! 1777: {
! 1778: this->child.reqid = reqid;
! 1779: }
! 1780:
! 1781: METHOD(child_create_t, use_marks, void,
! 1782: private_child_create_t *this, uint32_t in, uint32_t out)
! 1783: {
! 1784: this->child.mark_in = in;
! 1785: this->child.mark_out = out;
! 1786: }
! 1787:
! 1788: METHOD(child_create_t, use_if_ids, void,
! 1789: private_child_create_t *this, uint32_t in, uint32_t out)
! 1790: {
! 1791: this->child.if_id_in = in;
! 1792: this->child.if_id_out = out;
! 1793: }
! 1794:
! 1795: METHOD(child_create_t, use_dh_group, void,
! 1796: private_child_create_t *this, diffie_hellman_group_t dh_group)
! 1797: {
! 1798: this->dh_group = dh_group;
! 1799: }
! 1800:
! 1801: METHOD(child_create_t, get_child, child_sa_t*,
! 1802: private_child_create_t *this)
! 1803: {
! 1804: return this->child_sa;
! 1805: }
! 1806:
! 1807: METHOD(child_create_t, set_config, void,
! 1808: private_child_create_t *this, child_cfg_t *cfg)
! 1809: {
! 1810: DESTROY_IF(this->config);
! 1811: this->config = cfg;
! 1812: }
! 1813:
! 1814: METHOD(child_create_t, get_lower_nonce, chunk_t,
! 1815: private_child_create_t *this)
! 1816: {
! 1817: if (memcmp(this->my_nonce.ptr, this->other_nonce.ptr,
! 1818: min(this->my_nonce.len, this->other_nonce.len)) < 0)
! 1819: {
! 1820: return this->my_nonce;
! 1821: }
! 1822: else
! 1823: {
! 1824: return this->other_nonce;
! 1825: }
! 1826: }
! 1827:
! 1828: METHOD(task_t, get_type, task_type_t,
! 1829: private_child_create_t *this)
! 1830: {
! 1831: return TASK_CHILD_CREATE;
! 1832: }
! 1833:
! 1834: METHOD(task_t, migrate, void,
! 1835: private_child_create_t *this, ike_sa_t *ike_sa)
! 1836: {
! 1837: chunk_free(&this->my_nonce);
! 1838: chunk_free(&this->other_nonce);
! 1839: if (this->tsr)
! 1840: {
! 1841: this->tsr->destroy_offset(this->tsr, offsetof(traffic_selector_t, destroy));
! 1842: }
! 1843: if (this->tsi)
! 1844: {
! 1845: this->tsi->destroy_offset(this->tsi, offsetof(traffic_selector_t, destroy));
! 1846: }
! 1847: DESTROY_IF(this->child_sa);
! 1848: DESTROY_IF(this->proposal);
! 1849: DESTROY_IF(this->nonceg);
! 1850: DESTROY_IF(this->dh);
! 1851: this->dh_failed = FALSE;
! 1852: if (this->proposals)
! 1853: {
! 1854: this->proposals->destroy_offset(this->proposals, offsetof(proposal_t, destroy));
! 1855: }
! 1856:
! 1857: this->ike_sa = ike_sa;
! 1858: this->keymat = (keymat_v2_t*)ike_sa->get_keymat(ike_sa);
! 1859: this->proposal = NULL;
! 1860: this->proposals = NULL;
! 1861: this->tsi = NULL;
! 1862: this->tsr = NULL;
! 1863: this->dh = NULL;
! 1864: this->nonceg = NULL;
! 1865: this->child_sa = NULL;
! 1866: this->mode = MODE_TUNNEL;
! 1867: this->ipcomp = IPCOMP_NONE;
! 1868: this->ipcomp_received = IPCOMP_NONE;
! 1869: this->other_cpi = 0;
! 1870: this->established = FALSE;
! 1871: this->child = (child_sa_create_t){};
! 1872: }
! 1873:
! 1874: METHOD(task_t, destroy, void,
! 1875: private_child_create_t *this)
! 1876: {
! 1877: chunk_free(&this->my_nonce);
! 1878: chunk_free(&this->other_nonce);
! 1879: if (this->tsr)
! 1880: {
! 1881: this->tsr->destroy_offset(this->tsr, offsetof(traffic_selector_t, destroy));
! 1882: }
! 1883: if (this->tsi)
! 1884: {
! 1885: this->tsi->destroy_offset(this->tsi, offsetof(traffic_selector_t, destroy));
! 1886: }
! 1887: if (!this->established)
! 1888: {
! 1889: DESTROY_IF(this->child_sa);
! 1890: }
! 1891: DESTROY_IF(this->packet_tsi);
! 1892: DESTROY_IF(this->packet_tsr);
! 1893: DESTROY_IF(this->proposal);
! 1894: DESTROY_IF(this->dh);
! 1895: if (this->proposals)
! 1896: {
! 1897: this->proposals->destroy_offset(this->proposals, offsetof(proposal_t, destroy));
! 1898: }
! 1899: DESTROY_IF(this->config);
! 1900: DESTROY_IF(this->nonceg);
! 1901: free(this);
! 1902: }
! 1903:
! 1904: /*
! 1905: * Described in header.
! 1906: */
! 1907: child_create_t *child_create_create(ike_sa_t *ike_sa,
! 1908: child_cfg_t *config, bool rekey,
! 1909: traffic_selector_t *tsi, traffic_selector_t *tsr)
! 1910: {
! 1911: private_child_create_t *this;
! 1912:
! 1913: INIT(this,
! 1914: .public = {
! 1915: .get_child = _get_child,
! 1916: .set_config = _set_config,
! 1917: .get_lower_nonce = _get_lower_nonce,
! 1918: .use_reqid = _use_reqid,
! 1919: .use_marks = _use_marks,
! 1920: .use_if_ids = _use_if_ids,
! 1921: .use_dh_group = _use_dh_group,
! 1922: .task = {
! 1923: .get_type = _get_type,
! 1924: .migrate = _migrate,
! 1925: .destroy = _destroy,
! 1926: },
! 1927: },
! 1928: .ike_sa = ike_sa,
! 1929: .config = config,
! 1930: .packet_tsi = tsi ? tsi->clone(tsi) : NULL,
! 1931: .packet_tsr = tsr ? tsr->clone(tsr) : NULL,
! 1932: .dh_group = MODP_NONE,
! 1933: .keymat = (keymat_v2_t*)ike_sa->get_keymat(ike_sa),
! 1934: .mode = MODE_TUNNEL,
! 1935: .tfcv3 = TRUE,
! 1936: .ipcomp = IPCOMP_NONE,
! 1937: .ipcomp_received = IPCOMP_NONE,
! 1938: .rekey = rekey,
! 1939: .retry = FALSE,
! 1940: );
! 1941:
! 1942: if (config)
! 1943: {
! 1944: this->public.task.build = _build_i;
! 1945: this->public.task.process = _process_i;
! 1946: this->initiator = TRUE;
! 1947: }
! 1948: else
! 1949: {
! 1950: this->public.task.build = _build_r;
! 1951: this->public.task.process = _process_r;
! 1952: this->initiator = FALSE;
! 1953: }
! 1954: return &this->public;
! 1955: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>