Return to connect_manager.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / libcharon / sa / ikev2 |
1.1 misho 1: /* 2: * Copyright (C) 2007-2008 Tobias Brunner 3: * HSR Hochschule fuer Technik Rapperswil 4: * 5: * This program is free software; you can redistribute it and/or modify it 6: * under the terms of the GNU General Public License as published by the 7: * Free Software Foundation; either version 2 of the License, or (at your 8: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. 9: * 10: * This program is distributed in the hope that it will be useful, but 11: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 12: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13: * for more details. 14: */ 15: 16: #include "connect_manager.h" 17: 18: #include <math.h> 19: 20: #include <daemon.h> 21: #include <threading/mutex.h> 22: #include <collections/linked_list.h> 23: #include <crypto/hashers/hasher.h> 24: 25: #include <processing/jobs/callback_job.h> 26: #include <processing/jobs/initiate_mediation_job.h> 27: #include <encoding/payloads/endpoint_notify.h> 28: 29: /* base timeout 30: * the check interval is ME_INTERVAL */ 31: #define ME_INTERVAL 25 /* ms */ 32: /* retransmission timeout is first ME_INTERVAL for ME_BOOST retransmissions 33: * then gets reduced to ME_INTERVAL * ME_RETRANS_BASE ^ (sent retransmissions - ME_BOOST). */ 34: /* number of initial retransmissions sent in short interval */ 35: #define ME_BOOST 2 36: /* base for retransmissions */ 37: #define ME_RETRANS_BASE 1.8 38: /* max number of retransmissions */ 39: #define ME_MAX_RETRANS 13 40: 41: /* time to wait before the initiator finishes the connectivity checks after 42: * the first check has succeeded */ 43: #define ME_WAIT_TO_FINISH 1000 /* ms */ 44: 45: typedef struct private_connect_manager_t private_connect_manager_t; 46: 47: /** 48: * Additional private members of connect_manager_t. 49: */ 50: struct private_connect_manager_t { 51: /** 52: * Public interface of connect_manager_t. 53: */ 54: connect_manager_t public; 55: 56: /** 57: * Lock for exclusively accessing the manager. 58: */ 59: mutex_t *mutex; 60: 61: /** 62: * Hasher to generate signatures 63: */ 64: hasher_t *hasher; 65: 66: /** 67: * Linked list with initiated mediated connections 68: */ 69: linked_list_t *initiated; 70: 71: /** 72: * Linked list with checklists (hash table with connect ID as key would 73: * be better). 74: */ 75: linked_list_t *checklists; 76: }; 77: 78: typedef enum check_state_t check_state_t; 79: 80: enum check_state_t { 81: CHECK_NONE, 82: CHECK_WAITING, 83: CHECK_IN_PROGRESS, 84: CHECK_SUCCEEDED, 85: CHECK_FAILED 86: }; 87: 88: typedef struct endpoint_pair_t endpoint_pair_t; 89: 90: /** 91: * An entry in the check list. 92: */ 93: struct endpoint_pair_t { 94: /** pair id */ 95: uint32_t id; 96: 97: /** priority */ 98: uint64_t priority; 99: 100: /** local endpoint */ 101: host_t *local; 102: 103: /** remote endpoint */ 104: host_t *remote; 105: 106: /** state */ 107: check_state_t state; 108: 109: /** number of retransmissions */ 110: uint32_t retransmitted; 111: 112: /** the generated packet */ 113: packet_t *packet; 114: }; 115: 116: /** 117: * Destroys an endpoint pair 118: */ 119: static void endpoint_pair_destroy(endpoint_pair_t *this) 120: { 121: DESTROY_IF(this->local); 122: DESTROY_IF(this->remote); 123: DESTROY_IF(this->packet); 124: free(this); 125: } 126: 127: /** 128: * Creates a new entry for the list. 129: */ 130: static endpoint_pair_t *endpoint_pair_create(endpoint_notify_t *initiator, 131: endpoint_notify_t *responder, bool initiator_is_local) 132: { 133: endpoint_pair_t *this; 134: 135: uint32_t pi = initiator->get_priority(initiator); 136: uint32_t pr = responder->get_priority(responder); 137: 138: INIT(this, 139: .priority = pow(2, 32) * min(pi, pr) + 2 * max(pi, pr) 140: + (pi > pr ? 1 : 0), 141: .local = initiator_is_local ? initiator->get_base(initiator) 142: : responder->get_base(responder), 143: .remote = initiator_is_local ? responder->get_host(responder) 144: : initiator->get_host(initiator), 145: .state = CHECK_WAITING, 146: ); 147: 148: this->local = this->local->clone(this->local); 149: this->remote = this->remote->clone(this->remote); 150: 151: return this; 152: } 153: 154: 155: typedef struct check_list_t check_list_t; 156: 157: /** 158: * An entry in the linked list. 159: */ 160: struct check_list_t { 161: 162: struct { 163: /** initiator's id */ 164: identification_t *id; 165: 166: /** initiator's key */ 167: chunk_t key; 168: 169: /** initiator's endpoints */ 170: linked_list_t *endpoints; 171: } initiator; 172: 173: struct { 174: /** responder's id */ 175: identification_t *id; 176: 177: /** responder's key */ 178: chunk_t key; 179: 180: /** responder's endpoints */ 181: linked_list_t *endpoints; 182: } responder; 183: 184: /** connect id */ 185: chunk_t connect_id; 186: 187: /** list of endpoint pairs */ 188: linked_list_t *pairs; 189: 190: /** pairs queued for triggered checks */ 191: linked_list_t *triggered; 192: 193: /** state */ 194: check_state_t state; 195: 196: /** TRUE if this is the initiator */ 197: bool is_initiator; 198: 199: /** TRUE if the initiator is finishing the checks */ 200: bool is_finishing; 201: 202: /** the current sender job */ 203: job_t *sender; 204: 205: }; 206: 207: /** 208: * Destroys a checklist 209: */ 210: static void check_list_destroy(check_list_t *this) 211: { 212: DESTROY_IF(this->initiator.id); 213: DESTROY_IF(this->responder.id); 214: 215: chunk_free(&this->connect_id); 216: chunk_free(&this->initiator.key); 217: chunk_free(&this->responder.key); 218: 219: DESTROY_OFFSET_IF(this->initiator.endpoints, 220: offsetof(endpoint_notify_t, destroy)); 221: DESTROY_OFFSET_IF(this->responder.endpoints, 222: offsetof(endpoint_notify_t, destroy)); 223: 224: DESTROY_FUNCTION_IF(this->pairs, (void*)endpoint_pair_destroy); 225: /* this list contains some of the elements contained in this->pairs */ 226: DESTROY_IF(this->triggered); 227: 228: free(this); 229: } 230: 231: /** 232: * Creates a new checklist 233: */ 234: static check_list_t *check_list_create(identification_t *initiator, 235: identification_t *responder, 236: chunk_t connect_id, 237: chunk_t initiator_key, 238: linked_list_t *initiator_endpoints, 239: bool is_initiator) 240: { 241: check_list_t *this; 242: 243: INIT(this, 244: .connect_id = chunk_clone(connect_id), 245: .initiator = { 246: .id = initiator->clone(initiator), 247: .key = chunk_clone(initiator_key), 248: .endpoints = initiator_endpoints->clone_offset(initiator_endpoints, 249: offsetof(endpoint_notify_t, clone)), 250: }, 251: .responder = { 252: .id = responder->clone(responder), 253: }, 254: .pairs = linked_list_create(), 255: .triggered = linked_list_create(), 256: .state = CHECK_NONE, 257: .is_initiator = is_initiator, 258: ); 259: 260: return this; 261: } 262: 263: typedef struct initiated_t initiated_t; 264: 265: /** 266: * For an initiator, the data stored about initiated mediation connections 267: */ 268: struct initiated_t { 269: /** my id */ 270: identification_t *id; 271: 272: /** peer id */ 273: identification_t *peer_id; 274: 275: /** list of mediated sas */ 276: linked_list_t *mediated; 277: }; 278: 279: /** 280: * Destroys a queued initiation 281: */ 282: static void initiated_destroy(initiated_t *this) 283: { 284: DESTROY_IF(this->id); 285: DESTROY_IF(this->peer_id); 286: this->mediated->destroy_offset(this->mediated, 287: offsetof(ike_sa_id_t, destroy)); 288: free(this); 289: } 290: 291: /** 292: * Creates a queued initiation 293: */ 294: static initiated_t *initiated_create(identification_t *id, 295: identification_t *peer_id) 296: { 297: initiated_t *this; 298: 299: INIT(this, 300: .id = id->clone(id), 301: .peer_id = peer_id->clone(peer_id), 302: .mediated = linked_list_create(), 303: ); 304: 305: return this; 306: } 307: 308: 309: typedef struct check_t check_t; 310: 311: /** 312: * Data exchanged in a connectivity check 313: */ 314: struct check_t { 315: /** message id */ 316: uint32_t mid; 317: 318: /** source of the connectivity check */ 319: host_t *src; 320: 321: /** destination of the connectivity check */ 322: host_t *dst; 323: 324: /** connect id */ 325: chunk_t connect_id; 326: 327: /** endpoint */ 328: endpoint_notify_t *endpoint; 329: 330: /** raw endpoint payload (to verify the signature) */ 331: chunk_t endpoint_raw; 332: 333: /** connect auth */ 334: chunk_t auth; 335: }; 336: 337: /** 338: * Destroys a connectivity check 339: */ 340: static void check_destroy(check_t *this) 341: { 342: chunk_free(&this->connect_id); 343: chunk_free(&this->endpoint_raw); 344: chunk_free(&this->auth); 345: DESTROY_IF(this->src); 346: DESTROY_IF(this->dst); 347: DESTROY_IF(this->endpoint); 348: free(this); 349: } 350: 351: /** 352: * Creates a new connectivity check 353: */ 354: static check_t *check_create() 355: { 356: check_t *this; 357: 358: INIT(this, 359: .mid = 0, 360: ); 361: 362: return this; 363: } 364: 365: typedef struct callback_data_t callback_data_t; 366: 367: /** 368: * Data required by several callback jobs used in this file 369: */ 370: struct callback_data_t { 371: /** connect manager */ 372: private_connect_manager_t *connect_manager; 373: 374: /** connect id */ 375: chunk_t connect_id; 376: 377: /** message (pair) id */ 378: uint32_t mid; 379: }; 380: 381: /** 382: * Destroys a callback data object 383: */ 384: static void callback_data_destroy(callback_data_t *this) 385: { 386: chunk_free(&this->connect_id); 387: free(this); 388: } 389: 390: /** 391: * Creates a new callback data object 392: */ 393: static callback_data_t *callback_data_create(private_connect_manager_t *connect_manager, 394: chunk_t connect_id) 395: { 396: callback_data_t *this; 397: INIT(this, 398: .connect_manager = connect_manager, 399: .connect_id = chunk_clone(connect_id), 400: .mid = 0, 401: ); 402: return this; 403: } 404: 405: /** 406: * Creates a new retransmission data object 407: */ 408: static callback_data_t *retransmit_data_create(private_connect_manager_t *connect_manager, 409: chunk_t connect_id, uint32_t mid) 410: { 411: callback_data_t *this = callback_data_create(connect_manager, connect_id); 412: this->mid = mid; 413: return this; 414: } 415: 416: typedef struct initiate_data_t initiate_data_t; 417: 418: /** 419: * Data required by the initiate mediated 420: */ 421: struct initiate_data_t { 422: /** checklist */ 423: check_list_t *checklist; 424: 425: /** waiting mediated connections */ 426: initiated_t *initiated; 427: }; 428: 429: /** 430: * Destroys a initiate data object 431: */ 432: static void initiate_data_destroy(initiate_data_t *this) 433: { 434: check_list_destroy(this->checklist); 435: initiated_destroy(this->initiated); 436: free(this); 437: } 438: 439: /** 440: * Creates a new initiate data object 441: */ 442: static initiate_data_t *initiate_data_create(check_list_t *checklist, 443: initiated_t *initiated) 444: { 445: initiate_data_t *this; 446: INIT(this, 447: .checklist = checklist, 448: .initiated = initiated, 449: ); 450: return this; 451: } 452: 453: CALLBACK(match_initiated_by_ids, bool, 454: initiated_t *current, va_list args) 455: { 456: identification_t *id, *peer_id; 457: 458: VA_ARGS_VGET(args, id, peer_id); 459: return id->equals(id, current->id) && peer_id->equals(peer_id, current->peer_id); 460: } 461: 462: static bool get_initiated_by_ids(private_connect_manager_t *this, 463: identification_t *id, 464: identification_t *peer_id, 465: initiated_t **initiated) 466: { 467: return this->initiated->find_first(this->initiated, match_initiated_by_ids, 468: (void**)initiated, id, peer_id); 469: } 470: 471: /** 472: * Removes data about initiated connections 473: */ 474: static void remove_initiated(private_connect_manager_t *this, 475: initiated_t *initiated) 476: { 477: enumerator_t *enumerator; 478: initiated_t *current; 479: 480: enumerator = this->initiated->create_enumerator(this->initiated); 481: while (enumerator->enumerate(enumerator, (void**)¤t)) 482: { 483: if (current == initiated) 484: { 485: this->initiated->remove_at(this->initiated, enumerator); 486: break; 487: } 488: } 489: enumerator->destroy(enumerator); 490: } 491: 492: CALLBACK(match_checklist_by_id, bool, 493: check_list_t *current, va_list args) 494: { 495: chunk_t connect_id; 496: 497: VA_ARGS_VGET(args, connect_id); 498: return chunk_equals(connect_id, current->connect_id); 499: } 500: 501: static bool get_checklist_by_id(private_connect_manager_t *this, 502: chunk_t connect_id, check_list_t **check_list) 503: { 504: return this->checklists->find_first(this->checklists, match_checklist_by_id, 505: (void**)check_list, connect_id); 506: } 507: 508: /** 509: * Removes a checklist 510: */ 511: static void remove_checklist(private_connect_manager_t *this, 512: check_list_t *checklist) 513: { 514: enumerator_t *enumerator; 515: check_list_t *current; 516: 517: enumerator = this->checklists->create_enumerator(this->checklists); 518: while (enumerator->enumerate(enumerator, (void**)¤t)) 519: { 520: if (current == checklist) 521: { 522: this->checklists->remove_at(this->checklists, enumerator); 523: break; 524: } 525: } 526: enumerator->destroy(enumerator); 527: } 528: 529: CALLBACK(match_endpoint_by_host, bool, 530: endpoint_notify_t *current, va_list args) 531: { 532: host_t *host; 533: 534: VA_ARGS_VGET(args, host); 535: return host->equals(host, current->get_host(current)); 536: } 537: 538: static bool endpoints_contain(linked_list_t *endpoints, host_t *host, 539: endpoint_notify_t **endpoint) 540: { 541: return endpoints->find_first(endpoints, match_endpoint_by_host, 542: (void**)endpoint, host); 543: } 544: 545: /** 546: * Inserts an endpoint pair into a list of pairs ordered by priority (high to low) 547: */ 548: static void insert_pair_by_priority(linked_list_t *pairs, endpoint_pair_t *pair) 549: { 550: enumerator_t *enumerator = pairs->create_enumerator(pairs); 551: endpoint_pair_t *current; 552: while (enumerator->enumerate(enumerator, (void**)¤t) && 553: current->priority >= pair->priority) 554: { 555: continue; 556: } 557: pairs->insert_before(pairs, enumerator, pair); 558: enumerator->destroy(enumerator); 559: } 560: 561: CALLBACK(match_pair_by_hosts, bool, 562: endpoint_pair_t *current, va_list args) 563: { 564: host_t *local, *remote; 565: 566: VA_ARGS_VGET(args, local, remote); 567: return local->equals(local, current->local) && 568: remote->equals(remote, current->remote); 569: } 570: 571: static bool get_pair_by_hosts(linked_list_t *pairs, host_t *local, 572: host_t *remote, endpoint_pair_t **pair) 573: { 574: return pairs->find_first(pairs, match_pair_by_hosts, (void**)pair, local, 575: remote); 576: } 577: 578: CALLBACK(match_pair_by_id, bool, 579: endpoint_pair_t *current, va_list args) 580: { 581: uint32_t id; 582: 583: VA_ARGS_VGET(args, id); 584: return current->id == id; 585: } 586: 587: /** 588: * Searches for a pair with a specific id 589: */ 590: static bool get_pair_by_id(check_list_t *checklist, uint32_t id, 591: endpoint_pair_t **pair) 592: { 593: return checklist->pairs->find_first(checklist->pairs, match_pair_by_id, 594: (void**)pair, id); 595: } 596: 597: CALLBACK(match_succeeded_pair, bool, 598: endpoint_pair_t *current, va_list args) 599: { 600: return current->state == CHECK_SUCCEEDED; 601: } 602: 603: /** 604: * Returns the best pair of state CHECK_SUCCEEDED from a checklist. 605: */ 606: static bool get_best_valid_pair(check_list_t *checklist, endpoint_pair_t **pair) 607: { 608: return checklist->pairs->find_first(checklist->pairs, match_succeeded_pair, 609: (void**)pair); 610: } 611: 612: CALLBACK(match_waiting_pair, bool, 613: endpoint_pair_t *current, va_list args) 614: { 615: return current->state == CHECK_WAITING; 616: } 617: 618: /** 619: * Returns and *removes* the first triggered pair in state CHECK_WAITING. 620: */ 621: static status_t get_triggered_pair(check_list_t *checklist, 622: endpoint_pair_t **pair) 623: { 624: enumerator_t *enumerator; 625: endpoint_pair_t *current; 626: status_t status = NOT_FOUND; 627: 628: enumerator = checklist->triggered->create_enumerator(checklist->triggered); 629: while (enumerator->enumerate(enumerator, (void**)¤t)) 630: { 631: checklist->triggered->remove_at(checklist->triggered, enumerator); 632: 633: if (current->state == CHECK_WAITING) 634: { 635: if (pair) 636: { 637: *pair = current; 638: } 639: status = SUCCESS; 640: break; 641: } 642: } 643: enumerator->destroy(enumerator); 644: 645: return status; 646: } 647: 648: /** 649: * Prints all the pairs on a checklist 650: */ 651: static void print_checklist(check_list_t *checklist) 652: { 653: enumerator_t *enumerator; 654: endpoint_pair_t *current; 655: 656: DBG1(DBG_IKE, "pairs on checklist %#B:", &checklist->connect_id); 657: enumerator = checklist->pairs->create_enumerator(checklist->pairs); 658: while (enumerator->enumerate(enumerator, (void**)¤t)) 659: { 660: DBG1(DBG_IKE, " * %#H - %#H (%d)", current->local, current->remote, 661: current->priority); 662: } 663: enumerator->destroy(enumerator); 664: } 665: 666: /** 667: * Prunes identical pairs with lower priority from the list 668: * Note: this function also numbers the remaining pairs serially 669: */ 670: static void prune_pairs(linked_list_t *pairs) 671: { 672: enumerator_t *enumerator, *search; 673: endpoint_pair_t *current, *other; 674: uint32_t id = 0; 675: 676: enumerator = pairs->create_enumerator(pairs); 677: search = pairs->create_enumerator(pairs); 678: while (enumerator->enumerate(enumerator, (void**)¤t)) 679: { 680: current->id = ++id; 681: 682: while (search->enumerate(search, (void**)&other)) 683: { 684: if (current == other) 685: { 686: continue; 687: } 688: 689: if (current->local->equals(current->local, other->local) && 690: current->remote->equals(current->remote, other->remote)) 691: { 692: /* since the list of pairs is sorted by priority in descending 693: * order, and we iterate the list from the beginning, we are 694: * sure that the priority of 'other' is lower than that of 695: * 'current', remove it */ 696: DBG1(DBG_IKE, "pruning endpoint pair %#H - %#H with priority %d", 697: other->local, other->remote, other->priority); 698: pairs->remove_at(pairs, search); 699: endpoint_pair_destroy(other); 700: } 701: } 702: pairs->reset_enumerator(pairs, search); 703: } 704: search->destroy(search); 705: enumerator->destroy(enumerator); 706: } 707: 708: /** 709: * Builds a list of endpoint pairs 710: */ 711: static void build_pairs(check_list_t *checklist) 712: { 713: /* FIXME: limit endpoints and pairs */ 714: enumerator_t *enumerator_i, *enumerator_r; 715: endpoint_notify_t *initiator, *responder; 716: 717: enumerator_i = checklist->initiator.endpoints->create_enumerator( 718: checklist->initiator.endpoints); 719: while (enumerator_i->enumerate(enumerator_i, (void**)&initiator)) 720: { 721: enumerator_r = checklist->responder.endpoints->create_enumerator( 722: checklist->responder.endpoints); 723: while (enumerator_r->enumerate(enumerator_r, (void**)&responder)) 724: { 725: if (initiator->get_family(initiator) != responder->get_family(responder)) 726: { 727: continue; 728: } 729: 730: insert_pair_by_priority(checklist->pairs, endpoint_pair_create( 731: initiator, responder, checklist->is_initiator)); 732: } 733: enumerator_r->destroy(enumerator_r); 734: } 735: enumerator_i->destroy(enumerator_i); 736: 737: print_checklist(checklist); 738: 739: prune_pairs(checklist->pairs); 740: } 741: 742: /** 743: * Processes the payloads of a connectivity check and returns the extracted data 744: */ 745: static status_t process_payloads(message_t *message, check_t *check) 746: { 747: enumerator_t *enumerator; 748: payload_t *payload; 749: 750: enumerator = message->create_payload_enumerator(message); 751: while (enumerator->enumerate(enumerator, &payload)) 752: { 753: if (payload->get_type(payload) != PLV2_NOTIFY) 754: { 755: DBG1(DBG_IKE, "ignoring payload of type '%N' while processing " 756: "connectivity check", payload_type_names, 757: payload->get_type(payload)); 758: continue; 759: } 760: 761: notify_payload_t *notify = (notify_payload_t*)payload; 762: 763: switch (notify->get_notify_type(notify)) 764: { 765: case ME_ENDPOINT: 766: { 767: if (check->endpoint) 768: { 769: DBG1(DBG_IKE, "connectivity check contains multiple " 770: "ME_ENDPOINT notifies"); 771: break; 772: } 773: 774: endpoint_notify_t *endpoint = endpoint_notify_create_from_payload(notify); 775: if (!endpoint) 776: { 777: DBG1(DBG_IKE, "received invalid ME_ENDPOINT notify"); 778: break; 779: } 780: check->endpoint = endpoint; 781: check->endpoint_raw = chunk_clone(notify->get_notification_data(notify)); 782: DBG2(DBG_IKE, "received ME_ENDPOINT notify"); 783: break; 784: } 785: case ME_CONNECTID: 786: { 787: if (check->connect_id.ptr) 788: { 789: DBG1(DBG_IKE, "connectivity check contains multiple " 790: "ME_CONNECTID notifies"); 791: break; 792: } 793: check->connect_id = chunk_clone(notify->get_notification_data(notify)); 794: DBG2(DBG_IKE, "received ME_CONNECTID %#B", &check->connect_id); 795: break; 796: } 797: case ME_CONNECTAUTH: 798: { 799: if (check->auth.ptr) 800: { 801: DBG1(DBG_IKE, "connectivity check contains multiple " 802: "ME_CONNECTAUTH notifies"); 803: break; 804: } 805: check->auth = chunk_clone(notify->get_notification_data(notify)); 806: DBG2(DBG_IKE, "received ME_CONNECTAUTH %#B", &check->auth); 807: break; 808: } 809: default: 810: break; 811: } 812: } 813: enumerator->destroy(enumerator); 814: 815: if (!check->connect_id.ptr || !check->endpoint || !check->auth.ptr) 816: { 817: DBG1(DBG_IKE, "at least one required payload was missing from the " 818: "connectivity check"); 819: return FAILED; 820: } 821: 822: return SUCCESS; 823: } 824: 825: /** 826: * Builds the signature for a connectivity check 827: */ 828: static chunk_t build_signature(private_connect_manager_t *this, 829: check_list_t *checklist, check_t *check, bool outbound) 830: { 831: uint32_t mid; 832: chunk_t mid_chunk, key_chunk, sig_chunk; 833: chunk_t sig_hash; 834: 835: mid = htonl(check->mid); 836: mid_chunk = chunk_from_thing(mid); 837: 838: key_chunk = (checklist->is_initiator && outbound) || (!checklist->is_initiator && !outbound) 839: ? checklist->initiator.key : checklist->responder.key; 840: 841: /* signature = SHA1( MID | ME_CONNECTID | ME_ENDPOINT | ME_CONNECTKEY ) */ 842: sig_chunk = chunk_cat("cccc", mid_chunk, check->connect_id, 843: check->endpoint_raw, key_chunk); 844: if (!this->hasher->allocate_hash(this->hasher, sig_chunk, &sig_hash)) 845: { 846: sig_hash = chunk_empty; 847: } 848: DBG3(DBG_IKE, "sig_chunk %#B", &sig_chunk); 849: DBG3(DBG_IKE, "sig_hash %#B", &sig_hash); 850: 851: chunk_free(&sig_chunk); 852: return sig_hash; 853: } 854: 855: static void queue_retransmission(private_connect_manager_t *this, check_list_t *checklist, endpoint_pair_t *pair); 856: static void schedule_checks(private_connect_manager_t *this, check_list_t *checklist, uint32_t time); 857: static void finish_checks(private_connect_manager_t *this, check_list_t *checklist); 858: 859: /** 860: * After one of the initiator's pairs has succeeded we finish the checks without 861: * waiting for all the timeouts 862: */ 863: static job_requeue_t initiator_finish(callback_data_t *data) 864: { 865: private_connect_manager_t *this = data->connect_manager; 866: 867: this->mutex->lock(this->mutex); 868: 869: check_list_t *checklist; 870: if (!get_checklist_by_id(this, data->connect_id, &checklist)) 871: { 872: DBG1(DBG_IKE, "checklist with id '%#B' not found, can't finish " 873: "connectivity checks", &data->connect_id); 874: this->mutex->unlock(this->mutex); 875: return JOB_REQUEUE_NONE; 876: } 877: 878: finish_checks(this, checklist); 879: 880: this->mutex->unlock(this->mutex); 881: 882: return JOB_REQUEUE_NONE; 883: } 884: 885: /** 886: * Updates the state of the whole checklist 887: */ 888: static void update_checklist_state(private_connect_manager_t *this, 889: check_list_t *checklist) 890: { 891: enumerator_t *enumerator; 892: endpoint_pair_t *current; 893: bool in_progress = FALSE, succeeded = FALSE; 894: 895: enumerator = checklist->pairs->create_enumerator(checklist->pairs); 896: while (enumerator->enumerate(enumerator, (void**)¤t)) 897: { 898: switch(current->state) 899: { 900: case CHECK_WAITING: 901: /* at least one is still waiting -> checklist remains 902: * in waiting state */ 903: enumerator->destroy(enumerator); 904: return; 905: case CHECK_IN_PROGRESS: 906: in_progress = TRUE; 907: break; 908: case CHECK_SUCCEEDED: 909: succeeded = TRUE; 910: break; 911: default: 912: break; 913: } 914: } 915: enumerator->destroy(enumerator); 916: 917: if (checklist->is_initiator && succeeded && !checklist->is_finishing) 918: { 919: /* instead of waiting until all checks have finished (i.e. all 920: * retransmissions have failed) the initiator finishes the checks 921: * right after the first check has succeeded. to allow a probably 922: * better pair to succeed, we still wait a certain time */ 923: DBG2(DBG_IKE, "fast finishing checks for checklist '%#B'", 924: &checklist->connect_id); 925: 926: callback_data_t *data = callback_data_create(this, checklist->connect_id); 927: lib->scheduler->schedule_job_ms(lib->scheduler, 928: (job_t*)callback_job_create((callback_job_cb_t)initiator_finish, 929: data, (callback_job_cleanup_t)callback_data_destroy, NULL), 930: ME_WAIT_TO_FINISH); 931: checklist->is_finishing = TRUE; 932: } 933: 934: if (in_progress) 935: { 936: checklist->state = CHECK_IN_PROGRESS; 937: } 938: else if (succeeded) 939: { 940: checklist->state = CHECK_SUCCEEDED; 941: } 942: else 943: { 944: checklist->state = CHECK_FAILED; 945: } 946: } 947: 948: /** 949: * This function is triggered for each sent check after a specific timeout 950: */ 951: static job_requeue_t retransmit(callback_data_t *data) 952: { 953: private_connect_manager_t *this = data->connect_manager; 954: 955: this->mutex->lock(this->mutex); 956: 957: check_list_t *checklist; 958: if (!get_checklist_by_id(this, data->connect_id, &checklist)) 959: { 960: DBG1(DBG_IKE, "checklist with id '%#B' not found, can't retransmit " 961: "connectivity check", &data->connect_id); 962: this->mutex->unlock(this->mutex); 963: return JOB_REQUEUE_NONE; 964: } 965: 966: endpoint_pair_t *pair; 967: if (!get_pair_by_id(checklist, data->mid, &pair)) 968: { 969: DBG1(DBG_IKE, "pair with id '%d' not found, can't retransmit " 970: "connectivity check", data->mid); 971: goto retransmit_end; 972: } 973: 974: if (pair->state != CHECK_IN_PROGRESS) 975: { 976: DBG2(DBG_IKE, "pair with id '%d' is in wrong state [%d], don't " 977: "retransmit the connectivity check", data->mid, pair->state); 978: goto retransmit_end; 979: } 980: 981: if (++pair->retransmitted > ME_MAX_RETRANS) 982: { 983: DBG2(DBG_IKE, "pair with id '%d' failed after %d retransmissions", 984: data->mid, ME_MAX_RETRANS); 985: pair->state = CHECK_FAILED; 986: goto retransmit_end; 987: } 988: 989: charon->sender->send(charon->sender, pair->packet->clone(pair->packet)); 990: 991: queue_retransmission(this, checklist, pair); 992: 993: retransmit_end: 994: update_checklist_state(this, checklist); 995: 996: switch(checklist->state) 997: { 998: case CHECK_SUCCEEDED: 999: case CHECK_FAILED: 1000: finish_checks(this, checklist); 1001: break; 1002: default: 1003: break; 1004: } 1005: 1006: this->mutex->unlock(this->mutex); 1007: 1008: /* we reschedule it manually */ 1009: return JOB_REQUEUE_NONE; 1010: } 1011: 1012: /** 1013: * Queues a retransmission job 1014: */ 1015: static void queue_retransmission(private_connect_manager_t *this, check_list_t *checklist, endpoint_pair_t *pair) 1016: { 1017: callback_data_t *data; 1018: job_t *job; 1019: 1020: data = retransmit_data_create(this, checklist->connect_id, pair->id); 1021: job = (job_t*)callback_job_create((callback_job_cb_t)retransmit, data, 1022: (callback_job_cleanup_t)callback_data_destroy, NULL); 1023: 1024: uint32_t retransmission = pair->retransmitted + 1; 1025: uint32_t rto = ME_INTERVAL; 1026: if (retransmission > ME_BOOST) 1027: { 1028: rto = (uint32_t)(ME_INTERVAL * pow(ME_RETRANS_BASE, retransmission - ME_BOOST)); 1029: } 1030: DBG2(DBG_IKE, "scheduling retransmission %d of pair '%d' in %dms", 1031: retransmission, pair->id, rto); 1032: 1033: lib->scheduler->schedule_job_ms(lib->scheduler, (job_t*)job, rto); 1034: } 1035: 1036: /** 1037: * Sends a check 1038: */ 1039: static void send_check(private_connect_manager_t *this, check_list_t *checklist, 1040: check_t *check, endpoint_pair_t *pair, bool request) 1041: { 1042: message_t *message = message_create(IKEV2_MAJOR_VERSION, IKEV2_MINOR_VERSION); 1043: message->set_message_id(message, check->mid); 1044: message->set_exchange_type(message, INFORMATIONAL); 1045: message->set_request(message, request); 1046: message->set_destination(message, check->dst->clone(check->dst)); 1047: message->set_source(message, check->src->clone(check->src)); 1048: 1049: ike_sa_id_t *ike_sa_id = ike_sa_id_create(IKEV2_MAJOR_VERSION, 0, 0, 1050: request); 1051: message->set_ike_sa_id(message, ike_sa_id); 1052: ike_sa_id->destroy(ike_sa_id); 1053: 1054: message->add_notify(message, FALSE, ME_CONNECTID, check->connect_id); 1055: DBG2(DBG_IKE, "send ME_CONNECTID %#B", &check->connect_id); 1056: 1057: notify_payload_t *endpoint = check->endpoint->build_notify(check->endpoint); 1058: check->endpoint_raw = chunk_clone(endpoint->get_notification_data(endpoint)); 1059: message->add_payload(message, (payload_t*)endpoint); 1060: DBG2(DBG_IKE, "send ME_ENDPOINT notify"); 1061: 1062: check->auth = build_signature(this, checklist, check, TRUE); 1063: message->add_notify(message, FALSE, ME_CONNECTAUTH, check->auth); 1064: DBG2(DBG_IKE, "send ME_CONNECTAUTH %#B", &check->auth); 1065: 1066: packet_t *packet; 1067: if (message->generate(message, NULL, &packet) == SUCCESS) 1068: { 1069: charon->sender->send(charon->sender, packet->clone(packet)); 1070: 1071: if (request) 1072: { 1073: DESTROY_IF(pair->packet); 1074: pair->packet = packet; 1075: pair->retransmitted = 0; 1076: queue_retransmission(this, checklist, pair); 1077: } 1078: else 1079: { 1080: packet->destroy(packet); 1081: } 1082: } 1083: message->destroy(message); 1084: } 1085: 1086: /** 1087: * Queues a triggered check 1088: */ 1089: static void queue_triggered_check(private_connect_manager_t *this, 1090: check_list_t *checklist, endpoint_pair_t *pair) 1091: { 1092: DBG2(DBG_IKE, "queueing triggered check for pair '%d'", pair->id); 1093: pair->state = CHECK_WAITING; 1094: checklist->triggered->insert_last(checklist->triggered, pair); 1095: 1096: if (!checklist->sender) 1097: { 1098: /* if the sender is not running we restart it */ 1099: schedule_checks(this, checklist, ME_INTERVAL); 1100: } 1101: } 1102: 1103: /** 1104: * This function is triggered for each checklist at a specific interval 1105: */ 1106: static job_requeue_t sender(callback_data_t *data) 1107: { 1108: private_connect_manager_t *this = data->connect_manager; 1109: 1110: this->mutex->lock(this->mutex); 1111: 1112: check_list_t *checklist; 1113: if (!get_checklist_by_id(this, data->connect_id, &checklist)) 1114: { 1115: DBG1(DBG_IKE, "checklist with id '%#B' not found, can't send " 1116: "connectivity check", &data->connect_id); 1117: this->mutex->unlock(this->mutex); 1118: return JOB_REQUEUE_NONE; 1119: } 1120: 1121: /* reset the sender */ 1122: checklist->sender = NULL; 1123: 1124: endpoint_pair_t *pair; 1125: if (get_triggered_pair(checklist, &pair) != SUCCESS) 1126: { 1127: DBG1(DBG_IKE, "no triggered check queued, sending an ordinary check"); 1128: 1129: if (!checklist->pairs->find_first(checklist->pairs, match_waiting_pair, 1130: (void**)&pair)) 1131: { 1132: this->mutex->unlock(this->mutex); 1133: DBG1(DBG_IKE, "no pairs in waiting state, aborting"); 1134: return JOB_REQUEUE_NONE; 1135: } 1136: } 1137: else 1138: { 1139: DBG1(DBG_IKE, "triggered check found"); 1140: } 1141: 1142: check_t *check = check_create(); 1143: check->mid = pair->id; 1144: check->src = pair->local->clone(pair->local); 1145: check->dst = pair->remote->clone(pair->remote); 1146: check->connect_id = chunk_clone(checklist->connect_id); 1147: check->endpoint = endpoint_notify_create_from_host(PEER_REFLEXIVE, NULL, 1148: NULL); 1149: 1150: pair->state = CHECK_IN_PROGRESS; 1151: 1152: send_check(this, checklist, check, pair, TRUE); 1153: 1154: check_destroy(check); 1155: 1156: /* schedule this job again */ 1157: schedule_checks(this, checklist, ME_INTERVAL); 1158: 1159: this->mutex->unlock(this->mutex); 1160: 1161: /* we reschedule it manually */ 1162: return JOB_REQUEUE_NONE; 1163: } 1164: 1165: /** 1166: * Schedules checks for a checklist (time in ms) 1167: */ 1168: static void schedule_checks(private_connect_manager_t *this, 1169: check_list_t *checklist, uint32_t time) 1170: { 1171: callback_data_t *data = callback_data_create(this, checklist->connect_id); 1172: checklist->sender = (job_t*)callback_job_create((callback_job_cb_t)sender, 1173: data, (callback_job_cleanup_t)callback_data_destroy, NULL); 1174: lib->scheduler->schedule_job_ms(lib->scheduler, checklist->sender, time); 1175: } 1176: 1177: /** 1178: * Initiates waiting mediated connections 1179: */ 1180: static job_requeue_t initiate_mediated(initiate_data_t *data) 1181: { 1182: check_list_t *checklist = data->checklist; 1183: initiated_t *initiated = data->initiated; 1184: 1185: endpoint_pair_t *pair; 1186: if (get_best_valid_pair(checklist, &pair)) 1187: { 1188: ike_sa_id_t *waiting_sa; 1189: enumerator_t *enumerator = initiated->mediated->create_enumerator( 1190: initiated->mediated); 1191: while (enumerator->enumerate(enumerator, (void**)&waiting_sa)) 1192: { 1193: ike_sa_t *sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, waiting_sa); 1194: if (sa->initiate_mediated(sa, pair->local, pair->remote, checklist->connect_id) != SUCCESS) 1195: { 1196: DBG1(DBG_IKE, "establishing mediated connection failed"); 1197: charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, sa); 1198: } 1199: else 1200: { 1201: charon->ike_sa_manager->checkin(charon->ike_sa_manager, sa); 1202: } 1203: } 1204: enumerator->destroy(enumerator); 1205: } 1206: else 1207: { 1208: /* this should (can?) not happen */ 1209: } 1210: 1211: return JOB_REQUEUE_NONE; 1212: } 1213: 1214: /** 1215: * Finishes checks for a checklist 1216: */ 1217: static void finish_checks(private_connect_manager_t *this, check_list_t *checklist) 1218: { 1219: if (checklist->is_initiator) 1220: { 1221: initiated_t *initiated; 1222: if (get_initiated_by_ids(this, checklist->initiator.id, 1223: checklist->responder.id, &initiated)) 1224: { 1225: callback_job_t *job; 1226: 1227: remove_checklist(this, checklist); 1228: remove_initiated(this, initiated); 1229: 1230: initiate_data_t *data = initiate_data_create(checklist, initiated); 1231: job = callback_job_create((callback_job_cb_t)initiate_mediated, 1232: data, (callback_job_cleanup_t)initiate_data_destroy, NULL); 1233: lib->processor->queue_job(lib->processor, (job_t*)job); 1234: return; 1235: } 1236: else 1237: { 1238: DBG1(DBG_IKE, "there is no mediated connection waiting between '%Y'" 1239: " and '%Y'", checklist->initiator.id, checklist->responder.id); 1240: } 1241: } 1242: } 1243: 1244: /** 1245: * Process the response to one of our requests 1246: */ 1247: static void process_response(private_connect_manager_t *this, check_t *check, 1248: check_list_t *checklist) 1249: { 1250: endpoint_pair_t *pair; 1251: if (get_pair_by_id(checklist, check->mid, &pair)) 1252: { 1253: if (pair->local->equals(pair->local, check->dst) && 1254: pair->remote->equals(pair->remote, check->src)) 1255: { 1256: DBG1(DBG_IKE, "endpoint pair '%d' is valid: '%#H' - '%#H'", 1257: pair->id, pair->local, pair->remote); 1258: pair->state = CHECK_SUCCEEDED; 1259: } 1260: 1261: linked_list_t *local_endpoints = checklist->is_initiator ? 1262: checklist->initiator.endpoints : checklist->responder.endpoints; 1263: 1264: endpoint_notify_t *local_endpoint; 1265: if (!endpoints_contain(local_endpoints, 1266: check->endpoint->get_host(check->endpoint), 1267: &local_endpoint)) 1268: { 1269: local_endpoint = endpoint_notify_create_from_host(PEER_REFLEXIVE, 1270: check->endpoint->get_host(check->endpoint), pair->local); 1271: local_endpoint->set_priority(local_endpoint, 1272: check->endpoint->get_priority(check->endpoint)); 1273: local_endpoints->insert_last(local_endpoints, local_endpoint); 1274: } 1275: 1276: update_checklist_state(this, checklist); 1277: 1278: switch(checklist->state) 1279: { 1280: case CHECK_SUCCEEDED: 1281: case CHECK_FAILED: 1282: finish_checks(this, checklist); 1283: break; 1284: default: 1285: break; 1286: } 1287: } 1288: else 1289: { 1290: DBG1(DBG_IKE, "pair with id '%d' not found", check->mid); 1291: } 1292: } 1293: 1294: static void process_request(private_connect_manager_t *this, check_t *check, 1295: check_list_t *checklist) 1296: { 1297: linked_list_t *remote_endpoints = checklist->is_initiator ? 1298: checklist->responder.endpoints : checklist->initiator.endpoints; 1299: 1300: endpoint_notify_t *peer_reflexive, *remote_endpoint; 1301: peer_reflexive = endpoint_notify_create_from_host(PEER_REFLEXIVE, 1302: check->src, NULL); 1303: peer_reflexive->set_priority(peer_reflexive, 1304: check->endpoint->get_priority(check->endpoint)); 1305: 1306: if (!endpoints_contain(remote_endpoints, check->src, &remote_endpoint)) 1307: { 1308: remote_endpoint = peer_reflexive->clone(peer_reflexive); 1309: remote_endpoints->insert_last(remote_endpoints, remote_endpoint); 1310: } 1311: 1312: endpoint_pair_t *pair; 1313: if (get_pair_by_hosts(checklist->pairs, check->dst, check->src, &pair)) 1314: { 1315: switch(pair->state) 1316: { 1317: case CHECK_IN_PROGRESS: 1318: /* prevent retransmissions */ 1319: pair->retransmitted = ME_MAX_RETRANS; 1320: /* FIXME: we should wait to the next rto to send the triggered 1321: * check */ 1322: /* fall-through */ 1323: case CHECK_WAITING: 1324: case CHECK_FAILED: 1325: queue_triggered_check(this, checklist, pair); 1326: break; 1327: case CHECK_SUCCEEDED: 1328: default: 1329: break; 1330: } 1331: } 1332: else 1333: { 1334: endpoint_notify_t *local_endpoint = endpoint_notify_create_from_host(HOST, check->dst, NULL); 1335: 1336: endpoint_notify_t *initiator = checklist->is_initiator ? local_endpoint : remote_endpoint; 1337: endpoint_notify_t *responder = checklist->is_initiator ? remote_endpoint : local_endpoint; 1338: 1339: pair = endpoint_pair_create(initiator, responder, checklist->is_initiator); 1340: pair->id = checklist->pairs->get_count(checklist->pairs) + 1; 1341: 1342: insert_pair_by_priority(checklist->pairs, pair); 1343: 1344: queue_triggered_check(this, checklist, pair); 1345: 1346: local_endpoint->destroy(local_endpoint); 1347: } 1348: 1349: check_t *response = check_create(); 1350: 1351: response->mid = check->mid; 1352: response->src = check->dst->clone(check->dst); 1353: response->dst = check->src->clone(check->src); 1354: response->connect_id = chunk_clone(check->connect_id); 1355: response->endpoint = peer_reflexive; 1356: 1357: send_check(this, checklist, response, pair, FALSE); 1358: 1359: check_destroy(response); 1360: } 1361: 1362: METHOD(connect_manager_t, process_check, void, 1363: private_connect_manager_t *this, message_t *message) 1364: { 1365: if (message->parse_body(message, NULL) != SUCCESS) 1366: { 1367: DBG1(DBG_IKE, "%N %s with message ID %d processing failed", 1368: exchange_type_names, message->get_exchange_type(message), 1369: message->get_request(message) ? "request" : "response", 1370: message->get_message_id(message)); 1371: return; 1372: } 1373: 1374: check_t *check = check_create(); 1375: check->mid = message->get_message_id(message); 1376: check->src = message->get_source(message); 1377: check->src = check->src->clone(check->src); 1378: check->dst = message->get_destination(message); 1379: check->dst = check->dst->clone(check->dst); 1380: 1381: if (process_payloads(message, check) != SUCCESS) 1382: { 1383: DBG1(DBG_IKE, "invalid connectivity check %s received", 1384: message->get_request(message) ? "request" : "response"); 1385: check_destroy(check); 1386: return; 1387: } 1388: 1389: this->mutex->lock(this->mutex); 1390: 1391: check_list_t *checklist; 1392: if (!get_checklist_by_id(this, check->connect_id, &checklist)) 1393: { 1394: DBG1(DBG_IKE, "checklist with id '%#B' not found", 1395: &check->connect_id); 1396: check_destroy(check); 1397: this->mutex->unlock(this->mutex); 1398: return; 1399: } 1400: 1401: chunk_t sig = build_signature(this, checklist, check, FALSE); 1402: if (!chunk_equals(sig, check->auth)) 1403: { 1404: DBG1(DBG_IKE, "connectivity check verification failed"); 1405: check_destroy(check); 1406: chunk_free(&sig); 1407: this->mutex->unlock(this->mutex); 1408: return; 1409: } 1410: chunk_free(&sig); 1411: 1412: if (message->get_request(message)) 1413: { 1414: process_request(this, check, checklist); 1415: } 1416: else 1417: { 1418: process_response(this, check, checklist); 1419: } 1420: 1421: this->mutex->unlock(this->mutex); 1422: 1423: check_destroy(check); 1424: } 1425: 1426: CALLBACK(id_matches, bool, 1427: ike_sa_id_t *a, va_list args) 1428: { 1429: ike_sa_id_t *b; 1430: 1431: VA_ARGS_VGET(args, b); 1432: return a->equals(a, b); 1433: } 1434: 1435: METHOD(connect_manager_t, check_and_register, bool, 1436: private_connect_manager_t *this, identification_t *id, 1437: identification_t *peer_id, ike_sa_id_t *mediated_sa) 1438: { 1439: initiated_t *initiated; 1440: bool already_there = TRUE; 1441: 1442: this->mutex->lock(this->mutex); 1443: 1444: if (!get_initiated_by_ids(this, id, peer_id, &initiated)) 1445: { 1446: DBG2(DBG_IKE, "registered waiting mediated connection with '%Y'", 1447: peer_id); 1448: initiated = initiated_create(id, peer_id); 1449: this->initiated->insert_last(this->initiated, initiated); 1450: already_there = FALSE; 1451: } 1452: 1453: if (!initiated->mediated->find_first(initiated->mediated, id_matches, 1454: NULL, mediated_sa)) 1455: { 1456: initiated->mediated->insert_last(initiated->mediated, 1457: mediated_sa->clone(mediated_sa)); 1458: } 1459: 1460: this->mutex->unlock(this->mutex); 1461: 1462: return already_there; 1463: } 1464: 1465: METHOD(connect_manager_t, check_and_initiate, void, 1466: private_connect_manager_t *this, ike_sa_id_t *mediation_sa, 1467: identification_t *id, identification_t *peer_id) 1468: { 1469: initiated_t *initiated; 1470: 1471: this->mutex->lock(this->mutex); 1472: 1473: if (!get_initiated_by_ids(this, id, peer_id, &initiated)) 1474: { 1475: DBG2(DBG_IKE, "no waiting mediated connections with '%Y'", peer_id); 1476: this->mutex->unlock(this->mutex); 1477: return; 1478: } 1479: 1480: ike_sa_id_t *waiting_sa; 1481: enumerator_t *enumerator = initiated->mediated->create_enumerator( 1482: initiated->mediated); 1483: while (enumerator->enumerate(enumerator, (void**)&waiting_sa)) 1484: { 1485: job_t *job = (job_t*)reinitiate_mediation_job_create(mediation_sa, 1486: waiting_sa); 1487: lib->processor->queue_job(lib->processor, job); 1488: } 1489: enumerator->destroy(enumerator); 1490: 1491: this->mutex->unlock(this->mutex); 1492: } 1493: 1494: METHOD(connect_manager_t, set_initiator_data, status_t, 1495: private_connect_manager_t *this, identification_t *initiator, 1496: identification_t *responder, chunk_t connect_id, chunk_t key, 1497: linked_list_t *endpoints, bool is_initiator) 1498: { 1499: check_list_t *checklist; 1500: 1501: this->mutex->lock(this->mutex); 1502: 1503: if (get_checklist_by_id(this, connect_id, NULL)) 1504: { 1505: DBG1(DBG_IKE, "checklist with id '%#B' already exists, aborting", 1506: &connect_id); 1507: this->mutex->unlock(this->mutex); 1508: return FAILED; 1509: } 1510: 1511: checklist = check_list_create(initiator, responder, connect_id, key, 1512: endpoints, is_initiator); 1513: this->checklists->insert_last(this->checklists, checklist); 1514: 1515: this->mutex->unlock(this->mutex); 1516: 1517: return SUCCESS; 1518: } 1519: 1520: METHOD(connect_manager_t, set_responder_data, status_t, 1521: private_connect_manager_t *this, chunk_t connect_id, chunk_t key, 1522: linked_list_t *endpoints) 1523: { 1524: check_list_t *checklist; 1525: 1526: this->mutex->lock(this->mutex); 1527: 1528: if (!get_checklist_by_id(this, connect_id, &checklist)) 1529: { 1530: DBG1(DBG_IKE, "checklist with id '%#B' not found", 1531: &connect_id); 1532: this->mutex->unlock(this->mutex); 1533: return NOT_FOUND; 1534: } 1535: 1536: checklist->responder.key = chunk_clone(key); 1537: checklist->responder.endpoints = endpoints->clone_offset(endpoints, 1538: offsetof(endpoint_notify_t, clone)); 1539: checklist->state = CHECK_WAITING; 1540: 1541: build_pairs(checklist); 1542: 1543: /* send the first check immediately */ 1544: schedule_checks(this, checklist, 0); 1545: 1546: this->mutex->unlock(this->mutex); 1547: 1548: return SUCCESS; 1549: } 1550: 1551: METHOD(connect_manager_t, stop_checks, status_t, 1552: private_connect_manager_t *this, chunk_t connect_id) 1553: { 1554: check_list_t *checklist; 1555: 1556: this->mutex->lock(this->mutex); 1557: 1558: if (!get_checklist_by_id(this, connect_id, &checklist)) 1559: { 1560: DBG1(DBG_IKE, "checklist with id '%#B' not found", 1561: &connect_id); 1562: this->mutex->unlock(this->mutex); 1563: return NOT_FOUND; 1564: } 1565: 1566: DBG1(DBG_IKE, "removing checklist with id '%#B'", &connect_id); 1567: 1568: remove_checklist(this, checklist); 1569: check_list_destroy(checklist); 1570: 1571: this->mutex->unlock(this->mutex); 1572: 1573: return SUCCESS; 1574: } 1575: 1576: METHOD(connect_manager_t, destroy, void, 1577: private_connect_manager_t *this) 1578: { 1579: this->mutex->lock(this->mutex); 1580: 1581: this->checklists->destroy_function(this->checklists, 1582: (void*)check_list_destroy); 1583: this->initiated->destroy_function(this->initiated, 1584: (void*)initiated_destroy); 1585: DESTROY_IF(this->hasher); 1586: 1587: this->mutex->unlock(this->mutex); 1588: this->mutex->destroy(this->mutex); 1589: free(this); 1590: } 1591: 1592: /* 1593: * Described in header. 1594: */ 1595: connect_manager_t *connect_manager_create() 1596: { 1597: private_connect_manager_t *this; 1598: 1599: INIT(this, 1600: .public = { 1601: .destroy = _destroy, 1602: .check_and_register = _check_and_register, 1603: .check_and_initiate = _check_and_initiate, 1604: .set_initiator_data = _set_initiator_data, 1605: .set_responder_data = _set_responder_data, 1606: .process_check = _process_check, 1607: .stop_checks = _stop_checks, 1608: }, 1609: .hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1), 1610: .mutex = mutex_create(MUTEX_TYPE_DEFAULT), 1611: .checklists = linked_list_create(), 1612: .initiated = linked_list_create(), 1613: ); 1614: 1615: if (this->hasher == NULL) 1616: { 1617: DBG1(DBG_IKE, "unable to create connect manager, SHA1 not supported"); 1618: destroy(this); 1619: return NULL; 1620: } 1621: 1622: return &this->public; 1623: }