Annotation of embedaddon/strongswan/src/libcharon/sa/ikev2/connect_manager.c, revision 1.1.1.1
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: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>