Annotation of embedaddon/strongswan/src/libcharon/plugins/lookip/lookip_listener.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * Copyright (C) 2012 Martin Willi
                      3:  * Copyright (C) 2012 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 "lookip_listener.h"
                     17: 
                     18: #include <daemon.h>
                     19: #include <collections/hashtable.h>
                     20: #include <collections/linked_list.h>
                     21: #include <threading/rwlock.h>
                     22: 
                     23: typedef struct private_lookip_listener_t private_lookip_listener_t;
                     24: 
                     25: /**
                     26:  * Private data of an lookip_listener_t object.
                     27:  */
                     28: struct private_lookip_listener_t {
                     29: 
                     30:        /**
                     31:         * Public lookip_listener_t interface.
                     32:         */
                     33:        lookip_listener_t public;
                     34: 
                     35:        /**
                     36:         * Lock for hashtable
                     37:         */
                     38:        rwlock_t *lock;
                     39: 
                     40:        /**
                     41:         * Hashtable with entries: host_t => entry_t
                     42:         */
                     43:        hashtable_t *entries;
                     44: 
                     45:        /**
                     46:         * List of registered listeners
                     47:         */
                     48:        linked_list_t *listeners;
                     49: };
                     50: 
                     51: /**
                     52:  * Listener entry
                     53:  */
                     54: typedef struct {
                     55:        /** callback function */
                     56:        lookip_callback_t cb;
                     57:        /** user data for callback */
                     58:        void *user;
                     59: } listener_entry_t;
                     60: 
                     61: /**
                     62:  * Hashtable entry
                     63:  */
                     64: typedef struct {
                     65:        /** virtual IP, serves as lookup key */
                     66:        host_t *vip;
                     67:        /** peers external address */
                     68:        host_t *other;
                     69:        /** peer (EAP-)Identity */
                     70:        identification_t *id;
                     71:        /** associated connection name */
                     72:        char *name;
                     73:        /** IKE_SA unique identifier */
                     74:        u_int unique_id;
                     75: } entry_t;
                     76: 
                     77: /**
                     78:  * Destroy a hashtable entry
                     79:  */
                     80: static void entry_destroy(entry_t *entry)
                     81: {
                     82:        entry->vip->destroy(entry->vip);
                     83:        entry->other->destroy(entry->other);
                     84:        entry->id->destroy(entry->id);
                     85:        free(entry->name);
                     86:        free(entry);
                     87: }
                     88: 
                     89: /**
                     90:  * Hashtable hash function
                     91:  */
                     92: static u_int hash(host_t *key)
                     93: {
                     94:        return chunk_hash(key->get_address(key));
                     95: }
                     96: 
                     97: /**
                     98:  * Hashtable equals function
                     99:  */
                    100: static bool equals(host_t *a, host_t *b)
                    101: {
                    102:        return a->ip_equals(a, b);
                    103: }
                    104: 
                    105: /**
                    106:  * Compare callback that invokes up callback of all registered listeners
                    107:  */
                    108: static bool notify_up(listener_entry_t *listener, entry_t *entry)
                    109: {
                    110:        if (!listener->cb(listener->user, TRUE, entry->vip, entry->other,
                    111:                                          entry->id, entry->name, entry->unique_id))
                    112:        {
                    113:                free(listener);
                    114:                return TRUE;
                    115:        }
                    116:        return FALSE;
                    117: }
                    118: 
                    119: /**
                    120:  * Compare callback that invokes down callback of all registered listeners
                    121:  */
                    122: static bool notify_down(listener_entry_t *listener, entry_t *entry)
                    123: {
                    124:        if (!listener->cb(listener->user, FALSE, entry->vip, entry->other,
                    125:                                          entry->id, entry->name, entry->unique_id))
                    126:        {
                    127:                free(listener);
                    128:                return TRUE;
                    129:        }
                    130:        return FALSE;
                    131: }
                    132: 
                    133: /**
                    134:  * Add a new entry to the hashtable
                    135:  */
                    136: static void add_entry(private_lookip_listener_t *this, ike_sa_t *ike_sa)
                    137: {
                    138:        enumerator_t *enumerator;
                    139:        host_t *vip, *other;
                    140:        identification_t *id;
                    141:        entry_t *entry;
                    142: 
                    143:        enumerator = ike_sa->create_virtual_ip_enumerator(ike_sa, FALSE);
                    144:        while (enumerator->enumerate(enumerator, &vip))
                    145:        {
                    146:                other = ike_sa->get_other_host(ike_sa);
                    147:                id = ike_sa->get_other_eap_id(ike_sa);
                    148: 
                    149:                INIT(entry,
                    150:                        .vip = vip->clone(vip),
                    151:                        .other = other->clone(other),
                    152:                        .id = id->clone(id),
                    153:                        .name = strdup(ike_sa->get_name(ike_sa)),
                    154:                        .unique_id = ike_sa->get_unique_id(ike_sa),
                    155:                );
                    156: 
                    157:                this->lock->read_lock(this->lock);
                    158:                this->listeners->remove(this->listeners, entry, (void*)notify_up);
                    159:                this->lock->unlock(this->lock);
                    160: 
                    161:                this->lock->write_lock(this->lock);
                    162:                entry = this->entries->put(this->entries, entry->vip, entry);
                    163:                this->lock->unlock(this->lock);
                    164:                if (entry)
                    165:                {
                    166:                        entry_destroy(entry);
                    167:                }
                    168:        }
                    169:        enumerator->destroy(enumerator);
                    170: }
                    171: 
                    172: /**
                    173:  * Remove an entry from the hashtable
                    174:  */
                    175: static void remove_entry(private_lookip_listener_t *this, ike_sa_t *ike_sa)
                    176: {
                    177:        enumerator_t *enumerator;
                    178:        host_t *vip;
                    179:        entry_t *entry;
                    180: 
                    181:        enumerator = ike_sa->create_virtual_ip_enumerator(ike_sa, FALSE);
                    182:        while (enumerator->enumerate(enumerator, &vip))
                    183:        {
                    184:                this->lock->write_lock(this->lock);
                    185:                entry = this->entries->remove(this->entries, vip);
                    186:                this->lock->unlock(this->lock);
                    187:                if (entry)
                    188:                {
                    189:                        this->lock->read_lock(this->lock);
                    190:                        this->listeners->remove(this->listeners, entry, (void*)notify_down);
                    191:                        this->lock->unlock(this->lock);
                    192: 
                    193:                        entry_destroy(entry);
                    194:                }
                    195:        }
                    196:        enumerator->destroy(enumerator);
                    197: }
                    198: 
                    199: METHOD(listener_t, message_hook, bool,
                    200:        private_lookip_listener_t *this, ike_sa_t *ike_sa,
                    201:        message_t *message, bool incoming, bool plain)
                    202: {
                    203:        if (plain && ike_sa->get_state(ike_sa) == IKE_ESTABLISHED &&
                    204:                !incoming && !message->get_request(message))
                    205:        {
                    206:                if (ike_sa->get_version(ike_sa) == IKEV1 &&
                    207:                        message->get_exchange_type(message) == TRANSACTION)
                    208:                {
                    209:                        add_entry(this, ike_sa);
                    210:                }
                    211:                if (ike_sa->get_version(ike_sa) == IKEV2 &&
                    212:                        message->get_exchange_type(message) == IKE_AUTH)
                    213:                {
                    214:                        add_entry(this, ike_sa);
                    215:                }
                    216:        }
                    217:        return TRUE;
                    218: }
                    219: 
                    220: METHOD(listener_t, ike_updown, bool,
                    221:        private_lookip_listener_t *this, ike_sa_t *ike_sa, bool up)
                    222: {
                    223:        if (!up)
                    224:        {
                    225:                remove_entry(this, ike_sa);
                    226:        }
                    227:        return TRUE;
                    228: }
                    229: 
                    230: METHOD(listener_t, ike_rekey, bool,
                    231:        private_lookip_listener_t *this, ike_sa_t *old, ike_sa_t *new)
                    232: {
                    233:        /* During IKE_SA rekey, the unique identifier changes. Fire update events
                    234:         * and update the cached entry. During the invocation of this hook, the
                    235:         * virtual IPs have been migrated to new, hence remove that entry. */
                    236:        remove_entry(this, new);
                    237:        add_entry(this, new);
                    238: 
                    239:        return TRUE;
                    240: }
                    241: 
                    242: METHOD(lookip_listener_t, lookup, int,
                    243:        private_lookip_listener_t *this, host_t *vip,
                    244:        lookip_callback_t cb, void *user)
                    245: {
                    246:        entry_t *entry;
                    247:        int matches = 0;
                    248: 
                    249:        this->lock->read_lock(this->lock);
                    250:        if (vip)
                    251:        {
                    252:                entry = this->entries->get(this->entries, vip);
                    253:                if (entry)
                    254:                {
                    255:                        cb(user, TRUE, entry->vip, entry->other, entry->id,
                    256:                           entry->name, entry->unique_id);
                    257:                        matches ++;
                    258:                }
                    259:        }
                    260:        else
                    261:        {
                    262:                enumerator_t *enumerator;
                    263: 
                    264:                enumerator = this->entries->create_enumerator(this->entries);
                    265:                while (enumerator->enumerate(enumerator, &vip, &entry))
                    266:                {
                    267:                        cb(user, TRUE, entry->vip, entry->other, entry->id,
                    268:                           entry->name, entry->unique_id);
                    269:                        matches++;
                    270:                }
                    271:                enumerator->destroy(enumerator);
                    272:        }
                    273:        this->lock->unlock(this->lock);
                    274: 
                    275:        return matches;
                    276: }
                    277: 
                    278: METHOD(lookip_listener_t, add_listener, void,
                    279:        private_lookip_listener_t *this, lookip_callback_t cb, void *user)
                    280: {
                    281:        listener_entry_t *listener;
                    282: 
                    283:        INIT(listener,
                    284:                .cb = cb,
                    285:                .user = user,
                    286:        );
                    287: 
                    288:        this->lock->write_lock(this->lock);
                    289:        this->listeners->insert_last(this->listeners, listener);
                    290:        this->lock->unlock(this->lock);
                    291: }
                    292: 
                    293: METHOD(lookip_listener_t, remove_listener, void,
                    294:        private_lookip_listener_t *this, void *user)
                    295: {
                    296:        listener_entry_t *listener;
                    297:        enumerator_t *enumerator;
                    298: 
                    299:        this->lock->write_lock(this->lock);
                    300:        enumerator = this->listeners->create_enumerator(this->listeners);
                    301:        while (enumerator->enumerate(enumerator, &listener))
                    302:        {
                    303:                if (listener->user == user)
                    304:                {
                    305:                        this->listeners->remove_at(this->listeners, enumerator);
                    306:                        free(listener);
                    307:                }
                    308:        }
                    309:        enumerator->destroy(enumerator);
                    310:        this->lock->unlock(this->lock);
                    311: }
                    312: 
                    313: METHOD(lookip_listener_t, destroy, void,
                    314:        private_lookip_listener_t *this)
                    315: {
                    316:        this->listeners->destroy_function(this->listeners, free);
                    317:        this->entries->destroy(this->entries);
                    318:        this->lock->destroy(this->lock);
                    319:        free(this);
                    320: }
                    321: 
                    322: /**
                    323:  * See header
                    324:  */
                    325: lookip_listener_t *lookip_listener_create()
                    326: {
                    327:        private_lookip_listener_t *this;
                    328: 
                    329:        INIT(this,
                    330:                .public = {
                    331:                        .listener = {
                    332:                                .message = _message_hook,
                    333:                                .ike_updown = _ike_updown,
                    334:                                .ike_rekey = _ike_rekey,
                    335:                        },
                    336:                        .lookup = _lookup,
                    337:                        .add_listener = _add_listener,
                    338:                        .remove_listener = _remove_listener,
                    339:                        .destroy = _destroy,
                    340:                },
                    341:                .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
                    342:                .entries = hashtable_create((hashtable_hash_t)hash,
                    343:                                                                        (hashtable_equals_t)equals, 32),
                    344:                .listeners = linked_list_create(),
                    345:        );
                    346: 
                    347:        return &this->public;
                    348: }

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