Annotation of embedaddon/strongswan/src/libcharon/plugins/ha/ha_cache.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * Copyright (C) 2010 Martin Willi
                      3:  * Copyright (C) 2010 revosec AG
                      4:  *
                      5:  * This program is free software; you can redistribute it and/or modify it
                      6:  * under the terms of the GNU General Public License as published by the
                      7:  * Free Software Foundation; either version 2 of the License, or (at your
                      8:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
                      9:  *
                     10:  * This program is distributed in the hope that it will be useful, but
                     11:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
                     12:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
                     13:  * for more details.
                     14:  */
                     15: 
                     16: #include "ha_cache.h"
                     17: 
                     18: #include <collections/hashtable.h>
                     19: #include <collections/linked_list.h>
                     20: #include <threading/mutex.h>
                     21: #include <processing/jobs/callback_job.h>
                     22: 
                     23: typedef struct private_ha_cache_t private_ha_cache_t;
                     24: 
                     25: /**
                     26:  * Private data of an ha_cache_t object.
                     27:  */
                     28: struct private_ha_cache_t {
                     29: 
                     30:        /**
                     31:         * Public ha_cache_t interface.
                     32:         */
                     33:        ha_cache_t public;
                     34: 
                     35:        /**
                     36:         * Kernel helper functions
                     37:         */
                     38:        ha_kernel_t *kernel;
                     39: 
                     40:        /**
                     41:         * Socket to send sync messages over
                     42:         */
                     43:        ha_socket_t *socket;
                     44: 
                     45:        /**
                     46:         * Tunnel securing sync messages
                     47:         */
                     48:        ha_tunnel_t *tunnel;
                     49: 
                     50:        /**
                     51:         * Total number of segments
                     52:         */
                     53:        u_int count;
                     54: 
                     55:        /**
                     56:         * cached entries (ike_sa_t, entry_t)
                     57:         */
                     58:        hashtable_t *cache;
                     59: 
                     60:        /**
                     61:         * Mutex to lock cache
                     62:         */
                     63:        mutex_t *mutex;
                     64: };
                     65: 
                     66: /**
                     67:  * Cache entry for an IKE_SA
                     68:  */
                     69: typedef struct {
                     70:        /* segment this entry is associate to */
                     71:        u_int segment;
                     72:        /* ADD message */
                     73:        ha_message_t *add;
                     74:        /* list of updates UPDATE message */
                     75:        linked_list_t *updates;
                     76:        /* last initiator mid */
                     77:        ha_message_t *midi;
                     78:        /* last responder mid */
                     79:        ha_message_t *midr;
                     80:        /* last IV update */
                     81:        ha_message_t *iv;
                     82: } entry_t;
                     83: 
                     84: /**
                     85:  * Create a entry with an add message
                     86:  */
                     87: static entry_t *entry_create(ha_message_t *add)
                     88: {
                     89:        entry_t *entry;
                     90: 
                     91:        INIT(entry,
                     92:                .add = add,
                     93:                .updates = linked_list_create(),
                     94:        );
                     95:        return entry;
                     96: }
                     97: 
                     98: /**
                     99:  * clean up a entry
                    100:  */
                    101: static void entry_destroy(entry_t *entry)
                    102: {
                    103:        entry->updates->destroy_offset(entry->updates,
                    104:                                                                        offsetof(ha_message_t, destroy));
                    105:        entry->add->destroy(entry->add);
                    106:        DESTROY_IF(entry->midi);
                    107:        DESTROY_IF(entry->midr);
                    108:        DESTROY_IF(entry->iv);
                    109:        free(entry);
                    110: }
                    111: 
                    112: METHOD(ha_cache_t, cache, void,
                    113:        private_ha_cache_t *this, ike_sa_t *ike_sa, ha_message_t *message)
                    114: {
                    115:        entry_t *entry;
                    116: 
                    117:        this->mutex->lock(this->mutex);
                    118:        switch (message->get_type(message))
                    119:        {
                    120:                case HA_IKE_ADD:
                    121:                        entry = entry_create(message);
                    122:                        entry = this->cache->put(this->cache, ike_sa, entry);
                    123:                        if (entry)
                    124:                        {
                    125:                                entry_destroy(entry);
                    126:                        }
                    127:                        break;
                    128:                case HA_IKE_UPDATE:
                    129:                        entry = this->cache->get(this->cache, ike_sa);
                    130:                        if (entry)
                    131:                        {
                    132:                                entry->segment = this->kernel->get_segment(this->kernel,
                    133:                                                                                        ike_sa->get_other_host(ike_sa));
                    134:                                entry->updates->insert_last(entry->updates, message);
                    135:                                break;
                    136:                        }
                    137:                        message->destroy(message);
                    138:                        break;
                    139:                case HA_IKE_MID_INITIATOR:
                    140:                        entry = this->cache->get(this->cache, ike_sa);
                    141:                        if (entry)
                    142:                        {
                    143:                                DESTROY_IF(entry->midi);
                    144:                                entry->midi = message;
                    145:                                break;
                    146:                        }
                    147:                        message->destroy(message);
                    148:                        break;
                    149:                case HA_IKE_MID_RESPONDER:
                    150:                        entry = this->cache->get(this->cache, ike_sa);
                    151:                        if (entry)
                    152:                        {
                    153:                                DESTROY_IF(entry->midr);
                    154:                                entry->midr = message;
                    155:                                break;
                    156:                        }
                    157:                        message->destroy(message);
                    158:                        break;
                    159:                case HA_IKE_IV:
                    160:                        entry = this->cache->get(this->cache, ike_sa);
                    161:                        if (entry)
                    162:                        {
                    163:                                DESTROY_IF(entry->iv);
                    164:                                entry->iv = message;
                    165:                                break;
                    166:                        }
                    167:                        message->destroy(message);
                    168:                        break;
                    169:                case HA_IKE_DELETE:
                    170:                        entry = this->cache->remove(this->cache, ike_sa);
                    171:                        if (entry)
                    172:                        {
                    173:                                entry_destroy(entry);
                    174:                        }
                    175:                        message->destroy(message);
                    176:                        break;
                    177:                default:
                    178:                        message->destroy(message);
                    179:                        break;
                    180:        }
                    181:        this->mutex->unlock(this->mutex);
                    182: }
                    183: 
                    184: METHOD(ha_cache_t, delete_, void,
                    185:        private_ha_cache_t *this, ike_sa_t *ike_sa)
                    186: {
                    187:        entry_t *entry;
                    188: 
                    189:        this->mutex->lock(this->mutex);
                    190:        entry = this->cache->remove(this->cache, ike_sa);
                    191:        if (entry)
                    192:        {
                    193:                entry_destroy(entry);
                    194:        }
                    195:        this->mutex->unlock(this->mutex);
                    196: }
                    197: 
                    198: /**
                    199:  * Rekey all children of an IKE_SA
                    200:  */
                    201: static status_t rekey_children(ike_sa_t *ike_sa)
                    202: {
                    203:        enumerator_t *enumerator;
                    204:        child_sa_t *child_sa;
                    205:        status_t status = SUCCESS;
                    206:        linked_list_t *children;
                    207:        struct {
                    208:                protocol_id_t protocol;
                    209:                uint32_t spi;
                    210:        } *info;
                    211: 
                    212:        children = linked_list_create();
                    213:        enumerator = ike_sa->create_child_sa_enumerator(ike_sa);
                    214:        while (enumerator->enumerate(enumerator, &child_sa))
                    215:        {
                    216:                INIT(info,
                    217:                        .protocol = child_sa->get_protocol(child_sa),
                    218:                        .spi = child_sa->get_spi(child_sa, TRUE),
                    219:                );
                    220:                children->insert_last(children, info);
                    221:        }
                    222:        enumerator->destroy(enumerator);
                    223: 
                    224:        enumerator = children->create_enumerator(children);
                    225:        while (enumerator->enumerate(enumerator, &info))
                    226:        {
                    227:                if (ike_sa->supports_extension(ike_sa, EXT_MS_WINDOWS) &&
                    228:                        ike_sa->has_condition(ike_sa, COND_NAT_THERE))
                    229:                {
                    230:                        /* NATed Windows clients don't accept CHILD_SA rekeying, but fail
                    231:                         * with an "invalid situation" error. We just close the CHILD_SA,
                    232:                         * Windows will reestablish it immediately if required. */
                    233:                        DBG1(DBG_CFG, "resyncing CHILD_SA using a delete");
                    234:                        status = ike_sa->delete_child_sa(ike_sa, info->protocol, info->spi,
                    235:                                                                                         FALSE);
                    236:                }
                    237:                else
                    238:                {
                    239:                        DBG1(DBG_CFG, "resyncing CHILD_SA using a rekey");
                    240:                        status = ike_sa->rekey_child_sa(ike_sa, info->protocol, info->spi);
                    241:                }
                    242:                if (status == DESTROY_ME)
                    243:                {
                    244:                        break;
                    245:                }
                    246:        }
                    247:        enumerator->destroy(enumerator);
                    248:        children->destroy_function(children, free);
                    249: 
                    250:        return status;
                    251: }
                    252: 
                    253: /**
                    254:  * Trigger rekeying of CHILD_SA in segment
                    255:  */
                    256: static void rekey_segment(private_ha_cache_t *this, u_int segment)
                    257: {
                    258:        ike_sa_t *ike_sa;
                    259:        enumerator_t *enumerator;
                    260:        linked_list_t *list;
                    261:        ike_sa_id_t *id;
                    262: 
                    263:        list = linked_list_create();
                    264: 
                    265:        enumerator = charon->ike_sa_manager->create_enumerator(
                    266:                                                                                                charon->ike_sa_manager, TRUE);
                    267:        while (enumerator->enumerate(enumerator, &ike_sa))
                    268:        {
                    269:                if (this->tunnel && this->tunnel->is_sa(this->tunnel, ike_sa))
                    270:                {
                    271:                        continue;
                    272:                }
                    273:                if (ike_sa->get_state(ike_sa) == IKE_ESTABLISHED &&
                    274:                        this->kernel->get_segment(this->kernel,
                    275:                                                ike_sa->get_other_host(ike_sa)) == segment)
                    276:                {
                    277:                        id = ike_sa->get_id(ike_sa);
                    278:                        list->insert_last(list, id->clone(id));
                    279:                }
                    280:        }
                    281:        enumerator->destroy(enumerator);
                    282: 
                    283:        while (list->remove_last(list, (void**)&id) == SUCCESS)
                    284:        {
                    285:                ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, id);
                    286:                if (ike_sa)
                    287:                {
                    288:                        if (rekey_children(ike_sa) != DESTROY_ME)
                    289:                        {
                    290:                                charon->ike_sa_manager->checkin(
                    291:                                                                                charon->ike_sa_manager, ike_sa);
                    292:                        }
                    293:                        else
                    294:                        {
                    295:                                charon->ike_sa_manager->checkin_and_destroy(
                    296:                                                                                charon->ike_sa_manager, ike_sa);
                    297:                        }
                    298:                }
                    299:                id->destroy(id);
                    300:        }
                    301:        list->destroy(list);
                    302: }
                    303: 
                    304: METHOD(ha_cache_t, resync, void,
                    305:        private_ha_cache_t *this, u_int segment)
                    306: {
                    307:        enumerator_t *enumerator, *updates;
                    308:        ike_sa_t *ike_sa;
                    309:        entry_t *entry;
                    310:        ha_message_t *message;
                    311: 
                    312:        DBG1(DBG_CFG, "resyncing HA segment %d", segment);
                    313: 
                    314:        this->mutex->lock(this->mutex);
                    315:        enumerator = this->cache->create_enumerator(this->cache);
                    316:        while (enumerator->enumerate(enumerator, &ike_sa, &entry))
                    317:        {
                    318:                if (entry->segment == segment)
                    319:                {
                    320:                        this->socket->push(this->socket, entry->add);
                    321:                        updates = entry->updates->create_enumerator(entry->updates);
                    322:                        while (updates->enumerate(updates, &message))
                    323:                        {
                    324:                                this->socket->push(this->socket, message);
                    325:                        }
                    326:                        updates->destroy(updates);
                    327:                        if (entry->midi)
                    328:                        {
                    329:                                this->socket->push(this->socket, entry->midi);
                    330:                        }
                    331:                        if (entry->midr)
                    332:                        {
                    333:                                this->socket->push(this->socket, entry->midr);
                    334:                        }
                    335:                        if (entry->iv)
                    336:                        {
                    337:                                this->socket->push(this->socket, entry->iv);
                    338:                        }
                    339:                }
                    340:        }
                    341:        enumerator->destroy(enumerator);
                    342:        this->mutex->unlock(this->mutex);
                    343: 
                    344:        rekey_segment(this, segment);
                    345: }
                    346: 
                    347: /**
                    348:  * Request a resync of all segments
                    349:  */
                    350: static job_requeue_t request_resync(private_ha_cache_t *this)
                    351: {
                    352:        ha_message_t *message;
                    353:        int i;
                    354: 
                    355:        DBG1(DBG_CFG, "requesting HA resynchronization");
                    356: 
                    357:        message = ha_message_create(HA_RESYNC);
                    358:        for (i = 1; i <= this->count; i++)
                    359:        {
                    360:                message->add_attribute(message, HA_SEGMENT, i);
                    361:        }
                    362:        this->socket->push(this->socket, message);
                    363:        message->destroy(message);
                    364:        return JOB_REQUEUE_NONE;
                    365: }
                    366: 
                    367: METHOD(ha_cache_t, destroy, void,
                    368:        private_ha_cache_t *this)
                    369: {
                    370:        this->cache->destroy(this->cache);
                    371:        this->mutex->destroy(this->mutex);
                    372:        free(this);
                    373: }
                    374: 
                    375: /**
                    376:  * See header
                    377:  */
                    378: ha_cache_t *ha_cache_create(ha_kernel_t *kernel, ha_socket_t *socket,
                    379:                                                        ha_tunnel_t *tunnel, bool sync, u_int count)
                    380: {
                    381:        private_ha_cache_t *this;
                    382: 
                    383:        INIT(this,
                    384:                .public = {
                    385:                        .cache = _cache,
                    386:                        .delete = _delete_,
                    387:                        .resync = _resync,
                    388:                        .destroy = _destroy,
                    389:                },
                    390:                .count = count,
                    391:                .kernel = kernel,
                    392:                .socket = socket,
                    393:                .tunnel = tunnel,
                    394:                .cache = hashtable_create(hashtable_hash_ptr, hashtable_equals_ptr, 8),
                    395:                .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
                    396:        );
                    397: 
                    398:        if (sync)
                    399:        {
                    400:                /* request a resync as soon as we are up */
                    401:                lib->scheduler->schedule_job(lib->scheduler, (job_t*)
                    402:                        callback_job_create_with_prio((callback_job_cb_t)request_resync,
                    403:                                                                        this, NULL, NULL, JOB_PRIO_CRITICAL), 1);
                    404:        }
                    405:        return &this->public;
                    406: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>