Annotation of embedaddon/strongswan/src/libcharon/plugins/ha/ha_dispatcher.c, revision 1.1.1.2

1.1       misho       1: /*
                      2:  * Copyright (C) 2008 Martin Willi
                      3:  * HSR Hochschule fuer Technik Rapperswil
                      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 "ha_dispatcher.h"
                     17: 
                     18: #include <daemon.h>
                     19: #include <sa/ikev2/keymat_v2.h>
                     20: #include <sa/ikev1/keymat_v1.h>
                     21: #include <processing/jobs/callback_job.h>
                     22: #include <processing/jobs/adopt_children_job.h>
                     23: 
                     24: typedef struct private_ha_dispatcher_t private_ha_dispatcher_t;
                     25: typedef struct ha_diffie_hellman_t ha_diffie_hellman_t;
                     26: 
                     27: /**
                     28:  * Private data of an ha_dispatcher_t object.
                     29:  */
                     30: struct private_ha_dispatcher_t {
                     31: 
                     32:        /**
                     33:         * Public ha_dispatcher_t interface.
                     34:         */
                     35:        ha_dispatcher_t public;
                     36: 
                     37:        /**
                     38:         * socket to pull messages from
                     39:         */
                     40:        ha_socket_t *socket;
                     41: 
                     42:        /**
                     43:         * segments to control
                     44:         */
                     45:        ha_segments_t *segments;
                     46: 
                     47:        /**
                     48:         * Cache for resync
                     49:         */
                     50:        ha_cache_t *cache;
                     51: 
                     52:        /**
                     53:         * Kernel helper
                     54:         */
                     55:        ha_kernel_t *kernel;
                     56: 
                     57:        /**
                     58:         * HA enabled pool
                     59:         */
                     60:        ha_attribute_t *attr;
                     61: };
                     62: 
                     63: /**
                     64:  * DH implementation for HA synced DH values
                     65:  */
                     66: struct ha_diffie_hellman_t {
                     67: 
                     68:        /**
                     69:         * Implements diffie_hellman_t
                     70:         */
                     71:        diffie_hellman_t dh;
                     72: 
                     73:        /**
                     74:         * Shared secret
                     75:         */
                     76:        chunk_t secret;
                     77: 
                     78:        /**
                     79:         * Own public value
                     80:         */
                     81:        chunk_t pub;
                     82: };
                     83: 
                     84: METHOD(diffie_hellman_t, dh_get_shared_secret, bool,
                     85:        ha_diffie_hellman_t *this, chunk_t *secret)
                     86: {
                     87:        *secret = chunk_clone(this->secret);
                     88:        return TRUE;
                     89: }
                     90: 
                     91: METHOD(diffie_hellman_t, dh_get_my_public_value, bool,
                     92:        ha_diffie_hellman_t *this, chunk_t *value)
                     93: {
                     94:        *value = chunk_clone(this->pub);
                     95:        return TRUE;
                     96: }
                     97: 
                     98: METHOD(diffie_hellman_t, dh_destroy, void,
                     99:        ha_diffie_hellman_t *this)
                    100: {
                    101:        free(this);
                    102: }
                    103: 
                    104: /**
                    105:  * Create a HA synced DH implementation
                    106:  */
                    107: static diffie_hellman_t *ha_diffie_hellman_create(chunk_t secret, chunk_t pub)
                    108: {
                    109:        ha_diffie_hellman_t *this;
                    110: 
                    111:        INIT(this,
                    112:                .dh = {
                    113:                        .get_shared_secret = _dh_get_shared_secret,
                    114:                        .get_my_public_value = _dh_get_my_public_value,
                    115:                        .destroy = _dh_destroy,
                    116:                },
                    117:                .secret = secret,
                    118:                .pub = pub,
                    119:        );
                    120: 
                    121:        return &this->dh;
                    122: }
                    123: 
                    124: /**
                    125:  * Process messages of type IKE_ADD
                    126:  */
                    127: static void process_ike_add(private_ha_dispatcher_t *this, ha_message_t *message)
                    128: {
                    129:        ha_message_attribute_t attribute;
                    130:        ha_message_value_t value;
                    131:        enumerator_t *enumerator;
                    132:        ike_sa_t *ike_sa = NULL, *old_sa = NULL;
                    133:        ike_version_t version = IKEV2;
                    134:        uint16_t encr = 0, len = 0, integ = 0, prf = 0, old_prf = PRF_UNDEFINED;
                    135:        uint16_t dh_grp = 0;
                    136:        chunk_t nonce_i = chunk_empty, nonce_r = chunk_empty;
                    137:        chunk_t secret = chunk_empty, old_skd = chunk_empty;
                    138:        chunk_t dh_local = chunk_empty, dh_remote = chunk_empty, psk = chunk_empty;
                    139:        host_t *other = NULL;
                    140:        bool ok = FALSE;
                    141:        auth_method_t method = AUTH_RSA;
                    142: 
                    143:        enumerator = message->create_attribute_enumerator(message);
                    144:        while (enumerator->enumerate(enumerator, &attribute, &value))
                    145:        {
                    146:                switch (attribute)
                    147:                {
                    148:                        case HA_IKE_ID:
                    149:                                ike_sa = ike_sa_create(value.ike_sa_id,
                    150:                                                value.ike_sa_id->is_initiator(value.ike_sa_id), version);
                    151:                                break;
                    152:                        case HA_IKE_REKEY_ID:
                    153:                                old_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
                    154:                                                                                                                  value.ike_sa_id);
                    155:                                break;
                    156:                        case HA_REMOTE_ADDR:
                    157:                                other = value.host->clone(value.host);
                    158:                                break;
                    159:                        case HA_IKE_VERSION:
                    160:                                version = value.u8;
                    161:                                break;
                    162:                        case HA_NONCE_I:
                    163:                                nonce_i = value.chunk;
                    164:                                break;
                    165:                        case HA_NONCE_R:
                    166:                                nonce_r = value.chunk;
                    167:                                break;
                    168:                        case HA_SECRET:
                    169:                                secret = value.chunk;
                    170:                                break;
                    171:                        case HA_LOCAL_DH:
                    172:                                dh_local = value.chunk;
                    173:                                break;
                    174:                        case HA_REMOTE_DH:
                    175:                                dh_remote = value.chunk;
                    176:                                break;
                    177:                        case HA_PSK:
                    178:                                psk = value.chunk;
                    179:                                break;
                    180:                        case HA_OLD_SKD:
                    181:                                old_skd = value.chunk;
                    182:                                break;
                    183:                        case HA_ALG_ENCR:
                    184:                                encr = value.u16;
                    185:                                break;
                    186:                        case HA_ALG_ENCR_LEN:
                    187:                                len = value.u16;
                    188:                                break;
                    189:                        case HA_ALG_INTEG:
                    190:                                integ = value.u16;
                    191:                                break;
                    192:                        case HA_ALG_PRF:
                    193:                                prf = value.u16;
                    194:                                break;
                    195:                        case HA_ALG_OLD_PRF:
                    196:                                old_prf = value.u16;
                    197:                                break;
                    198:                        case HA_ALG_DH:
                    199:                                dh_grp = value.u16;
                    200:                                break;
                    201:                        case HA_AUTH_METHOD:
                    202:                                method = value.u16;
                    203:                        default:
                    204:                                break;
                    205:                }
                    206:        }
                    207:        enumerator->destroy(enumerator);
                    208: 
                    209:        if (ike_sa)
                    210:        {
                    211:                proposal_t *proposal;
                    212:                diffie_hellman_t *dh;
                    213: 
                    214:                proposal = proposal_create(PROTO_IKE, 0);
                    215:                if (integ)
                    216:                {
                    217:                        proposal->add_algorithm(proposal, INTEGRITY_ALGORITHM, integ, 0);
                    218:                }
                    219:                if (encr)
                    220:                {
                    221:                        proposal->add_algorithm(proposal, ENCRYPTION_ALGORITHM, encr, len);
                    222:                }
                    223:                if (prf)
                    224:                {
                    225:                        proposal->add_algorithm(proposal, PSEUDO_RANDOM_FUNCTION, prf, 0);
                    226:                }
                    227:                if (dh_grp)
                    228:                {
                    229:                        proposal->add_algorithm(proposal, DIFFIE_HELLMAN_GROUP, dh_grp, 0);
                    230:                }
                    231:                charon->bus->set_sa(charon->bus, ike_sa);
                    232:                dh = ha_diffie_hellman_create(secret, dh_local);
                    233:                if (ike_sa->get_version(ike_sa) == IKEV2)
                    234:                {
                    235:                        keymat_v2_t *keymat_v2 = (keymat_v2_t*)ike_sa->get_keymat(ike_sa);
                    236: 
                    237:                        ok = keymat_v2->derive_ike_keys(keymat_v2, proposal, dh, nonce_i,
                    238:                                                        nonce_r, ike_sa->get_id(ike_sa), old_prf, old_skd);
                    239:                }
                    240:                if (ike_sa->get_version(ike_sa) == IKEV1)
                    241:                {
                    242:                        keymat_v1_t *keymat_v1 = (keymat_v1_t*)ike_sa->get_keymat(ike_sa);
                    243:                        shared_key_t *shared = NULL;
                    244: 
                    245:                        if (psk.len)
                    246:                        {
                    247:                                method = AUTH_PSK;
                    248:                                shared = shared_key_create(SHARED_IKE, chunk_clone(psk));
                    249:                        }
                    250:                        if (keymat_v1->create_hasher(keymat_v1, proposal))
                    251:                        {
                    252:                                ok = keymat_v1->derive_ike_keys(keymat_v1, proposal,
                    253:                                                                dh, dh_remote, nonce_i, nonce_r,
                    254:                                                                ike_sa->get_id(ike_sa), method, shared);
                    255:                        }
                    256:                        DESTROY_IF(shared);
                    257:                }
                    258:                dh->destroy(dh);
                    259:                if (ok)
                    260:                {
                    261:                        if (old_sa)
1.1.1.2 ! misho     262:                        {       /* register IKE_SA before calling inherit_post() so no scheduled
        !           263:                                 * jobs are lost */
        !           264:                                charon->ike_sa_manager->checkout_new(charon->ike_sa_manager,
        !           265:                                                                                                         old_sa);
1.1       misho     266:                                ike_sa->inherit_pre(ike_sa, old_sa);
                    267:                                ike_sa->inherit_post(ike_sa, old_sa);
                    268:                                charon->ike_sa_manager->checkin_and_destroy(
                    269:                                                                                                charon->ike_sa_manager, old_sa);
                    270:                                old_sa = NULL;
                    271:                        }
                    272:                        if (other)
                    273:                        {
                    274:                                ike_sa->set_other_host(ike_sa, other);
                    275:                                other = NULL;
                    276:                        }
                    277:                        ike_sa->set_state(ike_sa, IKE_CONNECTING);
                    278:                        ike_sa->set_proposal(ike_sa, proposal);
                    279:                        this->cache->cache(this->cache, ike_sa, message);
                    280:                        message = NULL;
                    281:                        charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
                    282:                }
                    283:                else
                    284:                {
                    285:                        DBG1(DBG_IKE, "HA keymat derivation failed");
                    286:                        ike_sa->destroy(ike_sa);
                    287:                }
                    288:                charon->bus->set_sa(charon->bus, NULL);
                    289:                proposal->destroy(proposal);
                    290:        }
                    291:        if (old_sa)
                    292:        {
                    293:                charon->ike_sa_manager->checkin(charon->ike_sa_manager, old_sa);
                    294:        }
                    295:        DESTROY_IF(other);
                    296:        DESTROY_IF(message);
                    297: }
                    298: 
                    299: /**
                    300:  * Apply a condition flag to the IKE_SA if it is in set
                    301:  */
                    302: static void set_condition(ike_sa_t *ike_sa, ike_condition_t set,
                    303:                                                  ike_condition_t flag)
                    304: {
                    305:        ike_sa->set_condition(ike_sa, flag, flag & set);
                    306: }
                    307: 
                    308: /**
                    309:  * Apply a extension flag to the IKE_SA if it is in set
                    310:  */
                    311: static void set_extension(ike_sa_t *ike_sa, ike_extension_t set,
                    312:                                                  ike_extension_t flag)
                    313: {
                    314:        if (flag & set)
                    315:        {
                    316:                ike_sa->enable_extension(ike_sa, flag);
                    317:        }
                    318: }
                    319: 
                    320: /**
                    321:  * Process messages of type IKE_UPDATE
                    322:  */
                    323: static void process_ike_update(private_ha_dispatcher_t *this,
                    324:                                                           ha_message_t *message)
                    325: {
                    326:        ha_message_attribute_t attribute;
                    327:        ha_message_value_t value;
                    328:        enumerator_t *enumerator;
                    329:        ike_sa_t *ike_sa = NULL;
                    330:        peer_cfg_t *peer_cfg = NULL;
                    331:        auth_cfg_t *auth;
                    332:        bool received_vip = FALSE, first_local_vip = TRUE, first_peer_addr = TRUE;
                    333: 
                    334:        enumerator = message->create_attribute_enumerator(message);
                    335:        while (enumerator->enumerate(enumerator, &attribute, &value))
                    336:        {
                    337:                if (attribute != HA_IKE_ID && ike_sa == NULL)
                    338:                {
                    339:                        /* must be first attribute */
                    340:                        break;
                    341:                }
                    342:                switch (attribute)
                    343:                {
                    344:                        case HA_IKE_ID:
                    345:                                ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
                    346:                                                                                                                  value.ike_sa_id);
                    347:                                break;
                    348:                        case HA_LOCAL_ID:
                    349:                                ike_sa->set_my_id(ike_sa, value.id->clone(value.id));
                    350:                                break;
                    351:                        case HA_REMOTE_ID:
                    352:                                ike_sa->set_other_id(ike_sa, value.id->clone(value.id));
                    353:                                break;
                    354:                        case HA_REMOTE_EAP_ID:
                    355:                                auth = auth_cfg_create();
                    356:                                auth->add(auth, AUTH_RULE_EAP_IDENTITY, value.id->clone(value.id));
                    357:                                ike_sa->add_auth_cfg(ike_sa, FALSE, auth);
                    358:                                break;
                    359:                        case HA_LOCAL_ADDR:
                    360:                                ike_sa->set_my_host(ike_sa, value.host->clone(value.host));
                    361:                                break;
                    362:                        case HA_REMOTE_ADDR:
                    363:                                ike_sa->set_other_host(ike_sa, value.host->clone(value.host));
                    364:                                break;
                    365:                        case HA_LOCAL_VIP:
                    366:                                if (first_local_vip)
                    367:                                {
                    368:                                        ike_sa->clear_virtual_ips(ike_sa, TRUE);
                    369:                                        first_local_vip = FALSE;
                    370:                                }
                    371:                                ike_sa->add_virtual_ip(ike_sa, TRUE, value.host);
                    372:                                break;
                    373:                        case HA_REMOTE_VIP:
                    374:                                if (!received_vip)
                    375:                                {
                    376:                                        ike_sa->clear_virtual_ips(ike_sa, FALSE);
                    377:                                }
                    378:                                ike_sa->add_virtual_ip(ike_sa, FALSE, value.host);
                    379:                                received_vip = TRUE;
                    380:                                break;
                    381:                        case HA_PEER_ADDR:
                    382:                                if (first_peer_addr)
                    383:                                {
                    384:                                        ike_sa->clear_peer_addresses(ike_sa);
                    385:                                        first_peer_addr = FALSE;
                    386:                                }
                    387:                                ike_sa->add_peer_address(ike_sa, value.host->clone(value.host));
                    388:                                break;
                    389:                        case HA_CONFIG_NAME:
                    390:                                peer_cfg = charon->backends->get_peer_cfg_by_name(
                    391:                                                                                                charon->backends, value.str);
                    392:                                if (peer_cfg)
                    393:                                {
                    394:                                        ike_sa->set_peer_cfg(ike_sa, peer_cfg);
                    395:                                        peer_cfg->destroy(peer_cfg);
                    396:                                }
                    397:                                else
                    398:                                {
                    399:                                        DBG1(DBG_IKE, "HA is missing nodes peer configuration");
                    400:                                        charon->ike_sa_manager->checkin_and_destroy(
                    401:                                                                                                charon->ike_sa_manager, ike_sa);
                    402:                                        ike_sa = NULL;
                    403:                                }
                    404:                                break;
                    405:                        case HA_EXTENSIONS:
                    406:                                set_extension(ike_sa, value.u32, EXT_NATT);
                    407:                                set_extension(ike_sa, value.u32, EXT_MOBIKE);
                    408:                                set_extension(ike_sa, value.u32, EXT_HASH_AND_URL);
                    409:                                set_extension(ike_sa, value.u32, EXT_MULTIPLE_AUTH);
                    410:                                set_extension(ike_sa, value.u32, EXT_STRONGSWAN);
                    411:                                set_extension(ike_sa, value.u32, EXT_EAP_ONLY_AUTHENTICATION);
                    412:                                set_extension(ike_sa, value.u32, EXT_MS_WINDOWS);
                    413:                                set_extension(ike_sa, value.u32, EXT_XAUTH);
                    414:                                set_extension(ike_sa, value.u32, EXT_DPD);
                    415:                                break;
                    416:                        case HA_CONDITIONS:
                    417:                                set_condition(ike_sa, value.u32, COND_NAT_ANY);
                    418:                                set_condition(ike_sa, value.u32, COND_NAT_HERE);
                    419:                                set_condition(ike_sa, value.u32, COND_NAT_THERE);
                    420:                                set_condition(ike_sa, value.u32, COND_NAT_FAKE);
                    421:                                set_condition(ike_sa, value.u32, COND_EAP_AUTHENTICATED);
                    422:                                set_condition(ike_sa, value.u32, COND_CERTREQ_SEEN);
                    423:                                set_condition(ike_sa, value.u32, COND_ORIGINAL_INITIATOR);
                    424:                                set_condition(ike_sa, value.u32, COND_STALE);
                    425:                                set_condition(ike_sa, value.u32, COND_INIT_CONTACT_SEEN);
                    426:                                set_condition(ike_sa, value.u32, COND_XAUTH_AUTHENTICATED);
                    427:                                break;
                    428:                        default:
                    429:                                break;
                    430:                }
                    431:        }
                    432:        enumerator->destroy(enumerator);
                    433: 
                    434:        if (ike_sa)
                    435:        {
                    436:                if (ike_sa->get_state(ike_sa) == IKE_CONNECTING &&
                    437:                        ike_sa->get_peer_cfg(ike_sa))
                    438:                {
                    439:                        DBG1(DBG_CFG, "installed HA passive IKE_SA '%s' %H[%Y]...%H[%Y]",
                    440:                                 ike_sa->get_name(ike_sa),
                    441:                                 ike_sa->get_my_host(ike_sa), ike_sa->get_my_id(ike_sa),
                    442:                                 ike_sa->get_other_host(ike_sa), ike_sa->get_other_id(ike_sa));
                    443:                        ike_sa->set_state(ike_sa, IKE_PASSIVE);
                    444:                }
                    445:                if (received_vip)
                    446:                {
                    447:                        enumerator_t *pools, *vips;
                    448:                        host_t *vip;
                    449:                        char *pool;
                    450: 
                    451:                        peer_cfg = ike_sa->get_peer_cfg(ike_sa);
                    452:                        if (peer_cfg)
                    453:                        {
                    454:                                pools = peer_cfg->create_pool_enumerator(peer_cfg);
                    455:                                while (pools->enumerate(pools, &pool))
                    456:                                {
                    457:                                        vips = ike_sa->create_virtual_ip_enumerator(ike_sa, FALSE);
                    458:                                        while (vips->enumerate(vips, &vip))
                    459:                                        {
                    460:                                                this->attr->reserve(this->attr, pool, vip);
                    461:                                        }
                    462:                                        vips->destroy(vips);
                    463:                                }
                    464:                                pools->destroy(pools);
                    465:                        }
                    466:                }
                    467: #ifdef USE_IKEV1
                    468:                if (ike_sa->get_version(ike_sa) == IKEV1)
                    469:                {
                    470:                        lib->processor->queue_job(lib->processor, (job_t*)
                    471:                                                        adopt_children_job_create(ike_sa->get_id(ike_sa)));
                    472:                }
                    473: #endif /* USE_IKEV1 */
                    474:                this->cache->cache(this->cache, ike_sa, message);
                    475:                charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
                    476:        }
                    477:        else
                    478:        {
                    479:                DBG1(DBG_CFG, "passive HA IKE_SA to update not found");
                    480:                message->destroy(message);
                    481:        }
                    482: }
                    483: 
                    484: /**
                    485:  * Process messages of type IKE_MID_INITIATOR/RESPONDER
                    486:  */
                    487: static void process_ike_mid(private_ha_dispatcher_t *this,
                    488:                                                           ha_message_t *message, bool initiator)
                    489: {
                    490:        ha_message_attribute_t attribute;
                    491:        ha_message_value_t value;
                    492:        enumerator_t *enumerator;
                    493:        ike_sa_t *ike_sa = NULL;
                    494:        uint32_t mid = 0;
                    495: 
                    496:        enumerator = message->create_attribute_enumerator(message);
                    497:        while (enumerator->enumerate(enumerator, &attribute, &value))
                    498:        {
                    499:                switch (attribute)
                    500:                {
                    501:                        case HA_IKE_ID:
                    502:                                ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
                    503:                                                                                                                  value.ike_sa_id);
                    504:                                break;
                    505:                        case HA_MID:
                    506:                                mid = value.u32;
                    507:                                break;
                    508:                        default:
                    509:                                break;
                    510:                }
                    511:        }
                    512:        enumerator->destroy(enumerator);
                    513: 
                    514:        if (ike_sa)
                    515:        {
                    516:                if (mid)
                    517:                {
                    518:                        ike_sa->set_message_id(ike_sa, initiator, mid);
                    519:                }
                    520:                this->cache->cache(this->cache, ike_sa, message);
                    521:                charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
                    522:        }
                    523:        else
                    524:        {
                    525:                message->destroy(message);
                    526:        }
                    527: }
                    528: 
                    529: /**
                    530:  * Process messages of type IKE_IV
                    531:  */
                    532: static void process_ike_iv(private_ha_dispatcher_t *this, ha_message_t *message)
                    533: {
                    534:        ha_message_attribute_t attribute;
                    535:        ha_message_value_t value;
                    536:        enumerator_t *enumerator;
                    537:        ike_sa_t *ike_sa = NULL;
                    538:        chunk_t iv = chunk_empty;
                    539: 
                    540:        enumerator = message->create_attribute_enumerator(message);
                    541:        while (enumerator->enumerate(enumerator, &attribute, &value))
                    542:        {
                    543:                switch (attribute)
                    544:                {
                    545:                        case HA_IKE_ID:
                    546:                                ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
                    547:                                                                                                                  value.ike_sa_id);
                    548:                                break;
                    549:                        case HA_IV:
                    550:                                iv = value.chunk;
                    551:                                break;
                    552:                        default:
                    553:                                break;
                    554:                }
                    555:        }
                    556:        enumerator->destroy(enumerator);
                    557: 
                    558:        if (ike_sa)
                    559:        {
                    560:                if (ike_sa->get_version(ike_sa) == IKEV1)
                    561:                {
                    562:                        if (iv.len)
                    563:                        {
                    564:                                keymat_v1_t *keymat;
                    565: 
                    566:                                keymat = (keymat_v1_t*)ike_sa->get_keymat(ike_sa);
                    567:                                if (keymat->update_iv(keymat, 0, iv))
                    568:                                {
                    569:                                        keymat->confirm_iv(keymat, 0);
                    570:                                }
                    571:                        }
                    572:                }
                    573:                this->cache->cache(this->cache, ike_sa, message);
                    574:                charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
                    575:        }
                    576:        else
                    577:        {
                    578:                message->destroy(message);
                    579:        }
                    580: }
                    581: 
                    582: /**
                    583:  * Process messages of type IKE_DELETE
                    584:  */
                    585: static void process_ike_delete(private_ha_dispatcher_t *this,
                    586:                                                           ha_message_t *message)
                    587: {
                    588:        ha_message_attribute_t attribute;
                    589:        ha_message_value_t value;
                    590:        enumerator_t *enumerator;
                    591:        ike_sa_t *ike_sa = NULL;
                    592: 
                    593:        enumerator = message->create_attribute_enumerator(message);
                    594:        while (enumerator->enumerate(enumerator, &attribute, &value))
                    595:        {
                    596:                switch (attribute)
                    597:                {
                    598:                        case HA_IKE_ID:
                    599:                                ike_sa = charon->ike_sa_manager->checkout(
                    600:                                                                        charon->ike_sa_manager, value.ike_sa_id);
                    601:                                break;
                    602:                        default:
                    603:                                break;
                    604:                }
                    605:        }
                    606:        enumerator->destroy(enumerator);
                    607:        if (ike_sa)
                    608:        {
                    609:                this->cache->cache(this->cache, ike_sa, message);
                    610:                charon->ike_sa_manager->checkin_and_destroy(
                    611:                                                charon->ike_sa_manager, ike_sa);
                    612:        }
                    613:        else
                    614:        {
                    615:                message->destroy(message);
                    616:        }
                    617: }
                    618: 
                    619: /**
                    620:  * Lookup a child cfg from the peer cfg by name
                    621:  */
                    622: static child_cfg_t* find_child_cfg(ike_sa_t *ike_sa, char *name)
                    623: {
                    624:        peer_cfg_t *peer_cfg;
                    625:        child_cfg_t *current, *found = NULL;
                    626:        enumerator_t *enumerator;
                    627: 
                    628:        peer_cfg = ike_sa->get_peer_cfg(ike_sa);
                    629:        if (peer_cfg)
                    630:        {
                    631:                enumerator = peer_cfg->create_child_cfg_enumerator(peer_cfg);
                    632:                while (enumerator->enumerate(enumerator, &current))
                    633:                {
                    634:                        if (streq(current->get_name(current), name))
                    635:                        {
                    636:                                found = current;
                    637:                                break;
                    638:                        }
                    639:                }
                    640:                enumerator->destroy(enumerator);
                    641:        }
                    642:        return found;
                    643: }
                    644: 
                    645: /**
                    646:  * Process messages of type CHILD_ADD
                    647:  */
                    648: static void process_child_add(private_ha_dispatcher_t *this,
                    649:                                                          ha_message_t *message)
                    650: {
                    651:        ha_message_attribute_t attribute;
                    652:        ha_message_value_t value;
                    653:        enumerator_t *enumerator;
                    654:        ike_sa_t *ike_sa = NULL;
                    655:        char *config_name = "";
                    656:        child_cfg_t *config = NULL;
                    657:        child_sa_t *child_sa;
                    658:        proposal_t *proposal;
                    659:        bool initiator = FALSE, failed = FALSE, ok = FALSE;
                    660:        uint32_t inbound_spi = 0, outbound_spi = 0;
                    661:        uint16_t inbound_cpi = 0, outbound_cpi = 0;
                    662:        uint8_t mode = MODE_TUNNEL, ipcomp = 0;
                    663:        uint16_t encr = 0, integ = 0, len = 0, dh_grp = 0;
                    664:        uint16_t esn = NO_EXT_SEQ_NUMBERS;
                    665:        u_int seg_i, seg_o;
                    666:        chunk_t nonce_i = chunk_empty, nonce_r = chunk_empty, secret = chunk_empty;
                    667:        chunk_t encr_i, integ_i, encr_r, integ_r;
                    668:        linked_list_t *local_ts, *remote_ts;
                    669:        diffie_hellman_t *dh = NULL;
                    670: 
                    671:        enumerator = message->create_attribute_enumerator(message);
                    672:        while (enumerator->enumerate(enumerator, &attribute, &value))
                    673:        {
                    674:                switch (attribute)
                    675:                {
                    676:                        case HA_IKE_ID:
                    677:                                ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
                    678:                                                                                                                  value.ike_sa_id);
                    679:                                break;
                    680:                        case HA_CONFIG_NAME:
                    681:                                config_name = value.str;
                    682:                                break;
                    683:                        case HA_INITIATOR:
                    684:                                initiator = value.u8;
                    685:                                break;
                    686:                        case HA_INBOUND_SPI:
                    687:                                inbound_spi = value.u32;
                    688:                                break;
                    689:                        case HA_OUTBOUND_SPI:
                    690:                                outbound_spi = value.u32;
                    691:                                break;
                    692:                        case HA_INBOUND_CPI:
                    693:                                inbound_cpi = value.u32;
                    694:                                break;
                    695:                        case HA_OUTBOUND_CPI:
                    696:                                outbound_cpi = value.u32;
                    697:                                break;
                    698:                        case HA_IPSEC_MODE:
                    699:                                mode = value.u8;
                    700:                                break;
                    701:                        case HA_IPCOMP:
                    702:                                ipcomp = value.u8;
                    703:                                break;
                    704:                        case HA_ALG_ENCR:
                    705:                                encr = value.u16;
                    706:                                break;
                    707:                        case HA_ALG_ENCR_LEN:
                    708:                                len = value.u16;
                    709:                                break;
                    710:                        case HA_ALG_INTEG:
                    711:                                integ = value.u16;
                    712:                                break;
                    713:                        case HA_ALG_DH:
                    714:                                dh_grp = value.u16;
                    715:                                break;
                    716:                        case HA_ESN:
                    717:                                esn = value.u16;
                    718:                                break;
                    719:                        case HA_NONCE_I:
                    720:                                nonce_i = value.chunk;
                    721:                                break;
                    722:                        case HA_NONCE_R:
                    723:                                nonce_r = value.chunk;
                    724:                                break;
                    725:                        case HA_SECRET:
                    726:                                secret = value.chunk;
                    727:                                break;
                    728:                        default:
                    729:                                break;
                    730:                }
                    731:        }
                    732:        enumerator->destroy(enumerator);
                    733: 
                    734:        if (!ike_sa)
                    735:        {
                    736:                DBG1(DBG_CHD, "IKE_SA for HA CHILD_SA not found");
                    737:                message->destroy(message);
                    738:                return;
                    739:        }
                    740:        config = find_child_cfg(ike_sa, config_name);
                    741:        if (!config)
                    742:        {
                    743:                DBG1(DBG_CHD, "HA is missing nodes child configuration");
                    744:                charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
                    745:                message->destroy(message);
                    746:                return;
                    747:        }
                    748: 
                    749:        child_sa_create_t data = {
                    750:                .encap = ike_sa->has_condition(ike_sa, COND_NAT_ANY),
                    751:        };
                    752:        child_sa = child_sa_create(ike_sa->get_my_host(ike_sa),
                    753:                                                           ike_sa->get_other_host(ike_sa), config, &data);
                    754:        child_sa->set_mode(child_sa, mode);
                    755:        child_sa->set_protocol(child_sa, PROTO_ESP);
                    756:        child_sa->set_ipcomp(child_sa, ipcomp);
                    757: 
                    758:        proposal = proposal_create(PROTO_ESP, 0);
                    759:        if (integ)
                    760:        {
                    761:                proposal->add_algorithm(proposal, INTEGRITY_ALGORITHM, integ, 0);
                    762:        }
                    763:        if (encr)
                    764:        {
                    765:                proposal->add_algorithm(proposal, ENCRYPTION_ALGORITHM, encr, len);
                    766:        }
                    767:        if (dh_grp)
                    768:        {
                    769:                proposal->add_algorithm(proposal, DIFFIE_HELLMAN_GROUP, dh_grp, 0);
                    770:        }
                    771:        proposal->add_algorithm(proposal, EXTENDED_SEQUENCE_NUMBERS, esn, 0);
                    772:        if (secret.len)
                    773:        {
                    774:                dh = ha_diffie_hellman_create(secret, chunk_empty);
                    775:        }
                    776:        if (ike_sa->get_version(ike_sa) == IKEV2)
                    777:        {
                    778:                keymat_v2_t *keymat_v2 = (keymat_v2_t*)ike_sa->get_keymat(ike_sa);
                    779: 
                    780:                ok = keymat_v2->derive_child_keys(keymat_v2, proposal, dh,
                    781:                                                nonce_i, nonce_r, &encr_i, &integ_i, &encr_r, &integ_r);
                    782:        }
                    783:        if (ike_sa->get_version(ike_sa) == IKEV1)
                    784:        {
                    785:                keymat_v1_t *keymat_v1 = (keymat_v1_t*)ike_sa->get_keymat(ike_sa);
                    786:                uint32_t spi_i, spi_r;
                    787: 
                    788:                spi_i = initiator ? inbound_spi : outbound_spi;
                    789:                spi_r = initiator ? outbound_spi : inbound_spi;
                    790: 
                    791:                ok = keymat_v1->derive_child_keys(keymat_v1, proposal, dh, spi_i, spi_r,
                    792:                                                nonce_i, nonce_r, &encr_i, &integ_i, &encr_r, &integ_r);
                    793:        }
                    794:        DESTROY_IF(dh);
                    795:        if (!ok)
                    796:        {
                    797:                DBG1(DBG_CHD, "HA CHILD_SA key derivation failed");
                    798:                child_sa->destroy(child_sa);
                    799:                proposal->destroy(proposal);
                    800:                charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
                    801:                return;
                    802:        }
                    803:        child_sa->set_proposal(child_sa, proposal);
                    804:        child_sa->set_state(child_sa, CHILD_INSTALLING);
                    805:        proposal->destroy(proposal);
                    806: 
                    807:        /* TODO: Change CHILD_SA API to avoid cloning twice */
                    808:        local_ts = linked_list_create();
                    809:        remote_ts = linked_list_create();
                    810:        enumerator = message->create_attribute_enumerator(message);
                    811:        while (enumerator->enumerate(enumerator, &attribute, &value))
                    812:        {
                    813:                switch (attribute)
                    814:                {
                    815:                        case HA_LOCAL_TS:
                    816:                                local_ts->insert_last(local_ts, value.ts->clone(value.ts));
                    817:                                break;
                    818:                        case HA_REMOTE_TS:
                    819:                                remote_ts->insert_last(remote_ts, value.ts->clone(value.ts));
                    820:                                break;
                    821:                        default:
                    822:                                break;
                    823:                }
                    824:        }
                    825:        enumerator->destroy(enumerator);
                    826: 
                    827:        child_sa->set_policies(child_sa, local_ts, remote_ts);
                    828: 
                    829:        if (initiator)
                    830:        {
                    831:                if (child_sa->install(child_sa, encr_r, integ_r, inbound_spi,
                    832:                                                          inbound_cpi, initiator, TRUE, TRUE) != SUCCESS ||
                    833:                        child_sa->install(child_sa, encr_i, integ_i, outbound_spi,
                    834:                                                          outbound_cpi, initiator, FALSE, TRUE) != SUCCESS)
                    835:                {
                    836:                        failed = TRUE;
                    837:                }
                    838:        }
                    839:        else
                    840:        {
                    841:                if (child_sa->install(child_sa, encr_i, integ_i, inbound_spi,
                    842:                                                          inbound_cpi, initiator, TRUE, TRUE) != SUCCESS ||
                    843:                        child_sa->install(child_sa, encr_r, integ_r, outbound_spi,
                    844:                                                          outbound_cpi, initiator, FALSE, TRUE) != SUCCESS)
                    845:                {
                    846:                        failed = TRUE;
                    847:                }
                    848:        }
                    849:        chunk_clear(&encr_i);
                    850:        chunk_clear(&integ_i);
                    851:        chunk_clear(&encr_r);
                    852:        chunk_clear(&integ_r);
                    853: 
                    854:        if (failed)
                    855:        {
                    856:                DBG1(DBG_CHD, "HA CHILD_SA installation failed");
                    857:                child_sa->destroy(child_sa);
                    858:                local_ts->destroy_offset(local_ts, offsetof(traffic_selector_t, destroy));
                    859:                remote_ts->destroy_offset(remote_ts, offsetof(traffic_selector_t, destroy));
                    860:                charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
                    861:                message->destroy(message);
                    862:                return;
                    863:        }
                    864: 
                    865:        seg_i = this->kernel->get_segment_spi(this->kernel,
                    866:                                                                ike_sa->get_my_host(ike_sa), inbound_spi);
                    867:        seg_o = this->kernel->get_segment_spi(this->kernel,
                    868:                                                                ike_sa->get_other_host(ike_sa), outbound_spi);
                    869: 
                    870:        DBG1(DBG_CFG, "installed HA CHILD_SA %s{%d} %#R === %#R "
                    871:                "(segment in: %d%s, out: %d%s)", child_sa->get_name(child_sa),
                    872:                child_sa->get_unique_id(child_sa), local_ts, remote_ts,
                    873:                seg_i, this->segments->is_active(this->segments, seg_i) ? "*" : "",
                    874:                seg_o, this->segments->is_active(this->segments, seg_o) ? "*" : "");
                    875:        child_sa->install_policies(child_sa);
                    876:        local_ts->destroy_offset(local_ts, offsetof(traffic_selector_t, destroy));
                    877:        remote_ts->destroy_offset(remote_ts, offsetof(traffic_selector_t, destroy));
                    878: 
                    879:        child_sa->set_state(child_sa, CHILD_INSTALLED);
                    880:        ike_sa->add_child_sa(ike_sa, child_sa);
                    881:        message->destroy(message);
                    882:        charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
                    883: }
                    884: 
                    885: /**
                    886:  * Process messages of type CHILD_DELETE
                    887:  */
                    888: static void process_child_delete(private_ha_dispatcher_t *this,
                    889:                                                                 ha_message_t *message)
                    890: {
                    891:        ha_message_attribute_t attribute;
                    892:        ha_message_value_t value;
                    893:        enumerator_t *enumerator;
                    894:        ike_sa_t *ike_sa = NULL;
                    895:        child_sa_t *child_sa;
                    896:        uint32_t spi = 0;
                    897: 
                    898:        enumerator = message->create_attribute_enumerator(message);
                    899:        while (enumerator->enumerate(enumerator, &attribute, &value))
                    900:        {
                    901:                switch (attribute)
                    902:                {
                    903:                        case HA_IKE_ID:
                    904:                                ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
                    905:                                                                                                                  value.ike_sa_id);
                    906:                                break;
                    907:                        case HA_INBOUND_SPI:
                    908:                                spi = value.u32;
                    909:                                break;
                    910:                        default:
                    911:                                break;
                    912:                }
                    913:        }
                    914:        enumerator->destroy(enumerator);
                    915: 
                    916:        if (ike_sa)
                    917:        {
                    918:                child_sa = ike_sa->get_child_sa(ike_sa, PROTO_ESP, spi, TRUE);
                    919:                if (child_sa)
                    920:                {
                    921:                        ike_sa->destroy_child_sa(ike_sa, PROTO_ESP, spi);
                    922:                }
                    923:                charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
                    924:        }
                    925:        message->destroy(message);
                    926: }
                    927: 
                    928: /**
                    929:  * Process messages of type SEGMENT_TAKE/DROP
                    930:  */
                    931: static void process_segment(private_ha_dispatcher_t *this,
                    932:                                                        ha_message_t *message, bool take)
                    933: {
                    934:        ha_message_attribute_t attribute;
                    935:        ha_message_value_t value;
                    936:        enumerator_t *enumerator;
                    937: 
                    938:        enumerator = message->create_attribute_enumerator(message);
                    939:        while (enumerator->enumerate(enumerator, &attribute, &value))
                    940:        {
                    941:                switch (attribute)
                    942:                {
                    943:                        case HA_SEGMENT:
                    944:                                if (take)
                    945:                                {
                    946:                                        DBG1(DBG_CFG, "remote node takes segment %d", value.u16);
                    947:                                        this->segments->deactivate(this->segments, value.u16, FALSE);
                    948:                                }
                    949:                                else
                    950:                                {
                    951:                                        DBG1(DBG_CFG, "remote node drops segment %d", value.u16);
                    952:                                        this->segments->activate(this->segments, value.u16, FALSE);
                    953:                                }
                    954:                                break;
                    955:                        default:
                    956:                                break;
                    957:                }
                    958:        }
                    959:        enumerator->destroy(enumerator);
                    960:        message->destroy(message);
                    961: }
                    962: 
                    963: /**
                    964:  * Process messages of type STATUS
                    965:  */
                    966: static void process_status(private_ha_dispatcher_t *this,
                    967:                                                   ha_message_t *message)
                    968: {
                    969:        ha_message_attribute_t attribute;
                    970:        ha_message_value_t value;
                    971:        enumerator_t *enumerator;
                    972:        segment_mask_t mask = 0;
                    973: 
                    974:        enumerator = message->create_attribute_enumerator(message);
                    975:        while (enumerator->enumerate(enumerator, &attribute, &value))
                    976:        {
                    977:                switch (attribute)
                    978:                {
                    979:                        case HA_SEGMENT:
                    980:                                mask |= SEGMENTS_BIT(value.u16);
                    981:                                break;
                    982:                        default:
                    983:                                break;
                    984:                }
                    985:        }
                    986:        enumerator->destroy(enumerator);
                    987: 
                    988:        this->segments->handle_status(this->segments, mask);
                    989:        message->destroy(message);
                    990: }
                    991: 
                    992: /**
                    993:  * Process messages of type RESYNC
                    994:  */
                    995: static void process_resync(private_ha_dispatcher_t *this,
                    996:                                                   ha_message_t *message)
                    997: {
                    998:        ha_message_attribute_t attribute;
                    999:        ha_message_value_t value;
                   1000:        enumerator_t *enumerator;
                   1001: 
                   1002:        enumerator = message->create_attribute_enumerator(message);
                   1003:        while (enumerator->enumerate(enumerator, &attribute, &value))
                   1004:        {
                   1005:                switch (attribute)
                   1006:                {
                   1007:                        case HA_SEGMENT:
                   1008:                                this->cache->resync(this->cache, value.u16);
                   1009:                                break;
                   1010:                        default:
                   1011:                                break;
                   1012:                }
                   1013:        }
                   1014:        enumerator->destroy(enumerator);
                   1015:        message->destroy(message);
                   1016: }
                   1017: 
                   1018: /**
                   1019:  * Dispatcher job function
                   1020:  */
                   1021: static job_requeue_t dispatch(private_ha_dispatcher_t *this)
                   1022: {
                   1023:        ha_message_t *message;
                   1024:        ha_message_type_t type;
                   1025: 
                   1026:        message = this->socket->pull(this->socket);
                   1027:        type = message->get_type(message);
                   1028:        if (type != HA_STATUS)
                   1029:        {
                   1030:                DBG2(DBG_CFG, "received HA %N message", ha_message_type_names,
                   1031:                         message->get_type(message));
                   1032:        }
                   1033:        switch (type)
                   1034:        {
                   1035:                case HA_IKE_ADD:
                   1036:                        process_ike_add(this, message);
                   1037:                        break;
                   1038:                case HA_IKE_UPDATE:
                   1039:                        process_ike_update(this, message);
                   1040:                        break;
                   1041:                case HA_IKE_MID_INITIATOR:
                   1042:                        process_ike_mid(this, message, TRUE);
                   1043:                        break;
                   1044:                case HA_IKE_MID_RESPONDER:
                   1045:                        process_ike_mid(this, message, FALSE);
                   1046:                        break;
                   1047:                case HA_IKE_IV:
                   1048:                        process_ike_iv(this, message);
                   1049:                        break;
                   1050:                case HA_IKE_DELETE:
                   1051:                        process_ike_delete(this, message);
                   1052:                        break;
                   1053:                case HA_CHILD_ADD:
                   1054:                        process_child_add(this, message);
                   1055:                        break;
                   1056:                case HA_CHILD_DELETE:
                   1057:                        process_child_delete(this, message);
                   1058:                        break;
                   1059:                case HA_SEGMENT_DROP:
                   1060:                        process_segment(this, message, FALSE);
                   1061:                        break;
                   1062:                case HA_SEGMENT_TAKE:
                   1063:                        process_segment(this, message, TRUE);
                   1064:                        break;
                   1065:                case HA_STATUS:
                   1066:                        process_status(this, message);
                   1067:                        break;
                   1068:                case HA_RESYNC:
                   1069:                        process_resync(this, message);
                   1070:                        break;
                   1071:                default:
                   1072:                        DBG1(DBG_CFG, "received unknown HA message type %d", type);
                   1073:                        message->destroy(message);
                   1074:                        break;
                   1075:        }
                   1076:        return JOB_REQUEUE_DIRECT;
                   1077: }
                   1078: 
                   1079: METHOD(ha_dispatcher_t, destroy, void,
                   1080:        private_ha_dispatcher_t *this)
                   1081: {
                   1082:        free(this);
                   1083: }
                   1084: 
                   1085: /**
                   1086:  * See header
                   1087:  */
                   1088: ha_dispatcher_t *ha_dispatcher_create(ha_socket_t *socket,
                   1089:                                                                        ha_segments_t *segments, ha_cache_t *cache,
                   1090:                                                                        ha_kernel_t *kernel, ha_attribute_t *attr)
                   1091: {
                   1092:        private_ha_dispatcher_t *this;
                   1093: 
                   1094: 
                   1095:        INIT(this,
                   1096:                .public = {
                   1097:                        .destroy = _destroy,
                   1098:                },
                   1099:                .socket = socket,
                   1100:                .segments = segments,
                   1101:                .cache = cache,
                   1102:                .kernel = kernel,
                   1103:                .attr = attr,
                   1104:        );
                   1105:        lib->processor->queue_job(lib->processor,
                   1106:                (job_t*)callback_job_create_with_prio((callback_job_cb_t)dispatch, this,
                   1107:                                NULL, (callback_job_cancel_t)return_false, JOB_PRIO_CRITICAL));
                   1108: 
                   1109:        return &this->public;
                   1110: }

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