Annotation of embedaddon/strongswan/src/libcharon/plugins/ha/ha_cache.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2010 Martin Willi
! 3: * Copyright (C) 2010 revosec AG
! 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_cache.h"
! 17:
! 18: #include <collections/hashtable.h>
! 19: #include <collections/linked_list.h>
! 20: #include <threading/mutex.h>
! 21: #include <processing/jobs/callback_job.h>
! 22:
! 23: typedef struct private_ha_cache_t private_ha_cache_t;
! 24:
! 25: /**
! 26: * Private data of an ha_cache_t object.
! 27: */
! 28: struct private_ha_cache_t {
! 29:
! 30: /**
! 31: * Public ha_cache_t interface.
! 32: */
! 33: ha_cache_t public;
! 34:
! 35: /**
! 36: * Kernel helper functions
! 37: */
! 38: ha_kernel_t *kernel;
! 39:
! 40: /**
! 41: * Socket to send sync messages over
! 42: */
! 43: ha_socket_t *socket;
! 44:
! 45: /**
! 46: * Tunnel securing sync messages
! 47: */
! 48: ha_tunnel_t *tunnel;
! 49:
! 50: /**
! 51: * Total number of segments
! 52: */
! 53: u_int count;
! 54:
! 55: /**
! 56: * cached entries (ike_sa_t, entry_t)
! 57: */
! 58: hashtable_t *cache;
! 59:
! 60: /**
! 61: * Mutex to lock cache
! 62: */
! 63: mutex_t *mutex;
! 64: };
! 65:
! 66: /**
! 67: * Cache entry for an IKE_SA
! 68: */
! 69: typedef struct {
! 70: /* segment this entry is associate to */
! 71: u_int segment;
! 72: /* ADD message */
! 73: ha_message_t *add;
! 74: /* list of updates UPDATE message */
! 75: linked_list_t *updates;
! 76: /* last initiator mid */
! 77: ha_message_t *midi;
! 78: /* last responder mid */
! 79: ha_message_t *midr;
! 80: /* last IV update */
! 81: ha_message_t *iv;
! 82: } entry_t;
! 83:
! 84: /**
! 85: * Create a entry with an add message
! 86: */
! 87: static entry_t *entry_create(ha_message_t *add)
! 88: {
! 89: entry_t *entry;
! 90:
! 91: INIT(entry,
! 92: .add = add,
! 93: .updates = linked_list_create(),
! 94: );
! 95: return entry;
! 96: }
! 97:
! 98: /**
! 99: * clean up a entry
! 100: */
! 101: static void entry_destroy(entry_t *entry)
! 102: {
! 103: entry->updates->destroy_offset(entry->updates,
! 104: offsetof(ha_message_t, destroy));
! 105: entry->add->destroy(entry->add);
! 106: DESTROY_IF(entry->midi);
! 107: DESTROY_IF(entry->midr);
! 108: DESTROY_IF(entry->iv);
! 109: free(entry);
! 110: }
! 111:
! 112: METHOD(ha_cache_t, cache, void,
! 113: private_ha_cache_t *this, ike_sa_t *ike_sa, ha_message_t *message)
! 114: {
! 115: entry_t *entry;
! 116:
! 117: this->mutex->lock(this->mutex);
! 118: switch (message->get_type(message))
! 119: {
! 120: case HA_IKE_ADD:
! 121: entry = entry_create(message);
! 122: entry = this->cache->put(this->cache, ike_sa, entry);
! 123: if (entry)
! 124: {
! 125: entry_destroy(entry);
! 126: }
! 127: break;
! 128: case HA_IKE_UPDATE:
! 129: entry = this->cache->get(this->cache, ike_sa);
! 130: if (entry)
! 131: {
! 132: entry->segment = this->kernel->get_segment(this->kernel,
! 133: ike_sa->get_other_host(ike_sa));
! 134: entry->updates->insert_last(entry->updates, message);
! 135: break;
! 136: }
! 137: message->destroy(message);
! 138: break;
! 139: case HA_IKE_MID_INITIATOR:
! 140: entry = this->cache->get(this->cache, ike_sa);
! 141: if (entry)
! 142: {
! 143: DESTROY_IF(entry->midi);
! 144: entry->midi = message;
! 145: break;
! 146: }
! 147: message->destroy(message);
! 148: break;
! 149: case HA_IKE_MID_RESPONDER:
! 150: entry = this->cache->get(this->cache, ike_sa);
! 151: if (entry)
! 152: {
! 153: DESTROY_IF(entry->midr);
! 154: entry->midr = message;
! 155: break;
! 156: }
! 157: message->destroy(message);
! 158: break;
! 159: case HA_IKE_IV:
! 160: entry = this->cache->get(this->cache, ike_sa);
! 161: if (entry)
! 162: {
! 163: DESTROY_IF(entry->iv);
! 164: entry->iv = message;
! 165: break;
! 166: }
! 167: message->destroy(message);
! 168: break;
! 169: case HA_IKE_DELETE:
! 170: entry = this->cache->remove(this->cache, ike_sa);
! 171: if (entry)
! 172: {
! 173: entry_destroy(entry);
! 174: }
! 175: message->destroy(message);
! 176: break;
! 177: default:
! 178: message->destroy(message);
! 179: break;
! 180: }
! 181: this->mutex->unlock(this->mutex);
! 182: }
! 183:
! 184: METHOD(ha_cache_t, delete_, void,
! 185: private_ha_cache_t *this, ike_sa_t *ike_sa)
! 186: {
! 187: entry_t *entry;
! 188:
! 189: this->mutex->lock(this->mutex);
! 190: entry = this->cache->remove(this->cache, ike_sa);
! 191: if (entry)
! 192: {
! 193: entry_destroy(entry);
! 194: }
! 195: this->mutex->unlock(this->mutex);
! 196: }
! 197:
! 198: /**
! 199: * Rekey all children of an IKE_SA
! 200: */
! 201: static status_t rekey_children(ike_sa_t *ike_sa)
! 202: {
! 203: enumerator_t *enumerator;
! 204: child_sa_t *child_sa;
! 205: status_t status = SUCCESS;
! 206: linked_list_t *children;
! 207: struct {
! 208: protocol_id_t protocol;
! 209: uint32_t spi;
! 210: } *info;
! 211:
! 212: children = linked_list_create();
! 213: enumerator = ike_sa->create_child_sa_enumerator(ike_sa);
! 214: while (enumerator->enumerate(enumerator, &child_sa))
! 215: {
! 216: INIT(info,
! 217: .protocol = child_sa->get_protocol(child_sa),
! 218: .spi = child_sa->get_spi(child_sa, TRUE),
! 219: );
! 220: children->insert_last(children, info);
! 221: }
! 222: enumerator->destroy(enumerator);
! 223:
! 224: enumerator = children->create_enumerator(children);
! 225: while (enumerator->enumerate(enumerator, &info))
! 226: {
! 227: if (ike_sa->supports_extension(ike_sa, EXT_MS_WINDOWS) &&
! 228: ike_sa->has_condition(ike_sa, COND_NAT_THERE))
! 229: {
! 230: /* NATed Windows clients don't accept CHILD_SA rekeying, but fail
! 231: * with an "invalid situation" error. We just close the CHILD_SA,
! 232: * Windows will reestablish it immediately if required. */
! 233: DBG1(DBG_CFG, "resyncing CHILD_SA using a delete");
! 234: status = ike_sa->delete_child_sa(ike_sa, info->protocol, info->spi,
! 235: FALSE);
! 236: }
! 237: else
! 238: {
! 239: DBG1(DBG_CFG, "resyncing CHILD_SA using a rekey");
! 240: status = ike_sa->rekey_child_sa(ike_sa, info->protocol, info->spi);
! 241: }
! 242: if (status == DESTROY_ME)
! 243: {
! 244: break;
! 245: }
! 246: }
! 247: enumerator->destroy(enumerator);
! 248: children->destroy_function(children, free);
! 249:
! 250: return status;
! 251: }
! 252:
! 253: /**
! 254: * Trigger rekeying of CHILD_SA in segment
! 255: */
! 256: static void rekey_segment(private_ha_cache_t *this, u_int segment)
! 257: {
! 258: ike_sa_t *ike_sa;
! 259: enumerator_t *enumerator;
! 260: linked_list_t *list;
! 261: ike_sa_id_t *id;
! 262:
! 263: list = linked_list_create();
! 264:
! 265: enumerator = charon->ike_sa_manager->create_enumerator(
! 266: charon->ike_sa_manager, TRUE);
! 267: while (enumerator->enumerate(enumerator, &ike_sa))
! 268: {
! 269: if (this->tunnel && this->tunnel->is_sa(this->tunnel, ike_sa))
! 270: {
! 271: continue;
! 272: }
! 273: if (ike_sa->get_state(ike_sa) == IKE_ESTABLISHED &&
! 274: this->kernel->get_segment(this->kernel,
! 275: ike_sa->get_other_host(ike_sa)) == segment)
! 276: {
! 277: id = ike_sa->get_id(ike_sa);
! 278: list->insert_last(list, id->clone(id));
! 279: }
! 280: }
! 281: enumerator->destroy(enumerator);
! 282:
! 283: while (list->remove_last(list, (void**)&id) == SUCCESS)
! 284: {
! 285: ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, id);
! 286: if (ike_sa)
! 287: {
! 288: if (rekey_children(ike_sa) != DESTROY_ME)
! 289: {
! 290: charon->ike_sa_manager->checkin(
! 291: charon->ike_sa_manager, ike_sa);
! 292: }
! 293: else
! 294: {
! 295: charon->ike_sa_manager->checkin_and_destroy(
! 296: charon->ike_sa_manager, ike_sa);
! 297: }
! 298: }
! 299: id->destroy(id);
! 300: }
! 301: list->destroy(list);
! 302: }
! 303:
! 304: METHOD(ha_cache_t, resync, void,
! 305: private_ha_cache_t *this, u_int segment)
! 306: {
! 307: enumerator_t *enumerator, *updates;
! 308: ike_sa_t *ike_sa;
! 309: entry_t *entry;
! 310: ha_message_t *message;
! 311:
! 312: DBG1(DBG_CFG, "resyncing HA segment %d", segment);
! 313:
! 314: this->mutex->lock(this->mutex);
! 315: enumerator = this->cache->create_enumerator(this->cache);
! 316: while (enumerator->enumerate(enumerator, &ike_sa, &entry))
! 317: {
! 318: if (entry->segment == segment)
! 319: {
! 320: this->socket->push(this->socket, entry->add);
! 321: updates = entry->updates->create_enumerator(entry->updates);
! 322: while (updates->enumerate(updates, &message))
! 323: {
! 324: this->socket->push(this->socket, message);
! 325: }
! 326: updates->destroy(updates);
! 327: if (entry->midi)
! 328: {
! 329: this->socket->push(this->socket, entry->midi);
! 330: }
! 331: if (entry->midr)
! 332: {
! 333: this->socket->push(this->socket, entry->midr);
! 334: }
! 335: if (entry->iv)
! 336: {
! 337: this->socket->push(this->socket, entry->iv);
! 338: }
! 339: }
! 340: }
! 341: enumerator->destroy(enumerator);
! 342: this->mutex->unlock(this->mutex);
! 343:
! 344: rekey_segment(this, segment);
! 345: }
! 346:
! 347: /**
! 348: * Request a resync of all segments
! 349: */
! 350: static job_requeue_t request_resync(private_ha_cache_t *this)
! 351: {
! 352: ha_message_t *message;
! 353: int i;
! 354:
! 355: DBG1(DBG_CFG, "requesting HA resynchronization");
! 356:
! 357: message = ha_message_create(HA_RESYNC);
! 358: for (i = 1; i <= this->count; i++)
! 359: {
! 360: message->add_attribute(message, HA_SEGMENT, i);
! 361: }
! 362: this->socket->push(this->socket, message);
! 363: message->destroy(message);
! 364: return JOB_REQUEUE_NONE;
! 365: }
! 366:
! 367: METHOD(ha_cache_t, destroy, void,
! 368: private_ha_cache_t *this)
! 369: {
! 370: this->cache->destroy(this->cache);
! 371: this->mutex->destroy(this->mutex);
! 372: free(this);
! 373: }
! 374:
! 375: /**
! 376: * See header
! 377: */
! 378: ha_cache_t *ha_cache_create(ha_kernel_t *kernel, ha_socket_t *socket,
! 379: ha_tunnel_t *tunnel, bool sync, u_int count)
! 380: {
! 381: private_ha_cache_t *this;
! 382:
! 383: INIT(this,
! 384: .public = {
! 385: .cache = _cache,
! 386: .delete = _delete_,
! 387: .resync = _resync,
! 388: .destroy = _destroy,
! 389: },
! 390: .count = count,
! 391: .kernel = kernel,
! 392: .socket = socket,
! 393: .tunnel = tunnel,
! 394: .cache = hashtable_create(hashtable_hash_ptr, hashtable_equals_ptr, 8),
! 395: .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
! 396: );
! 397:
! 398: if (sync)
! 399: {
! 400: /* request a resync as soon as we are up */
! 401: lib->scheduler->schedule_job(lib->scheduler, (job_t*)
! 402: callback_job_create_with_prio((callback_job_cb_t)request_resync,
! 403: this, NULL, NULL, JOB_PRIO_CRITICAL), 1);
! 404: }
! 405: return &this->public;
! 406: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>