Annotation of embedaddon/strongswan/src/libcharon/plugins/ha/ha_dispatcher.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2008 Martin Willi
! 3: * HSR Hochschule fuer Technik Rapperswil
! 4: *
! 5: * This program is free software; you can redistribute it and/or modify it
! 6: * under the terms of the GNU General Public License as published by the
! 7: * Free Software Foundation; either version 2 of the License, or (at your
! 8: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
! 9: *
! 10: * This program is distributed in the hope that it will be useful, but
! 11: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
! 12: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
! 13: * for more details.
! 14: */
! 15:
! 16: #include "ha_dispatcher.h"
! 17:
! 18: #include <daemon.h>
! 19: #include <sa/ikev2/keymat_v2.h>
! 20: #include <sa/ikev1/keymat_v1.h>
! 21: #include <processing/jobs/callback_job.h>
! 22: #include <processing/jobs/adopt_children_job.h>
! 23:
! 24: typedef struct private_ha_dispatcher_t private_ha_dispatcher_t;
! 25: typedef struct ha_diffie_hellman_t ha_diffie_hellman_t;
! 26:
! 27: /**
! 28: * Private data of an ha_dispatcher_t object.
! 29: */
! 30: struct private_ha_dispatcher_t {
! 31:
! 32: /**
! 33: * Public ha_dispatcher_t interface.
! 34: */
! 35: ha_dispatcher_t public;
! 36:
! 37: /**
! 38: * socket to pull messages from
! 39: */
! 40: ha_socket_t *socket;
! 41:
! 42: /**
! 43: * segments to control
! 44: */
! 45: ha_segments_t *segments;
! 46:
! 47: /**
! 48: * Cache for resync
! 49: */
! 50: ha_cache_t *cache;
! 51:
! 52: /**
! 53: * Kernel helper
! 54: */
! 55: ha_kernel_t *kernel;
! 56:
! 57: /**
! 58: * HA enabled pool
! 59: */
! 60: ha_attribute_t *attr;
! 61: };
! 62:
! 63: /**
! 64: * DH implementation for HA synced DH values
! 65: */
! 66: struct ha_diffie_hellman_t {
! 67:
! 68: /**
! 69: * Implements diffie_hellman_t
! 70: */
! 71: diffie_hellman_t dh;
! 72:
! 73: /**
! 74: * Shared secret
! 75: */
! 76: chunk_t secret;
! 77:
! 78: /**
! 79: * Own public value
! 80: */
! 81: chunk_t pub;
! 82: };
! 83:
! 84: METHOD(diffie_hellman_t, dh_get_shared_secret, bool,
! 85: ha_diffie_hellman_t *this, chunk_t *secret)
! 86: {
! 87: *secret = chunk_clone(this->secret);
! 88: return TRUE;
! 89: }
! 90:
! 91: METHOD(diffie_hellman_t, dh_get_my_public_value, bool,
! 92: ha_diffie_hellman_t *this, chunk_t *value)
! 93: {
! 94: *value = chunk_clone(this->pub);
! 95: return TRUE;
! 96: }
! 97:
! 98: METHOD(diffie_hellman_t, dh_destroy, void,
! 99: ha_diffie_hellman_t *this)
! 100: {
! 101: free(this);
! 102: }
! 103:
! 104: /**
! 105: * Create a HA synced DH implementation
! 106: */
! 107: static diffie_hellman_t *ha_diffie_hellman_create(chunk_t secret, chunk_t pub)
! 108: {
! 109: ha_diffie_hellman_t *this;
! 110:
! 111: INIT(this,
! 112: .dh = {
! 113: .get_shared_secret = _dh_get_shared_secret,
! 114: .get_my_public_value = _dh_get_my_public_value,
! 115: .destroy = _dh_destroy,
! 116: },
! 117: .secret = secret,
! 118: .pub = pub,
! 119: );
! 120:
! 121: return &this->dh;
! 122: }
! 123:
! 124: /**
! 125: * Process messages of type IKE_ADD
! 126: */
! 127: static void process_ike_add(private_ha_dispatcher_t *this, ha_message_t *message)
! 128: {
! 129: ha_message_attribute_t attribute;
! 130: ha_message_value_t value;
! 131: enumerator_t *enumerator;
! 132: ike_sa_t *ike_sa = NULL, *old_sa = NULL;
! 133: ike_version_t version = IKEV2;
! 134: uint16_t encr = 0, len = 0, integ = 0, prf = 0, old_prf = PRF_UNDEFINED;
! 135: uint16_t dh_grp = 0;
! 136: chunk_t nonce_i = chunk_empty, nonce_r = chunk_empty;
! 137: chunk_t secret = chunk_empty, old_skd = chunk_empty;
! 138: chunk_t dh_local = chunk_empty, dh_remote = chunk_empty, psk = chunk_empty;
! 139: host_t *other = NULL;
! 140: bool ok = FALSE;
! 141: auth_method_t method = AUTH_RSA;
! 142:
! 143: enumerator = message->create_attribute_enumerator(message);
! 144: while (enumerator->enumerate(enumerator, &attribute, &value))
! 145: {
! 146: switch (attribute)
! 147: {
! 148: case HA_IKE_ID:
! 149: ike_sa = ike_sa_create(value.ike_sa_id,
! 150: value.ike_sa_id->is_initiator(value.ike_sa_id), version);
! 151: break;
! 152: case HA_IKE_REKEY_ID:
! 153: old_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
! 154: value.ike_sa_id);
! 155: break;
! 156: case HA_REMOTE_ADDR:
! 157: other = value.host->clone(value.host);
! 158: break;
! 159: case HA_IKE_VERSION:
! 160: version = value.u8;
! 161: break;
! 162: case HA_NONCE_I:
! 163: nonce_i = value.chunk;
! 164: break;
! 165: case HA_NONCE_R:
! 166: nonce_r = value.chunk;
! 167: break;
! 168: case HA_SECRET:
! 169: secret = value.chunk;
! 170: break;
! 171: case HA_LOCAL_DH:
! 172: dh_local = value.chunk;
! 173: break;
! 174: case HA_REMOTE_DH:
! 175: dh_remote = value.chunk;
! 176: break;
! 177: case HA_PSK:
! 178: psk = value.chunk;
! 179: break;
! 180: case HA_OLD_SKD:
! 181: old_skd = value.chunk;
! 182: break;
! 183: case HA_ALG_ENCR:
! 184: encr = value.u16;
! 185: break;
! 186: case HA_ALG_ENCR_LEN:
! 187: len = value.u16;
! 188: break;
! 189: case HA_ALG_INTEG:
! 190: integ = value.u16;
! 191: break;
! 192: case HA_ALG_PRF:
! 193: prf = value.u16;
! 194: break;
! 195: case HA_ALG_OLD_PRF:
! 196: old_prf = value.u16;
! 197: break;
! 198: case HA_ALG_DH:
! 199: dh_grp = value.u16;
! 200: break;
! 201: case HA_AUTH_METHOD:
! 202: method = value.u16;
! 203: default:
! 204: break;
! 205: }
! 206: }
! 207: enumerator->destroy(enumerator);
! 208:
! 209: if (ike_sa)
! 210: {
! 211: proposal_t *proposal;
! 212: diffie_hellman_t *dh;
! 213:
! 214: proposal = proposal_create(PROTO_IKE, 0);
! 215: if (integ)
! 216: {
! 217: proposal->add_algorithm(proposal, INTEGRITY_ALGORITHM, integ, 0);
! 218: }
! 219: if (encr)
! 220: {
! 221: proposal->add_algorithm(proposal, ENCRYPTION_ALGORITHM, encr, len);
! 222: }
! 223: if (prf)
! 224: {
! 225: proposal->add_algorithm(proposal, PSEUDO_RANDOM_FUNCTION, prf, 0);
! 226: }
! 227: if (dh_grp)
! 228: {
! 229: proposal->add_algorithm(proposal, DIFFIE_HELLMAN_GROUP, dh_grp, 0);
! 230: }
! 231: charon->bus->set_sa(charon->bus, ike_sa);
! 232: dh = ha_diffie_hellman_create(secret, dh_local);
! 233: if (ike_sa->get_version(ike_sa) == IKEV2)
! 234: {
! 235: keymat_v2_t *keymat_v2 = (keymat_v2_t*)ike_sa->get_keymat(ike_sa);
! 236:
! 237: ok = keymat_v2->derive_ike_keys(keymat_v2, proposal, dh, nonce_i,
! 238: nonce_r, ike_sa->get_id(ike_sa), old_prf, old_skd);
! 239: }
! 240: if (ike_sa->get_version(ike_sa) == IKEV1)
! 241: {
! 242: keymat_v1_t *keymat_v1 = (keymat_v1_t*)ike_sa->get_keymat(ike_sa);
! 243: shared_key_t *shared = NULL;
! 244:
! 245: if (psk.len)
! 246: {
! 247: method = AUTH_PSK;
! 248: shared = shared_key_create(SHARED_IKE, chunk_clone(psk));
! 249: }
! 250: if (keymat_v1->create_hasher(keymat_v1, proposal))
! 251: {
! 252: ok = keymat_v1->derive_ike_keys(keymat_v1, proposal,
! 253: dh, dh_remote, nonce_i, nonce_r,
! 254: ike_sa->get_id(ike_sa), method, shared);
! 255: }
! 256: DESTROY_IF(shared);
! 257: }
! 258: dh->destroy(dh);
! 259: if (ok)
! 260: {
! 261: if (old_sa)
! 262: {
! 263: ike_sa->inherit_pre(ike_sa, old_sa);
! 264: ike_sa->inherit_post(ike_sa, old_sa);
! 265: charon->ike_sa_manager->checkin_and_destroy(
! 266: charon->ike_sa_manager, old_sa);
! 267: old_sa = NULL;
! 268: }
! 269: if (other)
! 270: {
! 271: ike_sa->set_other_host(ike_sa, other);
! 272: other = NULL;
! 273: }
! 274: ike_sa->set_state(ike_sa, IKE_CONNECTING);
! 275: ike_sa->set_proposal(ike_sa, proposal);
! 276: this->cache->cache(this->cache, ike_sa, message);
! 277: message = NULL;
! 278: charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
! 279: }
! 280: else
! 281: {
! 282: DBG1(DBG_IKE, "HA keymat derivation failed");
! 283: ike_sa->destroy(ike_sa);
! 284: }
! 285: charon->bus->set_sa(charon->bus, NULL);
! 286: proposal->destroy(proposal);
! 287: }
! 288: if (old_sa)
! 289: {
! 290: charon->ike_sa_manager->checkin(charon->ike_sa_manager, old_sa);
! 291: }
! 292: DESTROY_IF(other);
! 293: DESTROY_IF(message);
! 294: }
! 295:
! 296: /**
! 297: * Apply a condition flag to the IKE_SA if it is in set
! 298: */
! 299: static void set_condition(ike_sa_t *ike_sa, ike_condition_t set,
! 300: ike_condition_t flag)
! 301: {
! 302: ike_sa->set_condition(ike_sa, flag, flag & set);
! 303: }
! 304:
! 305: /**
! 306: * Apply a extension flag to the IKE_SA if it is in set
! 307: */
! 308: static void set_extension(ike_sa_t *ike_sa, ike_extension_t set,
! 309: ike_extension_t flag)
! 310: {
! 311: if (flag & set)
! 312: {
! 313: ike_sa->enable_extension(ike_sa, flag);
! 314: }
! 315: }
! 316:
! 317: /**
! 318: * Process messages of type IKE_UPDATE
! 319: */
! 320: static void process_ike_update(private_ha_dispatcher_t *this,
! 321: ha_message_t *message)
! 322: {
! 323: ha_message_attribute_t attribute;
! 324: ha_message_value_t value;
! 325: enumerator_t *enumerator;
! 326: ike_sa_t *ike_sa = NULL;
! 327: peer_cfg_t *peer_cfg = NULL;
! 328: auth_cfg_t *auth;
! 329: bool received_vip = FALSE, first_local_vip = TRUE, first_peer_addr = TRUE;
! 330:
! 331: enumerator = message->create_attribute_enumerator(message);
! 332: while (enumerator->enumerate(enumerator, &attribute, &value))
! 333: {
! 334: if (attribute != HA_IKE_ID && ike_sa == NULL)
! 335: {
! 336: /* must be first attribute */
! 337: break;
! 338: }
! 339: switch (attribute)
! 340: {
! 341: case HA_IKE_ID:
! 342: ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
! 343: value.ike_sa_id);
! 344: break;
! 345: case HA_LOCAL_ID:
! 346: ike_sa->set_my_id(ike_sa, value.id->clone(value.id));
! 347: break;
! 348: case HA_REMOTE_ID:
! 349: ike_sa->set_other_id(ike_sa, value.id->clone(value.id));
! 350: break;
! 351: case HA_REMOTE_EAP_ID:
! 352: auth = auth_cfg_create();
! 353: auth->add(auth, AUTH_RULE_EAP_IDENTITY, value.id->clone(value.id));
! 354: ike_sa->add_auth_cfg(ike_sa, FALSE, auth);
! 355: break;
! 356: case HA_LOCAL_ADDR:
! 357: ike_sa->set_my_host(ike_sa, value.host->clone(value.host));
! 358: break;
! 359: case HA_REMOTE_ADDR:
! 360: ike_sa->set_other_host(ike_sa, value.host->clone(value.host));
! 361: break;
! 362: case HA_LOCAL_VIP:
! 363: if (first_local_vip)
! 364: {
! 365: ike_sa->clear_virtual_ips(ike_sa, TRUE);
! 366: first_local_vip = FALSE;
! 367: }
! 368: ike_sa->add_virtual_ip(ike_sa, TRUE, value.host);
! 369: break;
! 370: case HA_REMOTE_VIP:
! 371: if (!received_vip)
! 372: {
! 373: ike_sa->clear_virtual_ips(ike_sa, FALSE);
! 374: }
! 375: ike_sa->add_virtual_ip(ike_sa, FALSE, value.host);
! 376: received_vip = TRUE;
! 377: break;
! 378: case HA_PEER_ADDR:
! 379: if (first_peer_addr)
! 380: {
! 381: ike_sa->clear_peer_addresses(ike_sa);
! 382: first_peer_addr = FALSE;
! 383: }
! 384: ike_sa->add_peer_address(ike_sa, value.host->clone(value.host));
! 385: break;
! 386: case HA_CONFIG_NAME:
! 387: peer_cfg = charon->backends->get_peer_cfg_by_name(
! 388: charon->backends, value.str);
! 389: if (peer_cfg)
! 390: {
! 391: ike_sa->set_peer_cfg(ike_sa, peer_cfg);
! 392: peer_cfg->destroy(peer_cfg);
! 393: }
! 394: else
! 395: {
! 396: DBG1(DBG_IKE, "HA is missing nodes peer configuration");
! 397: charon->ike_sa_manager->checkin_and_destroy(
! 398: charon->ike_sa_manager, ike_sa);
! 399: ike_sa = NULL;
! 400: }
! 401: break;
! 402: case HA_EXTENSIONS:
! 403: set_extension(ike_sa, value.u32, EXT_NATT);
! 404: set_extension(ike_sa, value.u32, EXT_MOBIKE);
! 405: set_extension(ike_sa, value.u32, EXT_HASH_AND_URL);
! 406: set_extension(ike_sa, value.u32, EXT_MULTIPLE_AUTH);
! 407: set_extension(ike_sa, value.u32, EXT_STRONGSWAN);
! 408: set_extension(ike_sa, value.u32, EXT_EAP_ONLY_AUTHENTICATION);
! 409: set_extension(ike_sa, value.u32, EXT_MS_WINDOWS);
! 410: set_extension(ike_sa, value.u32, EXT_XAUTH);
! 411: set_extension(ike_sa, value.u32, EXT_DPD);
! 412: break;
! 413: case HA_CONDITIONS:
! 414: set_condition(ike_sa, value.u32, COND_NAT_ANY);
! 415: set_condition(ike_sa, value.u32, COND_NAT_HERE);
! 416: set_condition(ike_sa, value.u32, COND_NAT_THERE);
! 417: set_condition(ike_sa, value.u32, COND_NAT_FAKE);
! 418: set_condition(ike_sa, value.u32, COND_EAP_AUTHENTICATED);
! 419: set_condition(ike_sa, value.u32, COND_CERTREQ_SEEN);
! 420: set_condition(ike_sa, value.u32, COND_ORIGINAL_INITIATOR);
! 421: set_condition(ike_sa, value.u32, COND_STALE);
! 422: set_condition(ike_sa, value.u32, COND_INIT_CONTACT_SEEN);
! 423: set_condition(ike_sa, value.u32, COND_XAUTH_AUTHENTICATED);
! 424: break;
! 425: default:
! 426: break;
! 427: }
! 428: }
! 429: enumerator->destroy(enumerator);
! 430:
! 431: if (ike_sa)
! 432: {
! 433: if (ike_sa->get_state(ike_sa) == IKE_CONNECTING &&
! 434: ike_sa->get_peer_cfg(ike_sa))
! 435: {
! 436: DBG1(DBG_CFG, "installed HA passive IKE_SA '%s' %H[%Y]...%H[%Y]",
! 437: ike_sa->get_name(ike_sa),
! 438: ike_sa->get_my_host(ike_sa), ike_sa->get_my_id(ike_sa),
! 439: ike_sa->get_other_host(ike_sa), ike_sa->get_other_id(ike_sa));
! 440: ike_sa->set_state(ike_sa, IKE_PASSIVE);
! 441: }
! 442: if (received_vip)
! 443: {
! 444: enumerator_t *pools, *vips;
! 445: host_t *vip;
! 446: char *pool;
! 447:
! 448: peer_cfg = ike_sa->get_peer_cfg(ike_sa);
! 449: if (peer_cfg)
! 450: {
! 451: pools = peer_cfg->create_pool_enumerator(peer_cfg);
! 452: while (pools->enumerate(pools, &pool))
! 453: {
! 454: vips = ike_sa->create_virtual_ip_enumerator(ike_sa, FALSE);
! 455: while (vips->enumerate(vips, &vip))
! 456: {
! 457: this->attr->reserve(this->attr, pool, vip);
! 458: }
! 459: vips->destroy(vips);
! 460: }
! 461: pools->destroy(pools);
! 462: }
! 463: }
! 464: #ifdef USE_IKEV1
! 465: if (ike_sa->get_version(ike_sa) == IKEV1)
! 466: {
! 467: lib->processor->queue_job(lib->processor, (job_t*)
! 468: adopt_children_job_create(ike_sa->get_id(ike_sa)));
! 469: }
! 470: #endif /* USE_IKEV1 */
! 471: this->cache->cache(this->cache, ike_sa, message);
! 472: charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
! 473: }
! 474: else
! 475: {
! 476: DBG1(DBG_CFG, "passive HA IKE_SA to update not found");
! 477: message->destroy(message);
! 478: }
! 479: }
! 480:
! 481: /**
! 482: * Process messages of type IKE_MID_INITIATOR/RESPONDER
! 483: */
! 484: static void process_ike_mid(private_ha_dispatcher_t *this,
! 485: ha_message_t *message, bool initiator)
! 486: {
! 487: ha_message_attribute_t attribute;
! 488: ha_message_value_t value;
! 489: enumerator_t *enumerator;
! 490: ike_sa_t *ike_sa = NULL;
! 491: uint32_t mid = 0;
! 492:
! 493: enumerator = message->create_attribute_enumerator(message);
! 494: while (enumerator->enumerate(enumerator, &attribute, &value))
! 495: {
! 496: switch (attribute)
! 497: {
! 498: case HA_IKE_ID:
! 499: ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
! 500: value.ike_sa_id);
! 501: break;
! 502: case HA_MID:
! 503: mid = value.u32;
! 504: break;
! 505: default:
! 506: break;
! 507: }
! 508: }
! 509: enumerator->destroy(enumerator);
! 510:
! 511: if (ike_sa)
! 512: {
! 513: if (mid)
! 514: {
! 515: ike_sa->set_message_id(ike_sa, initiator, mid);
! 516: }
! 517: this->cache->cache(this->cache, ike_sa, message);
! 518: charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
! 519: }
! 520: else
! 521: {
! 522: message->destroy(message);
! 523: }
! 524: }
! 525:
! 526: /**
! 527: * Process messages of type IKE_IV
! 528: */
! 529: static void process_ike_iv(private_ha_dispatcher_t *this, ha_message_t *message)
! 530: {
! 531: ha_message_attribute_t attribute;
! 532: ha_message_value_t value;
! 533: enumerator_t *enumerator;
! 534: ike_sa_t *ike_sa = NULL;
! 535: chunk_t iv = chunk_empty;
! 536:
! 537: enumerator = message->create_attribute_enumerator(message);
! 538: while (enumerator->enumerate(enumerator, &attribute, &value))
! 539: {
! 540: switch (attribute)
! 541: {
! 542: case HA_IKE_ID:
! 543: ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
! 544: value.ike_sa_id);
! 545: break;
! 546: case HA_IV:
! 547: iv = value.chunk;
! 548: break;
! 549: default:
! 550: break;
! 551: }
! 552: }
! 553: enumerator->destroy(enumerator);
! 554:
! 555: if (ike_sa)
! 556: {
! 557: if (ike_sa->get_version(ike_sa) == IKEV1)
! 558: {
! 559: if (iv.len)
! 560: {
! 561: keymat_v1_t *keymat;
! 562:
! 563: keymat = (keymat_v1_t*)ike_sa->get_keymat(ike_sa);
! 564: if (keymat->update_iv(keymat, 0, iv))
! 565: {
! 566: keymat->confirm_iv(keymat, 0);
! 567: }
! 568: }
! 569: }
! 570: this->cache->cache(this->cache, ike_sa, message);
! 571: charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
! 572: }
! 573: else
! 574: {
! 575: message->destroy(message);
! 576: }
! 577: }
! 578:
! 579: /**
! 580: * Process messages of type IKE_DELETE
! 581: */
! 582: static void process_ike_delete(private_ha_dispatcher_t *this,
! 583: ha_message_t *message)
! 584: {
! 585: ha_message_attribute_t attribute;
! 586: ha_message_value_t value;
! 587: enumerator_t *enumerator;
! 588: ike_sa_t *ike_sa = NULL;
! 589:
! 590: enumerator = message->create_attribute_enumerator(message);
! 591: while (enumerator->enumerate(enumerator, &attribute, &value))
! 592: {
! 593: switch (attribute)
! 594: {
! 595: case HA_IKE_ID:
! 596: ike_sa = charon->ike_sa_manager->checkout(
! 597: charon->ike_sa_manager, value.ike_sa_id);
! 598: break;
! 599: default:
! 600: break;
! 601: }
! 602: }
! 603: enumerator->destroy(enumerator);
! 604: if (ike_sa)
! 605: {
! 606: this->cache->cache(this->cache, ike_sa, message);
! 607: charon->ike_sa_manager->checkin_and_destroy(
! 608: charon->ike_sa_manager, ike_sa);
! 609: }
! 610: else
! 611: {
! 612: message->destroy(message);
! 613: }
! 614: }
! 615:
! 616: /**
! 617: * Lookup a child cfg from the peer cfg by name
! 618: */
! 619: static child_cfg_t* find_child_cfg(ike_sa_t *ike_sa, char *name)
! 620: {
! 621: peer_cfg_t *peer_cfg;
! 622: child_cfg_t *current, *found = NULL;
! 623: enumerator_t *enumerator;
! 624:
! 625: peer_cfg = ike_sa->get_peer_cfg(ike_sa);
! 626: if (peer_cfg)
! 627: {
! 628: enumerator = peer_cfg->create_child_cfg_enumerator(peer_cfg);
! 629: while (enumerator->enumerate(enumerator, ¤t))
! 630: {
! 631: if (streq(current->get_name(current), name))
! 632: {
! 633: found = current;
! 634: break;
! 635: }
! 636: }
! 637: enumerator->destroy(enumerator);
! 638: }
! 639: return found;
! 640: }
! 641:
! 642: /**
! 643: * Process messages of type CHILD_ADD
! 644: */
! 645: static void process_child_add(private_ha_dispatcher_t *this,
! 646: ha_message_t *message)
! 647: {
! 648: ha_message_attribute_t attribute;
! 649: ha_message_value_t value;
! 650: enumerator_t *enumerator;
! 651: ike_sa_t *ike_sa = NULL;
! 652: char *config_name = "";
! 653: child_cfg_t *config = NULL;
! 654: child_sa_t *child_sa;
! 655: proposal_t *proposal;
! 656: bool initiator = FALSE, failed = FALSE, ok = FALSE;
! 657: uint32_t inbound_spi = 0, outbound_spi = 0;
! 658: uint16_t inbound_cpi = 0, outbound_cpi = 0;
! 659: uint8_t mode = MODE_TUNNEL, ipcomp = 0;
! 660: uint16_t encr = 0, integ = 0, len = 0, dh_grp = 0;
! 661: uint16_t esn = NO_EXT_SEQ_NUMBERS;
! 662: u_int seg_i, seg_o;
! 663: chunk_t nonce_i = chunk_empty, nonce_r = chunk_empty, secret = chunk_empty;
! 664: chunk_t encr_i, integ_i, encr_r, integ_r;
! 665: linked_list_t *local_ts, *remote_ts;
! 666: diffie_hellman_t *dh = NULL;
! 667:
! 668: enumerator = message->create_attribute_enumerator(message);
! 669: while (enumerator->enumerate(enumerator, &attribute, &value))
! 670: {
! 671: switch (attribute)
! 672: {
! 673: case HA_IKE_ID:
! 674: ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
! 675: value.ike_sa_id);
! 676: break;
! 677: case HA_CONFIG_NAME:
! 678: config_name = value.str;
! 679: break;
! 680: case HA_INITIATOR:
! 681: initiator = value.u8;
! 682: break;
! 683: case HA_INBOUND_SPI:
! 684: inbound_spi = value.u32;
! 685: break;
! 686: case HA_OUTBOUND_SPI:
! 687: outbound_spi = value.u32;
! 688: break;
! 689: case HA_INBOUND_CPI:
! 690: inbound_cpi = value.u32;
! 691: break;
! 692: case HA_OUTBOUND_CPI:
! 693: outbound_cpi = value.u32;
! 694: break;
! 695: case HA_IPSEC_MODE:
! 696: mode = value.u8;
! 697: break;
! 698: case HA_IPCOMP:
! 699: ipcomp = value.u8;
! 700: break;
! 701: case HA_ALG_ENCR:
! 702: encr = value.u16;
! 703: break;
! 704: case HA_ALG_ENCR_LEN:
! 705: len = value.u16;
! 706: break;
! 707: case HA_ALG_INTEG:
! 708: integ = value.u16;
! 709: break;
! 710: case HA_ALG_DH:
! 711: dh_grp = value.u16;
! 712: break;
! 713: case HA_ESN:
! 714: esn = value.u16;
! 715: break;
! 716: case HA_NONCE_I:
! 717: nonce_i = value.chunk;
! 718: break;
! 719: case HA_NONCE_R:
! 720: nonce_r = value.chunk;
! 721: break;
! 722: case HA_SECRET:
! 723: secret = value.chunk;
! 724: break;
! 725: default:
! 726: break;
! 727: }
! 728: }
! 729: enumerator->destroy(enumerator);
! 730:
! 731: if (!ike_sa)
! 732: {
! 733: DBG1(DBG_CHD, "IKE_SA for HA CHILD_SA not found");
! 734: message->destroy(message);
! 735: return;
! 736: }
! 737: config = find_child_cfg(ike_sa, config_name);
! 738: if (!config)
! 739: {
! 740: DBG1(DBG_CHD, "HA is missing nodes child configuration");
! 741: charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
! 742: message->destroy(message);
! 743: return;
! 744: }
! 745:
! 746: child_sa_create_t data = {
! 747: .encap = ike_sa->has_condition(ike_sa, COND_NAT_ANY),
! 748: };
! 749: child_sa = child_sa_create(ike_sa->get_my_host(ike_sa),
! 750: ike_sa->get_other_host(ike_sa), config, &data);
! 751: child_sa->set_mode(child_sa, mode);
! 752: child_sa->set_protocol(child_sa, PROTO_ESP);
! 753: child_sa->set_ipcomp(child_sa, ipcomp);
! 754:
! 755: proposal = proposal_create(PROTO_ESP, 0);
! 756: if (integ)
! 757: {
! 758: proposal->add_algorithm(proposal, INTEGRITY_ALGORITHM, integ, 0);
! 759: }
! 760: if (encr)
! 761: {
! 762: proposal->add_algorithm(proposal, ENCRYPTION_ALGORITHM, encr, len);
! 763: }
! 764: if (dh_grp)
! 765: {
! 766: proposal->add_algorithm(proposal, DIFFIE_HELLMAN_GROUP, dh_grp, 0);
! 767: }
! 768: proposal->add_algorithm(proposal, EXTENDED_SEQUENCE_NUMBERS, esn, 0);
! 769: if (secret.len)
! 770: {
! 771: dh = ha_diffie_hellman_create(secret, chunk_empty);
! 772: }
! 773: if (ike_sa->get_version(ike_sa) == IKEV2)
! 774: {
! 775: keymat_v2_t *keymat_v2 = (keymat_v2_t*)ike_sa->get_keymat(ike_sa);
! 776:
! 777: ok = keymat_v2->derive_child_keys(keymat_v2, proposal, dh,
! 778: nonce_i, nonce_r, &encr_i, &integ_i, &encr_r, &integ_r);
! 779: }
! 780: if (ike_sa->get_version(ike_sa) == IKEV1)
! 781: {
! 782: keymat_v1_t *keymat_v1 = (keymat_v1_t*)ike_sa->get_keymat(ike_sa);
! 783: uint32_t spi_i, spi_r;
! 784:
! 785: spi_i = initiator ? inbound_spi : outbound_spi;
! 786: spi_r = initiator ? outbound_spi : inbound_spi;
! 787:
! 788: ok = keymat_v1->derive_child_keys(keymat_v1, proposal, dh, spi_i, spi_r,
! 789: nonce_i, nonce_r, &encr_i, &integ_i, &encr_r, &integ_r);
! 790: }
! 791: DESTROY_IF(dh);
! 792: if (!ok)
! 793: {
! 794: DBG1(DBG_CHD, "HA CHILD_SA key derivation failed");
! 795: child_sa->destroy(child_sa);
! 796: proposal->destroy(proposal);
! 797: charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
! 798: return;
! 799: }
! 800: child_sa->set_proposal(child_sa, proposal);
! 801: child_sa->set_state(child_sa, CHILD_INSTALLING);
! 802: proposal->destroy(proposal);
! 803:
! 804: /* TODO: Change CHILD_SA API to avoid cloning twice */
! 805: local_ts = linked_list_create();
! 806: remote_ts = linked_list_create();
! 807: enumerator = message->create_attribute_enumerator(message);
! 808: while (enumerator->enumerate(enumerator, &attribute, &value))
! 809: {
! 810: switch (attribute)
! 811: {
! 812: case HA_LOCAL_TS:
! 813: local_ts->insert_last(local_ts, value.ts->clone(value.ts));
! 814: break;
! 815: case HA_REMOTE_TS:
! 816: remote_ts->insert_last(remote_ts, value.ts->clone(value.ts));
! 817: break;
! 818: default:
! 819: break;
! 820: }
! 821: }
! 822: enumerator->destroy(enumerator);
! 823:
! 824: child_sa->set_policies(child_sa, local_ts, remote_ts);
! 825:
! 826: if (initiator)
! 827: {
! 828: if (child_sa->install(child_sa, encr_r, integ_r, inbound_spi,
! 829: inbound_cpi, initiator, TRUE, TRUE) != SUCCESS ||
! 830: child_sa->install(child_sa, encr_i, integ_i, outbound_spi,
! 831: outbound_cpi, initiator, FALSE, TRUE) != SUCCESS)
! 832: {
! 833: failed = TRUE;
! 834: }
! 835: }
! 836: else
! 837: {
! 838: if (child_sa->install(child_sa, encr_i, integ_i, inbound_spi,
! 839: inbound_cpi, initiator, TRUE, TRUE) != SUCCESS ||
! 840: child_sa->install(child_sa, encr_r, integ_r, outbound_spi,
! 841: outbound_cpi, initiator, FALSE, TRUE) != SUCCESS)
! 842: {
! 843: failed = TRUE;
! 844: }
! 845: }
! 846: chunk_clear(&encr_i);
! 847: chunk_clear(&integ_i);
! 848: chunk_clear(&encr_r);
! 849: chunk_clear(&integ_r);
! 850:
! 851: if (failed)
! 852: {
! 853: DBG1(DBG_CHD, "HA CHILD_SA installation failed");
! 854: child_sa->destroy(child_sa);
! 855: local_ts->destroy_offset(local_ts, offsetof(traffic_selector_t, destroy));
! 856: remote_ts->destroy_offset(remote_ts, offsetof(traffic_selector_t, destroy));
! 857: charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
! 858: message->destroy(message);
! 859: return;
! 860: }
! 861:
! 862: seg_i = this->kernel->get_segment_spi(this->kernel,
! 863: ike_sa->get_my_host(ike_sa), inbound_spi);
! 864: seg_o = this->kernel->get_segment_spi(this->kernel,
! 865: ike_sa->get_other_host(ike_sa), outbound_spi);
! 866:
! 867: DBG1(DBG_CFG, "installed HA CHILD_SA %s{%d} %#R === %#R "
! 868: "(segment in: %d%s, out: %d%s)", child_sa->get_name(child_sa),
! 869: child_sa->get_unique_id(child_sa), local_ts, remote_ts,
! 870: seg_i, this->segments->is_active(this->segments, seg_i) ? "*" : "",
! 871: seg_o, this->segments->is_active(this->segments, seg_o) ? "*" : "");
! 872: child_sa->install_policies(child_sa);
! 873: local_ts->destroy_offset(local_ts, offsetof(traffic_selector_t, destroy));
! 874: remote_ts->destroy_offset(remote_ts, offsetof(traffic_selector_t, destroy));
! 875:
! 876: child_sa->set_state(child_sa, CHILD_INSTALLED);
! 877: ike_sa->add_child_sa(ike_sa, child_sa);
! 878: message->destroy(message);
! 879: charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
! 880: }
! 881:
! 882: /**
! 883: * Process messages of type CHILD_DELETE
! 884: */
! 885: static void process_child_delete(private_ha_dispatcher_t *this,
! 886: ha_message_t *message)
! 887: {
! 888: ha_message_attribute_t attribute;
! 889: ha_message_value_t value;
! 890: enumerator_t *enumerator;
! 891: ike_sa_t *ike_sa = NULL;
! 892: child_sa_t *child_sa;
! 893: uint32_t spi = 0;
! 894:
! 895: enumerator = message->create_attribute_enumerator(message);
! 896: while (enumerator->enumerate(enumerator, &attribute, &value))
! 897: {
! 898: switch (attribute)
! 899: {
! 900: case HA_IKE_ID:
! 901: ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
! 902: value.ike_sa_id);
! 903: break;
! 904: case HA_INBOUND_SPI:
! 905: spi = value.u32;
! 906: break;
! 907: default:
! 908: break;
! 909: }
! 910: }
! 911: enumerator->destroy(enumerator);
! 912:
! 913: if (ike_sa)
! 914: {
! 915: child_sa = ike_sa->get_child_sa(ike_sa, PROTO_ESP, spi, TRUE);
! 916: if (child_sa)
! 917: {
! 918: ike_sa->destroy_child_sa(ike_sa, PROTO_ESP, spi);
! 919: }
! 920: charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
! 921: }
! 922: message->destroy(message);
! 923: }
! 924:
! 925: /**
! 926: * Process messages of type SEGMENT_TAKE/DROP
! 927: */
! 928: static void process_segment(private_ha_dispatcher_t *this,
! 929: ha_message_t *message, bool take)
! 930: {
! 931: ha_message_attribute_t attribute;
! 932: ha_message_value_t value;
! 933: enumerator_t *enumerator;
! 934:
! 935: enumerator = message->create_attribute_enumerator(message);
! 936: while (enumerator->enumerate(enumerator, &attribute, &value))
! 937: {
! 938: switch (attribute)
! 939: {
! 940: case HA_SEGMENT:
! 941: if (take)
! 942: {
! 943: DBG1(DBG_CFG, "remote node takes segment %d", value.u16);
! 944: this->segments->deactivate(this->segments, value.u16, FALSE);
! 945: }
! 946: else
! 947: {
! 948: DBG1(DBG_CFG, "remote node drops segment %d", value.u16);
! 949: this->segments->activate(this->segments, value.u16, FALSE);
! 950: }
! 951: break;
! 952: default:
! 953: break;
! 954: }
! 955: }
! 956: enumerator->destroy(enumerator);
! 957: message->destroy(message);
! 958: }
! 959:
! 960: /**
! 961: * Process messages of type STATUS
! 962: */
! 963: static void process_status(private_ha_dispatcher_t *this,
! 964: ha_message_t *message)
! 965: {
! 966: ha_message_attribute_t attribute;
! 967: ha_message_value_t value;
! 968: enumerator_t *enumerator;
! 969: segment_mask_t mask = 0;
! 970:
! 971: enumerator = message->create_attribute_enumerator(message);
! 972: while (enumerator->enumerate(enumerator, &attribute, &value))
! 973: {
! 974: switch (attribute)
! 975: {
! 976: case HA_SEGMENT:
! 977: mask |= SEGMENTS_BIT(value.u16);
! 978: break;
! 979: default:
! 980: break;
! 981: }
! 982: }
! 983: enumerator->destroy(enumerator);
! 984:
! 985: this->segments->handle_status(this->segments, mask);
! 986: message->destroy(message);
! 987: }
! 988:
! 989: /**
! 990: * Process messages of type RESYNC
! 991: */
! 992: static void process_resync(private_ha_dispatcher_t *this,
! 993: ha_message_t *message)
! 994: {
! 995: ha_message_attribute_t attribute;
! 996: ha_message_value_t value;
! 997: enumerator_t *enumerator;
! 998:
! 999: enumerator = message->create_attribute_enumerator(message);
! 1000: while (enumerator->enumerate(enumerator, &attribute, &value))
! 1001: {
! 1002: switch (attribute)
! 1003: {
! 1004: case HA_SEGMENT:
! 1005: this->cache->resync(this->cache, value.u16);
! 1006: break;
! 1007: default:
! 1008: break;
! 1009: }
! 1010: }
! 1011: enumerator->destroy(enumerator);
! 1012: message->destroy(message);
! 1013: }
! 1014:
! 1015: /**
! 1016: * Dispatcher job function
! 1017: */
! 1018: static job_requeue_t dispatch(private_ha_dispatcher_t *this)
! 1019: {
! 1020: ha_message_t *message;
! 1021: ha_message_type_t type;
! 1022:
! 1023: message = this->socket->pull(this->socket);
! 1024: type = message->get_type(message);
! 1025: if (type != HA_STATUS)
! 1026: {
! 1027: DBG2(DBG_CFG, "received HA %N message", ha_message_type_names,
! 1028: message->get_type(message));
! 1029: }
! 1030: switch (type)
! 1031: {
! 1032: case HA_IKE_ADD:
! 1033: process_ike_add(this, message);
! 1034: break;
! 1035: case HA_IKE_UPDATE:
! 1036: process_ike_update(this, message);
! 1037: break;
! 1038: case HA_IKE_MID_INITIATOR:
! 1039: process_ike_mid(this, message, TRUE);
! 1040: break;
! 1041: case HA_IKE_MID_RESPONDER:
! 1042: process_ike_mid(this, message, FALSE);
! 1043: break;
! 1044: case HA_IKE_IV:
! 1045: process_ike_iv(this, message);
! 1046: break;
! 1047: case HA_IKE_DELETE:
! 1048: process_ike_delete(this, message);
! 1049: break;
! 1050: case HA_CHILD_ADD:
! 1051: process_child_add(this, message);
! 1052: break;
! 1053: case HA_CHILD_DELETE:
! 1054: process_child_delete(this, message);
! 1055: break;
! 1056: case HA_SEGMENT_DROP:
! 1057: process_segment(this, message, FALSE);
! 1058: break;
! 1059: case HA_SEGMENT_TAKE:
! 1060: process_segment(this, message, TRUE);
! 1061: break;
! 1062: case HA_STATUS:
! 1063: process_status(this, message);
! 1064: break;
! 1065: case HA_RESYNC:
! 1066: process_resync(this, message);
! 1067: break;
! 1068: default:
! 1069: DBG1(DBG_CFG, "received unknown HA message type %d", type);
! 1070: message->destroy(message);
! 1071: break;
! 1072: }
! 1073: return JOB_REQUEUE_DIRECT;
! 1074: }
! 1075:
! 1076: METHOD(ha_dispatcher_t, destroy, void,
! 1077: private_ha_dispatcher_t *this)
! 1078: {
! 1079: free(this);
! 1080: }
! 1081:
! 1082: /**
! 1083: * See header
! 1084: */
! 1085: ha_dispatcher_t *ha_dispatcher_create(ha_socket_t *socket,
! 1086: ha_segments_t *segments, ha_cache_t *cache,
! 1087: ha_kernel_t *kernel, ha_attribute_t *attr)
! 1088: {
! 1089: private_ha_dispatcher_t *this;
! 1090:
! 1091:
! 1092: INIT(this,
! 1093: .public = {
! 1094: .destroy = _destroy,
! 1095: },
! 1096: .socket = socket,
! 1097: .segments = segments,
! 1098: .cache = cache,
! 1099: .kernel = kernel,
! 1100: .attr = attr,
! 1101: );
! 1102: lib->processor->queue_job(lib->processor,
! 1103: (job_t*)callback_job_create_with_prio((callback_job_cb_t)dispatch, this,
! 1104: NULL, (callback_job_cancel_t)return_false, JOB_PRIO_CRITICAL));
! 1105:
! 1106: return &this->public;
! 1107: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>