Annotation of embedaddon/strongswan/src/libcharon/plugins/duplicheck/duplicheck_listener.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2011 Martin Willi
! 3: * Copyright (C) 2011 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 "duplicheck_listener.h"
! 17:
! 18: #include <daemon.h>
! 19: #include <threading/mutex.h>
! 20: #include <collections/hashtable.h>
! 21: #include <encoding/payloads/delete_payload.h>
! 22: #include <processing/jobs/delete_ike_sa_job.h>
! 23:
! 24: typedef struct private_duplicheck_listener_t private_duplicheck_listener_t;
! 25:
! 26: /**
! 27: * Private data of an duplicheck_listener_t object.
! 28: */
! 29: struct private_duplicheck_listener_t {
! 30:
! 31: /**
! 32: * Public duplicheck_listener_t interface.
! 33: */
! 34: duplicheck_listener_t public;
! 35:
! 36: /**
! 37: * Socket to send notifications to
! 38: */
! 39: duplicheck_notify_t *notify;
! 40:
! 41: /**
! 42: * Mutex to lock hashtables
! 43: */
! 44: mutex_t *mutex;
! 45:
! 46: /**
! 47: * Hashtable of active IKE_SAs, identification_t => entry_t
! 48: */
! 49: hashtable_t *active;
! 50:
! 51: /**
! 52: * Hashtable with active liveness checks, identification_t => entry_t
! 53: */
! 54: hashtable_t *checking;
! 55: };
! 56:
! 57: /**
! 58: * Entry for hashtables
! 59: */
! 60: typedef struct {
! 61: /** peer identity */
! 62: identification_t *id;
! 63: /** list of IKE_SA identifiers, ike_sa_id_t */
! 64: linked_list_t *sas;
! 65: } entry_t;
! 66:
! 67: /**
! 68: * Destroy a hashtable entry
! 69: */
! 70: static void entry_destroy(entry_t *this)
! 71: {
! 72: this->id->destroy(this->id);
! 73: this->sas->destroy_offset(this->sas, offsetof(ike_sa_id_t, destroy));
! 74: free(this);
! 75: }
! 76:
! 77: /**
! 78: * Hashtable hash function
! 79: */
! 80: static u_int hash(identification_t *key)
! 81: {
! 82: return chunk_hash(key->get_encoding(key));
! 83: }
! 84:
! 85: /**
! 86: * Hashtable equals function
! 87: */
! 88: static bool equals(identification_t *a, identification_t *b)
! 89: {
! 90: return a->equals(a, b);
! 91: }
! 92:
! 93: /**
! 94: * Put an IKE_SA identifier to hashtable
! 95: */
! 96: static void put(hashtable_t *table, identification_t *id, ike_sa_id_t *sa)
! 97: {
! 98: entry_t *entry;
! 99:
! 100: entry = table->get(table, id);
! 101: if (!entry)
! 102: {
! 103: INIT(entry,
! 104: .id = id->clone(id),
! 105: .sas = linked_list_create(),
! 106: );
! 107: table->put(table, entry->id, entry);
! 108: }
! 109: entry->sas->insert_last(entry->sas, sa->clone(sa));
! 110: }
! 111:
! 112: /**
! 113: * Purge an entry from table if it has no IKE_SA identifiers
! 114: */
! 115: static void remove_if_empty(hashtable_t *table, entry_t *entry)
! 116: {
! 117: if (entry->sas->get_count(entry->sas) == 0)
! 118: {
! 119: entry = table->remove(table, entry->id);
! 120: if (entry)
! 121: {
! 122: entry_destroy(entry);
! 123: }
! 124: }
! 125: }
! 126:
! 127: /**
! 128: * Remove the first entry found in the table for the given id
! 129: */
! 130: static ike_sa_id_t *remove_first(hashtable_t *table, identification_t *id)
! 131: {
! 132: ike_sa_id_t *sa = NULL;
! 133: entry_t *entry;
! 134:
! 135: entry = table->get(table, id);
! 136: if (entry)
! 137: {
! 138: entry->sas->remove_first(entry->sas, (void**)&sa);
! 139: remove_if_empty(table, entry);
! 140: }
! 141: return sa;
! 142: }
! 143:
! 144: /**
! 145: * Remove a specific IKE_SA ID for the given identity
! 146: */
! 147: static bool remove_specific(hashtable_t *table, identification_t *id,
! 148: ike_sa_id_t *sa)
! 149: {
! 150: enumerator_t *enumerator;
! 151: bool found = FALSE;
! 152: entry_t *entry;
! 153: ike_sa_id_t *current;
! 154:
! 155: entry = table->get(table, id);
! 156: if (entry)
! 157: {
! 158: enumerator = entry->sas->create_enumerator(entry->sas);
! 159: while (enumerator->enumerate(enumerator, ¤t))
! 160: {
! 161: if (sa->equals(sa, current))
! 162: {
! 163: entry->sas->remove_at(entry->sas, enumerator);
! 164: current->destroy(current);
! 165: found = TRUE;
! 166: break;
! 167: }
! 168: }
! 169: enumerator->destroy(enumerator);
! 170: if (found)
! 171: {
! 172: remove_if_empty(table, entry);
! 173: }
! 174: }
! 175: return found;
! 176: }
! 177:
! 178: METHOD(listener_t, ike_rekey, bool,
! 179: private_duplicheck_listener_t *this, ike_sa_t *old, ike_sa_t *new)
! 180: {
! 181: this->mutex->lock(this->mutex);
! 182:
! 183: remove_specific(this->active, old->get_other_id(old), old->get_id(old));
! 184: put(this->active, new->get_other_id(new), new->get_id(new));
! 185:
! 186: this->mutex->unlock(this->mutex);
! 187:
! 188: return TRUE;
! 189: }
! 190:
! 191: METHOD(listener_t, ike_updown, bool,
! 192: private_duplicheck_listener_t *this, ike_sa_t *ike_sa, bool up)
! 193: {
! 194: identification_t *id;
! 195: ike_sa_id_t *sa;
! 196:
! 197: id = ike_sa->get_other_id(ike_sa);
! 198:
! 199: this->mutex->lock(this->mutex);
! 200: if (up)
! 201: {
! 202: /* another IKE_SA for this identity active? */
! 203: sa = remove_first(this->active, id);
! 204: if (sa)
! 205: {
! 206: DBG1(DBG_CFG, "detected duplicate IKE_SA for '%Y', "
! 207: "triggering delete for old IKE_SA", id);
! 208: put(this->checking, id, sa);
! 209: lib->processor->queue_job(lib->processor,
! 210: (job_t*)delete_ike_sa_job_create(sa, TRUE));
! 211: sa->destroy(sa);
! 212: }
! 213: /* register IKE_SA as the new active */
! 214: sa = ike_sa->get_id(ike_sa);
! 215: put(this->active, id, sa);
! 216: }
! 217: else
! 218: {
! 219: sa = ike_sa->get_id(ike_sa);
! 220: /* check if closing an IKE_SA currently in checking state */
! 221: if (remove_specific(this->checking, id, sa))
! 222: {
! 223: DBG1(DBG_CFG, "delete for duplicate IKE_SA '%Y' timed out, "
! 224: "keeping new IKE_SA", id);
! 225: }
! 226: /* check normal close of IKE_SA */
! 227: remove_specific(this->active, id, sa);
! 228: }
! 229: this->mutex->unlock(this->mutex);
! 230:
! 231: return TRUE;
! 232: }
! 233:
! 234: METHOD(listener_t, message_hook, bool,
! 235: private_duplicheck_listener_t *this, ike_sa_t *ike_sa,
! 236: message_t *message, bool incoming, bool plain)
! 237: {
! 238: if (incoming && plain && !message->get_request(message))
! 239: {
! 240: identification_t *id;
! 241: ike_sa_id_t *sa;
! 242:
! 243: id = ike_sa->get_other_id(ike_sa);
! 244: sa = ike_sa->get_id(ike_sa);
! 245:
! 246: this->mutex->lock(this->mutex);
! 247: if (remove_specific(this->checking, id, sa))
! 248: {
! 249: DBG1(DBG_CFG, "got a response on a duplicate IKE_SA for '%Y', "
! 250: "deleting new IKE_SA", id);
! 251: charon->bus->alert(charon->bus, ALERT_UNIQUE_KEEP);
! 252: sa = remove_first(this->active, id);
! 253: if (sa)
! 254: {
! 255: lib->processor->queue_job(lib->processor,
! 256: (job_t*)delete_ike_sa_job_create(sa, TRUE));
! 257: sa->destroy(sa);
! 258: }
! 259: this->mutex->unlock(this->mutex);
! 260:
! 261: this->notify->send(this->notify, id);
! 262: }
! 263: else
! 264: {
! 265: this->mutex->unlock(this->mutex);
! 266: }
! 267: }
! 268: return TRUE;
! 269: }
! 270:
! 271: METHOD(duplicheck_listener_t, destroy, void,
! 272: private_duplicheck_listener_t *this)
! 273: {
! 274: enumerator_t *enumerator;
! 275: identification_t *key;
! 276: entry_t *value;
! 277:
! 278: enumerator = this->active->create_enumerator(this->active);
! 279: while (enumerator->enumerate(enumerator, &key, &value))
! 280: {
! 281: entry_destroy(value);
! 282: }
! 283: enumerator->destroy(enumerator);
! 284:
! 285: enumerator = this->checking->create_enumerator(this->checking);
! 286: while (enumerator->enumerate(enumerator, &key, &value))
! 287: {
! 288: entry_destroy(value);
! 289: }
! 290: enumerator->destroy(enumerator);
! 291:
! 292: this->active->destroy(this->active);
! 293: this->checking->destroy(this->checking);
! 294: this->mutex->destroy(this->mutex);
! 295: free(this);
! 296: }
! 297:
! 298: /**
! 299: * See header
! 300: */
! 301: duplicheck_listener_t *duplicheck_listener_create(duplicheck_notify_t *notify)
! 302: {
! 303: private_duplicheck_listener_t *this;
! 304:
! 305: INIT(this,
! 306: .public = {
! 307: .listener = {
! 308: .ike_rekey = _ike_rekey,
! 309: .ike_updown = _ike_updown,
! 310: .message = _message_hook,
! 311: },
! 312: .destroy = _destroy,
! 313: },
! 314: .notify = notify,
! 315: .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
! 316: .active = hashtable_create((hashtable_hash_t)hash,
! 317: (hashtable_equals_t)equals, 32),
! 318: .checking = hashtable_create((hashtable_hash_t)hash,
! 319: (hashtable_equals_t)equals, 2),
! 320: );
! 321:
! 322: return &this->public;
! 323: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>