Annotation of embedaddon/strongswan/src/libcharon/plugins/unity/unity_handler.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * Copyright (C) 2013 Tobias Brunner
        !             3:  * HSR Hochschule fuer Technik Rapperswil
        !             4:  *
        !             5:  * Copyright (C) 2012 Martin Willi
        !             6:  * Copyright (C) 2012 revosec AG
        !             7:  *
        !             8:  * This program is free software; you can redistribute it and/or modify it
        !             9:  * under the terms of the GNU General Public License as published by the
        !            10:  * Free Software Foundation; either version 2 of the License, or (at your
        !            11:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
        !            12:  *
        !            13:  * This program is distributed in the hope that it will be useful, but
        !            14:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
        !            15:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
        !            16:  * for more details.
        !            17:  */
        !            18: 
        !            19: #include "unity_handler.h"
        !            20: 
        !            21: #include <daemon.h>
        !            22: #include <threading/mutex.h>
        !            23: #include <collections/linked_list.h>
        !            24: #include <processing/jobs/callback_job.h>
        !            25: 
        !            26: typedef struct private_unity_handler_t private_unity_handler_t;
        !            27: 
        !            28: /**
        !            29:  * Private data of an unity_handler_t object.
        !            30:  */
        !            31: struct private_unity_handler_t {
        !            32: 
        !            33:        /**
        !            34:         * Public unity_handler_t interface.
        !            35:         */
        !            36:        unity_handler_t public;
        !            37: 
        !            38:        /**
        !            39:         * List of subnets to include, as entry_t
        !            40:         */
        !            41:        linked_list_t *include;
        !            42: 
        !            43:        /**
        !            44:         * Mutex for concurrent access to lists
        !            45:         */
        !            46:        mutex_t *mutex;
        !            47: };
        !            48: 
        !            49: /**
        !            50:  * Traffic selector entry for networks to include under a given IKE_SA
        !            51:  */
        !            52: typedef struct {
        !            53:        /** associated IKE_SA COOKIEs */
        !            54:        ike_sa_id_t *id;
        !            55:        /** traffic selector to include/exclude */
        !            56:        traffic_selector_t *ts;
        !            57: } entry_t;
        !            58: 
        !            59: /**
        !            60:  * Clean up an entry
        !            61:  */
        !            62: static void entry_destroy(entry_t *this)
        !            63: {
        !            64:        this->id->destroy(this->id);
        !            65:        this->ts->destroy(this->ts);
        !            66:        free(this);
        !            67: }
        !            68: 
        !            69: /**
        !            70:  * Create a traffic selector from a unity subnet definition
        !            71:  */
        !            72: static traffic_selector_t *create_ts(chunk_t subnet)
        !            73: {
        !            74:        chunk_t net, mask;
        !            75:        int i;
        !            76: 
        !            77:        net = chunk_create(subnet.ptr, 4);
        !            78:        mask = chunk_clonea(chunk_create(subnet.ptr + 4, 4));
        !            79:        for (i = 0; i < net.len; i++)
        !            80:        {
        !            81:                mask.ptr[i] = (mask.ptr[i] ^ 0xFF) | net.ptr[i];
        !            82:        }
        !            83:        return traffic_selector_create_from_bytes(0, TS_IPV4_ADDR_RANGE,
        !            84:                                                                                          net, 0, mask, 65535);
        !            85: }
        !            86: 
        !            87: /**
        !            88:  * Parse a unity attribute and extract all subnets as traffic selectors
        !            89:  */
        !            90: static linked_list_t *parse_subnets(chunk_t data)
        !            91: {
        !            92:        linked_list_t *list = NULL;
        !            93:        traffic_selector_t *ts;
        !            94: 
        !            95:        while (data.len >= 8)
        !            96:        {       /* the padding is optional */
        !            97:                ts = create_ts(data);
        !            98:                if (ts)
        !            99:                {
        !           100:                        if (!list)
        !           101:                        {
        !           102:                                list = linked_list_create();
        !           103:                        }
        !           104:                        list->insert_last(list, ts);
        !           105:                }
        !           106:                /* skip address, mask and 6 bytes of padding */
        !           107:                data = chunk_skip(data, 14);
        !           108:        }
        !           109:        return list;
        !           110: }
        !           111: 
        !           112: /**
        !           113:  * Store a list of subnets to include in tunnels under this IKE_SA
        !           114:  */
        !           115: static bool add_include(private_unity_handler_t *this, chunk_t data)
        !           116: {
        !           117:        traffic_selector_t *ts;
        !           118:        linked_list_t *list;
        !           119:        ike_sa_t *ike_sa;
        !           120:        entry_t *entry;
        !           121: 
        !           122:        ike_sa = charon->bus->get_sa(charon->bus);
        !           123:        if (!ike_sa)
        !           124:        {
        !           125:                return FALSE;
        !           126:        }
        !           127:        list = parse_subnets(data);
        !           128:        if (!list)
        !           129:        {
        !           130:                return FALSE;
        !           131:        }
        !           132:        while (list->remove_first(list, (void**)&ts) == SUCCESS)
        !           133:        {
        !           134:                INIT(entry,
        !           135:                        .id = ike_sa->get_id(ike_sa),
        !           136:                        .ts = ts,
        !           137:                );
        !           138:                entry->id = entry->id->clone(entry->id);
        !           139: 
        !           140:                this->mutex->lock(this->mutex);
        !           141:                this->include->insert_last(this->include, entry);
        !           142:                this->mutex->unlock(this->mutex);
        !           143:        }
        !           144:        list->destroy(list);
        !           145:        return TRUE;
        !           146: }
        !           147: 
        !           148: /**
        !           149:  * Remove a list of subnets from the inclusion list for this IKE_SA
        !           150:  */
        !           151: static bool remove_include(private_unity_handler_t *this, chunk_t data)
        !           152: {
        !           153:        enumerator_t *enumerator;
        !           154:        traffic_selector_t *ts;
        !           155:        linked_list_t *list;
        !           156:        ike_sa_t *ike_sa;
        !           157:        entry_t *entry;
        !           158: 
        !           159:        ike_sa = charon->bus->get_sa(charon->bus);
        !           160:        if (!ike_sa)
        !           161:        {
        !           162:                return FALSE;
        !           163:        }
        !           164:        list = parse_subnets(data);
        !           165:        if (!list)
        !           166:        {
        !           167:                return FALSE;
        !           168:        }
        !           169: 
        !           170:        this->mutex->lock(this->mutex);
        !           171:        while (list->remove_first(list, (void**)&ts) == SUCCESS)
        !           172:        {
        !           173:                enumerator = this->include->create_enumerator(this->include);
        !           174:                while (enumerator->enumerate(enumerator, &entry))
        !           175:                {
        !           176:                        if (entry->id->equals(entry->id, ike_sa->get_id(ike_sa)) &&
        !           177:                                ts->equals(ts, entry->ts))
        !           178:                        {
        !           179:                                this->include->remove_at(this->include, enumerator);
        !           180:                                entry_destroy(entry);
        !           181:                                break;
        !           182:                        }
        !           183:                }
        !           184:                enumerator->destroy(enumerator);
        !           185:                ts->destroy(ts);
        !           186:        }
        !           187:        this->mutex->unlock(this->mutex);
        !           188:        list->destroy(list);
        !           189:        return TRUE;
        !           190: }
        !           191: 
        !           192: /**
        !           193:  * Create a unique shunt name for a bypass policy
        !           194:  */
        !           195: static void create_shunt_name(ike_sa_t *ike_sa, traffic_selector_t *ts,
        !           196:                                                          char *buf, size_t len)
        !           197: {
        !           198:        snprintf(buf, len, "Unity (%s[%u]: %R)", ike_sa->get_name(ike_sa),
        !           199:                         ike_sa->get_unique_id(ike_sa), ts);
        !           200: }
        !           201: 
        !           202: /**
        !           203:  * Install entry as a shunt policy
        !           204:  */
        !           205: static job_requeue_t add_exclude_async(entry_t *entry)
        !           206: {
        !           207:        enumerator_t *enumerator;
        !           208:        child_cfg_t *child_cfg;
        !           209:        child_cfg_create_t child = {
        !           210:                .mode = MODE_PASS,
        !           211:        };
        !           212:        ike_sa_t *ike_sa;
        !           213:        char name[128];
        !           214:        host_t *host;
        !           215: 
        !           216:        ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, entry->id);
        !           217:        if (ike_sa)
        !           218:        {
        !           219:                create_shunt_name(ike_sa, entry->ts, name, sizeof(name));
        !           220: 
        !           221:                child_cfg = child_cfg_create(name, &child);
        !           222:                child_cfg->add_traffic_selector(child_cfg, FALSE,
        !           223:                                                                                entry->ts->clone(entry->ts));
        !           224:                host = ike_sa->get_my_host(ike_sa);
        !           225:                child_cfg->add_traffic_selector(child_cfg, TRUE,
        !           226:                                traffic_selector_create_from_subnet(host->clone(host),
        !           227:                                                                                                        32, 0, 0, 65535));
        !           228:                enumerator = ike_sa->create_virtual_ip_enumerator(ike_sa, TRUE);
        !           229:                while (enumerator->enumerate(enumerator, &host))
        !           230:                {
        !           231:                        child_cfg->add_traffic_selector(child_cfg, TRUE,
        !           232:                                traffic_selector_create_from_subnet(host->clone(host),
        !           233:                                                                                                        32, 0, 0, 65535));
        !           234:                }
        !           235:                enumerator->destroy(enumerator);
        !           236:                charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
        !           237: 
        !           238:                charon->shunts->install(charon->shunts, "unity", child_cfg);
        !           239:                child_cfg->destroy(child_cfg);
        !           240: 
        !           241:                DBG1(DBG_IKE, "installed %N bypass policy for %R",
        !           242:                         configuration_attribute_type_names, UNITY_LOCAL_LAN, entry->ts);
        !           243:        }
        !           244:        return JOB_REQUEUE_NONE;
        !           245: }
        !           246: 
        !           247: /**
        !           248:  * Add a bypass policy for a given subnet
        !           249:  */
        !           250: static bool add_exclude(private_unity_handler_t *this, chunk_t data)
        !           251: {
        !           252:        traffic_selector_t *ts;
        !           253:        linked_list_t *list;
        !           254:        ike_sa_t *ike_sa;
        !           255:        entry_t *entry;
        !           256: 
        !           257:        ike_sa = charon->bus->get_sa(charon->bus);
        !           258:        if (!ike_sa)
        !           259:        {
        !           260:                return FALSE;
        !           261:        }
        !           262:        list = parse_subnets(data);
        !           263:        if (!list)
        !           264:        {
        !           265:                return FALSE;
        !           266:        }
        !           267: 
        !           268:        while (list->remove_first(list, (void**)&ts) == SUCCESS)
        !           269:        {
        !           270:                INIT(entry,
        !           271:                        .id = ike_sa->get_id(ike_sa),
        !           272:                        .ts = ts,
        !           273:                );
        !           274:                entry->id = entry->id->clone(entry->id);
        !           275: 
        !           276:                /* we can't install the shunt policy yet, as we don't know the virtual IP.
        !           277:                 * Defer installation using an async callback. */
        !           278:                lib->processor->queue_job(lib->processor, (job_t*)
        !           279:                                                        callback_job_create((void*)add_exclude_async, entry,
        !           280:                                                                                                (void*)entry_destroy, NULL));
        !           281:        }
        !           282:        list->destroy(list);
        !           283:        return TRUE;
        !           284: }
        !           285: 
        !           286: /**
        !           287:  * Remove a bypass policy for a given subnet
        !           288:  */
        !           289: static bool remove_exclude(private_unity_handler_t *this, chunk_t data)
        !           290: {
        !           291:        traffic_selector_t *ts;
        !           292:        linked_list_t *list;
        !           293:        ike_sa_t *ike_sa;
        !           294:        char name[128];
        !           295:        bool success = TRUE;
        !           296: 
        !           297:        ike_sa = charon->bus->get_sa(charon->bus);
        !           298:        if (!ike_sa)
        !           299:        {
        !           300:                return FALSE;
        !           301:        }
        !           302:        list = parse_subnets(data);
        !           303:        if (!list)
        !           304:        {
        !           305:                return FALSE;
        !           306:        }
        !           307:        while (list->remove_first(list, (void**)&ts) == SUCCESS)
        !           308:        {
        !           309:                create_shunt_name(ike_sa, ts, name, sizeof(name));
        !           310:                DBG1(DBG_IKE, "uninstalling %N bypass policy for %R",
        !           311:                         configuration_attribute_type_names, UNITY_LOCAL_LAN, ts);
        !           312:                ts->destroy(ts);
        !           313:                success = charon->shunts->uninstall(charon->shunts, "unity",
        !           314:                                                                                        name) && success;
        !           315:        }
        !           316:        list->destroy(list);
        !           317:        return success;
        !           318: }
        !           319: 
        !           320: METHOD(attribute_handler_t, handle, bool,
        !           321:        private_unity_handler_t *this, ike_sa_t *ike_sa,
        !           322:        configuration_attribute_type_t type, chunk_t data)
        !           323: {
        !           324:        switch (type)
        !           325:        {
        !           326:                case UNITY_SPLIT_INCLUDE:
        !           327:                        return add_include(this, data);
        !           328:                case UNITY_LOCAL_LAN:
        !           329:                        return add_exclude(this, data);
        !           330:                default:
        !           331:                        return FALSE;
        !           332:        }
        !           333: }
        !           334: 
        !           335: METHOD(attribute_handler_t, release, void,
        !           336:        private_unity_handler_t *this, ike_sa_t *ike_sa,
        !           337:        configuration_attribute_type_t type, chunk_t data)
        !           338: {
        !           339:        switch (type)
        !           340:        {
        !           341:                case UNITY_SPLIT_INCLUDE:
        !           342:                        remove_include(this, data);
        !           343:                        break;
        !           344:                case UNITY_LOCAL_LAN:
        !           345:                        remove_exclude(this, data);
        !           346:                        break;
        !           347:                default:
        !           348:                        break;
        !           349:        }
        !           350: }
        !           351: 
        !           352: /**
        !           353:  * Configuration attributes to request
        !           354:  */
        !           355: static configuration_attribute_type_t attributes[] = {
        !           356:        UNITY_SPLIT_INCLUDE,
        !           357:        UNITY_LOCAL_LAN,
        !           358: };
        !           359: 
        !           360: /**
        !           361:  * Attribute enumerator implementation
        !           362:  */
        !           363: typedef struct {
        !           364:        /** implements enumerator_t */
        !           365:        enumerator_t public;
        !           366:        /** position in attributes[] */
        !           367:        int i;
        !           368: } attribute_enumerator_t;
        !           369: 
        !           370: METHOD(enumerator_t, enumerate_attributes, bool,
        !           371:        attribute_enumerator_t *this, va_list args)
        !           372: {
        !           373:        configuration_attribute_type_t *type;
        !           374:        chunk_t *data;
        !           375: 
        !           376:        VA_ARGS_VGET(args, type, data);
        !           377:        if (this->i < countof(attributes))
        !           378:        {
        !           379:                *type = attributes[this->i++];
        !           380:                *data = chunk_empty;
        !           381:                return TRUE;
        !           382:        }
        !           383:        return FALSE;
        !           384: }
        !           385: 
        !           386: METHOD(attribute_handler_t, create_attribute_enumerator, enumerator_t *,
        !           387:        unity_handler_t *this, ike_sa_t *ike_sa, linked_list_t *vips)
        !           388: {
        !           389:        attribute_enumerator_t *enumerator;
        !           390: 
        !           391:        ike_sa = charon->bus->get_sa(charon->bus);
        !           392:        if (!ike_sa || ike_sa->get_version(ike_sa) != IKEV1 ||
        !           393:                !ike_sa->supports_extension(ike_sa, EXT_CISCO_UNITY))
        !           394:        {
        !           395:                return enumerator_create_empty();
        !           396:        }
        !           397:        INIT(enumerator,
        !           398:                .public = {
        !           399:                        .enumerate = enumerator_enumerate_default,
        !           400:                        .venumerate = _enumerate_attributes,
        !           401:                        .destroy = (void*)free,
        !           402:                },
        !           403:        );
        !           404:        return &enumerator->public;
        !           405: }
        !           406: 
        !           407: typedef struct {
        !           408:        /** mutex to unlock */
        !           409:        mutex_t *mutex;
        !           410:        /** IKE_SA ID to filter for */
        !           411:        ike_sa_id_t *id;
        !           412: } include_filter_t;
        !           413: 
        !           414: CALLBACK(include_filter, bool,
        !           415:        include_filter_t *data, enumerator_t *orig, va_list args)
        !           416: {
        !           417:        entry_t *entry;
        !           418:        traffic_selector_t **ts;
        !           419: 
        !           420:        VA_ARGS_VGET(args, ts);
        !           421: 
        !           422:        while (orig->enumerate(orig, &entry))
        !           423:        {
        !           424:                if (data->id->equals(data->id, entry->id))
        !           425:                {
        !           426:                        *ts = entry->ts;
        !           427:                        return TRUE;
        !           428:                }
        !           429:        }
        !           430:        return FALSE;
        !           431: }
        !           432: 
        !           433: CALLBACK(destroy_filter, void,
        !           434:        include_filter_t *data)
        !           435: {
        !           436:        data->mutex->unlock(data->mutex);
        !           437:        free(data);
        !           438: }
        !           439: 
        !           440: METHOD(unity_handler_t, create_include_enumerator, enumerator_t*,
        !           441:        private_unity_handler_t *this, ike_sa_id_t *id)
        !           442: {
        !           443:        include_filter_t *data;
        !           444: 
        !           445:        INIT(data,
        !           446:                .mutex = this->mutex,
        !           447:                .id = id,
        !           448:        );
        !           449:        data->mutex->lock(data->mutex);
        !           450:        return enumerator_create_filter(
        !           451:                                        this->include->create_enumerator(this->include),
        !           452:                                        include_filter, data, destroy_filter);
        !           453: }
        !           454: 
        !           455: METHOD(unity_handler_t, destroy, void,
        !           456:        private_unity_handler_t *this)
        !           457: {
        !           458:        this->include->destroy(this->include);
        !           459:        this->mutex->destroy(this->mutex);
        !           460:        free(this);
        !           461: }
        !           462: 
        !           463: /**
        !           464:  * See header
        !           465:  */
        !           466: unity_handler_t *unity_handler_create()
        !           467: {
        !           468:        private_unity_handler_t *this;
        !           469: 
        !           470:        INIT(this,
        !           471:                .public = {
        !           472:                        .handler = {
        !           473:                                .handle = _handle,
        !           474:                                .release = _release,
        !           475:                                .create_attribute_enumerator = _create_attribute_enumerator,
        !           476:                        },
        !           477:                        .create_include_enumerator = _create_include_enumerator,
        !           478:                        .destroy = _destroy,
        !           479:                },
        !           480:                .include = linked_list_create(),
        !           481:                .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
        !           482:        );
        !           483: 
        !           484:        return &this->public;
        !           485: }

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