Annotation of embedaddon/strongswan/src/libcharon/plugins/duplicheck/duplicheck_listener.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * Copyright (C) 2011 Martin Willi
                      3:  * Copyright (C) 2011 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 "duplicheck_listener.h"
                     17: 
                     18: #include <daemon.h>
                     19: #include <threading/mutex.h>
                     20: #include <collections/hashtable.h>
                     21: #include <encoding/payloads/delete_payload.h>
                     22: #include <processing/jobs/delete_ike_sa_job.h>
                     23: 
                     24: typedef struct private_duplicheck_listener_t private_duplicheck_listener_t;
                     25: 
                     26: /**
                     27:  * Private data of an duplicheck_listener_t object.
                     28:  */
                     29: struct private_duplicheck_listener_t {
                     30: 
                     31:        /**
                     32:         * Public duplicheck_listener_t interface.
                     33:         */
                     34:        duplicheck_listener_t public;
                     35: 
                     36:        /**
                     37:         * Socket to send notifications to
                     38:         */
                     39:        duplicheck_notify_t *notify;
                     40: 
                     41:        /**
                     42:         * Mutex to lock hashtables
                     43:         */
                     44:        mutex_t *mutex;
                     45: 
                     46:        /**
                     47:         * Hashtable of active IKE_SAs, identification_t => entry_t
                     48:         */
                     49:        hashtable_t *active;
                     50: 
                     51:        /**
                     52:         * Hashtable with active liveness checks, identification_t => entry_t
                     53:         */
                     54:        hashtable_t *checking;
                     55: };
                     56: 
                     57: /**
                     58:  * Entry for hashtables
                     59:  */
                     60: typedef struct {
                     61:        /** peer identity */
                     62:        identification_t *id;
                     63:        /** list of IKE_SA identifiers, ike_sa_id_t */
                     64:        linked_list_t *sas;
                     65: } entry_t;
                     66: 
                     67: /**
                     68:  * Destroy a hashtable entry
                     69:  */
                     70: static void entry_destroy(entry_t *this)
                     71: {
                     72:        this->id->destroy(this->id);
                     73:        this->sas->destroy_offset(this->sas, offsetof(ike_sa_id_t, destroy));
                     74:        free(this);
                     75: }
                     76: 
                     77: /**
                     78:  * Hashtable hash function
                     79:  */
                     80: static u_int hash(identification_t *key)
                     81: {
                     82:        return chunk_hash(key->get_encoding(key));
                     83: }
                     84: 
                     85: /**
                     86:  * Hashtable equals function
                     87:  */
                     88: static bool equals(identification_t *a, identification_t *b)
                     89: {
                     90:        return a->equals(a, b);
                     91: }
                     92: 
                     93: /**
                     94:  * Put an IKE_SA identifier to hashtable
                     95:  */
                     96: static void put(hashtable_t *table, identification_t *id, ike_sa_id_t *sa)
                     97: {
                     98:        entry_t *entry;
                     99: 
                    100:        entry = table->get(table, id);
                    101:        if (!entry)
                    102:        {
                    103:                INIT(entry,
                    104:                        .id = id->clone(id),
                    105:                        .sas = linked_list_create(),
                    106:                );
                    107:                table->put(table, entry->id, entry);
                    108:        }
                    109:        entry->sas->insert_last(entry->sas, sa->clone(sa));
                    110: }
                    111: 
                    112: /**
                    113:  * Purge an entry from table if it has no IKE_SA identifiers
                    114:  */
                    115: static void remove_if_empty(hashtable_t *table, entry_t *entry)
                    116: {
                    117:        if (entry->sas->get_count(entry->sas) == 0)
                    118:        {
                    119:                entry = table->remove(table, entry->id);
                    120:                if (entry)
                    121:                {
                    122:                        entry_destroy(entry);
                    123:                }
                    124:        }
                    125: }
                    126: 
                    127: /**
                    128:  * Remove the first entry found in the table for the given id
                    129:  */
                    130: static ike_sa_id_t *remove_first(hashtable_t *table, identification_t *id)
                    131: {
                    132:        ike_sa_id_t *sa = NULL;
                    133:        entry_t *entry;
                    134: 
                    135:        entry = table->get(table, id);
                    136:        if (entry)
                    137:        {
                    138:                entry->sas->remove_first(entry->sas, (void**)&sa);
                    139:                remove_if_empty(table, entry);
                    140:        }
                    141:        return sa;
                    142: }
                    143: 
                    144: /**
                    145:  * Remove a specific IKE_SA ID for the given identity
                    146:  */
                    147: static bool remove_specific(hashtable_t *table, identification_t *id,
                    148:                                                        ike_sa_id_t *sa)
                    149: {
                    150:        enumerator_t *enumerator;
                    151:        bool found = FALSE;
                    152:        entry_t *entry;
                    153:        ike_sa_id_t *current;
                    154: 
                    155:        entry = table->get(table, id);
                    156:        if (entry)
                    157:        {
                    158:                enumerator = entry->sas->create_enumerator(entry->sas);
                    159:                while (enumerator->enumerate(enumerator, &current))
                    160:                {
                    161:                        if (sa->equals(sa, current))
                    162:                        {
                    163:                                entry->sas->remove_at(entry->sas, enumerator);
                    164:                                current->destroy(current);
                    165:                                found = TRUE;
                    166:                                break;
                    167:                        }
                    168:                }
                    169:                enumerator->destroy(enumerator);
                    170:                if (found)
                    171:                {
                    172:                        remove_if_empty(table, entry);
                    173:                }
                    174:        }
                    175:        return found;
                    176: }
                    177: 
                    178: METHOD(listener_t, ike_rekey, bool,
                    179:        private_duplicheck_listener_t *this, ike_sa_t *old, ike_sa_t *new)
                    180: {
                    181:        this->mutex->lock(this->mutex);
                    182: 
                    183:        remove_specific(this->active, old->get_other_id(old), old->get_id(old));
                    184:        put(this->active, new->get_other_id(new), new->get_id(new));
                    185: 
                    186:        this->mutex->unlock(this->mutex);
                    187: 
                    188:        return TRUE;
                    189: }
                    190: 
                    191: METHOD(listener_t, ike_updown, bool,
                    192:        private_duplicheck_listener_t *this, ike_sa_t *ike_sa, bool up)
                    193: {
                    194:        identification_t *id;
                    195:        ike_sa_id_t *sa;
                    196: 
                    197:        id = ike_sa->get_other_id(ike_sa);
                    198: 
                    199:        this->mutex->lock(this->mutex);
                    200:        if (up)
                    201:        {
                    202:                /* another IKE_SA for this identity active? */
                    203:                sa = remove_first(this->active, id);
                    204:                if (sa)
                    205:                {
                    206:                        DBG1(DBG_CFG, "detected duplicate IKE_SA for '%Y', "
                    207:                                 "triggering delete for old IKE_SA", id);
                    208:                        put(this->checking, id, sa);
                    209:                        lib->processor->queue_job(lib->processor,
                    210:                                                                (job_t*)delete_ike_sa_job_create(sa, TRUE));
                    211:                        sa->destroy(sa);
                    212:                }
                    213:                /* register IKE_SA as the new active */
                    214:                sa = ike_sa->get_id(ike_sa);
                    215:                put(this->active, id, sa);
                    216:        }
                    217:        else
                    218:        {
                    219:                sa = ike_sa->get_id(ike_sa);
                    220:                /* check if closing an IKE_SA currently in checking state */
                    221:                if (remove_specific(this->checking, id, sa))
                    222:                {
                    223:                        DBG1(DBG_CFG, "delete for duplicate IKE_SA '%Y' timed out, "
                    224:                                 "keeping new IKE_SA", id);
                    225:                }
                    226:                /* check normal close of IKE_SA */
                    227:                remove_specific(this->active, id, sa);
                    228:        }
                    229:        this->mutex->unlock(this->mutex);
                    230: 
                    231:        return TRUE;
                    232: }
                    233: 
                    234: METHOD(listener_t, message_hook, bool,
                    235:        private_duplicheck_listener_t *this, ike_sa_t *ike_sa,
                    236:        message_t *message, bool incoming, bool plain)
                    237: {
                    238:        if (incoming && plain && !message->get_request(message))
                    239:        {
                    240:                identification_t *id;
                    241:                ike_sa_id_t *sa;
                    242: 
                    243:                id = ike_sa->get_other_id(ike_sa);
                    244:                sa = ike_sa->get_id(ike_sa);
                    245: 
                    246:                this->mutex->lock(this->mutex);
                    247:                if (remove_specific(this->checking, id, sa))
                    248:                {
                    249:                        DBG1(DBG_CFG, "got a response on a duplicate IKE_SA for '%Y', "
                    250:                                 "deleting new IKE_SA", id);
                    251:                        charon->bus->alert(charon->bus, ALERT_UNIQUE_KEEP);
                    252:                        sa = remove_first(this->active, id);
                    253:                        if (sa)
                    254:                        {
                    255:                                lib->processor->queue_job(lib->processor,
                    256:                                                                (job_t*)delete_ike_sa_job_create(sa, TRUE));
                    257:                                sa->destroy(sa);
                    258:                        }
                    259:                        this->mutex->unlock(this->mutex);
                    260: 
                    261:                        this->notify->send(this->notify, id);
                    262:                }
                    263:                else
                    264:                {
                    265:                        this->mutex->unlock(this->mutex);
                    266:                }
                    267:        }
                    268:        return TRUE;
                    269: }
                    270: 
                    271: METHOD(duplicheck_listener_t, destroy, void,
                    272:        private_duplicheck_listener_t *this)
                    273: {
                    274:        enumerator_t *enumerator;
                    275:        identification_t *key;
                    276:        entry_t *value;
                    277: 
                    278:        enumerator = this->active->create_enumerator(this->active);
                    279:        while (enumerator->enumerate(enumerator, &key, &value))
                    280:        {
                    281:                entry_destroy(value);
                    282:        }
                    283:        enumerator->destroy(enumerator);
                    284: 
                    285:        enumerator = this->checking->create_enumerator(this->checking);
                    286:        while (enumerator->enumerate(enumerator, &key, &value))
                    287:        {
                    288:                entry_destroy(value);
                    289:        }
                    290:        enumerator->destroy(enumerator);
                    291: 
                    292:        this->active->destroy(this->active);
                    293:        this->checking->destroy(this->checking);
                    294:        this->mutex->destroy(this->mutex);
                    295:        free(this);
                    296: }
                    297: 
                    298: /**
                    299:  * See header
                    300:  */
                    301: duplicheck_listener_t *duplicheck_listener_create(duplicheck_notify_t *notify)
                    302: {
                    303:        private_duplicheck_listener_t *this;
                    304: 
                    305:        INIT(this,
                    306:                .public = {
                    307:                        .listener = {
                    308:                                .ike_rekey = _ike_rekey,
                    309:                                .ike_updown = _ike_updown,
                    310:                                .message = _message_hook,
                    311:                        },
                    312:                        .destroy = _destroy,
                    313:                },
                    314:                .notify = notify,
                    315:                .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
                    316:                .active = hashtable_create((hashtable_hash_t)hash,
                    317:                                                                   (hashtable_equals_t)equals, 32),
                    318:                .checking = hashtable_create((hashtable_hash_t)hash,
                    319:                                                                         (hashtable_equals_t)equals, 2),
                    320:        );
                    321: 
                    322:        return &this->public;
                    323: }

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