Annotation of embedaddon/strongswan/src/libcharon/sa/ikev1/tasks/isakmp_natd.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * Copyright (C) 2006-2011 Tobias Brunner,
        !             3:  * Copyright (C) 2006-2007 Martin Willi
        !             4:  * Copyright (C) 2006 Daniel Roethlisberger
        !             5:  * HSR Hochschule fuer Technik Rapperswil
        !             6:  *
        !             7:  * This program is free software; you can redistribute it and/or modify it
        !             8:  * under the terms of the GNU General Public License as published by the
        !             9:  * Free Software Foundation; either version 2 of the License, or (at your
        !            10:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
        !            11:  *
        !            12:  * This program is distributed in the hope that it will be useful, but
        !            13:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
        !            14:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
        !            15:  * for more details.
        !            16:  */
        !            17: 
        !            18: /*
        !            19:  * Copyright (C) 2012 Volker RĂ¼melin
        !            20:  *
        !            21:  * Permission is hereby granted, free of charge, to any person obtaining a copy
        !            22:  * of this software and associated documentation files (the "Software"), to deal
        !            23:  * in the Software without restriction, including without limitation the rights
        !            24:  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        !            25:  * copies of the Software, and to permit persons to whom the Software is
        !            26:  * furnished to do so, subject to the following conditions:
        !            27:  *
        !            28:  * The above copyright notice and this permission notice shall be included in
        !            29:  * all copies or substantial portions of the Software.
        !            30:  *
        !            31:  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        !            32:  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        !            33:  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        !            34:  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        !            35:  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        !            36:  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
        !            37:  * THE SOFTWARE.
        !            38:  */
        !            39: 
        !            40: #include "isakmp_natd.h"
        !            41: 
        !            42: #include <string.h>
        !            43: 
        !            44: #include <daemon.h>
        !            45: #include <sa/ikev1/keymat_v1.h>
        !            46: #include <config/peer_cfg.h>
        !            47: #include <crypto/hashers/hasher.h>
        !            48: #include <encoding/payloads/hash_payload.h>
        !            49: 
        !            50: typedef struct private_isakmp_natd_t private_isakmp_natd_t;
        !            51: 
        !            52: /**
        !            53:  * Private members of a ike_natt_t task.
        !            54:  */
        !            55: struct private_isakmp_natd_t {
        !            56: 
        !            57:        /**
        !            58:         * Public interface.
        !            59:         */
        !            60:        isakmp_natd_t public;
        !            61: 
        !            62:        /**
        !            63:         * Assigned IKE_SA.
        !            64:         */
        !            65:        ike_sa_t *ike_sa;
        !            66: 
        !            67:        /**
        !            68:         * Are we the initiator?
        !            69:         */
        !            70:        bool initiator;
        !            71: 
        !            72:        /**
        !            73:         * Keymat derivation (from SA)
        !            74:         */
        !            75:        keymat_v1_t *keymat;
        !            76: 
        !            77:        /**
        !            78:         * Did we process any NAT detection payloads for a source address?
        !            79:         */
        !            80:        bool src_seen;
        !            81: 
        !            82:        /**
        !            83:         * Did we process any NAT detection payloads for a destination address?
        !            84:         */
        !            85:        bool dst_seen;
        !            86: 
        !            87:        /**
        !            88:         * Have we found a matching source address NAT hash?
        !            89:         */
        !            90:        bool src_matched;
        !            91: 
        !            92:        /**
        !            93:         * Have we found a matching destination address NAT hash?
        !            94:         */
        !            95:        bool dst_matched;
        !            96: };
        !            97: 
        !            98: /**
        !            99:  * Check if UDP encapsulation has to be forced either by config or required
        !           100:  * by the kernel interface
        !           101:  */
        !           102: static bool force_encap(ike_cfg_t *ike_cfg)
        !           103: {
        !           104:        if (!ike_cfg->force_encap(ike_cfg))
        !           105:        {
        !           106:                return charon->kernel->get_features(charon->kernel) &
        !           107:                                        KERNEL_REQUIRE_UDP_ENCAPSULATION;
        !           108:        }
        !           109:        return TRUE;
        !           110: }
        !           111: 
        !           112: /**
        !           113:  * Get NAT-D payload type (RFC 3947 or RFC 3947 drafts).
        !           114:  */
        !           115: static payload_type_t get_nat_d_payload_type(ike_sa_t *ike_sa)
        !           116: {
        !           117:        if (ike_sa->supports_extension(ike_sa, EXT_NATT_DRAFT_02_03))
        !           118:        {
        !           119:                return PLV1_NAT_D_DRAFT_00_03;
        !           120:        }
        !           121:        return PLV1_NAT_D;
        !           122: }
        !           123: 
        !           124: /**
        !           125:  * Build NAT detection hash for a host.
        !           126:  */
        !           127: static chunk_t generate_natd_hash(private_isakmp_natd_t *this,
        !           128:                                                                  ike_sa_id_t *ike_sa_id, host_t *host)
        !           129: {
        !           130:        hasher_t *hasher;
        !           131:        chunk_t natd_chunk, natd_hash;
        !           132:        uint64_t spi_i, spi_r;
        !           133:        uint16_t port;
        !           134: 
        !           135:        hasher = this->keymat->get_hasher(this->keymat);
        !           136:        if (!hasher)
        !           137:        {
        !           138:                DBG1(DBG_IKE, "no hasher available to build NAT-D payload");
        !           139:                return chunk_empty;
        !           140:        }
        !           141: 
        !           142:        spi_i = ike_sa_id->get_initiator_spi(ike_sa_id);
        !           143:        spi_r = ike_sa_id->get_responder_spi(ike_sa_id);
        !           144:        port = htons(host->get_port(host));
        !           145: 
        !           146:        /*  natd_hash = HASH(CKY-I | CKY-R | IP | Port) */
        !           147:        natd_chunk = chunk_cata("cccc", chunk_from_thing(spi_i),
        !           148:                                                    chunk_from_thing(spi_r), host->get_address(host),
        !           149:                                                    chunk_from_thing(port));
        !           150:        if (!hasher->allocate_hash(hasher, natd_chunk, &natd_hash))
        !           151:        {
        !           152:                DBG1(DBG_IKE, "creating NAT-D payload hash failed");
        !           153:                return chunk_empty;
        !           154:        }
        !           155:        DBG3(DBG_IKE, "natd_chunk %B", &natd_chunk);
        !           156:        DBG3(DBG_IKE, "natd_hash %B", &natd_hash);
        !           157: 
        !           158:        return natd_hash;
        !           159: }
        !           160: 
        !           161: /**
        !           162:  * Build a faked NAT-D payload to enforce UDP encapsulation.
        !           163:  */
        !           164: static chunk_t generate_natd_hash_faked(private_isakmp_natd_t *this)
        !           165: {
        !           166:        hasher_t *hasher;
        !           167:        chunk_t chunk;
        !           168:        rng_t *rng;
        !           169: 
        !           170:        hasher = this->keymat->get_hasher(this->keymat);
        !           171:        if (!hasher)
        !           172:        {
        !           173:                DBG1(DBG_IKE, "no hasher available to build NAT-D payload");
        !           174:                return chunk_empty;
        !           175:        }
        !           176:        rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
        !           177:        if (!rng ||
        !           178:                !rng->allocate_bytes(rng, hasher->get_hash_size(hasher), &chunk))
        !           179:        {
        !           180:                DBG1(DBG_IKE, "unable to get random bytes for NAT-D fake");
        !           181:                DESTROY_IF(rng);
        !           182:                return chunk_empty;
        !           183:        }
        !           184:        rng->destroy(rng);
        !           185:        return chunk;
        !           186: }
        !           187: 
        !           188: /**
        !           189:  * Build a NAT-D payload.
        !           190:  */
        !           191: static hash_payload_t *build_natd_payload(private_isakmp_natd_t *this, bool src,
        !           192:                                                                                  host_t *host)
        !           193: {
        !           194:        hash_payload_t *payload;
        !           195:        ike_cfg_t *config;
        !           196:        chunk_t hash;
        !           197: 
        !           198:        config = this->ike_sa->get_ike_cfg(this->ike_sa);
        !           199:        if (src && force_encap(config))
        !           200:        {
        !           201:                hash = generate_natd_hash_faked(this);
        !           202:        }
        !           203:        else
        !           204:        {
        !           205:                ike_sa_id_t *ike_sa_id = this->ike_sa->get_id(this->ike_sa);
        !           206:                hash = generate_natd_hash(this, ike_sa_id, host);
        !           207:        }
        !           208:        if (!hash.len)
        !           209:        {
        !           210:                return NULL;
        !           211:        }
        !           212:        payload = hash_payload_create(get_nat_d_payload_type(this->ike_sa));
        !           213:        payload->set_hash(payload, hash);
        !           214:        chunk_free(&hash);
        !           215:        return payload;
        !           216: }
        !           217: 
        !           218: /**
        !           219:  * Add NAT-D payloads to the message.
        !           220:  */
        !           221: static void add_natd_payloads(private_isakmp_natd_t *this, message_t *message)
        !           222: {
        !           223:        hash_payload_t *payload;
        !           224:        host_t *host;
        !           225: 
        !           226:        /* destination has to be added first */
        !           227:        host = message->get_destination(message);
        !           228:        payload = build_natd_payload(this, FALSE, host);
        !           229:        if (payload)
        !           230:        {
        !           231:                message->add_payload(message, (payload_t*)payload);
        !           232:        }
        !           233: 
        !           234:        /* source is added second, compared with IKEv2 we always know the source,
        !           235:         * as these payloads are added in the second Phase 1 exchange or the
        !           236:         * response to the first */
        !           237:        host = message->get_source(message);
        !           238:        payload = build_natd_payload(this, TRUE, host);
        !           239:        if (payload)
        !           240:        {
        !           241:                message->add_payload(message, (payload_t*)payload);
        !           242:        }
        !           243: }
        !           244: 
        !           245: /**
        !           246:  * Read NAT-D payloads from message and evaluate them.
        !           247:  */
        !           248: static void process_payloads(private_isakmp_natd_t *this, message_t *message)
        !           249: {
        !           250:        enumerator_t *enumerator;
        !           251:        payload_t *payload;
        !           252:        hash_payload_t *hash_payload;
        !           253:        chunk_t hash, src_hash, dst_hash;
        !           254:        ike_sa_id_t *ike_sa_id;
        !           255:        host_t *me, *other;
        !           256:        ike_cfg_t *config;
        !           257: 
        !           258:        /* precompute hashes for incoming NAT-D comparison */
        !           259:        ike_sa_id = message->get_ike_sa_id(message);
        !           260:        me = message->get_destination(message);
        !           261:        other = message->get_source(message);
        !           262:        dst_hash = generate_natd_hash(this, ike_sa_id, me);
        !           263:        src_hash = generate_natd_hash(this, ike_sa_id, other);
        !           264: 
        !           265:        DBG3(DBG_IKE, "precalculated src_hash %B", &src_hash);
        !           266:        DBG3(DBG_IKE, "precalculated dst_hash %B", &dst_hash);
        !           267: 
        !           268:        enumerator = message->create_payload_enumerator(message);
        !           269:        while (enumerator->enumerate(enumerator, &payload))
        !           270:        {
        !           271:                if (payload->get_type(payload) != PLV1_NAT_D &&
        !           272:                        payload->get_type(payload) != PLV1_NAT_D_DRAFT_00_03)
        !           273:                {
        !           274:                        continue;
        !           275:                }
        !           276:                hash_payload = (hash_payload_t*)payload;
        !           277:                if (!this->dst_seen)
        !           278:                {       /* the first NAT-D payload contains the destination hash */
        !           279:                        this->dst_seen = TRUE;
        !           280:                        hash = hash_payload->get_hash(hash_payload);
        !           281:                        DBG3(DBG_IKE, "received dst_hash %B", &hash);
        !           282:                        if (chunk_equals(hash, dst_hash))
        !           283:                        {
        !           284:                                this->dst_matched = TRUE;
        !           285:                        }
        !           286:                        continue;
        !           287:                }
        !           288:                /* the other NAT-D payloads contain source hashes */
        !           289:                this->src_seen = TRUE;
        !           290:                if (!this->src_matched)
        !           291:                {
        !           292:                        hash = hash_payload->get_hash(hash_payload);
        !           293:                        DBG3(DBG_IKE, "received src_hash %B", &hash);
        !           294:                        if (chunk_equals(hash, src_hash))
        !           295:                        {
        !           296:                                this->src_matched = TRUE;
        !           297:                        }
        !           298:                }
        !           299:        }
        !           300:        enumerator->destroy(enumerator);
        !           301: 
        !           302:        chunk_free(&src_hash);
        !           303:        chunk_free(&dst_hash);
        !           304: 
        !           305:        if (this->src_seen && this->dst_seen)
        !           306:        {
        !           307:                this->ike_sa->set_condition(this->ike_sa, COND_NAT_HERE,
        !           308:                                                                        !this->dst_matched);
        !           309:                this->ike_sa->set_condition(this->ike_sa, COND_NAT_THERE,
        !           310:                                                                        !this->src_matched);
        !           311:                config = this->ike_sa->get_ike_cfg(this->ike_sa);
        !           312:                if (this->dst_matched && this->src_matched &&
        !           313:                        force_encap(config))
        !           314:                {
        !           315:                        this->ike_sa->set_condition(this->ike_sa, COND_NAT_FAKE, TRUE);
        !           316:                }
        !           317:        }
        !           318: }
        !           319: 
        !           320: METHOD(task_t, build_i, status_t,
        !           321:        private_isakmp_natd_t *this, message_t *message)
        !           322: {
        !           323:        status_t result = NEED_MORE;
        !           324: 
        !           325:        switch (message->get_exchange_type(message))
        !           326:        {
        !           327:                case AGGRESSIVE:
        !           328:                {       /* add NAT-D payloads to the second request, already processed
        !           329:                         * those by the responder contained in the first response */
        !           330:                        result = SUCCESS;
        !           331:                        /* fall */
        !           332:                }
        !           333:                case ID_PROT:
        !           334:                {       /* add NAT-D payloads to the second request, need to process
        !           335:                         * those by the responder contained in the second response */
        !           336:                        if (message->get_payload(message, PLV1_SECURITY_ASSOCIATION))
        !           337:                        {       /* wait for the second exchange */
        !           338:                                return NEED_MORE;
        !           339:                        }
        !           340:                        add_natd_payloads(this, message);
        !           341:                        return result;
        !           342:                }
        !           343:                default:
        !           344:                        break;
        !           345:        }
        !           346:        return SUCCESS;
        !           347: }
        !           348: 
        !           349: METHOD(task_t, process_i, status_t,
        !           350:        private_isakmp_natd_t *this, message_t *message)
        !           351: {
        !           352:        status_t result = NEED_MORE;
        !           353: 
        !           354:        if (!this->ike_sa->supports_extension(this->ike_sa, EXT_NATT))
        !           355:        {       /* we didn't receive VIDs indicating support for NAT-T */
        !           356:                return SUCCESS;
        !           357:        }
        !           358: 
        !           359:        switch (message->get_exchange_type(message))
        !           360:        {
        !           361:                case ID_PROT:
        !           362:                {       /* process NAT-D payloads in the second response, added them in the
        !           363:                         * second request already, so we're done afterwards */
        !           364:                        if (message->get_payload(message, PLV1_SECURITY_ASSOCIATION))
        !           365:                        {       /* wait for the second exchange */
        !           366:                                return NEED_MORE;
        !           367:                        }
        !           368:                        result = SUCCESS;
        !           369:                        /* fall */
        !           370:                }
        !           371:                case AGGRESSIVE:
        !           372:                {       /* process NAT-D payloads in the first response, add them in the
        !           373:                         * following second request */
        !           374:                        process_payloads(this, message);
        !           375: 
        !           376:                        if (this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY))
        !           377:                        {
        !           378:                                this->ike_sa->float_ports(this->ike_sa);
        !           379:                        }
        !           380:                        return result;
        !           381:                }
        !           382:                default:
        !           383:                        break;
        !           384:        }
        !           385:        return SUCCESS;
        !           386: }
        !           387: 
        !           388: METHOD(task_t, process_r, status_t,
        !           389:        private_isakmp_natd_t *this, message_t *message)
        !           390: {
        !           391:        status_t result = NEED_MORE;
        !           392: 
        !           393:        if (!this->ike_sa->supports_extension(this->ike_sa, EXT_NATT))
        !           394:        {       /* we didn't receive VIDs indicating NAT-T support */
        !           395:                return SUCCESS;
        !           396:        }
        !           397: 
        !           398:        switch (message->get_exchange_type(message))
        !           399:        {
        !           400:                case AGGRESSIVE:
        !           401:                {       /* process NAT-D payloads in the second request, already added ours
        !           402:                         * in the first response */
        !           403:                        result = SUCCESS;
        !           404:                        /* fall */
        !           405:                }
        !           406:                case ID_PROT:
        !           407:                {       /* process NAT-D payloads in the second request, need to add ours
        !           408:                         * to the second response */
        !           409:                        if (message->get_payload(message, PLV1_SECURITY_ASSOCIATION))
        !           410:                        {       /* wait for the second exchange */
        !           411:                                return NEED_MORE;
        !           412:                        }
        !           413:                        process_payloads(this, message);
        !           414:                        return result;
        !           415:                }
        !           416:                default:
        !           417:                        break;
        !           418:        }
        !           419:        return SUCCESS;
        !           420: }
        !           421: 
        !           422: METHOD(task_t, build_r, status_t,
        !           423:        private_isakmp_natd_t *this, message_t *message)
        !           424: {
        !           425:        switch (message->get_exchange_type(message))
        !           426:        {
        !           427:                case ID_PROT:
        !           428:                {       /* add NAT-D payloads to second response, already processed those
        !           429:                         * contained in the second request */
        !           430:                        if (message->get_payload(message, PLV1_SECURITY_ASSOCIATION))
        !           431:                        {       /* wait for the second exchange */
        !           432:                                return NEED_MORE;
        !           433:                        }
        !           434:                        add_natd_payloads(this, message);
        !           435:                        return SUCCESS;
        !           436:                }
        !           437:                case AGGRESSIVE:
        !           438:                {       /* add NAT-D payloads to the first response, process those contained
        !           439:                         * in the following second request */
        !           440:                        add_natd_payloads(this, message);
        !           441:                        return NEED_MORE;
        !           442:                }
        !           443:                default:
        !           444:                        break;
        !           445:        }
        !           446:        return SUCCESS;
        !           447: }
        !           448: 
        !           449: METHOD(task_t, get_type, task_type_t,
        !           450:        private_isakmp_natd_t *this)
        !           451: {
        !           452:        return TASK_ISAKMP_NATD;
        !           453: }
        !           454: 
        !           455: METHOD(task_t, migrate, void,
        !           456:        private_isakmp_natd_t *this, ike_sa_t *ike_sa)
        !           457: {
        !           458:        this->ike_sa = ike_sa;
        !           459:        this->keymat = (keymat_v1_t*)ike_sa->get_keymat(ike_sa);
        !           460:        this->src_seen = FALSE;
        !           461:        this->dst_seen = FALSE;
        !           462:        this->src_matched = FALSE;
        !           463:        this->dst_matched = FALSE;
        !           464: }
        !           465: 
        !           466: METHOD(task_t, destroy, void,
        !           467:        private_isakmp_natd_t *this)
        !           468: {
        !           469:        free(this);
        !           470: }
        !           471: 
        !           472: /*
        !           473:  * Described in header.
        !           474:  */
        !           475: isakmp_natd_t *isakmp_natd_create(ike_sa_t *ike_sa, bool initiator)
        !           476: {
        !           477:        private_isakmp_natd_t *this;
        !           478: 
        !           479:        INIT(this,
        !           480:                .public = {
        !           481:                        .task = {
        !           482:                                .get_type = _get_type,
        !           483:                                .migrate = _migrate,
        !           484:                                .destroy = _destroy,
        !           485:                        },
        !           486:                },
        !           487:                .ike_sa = ike_sa,
        !           488:                .keymat = (keymat_v1_t*)ike_sa->get_keymat(ike_sa),
        !           489:                .initiator = initiator,
        !           490:        );
        !           491: 
        !           492:        if (initiator)
        !           493:        {
        !           494:                this->public.task.build = _build_i;
        !           495:                this->public.task.process = _process_i;
        !           496:        }
        !           497:        else
        !           498:        {
        !           499:                this->public.task.build = _build_r;
        !           500:                this->public.task.process = _process_r;
        !           501:        }
        !           502: 
        !           503:        return &this->public;
        !           504: }

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