Return to ha_ike.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / libcharon / plugins / ha |
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_ike.h" 17: 18: #include <sa/ikev2/keymat_v2.h> 19: #include <sa/ikev1/keymat_v1.h> 20: 21: typedef struct private_ha_ike_t private_ha_ike_t; 22: 23: /** 24: * Private data of an ha_ike_t object. 25: */ 26: struct private_ha_ike_t { 27: 28: /** 29: * Public ha_ike_t interface. 30: */ 31: ha_ike_t public; 32: 33: /** 34: * socket we use for syncing 35: */ 36: ha_socket_t *socket; 37: 38: /** 39: * tunnel securing sync messages 40: */ 41: ha_tunnel_t *tunnel; 42: 43: /** 44: * message cache 45: */ 46: ha_cache_t *cache; 47: }; 48: 49: /** 50: * Return condition if it is set on ike_sa 51: */ 52: static ike_condition_t copy_condition(ike_sa_t *ike_sa, ike_condition_t cond) 53: { 54: if (ike_sa->has_condition(ike_sa, cond)) 55: { 56: return cond; 57: } 58: return 0; 59: } 60: 61: /** 62: * Return extension if it is supported by peers IKE_SA 63: */ 64: static ike_extension_t copy_extension(ike_sa_t *ike_sa, ike_extension_t ext) 65: { 66: if (ike_sa->supports_extension(ike_sa, ext)) 67: { 68: return ext; 69: } 70: return 0; 71: } 72: 73: METHOD(listener_t, ike_keys, bool, 74: private_ha_ike_t *this, ike_sa_t *ike_sa, diffie_hellman_t *dh, 75: chunk_t dh_other, chunk_t nonce_i, chunk_t nonce_r, ike_sa_t *rekey, 76: shared_key_t *shared, auth_method_t method) 77: { 78: ha_message_t *m; 79: chunk_t secret; 80: proposal_t *proposal; 81: uint16_t alg, len; 82: 83: if (this->tunnel && this->tunnel->is_sa(this->tunnel, ike_sa)) 84: { /* do not sync SA between nodes */ 85: return TRUE; 86: } 87: if (!dh->get_shared_secret(dh, &secret)) 88: { 89: return TRUE; 90: } 91: 92: m = ha_message_create(HA_IKE_ADD); 93: m->add_attribute(m, HA_IKE_VERSION, ike_sa->get_version(ike_sa)); 94: m->add_attribute(m, HA_IKE_ID, ike_sa->get_id(ike_sa)); 95: 96: if (rekey && rekey->get_version(rekey) == IKEV2) 97: { 98: chunk_t skd; 99: keymat_v2_t *keymat; 100: 101: keymat = (keymat_v2_t*)rekey->get_keymat(rekey); 102: m->add_attribute(m, HA_IKE_REKEY_ID, rekey->get_id(rekey)); 103: m->add_attribute(m, HA_ALG_OLD_PRF, keymat->get_skd(keymat, &skd)); 104: m->add_attribute(m, HA_OLD_SKD, skd); 105: } 106: 107: proposal = ike_sa->get_proposal(ike_sa); 108: if (proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, &alg, &len)) 109: { 110: m->add_attribute(m, HA_ALG_ENCR, alg); 111: if (len) 112: { 113: m->add_attribute(m, HA_ALG_ENCR_LEN, len); 114: } 115: } 116: if (proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM, &alg, NULL)) 117: { 118: m->add_attribute(m, HA_ALG_INTEG, alg); 119: } 120: if (proposal->get_algorithm(proposal, PSEUDO_RANDOM_FUNCTION, &alg, NULL)) 121: { 122: m->add_attribute(m, HA_ALG_PRF, alg); 123: } 124: if (proposal->get_algorithm(proposal, DIFFIE_HELLMAN_GROUP, &alg, NULL)) 125: { 126: m->add_attribute(m, HA_ALG_DH, alg); 127: } 128: m->add_attribute(m, HA_NONCE_I, nonce_i); 129: m->add_attribute(m, HA_NONCE_R, nonce_r); 130: m->add_attribute(m, HA_SECRET, secret); 131: chunk_clear(&secret); 132: if (ike_sa->get_version(ike_sa) == IKEV1) 133: { 134: if (dh->get_my_public_value(dh, &secret)) 135: { 136: m->add_attribute(m, HA_LOCAL_DH, secret); 137: chunk_free(&secret); 138: } 139: m->add_attribute(m, HA_REMOTE_DH, dh_other); 140: if (shared) 141: { 142: m->add_attribute(m, HA_PSK, shared->get_key(shared)); 143: } 144: else 145: { 146: m->add_attribute(m, HA_AUTH_METHOD, method); 147: } 148: } 149: m->add_attribute(m, HA_REMOTE_ADDR, ike_sa->get_other_host(ike_sa)); 150: 151: this->socket->push(this->socket, m); 152: this->cache->cache(this->cache, ike_sa, m); 153: 154: return TRUE; 155: } 156: 157: METHOD(listener_t, ike_updown, bool, 158: private_ha_ike_t *this, ike_sa_t *ike_sa, bool up) 159: { 160: ha_message_t *m; 161: 162: if (ike_sa->get_state(ike_sa) == IKE_PASSIVE) 163: { /* only sync active IKE_SAs */ 164: return TRUE; 165: } 166: if (this->tunnel && this->tunnel->is_sa(this->tunnel, ike_sa)) 167: { /* do not sync SA between nodes */ 168: return TRUE; 169: } 170: 171: if (up) 172: { 173: enumerator_t *enumerator; 174: peer_cfg_t *peer_cfg; 175: uint32_t extension, condition; 176: host_t *addr; 177: ike_sa_id_t *id; 178: identification_t *eap_id; 179: 180: peer_cfg = ike_sa->get_peer_cfg(ike_sa); 181: 182: condition = copy_condition(ike_sa, COND_NAT_ANY) 183: | copy_condition(ike_sa, COND_NAT_HERE) 184: | copy_condition(ike_sa, COND_NAT_THERE) 185: | copy_condition(ike_sa, COND_NAT_FAKE) 186: | copy_condition(ike_sa, COND_EAP_AUTHENTICATED) 187: | copy_condition(ike_sa, COND_CERTREQ_SEEN) 188: | copy_condition(ike_sa, COND_ORIGINAL_INITIATOR) 189: | copy_condition(ike_sa, COND_STALE) 190: | copy_condition(ike_sa, COND_INIT_CONTACT_SEEN) 191: | copy_condition(ike_sa, COND_XAUTH_AUTHENTICATED); 192: 193: extension = copy_extension(ike_sa, EXT_NATT) 194: | copy_extension(ike_sa, EXT_MOBIKE) 195: | copy_extension(ike_sa, EXT_HASH_AND_URL) 196: | copy_extension(ike_sa, EXT_MULTIPLE_AUTH) 197: | copy_extension(ike_sa, EXT_STRONGSWAN) 198: | copy_extension(ike_sa, EXT_EAP_ONLY_AUTHENTICATION) 199: | copy_extension(ike_sa, EXT_MS_WINDOWS) 200: | copy_extension(ike_sa, EXT_XAUTH) 201: | copy_extension(ike_sa, EXT_DPD); 202: 203: id = ike_sa->get_id(ike_sa); 204: 205: m = ha_message_create(HA_IKE_UPDATE); 206: m->add_attribute(m, HA_IKE_ID, id); 207: m->add_attribute(m, HA_LOCAL_ID, ike_sa->get_my_id(ike_sa)); 208: m->add_attribute(m, HA_REMOTE_ID, ike_sa->get_other_id(ike_sa)); 209: eap_id = ike_sa->get_other_eap_id(ike_sa); 210: if (!eap_id->equals(eap_id, ike_sa->get_other_id(ike_sa))) 211: { 212: m->add_attribute(m, HA_REMOTE_EAP_ID, eap_id); 213: } 214: m->add_attribute(m, HA_LOCAL_ADDR, ike_sa->get_my_host(ike_sa)); 215: m->add_attribute(m, HA_REMOTE_ADDR, ike_sa->get_other_host(ike_sa)); 216: m->add_attribute(m, HA_CONDITIONS, condition); 217: m->add_attribute(m, HA_EXTENSIONS, extension); 218: m->add_attribute(m, HA_CONFIG_NAME, peer_cfg->get_name(peer_cfg)); 219: enumerator = ike_sa->create_peer_address_enumerator(ike_sa); 220: while (enumerator->enumerate(enumerator, (void**)&addr)) 221: { 222: m->add_attribute(m, HA_PEER_ADDR, addr); 223: } 224: enumerator->destroy(enumerator); 225: } 226: else 227: { 228: m = ha_message_create(HA_IKE_DELETE); 229: m->add_attribute(m, HA_IKE_ID, ike_sa->get_id(ike_sa)); 230: } 231: this->socket->push(this->socket, m); 232: this->cache->cache(this->cache, ike_sa, m); 233: return TRUE; 234: } 235: 236: METHOD(listener_t, ike_rekey, bool, 237: private_ha_ike_t *this, ike_sa_t *old, ike_sa_t *new) 238: { 239: ike_updown(this, old, FALSE); 240: ike_updown(this, new, TRUE); 241: return TRUE; 242: } 243: 244: METHOD(listener_t, alert, bool, 245: private_ha_ike_t *this, ike_sa_t *ike_sa, alert_t alert, va_list args) 246: { 247: switch (alert) 248: { 249: case ALERT_HALF_OPEN_TIMEOUT: 250: ike_updown(this, ike_sa, FALSE); 251: break; 252: default: 253: break; 254: } 255: return TRUE; 256: } 257: 258: METHOD(listener_t, ike_state_change, bool, 259: private_ha_ike_t *this, ike_sa_t *ike_sa, ike_sa_state_t new) 260: { 261: /* delete any remaining cache entry if IKE_SA gets destroyed */ 262: if (new == IKE_DESTROYING) 263: { 264: this->cache->delete(this->cache, ike_sa); 265: } 266: return TRUE; 267: } 268: 269: /** 270: * Send a virtual IP sync message for remote VIPs 271: */ 272: static void sync_vips(private_ha_ike_t *this, ike_sa_t *ike_sa) 273: { 274: ha_message_t *m = NULL; 275: enumerator_t *enumerator; 276: host_t *vip; 277: 278: enumerator = ike_sa->create_virtual_ip_enumerator(ike_sa, FALSE); 279: while (enumerator->enumerate(enumerator, &vip)) 280: { 281: if (!m) 282: { 283: m = ha_message_create(HA_IKE_UPDATE); 284: m->add_attribute(m, HA_IKE_ID, ike_sa->get_id(ike_sa)); 285: } 286: m->add_attribute(m, HA_REMOTE_VIP, vip); 287: } 288: enumerator->destroy(enumerator); 289: 290: if (m) 291: { 292: this->socket->push(this->socket, m); 293: this->cache->cache(this->cache, ike_sa, m); 294: } 295: } 296: 297: METHOD(listener_t, message_hook, bool, 298: private_ha_ike_t *this, ike_sa_t *ike_sa, message_t *message, 299: bool incoming, bool plain) 300: { 301: if (this->tunnel && this->tunnel->is_sa(this->tunnel, ike_sa)) 302: { /* do not sync SA between nodes */ 303: return TRUE; 304: } 305: 306: if (plain && ike_sa->get_version(ike_sa) == IKEV2) 307: { 308: if (message->get_exchange_type(message) != IKE_SA_INIT && 309: message->get_request(message)) 310: { /* we sync on requests, but skip it on IKE_SA_INIT */ 311: ha_message_t *m; 312: 313: if (incoming) 314: { 315: m = ha_message_create(HA_IKE_MID_RESPONDER); 316: } 317: else 318: { 319: m = ha_message_create(HA_IKE_MID_INITIATOR); 320: } 321: m->add_attribute(m, HA_IKE_ID, ike_sa->get_id(ike_sa)); 322: m->add_attribute(m, HA_MID, message->get_message_id(message) + 1); 323: this->socket->push(this->socket, m); 324: this->cache->cache(this->cache, ike_sa, m); 325: } 326: if (ike_sa->get_state(ike_sa) == IKE_ESTABLISHED && 327: message->get_exchange_type(message) == IKE_AUTH && 328: !message->get_request(message)) 329: { /* After IKE_SA has been established, sync peers virtual IP. 330: * We cannot sync it in the state_change hook, it is installed later. 331: * TODO: where to sync local VIP? */ 332: sync_vips(this, ike_sa); 333: } 334: } 335: if (ike_sa->get_version(ike_sa) == IKEV1) 336: { 337: ha_message_t *m; 338: keymat_v1_t *keymat; 339: chunk_t iv; 340: 341: /* we need the last block (or expected next IV) of Phase 1, which gets 342: * updated after successful en-/decryption depending on direction */ 343: if (incoming == plain) 344: { 345: if (message->get_message_id(message) == 0) 346: { 347: keymat = (keymat_v1_t*)ike_sa->get_keymat(ike_sa); 348: if (keymat->get_iv(keymat, 0, &iv)) 349: { 350: m = ha_message_create(HA_IKE_IV); 351: m->add_attribute(m, HA_IKE_ID, ike_sa->get_id(ike_sa)); 352: m->add_attribute(m, HA_IV, iv); 353: this->socket->push(this->socket, m); 354: this->cache->cache(this->cache, ike_sa, m); 355: } 356: } 357: } 358: if (!plain && !incoming && 359: message->get_exchange_type(message) == TRANSACTION) 360: { 361: sync_vips(this, ike_sa); 362: } 363: } 364: if (plain && ike_sa->get_version(ike_sa) == IKEV1 && 365: message->get_exchange_type(message) == INFORMATIONAL_V1) 366: { 367: ha_message_t *m; 368: notify_payload_t *notify; 369: chunk_t data; 370: uint32_t seq; 371: 372: notify = message->get_notify(message, DPD_R_U_THERE); 373: if (notify) 374: { 375: data = notify->get_notification_data(notify); 376: if (data.len == 4) 377: { 378: seq = untoh32(data.ptr); 379: if (incoming) 380: { 381: m = ha_message_create(HA_IKE_MID_RESPONDER); 382: } 383: else 384: { 385: m = ha_message_create(HA_IKE_MID_INITIATOR); 386: } 387: m->add_attribute(m, HA_IKE_ID, ike_sa->get_id(ike_sa)); 388: m->add_attribute(m, HA_MID, seq + 1); 389: this->socket->push(this->socket, m); 390: this->cache->cache(this->cache, ike_sa, m); 391: } 392: } 393: } 394: return TRUE; 395: } 396: 397: METHOD(ha_ike_t, destroy, void, 398: private_ha_ike_t *this) 399: { 400: free(this); 401: } 402: 403: /** 404: * See header 405: */ 406: ha_ike_t *ha_ike_create(ha_socket_t *socket, ha_tunnel_t *tunnel, 407: ha_cache_t *cache) 408: { 409: private_ha_ike_t *this; 410: 411: INIT(this, 412: .public = { 413: .listener = { 414: .alert = _alert, 415: .ike_keys = _ike_keys, 416: .ike_updown = _ike_updown, 417: .ike_rekey = _ike_rekey, 418: .ike_state_change = _ike_state_change, 419: .message = _message_hook, 420: }, 421: .destroy = _destroy, 422: }, 423: .socket = socket, 424: .tunnel = tunnel, 425: .cache = cache, 426: ); 427: 428: return &this->public; 429: } 430: