Annotation of embedaddon/strongswan/src/libcharon/plugins/unity/unity_handler.c, revision 1.1.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>