Annotation of embedaddon/strongswan/src/libcharon/sa/child_sa.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * Copyright (C) 2006-2019 Tobias Brunner
        !             3:  * Copyright (C) 2016 Andreas Steffen
        !             4:  * Copyright (C) 2005-2008 Martin Willi
        !             5:  * Copyright (C) 2006 Daniel Roethlisberger
        !             6:  * Copyright (C) 2005 Jan Hutter
        !             7:  * HSR Hochschule fuer Technik Rapperswil
        !             8:  *
        !             9:  * This program is free software; you can redistribute it and/or modify it
        !            10:  * under the terms of the GNU General Public License as published by the
        !            11:  * Free Software Foundation; either version 2 of the License, or (at your
        !            12:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
        !            13:  *
        !            14:  * This program is distributed in the hope that it will be useful, but
        !            15:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
        !            16:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
        !            17:  * for more details.
        !            18:  */
        !            19: 
        !            20: #define _GNU_SOURCE
        !            21: #include "child_sa.h"
        !            22: 
        !            23: #include <stdio.h>
        !            24: #include <string.h>
        !            25: #include <time.h>
        !            26: 
        !            27: #include <daemon.h>
        !            28: #include <collections/array.h>
        !            29: 
        !            30: ENUM(child_sa_state_names, CHILD_CREATED, CHILD_DESTROYING,
        !            31:        "CREATED",
        !            32:        "ROUTED",
        !            33:        "INSTALLING",
        !            34:        "INSTALLED",
        !            35:        "UPDATING",
        !            36:        "REKEYING",
        !            37:        "REKEYED",
        !            38:        "RETRYING",
        !            39:        "DELETING",
        !            40:        "DELETED",
        !            41:        "DESTROYING",
        !            42: );
        !            43: 
        !            44: ENUM_FLAGS(child_sa_outbound_state_names, CHILD_OUTBOUND_REGISTERED, CHILD_OUTBOUND_POLICIES,
        !            45:        "REGISTERED",
        !            46:        "SA",
        !            47:        "POLICIES",
        !            48: );
        !            49: 
        !            50: typedef struct private_child_sa_t private_child_sa_t;
        !            51: 
        !            52: /**
        !            53:  * Private data of a child_sa_t object.
        !            54:  */
        !            55: struct private_child_sa_t {
        !            56:        /**
        !            57:         * Public interface of child_sa_t.
        !            58:         */
        !            59:        child_sa_t public;
        !            60: 
        !            61:        /**
        !            62:         * address of us
        !            63:         */
        !            64:        host_t *my_addr;
        !            65: 
        !            66:        /**
        !            67:         * address of remote
        !            68:         */
        !            69:        host_t *other_addr;
        !            70: 
        !            71:        /**
        !            72:         * our actually used SPI, 0 if unused
        !            73:         */
        !            74:        uint32_t my_spi;
        !            75: 
        !            76:        /**
        !            77:         * others used SPI, 0 if unused
        !            78:         */
        !            79:        uint32_t other_spi;
        !            80: 
        !            81:        /**
        !            82:         * our Compression Parameter Index (CPI) used, 0 if unused
        !            83:         */
        !            84:        uint16_t my_cpi;
        !            85: 
        !            86:        /**
        !            87:         * others Compression Parameter Index (CPI) used, 0 if unused
        !            88:         */
        !            89:        uint16_t other_cpi;
        !            90: 
        !            91:        /**
        !            92:         * Array for local traffic selectors
        !            93:         */
        !            94:        array_t *my_ts;
        !            95: 
        !            96:        /**
        !            97:         * Array for remote traffic selectors
        !            98:         */
        !            99:        array_t *other_ts;
        !           100: 
        !           101:        /**
        !           102:         * Outbound encryption key cached during a rekeying
        !           103:         */
        !           104:        chunk_t encr_r;
        !           105: 
        !           106:        /**
        !           107:         * Outbound integrity key cached during a rekeying
        !           108:         */
        !           109:        chunk_t integ_r;
        !           110: 
        !           111:        /**
        !           112:         * Whether the outbound SA has only been registered yet during a rekeying
        !           113:         */
        !           114:        child_sa_outbound_state_t outbound_state;
        !           115: 
        !           116:        /**
        !           117:         * Whether the peer supports TFCv3
        !           118:         */
        !           119:        bool tfcv3;
        !           120: 
        !           121:        /**
        !           122:         * The outbound SPI of the CHILD_SA that replaced this one during a rekeying
        !           123:         */
        !           124:        uint32_t rekey_spi;
        !           125: 
        !           126:        /**
        !           127:         * Protocol used to protect this SA, ESP|AH
        !           128:         */
        !           129:        protocol_id_t protocol;
        !           130: 
        !           131:        /**
        !           132:         * reqid used for this child_sa
        !           133:         */
        !           134:        uint32_t reqid;
        !           135: 
        !           136:        /**
        !           137:         * Did we allocate/confirm and must release the reqid?
        !           138:         */
        !           139:        bool reqid_allocated;
        !           140: 
        !           141:        /**
        !           142:         * Is the reqid statically configured
        !           143:         */
        !           144:        bool static_reqid;
        !           145: 
        !           146:        /**
        !           147:         * Unique CHILD_SA identifier
        !           148:         */
        !           149:        uint32_t unique_id;
        !           150: 
        !           151:        /**
        !           152:         * Whether FWD policies in the outbound direction should be installed
        !           153:         */
        !           154:        bool policies_fwd_out;
        !           155: 
        !           156:        /**
        !           157:         * Inbound interface ID
        !           158:         */
        !           159:        uint32_t if_id_in;
        !           160: 
        !           161:        /**
        !           162:         * Outbound interface ID
        !           163:         */
        !           164:        uint32_t if_id_out;
        !           165: 
        !           166:        /**
        !           167:         * inbound mark used for this child_sa
        !           168:         */
        !           169:        mark_t mark_in;
        !           170: 
        !           171:        /**
        !           172:         * outbound mark used for this child_sa
        !           173:         */
        !           174:        mark_t mark_out;
        !           175: 
        !           176:        /**
        !           177:         * absolute time when rekeying is scheduled
        !           178:         */
        !           179:        time_t rekey_time;
        !           180: 
        !           181:        /**
        !           182:         * absolute time when the SA expires
        !           183:         */
        !           184:        time_t expire_time;
        !           185: 
        !           186:        /**
        !           187:         * absolute time when SA has been installed
        !           188:         */
        !           189:        time_t install_time;
        !           190: 
        !           191:        /**
        !           192:         * state of the CHILD_SA
        !           193:         */
        !           194:        child_sa_state_t state;
        !           195: 
        !           196:        /**
        !           197:         * TRUE if this CHILD_SA is used to install trap policies
        !           198:         */
        !           199:        bool trap;
        !           200: 
        !           201:        /**
        !           202:         * Specifies if UDP encapsulation is enabled (NAT traversal)
        !           203:         */
        !           204:        bool encap;
        !           205: 
        !           206:        /**
        !           207:         * Specifies the IPComp transform used (IPCOMP_NONE if disabled)
        !           208:         */
        !           209:        ipcomp_transform_t ipcomp;
        !           210: 
        !           211:        /**
        !           212:         * mode this SA uses, tunnel/transport
        !           213:         */
        !           214:        ipsec_mode_t mode;
        !           215: 
        !           216:        /**
        !           217:         * Action to enforce if peer closes the CHILD_SA
        !           218:         */
        !           219:        action_t close_action;
        !           220: 
        !           221:        /**
        !           222:         * Action to enforce if peer is considered dead
        !           223:         */
        !           224:        action_t dpd_action;
        !           225: 
        !           226:        /**
        !           227:         * selected proposal
        !           228:         */
        !           229:        proposal_t *proposal;
        !           230: 
        !           231:        /**
        !           232:         * config used to create this child
        !           233:         */
        !           234:        child_cfg_t *config;
        !           235: 
        !           236:        /**
        !           237:         * time of last use in seconds (inbound)
        !           238:         */
        !           239:        time_t my_usetime;
        !           240: 
        !           241:        /**
        !           242:         * time of last use in seconds (outbound)
        !           243:         */
        !           244:        time_t other_usetime;
        !           245: 
        !           246:        /**
        !           247:         * last number of inbound bytes
        !           248:         */
        !           249:        uint64_t my_usebytes;
        !           250: 
        !           251:        /**
        !           252:         * last number of outbound bytes
        !           253:         */
        !           254:        uint64_t other_usebytes;
        !           255: 
        !           256:        /**
        !           257:         * last number of inbound packets
        !           258:         */
        !           259:        uint64_t my_usepackets;
        !           260: 
        !           261:        /**
        !           262:         * last number of outbound bytes
        !           263:         */
        !           264:        uint64_t other_usepackets;
        !           265: };
        !           266: 
        !           267: /**
        !           268:  * Convert an IKEv2 specific protocol identifier to the IP protocol identifier
        !           269:  */
        !           270: static inline uint8_t proto_ike2ip(protocol_id_t protocol)
        !           271: {
        !           272:        switch (protocol)
        !           273:        {
        !           274:                case PROTO_ESP:
        !           275:                        return IPPROTO_ESP;
        !           276:                case PROTO_AH:
        !           277:                        return IPPROTO_AH;
        !           278:                default:
        !           279:                        return protocol;
        !           280:        }
        !           281: }
        !           282: 
        !           283: /**
        !           284:  * Returns the mark to use on the inbound SA
        !           285:  */
        !           286: static inline mark_t mark_in_sa(private_child_sa_t *this)
        !           287: {
        !           288:        if (this->config->has_option(this->config, OPT_MARK_IN_SA))
        !           289:        {
        !           290:                return this->mark_in;
        !           291:        }
        !           292:        return (mark_t){};
        !           293: }
        !           294: 
        !           295: METHOD(child_sa_t, get_name, char*,
        !           296:           private_child_sa_t *this)
        !           297: {
        !           298:        return this->config->get_name(this->config);
        !           299: }
        !           300: 
        !           301: METHOD(child_sa_t, get_reqid, uint32_t,
        !           302:           private_child_sa_t *this)
        !           303: {
        !           304:        return this->reqid;
        !           305: }
        !           306: 
        !           307: METHOD(child_sa_t, get_unique_id, uint32_t,
        !           308:        private_child_sa_t *this)
        !           309: {
        !           310:        return this->unique_id;
        !           311: }
        !           312: 
        !           313: METHOD(child_sa_t, get_config, child_cfg_t*,
        !           314:           private_child_sa_t *this)
        !           315: {
        !           316:        return this->config;
        !           317: }
        !           318: 
        !           319: METHOD(child_sa_t, set_state, void,
        !           320:           private_child_sa_t *this, child_sa_state_t state)
        !           321: {
        !           322:        if (this->state != state)
        !           323:        {
        !           324:                DBG2(DBG_CHD, "CHILD_SA %s{%d} state change: %N => %N",
        !           325:                         get_name(this), this->unique_id,
        !           326:                         child_sa_state_names, this->state,
        !           327:                         child_sa_state_names, state);
        !           328:                charon->bus->child_state_change(charon->bus, &this->public, state);
        !           329:                this->state = state;
        !           330:        }
        !           331: }
        !           332: 
        !           333: METHOD(child_sa_t, get_state, child_sa_state_t,
        !           334:           private_child_sa_t *this)
        !           335: {
        !           336:        return this->state;
        !           337: }
        !           338: 
        !           339: METHOD(child_sa_t, get_outbound_state, child_sa_outbound_state_t,
        !           340:           private_child_sa_t *this)
        !           341: {
        !           342:        return this->outbound_state;
        !           343: }
        !           344: 
        !           345: METHOD(child_sa_t, get_spi, uint32_t,
        !           346:           private_child_sa_t *this, bool inbound)
        !           347: {
        !           348:        return inbound ? this->my_spi : this->other_spi;
        !           349: }
        !           350: 
        !           351: METHOD(child_sa_t, get_cpi, uint16_t,
        !           352:           private_child_sa_t *this, bool inbound)
        !           353: {
        !           354:        return inbound ? this->my_cpi : this->other_cpi;
        !           355: }
        !           356: 
        !           357: METHOD(child_sa_t, get_protocol, protocol_id_t,
        !           358:           private_child_sa_t *this)
        !           359: {
        !           360:        return this->protocol;
        !           361: }
        !           362: 
        !           363: METHOD(child_sa_t, set_protocol, void,
        !           364:           private_child_sa_t *this, protocol_id_t protocol)
        !           365: {
        !           366:        this->protocol = protocol;
        !           367: }
        !           368: 
        !           369: METHOD(child_sa_t, get_mode, ipsec_mode_t,
        !           370:           private_child_sa_t *this)
        !           371: {
        !           372:        return this->mode;
        !           373: }
        !           374: 
        !           375: METHOD(child_sa_t, set_mode, void,
        !           376:           private_child_sa_t *this, ipsec_mode_t mode)
        !           377: {
        !           378:        this->mode = mode;
        !           379: }
        !           380: 
        !           381: METHOD(child_sa_t, has_encap, bool,
        !           382:           private_child_sa_t *this)
        !           383: {
        !           384:        return this->encap;
        !           385: }
        !           386: 
        !           387: METHOD(child_sa_t, get_ipcomp, ipcomp_transform_t,
        !           388:           private_child_sa_t *this)
        !           389: {
        !           390:        return this->ipcomp;
        !           391: }
        !           392: 
        !           393: METHOD(child_sa_t, set_ipcomp, void,
        !           394:           private_child_sa_t *this, ipcomp_transform_t ipcomp)
        !           395: {
        !           396:        this->ipcomp = ipcomp;
        !           397: }
        !           398: 
        !           399: METHOD(child_sa_t, set_close_action, void,
        !           400:           private_child_sa_t *this, action_t action)
        !           401: {
        !           402:        this->close_action = action;
        !           403: }
        !           404: 
        !           405: METHOD(child_sa_t, get_close_action, action_t,
        !           406:           private_child_sa_t *this)
        !           407: {
        !           408:        return this->close_action;
        !           409: }
        !           410: 
        !           411: METHOD(child_sa_t, set_dpd_action, void,
        !           412:           private_child_sa_t *this, action_t action)
        !           413: {
        !           414:        this->dpd_action = action;
        !           415: }
        !           416: 
        !           417: METHOD(child_sa_t, get_dpd_action, action_t,
        !           418:           private_child_sa_t *this)
        !           419: {
        !           420:        return this->dpd_action;
        !           421: }
        !           422: 
        !           423: METHOD(child_sa_t, get_proposal, proposal_t*,
        !           424:           private_child_sa_t *this)
        !           425: {
        !           426:        return this->proposal;
        !           427: }
        !           428: 
        !           429: METHOD(child_sa_t, set_proposal, void,
        !           430:           private_child_sa_t *this, proposal_t *proposal)
        !           431: {
        !           432:        this->proposal = proposal->clone(proposal, 0);
        !           433: }
        !           434: 
        !           435: METHOD(child_sa_t, create_ts_enumerator, enumerator_t*,
        !           436:        private_child_sa_t *this, bool local)
        !           437: {
        !           438:        if (local)
        !           439:        {
        !           440:                return array_create_enumerator(this->my_ts);
        !           441:        }
        !           442:        return array_create_enumerator(this->other_ts);
        !           443: }
        !           444: 
        !           445: typedef struct policy_enumerator_t policy_enumerator_t;
        !           446: 
        !           447: /**
        !           448:  * Private policy enumerator
        !           449:  */
        !           450: struct policy_enumerator_t {
        !           451:        /** implements enumerator_t */
        !           452:        enumerator_t public;
        !           453:        /** enumerator over own TS */
        !           454:        enumerator_t *mine;
        !           455:        /** enumerator over others TS */
        !           456:        enumerator_t *other;
        !           457:        /** array of others TS, to recreate enumerator */
        !           458:        array_t *array;
        !           459:        /** currently enumerating TS for "me" side */
        !           460:        traffic_selector_t *ts;
        !           461: };
        !           462: 
        !           463: METHOD(enumerator_t, policy_enumerate, bool,
        !           464:           policy_enumerator_t *this, va_list args)
        !           465: {
        !           466:        traffic_selector_t *other_ts, **my_out, **other_out;
        !           467: 
        !           468:        VA_ARGS_VGET(args, my_out, other_out);
        !           469: 
        !           470:        while (this->ts || this->mine->enumerate(this->mine, &this->ts))
        !           471:        {
        !           472:                if (!this->other->enumerate(this->other, &other_ts))
        !           473:                {       /* end of others list, restart with new of mine */
        !           474:                        this->other->destroy(this->other);
        !           475:                        this->other = array_create_enumerator(this->array);
        !           476:                        this->ts = NULL;
        !           477:                        continue;
        !           478:                }
        !           479:                if (this->ts->get_type(this->ts) != other_ts->get_type(other_ts))
        !           480:                {       /* family mismatch */
        !           481:                        continue;
        !           482:                }
        !           483:                if (this->ts->get_protocol(this->ts) &&
        !           484:                        other_ts->get_protocol(other_ts) &&
        !           485:                        this->ts->get_protocol(this->ts) != other_ts->get_protocol(other_ts))
        !           486:                {       /* protocol mismatch */
        !           487:                        continue;
        !           488:                }
        !           489:                if (my_out)
        !           490:                {
        !           491:                        *my_out = this->ts;
        !           492:                }
        !           493:                if (other_out)
        !           494:                {
        !           495:                        *other_out = other_ts;
        !           496:                }
        !           497:                return TRUE;
        !           498:        }
        !           499:        return FALSE;
        !           500: }
        !           501: 
        !           502: METHOD(enumerator_t, policy_destroy, void,
        !           503:           policy_enumerator_t *this)
        !           504: {
        !           505:        this->mine->destroy(this->mine);
        !           506:        this->other->destroy(this->other);
        !           507:        free(this);
        !           508: }
        !           509: 
        !           510: METHOD(child_sa_t, create_policy_enumerator, enumerator_t*,
        !           511:           private_child_sa_t *this)
        !           512: {
        !           513:        policy_enumerator_t *e;
        !           514: 
        !           515:        INIT(e,
        !           516:                .public = {
        !           517:                        .enumerate = enumerator_enumerate_default,
        !           518:                        .venumerate = _policy_enumerate,
        !           519:                        .destroy = _policy_destroy,
        !           520:                },
        !           521:                .mine = array_create_enumerator(this->my_ts),
        !           522:                .other = array_create_enumerator(this->other_ts),
        !           523:                .array = this->other_ts,
        !           524:                .ts = NULL,
        !           525:        );
        !           526: 
        !           527:        return &e->public;
        !           528: }
        !           529: 
        !           530: /**
        !           531:  * update the cached usebytes
        !           532:  * returns SUCCESS if the usebytes have changed, FAILED if not or no SPIs
        !           533:  * are available, and NOT_SUPPORTED if the kernel interface does not support
        !           534:  * querying the usebytes.
        !           535:  */
        !           536: static status_t update_usebytes(private_child_sa_t *this, bool inbound)
        !           537: {
        !           538:        status_t status = FAILED;
        !           539:        uint64_t bytes, packets;
        !           540:        time_t time;
        !           541: 
        !           542:        if (inbound)
        !           543:        {
        !           544:                if (this->my_spi)
        !           545:                {
        !           546:                        kernel_ipsec_sa_id_t id = {
        !           547:                                .src = this->other_addr,
        !           548:                                .dst = this->my_addr,
        !           549:                                .spi = this->my_spi,
        !           550:                                .proto = proto_ike2ip(this->protocol),
        !           551:                                .mark = mark_in_sa(this),
        !           552:                                .if_id = this->if_id_in,
        !           553:                        };
        !           554:                        kernel_ipsec_query_sa_t query = {};
        !           555: 
        !           556:                        status = charon->kernel->query_sa(charon->kernel, &id, &query,
        !           557:                                                                                          &bytes, &packets, &time);
        !           558:                        if (status == SUCCESS)
        !           559:                        {
        !           560:                                if (bytes > this->my_usebytes)
        !           561:                                {
        !           562:                                        this->my_usebytes = bytes;
        !           563:                                        this->my_usepackets = packets;
        !           564:                                        if (time)
        !           565:                                        {
        !           566:                                                this->my_usetime = time;
        !           567:                                        }
        !           568:                                }
        !           569:                                else
        !           570:                                {
        !           571:                                        status = FAILED;
        !           572:                                }
        !           573:                        }
        !           574:                }
        !           575:        }
        !           576:        else
        !           577:        {
        !           578:                if (this->other_spi && (this->outbound_state & CHILD_OUTBOUND_SA))
        !           579:                {
        !           580:                        kernel_ipsec_sa_id_t id = {
        !           581:                                .src = this->my_addr,
        !           582:                                .dst = this->other_addr,
        !           583:                                .spi = this->other_spi,
        !           584:                                .proto = proto_ike2ip(this->protocol),
        !           585:                                .mark = this->mark_out,
        !           586:                                .if_id = this->if_id_out,
        !           587:                        };
        !           588:                        kernel_ipsec_query_sa_t query = {};
        !           589: 
        !           590:                        status = charon->kernel->query_sa(charon->kernel, &id, &query,
        !           591:                                                                                          &bytes, &packets, &time);
        !           592:                        if (status == SUCCESS)
        !           593:                        {
        !           594:                                if (bytes > this->other_usebytes)
        !           595:                                {
        !           596:                                        this->other_usebytes = bytes;
        !           597:                                        this->other_usepackets = packets;
        !           598:                                        if (time)
        !           599:                                        {
        !           600:                                                this->other_usetime = time;
        !           601:                                        }
        !           602:                                }
        !           603:                                else
        !           604:                                {
        !           605:                                        status = FAILED;
        !           606:                                }
        !           607:                        }
        !           608:                }
        !           609:        }
        !           610:        return status;
        !           611: }
        !           612: 
        !           613: /**
        !           614:  * updates the cached usetime
        !           615:  */
        !           616: static bool update_usetime(private_child_sa_t *this, bool inbound)
        !           617: {
        !           618:        enumerator_t *enumerator;
        !           619:        traffic_selector_t *my_ts, *other_ts;
        !           620:        time_t last_use = 0;
        !           621: 
        !           622:        enumerator = create_policy_enumerator(this);
        !           623:        while (enumerator->enumerate(enumerator, &my_ts, &other_ts))
        !           624:        {
        !           625:                time_t in, out, fwd;
        !           626: 
        !           627:                if (inbound)
        !           628:                {
        !           629:                        kernel_ipsec_policy_id_t id = {
        !           630:                                .dir = POLICY_IN,
        !           631:                                .src_ts = other_ts,
        !           632:                                .dst_ts = my_ts,
        !           633:                                .mark = this->mark_in,
        !           634:                                .if_id = this->if_id_in,
        !           635:                        };
        !           636:                        kernel_ipsec_query_policy_t query = {};
        !           637: 
        !           638:                        if (charon->kernel->query_policy(charon->kernel, &id, &query,
        !           639:                                                                                         &in) == SUCCESS)
        !           640:                        {
        !           641:                                last_use = max(last_use, in);
        !           642:                        }
        !           643:                        if (this->mode != MODE_TRANSPORT)
        !           644:                        {
        !           645:                                id.dir = POLICY_FWD;
        !           646:                                if (charon->kernel->query_policy(charon->kernel, &id, &query,
        !           647:                                                                                                 &fwd) == SUCCESS)
        !           648:                                {
        !           649:                                        last_use = max(last_use, fwd);
        !           650:                                }
        !           651:                        }
        !           652:                }
        !           653:                else
        !           654:                {
        !           655:                        kernel_ipsec_policy_id_t id = {
        !           656:                                .dir = POLICY_OUT,
        !           657:                                .src_ts = my_ts,
        !           658:                                .dst_ts = other_ts,
        !           659:                                .mark = this->mark_out,
        !           660:                                .if_id = this->if_id_out,
        !           661:                                .interface = this->config->get_interface(this->config),
        !           662:                        };
        !           663:                        kernel_ipsec_query_policy_t query = {};
        !           664: 
        !           665:                        if (charon->kernel->query_policy(charon->kernel, &id, &query,
        !           666:                                                                                         &out) == SUCCESS)
        !           667:                        {
        !           668:                                last_use = max(last_use, out);
        !           669:                        }
        !           670:                }
        !           671:        }
        !           672:        enumerator->destroy(enumerator);
        !           673: 
        !           674:        if (last_use == 0)
        !           675:        {
        !           676:                return FALSE;
        !           677:        }
        !           678:        if (inbound)
        !           679:        {
        !           680:                this->my_usetime = last_use;
        !           681:        }
        !           682:        else
        !           683:        {
        !           684:                this->other_usetime = last_use;
        !           685:        }
        !           686:        return TRUE;
        !           687: }
        !           688: 
        !           689: METHOD(child_sa_t, get_usestats, void,
        !           690:        private_child_sa_t *this, bool inbound,
        !           691:        time_t *time, uint64_t *bytes, uint64_t *packets)
        !           692: {
        !           693:        if ((!bytes && !packets) || update_usebytes(this, inbound) != FAILED)
        !           694:        {
        !           695:                /* there was traffic since last update or the kernel interface
        !           696:                 * does not support querying the number of usebytes.
        !           697:                 */
        !           698:                if (time)
        !           699:                {
        !           700:                        if (!update_usetime(this, inbound) && !bytes && !packets)
        !           701:                        {
        !           702:                                /* if policy query did not yield a usetime, query SAs instead */
        !           703:                                update_usebytes(this, inbound);
        !           704:                        }
        !           705:                }
        !           706:        }
        !           707:        if (time)
        !           708:        {
        !           709:                *time = inbound ? this->my_usetime : this->other_usetime;
        !           710:        }
        !           711:        if (bytes)
        !           712:        {
        !           713:                *bytes = inbound ? this->my_usebytes : this->other_usebytes;
        !           714:        }
        !           715:        if (packets)
        !           716:        {
        !           717:                *packets = inbound ? this->my_usepackets : this->other_usepackets;
        !           718:        }
        !           719: }
        !           720: 
        !           721: METHOD(child_sa_t, get_mark, mark_t,
        !           722:        private_child_sa_t *this, bool inbound)
        !           723: {
        !           724:        return inbound ? this->mark_in : this->mark_out;
        !           725: }
        !           726: 
        !           727: METHOD(child_sa_t, get_if_id, uint32_t,
        !           728:        private_child_sa_t *this, bool inbound)
        !           729: {
        !           730:        return inbound ? this->if_id_in : this->if_id_out;
        !           731: }
        !           732: 
        !           733: METHOD(child_sa_t, get_lifetime, time_t,
        !           734:           private_child_sa_t *this, bool hard)
        !           735: {
        !           736:        return hard ? this->expire_time : this->rekey_time;
        !           737: }
        !           738: 
        !           739: METHOD(child_sa_t, get_installtime, time_t,
        !           740:        private_child_sa_t *this)
        !           741: {
        !           742:        return this->install_time;
        !           743: }
        !           744: 
        !           745: METHOD(child_sa_t, alloc_spi, uint32_t,
        !           746:           private_child_sa_t *this, protocol_id_t protocol)
        !           747: {
        !           748:        if (charon->kernel->get_spi(charon->kernel, this->other_addr, this->my_addr,
        !           749:                                                        proto_ike2ip(protocol), &this->my_spi) == SUCCESS)
        !           750:        {
        !           751:                /* if we allocate a SPI, but then are unable to establish the SA, we
        !           752:                 * need to know the protocol family to delete the partial SA */
        !           753:                this->protocol = protocol;
        !           754:                return this->my_spi;
        !           755:        }
        !           756:        return 0;
        !           757: }
        !           758: 
        !           759: METHOD(child_sa_t, alloc_cpi, uint16_t,
        !           760:           private_child_sa_t *this)
        !           761: {
        !           762:        if (charon->kernel->get_cpi(charon->kernel, this->other_addr, this->my_addr,
        !           763:                                                                &this->my_cpi) == SUCCESS)
        !           764:        {
        !           765:                return this->my_cpi;
        !           766:        }
        !           767:        return 0;
        !           768: }
        !           769: 
        !           770: /**
        !           771:  * Install the given SA in the kernel
        !           772:  */
        !           773: static status_t install_internal(private_child_sa_t *this, chunk_t encr,
        !           774:        chunk_t integ, uint32_t spi, uint16_t cpi, bool initiator, bool inbound,
        !           775:        bool tfcv3)
        !           776: {
        !           777:        uint16_t enc_alg = ENCR_UNDEFINED, int_alg = AUTH_UNDEFINED, size;
        !           778:        uint16_t esn = NO_EXT_SEQ_NUMBERS;
        !           779:        linked_list_t *my_ts, *other_ts, *src_ts, *dst_ts;
        !           780:        time_t now;
        !           781:        kernel_ipsec_sa_id_t id;
        !           782:        kernel_ipsec_add_sa_t sa;
        !           783:        lifetime_cfg_t *lifetime;
        !           784:        uint32_t tfc = 0;
        !           785:        host_t *src, *dst;
        !           786:        status_t status;
        !           787:        bool update = FALSE;
        !           788: 
        !           789:        /* BEET requires the bound address from the traffic selectors */
        !           790:        my_ts = linked_list_create_from_enumerator(
        !           791:                                                                        array_create_enumerator(this->my_ts));
        !           792:        other_ts = linked_list_create_from_enumerator(
        !           793:                                                                        array_create_enumerator(this->other_ts));
        !           794: 
        !           795:        /* now we have to decide which spi to use. Use self allocated, if "in",
        !           796:         * or the one in the proposal, if not "in" (others). Additionally,
        !           797:         * source and dest host switch depending on the role */
        !           798:        if (inbound)
        !           799:        {
        !           800:                dst = this->my_addr;
        !           801:                src = this->other_addr;
        !           802:                if (this->my_spi == spi)
        !           803:                {       /* alloc_spi has been called, do an SA update */
        !           804:                        update = TRUE;
        !           805:                }
        !           806:                this->my_spi = spi;
        !           807:                this->my_cpi = cpi;
        !           808:                dst_ts = my_ts;
        !           809:                src_ts = other_ts;
        !           810:        }
        !           811:        else
        !           812:        {
        !           813:                src = this->my_addr;
        !           814:                dst = this->other_addr;
        !           815:                this->other_spi = spi;
        !           816:                this->other_cpi = cpi;
        !           817:                src_ts = my_ts;
        !           818:                dst_ts = other_ts;
        !           819: 
        !           820:                if (tfcv3)
        !           821:                {
        !           822:                        tfc = this->config->get_tfc(this->config);
        !           823:                }
        !           824:                this->outbound_state |= CHILD_OUTBOUND_SA;
        !           825:        }
        !           826: 
        !           827:        DBG2(DBG_CHD, "adding %s %N SA", inbound ? "inbound" : "outbound",
        !           828:                 protocol_id_names, this->protocol);
        !           829: 
        !           830:        /* send SA down to the kernel */
        !           831:        DBG2(DBG_CHD, "  SPI 0x%.8x, src %H dst %H", ntohl(spi), src, dst);
        !           832: 
        !           833:        this->proposal->get_algorithm(this->proposal, ENCRYPTION_ALGORITHM,
        !           834:                                                                  &enc_alg, &size);
        !           835:        this->proposal->get_algorithm(this->proposal, INTEGRITY_ALGORITHM,
        !           836:                                                                  &int_alg, &size);
        !           837:        this->proposal->get_algorithm(this->proposal, EXTENDED_SEQUENCE_NUMBERS,
        !           838:                                                                  &esn, NULL);
        !           839: 
        !           840:        if (int_alg == AUTH_HMAC_SHA2_256_128 &&
        !           841:                this->config->has_option(this->config, OPT_SHA256_96))
        !           842:        {
        !           843:                DBG2(DBG_CHD, "  using %N with 96-bit truncation",
        !           844:                         integrity_algorithm_names, int_alg);
        !           845:                int_alg = AUTH_HMAC_SHA2_256_96;
        !           846:        }
        !           847: 
        !           848:        if (!this->reqid_allocated && !this->static_reqid)
        !           849:        {
        !           850:                status = charon->kernel->alloc_reqid(charon->kernel, my_ts, other_ts,
        !           851:                                                                this->mark_in, this->mark_out, this->if_id_in,
        !           852:                                                                this->if_id_out, &this->reqid);
        !           853:                if (status != SUCCESS)
        !           854:                {
        !           855:                        my_ts->destroy(my_ts);
        !           856:                        other_ts->destroy(other_ts);
        !           857:                        return status;
        !           858:                }
        !           859:                this->reqid_allocated = TRUE;
        !           860:        }
        !           861: 
        !           862:        lifetime = this->config->get_lifetime(this->config, TRUE);
        !           863: 
        !           864:        now = time_monotonic(NULL);
        !           865:        if (lifetime->time.rekey)
        !           866:        {
        !           867:                if (this->rekey_time)
        !           868:                {
        !           869:                        this->rekey_time = min(this->rekey_time, now + lifetime->time.rekey);
        !           870:                }
        !           871:                else
        !           872:                {
        !           873:                        this->rekey_time = now + lifetime->time.rekey;
        !           874:                }
        !           875:        }
        !           876:        if (lifetime->time.life)
        !           877:        {
        !           878:                this->expire_time = now + lifetime->time.life;
        !           879:        }
        !           880: 
        !           881:        if (!lifetime->time.jitter && !inbound)
        !           882:        {       /* avoid triggering multiple rekey events */
        !           883:                lifetime->time.rekey = 0;
        !           884:        }
        !           885: 
        !           886:        id = (kernel_ipsec_sa_id_t){
        !           887:                .src = src,
        !           888:                .dst = dst,
        !           889:                .spi = spi,
        !           890:                .proto = proto_ike2ip(this->protocol),
        !           891:                .mark = inbound ? mark_in_sa(this) : this->mark_out,
        !           892:                .if_id = inbound ? this->if_id_in : this->if_id_out,
        !           893:        };
        !           894:        sa = (kernel_ipsec_add_sa_t){
        !           895:                .reqid = this->reqid,
        !           896:                .mode = this->mode,
        !           897:                .src_ts = src_ts,
        !           898:                .dst_ts = dst_ts,
        !           899:                .interface = inbound ? NULL : this->config->get_interface(this->config),
        !           900:                .lifetime = lifetime,
        !           901:                .enc_alg = enc_alg,
        !           902:                .enc_key = encr,
        !           903:                .int_alg = int_alg,
        !           904:                .int_key = integ,
        !           905:                .replay_window = this->config->get_replay_window(this->config),
        !           906:                .tfc = tfc,
        !           907:                .ipcomp = this->ipcomp,
        !           908:                .cpi = cpi,
        !           909:                .encap = this->encap,
        !           910:                .hw_offload = this->config->get_hw_offload(this->config),
        !           911:                .mark = this->config->get_set_mark(this->config, inbound),
        !           912:                .esn = esn,
        !           913:                .copy_df = !this->config->has_option(this->config, OPT_NO_COPY_DF),
        !           914:                .copy_ecn = !this->config->has_option(this->config, OPT_NO_COPY_ECN),
        !           915:                .copy_dscp = this->config->get_copy_dscp(this->config),
        !           916:                .initiator = initiator,
        !           917:                .inbound = inbound,
        !           918:                .update = update,
        !           919:        };
        !           920: 
        !           921:        if (sa.mark.value == MARK_SAME)
        !           922:        {
        !           923:                sa.mark.value = inbound ? this->mark_in.value : this->mark_out.value;
        !           924:        }
        !           925: 
        !           926:        status = charon->kernel->add_sa(charon->kernel, &id, &sa);
        !           927: 
        !           928:        my_ts->destroy(my_ts);
        !           929:        other_ts->destroy(other_ts);
        !           930:        free(lifetime);
        !           931: 
        !           932:        return status;
        !           933: }
        !           934: 
        !           935: METHOD(child_sa_t, install, status_t,
        !           936:        private_child_sa_t *this, chunk_t encr, chunk_t integ, uint32_t spi,
        !           937:        uint16_t cpi, bool initiator, bool inbound, bool tfcv3)
        !           938: {
        !           939:        return install_internal(this, encr, integ, spi, cpi, initiator, inbound,
        !           940:                                                        tfcv3);
        !           941: }
        !           942: 
        !           943: /**
        !           944:  * Check kernel interface if policy updates are required
        !           945:  */
        !           946: static bool require_policy_update()
        !           947: {
        !           948:        kernel_feature_t f;
        !           949: 
        !           950:        f = charon->kernel->get_features(charon->kernel);
        !           951:        return !(f & KERNEL_NO_POLICY_UPDATES);
        !           952: }
        !           953: 
        !           954: /**
        !           955:  * Prepare SA config to install/delete policies
        !           956:  */
        !           957: static void prepare_sa_cfg(private_child_sa_t *this, ipsec_sa_cfg_t *my_sa,
        !           958:                                                   ipsec_sa_cfg_t *other_sa)
        !           959: {
        !           960:        enumerator_t *enumerator;
        !           961: 
        !           962:        *my_sa = (ipsec_sa_cfg_t){
        !           963:                .mode = this->mode,
        !           964:                .reqid = this->reqid,
        !           965:                .ipcomp = {
        !           966:                        .transform = this->ipcomp,
        !           967:                },
        !           968:        };
        !           969:        *other_sa = *my_sa;
        !           970: 
        !           971:        my_sa->ipcomp.cpi = this->my_cpi;
        !           972:        other_sa->ipcomp.cpi = this->other_cpi;
        !           973: 
        !           974:        if (this->protocol == PROTO_ESP)
        !           975:        {
        !           976:                my_sa->esp.use = TRUE;
        !           977:                my_sa->esp.spi = this->my_spi;
        !           978:                other_sa->esp.use = TRUE;
        !           979:                other_sa->esp.spi = this->other_spi;
        !           980:        }
        !           981:        else
        !           982:        {
        !           983:                my_sa->ah.use = TRUE;
        !           984:                my_sa->ah.spi = this->my_spi;
        !           985:                other_sa->ah.use = TRUE;
        !           986:                other_sa->ah.spi = this->other_spi;
        !           987:        }
        !           988: 
        !           989:        enumerator = create_policy_enumerator(this);
        !           990:        while (enumerator->enumerate(enumerator, NULL, NULL))
        !           991:        {
        !           992:                my_sa->policy_count++;
        !           993:                other_sa->policy_count++;
        !           994:        }
        !           995:        enumerator->destroy(enumerator);
        !           996: }
        !           997: 
        !           998: /**
        !           999:  * Install inbound policies: in, fwd
        !          1000:  */
        !          1001: static status_t install_policies_inbound(private_child_sa_t *this,
        !          1002:        host_t *my_addr, host_t *other_addr, traffic_selector_t *my_ts,
        !          1003:        traffic_selector_t *other_ts, ipsec_sa_cfg_t *my_sa,
        !          1004:        ipsec_sa_cfg_t *other_sa, policy_type_t type,
        !          1005:        policy_priority_t priority,     uint32_t manual_prio)
        !          1006: {
        !          1007:        kernel_ipsec_policy_id_t in_id = {
        !          1008:                .dir = POLICY_IN,
        !          1009:                .src_ts = other_ts,
        !          1010:                .dst_ts = my_ts,
        !          1011:                .mark = this->mark_in,
        !          1012:                .if_id = this->if_id_in,
        !          1013:        };
        !          1014:        kernel_ipsec_manage_policy_t in_policy = {
        !          1015:                .type = type,
        !          1016:                .prio = priority,
        !          1017:                .manual_prio = manual_prio,
        !          1018:                .src = other_addr,
        !          1019:                .dst = my_addr,
        !          1020:                .sa = my_sa,
        !          1021:        };
        !          1022:        status_t status = SUCCESS;
        !          1023: 
        !          1024:        status |= charon->kernel->add_policy(charon->kernel, &in_id, &in_policy);
        !          1025:        if (this->mode != MODE_TRANSPORT)
        !          1026:        {
        !          1027:                in_id.dir = POLICY_FWD;
        !          1028:                status |= charon->kernel->add_policy(charon->kernel, &in_id, &in_policy);
        !          1029:        }
        !          1030:        return status;
        !          1031: }
        !          1032: 
        !          1033: /**
        !          1034:  * Install outbound policies: out, [fwd]
        !          1035:  */
        !          1036: static status_t install_policies_outbound(private_child_sa_t *this,
        !          1037:        host_t *my_addr, host_t *other_addr, traffic_selector_t *my_ts,
        !          1038:        traffic_selector_t *other_ts, ipsec_sa_cfg_t *my_sa,
        !          1039:        ipsec_sa_cfg_t *other_sa, policy_type_t type,
        !          1040:        policy_priority_t priority,     uint32_t manual_prio)
        !          1041: {
        !          1042:        kernel_ipsec_policy_id_t out_id = {
        !          1043:                .dir = POLICY_OUT,
        !          1044:                .src_ts = my_ts,
        !          1045:                .dst_ts = other_ts,
        !          1046:                .mark = this->mark_out,
        !          1047:                .if_id = this->if_id_out,
        !          1048:                .interface = this->config->get_interface(this->config),
        !          1049:        };
        !          1050:        kernel_ipsec_manage_policy_t out_policy = {
        !          1051:                .type = type,
        !          1052:                .prio = priority,
        !          1053:                .manual_prio = manual_prio,
        !          1054:                .src = my_addr,
        !          1055:                .dst = other_addr,
        !          1056:                .sa = other_sa,
        !          1057:        };
        !          1058:        status_t status = SUCCESS;
        !          1059: 
        !          1060:        status |= charon->kernel->add_policy(charon->kernel, &out_id, &out_policy);
        !          1061: 
        !          1062:        if (this->mode != MODE_TRANSPORT && this->policies_fwd_out)
        !          1063:        {
        !          1064:                /* install an "outbound" FWD policy in case there is a drop policy
        !          1065:                 * matching outbound forwarded traffic, to allow another tunnel to use
        !          1066:                 * the reversed subnets and do the same we don't set a reqid (this also
        !          1067:                 * allows the kernel backend to distinguish between the two types of
        !          1068:                 * FWD policies). To avoid problems with symmetrically overlapping
        !          1069:                 * policies of two SAs we install them with reduced priority.  As they
        !          1070:                 * basically act as bypass policies for drop policies we use a higher
        !          1071:                 * priority than is used for them. */
        !          1072:                out_id.dir = POLICY_FWD;
        !          1073:                other_sa->reqid = 0;
        !          1074:                if (priority == POLICY_PRIORITY_DEFAULT)
        !          1075:                {
        !          1076:                        out_policy.prio = POLICY_PRIORITY_ROUTED;
        !          1077:                }
        !          1078:                status |= charon->kernel->add_policy(charon->kernel, &out_id,
        !          1079:                                                                                         &out_policy);
        !          1080:                /* reset the reqid for any other further policies */
        !          1081:                other_sa->reqid = this->reqid;
        !          1082:        }
        !          1083:        return status;
        !          1084: }
        !          1085: 
        !          1086: /**
        !          1087:  * Install all policies
        !          1088:  */
        !          1089: static status_t install_policies_internal(private_child_sa_t *this,
        !          1090:        host_t *my_addr, host_t *other_addr, traffic_selector_t *my_ts,
        !          1091:        traffic_selector_t *other_ts, ipsec_sa_cfg_t *my_sa,
        !          1092:        ipsec_sa_cfg_t *other_sa, policy_type_t type,
        !          1093:        policy_priority_t priority,     uint32_t manual_prio, bool outbound)
        !          1094: {
        !          1095:        status_t status = SUCCESS;
        !          1096: 
        !          1097:        status |= install_policies_inbound(this, my_addr, other_addr, my_ts,
        !          1098:                                                other_ts, my_sa, other_sa, type, priority, manual_prio);
        !          1099:        if (outbound)
        !          1100:        {
        !          1101:                status |= install_policies_outbound(this, my_addr, other_addr, my_ts,
        !          1102:                                                other_ts, my_sa, other_sa, type, priority, manual_prio);
        !          1103:        }
        !          1104:        return status;
        !          1105: }
        !          1106: 
        !          1107: /**
        !          1108:  * Delete inbound policies: in, fwd
        !          1109:  */
        !          1110: static void del_policies_inbound(private_child_sa_t *this,
        !          1111:        host_t *my_addr, host_t *other_addr, traffic_selector_t *my_ts,
        !          1112:        traffic_selector_t *other_ts, ipsec_sa_cfg_t *my_sa,
        !          1113:        ipsec_sa_cfg_t *other_sa, policy_type_t type,
        !          1114:        policy_priority_t priority, uint32_t manual_prio)
        !          1115: {
        !          1116:        kernel_ipsec_policy_id_t in_id = {
        !          1117:                .dir = POLICY_IN,
        !          1118:                .src_ts = other_ts,
        !          1119:                .dst_ts = my_ts,
        !          1120:                .mark = this->mark_in,
        !          1121:                .if_id = this->if_id_in,
        !          1122:        };
        !          1123:        kernel_ipsec_manage_policy_t in_policy = {
        !          1124:                .type = type,
        !          1125:                .prio = priority,
        !          1126:                .manual_prio = manual_prio,
        !          1127:                .src = other_addr,
        !          1128:                .dst = my_addr,
        !          1129:                .sa = my_sa,
        !          1130:        };
        !          1131: 
        !          1132:        charon->kernel->del_policy(charon->kernel, &in_id, &in_policy);
        !          1133: 
        !          1134:        if (this->mode != MODE_TRANSPORT)
        !          1135:        {
        !          1136:                in_id.dir = POLICY_FWD;
        !          1137:                charon->kernel->del_policy(charon->kernel, &in_id, &in_policy);
        !          1138:        }
        !          1139: }
        !          1140: 
        !          1141: /**
        !          1142:  * Delete outbound policies: out, [fwd]
        !          1143:  */
        !          1144: static void del_policies_outbound(private_child_sa_t *this,
        !          1145:        host_t *my_addr, host_t *other_addr, traffic_selector_t *my_ts,
        !          1146:        traffic_selector_t *other_ts, ipsec_sa_cfg_t *my_sa,
        !          1147:        ipsec_sa_cfg_t *other_sa, policy_type_t type,
        !          1148:        policy_priority_t priority, uint32_t manual_prio)
        !          1149: {
        !          1150:        kernel_ipsec_policy_id_t out_id = {
        !          1151:                .dir = POLICY_OUT,
        !          1152:                .src_ts = my_ts,
        !          1153:                .dst_ts = other_ts,
        !          1154:                .mark = this->mark_out,
        !          1155:                .if_id = this->if_id_out,
        !          1156:                .interface = this->config->get_interface(this->config),
        !          1157:        };
        !          1158:        kernel_ipsec_manage_policy_t out_policy = {
        !          1159:                .type = type,
        !          1160:                .prio = priority,
        !          1161:                .manual_prio = manual_prio,
        !          1162:                .src = my_addr,
        !          1163:                .dst = other_addr,
        !          1164:                .sa = other_sa,
        !          1165:        };
        !          1166: 
        !          1167:        charon->kernel->del_policy(charon->kernel, &out_id, &out_policy);
        !          1168: 
        !          1169:        if (this->mode != MODE_TRANSPORT && this->policies_fwd_out)
        !          1170:        {
        !          1171:                out_id.dir = POLICY_FWD;
        !          1172:                other_sa->reqid = 0;
        !          1173:                if (priority == POLICY_PRIORITY_DEFAULT)
        !          1174:                {
        !          1175:                        out_policy.prio = POLICY_PRIORITY_ROUTED;
        !          1176:                }
        !          1177:                charon->kernel->del_policy(charon->kernel, &out_id, &out_policy);
        !          1178:                other_sa->reqid = this->reqid;
        !          1179:        }
        !          1180: }
        !          1181: 
        !          1182: /**
        !          1183:  * Delete in- and outbound policies
        !          1184:  */
        !          1185: static void del_policies_internal(private_child_sa_t *this,
        !          1186:        host_t *my_addr, host_t *other_addr, traffic_selector_t *my_ts,
        !          1187:        traffic_selector_t *other_ts, ipsec_sa_cfg_t *my_sa,
        !          1188:        ipsec_sa_cfg_t *other_sa, policy_type_t type,
        !          1189:        policy_priority_t priority, uint32_t manual_prio, bool outbound)
        !          1190: {
        !          1191:        if (outbound)
        !          1192:        {
        !          1193:                del_policies_outbound(this, my_addr, other_addr, my_ts, other_ts, my_sa,
        !          1194:                                                other_sa, type, priority, manual_prio);
        !          1195:        }
        !          1196:        del_policies_inbound(this, my_addr, other_addr, my_ts, other_ts, my_sa,
        !          1197:                                                other_sa, type, priority, manual_prio);
        !          1198: }
        !          1199: 
        !          1200: METHOD(child_sa_t, set_policies, void,
        !          1201:           private_child_sa_t *this, linked_list_t *my_ts_list,
        !          1202:           linked_list_t *other_ts_list)
        !          1203: {
        !          1204:        enumerator_t *enumerator;
        !          1205:        traffic_selector_t *my_ts, *other_ts;
        !          1206: 
        !          1207:        if (array_count(this->my_ts))
        !          1208:        {
        !          1209:                array_destroy_offset(this->my_ts,
        !          1210:                                                         offsetof(traffic_selector_t, destroy));
        !          1211:                this->my_ts = array_create(0, 0);
        !          1212:        }
        !          1213:        enumerator = my_ts_list->create_enumerator(my_ts_list);
        !          1214:        while (enumerator->enumerate(enumerator, &my_ts))
        !          1215:        {
        !          1216:                array_insert(this->my_ts, ARRAY_TAIL, my_ts->clone(my_ts));
        !          1217:        }
        !          1218:        enumerator->destroy(enumerator);
        !          1219:        array_sort(this->my_ts, (void*)traffic_selector_cmp, NULL);
        !          1220: 
        !          1221:        if (array_count(this->other_ts))
        !          1222:        {
        !          1223:                array_destroy_offset(this->other_ts,
        !          1224:                                                         offsetof(traffic_selector_t, destroy));
        !          1225:                this->other_ts = array_create(0, 0);
        !          1226:        }
        !          1227:        enumerator = other_ts_list->create_enumerator(other_ts_list);
        !          1228:        while (enumerator->enumerate(enumerator, &other_ts))
        !          1229:        {
        !          1230:                array_insert(this->other_ts, ARRAY_TAIL, other_ts->clone(other_ts));
        !          1231:        }
        !          1232:        enumerator->destroy(enumerator);
        !          1233:        array_sort(this->other_ts, (void*)traffic_selector_cmp, NULL);
        !          1234: }
        !          1235: 
        !          1236: METHOD(child_sa_t, install_policies, status_t,
        !          1237:           private_child_sa_t *this)
        !          1238: {
        !          1239:        enumerator_t *enumerator;
        !          1240:        linked_list_t *my_ts_list, *other_ts_list;
        !          1241:        traffic_selector_t *my_ts, *other_ts;
        !          1242:        status_t status = SUCCESS;
        !          1243:        bool install_outbound = FALSE;
        !          1244: 
        !          1245:        if (!this->reqid_allocated && !this->static_reqid)
        !          1246:        {
        !          1247:                my_ts_list = linked_list_create_from_enumerator(
        !          1248:                                                                        array_create_enumerator(this->my_ts));
        !          1249:                other_ts_list = linked_list_create_from_enumerator(
        !          1250:                                                                        array_create_enumerator(this->other_ts));
        !          1251:                status = charon->kernel->alloc_reqid(
        !          1252:                                                        charon->kernel, my_ts_list, other_ts_list,
        !          1253:                                                        this->mark_in, this->mark_out, this->if_id_in,
        !          1254:                                                        this->if_id_out, &this->reqid);
        !          1255:                my_ts_list->destroy(my_ts_list);
        !          1256:                other_ts_list->destroy(other_ts_list);
        !          1257:                if (status != SUCCESS)
        !          1258:                {
        !          1259:                        return status;
        !          1260:                }
        !          1261:                this->reqid_allocated = TRUE;
        !          1262:        }
        !          1263: 
        !          1264:        if (!(this->outbound_state & CHILD_OUTBOUND_REGISTERED))
        !          1265:        {
        !          1266:                install_outbound = TRUE;
        !          1267:                this->outbound_state |= CHILD_OUTBOUND_POLICIES;
        !          1268:        }
        !          1269: 
        !          1270:        if (!this->config->has_option(this->config, OPT_NO_POLICIES))
        !          1271:        {
        !          1272:                policy_priority_t priority;
        !          1273:                ipsec_sa_cfg_t my_sa, other_sa;
        !          1274:                uint32_t manual_prio;
        !          1275: 
        !          1276:                prepare_sa_cfg(this, &my_sa, &other_sa);
        !          1277:                manual_prio = this->config->get_manual_prio(this->config);
        !          1278: 
        !          1279:                /* if we're not in state CHILD_INSTALLING (i.e. if there is no SAD
        !          1280:                 * entry) we install a trap policy */
        !          1281:                this->trap = this->state == CHILD_CREATED;
        !          1282:                priority = this->trap ? POLICY_PRIORITY_ROUTED
        !          1283:                                                          : POLICY_PRIORITY_DEFAULT;
        !          1284: 
        !          1285:                /* enumerate pairs of traffic selectors */
        !          1286:                enumerator = create_policy_enumerator(this);
        !          1287:                while (enumerator->enumerate(enumerator, &my_ts, &other_ts))
        !          1288:                {
        !          1289:                        status |= install_policies_internal(this, this->my_addr,
        !          1290:                                                                        this->other_addr, my_ts, other_ts,
        !          1291:                                                                        &my_sa, &other_sa, POLICY_IPSEC, priority,
        !          1292:                                                                        manual_prio, install_outbound);
        !          1293:                        if (status != SUCCESS)
        !          1294:                        {
        !          1295:                                break;
        !          1296:                        }
        !          1297:                }
        !          1298:                enumerator->destroy(enumerator);
        !          1299:        }
        !          1300: 
        !          1301:        if (status == SUCCESS && this->trap)
        !          1302:        {
        !          1303:                set_state(this, CHILD_ROUTED);
        !          1304:        }
        !          1305:        return status;
        !          1306: }
        !          1307: 
        !          1308: METHOD(child_sa_t, register_outbound, status_t,
        !          1309:        private_child_sa_t *this, chunk_t encr, chunk_t integ, uint32_t spi,
        !          1310:        uint16_t cpi, bool tfcv3)
        !          1311: {
        !          1312:        status_t status;
        !          1313: 
        !          1314:        /* if the kernel supports installing SPIs with policies we install the
        !          1315:         * SA immediately as it will only be used once we update the policies */
        !          1316:        if (charon->kernel->get_features(charon->kernel) & KERNEL_POLICY_SPI)
        !          1317:        {
        !          1318:                status = install_internal(this, encr, integ, spi, cpi, FALSE, FALSE,
        !          1319:                                                                  tfcv3);
        !          1320:        }
        !          1321:        else
        !          1322:        {
        !          1323:                DBG2(DBG_CHD, "registering outbound %N SA", protocol_id_names,
        !          1324:                         this->protocol);
        !          1325:                DBG2(DBG_CHD, "  SPI 0x%.8x, src %H dst %H", ntohl(spi), this->my_addr,
        !          1326:                         this->other_addr);
        !          1327: 
        !          1328:                this->other_spi = spi;
        !          1329:                this->other_cpi = cpi;
        !          1330:                this->encr_r = chunk_clone(encr);
        !          1331:                this->integ_r = chunk_clone(integ);
        !          1332:                this->tfcv3 = tfcv3;
        !          1333:                status = SUCCESS;
        !          1334:        }
        !          1335:        this->outbound_state |= CHILD_OUTBOUND_REGISTERED;
        !          1336:        return status;
        !          1337: }
        !          1338: 
        !          1339: METHOD(child_sa_t, install_outbound, status_t,
        !          1340:        private_child_sa_t *this)
        !          1341: {
        !          1342:        enumerator_t *enumerator;
        !          1343:        traffic_selector_t *my_ts, *other_ts;
        !          1344:        status_t status = SUCCESS;
        !          1345: 
        !          1346:        if (!(this->outbound_state & CHILD_OUTBOUND_SA))
        !          1347:        {
        !          1348:                status = install_internal(this, this->encr_r, this->integ_r,
        !          1349:                                                                  this->other_spi, this->other_cpi, FALSE,
        !          1350:                                                                  FALSE, this->tfcv3);
        !          1351:                chunk_clear(&this->encr_r);
        !          1352:                chunk_clear(&this->integ_r);
        !          1353:        }
        !          1354:        this->outbound_state &= ~CHILD_OUTBOUND_REGISTERED;
        !          1355:        if (status != SUCCESS)
        !          1356:        {
        !          1357:                return status;
        !          1358:        }
        !          1359:        if (!this->config->has_option(this->config, OPT_NO_POLICIES) &&
        !          1360:                !(this->outbound_state & CHILD_OUTBOUND_POLICIES))
        !          1361:        {
        !          1362:                ipsec_sa_cfg_t my_sa, other_sa;
        !          1363:                uint32_t manual_prio;
        !          1364: 
        !          1365:                prepare_sa_cfg(this, &my_sa, &other_sa);
        !          1366:                manual_prio = this->config->get_manual_prio(this->config);
        !          1367: 
        !          1368:                enumerator = create_policy_enumerator(this);
        !          1369:                while (enumerator->enumerate(enumerator, &my_ts, &other_ts))
        !          1370:                {
        !          1371:                        status |= install_policies_outbound(this, this->my_addr,
        !          1372:                                                                        this->other_addr, my_ts, other_ts,
        !          1373:                                                                        &my_sa, &other_sa, POLICY_IPSEC,
        !          1374:                                                                        POLICY_PRIORITY_DEFAULT, manual_prio);
        !          1375:                        if (status != SUCCESS)
        !          1376:                        {
        !          1377:                                break;
        !          1378:                        }
        !          1379:                }
        !          1380:                enumerator->destroy(enumerator);
        !          1381:        }
        !          1382:        this->outbound_state |= CHILD_OUTBOUND_POLICIES;
        !          1383:        return status;
        !          1384: }
        !          1385: 
        !          1386: METHOD(child_sa_t, remove_outbound, void,
        !          1387:        private_child_sa_t *this)
        !          1388: {
        !          1389:        enumerator_t *enumerator;
        !          1390:        traffic_selector_t *my_ts, *other_ts;
        !          1391: 
        !          1392:        if (!(this->outbound_state & CHILD_OUTBOUND_SA))
        !          1393:        {
        !          1394:                if (this->outbound_state & CHILD_OUTBOUND_REGISTERED)
        !          1395:                {
        !          1396:                        chunk_clear(&this->encr_r);
        !          1397:                        chunk_clear(&this->integ_r);
        !          1398:                        this->outbound_state = CHILD_OUTBOUND_NONE;
        !          1399:                }
        !          1400:                return;
        !          1401:        }
        !          1402: 
        !          1403:        if (!this->config->has_option(this->config, OPT_NO_POLICIES) &&
        !          1404:                (this->outbound_state & CHILD_OUTBOUND_POLICIES))
        !          1405:        {
        !          1406:                ipsec_sa_cfg_t my_sa, other_sa;
        !          1407:                uint32_t manual_prio;
        !          1408: 
        !          1409:                prepare_sa_cfg(this, &my_sa, &other_sa);
        !          1410:                manual_prio = this->config->get_manual_prio(this->config);
        !          1411: 
        !          1412:                enumerator = create_policy_enumerator(this);
        !          1413:                while (enumerator->enumerate(enumerator, &my_ts, &other_ts))
        !          1414:                {
        !          1415:                        del_policies_outbound(this, this->my_addr, this->other_addr,
        !          1416:                                                                  my_ts, other_ts, &my_sa, &other_sa,
        !          1417:                                                                  POLICY_IPSEC, POLICY_PRIORITY_DEFAULT,
        !          1418:                                                                  manual_prio);
        !          1419:                }
        !          1420:                enumerator->destroy(enumerator);
        !          1421:        }
        !          1422: 
        !          1423:        kernel_ipsec_sa_id_t id = {
        !          1424:                .src = this->my_addr,
        !          1425:                .dst = this->other_addr,
        !          1426:                .spi = this->other_spi,
        !          1427:                .proto = proto_ike2ip(this->protocol),
        !          1428:                .mark = this->mark_out,
        !          1429:                .if_id = this->if_id_out,
        !          1430:        };
        !          1431:        kernel_ipsec_del_sa_t sa = {
        !          1432:                .cpi = this->other_cpi,
        !          1433:        };
        !          1434:        charon->kernel->del_sa(charon->kernel, &id, &sa);
        !          1435:        this->outbound_state = CHILD_OUTBOUND_NONE;
        !          1436: }
        !          1437: 
        !          1438: METHOD(child_sa_t, set_rekey_spi, void,
        !          1439:        private_child_sa_t *this, uint32_t spi)
        !          1440: {
        !          1441:        this->rekey_spi = spi;
        !          1442: }
        !          1443: 
        !          1444: METHOD(child_sa_t, get_rekey_spi, uint32_t,
        !          1445:        private_child_sa_t *this)
        !          1446: {
        !          1447:        return this->rekey_spi;
        !          1448: }
        !          1449: 
        !          1450: CALLBACK(reinstall_vip, void,
        !          1451:        host_t *vip, va_list args)
        !          1452: {
        !          1453:        host_t *me;
        !          1454:        char *iface;
        !          1455: 
        !          1456:        VA_ARGS_VGET(args, me);
        !          1457:        if (charon->kernel->get_interface(charon->kernel, me, &iface))
        !          1458:        {
        !          1459:                charon->kernel->del_ip(charon->kernel, vip, -1, TRUE);
        !          1460:                charon->kernel->add_ip(charon->kernel, vip, -1, iface);
        !          1461:                free(iface);
        !          1462:        }
        !          1463: }
        !          1464: 
        !          1465: /**
        !          1466:  * Update addresses and encap state of IPsec SAs in the kernel
        !          1467:  */
        !          1468: static status_t update_sas(private_child_sa_t *this, host_t *me, host_t *other,
        !          1469:                                                   bool encap)
        !          1470: {
        !          1471:        /* update our (initiator) SA */
        !          1472:        if (this->my_spi)
        !          1473:        {
        !          1474:                kernel_ipsec_sa_id_t id = {
        !          1475:                        .src = this->other_addr,
        !          1476:                        .dst = this->my_addr,
        !          1477:                        .spi = this->my_spi,
        !          1478:                        .proto = proto_ike2ip(this->protocol),
        !          1479:                        .mark = mark_in_sa(this),
        !          1480:                        .if_id = this->if_id_in,
        !          1481:                };
        !          1482:                kernel_ipsec_update_sa_t sa = {
        !          1483:                        .cpi = this->ipcomp != IPCOMP_NONE ? this->my_cpi : 0,
        !          1484:                        .new_src = other,
        !          1485:                        .new_dst = me,
        !          1486:                        .encap = this->encap,
        !          1487:                        .new_encap = encap,
        !          1488:                };
        !          1489:                if (charon->kernel->update_sa(charon->kernel, &id,
        !          1490:                                                                          &sa) == NOT_SUPPORTED)
        !          1491:                {
        !          1492:                        return NOT_SUPPORTED;
        !          1493:                }
        !          1494:        }
        !          1495: 
        !          1496:        /* update his (responder) SA */
        !          1497:        if (this->other_spi && (this->outbound_state & CHILD_OUTBOUND_SA))
        !          1498:        {
        !          1499:                kernel_ipsec_sa_id_t id = {
        !          1500:                        .src = this->my_addr,
        !          1501:                        .dst = this->other_addr,
        !          1502:                        .spi = this->other_spi,
        !          1503:                        .proto = proto_ike2ip(this->protocol),
        !          1504:                        .mark = this->mark_out,
        !          1505:                        .if_id = this->if_id_out,
        !          1506:                };
        !          1507:                kernel_ipsec_update_sa_t sa = {
        !          1508:                        .cpi = this->ipcomp != IPCOMP_NONE ? this->other_cpi : 0,
        !          1509:                        .new_src = me,
        !          1510:                        .new_dst = other,
        !          1511:                        .encap = this->encap,
        !          1512:                        .new_encap = encap,
        !          1513:                };
        !          1514:                if (charon->kernel->update_sa(charon->kernel, &id,
        !          1515:                                                                          &sa) == NOT_SUPPORTED)
        !          1516:                {
        !          1517:                        return NOT_SUPPORTED;
        !          1518:                }
        !          1519:        }
        !          1520:        /* we currently ignore the actual return values above */
        !          1521:        return SUCCESS;
        !          1522: }
        !          1523: 
        !          1524: METHOD(child_sa_t, update, status_t,
        !          1525:        private_child_sa_t *this, host_t *me, host_t *other, linked_list_t *vips,
        !          1526:        bool encap)
        !          1527: {
        !          1528:        child_sa_state_t old;
        !          1529:        bool transport_proxy_mode;
        !          1530: 
        !          1531:        /* anything changed at all? */
        !          1532:        if (me->equals(me, this->my_addr) &&
        !          1533:                other->equals(other, this->other_addr) && this->encap == encap)
        !          1534:        {
        !          1535:                return SUCCESS;
        !          1536:        }
        !          1537: 
        !          1538:        old = this->state;
        !          1539:        set_state(this, CHILD_UPDATING);
        !          1540:        transport_proxy_mode = this->mode == MODE_TRANSPORT &&
        !          1541:                                                   this->config->has_option(this->config,
        !          1542:                                                                                                        OPT_PROXY_MODE);
        !          1543: 
        !          1544:        if (!this->config->has_option(this->config, OPT_NO_POLICIES) &&
        !          1545:                require_policy_update())
        !          1546:        {
        !          1547:                ipsec_sa_cfg_t my_sa, other_sa;
        !          1548:                enumerator_t *enumerator;
        !          1549:                traffic_selector_t *my_ts, *other_ts;
        !          1550:                uint32_t manual_prio;
        !          1551:                status_t state;
        !          1552:                bool outbound;
        !          1553: 
        !          1554:                prepare_sa_cfg(this, &my_sa, &other_sa);
        !          1555:                manual_prio = this->config->get_manual_prio(this->config);
        !          1556:                outbound = (this->outbound_state & CHILD_OUTBOUND_POLICIES);
        !          1557: 
        !          1558:                enumerator = create_policy_enumerator(this);
        !          1559:                while (enumerator->enumerate(enumerator, &my_ts, &other_ts))
        !          1560:                {
        !          1561:                        /* install drop policy to avoid traffic leaks, acquires etc. */
        !          1562:                        if (outbound)
        !          1563:                        {
        !          1564:                                install_policies_outbound(this, this->my_addr, this->other_addr,
        !          1565:                                                        my_ts, other_ts, &my_sa, &other_sa, POLICY_DROP,
        !          1566:                                                        POLICY_PRIORITY_DEFAULT, manual_prio);
        !          1567:                        }
        !          1568:                        /* remove old policies */
        !          1569:                        del_policies_internal(this, this->my_addr, this->other_addr,
        !          1570:                                                my_ts, other_ts, &my_sa, &other_sa, POLICY_IPSEC,
        !          1571:                                                POLICY_PRIORITY_DEFAULT, manual_prio, outbound);
        !          1572:                }
        !          1573:                enumerator->destroy(enumerator);
        !          1574: 
        !          1575:                /* update the IPsec SAs */
        !          1576:                state = update_sas(this, me, other, encap);
        !          1577: 
        !          1578:                enumerator = create_policy_enumerator(this);
        !          1579:                while (enumerator->enumerate(enumerator, &my_ts, &other_ts))
        !          1580:                {
        !          1581:                        traffic_selector_t *old_my_ts = NULL, *old_other_ts = NULL;
        !          1582: 
        !          1583:                        /* reinstall the previous policies if we can't update the SAs */
        !          1584:                        if (state == NOT_SUPPORTED)
        !          1585:                        {
        !          1586:                                install_policies_internal(this, this->my_addr, this->other_addr,
        !          1587:                                                my_ts, other_ts, &my_sa, &other_sa, POLICY_IPSEC,
        !          1588:                                                POLICY_PRIORITY_DEFAULT, manual_prio, outbound);
        !          1589:                        }
        !          1590:                        else
        !          1591:                        {
        !          1592:                                /* check if we have to update a "dynamic" traffic selector */
        !          1593:                                if (!me->ip_equals(me, this->my_addr) &&
        !          1594:                                        my_ts->is_host(my_ts, this->my_addr))
        !          1595:                                {
        !          1596:                                        old_my_ts = my_ts->clone(my_ts);
        !          1597:                                        my_ts->set_address(my_ts, me);
        !          1598:                                }
        !          1599:                                if (!other->ip_equals(other, this->other_addr) &&
        !          1600:                                        other_ts->is_host(other_ts, this->other_addr))
        !          1601:                                {
        !          1602:                                        old_other_ts = other_ts->clone(other_ts);
        !          1603:                                        other_ts->set_address(other_ts, other);
        !          1604:                                }
        !          1605: 
        !          1606:                                /* we reinstall the virtual IP to handle interface roaming
        !          1607:                                 * correctly */
        !          1608:                                vips->invoke_function(vips, reinstall_vip, me);
        !          1609: 
        !          1610:                                /* reinstall updated policies */
        !          1611:                                install_policies_internal(this, me, other, my_ts, other_ts,
        !          1612:                                                &my_sa, &other_sa, POLICY_IPSEC,
        !          1613:                                                POLICY_PRIORITY_DEFAULT, manual_prio, outbound);
        !          1614:                        }
        !          1615:                        /* remove the drop policy */
        !          1616:                        if (outbound)
        !          1617:                        {
        !          1618:                                del_policies_outbound(this, this->my_addr, this->other_addr,
        !          1619:                                                old_my_ts ?: my_ts, old_other_ts ?: other_ts,
        !          1620:                                                &my_sa, &other_sa, POLICY_DROP,
        !          1621:                                                POLICY_PRIORITY_DEFAULT, manual_prio);
        !          1622:                        }
        !          1623: 
        !          1624:                        DESTROY_IF(old_my_ts);
        !          1625:                        DESTROY_IF(old_other_ts);
        !          1626:                }
        !          1627:                enumerator->destroy(enumerator);
        !          1628: 
        !          1629:                if (state == NOT_SUPPORTED)
        !          1630:                {
        !          1631:                        set_state(this, old);
        !          1632:                        return NOT_SUPPORTED;
        !          1633:                }
        !          1634: 
        !          1635:        }
        !          1636:        else if (!transport_proxy_mode)
        !          1637:        {
        !          1638:                if (update_sas(this, me, other, encap) == NOT_SUPPORTED)
        !          1639:                {
        !          1640:                        set_state(this, old);
        !          1641:                        return NOT_SUPPORTED;
        !          1642:                }
        !          1643:        }
        !          1644: 
        !          1645:        if (!transport_proxy_mode)
        !          1646:        {
        !          1647:                /* apply hosts */
        !          1648:                if (!me->equals(me, this->my_addr))
        !          1649:                {
        !          1650:                        this->my_addr->destroy(this->my_addr);
        !          1651:                        this->my_addr = me->clone(me);
        !          1652:                }
        !          1653:                if (!other->equals(other, this->other_addr))
        !          1654:                {
        !          1655:                        this->other_addr->destroy(this->other_addr);
        !          1656:                        this->other_addr = other->clone(other);
        !          1657:                }
        !          1658:        }
        !          1659: 
        !          1660:        this->encap = encap;
        !          1661:        set_state(this, old);
        !          1662: 
        !          1663:        return SUCCESS;
        !          1664: }
        !          1665: 
        !          1666: METHOD(child_sa_t, destroy, void,
        !          1667:           private_child_sa_t *this)
        !          1668: {
        !          1669:        enumerator_t *enumerator;
        !          1670:        traffic_selector_t *my_ts, *other_ts;
        !          1671:        policy_priority_t priority;
        !          1672: 
        !          1673:        priority = this->trap ? POLICY_PRIORITY_ROUTED : POLICY_PRIORITY_DEFAULT;
        !          1674: 
        !          1675:        set_state(this, CHILD_DESTROYING);
        !          1676: 
        !          1677:        if (!this->config->has_option(this->config, OPT_NO_POLICIES))
        !          1678:        {
        !          1679:                ipsec_sa_cfg_t my_sa, other_sa;
        !          1680:                uint32_t manual_prio;
        !          1681:                bool del_outbound;
        !          1682: 
        !          1683:                prepare_sa_cfg(this, &my_sa, &other_sa);
        !          1684:                manual_prio = this->config->get_manual_prio(this->config);
        !          1685:                del_outbound = (this->outbound_state & CHILD_OUTBOUND_POLICIES) ||
        !          1686:                                                this->trap;
        !          1687: 
        !          1688:                /* delete all policies in the kernel */
        !          1689:                enumerator = create_policy_enumerator(this);
        !          1690:                while (enumerator->enumerate(enumerator, &my_ts, &other_ts))
        !          1691:                {
        !          1692:                        del_policies_internal(this, this->my_addr,
        !          1693:                                                this->other_addr, my_ts, other_ts, &my_sa, &other_sa,
        !          1694:                                                POLICY_IPSEC, priority, manual_prio, del_outbound);
        !          1695:                }
        !          1696:                enumerator->destroy(enumerator);
        !          1697:        }
        !          1698: 
        !          1699:        /* delete SAs in the kernel, if they are set up */
        !          1700:        if (this->my_spi)
        !          1701:        {
        !          1702:                kernel_ipsec_sa_id_t id = {
        !          1703:                        .src = this->other_addr,
        !          1704:                        .dst = this->my_addr,
        !          1705:                        .spi = this->my_spi,
        !          1706:                        .proto = proto_ike2ip(this->protocol),
        !          1707:                        .mark = mark_in_sa(this),
        !          1708:                        .if_id = this->if_id_in,
        !          1709:                };
        !          1710:                kernel_ipsec_del_sa_t sa = {
        !          1711:                        .cpi = this->my_cpi,
        !          1712:                };
        !          1713:                charon->kernel->del_sa(charon->kernel, &id, &sa);
        !          1714:        }
        !          1715:        if (this->other_spi && (this->outbound_state & CHILD_OUTBOUND_SA))
        !          1716:        {
        !          1717:                kernel_ipsec_sa_id_t id = {
        !          1718:                        .src = this->my_addr,
        !          1719:                        .dst = this->other_addr,
        !          1720:                        .spi = this->other_spi,
        !          1721:                        .proto = proto_ike2ip(this->protocol),
        !          1722:                        .mark = this->mark_out,
        !          1723:                        .if_id = this->if_id_out,
        !          1724:                };
        !          1725:                kernel_ipsec_del_sa_t sa = {
        !          1726:                        .cpi = this->other_cpi,
        !          1727:                };
        !          1728:                charon->kernel->del_sa(charon->kernel, &id, &sa);
        !          1729:        }
        !          1730: 
        !          1731:        if (this->reqid_allocated)
        !          1732:        {
        !          1733:                if (charon->kernel->release_reqid(charon->kernel,
        !          1734:                                                this->reqid, this->mark_in, this->mark_out,
        !          1735:                                                this->if_id_in, this->if_id_out) != SUCCESS)
        !          1736:                {
        !          1737:                        DBG1(DBG_CHD, "releasing reqid %u failed", this->reqid);
        !          1738:                }
        !          1739:        }
        !          1740: 
        !          1741:        array_destroy_offset(this->my_ts, offsetof(traffic_selector_t, destroy));
        !          1742:        array_destroy_offset(this->other_ts, offsetof(traffic_selector_t, destroy));
        !          1743:        this->my_addr->destroy(this->my_addr);
        !          1744:        this->other_addr->destroy(this->other_addr);
        !          1745:        DESTROY_IF(this->proposal);
        !          1746:        this->config->destroy(this->config);
        !          1747:        chunk_clear(&this->encr_r);
        !          1748:        chunk_clear(&this->integ_r);
        !          1749:        free(this);
        !          1750: }
        !          1751: 
        !          1752: /**
        !          1753:  * Get proxy address for one side, if any
        !          1754:  */
        !          1755: static host_t* get_proxy_addr(child_cfg_t *config, host_t *ike, bool local)
        !          1756: {
        !          1757:        host_t *host = NULL;
        !          1758:        uint8_t mask;
        !          1759:        enumerator_t *enumerator;
        !          1760:        linked_list_t *ts_list, *list;
        !          1761:        traffic_selector_t *ts;
        !          1762: 
        !          1763:        list = linked_list_create_with_items(ike, NULL);
        !          1764:        ts_list = config->get_traffic_selectors(config, local, NULL, list, FALSE);
        !          1765:        list->destroy(list);
        !          1766: 
        !          1767:        enumerator = ts_list->create_enumerator(ts_list);
        !          1768:        while (enumerator->enumerate(enumerator, &ts))
        !          1769:        {
        !          1770:                if (ts->is_host(ts, NULL) && ts->to_subnet(ts, &host, &mask))
        !          1771:                {
        !          1772:                        DBG1(DBG_CHD, "%s address: %H is a transport mode proxy for %H",
        !          1773:                                 local ? "my" : "other", ike, host);
        !          1774:                        break;
        !          1775:                }
        !          1776:        }
        !          1777:        enumerator->destroy(enumerator);
        !          1778:        ts_list->destroy_offset(ts_list, offsetof(traffic_selector_t, destroy));
        !          1779: 
        !          1780:        if (!host)
        !          1781:        {
        !          1782:                host = ike->clone(ike);
        !          1783:        }
        !          1784:        return host;
        !          1785: }
        !          1786: 
        !          1787: /*
        !          1788:  * Described in header
        !          1789:  */
        !          1790: child_sa_t *child_sa_create(host_t *me, host_t *other, child_cfg_t *config,
        !          1791:                                                        child_sa_create_t *data)
        !          1792: {
        !          1793:        private_child_sa_t *this;
        !          1794:        static refcount_t unique_id = 0, unique_mark = 0;
        !          1795: 
        !          1796:        INIT(this,
        !          1797:                .public = {
        !          1798:                        .get_name = _get_name,
        !          1799:                        .get_reqid = _get_reqid,
        !          1800:                        .get_unique_id = _get_unique_id,
        !          1801:                        .get_config = _get_config,
        !          1802:                        .get_state = _get_state,
        !          1803:                        .set_state = _set_state,
        !          1804:                        .get_outbound_state = _get_outbound_state,
        !          1805:                        .get_spi = _get_spi,
        !          1806:                        .get_cpi = _get_cpi,
        !          1807:                        .get_protocol = _get_protocol,
        !          1808:                        .set_protocol = _set_protocol,
        !          1809:                        .get_mode = _get_mode,
        !          1810:                        .set_mode = _set_mode,
        !          1811:                        .get_proposal = _get_proposal,
        !          1812:                        .set_proposal = _set_proposal,
        !          1813:                        .get_lifetime = _get_lifetime,
        !          1814:                        .get_installtime = _get_installtime,
        !          1815:                        .get_usestats = _get_usestats,
        !          1816:                        .get_mark = _get_mark,
        !          1817:                        .get_if_id = _get_if_id,
        !          1818:                        .has_encap = _has_encap,
        !          1819:                        .get_ipcomp = _get_ipcomp,
        !          1820:                        .set_ipcomp = _set_ipcomp,
        !          1821:                        .get_close_action = _get_close_action,
        !          1822:                        .set_close_action = _set_close_action,
        !          1823:                        .get_dpd_action = _get_dpd_action,
        !          1824:                        .set_dpd_action = _set_dpd_action,
        !          1825:                        .alloc_spi = _alloc_spi,
        !          1826:                        .alloc_cpi = _alloc_cpi,
        !          1827:                        .install = _install,
        !          1828:                        .register_outbound = _register_outbound,
        !          1829:                        .install_outbound = _install_outbound,
        !          1830:                        .remove_outbound = _remove_outbound,
        !          1831:                        .set_rekey_spi = _set_rekey_spi,
        !          1832:                        .get_rekey_spi = _get_rekey_spi,
        !          1833:                        .update = _update,
        !          1834:                        .set_policies = _set_policies,
        !          1835:                        .install_policies = _install_policies,
        !          1836:                        .create_ts_enumerator = _create_ts_enumerator,
        !          1837:                        .create_policy_enumerator = _create_policy_enumerator,
        !          1838:                        .destroy = _destroy,
        !          1839:                },
        !          1840:                .encap = data->encap,
        !          1841:                .ipcomp = IPCOMP_NONE,
        !          1842:                .state = CHILD_CREATED,
        !          1843:                .my_ts = array_create(0, 0),
        !          1844:                .other_ts = array_create(0, 0),
        !          1845:                .protocol = PROTO_NONE,
        !          1846:                .mode = MODE_TUNNEL,
        !          1847:                .close_action = config->get_close_action(config),
        !          1848:                .dpd_action = config->get_dpd_action(config),
        !          1849:                .reqid = config->get_reqid(config),
        !          1850:                .unique_id = ref_get(&unique_id),
        !          1851:                .mark_in = config->get_mark(config, TRUE),
        !          1852:                .mark_out = config->get_mark(config, FALSE),
        !          1853:                .if_id_in = config->get_if_id(config, TRUE) ?: data->if_id_in_def,
        !          1854:                .if_id_out = config->get_if_id(config, FALSE) ?: data->if_id_out_def,
        !          1855:                .install_time = time_monotonic(NULL),
        !          1856:                .policies_fwd_out = config->has_option(config, OPT_FWD_OUT_POLICIES),
        !          1857:        );
        !          1858: 
        !          1859:        this->config = config;
        !          1860:        config->get_ref(config);
        !          1861: 
        !          1862:        if (data->mark_in)
        !          1863:        {
        !          1864:                this->mark_in.value = data->mark_in;
        !          1865:        }
        !          1866:        if (data->mark_out)
        !          1867:        {
        !          1868:                this->mark_out.value = data->mark_out;
        !          1869:        }
        !          1870:        if (data->if_id_in)
        !          1871:        {
        !          1872:                this->if_id_in = data->if_id_in;
        !          1873:        }
        !          1874:        if (data->if_id_out)
        !          1875:        {
        !          1876:                this->if_id_out = data->if_id_out;
        !          1877:        }
        !          1878: 
        !          1879:        allocate_unique_if_ids(&this->if_id_in, &this->if_id_out);
        !          1880: 
        !          1881:        if (MARK_IS_UNIQUE(this->mark_in.value) ||
        !          1882:                MARK_IS_UNIQUE(this->mark_out.value))
        !          1883:        {
        !          1884:                refcount_t mark = 0;
        !          1885:                bool unique_dir = this->mark_in.value == MARK_UNIQUE_DIR ||
        !          1886:                                                  this->mark_out.value == MARK_UNIQUE_DIR;
        !          1887: 
        !          1888:                if (!unique_dir)
        !          1889:                {
        !          1890:                        mark = ref_get(&unique_mark);
        !          1891:                }
        !          1892:                if (MARK_IS_UNIQUE(this->mark_in.value))
        !          1893:                {
        !          1894:                        this->mark_in.value = unique_dir ? ref_get(&unique_mark) : mark;
        !          1895:                }
        !          1896:                if (MARK_IS_UNIQUE(this->mark_out.value))
        !          1897:                {
        !          1898:                        this->mark_out.value = unique_dir ? ref_get(&unique_mark) : mark;
        !          1899:                }
        !          1900:        }
        !          1901: 
        !          1902:        if (!this->reqid)
        !          1903:        {
        !          1904:                /* reuse old reqid if we are rekeying an existing CHILD_SA and when
        !          1905:                 * initiating a trap policy. While the reqid cache would find the same
        !          1906:                 * reqid for our selectors, this does not work in a special case: If an
        !          1907:                 * SA is triggered by a trap policy, but the negotiated TS get
        !          1908:                 * narrowed, we still must reuse the same reqid to successfully
        !          1909:                 * replace the temporary SA on the kernel level. Rekeying such an SA
        !          1910:                 * requires an explicit reqid, as the cache currently knows the original
        !          1911:                 * selectors only for that reqid. */
        !          1912:                this->reqid = data->reqid;
        !          1913:        }
        !          1914:        else
        !          1915:        {
        !          1916:                this->static_reqid = TRUE;
        !          1917:        }
        !          1918: 
        !          1919:        /* MIPv6 proxy transport mode sets SA endpoints to TS hosts */
        !          1920:        if (config->get_mode(config) == MODE_TRANSPORT &&
        !          1921:                config->has_option(config, OPT_PROXY_MODE))
        !          1922:        {
        !          1923:                this->mode = MODE_TRANSPORT;
        !          1924: 
        !          1925:                this->my_addr = get_proxy_addr(config, me, TRUE);
        !          1926:                this->other_addr = get_proxy_addr(config, other, FALSE);
        !          1927:        }
        !          1928:        else
        !          1929:        {
        !          1930:                this->my_addr = me->clone(me);
        !          1931:                this->other_addr = other->clone(other);
        !          1932:        }
        !          1933:        return &this->public;
        !          1934: }

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