Annotation of embedaddon/strongswan/src/libcharon/sa/ike_sa_manager.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2005-2011 Martin Willi
! 3: * Copyright (C) 2011 revosec AG
! 4: *
! 5: * Copyright (C) 2008-2018 Tobias Brunner
! 6: * Copyright (C) 2005 Jan Hutter
! 7: * HSR Hochschule fuer Technik Rapperswil
! 8: *
! 9: * This program is free software; you can redistribute it and/or modify it
! 10: * under the terms of the GNU General Public License as published by the
! 11: * Free Software Foundation; either version 2 of the License, or (at your
! 12: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
! 13: *
! 14: * This program is distributed in the hope that it will be useful, but
! 15: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
! 16: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
! 17: * for more details.
! 18: */
! 19:
! 20: #include <string.h>
! 21: #include <inttypes.h>
! 22:
! 23: #include "ike_sa_manager.h"
! 24:
! 25: #include <daemon.h>
! 26: #include <sa/ike_sa_id.h>
! 27: #include <bus/bus.h>
! 28: #include <threading/thread.h>
! 29: #include <threading/condvar.h>
! 30: #include <threading/mutex.h>
! 31: #include <threading/rwlock.h>
! 32: #include <collections/linked_list.h>
! 33: #include <crypto/hashers/hasher.h>
! 34: #include <processing/jobs/delete_ike_sa_job.h>
! 35:
! 36: /* the default size of the hash table (MUST be a power of 2) */
! 37: #define DEFAULT_HASHTABLE_SIZE 1
! 38:
! 39: /* the maximum size of the hash table (MUST be a power of 2) */
! 40: #define MAX_HASHTABLE_SIZE (1 << 30)
! 41:
! 42: /* the default number of segments (MUST be a power of 2) */
! 43: #define DEFAULT_SEGMENT_COUNT 1
! 44:
! 45: typedef struct entry_t entry_t;
! 46:
! 47: /**
! 48: * An entry in the linked list, contains IKE_SA, locking and lookup data.
! 49: */
! 50: struct entry_t {
! 51:
! 52: /**
! 53: * Number of threads waiting for this ike_sa_t object.
! 54: */
! 55: int waiting_threads;
! 56:
! 57: /**
! 58: * Condvar where threads can wait until ike_sa_t object is free for use again.
! 59: */
! 60: condvar_t *condvar;
! 61:
! 62: /**
! 63: * Thread by which this IKE_SA is currently checked out, if any
! 64: */
! 65: thread_t *checked_out;
! 66:
! 67: /**
! 68: * Does this SA drives out new threads?
! 69: */
! 70: bool driveout_new_threads;
! 71:
! 72: /**
! 73: * Does this SA drives out waiting threads?
! 74: */
! 75: bool driveout_waiting_threads;
! 76:
! 77: /**
! 78: * Identification of an IKE_SA (SPIs).
! 79: */
! 80: ike_sa_id_t *ike_sa_id;
! 81:
! 82: /**
! 83: * The contained ike_sa_t object.
! 84: */
! 85: ike_sa_t *ike_sa;
! 86:
! 87: /**
! 88: * hash of the IKE_SA_INIT message, used to detect retransmissions
! 89: */
! 90: chunk_t init_hash;
! 91:
! 92: /**
! 93: * remote host address, required for DoS detection and duplicate
! 94: * checking (host with same my_id and other_id is *not* considered
! 95: * a duplicate if the address family differs)
! 96: */
! 97: host_t *other;
! 98:
! 99: /**
! 100: * As responder: Is this SA half-open?
! 101: */
! 102: bool half_open;
! 103:
! 104: /**
! 105: * own identity, required for duplicate checking
! 106: */
! 107: identification_t *my_id;
! 108:
! 109: /**
! 110: * remote identity, required for duplicate checking
! 111: */
! 112: identification_t *other_id;
! 113:
! 114: /**
! 115: * message ID or hash of currently processing message, -1 if none
! 116: */
! 117: uint32_t processing;
! 118: };
! 119:
! 120: /**
! 121: * Implementation of entry_t.destroy.
! 122: */
! 123: static status_t entry_destroy(entry_t *this)
! 124: {
! 125: /* also destroy IKE SA */
! 126: this->ike_sa->destroy(this->ike_sa);
! 127: this->ike_sa_id->destroy(this->ike_sa_id);
! 128: chunk_free(&this->init_hash);
! 129: DESTROY_IF(this->other);
! 130: DESTROY_IF(this->my_id);
! 131: DESTROY_IF(this->other_id);
! 132: this->condvar->destroy(this->condvar);
! 133: free(this);
! 134: return SUCCESS;
! 135: }
! 136:
! 137: /**
! 138: * Creates a new entry for the ike_sa_t list.
! 139: */
! 140: static entry_t *entry_create()
! 141: {
! 142: entry_t *this;
! 143:
! 144: INIT(this,
! 145: .condvar = condvar_create(CONDVAR_TYPE_DEFAULT),
! 146: .processing = -1,
! 147: );
! 148:
! 149: return this;
! 150: }
! 151:
! 152: /**
! 153: * Function that matches entry_t objects by ike_sa_id_t.
! 154: */
! 155: static bool entry_match_by_id(entry_t *entry, void *arg)
! 156: {
! 157: ike_sa_id_t *id = arg;
! 158:
! 159: if (id->equals(id, entry->ike_sa_id))
! 160: {
! 161: return TRUE;
! 162: }
! 163: if ((id->get_responder_spi(id) == 0 ||
! 164: entry->ike_sa_id->get_responder_spi(entry->ike_sa_id) == 0) &&
! 165: (id->get_ike_version(id) == IKEV1_MAJOR_VERSION ||
! 166: id->is_initiator(id) == entry->ike_sa_id->is_initiator(entry->ike_sa_id)) &&
! 167: id->get_initiator_spi(id) == entry->ike_sa_id->get_initiator_spi(entry->ike_sa_id))
! 168: {
! 169: /* this is TRUE for IKE_SAs that we initiated but have not yet received a response */
! 170: return TRUE;
! 171: }
! 172: return FALSE;
! 173: }
! 174:
! 175: /**
! 176: * Function that matches entry_t objects by ike_sa_t pointers.
! 177: */
! 178: static bool entry_match_by_sa(entry_t *entry, void *ike_sa)
! 179: {
! 180: return entry->ike_sa == ike_sa;
! 181: }
! 182:
! 183: /**
! 184: * Hash function for ike_sa_id_t objects.
! 185: */
! 186: static u_int ike_sa_id_hash(ike_sa_id_t *ike_sa_id)
! 187: {
! 188: /* IKEv2 does not mandate random SPIs (RFC 5996, 2.6), they just have to be
! 189: * locally unique, so we use our randomly allocated SPI whether we are
! 190: * initiator or responder to ensure a good distribution. The latter is not
! 191: * possible for IKEv1 as we don't know whether we are original initiator or
! 192: * not (based on the IKE header). But as RFC 2408, section 2.5.3 proposes
! 193: * SPIs (Cookies) to be allocated near random (we allocate them randomly
! 194: * anyway) it seems safe to always use the initiator SPI. */
! 195: if (ike_sa_id->get_ike_version(ike_sa_id) == IKEV1_MAJOR_VERSION ||
! 196: ike_sa_id->is_initiator(ike_sa_id))
! 197: {
! 198: return ike_sa_id->get_initiator_spi(ike_sa_id);
! 199: }
! 200: return ike_sa_id->get_responder_spi(ike_sa_id);
! 201: }
! 202:
! 203: typedef struct half_open_t half_open_t;
! 204:
! 205: /**
! 206: * Struct to manage half-open IKE_SAs per peer.
! 207: */
! 208: struct half_open_t {
! 209: /** chunk of remote host address */
! 210: chunk_t other;
! 211:
! 212: /** the number of half-open IKE_SAs with that host */
! 213: u_int count;
! 214:
! 215: /** the number of half-open IKE_SAs we responded to with that host */
! 216: u_int count_responder;
! 217: };
! 218:
! 219: /**
! 220: * Destroys a half_open_t object.
! 221: */
! 222: static void half_open_destroy(half_open_t *this)
! 223: {
! 224: chunk_free(&this->other);
! 225: free(this);
! 226: }
! 227:
! 228: typedef struct connected_peers_t connected_peers_t;
! 229:
! 230: struct connected_peers_t {
! 231: /** own identity */
! 232: identification_t *my_id;
! 233:
! 234: /** remote identity */
! 235: identification_t *other_id;
! 236:
! 237: /** ip address family of peer */
! 238: int family;
! 239:
! 240: /** list of ike_sa_id_t objects of IKE_SAs between the two identities */
! 241: linked_list_t *sas;
! 242: };
! 243:
! 244: static void connected_peers_destroy(connected_peers_t *this)
! 245: {
! 246: this->my_id->destroy(this->my_id);
! 247: this->other_id->destroy(this->other_id);
! 248: this->sas->destroy(this->sas);
! 249: free(this);
! 250: }
! 251:
! 252: /**
! 253: * Function that matches connected_peers_t objects by the given ids.
! 254: */
! 255: static inline bool connected_peers_match(connected_peers_t *connected_peers,
! 256: identification_t *my_id, identification_t *other_id,
! 257: int family)
! 258: {
! 259: return my_id->equals(my_id, connected_peers->my_id) &&
! 260: other_id->equals(other_id, connected_peers->other_id) &&
! 261: (!family || family == connected_peers->family);
! 262: }
! 263:
! 264: typedef struct init_hash_t init_hash_t;
! 265:
! 266: struct init_hash_t {
! 267: /** hash of IKE_SA_INIT or initial phase1 message (data is not cloned) */
! 268: chunk_t hash;
! 269:
! 270: /** our SPI allocated for the IKE_SA based on this message */
! 271: uint64_t our_spi;
! 272: };
! 273:
! 274: typedef struct segment_t segment_t;
! 275:
! 276: /**
! 277: * Struct to manage segments of the hash table.
! 278: */
! 279: struct segment_t {
! 280: /** mutex to access a segment exclusively */
! 281: mutex_t *mutex;
! 282: };
! 283:
! 284: typedef struct shareable_segment_t shareable_segment_t;
! 285:
! 286: /**
! 287: * Struct to manage segments of the "half-open" and "connected peers" hash tables.
! 288: */
! 289: struct shareable_segment_t {
! 290: /** rwlock to access a segment non-/exclusively */
! 291: rwlock_t *lock;
! 292:
! 293: /** the number of entries in this segment - in case of the "half-open table"
! 294: * it's the sum of all half_open_t.count in a segment. */
! 295: u_int count;
! 296: };
! 297:
! 298: typedef struct table_item_t table_item_t;
! 299:
! 300: /**
! 301: * Instead of using linked_list_t for each bucket we store the data in our own
! 302: * list to save memory.
! 303: */
! 304: struct table_item_t {
! 305: /** data of this item */
! 306: void *value;
! 307:
! 308: /** next item in the overflow list */
! 309: table_item_t *next;
! 310: };
! 311:
! 312: typedef struct private_ike_sa_manager_t private_ike_sa_manager_t;
! 313:
! 314: /**
! 315: * Additional private members of ike_sa_manager_t.
! 316: */
! 317: struct private_ike_sa_manager_t {
! 318: /**
! 319: * Public interface of ike_sa_manager_t.
! 320: */
! 321: ike_sa_manager_t public;
! 322:
! 323: /**
! 324: * Hash table with entries for the ike_sa_t objects.
! 325: */
! 326: table_item_t **ike_sa_table;
! 327:
! 328: /**
! 329: * The size of the hash table.
! 330: */
! 331: u_int table_size;
! 332:
! 333: /**
! 334: * Mask to map the hashes to table rows.
! 335: */
! 336: u_int table_mask;
! 337:
! 338: /**
! 339: * Segments of the hash table.
! 340: */
! 341: segment_t *segments;
! 342:
! 343: /**
! 344: * The number of segments.
! 345: */
! 346: u_int segment_count;
! 347:
! 348: /**
! 349: * Mask to map a table row to a segment.
! 350: */
! 351: u_int segment_mask;
! 352:
! 353: /**
! 354: * Hash table with half_open_t objects.
! 355: */
! 356: table_item_t **half_open_table;
! 357:
! 358: /**
! 359: * Segments of the "half-open" hash table.
! 360: */
! 361: shareable_segment_t *half_open_segments;
! 362:
! 363: /**
! 364: * Total number of half-open IKE_SAs.
! 365: */
! 366: refcount_t half_open_count;
! 367:
! 368: /**
! 369: * Total number of half-open IKE_SAs as responder.
! 370: */
! 371: refcount_t half_open_count_responder;
! 372:
! 373: /**
! 374: * Total number of IKE_SAs registered with IKE_SA manager.
! 375: */
! 376: refcount_t total_sa_count;
! 377:
! 378: /**
! 379: * Hash table with connected_peers_t objects.
! 380: */
! 381: table_item_t **connected_peers_table;
! 382:
! 383: /**
! 384: * Segments of the "connected peers" hash table.
! 385: */
! 386: shareable_segment_t *connected_peers_segments;
! 387:
! 388: /**
! 389: * Hash table with init_hash_t objects.
! 390: */
! 391: table_item_t **init_hashes_table;
! 392:
! 393: /**
! 394: * Segments of the "hashes" hash table.
! 395: */
! 396: segment_t *init_hashes_segments;
! 397:
! 398: /**
! 399: * RNG to get random SPIs for our side
! 400: */
! 401: rng_t *rng;
! 402:
! 403: /**
! 404: * Registered callback for IKE SPIs
! 405: */
! 406: struct {
! 407: spi_cb_t cb;
! 408: void *data;
! 409: } spi_cb;
! 410:
! 411: /**
! 412: * Lock to access the RNG instance and the callback
! 413: */
! 414: rwlock_t *spi_lock;
! 415:
! 416: /**
! 417: * Mask applied to local SPIs before mixing in the label
! 418: */
! 419: uint64_t spi_mask;
! 420:
! 421: /**
! 422: * Label applied to local SPIs
! 423: */
! 424: uint64_t spi_label;
! 425:
! 426: /**
! 427: * reuse existing IKE_SAs in checkout_by_config
! 428: */
! 429: bool reuse_ikesa;
! 430:
! 431: /**
! 432: * Configured IKE_SA limit, if any
! 433: */
! 434: u_int ikesa_limit;
! 435: };
! 436:
! 437: /**
! 438: * Acquire a lock to access the segment of the table row with the given index.
! 439: * It also works with the segment index directly.
! 440: */
! 441: static inline void lock_single_segment(private_ike_sa_manager_t *this,
! 442: u_int index)
! 443: {
! 444: mutex_t *lock = this->segments[index & this->segment_mask].mutex;
! 445: lock->lock(lock);
! 446: }
! 447:
! 448: /**
! 449: * Release the lock required to access the segment of the table row with the given index.
! 450: * It also works with the segment index directly.
! 451: */
! 452: static inline void unlock_single_segment(private_ike_sa_manager_t *this,
! 453: u_int index)
! 454: {
! 455: mutex_t *lock = this->segments[index & this->segment_mask].mutex;
! 456: lock->unlock(lock);
! 457: }
! 458:
! 459: /**
! 460: * Lock all segments
! 461: */
! 462: static void lock_all_segments(private_ike_sa_manager_t *this)
! 463: {
! 464: u_int i;
! 465:
! 466: for (i = 0; i < this->segment_count; i++)
! 467: {
! 468: this->segments[i].mutex->lock(this->segments[i].mutex);
! 469: }
! 470: }
! 471:
! 472: /**
! 473: * Unlock all segments
! 474: */
! 475: static void unlock_all_segments(private_ike_sa_manager_t *this)
! 476: {
! 477: u_int i;
! 478:
! 479: for (i = 0; i < this->segment_count; i++)
! 480: {
! 481: this->segments[i].mutex->unlock(this->segments[i].mutex);
! 482: }
! 483: }
! 484:
! 485: typedef struct private_enumerator_t private_enumerator_t;
! 486:
! 487: /**
! 488: * hash table enumerator implementation
! 489: */
! 490: struct private_enumerator_t {
! 491:
! 492: /**
! 493: * implements enumerator interface
! 494: */
! 495: enumerator_t enumerator;
! 496:
! 497: /**
! 498: * associated ike_sa_manager_t
! 499: */
! 500: private_ike_sa_manager_t *manager;
! 501:
! 502: /**
! 503: * current segment index
! 504: */
! 505: u_int segment;
! 506:
! 507: /**
! 508: * currently enumerating entry
! 509: */
! 510: entry_t *entry;
! 511:
! 512: /**
! 513: * current table row index
! 514: */
! 515: u_int row;
! 516:
! 517: /**
! 518: * current table item
! 519: */
! 520: table_item_t *current;
! 521:
! 522: /**
! 523: * previous table item
! 524: */
! 525: table_item_t *prev;
! 526: };
! 527:
! 528: METHOD(enumerator_t, enumerate, bool,
! 529: private_enumerator_t *this, va_list args)
! 530: {
! 531: entry_t **entry;
! 532: u_int *segment;
! 533:
! 534: VA_ARGS_VGET(args, entry, segment);
! 535:
! 536: if (this->entry)
! 537: {
! 538: this->entry->condvar->signal(this->entry->condvar);
! 539: this->entry = NULL;
! 540: }
! 541: while (this->segment < this->manager->segment_count)
! 542: {
! 543: while (this->row < this->manager->table_size)
! 544: {
! 545: this->prev = this->current;
! 546: if (this->current)
! 547: {
! 548: this->current = this->current->next;
! 549: }
! 550: else
! 551: {
! 552: lock_single_segment(this->manager, this->segment);
! 553: this->current = this->manager->ike_sa_table[this->row];
! 554: }
! 555: if (this->current)
! 556: {
! 557: *entry = this->entry = this->current->value;
! 558: *segment = this->segment;
! 559: return TRUE;
! 560: }
! 561: unlock_single_segment(this->manager, this->segment);
! 562: this->row += this->manager->segment_count;
! 563: }
! 564: this->segment++;
! 565: this->row = this->segment;
! 566: }
! 567: return FALSE;
! 568: }
! 569:
! 570: METHOD(enumerator_t, enumerator_destroy, void,
! 571: private_enumerator_t *this)
! 572: {
! 573: if (this->entry)
! 574: {
! 575: this->entry->condvar->signal(this->entry->condvar);
! 576: }
! 577: if (this->current)
! 578: {
! 579: unlock_single_segment(this->manager, this->segment);
! 580: }
! 581: free(this);
! 582: }
! 583:
! 584: /**
! 585: * Creates an enumerator to enumerate the entries in the hash table.
! 586: */
! 587: static enumerator_t* create_table_enumerator(private_ike_sa_manager_t *this)
! 588: {
! 589: private_enumerator_t *enumerator;
! 590:
! 591: INIT(enumerator,
! 592: .enumerator = {
! 593: .enumerate = enumerator_enumerate_default,
! 594: .venumerate = _enumerate,
! 595: .destroy = _enumerator_destroy,
! 596: },
! 597: .manager = this,
! 598: );
! 599: return &enumerator->enumerator;
! 600: }
! 601:
! 602: /**
! 603: * Put an entry into the hash table.
! 604: * Note: The caller has to unlock the returned segment.
! 605: */
! 606: static u_int put_entry(private_ike_sa_manager_t *this, entry_t *entry)
! 607: {
! 608: table_item_t *current, *item;
! 609: u_int row, segment;
! 610:
! 611: INIT(item,
! 612: .value = entry,
! 613: );
! 614:
! 615: row = ike_sa_id_hash(entry->ike_sa_id) & this->table_mask;
! 616: segment = row & this->segment_mask;
! 617:
! 618: lock_single_segment(this, segment);
! 619: current = this->ike_sa_table[row];
! 620: if (current)
! 621: { /* insert at the front of current bucket */
! 622: item->next = current;
! 623: }
! 624: this->ike_sa_table[row] = item;
! 625: ref_get(&this->total_sa_count);
! 626: return segment;
! 627: }
! 628:
! 629: /**
! 630: * Remove an entry from the hash table.
! 631: * Note: The caller MUST have a lock on the segment of this entry.
! 632: */
! 633: static void remove_entry(private_ike_sa_manager_t *this, entry_t *entry)
! 634: {
! 635: table_item_t *item, *prev = NULL;
! 636: u_int row;
! 637:
! 638: row = ike_sa_id_hash(entry->ike_sa_id) & this->table_mask;
! 639: item = this->ike_sa_table[row];
! 640: while (item)
! 641: {
! 642: if (item->value == entry)
! 643: {
! 644: if (prev)
! 645: {
! 646: prev->next = item->next;
! 647: }
! 648: else
! 649: {
! 650: this->ike_sa_table[row] = item->next;
! 651: }
! 652: ignore_result(ref_put(&this->total_sa_count));
! 653: free(item);
! 654: break;
! 655: }
! 656: prev = item;
! 657: item = item->next;
! 658: }
! 659: }
! 660:
! 661: /**
! 662: * Remove the entry at the current enumerator position.
! 663: */
! 664: static void remove_entry_at(private_enumerator_t *this)
! 665: {
! 666: this->entry = NULL;
! 667: if (this->current)
! 668: {
! 669: table_item_t *current = this->current;
! 670:
! 671: ignore_result(ref_put(&this->manager->total_sa_count));
! 672: this->current = this->prev;
! 673:
! 674: if (this->prev)
! 675: {
! 676: this->prev->next = current->next;
! 677: }
! 678: else
! 679: {
! 680: this->manager->ike_sa_table[this->row] = current->next;
! 681: unlock_single_segment(this->manager, this->segment);
! 682: }
! 683: free(current);
! 684: }
! 685: }
! 686:
! 687: /**
! 688: * Find an entry using the provided match function to compare the entries for
! 689: * equality.
! 690: */
! 691: static status_t get_entry_by_match_function(private_ike_sa_manager_t *this,
! 692: ike_sa_id_t *ike_sa_id, entry_t **entry, u_int *segment,
! 693: bool (*match)(entry_t*,void*), void *param)
! 694: {
! 695: table_item_t *item;
! 696: u_int row, seg;
! 697:
! 698: row = ike_sa_id_hash(ike_sa_id) & this->table_mask;
! 699: seg = row & this->segment_mask;
! 700:
! 701: lock_single_segment(this, seg);
! 702: item = this->ike_sa_table[row];
! 703: while (item)
! 704: {
! 705: if (match(item->value, param))
! 706: {
! 707: *entry = item->value;
! 708: *segment = seg;
! 709: /* the locked segment has to be unlocked by the caller */
! 710: return SUCCESS;
! 711: }
! 712: item = item->next;
! 713: }
! 714: unlock_single_segment(this, seg);
! 715: return NOT_FOUND;
! 716: }
! 717:
! 718: /**
! 719: * Find an entry by ike_sa_id_t.
! 720: * Note: On SUCCESS, the caller has to unlock the segment.
! 721: */
! 722: static status_t get_entry_by_id(private_ike_sa_manager_t *this,
! 723: ike_sa_id_t *ike_sa_id, entry_t **entry, u_int *segment)
! 724: {
! 725: return get_entry_by_match_function(this, ike_sa_id, entry, segment,
! 726: entry_match_by_id, ike_sa_id);
! 727: }
! 728:
! 729: /**
! 730: * Find an entry by IKE_SA pointer.
! 731: * Note: On SUCCESS, the caller has to unlock the segment.
! 732: */
! 733: static status_t get_entry_by_sa(private_ike_sa_manager_t *this,
! 734: ike_sa_id_t *ike_sa_id, ike_sa_t *ike_sa, entry_t **entry, u_int *segment)
! 735: {
! 736: return get_entry_by_match_function(this, ike_sa_id, entry, segment,
! 737: entry_match_by_sa, ike_sa);
! 738: }
! 739:
! 740: /**
! 741: * Wait until no other thread is using an IKE_SA, return FALSE if entry not
! 742: * acquirable.
! 743: */
! 744: static bool wait_for_entry(private_ike_sa_manager_t *this, entry_t *entry,
! 745: u_int segment)
! 746: {
! 747: if (entry->driveout_new_threads)
! 748: {
! 749: /* we are not allowed to get this */
! 750: return FALSE;
! 751: }
! 752: while (entry->checked_out && !entry->driveout_waiting_threads)
! 753: {
! 754: /* so wait until we can get it for us.
! 755: * we register us as waiting. */
! 756: entry->waiting_threads++;
! 757: entry->condvar->wait(entry->condvar, this->segments[segment].mutex);
! 758: entry->waiting_threads--;
! 759: }
! 760: /* hm, a deletion request forbids us to get this SA, get next one */
! 761: if (entry->driveout_waiting_threads)
! 762: {
! 763: /* we must signal here, others may be waiting on it, too */
! 764: entry->condvar->signal(entry->condvar);
! 765: return FALSE;
! 766: }
! 767: return TRUE;
! 768: }
! 769:
! 770: /**
! 771: * Put a half-open SA into the hash table.
! 772: */
! 773: static void put_half_open(private_ike_sa_manager_t *this, entry_t *entry)
! 774: {
! 775: table_item_t *item;
! 776: u_int row, segment;
! 777: rwlock_t *lock;
! 778: ike_sa_id_t *ike_id;
! 779: half_open_t *half_open;
! 780: chunk_t addr;
! 781:
! 782: ike_id = entry->ike_sa_id;
! 783: addr = entry->other->get_address(entry->other);
! 784: row = chunk_hash(addr) & this->table_mask;
! 785: segment = row & this->segment_mask;
! 786: lock = this->half_open_segments[segment].lock;
! 787: lock->write_lock(lock);
! 788: item = this->half_open_table[row];
! 789: while (item)
! 790: {
! 791: half_open = item->value;
! 792:
! 793: if (chunk_equals(addr, half_open->other))
! 794: {
! 795: break;
! 796: }
! 797: item = item->next;
! 798: }
! 799:
! 800: if (!item)
! 801: {
! 802: INIT(half_open,
! 803: .other = chunk_clone(addr),
! 804: );
! 805: INIT(item,
! 806: .value = half_open,
! 807: .next = this->half_open_table[row],
! 808: );
! 809: this->half_open_table[row] = item;
! 810: }
! 811: half_open->count++;
! 812: ref_get(&this->half_open_count);
! 813: if (!ike_id->is_initiator(ike_id))
! 814: {
! 815: half_open->count_responder++;
! 816: ref_get(&this->half_open_count_responder);
! 817: }
! 818: this->half_open_segments[segment].count++;
! 819: lock->unlock(lock);
! 820: }
! 821:
! 822: /**
! 823: * Remove a half-open SA from the hash table.
! 824: */
! 825: static void remove_half_open(private_ike_sa_manager_t *this, entry_t *entry)
! 826: {
! 827: table_item_t *item, *prev = NULL;
! 828: u_int row, segment;
! 829: rwlock_t *lock;
! 830: ike_sa_id_t *ike_id;
! 831: chunk_t addr;
! 832:
! 833: ike_id = entry->ike_sa_id;
! 834: addr = entry->other->get_address(entry->other);
! 835: row = chunk_hash(addr) & this->table_mask;
! 836: segment = row & this->segment_mask;
! 837: lock = this->half_open_segments[segment].lock;
! 838: lock->write_lock(lock);
! 839: item = this->half_open_table[row];
! 840: while (item)
! 841: {
! 842: half_open_t *half_open = item->value;
! 843:
! 844: if (chunk_equals(addr, half_open->other))
! 845: {
! 846: if (!ike_id->is_initiator(ike_id))
! 847: {
! 848: half_open->count_responder--;
! 849: ignore_result(ref_put(&this->half_open_count_responder));
! 850: }
! 851: ignore_result(ref_put(&this->half_open_count));
! 852: if (--half_open->count == 0)
! 853: {
! 854: if (prev)
! 855: {
! 856: prev->next = item->next;
! 857: }
! 858: else
! 859: {
! 860: this->half_open_table[row] = item->next;
! 861: }
! 862: half_open_destroy(half_open);
! 863: free(item);
! 864: }
! 865: this->half_open_segments[segment].count--;
! 866: break;
! 867: }
! 868: prev = item;
! 869: item = item->next;
! 870: }
! 871: lock->unlock(lock);
! 872: }
! 873:
! 874: CALLBACK(id_matches, bool,
! 875: ike_sa_id_t *a, va_list args)
! 876: {
! 877: ike_sa_id_t *b;
! 878:
! 879: VA_ARGS_VGET(args, b);
! 880: return a->equals(a, b);
! 881: }
! 882:
! 883: /**
! 884: * Put an SA between two peers into the hash table.
! 885: */
! 886: static void put_connected_peers(private_ike_sa_manager_t *this, entry_t *entry)
! 887: {
! 888: table_item_t *item;
! 889: u_int row, segment;
! 890: rwlock_t *lock;
! 891: connected_peers_t *connected_peers;
! 892: chunk_t my_id, other_id;
! 893: int family;
! 894:
! 895: my_id = entry->my_id->get_encoding(entry->my_id);
! 896: other_id = entry->other_id->get_encoding(entry->other_id);
! 897: family = entry->other->get_family(entry->other);
! 898: row = chunk_hash_inc(other_id, chunk_hash(my_id)) & this->table_mask;
! 899: segment = row & this->segment_mask;
! 900: lock = this->connected_peers_segments[segment].lock;
! 901: lock->write_lock(lock);
! 902: item = this->connected_peers_table[row];
! 903: while (item)
! 904: {
! 905: connected_peers = item->value;
! 906:
! 907: if (connected_peers_match(connected_peers, entry->my_id,
! 908: entry->other_id, family))
! 909: {
! 910: if (connected_peers->sas->find_first(connected_peers->sas,
! 911: id_matches, NULL, entry->ike_sa_id))
! 912: {
! 913: lock->unlock(lock);
! 914: return;
! 915: }
! 916: break;
! 917: }
! 918: item = item->next;
! 919: }
! 920:
! 921: if (!item)
! 922: {
! 923: INIT(connected_peers,
! 924: .my_id = entry->my_id->clone(entry->my_id),
! 925: .other_id = entry->other_id->clone(entry->other_id),
! 926: .family = family,
! 927: .sas = linked_list_create(),
! 928: );
! 929: INIT(item,
! 930: .value = connected_peers,
! 931: .next = this->connected_peers_table[row],
! 932: );
! 933: this->connected_peers_table[row] = item;
! 934: }
! 935: connected_peers->sas->insert_last(connected_peers->sas,
! 936: entry->ike_sa_id->clone(entry->ike_sa_id));
! 937: this->connected_peers_segments[segment].count++;
! 938: lock->unlock(lock);
! 939: }
! 940:
! 941: /**
! 942: * Remove an SA between two peers from the hash table.
! 943: */
! 944: static void remove_connected_peers(private_ike_sa_manager_t *this, entry_t *entry)
! 945: {
! 946: table_item_t *item, *prev = NULL;
! 947: u_int row, segment;
! 948: rwlock_t *lock;
! 949: chunk_t my_id, other_id;
! 950: int family;
! 951:
! 952: my_id = entry->my_id->get_encoding(entry->my_id);
! 953: other_id = entry->other_id->get_encoding(entry->other_id);
! 954: family = entry->other->get_family(entry->other);
! 955:
! 956: row = chunk_hash_inc(other_id, chunk_hash(my_id)) & this->table_mask;
! 957: segment = row & this->segment_mask;
! 958:
! 959: lock = this->connected_peers_segments[segment].lock;
! 960: lock->write_lock(lock);
! 961: item = this->connected_peers_table[row];
! 962: while (item)
! 963: {
! 964: connected_peers_t *current = item->value;
! 965:
! 966: if (connected_peers_match(current, entry->my_id, entry->other_id,
! 967: family))
! 968: {
! 969: enumerator_t *enumerator;
! 970: ike_sa_id_t *ike_sa_id;
! 971:
! 972: enumerator = current->sas->create_enumerator(current->sas);
! 973: while (enumerator->enumerate(enumerator, &ike_sa_id))
! 974: {
! 975: if (ike_sa_id->equals(ike_sa_id, entry->ike_sa_id))
! 976: {
! 977: current->sas->remove_at(current->sas, enumerator);
! 978: ike_sa_id->destroy(ike_sa_id);
! 979: this->connected_peers_segments[segment].count--;
! 980: break;
! 981: }
! 982: }
! 983: enumerator->destroy(enumerator);
! 984: if (current->sas->get_count(current->sas) == 0)
! 985: {
! 986: if (prev)
! 987: {
! 988: prev->next = item->next;
! 989: }
! 990: else
! 991: {
! 992: this->connected_peers_table[row] = item->next;
! 993: }
! 994: connected_peers_destroy(current);
! 995: free(item);
! 996: }
! 997: break;
! 998: }
! 999: prev = item;
! 1000: item = item->next;
! 1001: }
! 1002: lock->unlock(lock);
! 1003: }
! 1004:
! 1005: /**
! 1006: * Get a random SPI for new IKE_SAs
! 1007: */
! 1008: static uint64_t get_spi(private_ike_sa_manager_t *this)
! 1009: {
! 1010: uint64_t spi;
! 1011:
! 1012: this->spi_lock->read_lock(this->spi_lock);
! 1013: if (this->spi_cb.cb)
! 1014: {
! 1015: spi = this->spi_cb.cb(this->spi_cb.data);
! 1016: }
! 1017: else if (!this->rng ||
! 1018: !this->rng->get_bytes(this->rng, sizeof(spi), (uint8_t*)&spi))
! 1019: {
! 1020: spi = 0;
! 1021: }
! 1022: this->spi_lock->unlock(this->spi_lock);
! 1023:
! 1024: if (spi)
! 1025: {
! 1026: spi = (spi & ~this->spi_mask) | this->spi_label;
! 1027: }
! 1028: return spi;
! 1029: }
! 1030:
! 1031: /**
! 1032: * Calculate the hash of the initial IKE message. Memory for the hash is
! 1033: * allocated on success.
! 1034: *
! 1035: * @returns TRUE on success
! 1036: */
! 1037: static bool get_init_hash(hasher_t *hasher, message_t *message, chunk_t *hash)
! 1038: {
! 1039: host_t *src;
! 1040:
! 1041: if (message->get_first_payload_type(message) == PLV1_FRAGMENT)
! 1042: { /* only hash the source IP, port and SPI for fragmented init messages */
! 1043: uint16_t port;
! 1044: uint64_t spi;
! 1045:
! 1046: src = message->get_source(message);
! 1047: if (!hasher->allocate_hash(hasher, src->get_address(src), NULL))
! 1048: {
! 1049: return FALSE;
! 1050: }
! 1051: port = src->get_port(src);
! 1052: if (!hasher->allocate_hash(hasher, chunk_from_thing(port), NULL))
! 1053: {
! 1054: return FALSE;
! 1055: }
! 1056: spi = message->get_initiator_spi(message);
! 1057: return hasher->allocate_hash(hasher, chunk_from_thing(spi), hash);
! 1058: }
! 1059: if (message->get_exchange_type(message) == ID_PROT)
! 1060: { /* include the source for Main Mode as the hash will be the same if
! 1061: * SPIs are reused by two initiators that use the same proposal */
! 1062: src = message->get_source(message);
! 1063:
! 1064: if (!hasher->allocate_hash(hasher, src->get_address(src), NULL))
! 1065: {
! 1066: return FALSE;
! 1067: }
! 1068: }
! 1069: return hasher->allocate_hash(hasher, message->get_packet_data(message), hash);
! 1070: }
! 1071:
! 1072: /**
! 1073: * Check if we already have created an IKE_SA based on the initial IKE message
! 1074: * with the given hash.
! 1075: * If not the hash is stored, the hash data is not(!) cloned.
! 1076: *
! 1077: * Also, the local SPI is returned. In case of a retransmit this is already
! 1078: * stored together with the hash, otherwise it is newly allocated and should
! 1079: * be used to create the IKE_SA.
! 1080: *
! 1081: * @returns ALREADY_DONE if the message with the given hash has been seen before
! 1082: * NOT_FOUND if the message hash was not found
! 1083: * FAILED if the SPI allocation failed
! 1084: */
! 1085: static status_t check_and_put_init_hash(private_ike_sa_manager_t *this,
! 1086: chunk_t init_hash, uint64_t *our_spi)
! 1087: {
! 1088: table_item_t *item;
! 1089: u_int row, segment;
! 1090: mutex_t *mutex;
! 1091: init_hash_t *init;
! 1092: uint64_t spi;
! 1093:
! 1094: row = chunk_hash(init_hash) & this->table_mask;
! 1095: segment = row & this->segment_mask;
! 1096: mutex = this->init_hashes_segments[segment].mutex;
! 1097: mutex->lock(mutex);
! 1098: item = this->init_hashes_table[row];
! 1099: while (item)
! 1100: {
! 1101: init_hash_t *current = item->value;
! 1102:
! 1103: if (chunk_equals(init_hash, current->hash))
! 1104: {
! 1105: *our_spi = current->our_spi;
! 1106: mutex->unlock(mutex);
! 1107: return ALREADY_DONE;
! 1108: }
! 1109: item = item->next;
! 1110: }
! 1111:
! 1112: spi = get_spi(this);
! 1113: if (!spi)
! 1114: {
! 1115: return FAILED;
! 1116: }
! 1117:
! 1118: INIT(init,
! 1119: .hash = {
! 1120: .len = init_hash.len,
! 1121: .ptr = init_hash.ptr,
! 1122: },
! 1123: .our_spi = spi,
! 1124: );
! 1125: INIT(item,
! 1126: .value = init,
! 1127: .next = this->init_hashes_table[row],
! 1128: );
! 1129: this->init_hashes_table[row] = item;
! 1130: *our_spi = init->our_spi;
! 1131: mutex->unlock(mutex);
! 1132: return NOT_FOUND;
! 1133: }
! 1134:
! 1135: /**
! 1136: * Remove the hash of an initial IKE message from the cache.
! 1137: */
! 1138: static void remove_init_hash(private_ike_sa_manager_t *this, chunk_t init_hash)
! 1139: {
! 1140: table_item_t *item, *prev = NULL;
! 1141: u_int row, segment;
! 1142: mutex_t *mutex;
! 1143:
! 1144: row = chunk_hash(init_hash) & this->table_mask;
! 1145: segment = row & this->segment_mask;
! 1146: mutex = this->init_hashes_segments[segment].mutex;
! 1147: mutex->lock(mutex);
! 1148: item = this->init_hashes_table[row];
! 1149: while (item)
! 1150: {
! 1151: init_hash_t *current = item->value;
! 1152:
! 1153: if (chunk_equals(init_hash, current->hash))
! 1154: {
! 1155: if (prev)
! 1156: {
! 1157: prev->next = item->next;
! 1158: }
! 1159: else
! 1160: {
! 1161: this->init_hashes_table[row] = item->next;
! 1162: }
! 1163: free(current);
! 1164: free(item);
! 1165: break;
! 1166: }
! 1167: prev = item;
! 1168: item = item->next;
! 1169: }
! 1170: mutex->unlock(mutex);
! 1171: }
! 1172:
! 1173: METHOD(ike_sa_manager_t, checkout, ike_sa_t*,
! 1174: private_ike_sa_manager_t *this, ike_sa_id_t *ike_sa_id)
! 1175: {
! 1176: ike_sa_t *ike_sa = NULL;
! 1177: entry_t *entry;
! 1178: u_int segment;
! 1179:
! 1180: DBG2(DBG_MGR, "checkout %N SA with SPIs %.16"PRIx64"_i %.16"PRIx64"_r",
! 1181: ike_version_names, ike_sa_id->get_ike_version(ike_sa_id),
! 1182: be64toh(ike_sa_id->get_initiator_spi(ike_sa_id)),
! 1183: be64toh(ike_sa_id->get_responder_spi(ike_sa_id)));
! 1184:
! 1185: if (get_entry_by_id(this, ike_sa_id, &entry, &segment) == SUCCESS)
! 1186: {
! 1187: if (wait_for_entry(this, entry, segment))
! 1188: {
! 1189: entry->checked_out = thread_current();
! 1190: ike_sa = entry->ike_sa;
! 1191: DBG2(DBG_MGR, "IKE_SA %s[%u] successfully checked out",
! 1192: ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa));
! 1193: }
! 1194: unlock_single_segment(this, segment);
! 1195: }
! 1196: charon->bus->set_sa(charon->bus, ike_sa);
! 1197:
! 1198: if (!ike_sa)
! 1199: {
! 1200: DBG2(DBG_MGR, "IKE_SA checkout not successful");
! 1201: }
! 1202: return ike_sa;
! 1203: }
! 1204:
! 1205: METHOD(ike_sa_manager_t, checkout_new, ike_sa_t*,
! 1206: private_ike_sa_manager_t* this, ike_version_t version, bool initiator)
! 1207: {
! 1208: ike_sa_id_t *ike_sa_id;
! 1209: ike_sa_t *ike_sa;
! 1210: uint8_t ike_version;
! 1211: uint64_t spi;
! 1212:
! 1213: ike_version = version == IKEV1 ? IKEV1_MAJOR_VERSION : IKEV2_MAJOR_VERSION;
! 1214:
! 1215: spi = get_spi(this);
! 1216: if (!spi)
! 1217: {
! 1218: DBG1(DBG_MGR, "failed to allocate SPI for new IKE_SA");
! 1219: return NULL;
! 1220: }
! 1221:
! 1222: if (initiator)
! 1223: {
! 1224: ike_sa_id = ike_sa_id_create(ike_version, spi, 0, TRUE);
! 1225: }
! 1226: else
! 1227: {
! 1228: ike_sa_id = ike_sa_id_create(ike_version, 0, spi, FALSE);
! 1229: }
! 1230: ike_sa = ike_sa_create(ike_sa_id, initiator, version);
! 1231: ike_sa_id->destroy(ike_sa_id);
! 1232:
! 1233: if (ike_sa)
! 1234: {
! 1235: DBG2(DBG_MGR, "created IKE_SA %s[%u]", ike_sa->get_name(ike_sa),
! 1236: ike_sa->get_unique_id(ike_sa));
! 1237: }
! 1238: return ike_sa;
! 1239: }
! 1240:
! 1241: /**
! 1242: * Get the message ID or message hash to detect early retransmissions
! 1243: */
! 1244: static uint32_t get_message_id_or_hash(message_t *message)
! 1245: {
! 1246: if (message->get_major_version(message) == IKEV1_MAJOR_VERSION)
! 1247: {
! 1248: /* Use a hash for IKEv1 Phase 1, where we don't have a MID, and Quick
! 1249: * Mode, where all three messages use the same message ID */
! 1250: if (message->get_message_id(message) == 0 ||
! 1251: message->get_exchange_type(message) == QUICK_MODE)
! 1252: {
! 1253: return chunk_hash(message->get_packet_data(message));
! 1254: }
! 1255: }
! 1256: return message->get_message_id(message);
! 1257: }
! 1258:
! 1259: METHOD(ike_sa_manager_t, checkout_by_message, ike_sa_t*,
! 1260: private_ike_sa_manager_t* this, message_t *message)
! 1261: {
! 1262: u_int segment;
! 1263: entry_t *entry;
! 1264: ike_sa_t *ike_sa = NULL;
! 1265: ike_sa_id_t *id;
! 1266: ike_version_t ike_version;
! 1267: bool is_init = FALSE;
! 1268:
! 1269: id = message->get_ike_sa_id(message);
! 1270: /* clone the IKE_SA ID so we can modify the initiator flag */
! 1271: id = id->clone(id);
! 1272: id->switch_initiator(id);
! 1273:
! 1274: DBG2(DBG_MGR, "checkout %N SA by message with SPIs %.16"PRIx64"_i "
! 1275: "%.16"PRIx64"_r", ike_version_names, id->get_ike_version(id),
! 1276: be64toh(id->get_initiator_spi(id)),
! 1277: be64toh(id->get_responder_spi(id)));
! 1278:
! 1279: if (id->get_responder_spi(id) == 0 &&
! 1280: message->get_message_id(message) == 0)
! 1281: {
! 1282: if (message->get_major_version(message) == IKEV2_MAJOR_VERSION)
! 1283: {
! 1284: if (message->get_exchange_type(message) == IKE_SA_INIT &&
! 1285: message->get_request(message))
! 1286: {
! 1287: ike_version = IKEV2;
! 1288: is_init = TRUE;
! 1289: }
! 1290: }
! 1291: else
! 1292: {
! 1293: if (message->get_exchange_type(message) == ID_PROT ||
! 1294: message->get_exchange_type(message) == AGGRESSIVE)
! 1295: {
! 1296: ike_version = IKEV1;
! 1297: is_init = TRUE;
! 1298: if (id->is_initiator(id))
! 1299: { /* not set in IKEv1, switch back before applying to new SA */
! 1300: id->switch_initiator(id);
! 1301: }
! 1302: }
! 1303: }
! 1304: }
! 1305:
! 1306: if (is_init)
! 1307: {
! 1308: hasher_t *hasher;
! 1309: uint64_t our_spi;
! 1310: chunk_t hash;
! 1311:
! 1312: hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
! 1313: if (!hasher || !get_init_hash(hasher, message, &hash))
! 1314: {
! 1315: DBG1(DBG_MGR, "ignoring message, failed to hash message");
! 1316: DESTROY_IF(hasher);
! 1317: id->destroy(id);
! 1318: goto out;
! 1319: }
! 1320: hasher->destroy(hasher);
! 1321:
! 1322: /* ensure this is not a retransmit of an already handled init message */
! 1323: switch (check_and_put_init_hash(this, hash, &our_spi))
! 1324: {
! 1325: case NOT_FOUND:
! 1326: { /* we've not seen this packet yet, create a new IKE_SA */
! 1327: if (!this->ikesa_limit ||
! 1328: this->public.get_count(&this->public) < this->ikesa_limit)
! 1329: {
! 1330: id->set_responder_spi(id, our_spi);
! 1331: ike_sa = ike_sa_create(id, FALSE, ike_version);
! 1332: if (ike_sa)
! 1333: {
! 1334: entry = entry_create();
! 1335: entry->ike_sa = ike_sa;
! 1336: entry->ike_sa_id = id;
! 1337: entry->processing = get_message_id_or_hash(message);
! 1338: entry->init_hash = hash;
! 1339:
! 1340: segment = put_entry(this, entry);
! 1341: entry->checked_out = thread_current();
! 1342: unlock_single_segment(this, segment);
! 1343:
! 1344: DBG2(DBG_MGR, "created IKE_SA %s[%u]",
! 1345: ike_sa->get_name(ike_sa),
! 1346: ike_sa->get_unique_id(ike_sa));
! 1347: goto out;
! 1348: }
! 1349: else
! 1350: {
! 1351: DBG1(DBG_MGR, "creating IKE_SA failed, ignoring message");
! 1352: }
! 1353: }
! 1354: else
! 1355: {
! 1356: DBG1(DBG_MGR, "ignoring %N, hitting IKE_SA limit (%u)",
! 1357: exchange_type_names, message->get_exchange_type(message),
! 1358: this->ikesa_limit);
! 1359: }
! 1360: remove_init_hash(this, hash);
! 1361: chunk_free(&hash);
! 1362: id->destroy(id);
! 1363: goto out;
! 1364: }
! 1365: case FAILED:
! 1366: { /* we failed to allocate an SPI */
! 1367: chunk_free(&hash);
! 1368: id->destroy(id);
! 1369: DBG1(DBG_MGR, "ignoring message, failed to allocate SPI");
! 1370: goto out;
! 1371: }
! 1372: case ALREADY_DONE:
! 1373: default:
! 1374: break;
! 1375: }
! 1376: /* it looks like we already handled this init message to some degree */
! 1377: id->set_responder_spi(id, our_spi);
! 1378: chunk_free(&hash);
! 1379: }
! 1380:
! 1381: if (get_entry_by_id(this, id, &entry, &segment) == SUCCESS)
! 1382: {
! 1383: /* only check out if we are not already processing it. */
! 1384: if (entry->processing == get_message_id_or_hash(message))
! 1385: {
! 1386: DBG1(DBG_MGR, "ignoring request with ID %u, already processing",
! 1387: entry->processing);
! 1388: }
! 1389: else if (wait_for_entry(this, entry, segment))
! 1390: {
! 1391: ike_sa_id_t *ike_id;
! 1392:
! 1393: ike_id = entry->ike_sa->get_id(entry->ike_sa);
! 1394: entry->checked_out = thread_current();
! 1395: if (message->get_first_payload_type(message) != PLV1_FRAGMENT &&
! 1396: message->get_first_payload_type(message) != PLV2_FRAGMENT)
! 1397: { /* TODO-FRAG: this fails if there are unencrypted payloads */
! 1398: entry->processing = get_message_id_or_hash(message);
! 1399: }
! 1400: if (ike_id->get_responder_spi(ike_id) == 0)
! 1401: {
! 1402: ike_id->set_responder_spi(ike_id, id->get_responder_spi(id));
! 1403: }
! 1404: ike_sa = entry->ike_sa;
! 1405: DBG2(DBG_MGR, "IKE_SA %s[%u] successfully checked out",
! 1406: ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa));
! 1407: }
! 1408: unlock_single_segment(this, segment);
! 1409: }
! 1410: else
! 1411: {
! 1412: charon->bus->alert(charon->bus, ALERT_INVALID_IKE_SPI, message);
! 1413: }
! 1414: id->destroy(id);
! 1415:
! 1416: out:
! 1417: charon->bus->set_sa(charon->bus, ike_sa);
! 1418: if (!ike_sa)
! 1419: {
! 1420: DBG2(DBG_MGR, "IKE_SA checkout not successful");
! 1421: }
! 1422: return ike_sa;
! 1423: }
! 1424:
! 1425: METHOD(ike_sa_manager_t, checkout_by_config, ike_sa_t*,
! 1426: private_ike_sa_manager_t *this, peer_cfg_t *peer_cfg)
! 1427: {
! 1428: enumerator_t *enumerator;
! 1429: entry_t *entry;
! 1430: ike_sa_t *ike_sa = NULL;
! 1431: peer_cfg_t *current_peer;
! 1432: ike_cfg_t *current_ike;
! 1433: u_int segment;
! 1434:
! 1435: DBG2(DBG_MGR, "checkout IKE_SA by config");
! 1436:
! 1437: if (!this->reuse_ikesa && peer_cfg->get_ike_version(peer_cfg) != IKEV1)
! 1438: { /* IKE_SA reuse disabled by config (not possible for IKEv1) */
! 1439: ike_sa = checkout_new(this, peer_cfg->get_ike_version(peer_cfg), TRUE);
! 1440: charon->bus->set_sa(charon->bus, ike_sa);
! 1441: goto out;
! 1442: }
! 1443:
! 1444: enumerator = create_table_enumerator(this);
! 1445: while (enumerator->enumerate(enumerator, &entry, &segment))
! 1446: {
! 1447: if (!wait_for_entry(this, entry, segment))
! 1448: {
! 1449: continue;
! 1450: }
! 1451: if (entry->ike_sa->get_state(entry->ike_sa) == IKE_DELETING ||
! 1452: entry->ike_sa->get_state(entry->ike_sa) == IKE_REKEYED)
! 1453: { /* skip IKE_SAs which are not usable, wake other waiting threads */
! 1454: entry->condvar->signal(entry->condvar);
! 1455: continue;
! 1456: }
! 1457:
! 1458: current_peer = entry->ike_sa->get_peer_cfg(entry->ike_sa);
! 1459: if (current_peer && current_peer->equals(current_peer, peer_cfg))
! 1460: {
! 1461: current_ike = current_peer->get_ike_cfg(current_peer);
! 1462: if (current_ike->equals(current_ike, peer_cfg->get_ike_cfg(peer_cfg)))
! 1463: {
! 1464: entry->checked_out = thread_current();
! 1465: ike_sa = entry->ike_sa;
! 1466: DBG2(DBG_MGR, "found existing IKE_SA %u with a '%s' config",
! 1467: ike_sa->get_unique_id(ike_sa),
! 1468: current_peer->get_name(current_peer));
! 1469: break;
! 1470: }
! 1471: }
! 1472: /* other threads might be waiting for this entry */
! 1473: entry->condvar->signal(entry->condvar);
! 1474: }
! 1475: enumerator->destroy(enumerator);
! 1476:
! 1477: if (!ike_sa)
! 1478: { /* no IKE_SA using such a config, hand out a new */
! 1479: ike_sa = checkout_new(this, peer_cfg->get_ike_version(peer_cfg), TRUE);
! 1480: }
! 1481: charon->bus->set_sa(charon->bus, ike_sa);
! 1482:
! 1483: out:
! 1484: if (!ike_sa)
! 1485: {
! 1486: DBG2(DBG_MGR, "IKE_SA checkout not successful");
! 1487: }
! 1488: return ike_sa;
! 1489: }
! 1490:
! 1491: METHOD(ike_sa_manager_t, checkout_by_id, ike_sa_t*,
! 1492: private_ike_sa_manager_t *this, uint32_t id)
! 1493: {
! 1494: enumerator_t *enumerator;
! 1495: entry_t *entry;
! 1496: ike_sa_t *ike_sa = NULL;
! 1497: u_int segment;
! 1498:
! 1499: DBG2(DBG_MGR, "checkout IKE_SA by unique ID %u", id);
! 1500:
! 1501: enumerator = create_table_enumerator(this);
! 1502: while (enumerator->enumerate(enumerator, &entry, &segment))
! 1503: {
! 1504: if (wait_for_entry(this, entry, segment))
! 1505: {
! 1506: if (entry->ike_sa->get_unique_id(entry->ike_sa) == id)
! 1507: {
! 1508: ike_sa = entry->ike_sa;
! 1509: entry->checked_out = thread_current();
! 1510: break;
! 1511: }
! 1512: /* other threads might be waiting for this entry */
! 1513: entry->condvar->signal(entry->condvar);
! 1514: }
! 1515: }
! 1516: enumerator->destroy(enumerator);
! 1517:
! 1518: if (ike_sa)
! 1519: {
! 1520: DBG2(DBG_MGR, "IKE_SA %s[%u] successfully checked out",
! 1521: ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa));
! 1522: }
! 1523: else
! 1524: {
! 1525: DBG2(DBG_MGR, "IKE_SA checkout not successful");
! 1526: }
! 1527: charon->bus->set_sa(charon->bus, ike_sa);
! 1528: return ike_sa;
! 1529: }
! 1530:
! 1531: METHOD(ike_sa_manager_t, checkout_by_name, ike_sa_t*,
! 1532: private_ike_sa_manager_t *this, char *name, bool child)
! 1533: {
! 1534: enumerator_t *enumerator, *children;
! 1535: entry_t *entry;
! 1536: ike_sa_t *ike_sa = NULL;
! 1537: child_sa_t *child_sa;
! 1538: u_int segment;
! 1539:
! 1540: DBG2(DBG_MGR, "checkout IKE_SA by%s name '%s'", child ? " child" : "", name);
! 1541:
! 1542: enumerator = create_table_enumerator(this);
! 1543: while (enumerator->enumerate(enumerator, &entry, &segment))
! 1544: {
! 1545: if (wait_for_entry(this, entry, segment))
! 1546: {
! 1547: /* look for a child with such a policy name ... */
! 1548: if (child)
! 1549: {
! 1550: children = entry->ike_sa->create_child_sa_enumerator(entry->ike_sa);
! 1551: while (children->enumerate(children, (void**)&child_sa))
! 1552: {
! 1553: if (streq(child_sa->get_name(child_sa), name))
! 1554: {
! 1555: ike_sa = entry->ike_sa;
! 1556: break;
! 1557: }
! 1558: }
! 1559: children->destroy(children);
! 1560: }
! 1561: else /* ... or for a IKE_SA with such a connection name */
! 1562: {
! 1563: if (streq(entry->ike_sa->get_name(entry->ike_sa), name))
! 1564: {
! 1565: ike_sa = entry->ike_sa;
! 1566: }
! 1567: }
! 1568: /* got one, return */
! 1569: if (ike_sa)
! 1570: {
! 1571: entry->checked_out = thread_current();
! 1572: DBG2(DBG_MGR, "IKE_SA %s[%u] successfully checked out",
! 1573: ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa));
! 1574: break;
! 1575: }
! 1576: /* other threads might be waiting for this entry */
! 1577: entry->condvar->signal(entry->condvar);
! 1578: }
! 1579: }
! 1580: enumerator->destroy(enumerator);
! 1581:
! 1582: charon->bus->set_sa(charon->bus, ike_sa);
! 1583:
! 1584: if (!ike_sa)
! 1585: {
! 1586: DBG2(DBG_MGR, "IKE_SA checkout not successful");
! 1587: }
! 1588: return ike_sa;
! 1589: }
! 1590:
! 1591: METHOD(ike_sa_manager_t, new_initiator_spi, bool,
! 1592: private_ike_sa_manager_t *this, ike_sa_t *ike_sa)
! 1593: {
! 1594: ike_sa_state_t state;
! 1595: ike_sa_id_t *ike_sa_id;
! 1596: entry_t *entry;
! 1597: u_int segment;
! 1598: uint64_t new_spi, spi;
! 1599:
! 1600: state = ike_sa->get_state(ike_sa);
! 1601: if (state != IKE_CONNECTING)
! 1602: {
! 1603: DBG1(DBG_MGR, "unable to change initiator SPI for IKE_SA in state "
! 1604: "%N", ike_sa_state_names, state);
! 1605: return FALSE;
! 1606: }
! 1607:
! 1608: ike_sa_id = ike_sa->get_id(ike_sa);
! 1609: if (!ike_sa_id->is_initiator(ike_sa_id))
! 1610: {
! 1611: DBG1(DBG_MGR, "unable to change initiator SPI of IKE_SA as responder");
! 1612: return FALSE;
! 1613: }
! 1614:
! 1615: if (ike_sa != charon->bus->get_sa(charon->bus))
! 1616: {
! 1617: DBG1(DBG_MGR, "unable to change initiator SPI of IKE_SA not checked "
! 1618: "out by current thread");
! 1619: return FALSE;
! 1620: }
! 1621:
! 1622: new_spi = get_spi(this);
! 1623: if (!new_spi)
! 1624: {
! 1625: DBG1(DBG_MGR, "unable to allocate new initiator SPI for IKE_SA");
! 1626: return FALSE;
! 1627: }
! 1628:
! 1629: if (get_entry_by_sa(this, ike_sa_id, ike_sa, &entry, &segment) == SUCCESS)
! 1630: {
! 1631: if (entry->driveout_waiting_threads && entry->driveout_new_threads)
! 1632: { /* it looks like flush() has been called and the SA is being deleted
! 1633: * anyway, no need for a new SPI */
! 1634: DBG2(DBG_MGR, "ignored change of initiator SPI during shutdown");
! 1635: unlock_single_segment(this, segment);
! 1636: return FALSE;
! 1637: }
! 1638: }
! 1639: else
! 1640: {
! 1641: DBG1(DBG_MGR, "unable to change initiator SPI of IKE_SA, not found");
! 1642: return FALSE;
! 1643: }
! 1644:
! 1645: /* the hashtable row and segment are determined by the local SPI as
! 1646: * initiator, so if we change it the row and segment derived from it might
! 1647: * change as well. This could be a problem for threads waiting for the
! 1648: * entry (in particular those enumerating entries to check them out by
! 1649: * unique ID or name). In order to avoid having to drive them out and thus
! 1650: * preventing them from checking out the entry (even though the ID or name
! 1651: * will not change and enumerating it is also fine), we mask the new SPI and
! 1652: * merge it with the old SPI so the entry ends up in the same row/segment.
! 1653: * Since SPIs are 64-bit and the number of rows/segments is usually
! 1654: * relatively low this should not be a problem. */
! 1655: spi = ike_sa_id->get_initiator_spi(ike_sa_id);
! 1656: new_spi = (spi & (uint64_t)this->table_mask) |
! 1657: (new_spi & ~(uint64_t)this->table_mask);
! 1658:
! 1659: DBG2(DBG_MGR, "change initiator SPI of IKE_SA %s[%u] from %.16"PRIx64" to "
! 1660: "%.16"PRIx64, ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa),
! 1661: be64toh(spi), be64toh(new_spi));
! 1662:
! 1663: ike_sa_id->set_initiator_spi(ike_sa_id, new_spi);
! 1664: entry->ike_sa_id->replace_values(entry->ike_sa_id, ike_sa_id);
! 1665:
! 1666: entry->condvar->signal(entry->condvar);
! 1667: unlock_single_segment(this, segment);
! 1668: return TRUE;
! 1669: }
! 1670:
! 1671: CALLBACK(enumerator_filter_wait, bool,
! 1672: private_ike_sa_manager_t *this, enumerator_t *orig, va_list args)
! 1673: {
! 1674: entry_t *entry;
! 1675: u_int segment;
! 1676: ike_sa_t **out;
! 1677:
! 1678: VA_ARGS_VGET(args, out);
! 1679:
! 1680: while (orig->enumerate(orig, &entry, &segment))
! 1681: {
! 1682: if (wait_for_entry(this, entry, segment))
! 1683: {
! 1684: *out = entry->ike_sa;
! 1685: charon->bus->set_sa(charon->bus, *out);
! 1686: return TRUE;
! 1687: }
! 1688: }
! 1689: return FALSE;
! 1690: }
! 1691:
! 1692: CALLBACK(enumerator_filter_skip, bool,
! 1693: private_ike_sa_manager_t *this, enumerator_t *orig, va_list args)
! 1694: {
! 1695: entry_t *entry;
! 1696: u_int segment;
! 1697: ike_sa_t **out;
! 1698:
! 1699: VA_ARGS_VGET(args, out);
! 1700:
! 1701: while (orig->enumerate(orig, &entry, &segment))
! 1702: {
! 1703: if (!entry->driveout_new_threads &&
! 1704: !entry->driveout_waiting_threads &&
! 1705: !entry->checked_out)
! 1706: {
! 1707: *out = entry->ike_sa;
! 1708: charon->bus->set_sa(charon->bus, *out);
! 1709: return TRUE;
! 1710: }
! 1711: }
! 1712: return FALSE;
! 1713: }
! 1714:
! 1715: CALLBACK(reset_sa, void,
! 1716: void *data)
! 1717: {
! 1718: charon->bus->set_sa(charon->bus, NULL);
! 1719: }
! 1720:
! 1721: METHOD(ike_sa_manager_t, create_enumerator, enumerator_t*,
! 1722: private_ike_sa_manager_t* this, bool wait)
! 1723: {
! 1724: return enumerator_create_filter(create_table_enumerator(this),
! 1725: wait ? (void*)enumerator_filter_wait : (void*)enumerator_filter_skip,
! 1726: this, reset_sa);
! 1727: }
! 1728:
! 1729: METHOD(ike_sa_manager_t, checkin, void,
! 1730: private_ike_sa_manager_t *this, ike_sa_t *ike_sa)
! 1731: {
! 1732: /* to check the SA back in, we look for the pointer of the ike_sa
! 1733: * in all entries.
! 1734: * The lookup is done by initiator SPI, so even if the SPI has changed (e.g.
! 1735: * on reception of a IKE_SA_INIT response) the lookup will work but
! 1736: * updating of the SPI MAY be necessary...
! 1737: */
! 1738: entry_t *entry;
! 1739: ike_sa_id_t *ike_sa_id;
! 1740: host_t *other;
! 1741: identification_t *my_id, *other_id;
! 1742: u_int segment;
! 1743:
! 1744: ike_sa_id = ike_sa->get_id(ike_sa);
! 1745: my_id = ike_sa->get_my_id(ike_sa);
! 1746: other_id = ike_sa->get_other_eap_id(ike_sa);
! 1747: other = ike_sa->get_other_host(ike_sa);
! 1748:
! 1749: DBG2(DBG_MGR, "checkin IKE_SA %s[%u]", ike_sa->get_name(ike_sa),
! 1750: ike_sa->get_unique_id(ike_sa));
! 1751:
! 1752: /* look for the entry */
! 1753: if (get_entry_by_sa(this, ike_sa_id, ike_sa, &entry, &segment) == SUCCESS)
! 1754: {
! 1755: /* ike_sa_id must be updated */
! 1756: entry->ike_sa_id->replace_values(entry->ike_sa_id, ike_sa->get_id(ike_sa));
! 1757: /* signal waiting threads */
! 1758: entry->checked_out = NULL;
! 1759: entry->processing = -1;
! 1760: /* check if this SA is half-open */
! 1761: if (entry->half_open && ike_sa->get_state(ike_sa) != IKE_CONNECTING)
! 1762: {
! 1763: /* not half open anymore */
! 1764: entry->half_open = FALSE;
! 1765: remove_half_open(this, entry);
! 1766: }
! 1767: else if (entry->half_open && !other->ip_equals(other, entry->other))
! 1768: {
! 1769: /* the other host's IP has changed, we must update the hash table */
! 1770: remove_half_open(this, entry);
! 1771: DESTROY_IF(entry->other);
! 1772: entry->other = other->clone(other);
! 1773: put_half_open(this, entry);
! 1774: }
! 1775: else if (!entry->half_open &&
! 1776: ike_sa->get_state(ike_sa) == IKE_CONNECTING)
! 1777: {
! 1778: /* this is a new half-open SA */
! 1779: entry->half_open = TRUE;
! 1780: entry->other = other->clone(other);
! 1781: put_half_open(this, entry);
! 1782: }
! 1783: entry->condvar->signal(entry->condvar);
! 1784: }
! 1785: else
! 1786: {
! 1787: entry = entry_create();
! 1788: entry->ike_sa_id = ike_sa_id->clone(ike_sa_id);
! 1789: entry->ike_sa = ike_sa;
! 1790: if (ike_sa->get_state(ike_sa) == IKE_CONNECTING)
! 1791: {
! 1792: entry->half_open = TRUE;
! 1793: entry->other = other->clone(other);
! 1794: put_half_open(this, entry);
! 1795: }
! 1796: segment = put_entry(this, entry);
! 1797: }
! 1798: DBG2(DBG_MGR, "checkin of IKE_SA successful");
! 1799:
! 1800: /* apply identities for duplicate test */
! 1801: if ((ike_sa->get_state(ike_sa) == IKE_ESTABLISHED ||
! 1802: ike_sa->get_state(ike_sa) == IKE_PASSIVE) &&
! 1803: entry->my_id == NULL && entry->other_id == NULL)
! 1804: {
! 1805: if (ike_sa->get_version(ike_sa) == IKEV1)
! 1806: {
! 1807: /* If authenticated and received INITIAL_CONTACT,
! 1808: * delete any existing IKE_SAs with that peer. */
! 1809: if (ike_sa->has_condition(ike_sa, COND_INIT_CONTACT_SEEN))
! 1810: {
! 1811: /* We can't hold the segment locked while checking the
! 1812: * uniqueness as this could lead to deadlocks. We mark the
! 1813: * entry as checked out while we release the lock so no other
! 1814: * thread can acquire it. Since it is not yet in the list of
! 1815: * connected peers that will not cause a deadlock as no other
! 1816: * caller of check_uniqueness() will try to check out this SA */
! 1817: entry->checked_out = thread_current();
! 1818: unlock_single_segment(this, segment);
! 1819:
! 1820: this->public.check_uniqueness(&this->public, ike_sa, TRUE);
! 1821: ike_sa->set_condition(ike_sa, COND_INIT_CONTACT_SEEN, FALSE);
! 1822:
! 1823: /* The entry could have been modified in the mean time, e.g.
! 1824: * because another SA was added/removed next to it or another
! 1825: * thread is waiting, but it should still exist, so there is no
! 1826: * need for a lookup via get_entry_by... */
! 1827: lock_single_segment(this, segment);
! 1828: entry->checked_out = NULL;
! 1829: /* We already signaled waiting threads above, we have to do that
! 1830: * again after checking the SA out and back in again. */
! 1831: entry->condvar->signal(entry->condvar);
! 1832: }
! 1833: }
! 1834:
! 1835: entry->my_id = my_id->clone(my_id);
! 1836: entry->other_id = other_id->clone(other_id);
! 1837: if (!entry->other)
! 1838: {
! 1839: entry->other = other->clone(other);
! 1840: }
! 1841: put_connected_peers(this, entry);
! 1842: }
! 1843:
! 1844: unlock_single_segment(this, segment);
! 1845:
! 1846: charon->bus->set_sa(charon->bus, NULL);
! 1847: }
! 1848:
! 1849: METHOD(ike_sa_manager_t, checkin_and_destroy, void,
! 1850: private_ike_sa_manager_t *this, ike_sa_t *ike_sa)
! 1851: {
! 1852: /* deletion is a bit complex, we must ensure that no thread is waiting for
! 1853: * this SA.
! 1854: * We take this SA from the table, and start signaling while threads
! 1855: * are in the condvar.
! 1856: */
! 1857: entry_t *entry;
! 1858: ike_sa_id_t *ike_sa_id;
! 1859: u_int segment;
! 1860:
! 1861: ike_sa_id = ike_sa->get_id(ike_sa);
! 1862:
! 1863: DBG2(DBG_MGR, "checkin and destroy IKE_SA %s[%u]", ike_sa->get_name(ike_sa),
! 1864: ike_sa->get_unique_id(ike_sa));
! 1865:
! 1866: if (get_entry_by_sa(this, ike_sa_id, ike_sa, &entry, &segment) == SUCCESS)
! 1867: {
! 1868: if (entry->driveout_waiting_threads && entry->driveout_new_threads)
! 1869: { /* it looks like flush() has been called and the SA is being deleted
! 1870: * anyway, just check it in */
! 1871: DBG2(DBG_MGR, "ignored checkin and destroy of IKE_SA during shutdown");
! 1872: entry->checked_out = NULL;
! 1873: entry->condvar->broadcast(entry->condvar);
! 1874: unlock_single_segment(this, segment);
! 1875: return;
! 1876: }
! 1877:
! 1878: /* drive out waiting threads, as we are in hurry */
! 1879: entry->driveout_waiting_threads = TRUE;
! 1880: /* mark it, so no new threads can get this entry */
! 1881: entry->driveout_new_threads = TRUE;
! 1882: /* wait until all workers have done their work */
! 1883: while (entry->waiting_threads)
! 1884: {
! 1885: /* wake up all */
! 1886: entry->condvar->broadcast(entry->condvar);
! 1887: /* they will wake us again when their work is done */
! 1888: entry->condvar->wait(entry->condvar, this->segments[segment].mutex);
! 1889: }
! 1890: remove_entry(this, entry);
! 1891: unlock_single_segment(this, segment);
! 1892:
! 1893: if (entry->half_open)
! 1894: {
! 1895: remove_half_open(this, entry);
! 1896: }
! 1897: if (entry->my_id && entry->other_id)
! 1898: {
! 1899: remove_connected_peers(this, entry);
! 1900: }
! 1901: if (entry->init_hash.ptr)
! 1902: {
! 1903: remove_init_hash(this, entry->init_hash);
! 1904: }
! 1905:
! 1906: entry_destroy(entry);
! 1907:
! 1908: DBG2(DBG_MGR, "checkin and destroy of IKE_SA successful");
! 1909: }
! 1910: else
! 1911: {
! 1912: DBG1(DBG_MGR, "tried to checkin and delete nonexistent IKE_SA");
! 1913: ike_sa->destroy(ike_sa);
! 1914: }
! 1915: charon->bus->set_sa(charon->bus, NULL);
! 1916: }
! 1917:
! 1918: /**
! 1919: * Cleanup function for create_id_enumerator
! 1920: */
! 1921: static void id_enumerator_cleanup(linked_list_t *ids)
! 1922: {
! 1923: ids->destroy_offset(ids, offsetof(ike_sa_id_t, destroy));
! 1924: }
! 1925:
! 1926: METHOD(ike_sa_manager_t, create_id_enumerator, enumerator_t*,
! 1927: private_ike_sa_manager_t *this, identification_t *me,
! 1928: identification_t *other, int family)
! 1929: {
! 1930: table_item_t *item;
! 1931: u_int row, segment;
! 1932: rwlock_t *lock;
! 1933: linked_list_t *ids = NULL;
! 1934:
! 1935: row = chunk_hash_inc(other->get_encoding(other),
! 1936: chunk_hash(me->get_encoding(me))) & this->table_mask;
! 1937: segment = row & this->segment_mask;
! 1938:
! 1939: lock = this->connected_peers_segments[segment].lock;
! 1940: lock->read_lock(lock);
! 1941: item = this->connected_peers_table[row];
! 1942: while (item)
! 1943: {
! 1944: connected_peers_t *current = item->value;
! 1945:
! 1946: if (connected_peers_match(current, me, other, family))
! 1947: {
! 1948: ids = current->sas->clone_offset(current->sas,
! 1949: offsetof(ike_sa_id_t, clone));
! 1950: break;
! 1951: }
! 1952: item = item->next;
! 1953: }
! 1954: lock->unlock(lock);
! 1955:
! 1956: if (!ids)
! 1957: {
! 1958: return enumerator_create_empty();
! 1959: }
! 1960: return enumerator_create_cleaner(ids->create_enumerator(ids),
! 1961: (void*)id_enumerator_cleanup, ids);
! 1962: }
! 1963:
! 1964: /**
! 1965: * Move all CHILD_SAs and virtual IPs from old to new
! 1966: */
! 1967: static void adopt_children_and_vips(ike_sa_t *old, ike_sa_t *new)
! 1968: {
! 1969: enumerator_t *enumerator;
! 1970: child_sa_t *child_sa;
! 1971: host_t *vip;
! 1972: int chcount = 0, vipcount = 0;
! 1973:
! 1974: charon->bus->children_migrate(charon->bus, new->get_id(new),
! 1975: new->get_unique_id(new));
! 1976: enumerator = old->create_child_sa_enumerator(old);
! 1977: while (enumerator->enumerate(enumerator, &child_sa))
! 1978: {
! 1979: old->remove_child_sa(old, enumerator);
! 1980: new->add_child_sa(new, child_sa);
! 1981: chcount++;
! 1982: }
! 1983: enumerator->destroy(enumerator);
! 1984:
! 1985: new->adopt_child_tasks(new, old);
! 1986:
! 1987: enumerator = old->create_virtual_ip_enumerator(old, FALSE);
! 1988: while (enumerator->enumerate(enumerator, &vip))
! 1989: {
! 1990: new->add_virtual_ip(new, FALSE, vip);
! 1991: vipcount++;
! 1992: }
! 1993: enumerator->destroy(enumerator);
! 1994: /* this does not release the addresses, which is good, but it does trigger
! 1995: * an assign_vips(FALSE) event... */
! 1996: old->clear_virtual_ips(old, FALSE);
! 1997: /* ...trigger the analogous event on the new SA */
! 1998: charon->bus->set_sa(charon->bus, new);
! 1999: charon->bus->assign_vips(charon->bus, new, TRUE);
! 2000: charon->bus->children_migrate(charon->bus, NULL, 0);
! 2001: charon->bus->set_sa(charon->bus, old);
! 2002:
! 2003: if (chcount || vipcount)
! 2004: {
! 2005: DBG1(DBG_IKE, "detected reauth of existing IKE_SA, adopting %d "
! 2006: "children and %d virtual IPs", chcount, vipcount);
! 2007: }
! 2008: }
! 2009:
! 2010: /**
! 2011: * Delete an existing IKE_SA due to a unique replace policy
! 2012: */
! 2013: static status_t enforce_replace(private_ike_sa_manager_t *this,
! 2014: ike_sa_t *duplicate, ike_sa_t *new,
! 2015: identification_t *other, host_t *host)
! 2016: {
! 2017: charon->bus->alert(charon->bus, ALERT_UNIQUE_REPLACE);
! 2018:
! 2019: if (host->equals(host, duplicate->get_other_host(duplicate)))
! 2020: {
! 2021: /* looks like a reauthentication attempt */
! 2022: if (!new->has_condition(new, COND_INIT_CONTACT_SEEN) &&
! 2023: new->get_version(new) == IKEV1)
! 2024: {
! 2025: /* IKEv1 implicitly takes over children, IKEv2 recreates them
! 2026: * explicitly. */
! 2027: adopt_children_and_vips(duplicate, new);
! 2028: }
! 2029: /* For IKEv1 we have to delay the delete for the old IKE_SA. Some
! 2030: * peers need to complete the new SA first, otherwise the quick modes
! 2031: * might get lost. For IKEv2 we do the same, as we want overlapping
! 2032: * CHILD_SAs to keep connectivity up. */
! 2033: lib->scheduler->schedule_job(lib->scheduler, (job_t*)
! 2034: delete_ike_sa_job_create(duplicate->get_id(duplicate), TRUE), 10);
! 2035: DBG1(DBG_IKE, "schedule delete of duplicate IKE_SA for peer '%Y' due "
! 2036: "to uniqueness policy and suspected reauthentication", other);
! 2037: return SUCCESS;
! 2038: }
! 2039: DBG1(DBG_IKE, "deleting duplicate IKE_SA for peer '%Y' due to "
! 2040: "uniqueness policy", other);
! 2041: return duplicate->delete(duplicate, FALSE);
! 2042: }
! 2043:
! 2044: METHOD(ike_sa_manager_t, check_uniqueness, bool,
! 2045: private_ike_sa_manager_t *this, ike_sa_t *ike_sa, bool force_replace)
! 2046: {
! 2047: bool cancel = FALSE;
! 2048: peer_cfg_t *peer_cfg;
! 2049: unique_policy_t policy;
! 2050: enumerator_t *enumerator;
! 2051: ike_sa_id_t *id = NULL;
! 2052: identification_t *me, *other;
! 2053: host_t *other_host;
! 2054:
! 2055: peer_cfg = ike_sa->get_peer_cfg(ike_sa);
! 2056: policy = peer_cfg->get_unique_policy(peer_cfg);
! 2057: if (policy == UNIQUE_NEVER || (policy == UNIQUE_NO && !force_replace))
! 2058: {
! 2059: return FALSE;
! 2060: }
! 2061: me = ike_sa->get_my_id(ike_sa);
! 2062: other = ike_sa->get_other_eap_id(ike_sa);
! 2063: other_host = ike_sa->get_other_host(ike_sa);
! 2064:
! 2065: enumerator = create_id_enumerator(this, me, other,
! 2066: other_host->get_family(other_host));
! 2067: while (enumerator->enumerate(enumerator, &id))
! 2068: {
! 2069: status_t status = SUCCESS;
! 2070: ike_sa_t *duplicate;
! 2071:
! 2072: duplicate = checkout(this, id);
! 2073: if (!duplicate)
! 2074: {
! 2075: continue;
! 2076: }
! 2077: if (force_replace)
! 2078: {
! 2079: DBG1(DBG_IKE, "destroying duplicate IKE_SA for peer '%Y', "
! 2080: "received INITIAL_CONTACT", other);
! 2081: charon->bus->ike_updown(charon->bus, duplicate, FALSE);
! 2082: checkin_and_destroy(this, duplicate);
! 2083: continue;
! 2084: }
! 2085: peer_cfg = duplicate->get_peer_cfg(duplicate);
! 2086: if (peer_cfg && peer_cfg->equals(peer_cfg, ike_sa->get_peer_cfg(ike_sa)))
! 2087: {
! 2088: switch (duplicate->get_state(duplicate))
! 2089: {
! 2090: case IKE_ESTABLISHED:
! 2091: case IKE_REKEYING:
! 2092: switch (policy)
! 2093: {
! 2094: case UNIQUE_REPLACE:
! 2095: status = enforce_replace(this, duplicate, ike_sa,
! 2096: other, other_host);
! 2097: break;
! 2098: case UNIQUE_KEEP:
! 2099: /* potential reauthentication? */
! 2100: if (!other_host->equals(other_host,
! 2101: duplicate->get_other_host(duplicate)))
! 2102: {
! 2103: cancel = TRUE;
! 2104: /* we keep the first IKE_SA and delete all
! 2105: * other duplicates that might exist */
! 2106: policy = UNIQUE_REPLACE;
! 2107: }
! 2108: break;
! 2109: default:
! 2110: break;
! 2111: }
! 2112: break;
! 2113: default:
! 2114: break;
! 2115: }
! 2116: }
! 2117: if (status == DESTROY_ME)
! 2118: {
! 2119: checkin_and_destroy(this, duplicate);
! 2120: }
! 2121: else
! 2122: {
! 2123: checkin(this, duplicate);
! 2124: }
! 2125: }
! 2126: enumerator->destroy(enumerator);
! 2127: /* reset thread's current IKE_SA after checkin */
! 2128: charon->bus->set_sa(charon->bus, ike_sa);
! 2129: return cancel;
! 2130: }
! 2131:
! 2132: METHOD(ike_sa_manager_t, has_contact, bool,
! 2133: private_ike_sa_manager_t *this, identification_t *me,
! 2134: identification_t *other, int family)
! 2135: {
! 2136: table_item_t *item;
! 2137: u_int row, segment;
! 2138: rwlock_t *lock;
! 2139: bool found = FALSE;
! 2140:
! 2141: row = chunk_hash_inc(other->get_encoding(other),
! 2142: chunk_hash(me->get_encoding(me))) & this->table_mask;
! 2143: segment = row & this->segment_mask;
! 2144: lock = this->connected_peers_segments[segment].lock;
! 2145: lock->read_lock(lock);
! 2146: item = this->connected_peers_table[row];
! 2147: while (item)
! 2148: {
! 2149: if (connected_peers_match(item->value, me, other, family))
! 2150: {
! 2151: found = TRUE;
! 2152: break;
! 2153: }
! 2154: item = item->next;
! 2155: }
! 2156: lock->unlock(lock);
! 2157:
! 2158: return found;
! 2159: }
! 2160:
! 2161: METHOD(ike_sa_manager_t, get_count, u_int,
! 2162: private_ike_sa_manager_t *this)
! 2163: {
! 2164: return (u_int)ref_cur(&this->total_sa_count);
! 2165: }
! 2166:
! 2167: METHOD(ike_sa_manager_t, get_half_open_count, u_int,
! 2168: private_ike_sa_manager_t *this, host_t *ip, bool responder_only)
! 2169: {
! 2170: table_item_t *item;
! 2171: u_int row, segment;
! 2172: rwlock_t *lock;
! 2173: chunk_t addr;
! 2174: u_int count = 0;
! 2175:
! 2176: if (ip)
! 2177: {
! 2178: addr = ip->get_address(ip);
! 2179: row = chunk_hash(addr) & this->table_mask;
! 2180: segment = row & this->segment_mask;
! 2181: lock = this->half_open_segments[segment].lock;
! 2182: lock->read_lock(lock);
! 2183: item = this->half_open_table[row];
! 2184: while (item)
! 2185: {
! 2186: half_open_t *half_open = item->value;
! 2187:
! 2188: if (chunk_equals(addr, half_open->other))
! 2189: {
! 2190: count = responder_only ? half_open->count_responder
! 2191: : half_open->count;
! 2192: break;
! 2193: }
! 2194: item = item->next;
! 2195: }
! 2196: lock->unlock(lock);
! 2197: }
! 2198: else
! 2199: {
! 2200: count = responder_only ? (u_int)ref_cur(&this->half_open_count_responder)
! 2201: : (u_int)ref_cur(&this->half_open_count);
! 2202: }
! 2203: return count;
! 2204: }
! 2205:
! 2206: METHOD(ike_sa_manager_t, set_spi_cb, void,
! 2207: private_ike_sa_manager_t *this, spi_cb_t callback, void *data)
! 2208: {
! 2209: this->spi_lock->write_lock(this->spi_lock);
! 2210: this->spi_cb.cb = callback;
! 2211: this->spi_cb.data = data;
! 2212: this->spi_lock->unlock(this->spi_lock);
! 2213: }
! 2214:
! 2215: /**
! 2216: * Destroy all entries
! 2217: */
! 2218: static void destroy_all_entries(private_ike_sa_manager_t *this)
! 2219: {
! 2220: enumerator_t *enumerator;
! 2221: entry_t *entry;
! 2222: u_int segment;
! 2223:
! 2224: enumerator = create_table_enumerator(this);
! 2225: while (enumerator->enumerate(enumerator, &entry, &segment))
! 2226: {
! 2227: charon->bus->set_sa(charon->bus, entry->ike_sa);
! 2228: if (entry->half_open)
! 2229: {
! 2230: remove_half_open(this, entry);
! 2231: }
! 2232: if (entry->my_id && entry->other_id)
! 2233: {
! 2234: remove_connected_peers(this, entry);
! 2235: }
! 2236: if (entry->init_hash.ptr)
! 2237: {
! 2238: remove_init_hash(this, entry->init_hash);
! 2239: }
! 2240: remove_entry_at((private_enumerator_t*)enumerator);
! 2241: entry_destroy(entry);
! 2242: }
! 2243: enumerator->destroy(enumerator);
! 2244: charon->bus->set_sa(charon->bus, NULL);
! 2245: }
! 2246:
! 2247: METHOD(ike_sa_manager_t, flush, void,
! 2248: private_ike_sa_manager_t *this)
! 2249: {
! 2250: enumerator_t *enumerator;
! 2251: entry_t *entry;
! 2252: u_int segment;
! 2253:
! 2254: lock_all_segments(this);
! 2255: DBG2(DBG_MGR, "going to destroy IKE_SA manager and all managed IKE_SA's");
! 2256: /* Step 1: drive out all waiting threads */
! 2257: DBG2(DBG_MGR, "set driveout flags for all stored IKE_SA's");
! 2258: enumerator = create_table_enumerator(this);
! 2259: while (enumerator->enumerate(enumerator, &entry, &segment))
! 2260: {
! 2261: /* do not accept new threads, drive out waiting threads */
! 2262: entry->driveout_new_threads = TRUE;
! 2263: entry->driveout_waiting_threads = TRUE;
! 2264: }
! 2265: enumerator->destroy(enumerator);
! 2266: DBG2(DBG_MGR, "wait for all threads to leave IKE_SA's");
! 2267: /* Step 2: wait until all are gone */
! 2268: enumerator = create_table_enumerator(this);
! 2269: while (enumerator->enumerate(enumerator, &entry, &segment))
! 2270: {
! 2271: while (entry->waiting_threads || entry->checked_out)
! 2272: {
! 2273: /* wake up all */
! 2274: entry->condvar->broadcast(entry->condvar);
! 2275: /* go sleeping until they are gone */
! 2276: entry->condvar->wait(entry->condvar, this->segments[segment].mutex);
! 2277: }
! 2278: }
! 2279: enumerator->destroy(enumerator);
! 2280: DBG2(DBG_MGR, "delete all IKE_SA's");
! 2281: /* Step 3: initiate deletion of all IKE_SAs */
! 2282: enumerator = create_table_enumerator(this);
! 2283: while (enumerator->enumerate(enumerator, &entry, &segment))
! 2284: {
! 2285: charon->bus->set_sa(charon->bus, entry->ike_sa);
! 2286: entry->ike_sa->delete(entry->ike_sa, TRUE);
! 2287: }
! 2288: enumerator->destroy(enumerator);
! 2289:
! 2290: DBG2(DBG_MGR, "destroy all entries");
! 2291: /* Step 4: destroy all entries */
! 2292: destroy_all_entries(this);
! 2293: unlock_all_segments(this);
! 2294:
! 2295: this->spi_lock->write_lock(this->spi_lock);
! 2296: DESTROY_IF(this->rng);
! 2297: this->rng = NULL;
! 2298: this->spi_cb.cb = NULL;
! 2299: this->spi_cb.data = NULL;
! 2300: this->spi_lock->unlock(this->spi_lock);
! 2301: }
! 2302:
! 2303: METHOD(ike_sa_manager_t, destroy, void,
! 2304: private_ike_sa_manager_t *this)
! 2305: {
! 2306: u_int i;
! 2307:
! 2308: /* in case new SAs were checked in after flush() was called */
! 2309: lock_all_segments(this);
! 2310: destroy_all_entries(this);
! 2311: unlock_all_segments(this);
! 2312:
! 2313: free(this->ike_sa_table);
! 2314: free(this->half_open_table);
! 2315: free(this->connected_peers_table);
! 2316: free(this->init_hashes_table);
! 2317: for (i = 0; i < this->segment_count; i++)
! 2318: {
! 2319: this->segments[i].mutex->destroy(this->segments[i].mutex);
! 2320: this->half_open_segments[i].lock->destroy(this->half_open_segments[i].lock);
! 2321: this->connected_peers_segments[i].lock->destroy(this->connected_peers_segments[i].lock);
! 2322: this->init_hashes_segments[i].mutex->destroy(this->init_hashes_segments[i].mutex);
! 2323: }
! 2324: free(this->segments);
! 2325: free(this->half_open_segments);
! 2326: free(this->connected_peers_segments);
! 2327: free(this->init_hashes_segments);
! 2328:
! 2329: this->spi_lock->destroy(this->spi_lock);
! 2330: free(this);
! 2331: }
! 2332:
! 2333: /**
! 2334: * This function returns the next-highest power of two for the given number.
! 2335: * The algorithm works by setting all bits on the right-hand side of the most
! 2336: * significant 1 to 1 and then increments the whole number so it rolls over
! 2337: * to the nearest power of two. Note: returns 0 for n == 0
! 2338: */
! 2339: static u_int get_nearest_powerof2(u_int n)
! 2340: {
! 2341: u_int i;
! 2342:
! 2343: --n;
! 2344: for (i = 1; i < sizeof(u_int) * 8; i <<= 1)
! 2345: {
! 2346: n |= n >> i;
! 2347: }
! 2348: return ++n;
! 2349: }
! 2350:
! 2351: /*
! 2352: * Described in header.
! 2353: */
! 2354: ike_sa_manager_t *ike_sa_manager_create()
! 2355: {
! 2356: private_ike_sa_manager_t *this;
! 2357: char *spi_val;
! 2358: u_int i;
! 2359:
! 2360: INIT(this,
! 2361: .public = {
! 2362: .checkout = _checkout,
! 2363: .checkout_new = _checkout_new,
! 2364: .checkout_by_message = _checkout_by_message,
! 2365: .checkout_by_config = _checkout_by_config,
! 2366: .checkout_by_id = _checkout_by_id,
! 2367: .checkout_by_name = _checkout_by_name,
! 2368: .new_initiator_spi = _new_initiator_spi,
! 2369: .check_uniqueness = _check_uniqueness,
! 2370: .has_contact = _has_contact,
! 2371: .create_enumerator = _create_enumerator,
! 2372: .create_id_enumerator = _create_id_enumerator,
! 2373: .checkin = _checkin,
! 2374: .checkin_and_destroy = _checkin_and_destroy,
! 2375: .get_count = _get_count,
! 2376: .get_half_open_count = _get_half_open_count,
! 2377: .flush = _flush,
! 2378: .set_spi_cb = _set_spi_cb,
! 2379: .destroy = _destroy,
! 2380: },
! 2381: );
! 2382:
! 2383: this->rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
! 2384: if (this->rng == NULL)
! 2385: {
! 2386: DBG1(DBG_MGR, "manager initialization failed, no RNG supported");
! 2387: free(this);
! 2388: return NULL;
! 2389: }
! 2390: this->spi_lock = rwlock_create(RWLOCK_TYPE_DEFAULT);
! 2391: spi_val = lib->settings->get_str(lib->settings, "%s.spi_mask", NULL,
! 2392: lib->ns);
! 2393: this->spi_mask = settings_value_as_uint64(spi_val, 0);
! 2394: spi_val = lib->settings->get_str(lib->settings, "%s.spi_label", NULL,
! 2395: lib->ns);
! 2396: this->spi_label = settings_value_as_uint64(spi_val, 0);
! 2397: if (this->spi_mask || this->spi_label)
! 2398: {
! 2399: DBG1(DBG_IKE, "using SPI label 0x%.16"PRIx64" and mask 0x%.16"PRIx64,
! 2400: this->spi_label, this->spi_mask);
! 2401: /* the allocated SPI is assumed to be in network order */
! 2402: this->spi_mask = htobe64(this->spi_mask);
! 2403: this->spi_label = htobe64(this->spi_label);
! 2404: }
! 2405:
! 2406: this->ikesa_limit = lib->settings->get_int(lib->settings,
! 2407: "%s.ikesa_limit", 0, lib->ns);
! 2408:
! 2409: this->table_size = get_nearest_powerof2(lib->settings->get_int(
! 2410: lib->settings, "%s.ikesa_table_size",
! 2411: DEFAULT_HASHTABLE_SIZE, lib->ns));
! 2412: this->table_size = max(1, min(this->table_size, MAX_HASHTABLE_SIZE));
! 2413: this->table_mask = this->table_size - 1;
! 2414:
! 2415: this->segment_count = get_nearest_powerof2(lib->settings->get_int(
! 2416: lib->settings, "%s.ikesa_table_segments",
! 2417: DEFAULT_SEGMENT_COUNT, lib->ns));
! 2418: this->segment_count = max(1, min(this->segment_count, this->table_size));
! 2419: this->segment_mask = this->segment_count - 1;
! 2420:
! 2421: this->ike_sa_table = calloc(this->table_size, sizeof(table_item_t*));
! 2422: this->segments = (segment_t*)calloc(this->segment_count, sizeof(segment_t));
! 2423: for (i = 0; i < this->segment_count; i++)
! 2424: {
! 2425: this->segments[i].mutex = mutex_create(MUTEX_TYPE_RECURSIVE);
! 2426: }
! 2427:
! 2428: /* we use the same table parameters for the table to track half-open SAs */
! 2429: this->half_open_table = calloc(this->table_size, sizeof(table_item_t*));
! 2430: this->half_open_segments = calloc(this->segment_count, sizeof(shareable_segment_t));
! 2431: for (i = 0; i < this->segment_count; i++)
! 2432: {
! 2433: this->half_open_segments[i].lock = rwlock_create(RWLOCK_TYPE_DEFAULT);
! 2434: }
! 2435:
! 2436: /* also for the hash table used for duplicate tests */
! 2437: this->connected_peers_table = calloc(this->table_size, sizeof(table_item_t*));
! 2438: this->connected_peers_segments = calloc(this->segment_count, sizeof(shareable_segment_t));
! 2439: for (i = 0; i < this->segment_count; i++)
! 2440: {
! 2441: this->connected_peers_segments[i].lock = rwlock_create(RWLOCK_TYPE_DEFAULT);
! 2442: }
! 2443:
! 2444: /* and again for the table of hashes of seen initial IKE messages */
! 2445: this->init_hashes_table = calloc(this->table_size, sizeof(table_item_t*));
! 2446: this->init_hashes_segments = calloc(this->segment_count, sizeof(segment_t));
! 2447: for (i = 0; i < this->segment_count; i++)
! 2448: {
! 2449: this->init_hashes_segments[i].mutex = mutex_create(MUTEX_TYPE_RECURSIVE);
! 2450: }
! 2451:
! 2452: this->reuse_ikesa = lib->settings->get_bool(lib->settings,
! 2453: "%s.reuse_ikesa", TRUE, lib->ns);
! 2454: return &this->public;
! 2455: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>