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**)&current))
                    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**)&current))
                    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**)&current) &&
                    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**)&current))
                    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**)&current))
                    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**)&current))
                    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**)&current))
                    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>