Annotation of embedaddon/strongswan/src/libcharon/sa/ikev2/tasks/ike_config.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * Copyright (C) 2007 Martin Willi
        !             3:  * Copyright (C) 2006-2007 Fabian Hartmann, Noah Heusser
        !             4:  * HSR Hochschule fuer Technik Rapperswil
        !             5:  *
        !             6:  * This program is free software; you can redistribute it and/or modify it
        !             7:  * under the terms of the GNU General Public License as published by the
        !             8:  * Free Software Foundation; either version 2 of the License, or (at your
        !             9:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
        !            10:  *
        !            11:  * This program is distributed in the hope that it will be useful, but
        !            12:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
        !            13:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
        !            14:  * for more details.
        !            15:  */
        !            16: 
        !            17: #include "ike_config.h"
        !            18: 
        !            19: #include <daemon.h>
        !            20: #include <encoding/payloads/cp_payload.h>
        !            21: 
        !            22: typedef struct private_ike_config_t private_ike_config_t;
        !            23: 
        !            24: /**
        !            25:  * Private members of a ike_config_t task.
        !            26:  */
        !            27: struct private_ike_config_t {
        !            28: 
        !            29:        /**
        !            30:         * Public methods and task_t interface.
        !            31:         */
        !            32:        ike_config_t public;
        !            33: 
        !            34:        /**
        !            35:         * Assigned IKE_SA.
        !            36:         */
        !            37:        ike_sa_t *ike_sa;
        !            38: 
        !            39:        /**
        !            40:         * Are we the initiator?
        !            41:         */
        !            42:        bool initiator;
        !            43: 
        !            44:        /**
        !            45:         * Did we request a virtual IP?
        !            46:         */
        !            47:        bool vip_requested;
        !            48: 
        !            49:        /**
        !            50:         * Received list of virtual IPs, host_t*
        !            51:         */
        !            52:        linked_list_t *vips;
        !            53: 
        !            54:        /**
        !            55:         * list of attributes requested and its handler, entry_t
        !            56:         */
        !            57:        linked_list_t *requested;
        !            58: };
        !            59: 
        !            60: /**
        !            61:  * Entry for a requested attribute and the requesting handler
        !            62:  */
        !            63: typedef struct {
        !            64:        /** attribute requested */
        !            65:        configuration_attribute_type_t type;
        !            66:        /** handler requesting this attribute */
        !            67:        attribute_handler_t *handler;
        !            68: } entry_t;
        !            69: 
        !            70: /**
        !            71:  * build INTERNAL_IPV4/6_ADDRESS attribute from virtual ip
        !            72:  */
        !            73: static configuration_attribute_t *build_vip(host_t *vip)
        !            74: {
        !            75:        configuration_attribute_type_t type;
        !            76:        chunk_t chunk, prefix;
        !            77: 
        !            78:        if (vip->get_family(vip) == AF_INET)
        !            79:        {
        !            80:                type = INTERNAL_IP4_ADDRESS;
        !            81:                if (vip->is_anyaddr(vip))
        !            82:                {
        !            83:                        chunk = chunk_empty;
        !            84:                }
        !            85:                else
        !            86:                {
        !            87:                        chunk = vip->get_address(vip);
        !            88:                }
        !            89:        }
        !            90:        else
        !            91:        {
        !            92:                type = INTERNAL_IP6_ADDRESS;
        !            93:                if (vip->is_anyaddr(vip))
        !            94:                {
        !            95:                        chunk = chunk_empty;
        !            96:                }
        !            97:                else
        !            98:                {
        !            99:                        prefix = chunk_alloca(1);
        !           100:                        *prefix.ptr = 64;
        !           101:                        chunk = vip->get_address(vip);
        !           102:                        chunk = chunk_cata("cc", chunk, prefix);
        !           103:                }
        !           104:        }
        !           105:        return configuration_attribute_create_chunk(PLV2_CONFIGURATION_ATTRIBUTE,
        !           106:                                                                                                type, chunk);
        !           107: }
        !           108: 
        !           109: /**
        !           110:  * Handle a received attribute as initiator
        !           111:  */
        !           112: static void handle_attribute(private_ike_config_t *this,
        !           113:                                                         configuration_attribute_t *ca)
        !           114: {
        !           115:        attribute_handler_t *handler = NULL;
        !           116:        enumerator_t *enumerator;
        !           117:        entry_t *entry;
        !           118: 
        !           119:        /* find the handler which requested this attribute */
        !           120:        enumerator = this->requested->create_enumerator(this->requested);
        !           121:        while (enumerator->enumerate(enumerator, &entry))
        !           122:        {
        !           123:                if (entry->type == ca->get_type(ca))
        !           124:                {
        !           125:                        handler = entry->handler;
        !           126:                        this->requested->remove_at(this->requested, enumerator);
        !           127:                        free(entry);
        !           128:                        break;
        !           129:                }
        !           130:        }
        !           131:        enumerator->destroy(enumerator);
        !           132: 
        !           133:        /* and pass it to the handle function */
        !           134:        handler = charon->attributes->handle(charon->attributes,
        !           135:                                        this->ike_sa, handler, ca->get_type(ca), ca->get_chunk(ca));
        !           136:        this->ike_sa->add_configuration_attribute(this->ike_sa,
        !           137:                                                        handler, ca->get_type(ca), ca->get_chunk(ca));
        !           138: }
        !           139: 
        !           140: /**
        !           141:  * process a single configuration attribute
        !           142:  */
        !           143: static void process_attribute(private_ike_config_t *this,
        !           144:                                                          configuration_attribute_t *ca)
        !           145: {
        !           146:        host_t *ip;
        !           147:        chunk_t addr;
        !           148:        int family = AF_INET6;
        !           149: 
        !           150:        switch (ca->get_type(ca))
        !           151:        {
        !           152:                case INTERNAL_IP4_ADDRESS:
        !           153:                        family = AF_INET;
        !           154:                        /* fall */
        !           155:                case INTERNAL_IP6_ADDRESS:
        !           156:                {
        !           157:                        if (this->initiator && !this->vip_requested)
        !           158:                        {
        !           159:                                handle_attribute(this, ca);
        !           160:                                return;
        !           161:                        }
        !           162: 
        !           163:                        addr = ca->get_chunk(ca);
        !           164:                        if (addr.len == 0)
        !           165:                        {
        !           166:                                ip = host_create_any(family);
        !           167:                        }
        !           168:                        else
        !           169:                        {
        !           170:                                /* skip prefix byte in IPv6 payload*/
        !           171:                                if (family == AF_INET6)
        !           172:                                {
        !           173:                                        addr.len--;
        !           174:                                }
        !           175:                                ip = host_create_from_chunk(family, addr, 0);
        !           176:                        }
        !           177:                        if (ip)
        !           178:                        {
        !           179:                                this->vips->insert_last(this->vips, ip);
        !           180:                        }
        !           181:                        break;
        !           182:                }
        !           183:                case INTERNAL_IP4_SERVER:
        !           184:                case INTERNAL_IP6_SERVER:
        !           185:                        /* assume it's a Windows client if we see proprietary attributes */
        !           186:                        this->ike_sa->enable_extension(this->ike_sa, EXT_MS_WINDOWS);
        !           187:                        /* fall */
        !           188:                default:
        !           189:                {
        !           190:                        if (this->initiator)
        !           191:                        {
        !           192:                                handle_attribute(this, ca);
        !           193:                        }
        !           194:                }
        !           195:        }
        !           196: }
        !           197: 
        !           198: /**
        !           199:  * Scan for configuration payloads and attributes
        !           200:  */
        !           201: static void process_payloads(private_ike_config_t *this, message_t *message)
        !           202: {
        !           203:        enumerator_t *enumerator, *attributes;
        !           204:        payload_t *payload;
        !           205: 
        !           206:        enumerator = message->create_payload_enumerator(message);
        !           207:        while (enumerator->enumerate(enumerator, &payload))
        !           208:        {
        !           209:                if (payload->get_type(payload) == PLV2_CONFIGURATION)
        !           210:                {
        !           211:                        cp_payload_t *cp = (cp_payload_t*)payload;
        !           212:                        configuration_attribute_t *ca;
        !           213: 
        !           214:                        switch (cp->get_type(cp))
        !           215:                        {
        !           216:                                case CFG_REQUEST:
        !           217:                                case CFG_REPLY:
        !           218:                                {
        !           219:                                        attributes = cp->create_attribute_enumerator(cp);
        !           220:                                        while (attributes->enumerate(attributes, &ca))
        !           221:                                        {
        !           222:                                                DBG2(DBG_IKE, "processing %N attribute",
        !           223:                                                         configuration_attribute_type_names, ca->get_type(ca));
        !           224:                                                process_attribute(this, ca);
        !           225:                                        }
        !           226:                                        attributes->destroy(attributes);
        !           227:                                        break;
        !           228:                                }
        !           229:                                default:
        !           230:                                        DBG1(DBG_IKE, "ignoring %N config payload",
        !           231:                                                 config_type_names, cp->get_type(cp));
        !           232:                                        break;
        !           233:                        }
        !           234:                }
        !           235:        }
        !           236:        enumerator->destroy(enumerator);
        !           237: }
        !           238: 
        !           239: METHOD(task_t, build_i, status_t,
        !           240:        private_ike_config_t *this, message_t *message)
        !           241: {
        !           242:        if (message->get_message_id(message) == 1)
        !           243:        {       /* in first IKE_AUTH only */
        !           244:                cp_payload_t *cp = NULL;
        !           245:                enumerator_t *enumerator;
        !           246:                attribute_handler_t *handler;
        !           247:                peer_cfg_t *config;
        !           248:                configuration_attribute_type_t type;
        !           249:                chunk_t data;
        !           250:                linked_list_t *vips;
        !           251:                host_t *host;
        !           252: 
        !           253:                vips = linked_list_create();
        !           254: 
        !           255:                /* reuse virtual IP if we already have one */
        !           256:                enumerator = this->ike_sa->create_virtual_ip_enumerator(this->ike_sa,
        !           257:                                                                                                                                TRUE);
        !           258:                while (enumerator->enumerate(enumerator, &host))
        !           259:                {
        !           260:                        vips->insert_last(vips, host);
        !           261:                }
        !           262:                enumerator->destroy(enumerator);
        !           263: 
        !           264:                if (vips->get_count(vips) == 0)
        !           265:                {
        !           266:                        config = this->ike_sa->get_peer_cfg(this->ike_sa);
        !           267:                        enumerator = config->create_virtual_ip_enumerator(config);
        !           268:                        while (enumerator->enumerate(enumerator, &host))
        !           269:                        {
        !           270:                                vips->insert_last(vips, host);
        !           271:                        }
        !           272:                        enumerator->destroy(enumerator);
        !           273:                }
        !           274: 
        !           275:                if (vips->get_count(vips))
        !           276:                {
        !           277:                        cp = cp_payload_create_type(PLV2_CONFIGURATION, CFG_REQUEST);
        !           278:                        enumerator = vips->create_enumerator(vips);
        !           279:                        while (enumerator->enumerate(enumerator, &host))
        !           280:                        {
        !           281:                                cp->add_attribute(cp, build_vip(host));
        !           282:                        }
        !           283:                        enumerator->destroy(enumerator);
        !           284:                        this->vip_requested = TRUE;
        !           285:                }
        !           286: 
        !           287:                enumerator = charon->attributes->create_initiator_enumerator(
        !           288:                                                                                charon->attributes, this->ike_sa, vips);
        !           289:                while (enumerator->enumerate(enumerator, &handler, &type, &data))
        !           290:                {
        !           291:                        configuration_attribute_t *ca;
        !           292:                        entry_t *entry;
        !           293: 
        !           294:                        /* create configuration attribute */
        !           295:                        DBG2(DBG_IKE, "building %N attribute",
        !           296:                                 configuration_attribute_type_names, type);
        !           297:                        ca = configuration_attribute_create_chunk(PLV2_CONFIGURATION_ATTRIBUTE,
        !           298:                                                                                                          type, data);
        !           299:                        if (!cp)
        !           300:                        {
        !           301:                                cp = cp_payload_create_type(PLV2_CONFIGURATION, CFG_REQUEST);
        !           302:                        }
        !           303:                        cp->add_attribute(cp, ca);
        !           304: 
        !           305:                        /* save handler along with requested type */
        !           306:                        entry = malloc_thing(entry_t);
        !           307:                        entry->type = type;
        !           308:                        entry->handler = handler;
        !           309: 
        !           310:                        this->requested->insert_last(this->requested, entry);
        !           311:                }
        !           312:                enumerator->destroy(enumerator);
        !           313: 
        !           314:                vips->destroy(vips);
        !           315: 
        !           316:                if (cp)
        !           317:                {
        !           318:                        message->add_payload(message, (payload_t*)cp);
        !           319:                }
        !           320:                else
        !           321:                {       /* we don't expect a CFG_REPLY */
        !           322:                        return SUCCESS;
        !           323:                }
        !           324:        }
        !           325:        return NEED_MORE;
        !           326: }
        !           327: 
        !           328: METHOD(task_t, process_r, status_t,
        !           329:        private_ike_config_t *this, message_t *message)
        !           330: {
        !           331:        if (message->get_message_id(message) == 1)
        !           332:        {       /* in first IKE_AUTH only */
        !           333:                process_payloads(this, message);
        !           334:        }
        !           335:        return NEED_MORE;
        !           336: }
        !           337: 
        !           338: METHOD(task_t, build_r, status_t,
        !           339:        private_ike_config_t *this, message_t *message)
        !           340: {
        !           341:        if (this->ike_sa->get_state(this->ike_sa) == IKE_ESTABLISHED)
        !           342:        {       /* in last IKE_AUTH exchange */
        !           343:                enumerator_t *enumerator;
        !           344:                configuration_attribute_type_t type;
        !           345:                chunk_t value;
        !           346:                cp_payload_t *cp = NULL;
        !           347:                peer_cfg_t *config;
        !           348:                identification_t *id;
        !           349:                linked_list_t *vips, *pools;
        !           350:                host_t *requested;
        !           351: 
        !           352:                if (this->ike_sa->has_condition(this->ike_sa, COND_REDIRECTED))
        !           353:                {       /* don't assign attributes for redirected SAs */
        !           354:                        return SUCCESS;
        !           355:                }
        !           356: 
        !           357:                id = this->ike_sa->get_other_eap_id(this->ike_sa);
        !           358:                config = this->ike_sa->get_peer_cfg(this->ike_sa);
        !           359:                vips = linked_list_create();
        !           360:                pools = linked_list_create_from_enumerator(
        !           361:                                                                        config->create_pool_enumerator(config));
        !           362: 
        !           363:                this->ike_sa->clear_virtual_ips(this->ike_sa, FALSE);
        !           364: 
        !           365:                enumerator = this->vips->create_enumerator(this->vips);
        !           366:                while (enumerator->enumerate(enumerator, &requested))
        !           367:                {
        !           368:                        host_t *found = NULL;
        !           369: 
        !           370:                        /* query all pools until we get an address */
        !           371:                        DBG1(DBG_IKE, "peer requested virtual IP %H", requested);
        !           372: 
        !           373:                        found = charon->attributes->acquire_address(charon->attributes,
        !           374:                                                                                                pools, this->ike_sa, requested);
        !           375:                        if (found)
        !           376:                        {
        !           377:                                DBG1(DBG_IKE, "assigning virtual IP %H to peer '%Y'", found, id);
        !           378:                                this->ike_sa->add_virtual_ip(this->ike_sa, FALSE, found);
        !           379:                                if (!cp)
        !           380:                                {
        !           381:                                        cp = cp_payload_create_type(PLV2_CONFIGURATION, CFG_REPLY);
        !           382:                                }
        !           383:                                cp->add_attribute(cp, build_vip(found));
        !           384:                                vips->insert_last(vips, found);
        !           385:                        }
        !           386:                        else
        !           387:                        {
        !           388:                                DBG1(DBG_IKE, "no virtual IP found for %H requested by '%Y'",
        !           389:                                         requested, id);
        !           390:                        }
        !           391:                }
        !           392:                enumerator->destroy(enumerator);
        !           393: 
        !           394:                if (this->vips->get_count(this->vips) && !vips->get_count(vips))
        !           395:                {
        !           396:                        DBG1(DBG_IKE, "no virtual IP found, sending %N",
        !           397:                                 notify_type_names, INTERNAL_ADDRESS_FAILURE);
        !           398:                        charon->bus->alert(charon->bus, ALERT_VIP_FAILURE, this->vips);
        !           399:                        message->add_notify(message, FALSE, INTERNAL_ADDRESS_FAILURE,
        !           400:                                                                chunk_empty);
        !           401:                        vips->destroy_offset(vips, offsetof(host_t, destroy));
        !           402:                        pools->destroy(pools);
        !           403:                        return SUCCESS;
        !           404:                }
        !           405:                charon->bus->assign_vips(charon->bus, this->ike_sa, TRUE);
        !           406: 
        !           407:                if (pools->get_count(pools) && !this->vips->get_count(this->vips))
        !           408:                {
        !           409:                        DBG1(DBG_IKE, "expected a virtual IP request, sending %N",
        !           410:                                 notify_type_names, FAILED_CP_REQUIRED);
        !           411:                        charon->bus->alert(charon->bus, ALERT_VIP_FAILURE, this->vips);
        !           412:                        message->add_notify(message, FALSE, FAILED_CP_REQUIRED, chunk_empty);
        !           413:                        vips->destroy_offset(vips, offsetof(host_t, destroy));
        !           414:                        pools->destroy(pools);
        !           415:                        return SUCCESS;
        !           416:                }
        !           417: 
        !           418:                /* query registered providers for additional attributes to include */
        !           419:                enumerator = charon->attributes->create_responder_enumerator(
        !           420:                                                                charon->attributes, pools, this->ike_sa, vips);
        !           421:                while (enumerator->enumerate(enumerator, &type, &value))
        !           422:                {
        !           423:                        if (!cp)
        !           424:                        {
        !           425:                                cp = cp_payload_create_type(PLV2_CONFIGURATION, CFG_REPLY);
        !           426:                        }
        !           427:                        DBG2(DBG_IKE, "building %N attribute",
        !           428:                                 configuration_attribute_type_names, type);
        !           429:                        cp->add_attribute(cp,
        !           430:                                configuration_attribute_create_chunk(PLV2_CONFIGURATION_ATTRIBUTE,
        !           431:                                                                                                         type, value));
        !           432:                }
        !           433:                enumerator->destroy(enumerator);
        !           434:                vips->destroy_offset(vips, offsetof(host_t, destroy));
        !           435:                pools->destroy(pools);
        !           436: 
        !           437:                if (cp)
        !           438:                {
        !           439:                        message->add_payload(message, (payload_t*)cp);
        !           440:                }
        !           441:                return SUCCESS;
        !           442:        }
        !           443:        return NEED_MORE;
        !           444: }
        !           445: 
        !           446: METHOD(task_t, process_i, status_t,
        !           447:        private_ike_config_t *this, message_t *message)
        !           448: {
        !           449:        if (this->ike_sa->get_state(this->ike_sa) == IKE_ESTABLISHED)
        !           450:        {       /* in last IKE_AUTH exchange */
        !           451:                enumerator_t *enumerator;
        !           452:                host_t *host;
        !           453: 
        !           454:                process_payloads(this, message);
        !           455: 
        !           456:                this->ike_sa->clear_virtual_ips(this->ike_sa, TRUE);
        !           457: 
        !           458:                enumerator = this->vips->create_enumerator(this->vips);
        !           459:                while (enumerator->enumerate(enumerator, &host))
        !           460:                {
        !           461:                        if (!host->is_anyaddr(host))
        !           462:                        {
        !           463:                                this->ike_sa->add_virtual_ip(this->ike_sa, TRUE, host);
        !           464:                        }
        !           465:                }
        !           466:                enumerator->destroy(enumerator);
        !           467: 
        !           468:                charon->bus->handle_vips(charon->bus, this->ike_sa, TRUE);
        !           469:                return SUCCESS;
        !           470:        }
        !           471:        return NEED_MORE;
        !           472: }
        !           473: 
        !           474: METHOD(task_t, get_type, task_type_t,
        !           475:        private_ike_config_t *this)
        !           476: {
        !           477:        return TASK_IKE_CONFIG;
        !           478: }
        !           479: 
        !           480: METHOD(task_t, migrate, void,
        !           481:        private_ike_config_t *this, ike_sa_t *ike_sa)
        !           482: {
        !           483:        this->ike_sa = ike_sa;
        !           484:        this->vips->destroy_offset(this->vips, offsetof(host_t, destroy));
        !           485:        this->vips = linked_list_create();
        !           486:        this->requested->destroy_function(this->requested, free);
        !           487:        this->requested = linked_list_create();
        !           488: }
        !           489: 
        !           490: METHOD(task_t, destroy, void,
        !           491:        private_ike_config_t *this)
        !           492: {
        !           493:        this->vips->destroy_offset(this->vips, offsetof(host_t, destroy));
        !           494:        this->requested->destroy_function(this->requested, free);
        !           495:        free(this);
        !           496: }
        !           497: 
        !           498: /*
        !           499:  * Described in header.
        !           500:  */
        !           501: ike_config_t *ike_config_create(ike_sa_t *ike_sa, bool initiator)
        !           502: {
        !           503:        private_ike_config_t *this;
        !           504: 
        !           505:        INIT(this,
        !           506:                .public = {
        !           507:                        .task = {
        !           508:                                .get_type = _get_type,
        !           509:                                .migrate = _migrate,
        !           510:                                .destroy = _destroy,
        !           511:                        },
        !           512:                },
        !           513:                .initiator = initiator,
        !           514:                .ike_sa = ike_sa,
        !           515:                .vips = linked_list_create(),
        !           516:                .requested = linked_list_create(),
        !           517:        );
        !           518: 
        !           519:        if (initiator)
        !           520:        {
        !           521:                this->public.task.build = _build_i;
        !           522:                this->public.task.process = _process_i;
        !           523:        }
        !           524:        else
        !           525:        {
        !           526:                this->public.task.build = _build_r;
        !           527:                this->public.task.process = _process_r;
        !           528:        }
        !           529: 
        !           530:        return &this->public;
        !           531: }

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