Annotation of embedaddon/strongswan/src/libcharon/plugins/kernel_wfp/kernel_wfp_ipsec.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * Copyright (C) 2013 Martin Willi
        !             3:  * Copyright (C) 2013 revosec AG
        !             4:  *
        !             5:  * This program is free software; you can redistribute it and/or modify it
        !             6:  * under the terms of the GNU General Public License as published by the
        !             7:  * Free Software Foundation; either version 2 of the License, or (at your
        !             8:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
        !             9:  *
        !            10:  * This program is distributed in the hope that it will be useful, but
        !            11:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
        !            12:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
        !            13:  * for more details.
        !            14:  */
        !            15: 
        !            16: /* Windows 7, for some fwpmu.h functionality */
        !            17: #define _WIN32_WINNT 0x0601
        !            18: 
        !            19: #include "kernel_wfp_compat.h"
        !            20: #include "kernel_wfp_ipsec.h"
        !            21: 
        !            22: #include <daemon.h>
        !            23: #include <threading/mutex.h>
        !            24: #include <collections/array.h>
        !            25: #include <collections/hashtable.h>
        !            26: #include <processing/jobs/callback_job.h>
        !            27: 
        !            28: #ifndef IPPROTO_IPIP
        !            29: #define IPPROTO_IPIP 4
        !            30: #endif
        !            31: #ifndef IPPROTO_IPV6
        !            32: #define IPPROTO_IPV6 41
        !            33: #endif
        !            34: 
        !            35: typedef struct private_kernel_wfp_ipsec_t private_kernel_wfp_ipsec_t;
        !            36: 
        !            37: struct private_kernel_wfp_ipsec_t {
        !            38: 
        !            39:        /**
        !            40:         * Public interface
        !            41:         */
        !            42:        kernel_wfp_ipsec_t public;
        !            43: 
        !            44:        /**
        !            45:         * Next SPI to allocate
        !            46:         */
        !            47:        refcount_t nextspi;
        !            48: 
        !            49:        /**
        !            50:         * Mix value to distribute SPI allocation randomly
        !            51:         */
        !            52:        uint32_t mixspi;
        !            53: 
        !            54:        /**
        !            55:         * IKE bypass filters, as UINT64 filter LUID
        !            56:         */
        !            57:        array_t *bypass;
        !            58: 
        !            59:        /**
        !            60:         * Temporary SAD/SPD entries referenced reqid, as uintptr_t => entry_t
        !            61:         */
        !            62:        hashtable_t *tsas;
        !            63: 
        !            64:        /**
        !            65:         * SAD/SPD entries referenced by inbound SA, as sa_entry_t => entry_t
        !            66:         */
        !            67:        hashtable_t *isas;
        !            68: 
        !            69:        /**
        !            70:         * SAD/SPD entries referenced by outbound SA, as sa_entry_t => entry_t
        !            71:         */
        !            72:        hashtable_t *osas;
        !            73: 
        !            74:        /**
        !            75:         * Installed routes, as route_t => route_t
        !            76:         */
        !            77:        hashtable_t *routes;
        !            78: 
        !            79:        /**
        !            80:         * Installed traps, as trap_t => trap_t
        !            81:         */
        !            82:        hashtable_t *traps;
        !            83: 
        !            84:        /**
        !            85:         * Mutex for accessing entries
        !            86:         */
        !            87:        mutex_t *mutex;
        !            88: 
        !            89:        /**
        !            90:         * WFP session handle
        !            91:         */
        !            92:        HANDLE handle;
        !            93: 
        !            94:        /**
        !            95:         * Provider charon registers as
        !            96:         */
        !            97:        FWPM_PROVIDER0 provider;
        !            98: 
        !            99:        /**
        !           100:         * Event handle
        !           101:         */
        !           102:        HANDLE event;
        !           103: };
        !           104: 
        !           105: /**
        !           106:  * Security association entry
        !           107:  */
        !           108: typedef struct {
        !           109:        /** SPI for this SA */
        !           110:        uint32_t spi;
        !           111:        /** protocol, IPPROTO_ESP/IPPROTO_AH */
        !           112:        uint8_t protocol;
        !           113:        /** hard lifetime of SA */
        !           114:        uint32_t lifetime;
        !           115:        /** destination host address for this SPI */
        !           116:        host_t *dst;
        !           117:        struct {
        !           118:                /** algorithm */
        !           119:                uint16_t alg;
        !           120:                /** key */
        !           121:                chunk_t key;
        !           122:        } integ, encr;
        !           123: } sa_entry_t;
        !           124: 
        !           125: /**
        !           126:  * Hash function for sas lookup table
        !           127:  */
        !           128: static u_int hash_sa(sa_entry_t *key)
        !           129: {
        !           130:        return chunk_hash_inc(chunk_from_thing(key->spi),
        !           131:                                                  chunk_hash(key->dst->get_address(key->dst)));
        !           132: }
        !           133: 
        !           134: /**
        !           135:  * equals function for sas lookup table
        !           136:  */
        !           137: static bool equals_sa(sa_entry_t *a, sa_entry_t *b)
        !           138: {
        !           139:        return a->spi == b->spi && a->dst->ip_equals(a->dst, b->dst);
        !           140: }
        !           141: 
        !           142: /**
        !           143:  * Security policy entry
        !           144:  */
        !           145: typedef struct {
        !           146:        /** policy source addresses */
        !           147:        traffic_selector_t *src;
        !           148:        /** policy destination addresses */
        !           149:        traffic_selector_t *dst;
        !           150:        /** WFP allocated LUID for inbound filter ID */
        !           151:        uint64_t policy_in;
        !           152:        /** WFP allocated LUID for outbound filter ID */
        !           153:        uint64_t policy_out;
        !           154:        /** WFP allocated LUID for forward inbound filter ID, tunnel mode only */
        !           155:        uint64_t policy_fwd_in;
        !           156:        /** WFP allocated LUID for forward outbound filter ID, tunnel mode only */
        !           157:        uint64_t policy_fwd_out;
        !           158:        /** have installed a route for it? */
        !           159:        bool route;
        !           160: } sp_entry_t;
        !           161: 
        !           162: /**
        !           163:  * Destroy an SP entry
        !           164:  */
        !           165: static void sp_entry_destroy(sp_entry_t *sp)
        !           166: {
        !           167:        sp->src->destroy(sp->src);
        !           168:        sp->dst->destroy(sp->dst);
        !           169:        free(sp);
        !           170: }
        !           171: 
        !           172: /**
        !           173:  * Collection of SA/SP database entries for a reqid
        !           174:  */
        !           175: typedef struct {
        !           176:        /** reqid of entry */
        !           177:        uint32_t reqid;
        !           178:        /** outer address on local host */
        !           179:        host_t *local;
        !           180:        /** outer address on remote host */
        !           181:        host_t *remote;
        !           182:        /** inbound SA entry */
        !           183:        sa_entry_t isa;
        !           184:        /** outbound SA entry */
        !           185:        sa_entry_t osa;
        !           186:        /** associated (outbound) policies, as sp_entry_t* */
        !           187:        array_t *sps;
        !           188:        /** IPsec mode, tunnel|transport */
        !           189:        ipsec_mode_t mode;
        !           190:        /** UDP encapsulation */
        !           191:        bool encap;
        !           192:        /** provider context, for tunnel mode only */
        !           193:        uint64_t provider;
        !           194:        /** WFP allocated LUID for SA context */
        !           195:        uint64_t sa_id;
        !           196:        /** WFP allocated LUID for tunnel mode IP-IPv4 inbound filter */
        !           197:        uint64_t ip_ipv4_in;
        !           198:        /** WFP allocated LUID for tunnel mode IP-IPv4 outbound filter */
        !           199:        uint64_t ip_ipv4_out;
        !           200:        /** WFP allocated LUID for tunnel mode IP-IPv6 inbound filter */
        !           201:        uint64_t ip_ipv6_in;
        !           202:        /** WFP allocated LUID for tunnel mode IP-IPv6 outbound filter */
        !           203:        uint64_t ip_ipv6_out;
        !           204: } entry_t;
        !           205: 
        !           206: /**
        !           207:  * Installed route
        !           208:  */
        !           209: typedef struct {
        !           210:        /** destination net of route */
        !           211:        host_t *dst;
        !           212:        /** prefix length of dst */
        !           213:        uint8_t mask;
        !           214:        /** source address for route */
        !           215:        host_t *src;
        !           216:        /** gateway of route, NULL if directly attached */
        !           217:        host_t *gtw;
        !           218:        /** references for route */
        !           219:        u_int refs;
        !           220: } route_t;
        !           221: 
        !           222: /**
        !           223:  * Destroy a route_t
        !           224:  */
        !           225: static void destroy_route(route_t *this)
        !           226: {
        !           227:        this->dst->destroy(this->dst);
        !           228:        this->src->destroy(this->src);
        !           229:        DESTROY_IF(this->gtw);
        !           230:        free(this);
        !           231: }
        !           232: 
        !           233: /**
        !           234:  * Hashtable equals function for routes
        !           235:  */
        !           236: static bool equals_route(route_t *a, route_t *b)
        !           237: {
        !           238:        return a->mask == b->mask &&
        !           239:                   a->dst->ip_equals(a->dst, b->dst) &&
        !           240:                   a->src->ip_equals(a->src, b->src);
        !           241: }
        !           242: 
        !           243: /**
        !           244:  * Hashtable hash function for routes
        !           245:  */
        !           246: static u_int hash_route(route_t *route)
        !           247: {
        !           248:        return chunk_hash_inc(route->src->get_address(route->src),
        !           249:                        chunk_hash_inc(route->dst->get_address(route->dst), route->mask));
        !           250: }
        !           251: 
        !           252: /** forward declaration */
        !           253: static bool manage_routes(private_kernel_wfp_ipsec_t *this, entry_t *entry,
        !           254:                                                  bool add);
        !           255: 
        !           256: /**
        !           257:  * Remove policies associated to an entry from kernel
        !           258:  */
        !           259: static void cleanup_policies(private_kernel_wfp_ipsec_t *this, entry_t *entry)
        !           260: {
        !           261:        enumerator_t *enumerator;
        !           262:        sp_entry_t *sp;
        !           263: 
        !           264:        if (entry->mode == MODE_TUNNEL)
        !           265:        {
        !           266:                manage_routes(this, entry, FALSE);
        !           267:        }
        !           268: 
        !           269:        enumerator = array_create_enumerator(entry->sps);
        !           270:        while (enumerator->enumerate(enumerator, &sp))
        !           271:        {
        !           272:                if (sp->policy_in)
        !           273:                {
        !           274:                        FwpmFilterDeleteById0(this->handle, sp->policy_in);
        !           275:                        sp->policy_in = 0;
        !           276:                }
        !           277:                if (sp->policy_out)
        !           278:                {
        !           279:                        FwpmFilterDeleteById0(this->handle, sp->policy_out);
        !           280:                        sp->policy_out = 0;
        !           281:                }
        !           282:                if (sp->policy_fwd_in)
        !           283:                {
        !           284:                        FwpmFilterDeleteById0(this->handle, sp->policy_fwd_in);
        !           285:                        sp->policy_fwd_in = 0;
        !           286:                }
        !           287:                if (sp->policy_fwd_out)
        !           288:                {
        !           289:                        FwpmFilterDeleteById0(this->handle, sp->policy_fwd_out);
        !           290:                        sp->policy_fwd_out = 0;
        !           291:                }
        !           292:        }
        !           293:        enumerator->destroy(enumerator);
        !           294: }
        !           295: 
        !           296: /**
        !           297:  * Destroy a SA/SP entry set
        !           298:  */
        !           299: static void entry_destroy(private_kernel_wfp_ipsec_t *this, entry_t *entry)
        !           300: {
        !           301:        if (entry->ip_ipv4_in)
        !           302:        {
        !           303:                FwpmFilterDeleteById0(this->handle, entry->ip_ipv4_in);
        !           304:        }
        !           305:        if (entry->ip_ipv4_out)
        !           306:        {
        !           307:                FwpmFilterDeleteById0(this->handle, entry->ip_ipv4_out);
        !           308:        }
        !           309:        if (entry->ip_ipv6_in)
        !           310:        {
        !           311:                FwpmFilterDeleteById0(this->handle, entry->ip_ipv6_in);
        !           312:        }
        !           313:        if (entry->ip_ipv6_out)
        !           314:        {
        !           315:                FwpmFilterDeleteById0(this->handle, entry->ip_ipv6_out);
        !           316:        }
        !           317:        if (entry->sa_id)
        !           318:        {
        !           319:                IPsecSaContextDeleteById0(this->handle, entry->sa_id);
        !           320:        }
        !           321:        if (entry->provider)
        !           322:        {
        !           323:                FwpmProviderContextDeleteById0(this->handle, entry->provider);
        !           324:        }
        !           325:        cleanup_policies(this, entry);
        !           326:        array_destroy_function(entry->sps, (void*)sp_entry_destroy, NULL);
        !           327:        entry->local->destroy(entry->local);
        !           328:        entry->remote->destroy(entry->remote);
        !           329:        chunk_clear(&entry->isa.integ.key);
        !           330:        chunk_clear(&entry->isa.encr.key);
        !           331:        chunk_clear(&entry->osa.integ.key);
        !           332:        chunk_clear(&entry->osa.encr.key);
        !           333:        free(entry);
        !           334: }
        !           335: 
        !           336: /**
        !           337:  * Append/Realloc a filter condition to an existing condition set
        !           338:  */
        !           339: static FWPM_FILTER_CONDITION0 *append_condition(FWPM_FILTER_CONDITION0 *conds[],
        !           340:                                                                                                int *count)
        !           341: {
        !           342:        FWPM_FILTER_CONDITION0 *cond;
        !           343: 
        !           344:        (*count)++;
        !           345:        *conds = realloc(*conds, *count * sizeof(*cond));
        !           346:        cond = *conds + *count - 1;
        !           347:        memset(cond, 0, sizeof(*cond));
        !           348: 
        !           349:        return cond;
        !           350: }
        !           351: 
        !           352: /**
        !           353:  * Convert an IPv4 prefix to a host order subnet mask
        !           354:  */
        !           355: static uint32_t prefix2mask(uint8_t prefix)
        !           356: {
        !           357:        uint8_t netmask[4] = {};
        !           358:        int i;
        !           359: 
        !           360:        for (i = 0; i < sizeof(netmask); i++)
        !           361:        {
        !           362:                if (prefix < 8)
        !           363:                {
        !           364:                        netmask[i] = 0xFF << (8 - prefix);
        !           365:                        break;
        !           366:                }
        !           367:                netmask[i] = 0xFF;
        !           368:                prefix -= 8;
        !           369:        }
        !           370:        return untoh32(netmask);
        !           371: }
        !           372: 
        !           373: /**
        !           374:  * Convert a 16-bit range to a WFP condition
        !           375:  */
        !           376: static void range2cond(FWPM_FILTER_CONDITION0 *cond,
        !           377:                                           uint16_t from, uint16_t to)
        !           378: {
        !           379:        if (from == to)
        !           380:        {
        !           381:                cond->matchType = FWP_MATCH_EQUAL;
        !           382:                cond->conditionValue.type = FWP_UINT16;
        !           383:                cond->conditionValue.uint16 = from;
        !           384:        }
        !           385:        else
        !           386:        {
        !           387:                cond->matchType = FWP_MATCH_RANGE;
        !           388:                cond->conditionValue.type = FWP_RANGE_TYPE;
        !           389:                cond->conditionValue.rangeValue = calloc(1, sizeof(FWP_RANGE0));
        !           390:                cond->conditionValue.rangeValue->valueLow.type = FWP_UINT16;
        !           391:                cond->conditionValue.rangeValue->valueLow.uint16 = from;
        !           392:                cond->conditionValue.rangeValue->valueHigh.type = FWP_UINT16;
        !           393:                cond->conditionValue.rangeValue->valueHigh.uint16 = to;
        !           394:        }
        !           395: }
        !           396: 
        !           397: /**
        !           398:  * (Re-)allocate filter conditions for given local or remote traffic selector
        !           399:  */
        !           400: static bool ts2condition(traffic_selector_t *ts, const GUID *target,
        !           401:                                                 FWPM_FILTER_CONDITION0 *conds[], int *count)
        !           402: {
        !           403:        FWPM_FILTER_CONDITION0 *cond;
        !           404:        FWP_BYTE_ARRAY16 *addr;
        !           405:        FWP_RANGE0 *range;
        !           406:        uint16_t from_port, to_port;
        !           407:        void *from, *to;
        !           408:        uint8_t proto;
        !           409:        host_t *net;
        !           410:        uint8_t prefix;
        !           411: 
        !           412:        from = ts->get_from_address(ts).ptr;
        !           413:        to = ts->get_to_address(ts).ptr;
        !           414:        from_port = ts->get_from_port(ts);
        !           415:        to_port = ts->get_to_port(ts);
        !           416: 
        !           417:        cond = append_condition(conds, count);
        !           418:        cond->fieldKey = *target;
        !           419:        if (ts->is_host(ts, NULL))
        !           420:        {
        !           421:                cond->matchType = FWP_MATCH_EQUAL;
        !           422:                switch (ts->get_type(ts))
        !           423:                {
        !           424:                        case TS_IPV4_ADDR_RANGE:
        !           425:                                cond->conditionValue.type = FWP_UINT32;
        !           426:                                cond->conditionValue.uint32 = untoh32(from);
        !           427:                                break;
        !           428:                        case TS_IPV6_ADDR_RANGE:
        !           429:                                cond->conditionValue.type = FWP_BYTE_ARRAY16_TYPE;
        !           430:                                cond->conditionValue.byteArray16 = addr = malloc(sizeof(*addr));
        !           431:                                memcpy(addr, from, sizeof(*addr));
        !           432:                                break;
        !           433:                        default:
        !           434:                                return FALSE;
        !           435:                }
        !           436:        }
        !           437:        else if (ts->to_subnet(ts, &net, &prefix))
        !           438:        {
        !           439:                FWP_V6_ADDR_AND_MASK *m6;
        !           440:                FWP_V4_ADDR_AND_MASK *m4;
        !           441: 
        !           442:                cond->matchType = FWP_MATCH_EQUAL;
        !           443:                switch (net->get_family(net))
        !           444:                {
        !           445:                        case AF_INET:
        !           446:                                cond->conditionValue.type = FWP_V4_ADDR_MASK;
        !           447:                                cond->conditionValue.v4AddrMask = m4 = calloc(1, sizeof(*m4));
        !           448:                                m4->addr = untoh32(from);
        !           449:                                m4->mask = prefix2mask(prefix);
        !           450:                                break;
        !           451:                        case AF_INET6:
        !           452:                                cond->conditionValue.type = FWP_V6_ADDR_MASK;
        !           453:                                cond->conditionValue.v6AddrMask = m6 = calloc(1, sizeof(*m6));
        !           454:                                memcpy(m6->addr, from, sizeof(m6->addr));
        !           455:                                m6->prefixLength = prefix;
        !           456:                                break;
        !           457:                        default:
        !           458:                                net->destroy(net);
        !           459:                                return FALSE;
        !           460:                }
        !           461:                net->destroy(net);
        !           462:        }
        !           463:        else
        !           464:        {
        !           465:                cond->matchType = FWP_MATCH_RANGE;
        !           466:                cond->conditionValue.type = FWP_RANGE_TYPE;
        !           467:                cond->conditionValue.rangeValue = range = calloc(1, sizeof(*range));
        !           468:                switch (ts->get_type(ts))
        !           469:                {
        !           470:                        case TS_IPV4_ADDR_RANGE:
        !           471:                                range->valueLow.type = FWP_UINT32;
        !           472:                                range->valueLow.uint32 = untoh32(from);
        !           473:                                range->valueHigh.type = FWP_UINT32;
        !           474:                                range->valueHigh.uint32 = untoh32(to);
        !           475:                                break;
        !           476:                        case TS_IPV6_ADDR_RANGE:
        !           477:                                range->valueLow.type = FWP_BYTE_ARRAY16_TYPE;
        !           478:                                range->valueLow.byteArray16 = addr = malloc(sizeof(*addr));
        !           479:                                memcpy(addr, from, sizeof(*addr));
        !           480:                                range->valueHigh.type = FWP_BYTE_ARRAY16_TYPE;
        !           481:                                range->valueHigh.byteArray16 = addr = malloc(sizeof(*addr));
        !           482:                                memcpy(addr, to, sizeof(*addr));
        !           483:                                break;
        !           484:                        default:
        !           485:                                return FALSE;
        !           486:                }
        !           487:        }
        !           488: 
        !           489:        proto = ts->get_protocol(ts);
        !           490:        if (proto && target == &FWPM_CONDITION_IP_LOCAL_ADDRESS)
        !           491:        {
        !           492:                cond = append_condition(conds, count);
        !           493:                cond->fieldKey = FWPM_CONDITION_IP_PROTOCOL;
        !           494:                cond->matchType = FWP_MATCH_EQUAL;
        !           495:                cond->conditionValue.type = FWP_UINT8;
        !           496:                cond->conditionValue.uint8 = proto;
        !           497:        }
        !           498: 
        !           499:        if (proto == IPPROTO_ICMP)
        !           500:        {
        !           501:                if (target == &FWPM_CONDITION_IP_LOCAL_ADDRESS)
        !           502:                {
        !           503:                        uint8_t from_type, to_type, from_code, to_code;
        !           504: 
        !           505:                        from_type = traffic_selector_icmp_type(from_port);
        !           506:                        to_type = traffic_selector_icmp_type(to_port);
        !           507:                        from_code = traffic_selector_icmp_code(from_port);
        !           508:                        to_code = traffic_selector_icmp_code(to_port);
        !           509: 
        !           510:                        if (from_type != 0 || to_type != 0xFF)
        !           511:                        {
        !           512:                                cond = append_condition(conds, count);
        !           513:                                cond->fieldKey = FWPM_CONDITION_ICMP_TYPE;
        !           514:                                range2cond(cond, from_type, to_type);
        !           515:                        }
        !           516:                        if (from_code != 0 || to_code != 0xFF)
        !           517:                        {
        !           518:                                cond = append_condition(conds, count);
        !           519:                                cond->fieldKey = FWPM_CONDITION_ICMP_CODE;
        !           520:                                range2cond(cond, from_code, to_code);
        !           521:                        }
        !           522:                }
        !           523:        }
        !           524:        else if (from_port != 0 || to_port != 0xFFFF)
        !           525:        {
        !           526:                if (target == &FWPM_CONDITION_IP_LOCAL_ADDRESS)
        !           527:                {
        !           528:                        cond = append_condition(conds, count);
        !           529:                        cond->fieldKey = FWPM_CONDITION_IP_LOCAL_PORT;
        !           530:                        range2cond(cond, from_port, to_port);
        !           531:                }
        !           532:                if (target == &FWPM_CONDITION_IP_REMOTE_ADDRESS)
        !           533:                {
        !           534:                        cond = append_condition(conds, count);
        !           535:                        cond->fieldKey = FWPM_CONDITION_IP_REMOTE_PORT;
        !           536:                        range2cond(cond, from_port, to_port);
        !           537:                }
        !           538:        }
        !           539:        return TRUE;
        !           540: }
        !           541: 
        !           542: /**
        !           543:  * Free memory associated to a single condition
        !           544:  */
        !           545: static void free_condition(FWP_DATA_TYPE type, void *value)
        !           546: {
        !           547:        FWP_RANGE0 *range;
        !           548: 
        !           549:        switch (type)
        !           550:        {
        !           551:                case FWP_BYTE_ARRAY16_TYPE:
        !           552:                case FWP_V4_ADDR_MASK:
        !           553:                case FWP_V6_ADDR_MASK:
        !           554:                        free(value);
        !           555:                        break;
        !           556:                case FWP_RANGE_TYPE:
        !           557:                        range = value;
        !           558:                        free_condition(range->valueLow.type, range->valueLow.sd);
        !           559:                        free_condition(range->valueHigh.type, range->valueHigh.sd);
        !           560:                        free(range);
        !           561:                        break;
        !           562:                default:
        !           563:                        break;
        !           564:        }
        !           565: }
        !           566: 
        !           567: /**
        !           568:  * Free memory used by a set of conditions
        !           569:  */
        !           570: static void free_conditions(FWPM_FILTER_CONDITION0 *conds, int count)
        !           571: {
        !           572:        int i;
        !           573: 
        !           574:        for (i = 0; i < count; i++)
        !           575:        {
        !           576:                free_condition(conds[i].conditionValue.type, conds[i].conditionValue.sd);
        !           577:        }
        !           578:        free(conds);
        !           579: }
        !           580: 
        !           581: /**
        !           582:  * Find the callout GUID for given parameters
        !           583:  */
        !           584: static bool find_callout(bool tunnel, bool v6, bool inbound, bool forward,
        !           585:                                                 bool ale, GUID *layer, GUID *sublayer, GUID *callout)
        !           586: {
        !           587:        struct {
        !           588:                bool tunnel;
        !           589:                bool v6;
        !           590:                bool inbound;
        !           591:                bool forward;
        !           592:                bool ale;
        !           593:                const GUID *layer;
        !           594:                const GUID *sublayer;
        !           595:                const GUID *callout;
        !           596:        } map[] = {
        !           597:                { 0, 0, 0, 0, 0,        &FWPM_LAYER_OUTBOUND_TRANSPORT_V4, NULL,
        !           598:                                                        &FWPM_CALLOUT_IPSEC_OUTBOUND_TRANSPORT_V4               },
        !           599:                { 0, 0, 1, 0, 0,        &FWPM_LAYER_INBOUND_TRANSPORT_V4, NULL,
        !           600:                                                        &FWPM_CALLOUT_IPSEC_INBOUND_TRANSPORT_V4                },
        !           601:                { 0, 1, 0, 0, 0,        &FWPM_LAYER_OUTBOUND_TRANSPORT_V6, NULL,
        !           602:                                                        &FWPM_CALLOUT_IPSEC_OUTBOUND_TRANSPORT_V6               },
        !           603:                { 0, 1, 1, 0, 0,        &FWPM_LAYER_INBOUND_TRANSPORT_V6, NULL,
        !           604:                                                        &FWPM_CALLOUT_IPSEC_INBOUND_TRANSPORT_V6                },
        !           605:                { 1, 0, 0, 0, 0,        &FWPM_LAYER_OUTBOUND_TRANSPORT_V4,
        !           606:                                                        &FWPM_SUBLAYER_IPSEC_TUNNEL,
        !           607:                                                        &FWPM_CALLOUT_IPSEC_OUTBOUND_TUNNEL_V4                  },
        !           608:                { 1, 0, 0, 1, 0,        &FWPM_LAYER_IPFORWARD_V4,
        !           609:                                                        &FWPM_SUBLAYER_IPSEC_FORWARD_OUTBOUND_TUNNEL,
        !           610:                                                        &FWPM_CALLOUT_IPSEC_FORWARD_OUTBOUND_TUNNEL_V4  },
        !           611:                { 1, 0, 1, 0, 0,        &FWPM_LAYER_INBOUND_TRANSPORT_V4,
        !           612:                                                        &FWPM_SUBLAYER_IPSEC_TUNNEL,
        !           613:                                                        &FWPM_CALLOUT_IPSEC_INBOUND_TUNNEL_V4                   },
        !           614:                { 1, 0, 1, 1, 0,        &FWPM_LAYER_IPFORWARD_V4,
        !           615:                                                        &FWPM_SUBLAYER_IPSEC_TUNNEL,
        !           616:                                                        &FWPM_CALLOUT_IPSEC_FORWARD_INBOUND_TUNNEL_V4   },
        !           617:                { 1, 0, 0, 0, 1,        &FWPM_LAYER_ALE_AUTH_CONNECT_V4, NULL,
        !           618:                                                        &FWPM_CALLOUT_IPSEC_ALE_CONNECT_V4                              },
        !           619:                { 1, 0, 1, 0, 1,        &FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4, NULL,
        !           620:                                                        &FWPM_CALLOUT_IPSEC_INBOUND_TUNNEL_ALE_ACCEPT_V4},
        !           621:                { 1, 1, 0, 0, 0,        &FWPM_LAYER_OUTBOUND_TRANSPORT_V6,
        !           622:                                                        &FWPM_SUBLAYER_IPSEC_TUNNEL,
        !           623:                                                        &FWPM_CALLOUT_IPSEC_OUTBOUND_TUNNEL_V6                  },
        !           624:                { 1, 1, 0, 1, 0,        &FWPM_LAYER_IPFORWARD_V6,
        !           625:                                                        &FWPM_SUBLAYER_IPSEC_FORWARD_OUTBOUND_TUNNEL,
        !           626:                                                        &FWPM_CALLOUT_IPSEC_FORWARD_OUTBOUND_TUNNEL_V6  },
        !           627:                { 1, 1, 1, 0, 0,        &FWPM_LAYER_INBOUND_TRANSPORT_V6,
        !           628:                                                        &FWPM_SUBLAYER_IPSEC_TUNNEL,
        !           629:                                                        &FWPM_CALLOUT_IPSEC_INBOUND_TUNNEL_V6                   },
        !           630:                { 1, 1, 1, 1, 0,        &FWPM_LAYER_IPFORWARD_V6,
        !           631:                                                        &FWPM_SUBLAYER_IPSEC_TUNNEL,
        !           632:                                                        &FWPM_CALLOUT_IPSEC_FORWARD_INBOUND_TUNNEL_V6   },
        !           633:                { 1, 1, 0, 0, 1,        &FWPM_LAYER_ALE_AUTH_CONNECT_V6, NULL,
        !           634:                                                        &FWPM_CALLOUT_IPSEC_ALE_CONNECT_V6                              },
        !           635:                { 1, 1, 1, 0, 1,        &FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6, NULL,
        !           636:                                                        &FWPM_CALLOUT_IPSEC_INBOUND_TUNNEL_ALE_ACCEPT_V6},
        !           637:        };
        !           638:        int i;
        !           639: 
        !           640:        for (i = 0; i < countof(map); i++)
        !           641:        {
        !           642:                if (tunnel == map[i].tunnel &&
        !           643:                        v6 == map[i].v6 &&
        !           644:                        inbound == map[i].inbound &&
        !           645:                        forward == map[i].forward &&
        !           646:                        ale == map[i].ale)
        !           647:                {
        !           648:                        *callout = *map[i].callout;
        !           649:                        *layer = *map[i].layer;
        !           650:                        if (map[i].sublayer)
        !           651:                        {
        !           652:                                *sublayer = *map[i].sublayer;
        !           653:                        }
        !           654:                        return TRUE;
        !           655:                }
        !           656:        }
        !           657:        return FALSE;
        !           658: }
        !           659: 
        !           660: /**
        !           661:  * Install a single policy in to the kernel
        !           662:  */
        !           663: static bool install_sp(private_kernel_wfp_ipsec_t *this, sp_entry_t *sp,
        !           664:                                           GUID *context, bool inbound, bool fwd, UINT64 *filter_id)
        !           665: {
        !           666:        FWPM_FILTER_CONDITION0 *conds = NULL;
        !           667:        traffic_selector_t *local, *remote;
        !           668:        const GUID *ltarget, *rtarget;
        !           669:        int count = 0;
        !           670:        bool v6;
        !           671:        DWORD res;
        !           672:        FWPM_FILTER0 filter = {
        !           673:                .displayData = {
        !           674:                        .name = L"charon IPsec policy",
        !           675:                },
        !           676:                .action = {
        !           677:                        .type = FWP_ACTION_CALLOUT_TERMINATING,
        !           678:                },
        !           679:        };
        !           680: 
        !           681:        if (context)
        !           682:        {
        !           683:                filter.flags |= FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT;
        !           684:                filter.providerKey = (GUID*)&this->provider.providerKey;
        !           685:                filter.providerContextKey = *context;
        !           686:        }
        !           687: 
        !           688:        v6 = sp->src->get_type(sp->src) == TS_IPV6_ADDR_RANGE;
        !           689:        if (!find_callout(context != NULL, v6, inbound, fwd, FALSE,
        !           690:                                          &filter.layerKey, &filter.subLayerKey,
        !           691:                                          &filter.action.calloutKey))
        !           692:        {
        !           693:                return FALSE;
        !           694:        }
        !           695: 
        !           696:        if (inbound && fwd)
        !           697:        {
        !           698:                local = sp->dst;
        !           699:                remote = sp->src;
        !           700:        }
        !           701:        else
        !           702:        {
        !           703:                local = sp->src;
        !           704:                remote = sp->dst;
        !           705:        }
        !           706:        if (fwd)
        !           707:        {
        !           708:                ltarget = &FWPM_CONDITION_IP_SOURCE_ADDRESS;
        !           709:                rtarget = &FWPM_CONDITION_IP_DESTINATION_ADDRESS;
        !           710:        }
        !           711:        else
        !           712:        {
        !           713:                ltarget = &FWPM_CONDITION_IP_LOCAL_ADDRESS;
        !           714:                rtarget = &FWPM_CONDITION_IP_REMOTE_ADDRESS;
        !           715:        }
        !           716:        if (!ts2condition(local, ltarget, &conds, &count) ||
        !           717:                !ts2condition(remote, rtarget, &conds, &count))
        !           718:        {
        !           719:                free_conditions(conds, count);
        !           720:                return FALSE;
        !           721:        }
        !           722: 
        !           723:        filter.numFilterConditions = count;
        !           724:        filter.filterCondition = conds;
        !           725: 
        !           726:        res = FwpmFilterAdd0(this->handle, &filter, NULL, filter_id);
        !           727:        free_conditions(conds, count);
        !           728:        if (res != ERROR_SUCCESS)
        !           729:        {
        !           730:                DBG1(DBG_KNL, "installing IPv%d %s%sbound %s WFP filter failed: 0x%08x",
        !           731:                         v6 ? 6 : 4, fwd ? "forward " : "", inbound ? "in" : "out",
        !           732:                         context ? "tunnel" : "transport", res);
        !           733:                return FALSE;
        !           734:        }
        !           735:        return TRUE;
        !           736: }
        !           737: 
        !           738: /**
        !           739:  * Install an IP-IP allow filter for SA specific hosts
        !           740:  */
        !           741: static bool install_ipip_ale(private_kernel_wfp_ipsec_t *this,
        !           742:                                                         host_t *local, host_t *remote, GUID *context,
        !           743:                                                         bool inbound, int proto, uint64_t *filter_id)
        !           744: {
        !           745:        traffic_selector_t *lts, *rts;
        !           746:        FWPM_FILTER_CONDITION0 *conds = NULL;
        !           747:        int count = 0;
        !           748:        bool v6;
        !           749:        DWORD res;
        !           750:        FWPM_FILTER0 filter = {
        !           751:                .displayData = {
        !           752:                        .name = L"charon IPsec IP-in-IP ALE policy",
        !           753:                },
        !           754:                .action = {
        !           755:                        .type = FWP_ACTION_CALLOUT_TERMINATING,
        !           756:                },
        !           757:        };
        !           758: 
        !           759:        if (context)
        !           760:        {
        !           761:                filter.flags |= FWPM_FILTER_FLAG_HAS_PROVIDER_CONTEXT;
        !           762:                filter.providerKey = (GUID*)&this->provider.providerKey;
        !           763:                filter.providerContextKey = *context;
        !           764:        }
        !           765: 
        !           766:        v6 = local->get_family(local) == AF_INET6;
        !           767:        if (!find_callout(TRUE, v6, inbound, FALSE, TRUE, &filter.layerKey,
        !           768:                                          &filter.subLayerKey, &filter.action.calloutKey))
        !           769:        {
        !           770:                return FALSE;
        !           771:        }
        !           772: 
        !           773:        lts = traffic_selector_create_from_subnet(local->clone(local),
        !           774:                                                                                        v6 ? 128 : 32 , proto, 0, 65535);
        !           775:        rts = traffic_selector_create_from_subnet(remote->clone(remote),
        !           776:                                                                                        v6 ? 128 : 32 , proto, 0, 65535);
        !           777:        if (!ts2condition(lts, &FWPM_CONDITION_IP_LOCAL_ADDRESS, &conds, &count) ||
        !           778:                !ts2condition(rts, &FWPM_CONDITION_IP_REMOTE_ADDRESS, &conds, &count))
        !           779:        {
        !           780:                free_conditions(conds, count);
        !           781:                lts->destroy(lts);
        !           782:                rts->destroy(rts);
        !           783:                return FALSE;
        !           784:        }
        !           785:        lts->destroy(lts);
        !           786:        rts->destroy(rts);
        !           787: 
        !           788:        filter.numFilterConditions = count;
        !           789:        filter.filterCondition = conds;
        !           790: 
        !           791:        res = FwpmFilterAdd0(this->handle, &filter, NULL, filter_id);
        !           792:        free_conditions(conds, count);
        !           793:        if (res != ERROR_SUCCESS)
        !           794:        {
        !           795:                DBG1(DBG_KNL, "installing IP-IPv%d %s ALE WFP filter failed: 0x%08x",
        !           796:                         v6 ? 6 : 4, inbound ? "inbound" : "outbound", res);
        !           797:                return FALSE;
        !           798:        }
        !           799:        return TRUE;
        !           800: }
        !           801: 
        !           802: /**
        !           803:  * Install a set of policies in to the kernel
        !           804:  */
        !           805: static bool install_sps(private_kernel_wfp_ipsec_t *this,
        !           806:                                                entry_t *entry, GUID *context)
        !           807: {
        !           808:        enumerator_t *enumerator;
        !           809:        sp_entry_t *sp;
        !           810:        bool has_v4 = FALSE, has_v6 = FALSE;
        !           811: 
        !           812:        enumerator = array_create_enumerator(entry->sps);
        !           813:        while (enumerator->enumerate(enumerator, &sp))
        !           814:        {
        !           815:                switch (sp->src->get_type(sp->src))
        !           816:                {
        !           817:                        case TS_IPV4_ADDR_RANGE:
        !           818:                                has_v4 = TRUE;
        !           819:                                break;
        !           820:                        case TS_IPV6_ADDR_RANGE:
        !           821:                                has_v6 = TRUE;
        !           822:                                break;
        !           823:                }
        !           824: 
        !           825:                /* inbound policy */
        !           826:                if (!install_sp(this, sp, context, TRUE, FALSE, &sp->policy_in))
        !           827:                {
        !           828:                        enumerator->destroy(enumerator);
        !           829:                        return FALSE;
        !           830:                }
        !           831:                /* outbound policy */
        !           832:                if (!install_sp(this, sp, context, FALSE, FALSE, &sp->policy_out))
        !           833:                {
        !           834:                        enumerator->destroy(enumerator);
        !           835:                        return FALSE;
        !           836:                }
        !           837: 
        !           838:                if (context)
        !           839:                {
        !           840:                        if (!sp->src->is_host(sp->src, entry->local) ||
        !           841:                                !sp->dst->is_host(sp->dst, entry->remote))
        !           842:                        {
        !           843:                                /* inbound forward policy, from decapsulation */
        !           844:                                if (!install_sp(this, sp, context, TRUE, TRUE,
        !           845:                                                                &sp->policy_fwd_in))
        !           846:                                {
        !           847:                                        enumerator->destroy(enumerator);
        !           848:                                        return FALSE;
        !           849:                                }
        !           850:                                /* outbound forward policy, to encapsulate */
        !           851:                                if (!install_sp(this, sp, context, FALSE, TRUE,
        !           852:                                                                &sp->policy_fwd_out))
        !           853:                                {
        !           854:                                        enumerator->destroy(enumerator);
        !           855:                                        return FALSE;
        !           856:                                }
        !           857:                        }
        !           858:                }
        !           859:        }
        !           860:        enumerator->destroy(enumerator);
        !           861: 
        !           862:        if (context)
        !           863:        {
        !           864:                /* In tunnel mode, Windows does firewall filtering on decrypted but
        !           865:                 * non-unwrapped packets: It sees them as IP-in-IP packets. When using
        !           866:                 * a default-drop policy, we need to allow such packets explicitly. */
        !           867:                if (has_v4)
        !           868:                {
        !           869:                        if (!install_ipip_ale(this, entry->local, entry->remote, context,
        !           870:                                                                  TRUE, IPPROTO_IPIP, &entry->ip_ipv4_in))
        !           871:                        {
        !           872:                                return FALSE;
        !           873:                        }
        !           874:                        if (!install_ipip_ale(this, entry->local, entry->remote, NULL,
        !           875:                                                                  FALSE, IPPROTO_IPIP, &entry->ip_ipv4_out))
        !           876:                        {
        !           877:                                return FALSE;
        !           878:                        }
        !           879:                }
        !           880:                if (has_v6)
        !           881:                {
        !           882:                        if (!install_ipip_ale(this, entry->local, entry->remote, context,
        !           883:                                                                  TRUE, IPPROTO_IPV6, &entry->ip_ipv6_in))
        !           884:                        {
        !           885:                                return FALSE;
        !           886:                        }
        !           887:                        if (!install_ipip_ale(this, entry->local, entry->remote, NULL,
        !           888:                                                                  FALSE, IPPROTO_IPV6, &entry->ip_ipv6_out))
        !           889:                        {
        !           890:                                return FALSE;
        !           891:                        }
        !           892:                }
        !           893:        }
        !           894:        return TRUE;
        !           895: }
        !           896: 
        !           897: /**
        !           898:  * Convert a chunk_t to a WFP FWP_BYTE_BLOB
        !           899:  */
        !           900: static inline FWP_BYTE_BLOB chunk2blob(chunk_t chunk)
        !           901: {
        !           902:        return (FWP_BYTE_BLOB){
        !           903:                .size = chunk.len,
        !           904:                .data = chunk.ptr,
        !           905:        };
        !           906: }
        !           907: 
        !           908: /**
        !           909:  * Convert an integrity_algorithm_t to a WFP IPSEC_AUTH_TRANFORM_ID0
        !           910:  */
        !           911: static bool alg2auth(integrity_algorithm_t alg,
        !           912:                                         IPSEC_SA_AUTH_INFORMATION0 *info)
        !           913: {
        !           914:        struct {
        !           915:                integrity_algorithm_t alg;
        !           916:                IPSEC_AUTH_TRANSFORM_ID0 transform;
        !           917:        } map[] = {
        !           918:                { AUTH_HMAC_MD5_96,                     IPSEC_AUTH_TRANSFORM_ID_HMAC_MD5_96             },
        !           919:                { AUTH_HMAC_SHA1_96,            IPSEC_AUTH_TRANSFORM_ID_HMAC_SHA_1_96   },
        !           920:                { AUTH_HMAC_SHA2_256_128,       IPSEC_AUTH_TRANSFORM_ID_HMAC_SHA_256_128},
        !           921:                { AUTH_AES_128_GMAC,            IPSEC_AUTH_TRANSFORM_ID_GCM_AES_128             },
        !           922:                { AUTH_AES_192_GMAC,            IPSEC_AUTH_TRANSFORM_ID_GCM_AES_192             },
        !           923:                { AUTH_AES_256_GMAC,            IPSEC_AUTH_TRANSFORM_ID_GCM_AES_256             },
        !           924:        };
        !           925:        int i;
        !           926: 
        !           927:        for (i = 0; i < countof(map); i++)
        !           928:        {
        !           929:                if (map[i].alg == alg)
        !           930:                {
        !           931:                        info->authTransform.authTransformId = map[i].transform;
        !           932:                        return TRUE;
        !           933:                }
        !           934:        }
        !           935:        return FALSE;
        !           936: }
        !           937: 
        !           938: /**
        !           939:  * Convert an encryption_algorithm_t to a WFP IPSEC_CIPHER_TRANFORM_ID0
        !           940:  */
        !           941: static bool alg2cipher(encryption_algorithm_t alg, int keylen,
        !           942:                                           IPSEC_SA_CIPHER_INFORMATION0 *info)
        !           943: {
        !           944:        struct {
        !           945:                encryption_algorithm_t alg;
        !           946:                int keylen;
        !           947:                IPSEC_CIPHER_TRANSFORM_ID0 transform;
        !           948:        } map[] = {
        !           949:                { ENCR_DES,                              8, IPSEC_CIPHER_TRANSFORM_ID_CBC_DES           },
        !           950:                { ENCR_3DES,                    24, IPSEC_CIPHER_TRANSFORM_ID_CBC_3DES          },
        !           951:                { ENCR_AES_CBC,                 16, IPSEC_CIPHER_TRANSFORM_ID_AES_128           },
        !           952:                { ENCR_AES_CBC,                 24, IPSEC_CIPHER_TRANSFORM_ID_AES_192           },
        !           953:                { ENCR_AES_CBC,                 32, IPSEC_CIPHER_TRANSFORM_ID_AES_256           },
        !           954:                { ENCR_AES_GCM_ICV16,   20, IPSEC_CIPHER_TRANSFORM_ID_GCM_AES_128       },
        !           955:                { ENCR_AES_GCM_ICV16,   28, IPSEC_CIPHER_TRANSFORM_ID_GCM_AES_192       },
        !           956:                { ENCR_AES_GCM_ICV16,   36, IPSEC_CIPHER_TRANSFORM_ID_GCM_AES_256       },
        !           957:        };
        !           958:        int i;
        !           959: 
        !           960:        for (i = 0; i < countof(map); i++)
        !           961:        {
        !           962:                if (map[i].alg == alg && map[i].keylen == keylen)
        !           963:                {
        !           964:                        info->cipherTransform.cipherTransformId = map[i].transform;
        !           965:                        return TRUE;
        !           966:                }
        !           967:        }
        !           968:        return FALSE;
        !           969: }
        !           970: 
        !           971: /**
        !           972:  * Get the integrity algorithm used for an AEAD transform
        !           973:  */
        !           974: static integrity_algorithm_t encr2integ(encryption_algorithm_t encr, int keylen)
        !           975: {
        !           976:        struct {
        !           977:                encryption_algorithm_t encr;
        !           978:                int keylen;
        !           979:                integrity_algorithm_t integ;
        !           980:        } map[] = {
        !           981:                { ENCR_NULL_AUTH_AES_GMAC,              20, AUTH_AES_128_GMAC                           },
        !           982:                { ENCR_NULL_AUTH_AES_GMAC,              28, AUTH_AES_192_GMAC                           },
        !           983:                { ENCR_NULL_AUTH_AES_GMAC,              36, AUTH_AES_256_GMAC                           },
        !           984:                { ENCR_AES_GCM_ICV16,                   20, AUTH_AES_128_GMAC                           },
        !           985:                { ENCR_AES_GCM_ICV16,                   28, AUTH_AES_192_GMAC                           },
        !           986:                { ENCR_AES_GCM_ICV16,                   36, AUTH_AES_256_GMAC                           },
        !           987:        };
        !           988:        int i;
        !           989: 
        !           990:        for (i = 0; i < countof(map); i++)
        !           991:        {
        !           992:                if (map[i].encr == encr && map[i].keylen == keylen)
        !           993:                {
        !           994:                        return map[i].integ;
        !           995:                }
        !           996:        }
        !           997:        return AUTH_UNDEFINED;
        !           998: }
        !           999: 
        !          1000: /**
        !          1001:  * Install a single SA
        !          1002:  */
        !          1003: static bool install_sa(private_kernel_wfp_ipsec_t *this, entry_t *entry,
        !          1004:                                           bool inbound, sa_entry_t *sa, FWP_IP_VERSION version)
        !          1005: {
        !          1006:        IPSEC_SA_AUTH_AND_CIPHER_INFORMATION0 info = {};
        !          1007:        IPSEC_SA0 ipsec = {
        !          1008:                .spi = ntohl(sa->spi),
        !          1009:        };
        !          1010:        IPSEC_SA_BUNDLE0 bundle = {
        !          1011:                .lifetime = {
        !          1012:                        .lifetimeSeconds = inbound ? entry->isa.lifetime
        !          1013:                                                                           : entry->osa.lifetime,
        !          1014:                },
        !          1015:                .saList = &ipsec,
        !          1016:                .numSAs = 1,
        !          1017:                .ipVersion = version,
        !          1018:        };
        !          1019:        struct {
        !          1020:                uint16_t alg;
        !          1021:                chunk_t key;
        !          1022:        } integ = {}, encr = {};
        !          1023:        DWORD res;
        !          1024: 
        !          1025:        switch (sa->protocol)
        !          1026:        {
        !          1027:                case IPPROTO_AH:
        !          1028:                        ipsec.saTransformType = IPSEC_TRANSFORM_AH;
        !          1029:                        ipsec.ahInformation = &info.saAuthInformation;
        !          1030:                        integ.key = sa->integ.key;
        !          1031:                        integ.alg = sa->integ.alg;
        !          1032:                        break;
        !          1033:                case IPPROTO_ESP:
        !          1034:                        if (sa->encr.alg == ENCR_NULL ||
        !          1035:                                sa->encr.alg == ENCR_NULL_AUTH_AES_GMAC)
        !          1036:                        {
        !          1037:                                ipsec.saTransformType = IPSEC_TRANSFORM_ESP_AUTH;
        !          1038:                                ipsec.espAuthInformation = &info.saAuthInformation;
        !          1039:                        }
        !          1040:                        else
        !          1041:                        {
        !          1042:                                ipsec.saTransformType = IPSEC_TRANSFORM_ESP_AUTH_AND_CIPHER;
        !          1043:                                ipsec.espAuthAndCipherInformation = &info;
        !          1044:                                encr.key = sa->encr.key;
        !          1045:                                encr.alg = sa->encr.alg;
        !          1046:                        }
        !          1047:                        if (encryption_algorithm_is_aead(sa->encr.alg))
        !          1048:                        {
        !          1049:                                integ.alg = encr2integ(sa->encr.alg, sa->encr.key.len);
        !          1050:                                integ.key = sa->encr.key;
        !          1051:                        }
        !          1052:                        else
        !          1053:                        {
        !          1054:                                integ.alg = sa->integ.alg;
        !          1055:                                integ.key = sa->integ.key;
        !          1056:                        }
        !          1057:                        break;
        !          1058:                default:
        !          1059:                        return FALSE;
        !          1060:        }
        !          1061: 
        !          1062:        if (integ.alg)
        !          1063:        {
        !          1064:                info.saAuthInformation.authKey = chunk2blob(integ.key);
        !          1065:                if (!alg2auth(integ.alg, &info.saAuthInformation))
        !          1066:                {
        !          1067:                        DBG1(DBG_KNL, "integrity algorithm %N not supported by WFP",
        !          1068:                                 integrity_algorithm_names, integ.alg);
        !          1069:                        return FALSE;
        !          1070:                }
        !          1071:        }
        !          1072:        if (encr.alg)
        !          1073:        {
        !          1074:                info.saCipherInformation.cipherKey = chunk2blob(encr.key);
        !          1075:                if (!alg2cipher(encr.alg, encr.key.len, &info.saCipherInformation))
        !          1076:                {
        !          1077:                        DBG1(DBG_KNL, "encryption algorithm %N not supported by WFP",
        !          1078:                                 encryption_algorithm_names, encr.alg);
        !          1079:                        return FALSE;
        !          1080:                }
        !          1081:        }
        !          1082: 
        !          1083:        if (inbound)
        !          1084:        {
        !          1085:                res = IPsecSaContextAddInbound0(this->handle, entry->sa_id, &bundle);
        !          1086:        }
        !          1087:        else
        !          1088:        {
        !          1089:                bundle.flags |= IPSEC_SA_BUNDLE_FLAG_ASSUME_UDP_CONTEXT_OUTBOUND;
        !          1090:                res = IPsecSaContextAddOutbound0(this->handle, entry->sa_id, &bundle);
        !          1091:        }
        !          1092:        if (res != ERROR_SUCCESS)
        !          1093:        {
        !          1094:                DBG1(DBG_KNL, "adding %sbound WFP SA failed: 0x%08x",
        !          1095:                         inbound ? "in" : "out", res);
        !          1096:                return FALSE;
        !          1097:        }
        !          1098:        return TRUE;
        !          1099: }
        !          1100: 
        !          1101: /**
        !          1102:  * Convert an IPv6 host address to WFP representation
        !          1103:  */
        !          1104: static void host2address6(host_t *host, void *out)
        !          1105: {
        !          1106:        uint32_t *src, *dst = out;
        !          1107: 
        !          1108:        src = (uint32_t*)host->get_address(host).ptr;
        !          1109: 
        !          1110:        dst[0] = untoh32(&src[3]);
        !          1111:        dst[1] = untoh32(&src[2]);
        !          1112:        dst[2] = untoh32(&src[1]);
        !          1113:        dst[3] = untoh32(&src[0]);
        !          1114: }
        !          1115: 
        !          1116: /**
        !          1117:  * Fill in traffic structure from entry addresses
        !          1118:  */
        !          1119: static bool hosts2traffic(private_kernel_wfp_ipsec_t *this,
        !          1120:                                                  host_t *l, host_t *r, IPSEC_TRAFFIC1 *traffic)
        !          1121: {
        !          1122:        if (l->get_family(l) != r->get_family(r))
        !          1123:        {
        !          1124:                return FALSE;
        !          1125:        }
        !          1126:        switch (l->get_family(l))
        !          1127:        {
        !          1128:                case AF_INET:
        !          1129:                        traffic->ipVersion = FWP_IP_VERSION_V4;
        !          1130:                        traffic->localV4Address = untoh32(l->get_address(l).ptr);
        !          1131:                        traffic->remoteV4Address = untoh32(r->get_address(r).ptr);
        !          1132:                        return TRUE;
        !          1133:                case AF_INET6:
        !          1134:                        traffic->ipVersion = FWP_IP_VERSION_V6;
        !          1135:                        host2address6(l, &traffic->localV6Address);
        !          1136:                        host2address6(r, &traffic->remoteV6Address);
        !          1137:                        return TRUE;
        !          1138:                default:
        !          1139:                        return FALSE;
        !          1140:        }
        !          1141: }
        !          1142: 
        !          1143: /**
        !          1144:  * Install SAs to the kernel
        !          1145:  */
        !          1146: static bool install_sas(private_kernel_wfp_ipsec_t *this, entry_t *entry,
        !          1147:                                                IPSEC_TRAFFIC_TYPE type)
        !          1148: {
        !          1149:        IPSEC_TRAFFIC1 traffic = {
        !          1150:                .trafficType = type,
        !          1151:        };
        !          1152:        IPSEC_GETSPI1 spi = {
        !          1153:                .inboundIpsecTraffic = {
        !          1154:                        .trafficType = type,
        !          1155:                },
        !          1156:        };
        !          1157:        enumerator_t *enumerator;
        !          1158:        sp_entry_t *sp;
        !          1159:        DWORD res;
        !          1160: 
        !          1161:        if (type == IPSEC_TRAFFIC_TYPE_TRANSPORT)
        !          1162:        {
        !          1163:                enumerator = array_create_enumerator(entry->sps);
        !          1164:                if (enumerator->enumerate(enumerator, &sp))
        !          1165:                {
        !          1166:                        traffic.ipsecFilterId = sp->policy_out;
        !          1167:                        spi.inboundIpsecTraffic.ipsecFilterId = sp->policy_in;
        !          1168:                }
        !          1169:                else
        !          1170:                {
        !          1171:                        enumerator->destroy(enumerator);
        !          1172:                        return FALSE;
        !          1173:                }
        !          1174:                enumerator->destroy(enumerator);
        !          1175:        }
        !          1176:        else
        !          1177:        {
        !          1178:                traffic.tunnelPolicyId = entry->provider;
        !          1179:                spi.inboundIpsecTraffic.tunnelPolicyId = entry->provider;
        !          1180:        }
        !          1181: 
        !          1182:        if (!hosts2traffic(this, entry->local, entry->remote, &traffic))
        !          1183:        {
        !          1184:                return FALSE;
        !          1185:        }
        !          1186: 
        !          1187:        res = IPsecSaContextCreate1(this->handle, &traffic, NULL, NULL,
        !          1188:                                                                &entry->sa_id);
        !          1189:        if (res != ERROR_SUCCESS)
        !          1190:        {
        !          1191:                DBG1(DBG_KNL, "creating WFP SA context failed: 0x%08x", res);
        !          1192:                return FALSE;
        !          1193:        }
        !          1194: 
        !          1195:        memcpy(spi.inboundIpsecTraffic.localV6Address, traffic.localV6Address,
        !          1196:                   sizeof(traffic.localV6Address));
        !          1197:        memcpy(spi.inboundIpsecTraffic.remoteV6Address, traffic.remoteV6Address,
        !          1198:                   sizeof(traffic.remoteV6Address));
        !          1199:        spi.ipVersion = traffic.ipVersion;
        !          1200: 
        !          1201:        res = IPsecSaContextSetSpi0(this->handle, entry->sa_id, &spi,
        !          1202:                                                                ntohl(entry->isa.spi));
        !          1203:        if (res != ERROR_SUCCESS)
        !          1204:        {
        !          1205:                DBG1(DBG_KNL, "setting WFP SA SPI failed: 0x%08x", res);
        !          1206:                IPsecSaContextDeleteById0(this->handle, entry->sa_id);
        !          1207:                entry->sa_id = 0;
        !          1208:                return FALSE;
        !          1209:        }
        !          1210: 
        !          1211:        if (!install_sa(this, entry, TRUE, &entry->isa, spi.ipVersion) ||
        !          1212:                !install_sa(this, entry, FALSE, &entry->osa, spi.ipVersion))
        !          1213:        {
        !          1214:                IPsecSaContextDeleteById0(this->handle, entry->sa_id);
        !          1215:                entry->sa_id = 0;
        !          1216:                return FALSE;
        !          1217:        }
        !          1218: 
        !          1219:        if (entry->encap)
        !          1220:        {
        !          1221:                IPSEC_V4_UDP_ENCAPSULATION0 encap = {
        !          1222:                        .localUdpEncapPort = entry->local->get_port(entry->local),
        !          1223:                        .remoteUdpEncapPort = entry->remote->get_port(entry->remote),
        !          1224:                };
        !          1225:                IPSEC_SA_CONTEXT1 *ctx;
        !          1226: 
        !          1227:                res = IPsecSaContextGetById1(this->handle, entry->sa_id, &ctx);
        !          1228:                if (res != ERROR_SUCCESS)
        !          1229:                {
        !          1230:                        DBG1(DBG_KNL, "getting WFP SA for UDP encap failed: 0x%08x", res);
        !          1231:                        IPsecSaContextDeleteById0(this->handle, entry->sa_id);
        !          1232:                        entry->sa_id = 0;
        !          1233:                        return FALSE;
        !          1234:                }
        !          1235:                ctx->inboundSa->udpEncapsulation = &encap;
        !          1236:                ctx->outboundSa->udpEncapsulation = &encap;
        !          1237: 
        !          1238:                res = IPsecSaContextUpdate0(this->handle,
        !          1239:                                                                IPSEC_SA_DETAILS_UPDATE_UDP_ENCAPSULATION, ctx);
        !          1240:                FwpmFreeMemory0((void**)&ctx);
        !          1241:                if (res != ERROR_SUCCESS)
        !          1242:                {
        !          1243:                        DBG1(DBG_KNL, "enable WFP UDP encap failed: 0x%08x", res);
        !          1244:                        IPsecSaContextDeleteById0(this->handle, entry->sa_id);
        !          1245:                        entry->sa_id = 0;
        !          1246:                        return FALSE;
        !          1247:                }
        !          1248:        }
        !          1249: 
        !          1250:        return TRUE;
        !          1251: }
        !          1252: 
        !          1253: /**
        !          1254:  * Install a transport mode SA/SP set to the kernel
        !          1255:  */
        !          1256: static bool install_transport(private_kernel_wfp_ipsec_t *this, entry_t *entry)
        !          1257: {
        !          1258:        if (install_sps(this, entry, NULL) &&
        !          1259:                install_sas(this, entry, IPSEC_TRAFFIC_TYPE_TRANSPORT))
        !          1260:        {
        !          1261:                return TRUE;
        !          1262:        }
        !          1263:        cleanup_policies(this, entry);
        !          1264:        return FALSE;
        !          1265: }
        !          1266: 
        !          1267: /**
        !          1268:  * Generate a new GUID, random
        !          1269:  */
        !          1270: static bool generate_guid(private_kernel_wfp_ipsec_t *this, GUID *guid)
        !          1271: {
        !          1272:        bool ok;
        !          1273:        rng_t *rng;
        !          1274: 
        !          1275:        rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
        !          1276:        if (!rng)
        !          1277:        {
        !          1278:                return FALSE;
        !          1279:        }
        !          1280:        ok = rng->get_bytes(rng, sizeof(GUID), (uint8_t*)guid);
        !          1281:        rng->destroy(rng);
        !          1282:        return ok;
        !          1283: }
        !          1284: 
        !          1285: /**
        !          1286:  * Register a dummy tunnel provider to associate tunnel filters to
        !          1287:  */
        !          1288: static bool add_tunnel_provider(private_kernel_wfp_ipsec_t *this,
        !          1289:                                                                entry_t *entry, GUID *guid, UINT64 *luid)
        !          1290: {
        !          1291:        DWORD res;
        !          1292: 
        !          1293:        IPSEC_AUTH_TRANSFORM0 transform = {
        !          1294:                /* Create any valid proposal. This is actually not used, as we
        !          1295:                 * don't create an SA from this information. */
        !          1296:                .authTransformId = IPSEC_AUTH_TRANSFORM_ID_HMAC_SHA_1_96,
        !          1297:        };
        !          1298:        IPSEC_SA_TRANSFORM0 transforms = {
        !          1299:                .ipsecTransformType = IPSEC_TRANSFORM_ESP_AUTH,
        !          1300:                .espAuthTransform = &transform,
        !          1301:        };
        !          1302:        IPSEC_PROPOSAL0 proposal = {
        !          1303:                .lifetime = {
        !          1304:                        /* We need a valid lifetime, even if we don't create any SA
        !          1305:                         * from these values. Pick some values accepted. */
        !          1306:                        .lifetimeSeconds = 0xFFFF,
        !          1307:                        .lifetimeKilobytes = 0xFFFFFFFF,
        !          1308:                        .lifetimePackets = 0xFFFFFFFF,
        !          1309:                },
        !          1310:                .numSaTransforms = 1,
        !          1311:                .saTransforms = &transforms,
        !          1312:        };
        !          1313:        IPSEC_TUNNEL_POLICY0 policy = {
        !          1314:                .numIpsecProposals = 1,
        !          1315:                .ipsecProposals = &proposal,
        !          1316:                .saIdleTimeout = {
        !          1317:                        /* not used, set to lifetime for maximum */
        !          1318:                        .idleTimeoutSeconds = proposal.lifetime.lifetimeSeconds,
        !          1319:                        .idleTimeoutSecondsFailOver = proposal.lifetime.lifetimeSeconds,
        !          1320:                },
        !          1321:        };
        !          1322:        FWPM_PROVIDER_CONTEXT0 qm = {
        !          1323:                .displayData = {
        !          1324:                        .name = L"charon tunnel provider",
        !          1325:                },
        !          1326:                .providerKey = (GUID*)&this->provider.providerKey,
        !          1327:                .type = FWPM_IPSEC_IKE_QM_TUNNEL_CONTEXT,
        !          1328:                .ikeQmTunnelPolicy = &policy,
        !          1329:        };
        !          1330: 
        !          1331:        switch (entry->local->get_family(entry->local))
        !          1332:        {
        !          1333:                case AF_INET:
        !          1334:                        policy.tunnelEndpoints.ipVersion = FWP_IP_VERSION_V4;
        !          1335:                        policy.tunnelEndpoints.localV4Address =
        !          1336:                                                untoh32(entry->local->get_address(entry->local).ptr);
        !          1337:                        policy.tunnelEndpoints.remoteV4Address =
        !          1338:                                                untoh32(entry->remote->get_address(entry->remote).ptr);
        !          1339:                        break;
        !          1340:                case AF_INET6:
        !          1341:                        policy.tunnelEndpoints.ipVersion = FWP_IP_VERSION_V6;
        !          1342:                        host2address6(entry->local, &policy.tunnelEndpoints.localV6Address);
        !          1343:                        host2address6(entry->remote, &policy.tunnelEndpoints.remoteV6Address);
        !          1344:                        break;
        !          1345:                default:
        !          1346:                        return FALSE;
        !          1347:        }
        !          1348: 
        !          1349:        if (!generate_guid(this, &qm.providerContextKey))
        !          1350:        {
        !          1351:                return FALSE;
        !          1352:        }
        !          1353: 
        !          1354:        res = FwpmProviderContextAdd0(this->handle, &qm, NULL, luid);
        !          1355:        if (res != ERROR_SUCCESS)
        !          1356:        {
        !          1357:                DBG1(DBG_KNL, "adding provider context failed: 0x%08x", res);
        !          1358:                return FALSE;
        !          1359:        }
        !          1360:        *guid = qm.providerContextKey;
        !          1361:        return TRUE;
        !          1362: }
        !          1363: 
        !          1364: /**
        !          1365:  * Install tunnel mode SPs to the kernel
        !          1366:  */
        !          1367: static bool install_tunnel_sps(private_kernel_wfp_ipsec_t *this, entry_t *entry)
        !          1368: {
        !          1369:        GUID guid;
        !          1370: 
        !          1371:        if (!add_tunnel_provider(this, entry, &guid, &entry->provider))
        !          1372:        {
        !          1373:                return FALSE;
        !          1374:        }
        !          1375:        if (!install_sps(this, entry, &guid))
        !          1376:        {
        !          1377:                return FALSE;
        !          1378:        }
        !          1379:        return TRUE;
        !          1380: }
        !          1381: 
        !          1382: /**
        !          1383:  * Reduce refcount, or uninstall a route if all refs gone
        !          1384:  */
        !          1385: static bool uninstall_route(private_kernel_wfp_ipsec_t *this,
        !          1386:                                                        host_t *dst, uint8_t mask, host_t *src, host_t *gtw)
        !          1387: {
        !          1388:        route_t *route, key = {
        !          1389:                .dst = dst,
        !          1390:                .mask = mask,
        !          1391:                .src = src,
        !          1392:        };
        !          1393:        char *name;
        !          1394:        bool res = FALSE;
        !          1395: 
        !          1396:        this->mutex->lock(this->mutex);
        !          1397:        route = this->routes->get(this->routes, &key);
        !          1398:        if (route)
        !          1399:        {
        !          1400:                if (--route->refs == 0)
        !          1401:                {
        !          1402:                        if (charon->kernel->get_interface(charon->kernel, src, &name))
        !          1403:                        {
        !          1404:                                res = charon->kernel->del_route(charon->kernel,
        !          1405:                                                                                dst->get_address(dst), mask, gtw, src,
        !          1406:                                                                                name, FALSE) == SUCCESS;
        !          1407:                                free(name);
        !          1408:                        }
        !          1409:                        route = this->routes->remove(this->routes, route);
        !          1410:                        if (route)
        !          1411:                        {
        !          1412:                                destroy_route(route);
        !          1413:                        }
        !          1414:                }
        !          1415:                else
        !          1416:                {
        !          1417:                        res = TRUE;
        !          1418:                }
        !          1419:        }
        !          1420:        this->mutex->unlock(this->mutex);
        !          1421: 
        !          1422:        return res;
        !          1423: }
        !          1424: 
        !          1425: /**
        !          1426:  * Install a single route, or refcount if exists
        !          1427:  */
        !          1428: static bool install_route(private_kernel_wfp_ipsec_t *this,
        !          1429:                                                  host_t *dst, uint8_t mask, host_t *src, host_t *gtw)
        !          1430: {
        !          1431:        route_t *route, key = {
        !          1432:                .dst = dst,
        !          1433:                .mask = mask,
        !          1434:                .src = src,
        !          1435:        };
        !          1436:        char *name;
        !          1437:        bool res = FALSE;
        !          1438: 
        !          1439:        this->mutex->lock(this->mutex);
        !          1440:        route = this->routes->get(this->routes, &key);
        !          1441:        if (route)
        !          1442:        {
        !          1443:                route->refs++;
        !          1444:                res = TRUE;
        !          1445:        }
        !          1446:        else
        !          1447:        {
        !          1448:                if (charon->kernel->get_interface(charon->kernel, src, &name))
        !          1449:                {
        !          1450:                        if (charon->kernel->add_route(charon->kernel, dst->get_address(dst),
        !          1451:                                                                                mask, gtw, src, name, FALSE) == SUCCESS)
        !          1452:                        {
        !          1453:                                INIT(route,
        !          1454:                                        .dst = dst->clone(dst),
        !          1455:                                        .mask = mask,
        !          1456:                                        .src = src->clone(src),
        !          1457:                                        .gtw = gtw ? gtw->clone(gtw) : NULL,
        !          1458:                                        .refs = 1,
        !          1459:                                );
        !          1460:                                route = this->routes->put(this->routes, route, route);
        !          1461:                                if (route)
        !          1462:                                {
        !          1463:                                        destroy_route(route);
        !          1464:                                }
        !          1465:                                res = TRUE;
        !          1466:                        }
        !          1467:                        free(name);
        !          1468:                }
        !          1469:        }
        !          1470:        this->mutex->unlock(this->mutex);
        !          1471: 
        !          1472:        return res;
        !          1473: }
        !          1474: 
        !          1475: /**
        !          1476:  * (Un)-install a single route
        !          1477:  */
        !          1478: static bool manage_route(private_kernel_wfp_ipsec_t *this,
        !          1479:                                                 host_t *local, host_t *remote,
        !          1480:                                                 traffic_selector_t *src_ts, traffic_selector_t *dst_ts,
        !          1481:                                                 bool add)
        !          1482: {
        !          1483:        host_t *src, *dst, *gtw;
        !          1484:        uint8_t mask;
        !          1485:        bool done;
        !          1486: 
        !          1487:        if (!dst_ts->to_subnet(dst_ts, &dst, &mask))
        !          1488:        {
        !          1489:                return FALSE;
        !          1490:        }
        !          1491:        if (charon->kernel->get_address_by_ts(charon->kernel, src_ts, &src,
        !          1492:                                                                                  NULL) != SUCCESS)
        !          1493:        {
        !          1494:                dst->destroy(dst);
        !          1495:                return FALSE;
        !          1496:        }
        !          1497:        gtw = charon->kernel->get_nexthop(charon->kernel, remote, -1, local, NULL);
        !          1498:        if (add)
        !          1499:        {
        !          1500:                done = install_route(this, dst, mask, src, gtw);
        !          1501:        }
        !          1502:        else
        !          1503:        {
        !          1504:                done = uninstall_route(this, dst, mask, src, gtw);
        !          1505:        }
        !          1506:        dst->destroy(dst);
        !          1507:        src->destroy(src);
        !          1508:        DESTROY_IF(gtw);
        !          1509: 
        !          1510:        if (!done)
        !          1511:        {
        !          1512:                DBG1(DBG_KNL, "%sinstalling route for policy %R === %R failed",
        !          1513:                         add ? "" : "un", src_ts, dst_ts);
        !          1514:        }
        !          1515:        return done;
        !          1516: }
        !          1517: 
        !          1518: /**
        !          1519:  * (Un)-install routes for IPsec policies
        !          1520:  */
        !          1521: static bool manage_routes(private_kernel_wfp_ipsec_t *this, entry_t *entry,
        !          1522:                                                  bool add)
        !          1523: {
        !          1524:        enumerator_t *enumerator;
        !          1525:        sp_entry_t *sp;
        !          1526: 
        !          1527:        enumerator = array_create_enumerator(entry->sps);
        !          1528:        while (enumerator->enumerate(enumerator, &sp))
        !          1529:        {
        !          1530:                if (add && sp->route)
        !          1531:                {
        !          1532:                        continue;
        !          1533:                }
        !          1534:                if (!add && !sp->route)
        !          1535:                {
        !          1536:                        continue;
        !          1537:                }
        !          1538:                if (manage_route(this, entry->local, entry->remote,
        !          1539:                                                 sp->src, sp->dst, add))
        !          1540:                {
        !          1541:                        sp->route = add;
        !          1542:                }
        !          1543:        }
        !          1544:        enumerator->destroy(enumerator);
        !          1545: 
        !          1546:        return TRUE;
        !          1547: }
        !          1548: 
        !          1549: /**
        !          1550:  * Install a tunnel mode SA/SP set to the kernel
        !          1551:  */
        !          1552: static bool install_tunnel(private_kernel_wfp_ipsec_t *this, entry_t *entry)
        !          1553: {
        !          1554:        if (install_tunnel_sps(this, entry) &&
        !          1555:                manage_routes(this, entry, TRUE) &&
        !          1556:                install_sas(this, entry, IPSEC_TRAFFIC_TYPE_TUNNEL))
        !          1557:        {
        !          1558:                return TRUE;
        !          1559:        }
        !          1560:        cleanup_policies(this, entry);
        !          1561:        return FALSE;
        !          1562: }
        !          1563: 
        !          1564: /**
        !          1565:  * Install a SA/SP set to the kernel
        !          1566:  */
        !          1567: static bool install(private_kernel_wfp_ipsec_t *this, entry_t *entry)
        !          1568: {
        !          1569:        switch (entry->mode)
        !          1570:        {
        !          1571:                case MODE_TRANSPORT:
        !          1572:                        return install_transport(this, entry);
        !          1573:                case MODE_TUNNEL:
        !          1574:                        return install_tunnel(this, entry);
        !          1575:                case MODE_BEET:
        !          1576:                default:
        !          1577:                        return FALSE;
        !          1578:        }
        !          1579: }
        !          1580: 
        !          1581: /**
        !          1582:  * Installed trap entry
        !          1583:  */
        !          1584: typedef struct {
        !          1585:        /** reqid this trap is installed for */
        !          1586:        uint32_t reqid;
        !          1587:        /** is this a forward policy trap for tunnel mode? */
        !          1588:        bool fwd;
        !          1589:        /** do we have installed a route for this trap policy? */
        !          1590:        bool route;
        !          1591:        /** local address of associated route */
        !          1592:        host_t *local;
        !          1593:        /** remote address of associated route */
        !          1594:        host_t *remote;
        !          1595:        /** src traffic selector */
        !          1596:        traffic_selector_t *src;
        !          1597:        /** dst traffic selector */
        !          1598:        traffic_selector_t *dst;
        !          1599:        /** LUID of installed tunnel policy filter */
        !          1600:        UINT64 filter_id;
        !          1601: } trap_t;
        !          1602: 
        !          1603: /**
        !          1604:  * Destroy a trap entry
        !          1605:  */
        !          1606: static void destroy_trap(trap_t *this)
        !          1607: {
        !          1608:        this->local->destroy(this->local);
        !          1609:        this->remote->destroy(this->remote);
        !          1610:        this->src->destroy(this->src);
        !          1611:        this->dst->destroy(this->dst);
        !          1612:        free(this);
        !          1613: }
        !          1614: 
        !          1615: /**
        !          1616:  * Hashtable equals function for traps
        !          1617:  */
        !          1618: static bool equals_trap(trap_t *a, trap_t *b)
        !          1619: {
        !          1620:        return a->filter_id == b->filter_id;
        !          1621: }
        !          1622: 
        !          1623: /**
        !          1624:  * Hashtable hash function for traps
        !          1625:  */
        !          1626: static u_int hash_trap(trap_t *trap)
        !          1627: {
        !          1628:        return chunk_hash(chunk_from_thing(trap->filter_id));
        !          1629: }
        !          1630: 
        !          1631: /**
        !          1632:  * Send an acquire for an installed trap filter
        !          1633:  */
        !          1634: static void acquire(private_kernel_wfp_ipsec_t *this, UINT64 filter_id,
        !          1635:                                        traffic_selector_t *src, traffic_selector_t *dst)
        !          1636: {
        !          1637:        uint32_t reqid = 0;
        !          1638:        trap_t *trap, key = {
        !          1639:                .filter_id = filter_id,
        !          1640:        };
        !          1641: 
        !          1642:        this->mutex->lock(this->mutex);
        !          1643:        trap = this->traps->get(this->traps, &key);
        !          1644:        if (trap)
        !          1645:        {
        !          1646:                reqid = trap->reqid;
        !          1647:        }
        !          1648:        this->mutex->unlock(this->mutex);
        !          1649: 
        !          1650:        if (reqid)
        !          1651:        {
        !          1652:                src = src ? src->clone(src) : NULL;
        !          1653:                dst = dst ? dst->clone(dst) : NULL;
        !          1654:                charon->kernel->acquire(charon->kernel, reqid, src, dst);
        !          1655:        }
        !          1656: }
        !          1657: 
        !          1658: /**
        !          1659:  * Create a single host traffic selector from an FWP address definition
        !          1660:  */
        !          1661: static traffic_selector_t *addr2ts(FWP_IP_VERSION version, void *data,
        !          1662:                                        uint8_t protocol, uint16_t from_port, uint16_t to_port)
        !          1663: {
        !          1664:        ts_type_t type;
        !          1665:        UINT32 ints[4];
        !          1666:        chunk_t addr;
        !          1667: 
        !          1668:        switch (version)
        !          1669:        {
        !          1670:                case FWP_IP_VERSION_V4:
        !          1671:                        ints[0] = untoh32(data);
        !          1672:                        addr = chunk_from_thing(ints[0]);
        !          1673:                        type = TS_IPV4_ADDR_RANGE;
        !          1674:                        break;
        !          1675:                case FWP_IP_VERSION_V6:
        !          1676:                        ints[3] = untoh32(data);
        !          1677:                        ints[2] = untoh32(data + 4);
        !          1678:                        ints[1] = untoh32(data + 8);
        !          1679:                        ints[0] = untoh32(data + 12);
        !          1680:                        addr = chunk_from_thing(ints);
        !          1681:                        type = TS_IPV6_ADDR_RANGE;
        !          1682:                        break;
        !          1683:                default:
        !          1684:                        return NULL;
        !          1685:        }
        !          1686:        return traffic_selector_create_from_bytes(protocol, type, addr, from_port,
        !          1687:                                                                                          addr, to_port);
        !          1688: }
        !          1689: 
        !          1690: /**
        !          1691:  * FwpmNetEventSubscribe0() callback
        !          1692:  */
        !          1693: static void WINAPI event_callback(void *user, const FWPM_NET_EVENT1 *event)
        !          1694: {
        !          1695:        private_kernel_wfp_ipsec_t *this = user;
        !          1696:        traffic_selector_t *local = NULL, *remote = NULL;
        !          1697:        uint8_t protocol = 0;
        !          1698:        uint16_t from_local = 0, to_local = 65535;
        !          1699:        uint16_t from_remote = 0, to_remote = 65535;
        !          1700: 
        !          1701:        if ((event->header.flags & FWPM_NET_EVENT_FLAG_LOCAL_ADDR_SET) &&
        !          1702:                (event->header.flags & FWPM_NET_EVENT_FLAG_REMOTE_ADDR_SET))
        !          1703:        {
        !          1704:                if (event->header.flags & FWPM_NET_EVENT_FLAG_LOCAL_PORT_SET)
        !          1705:                {
        !          1706:                        from_local = to_local = event->header.localPort;
        !          1707:                }
        !          1708:                if (event->header.flags & FWPM_NET_EVENT_FLAG_LOCAL_PORT_SET)
        !          1709:                {
        !          1710:                        from_remote = to_remote = event->header.remotePort;
        !          1711:                }
        !          1712:                if (event->header.flags & FWPM_NET_EVENT_FLAG_IP_PROTOCOL_SET)
        !          1713:                {
        !          1714:                        protocol = event->header.ipProtocol;
        !          1715:                }
        !          1716: 
        !          1717:                local = addr2ts(event->header.ipVersion,
        !          1718:                                                (void*)&event->header.localAddrV6,
        !          1719:                                                protocol, from_local, to_local);
        !          1720:                remote = addr2ts(event->header.ipVersion,
        !          1721:                                                (void*)&event->header.remoteAddrV6,
        !          1722:                                                protocol, from_remote, to_remote);
        !          1723:        }
        !          1724: 
        !          1725:        switch (event->type)
        !          1726:        {
        !          1727:                case FWPM_NET_EVENT_TYPE_CLASSIFY_DROP:
        !          1728:                        acquire(this, event->classifyDrop->filterId, local, remote);
        !          1729:                        break;
        !          1730:                case FWPM_NET_EVENT_TYPE_IKEEXT_MM_FAILURE:
        !          1731:                        DBG1(DBG_KNL, "WFP MM failure: %R === %R, 0x%08x, filterId %llu",
        !          1732:                                 local, remote, event->ikeMmFailure->failureErrorCode,
        !          1733:                                 event->ikeMmFailure->mmFilterId);
        !          1734:                        break;
        !          1735:                case FWPM_NET_EVENT_TYPE_IKEEXT_QM_FAILURE:
        !          1736:                        DBG1(DBG_KNL, "WFP QM failure: %R === %R, 0x%08x, filterId %llu",
        !          1737:                                 local, remote, event->ikeQmFailure->failureErrorCode,
        !          1738:                                 event->ikeQmFailure->qmFilterId);
        !          1739:                        break;
        !          1740:                case FWPM_NET_EVENT_TYPE_IKEEXT_EM_FAILURE:
        !          1741:                        DBG1(DBG_KNL, "WFP EM failure: %R === %R, 0x%08x, filterId %llu",
        !          1742:                                 local, remote, event->ikeEmFailure->failureErrorCode,
        !          1743:                                 event->ikeEmFailure->qmFilterId);
        !          1744:                        break;
        !          1745:                case FWPM_NET_EVENT_TYPE_IPSEC_KERNEL_DROP:
        !          1746:                        DBG1(DBG_KNL, "IPsec kernel drop: %R === %R, error 0x%08x, "
        !          1747:                                 "SPI 0x%08x, %s filterId %llu", local, remote,
        !          1748:                                 event->ipsecDrop->failureStatus, event->ipsecDrop->spi,
        !          1749:                                 event->ipsecDrop->direction ? "in" : "out",
        !          1750:                                 event->ipsecDrop->filterId);
        !          1751:                        break;
        !          1752:                case FWPM_NET_EVENT_TYPE_IPSEC_DOSP_DROP:
        !          1753:                default:
        !          1754:                        break;
        !          1755:        }
        !          1756: 
        !          1757:        DESTROY_IF(local);
        !          1758:        DESTROY_IF(remote);
        !          1759: }
        !          1760: 
        !          1761: /**
        !          1762:  * Register for net events
        !          1763:  */
        !          1764: static bool register_events(private_kernel_wfp_ipsec_t *this)
        !          1765: {
        !          1766:        FWPM_NET_EVENT_SUBSCRIPTION0 subscription = {};
        !          1767:        DWORD res;
        !          1768: 
        !          1769:        res = FwpmNetEventSubscribe0(this->handle, &subscription,
        !          1770:                                                                 event_callback, this, &this->event);
        !          1771:        if (res != ERROR_SUCCESS)
        !          1772:        {
        !          1773:                DBG1(DBG_KNL, "registering for WFP events failed: 0x%08x", res);
        !          1774:                return FALSE;
        !          1775:        }
        !          1776:        return TRUE;
        !          1777: }
        !          1778: 
        !          1779: /**
        !          1780:  * Install a trap policy to kernel
        !          1781:  */
        !          1782: static bool install_trap(private_kernel_wfp_ipsec_t *this, trap_t *trap)
        !          1783: {
        !          1784:        FWPM_FILTER_CONDITION0 *conds = NULL;
        !          1785:        int count = 0;
        !          1786:        DWORD res;
        !          1787:        const GUID *starget, *dtarget;
        !          1788:        UINT64 weight = 0x000000000000ff00;
        !          1789:        FWPM_FILTER0 filter = {
        !          1790:                .displayData = {
        !          1791:                        .name = L"charon IPsec trap",
        !          1792:                },
        !          1793:                .action = {
        !          1794:                        .type = FWP_ACTION_BLOCK,
        !          1795:                },
        !          1796:                .weight = {
        !          1797:                        .type = FWP_UINT64,
        !          1798:                        .uint64 = &weight,
        !          1799:                },
        !          1800:        };
        !          1801: 
        !          1802:        if (trap->fwd)
        !          1803:        {
        !          1804:                if (trap->src->get_type(trap->src) == TS_IPV4_ADDR_RANGE)
        !          1805:                {
        !          1806:                        filter.layerKey = FWPM_LAYER_IPFORWARD_V4;
        !          1807:                }
        !          1808:                else
        !          1809:                {
        !          1810:                        filter.layerKey = FWPM_LAYER_IPFORWARD_V6;
        !          1811:                }
        !          1812:                starget = &FWPM_CONDITION_IP_SOURCE_ADDRESS;
        !          1813:                dtarget = &FWPM_CONDITION_IP_DESTINATION_ADDRESS;
        !          1814:        }
        !          1815:        else
        !          1816:        {
        !          1817:                if (trap->src->get_type(trap->src) == TS_IPV4_ADDR_RANGE)
        !          1818:                {
        !          1819:                        filter.layerKey = FWPM_LAYER_OUTBOUND_TRANSPORT_V4;
        !          1820:                }
        !          1821:                else
        !          1822:                {
        !          1823:                        filter.layerKey = FWPM_LAYER_OUTBOUND_TRANSPORT_V6;
        !          1824:                }
        !          1825:                starget = &FWPM_CONDITION_IP_LOCAL_ADDRESS;
        !          1826:                dtarget = &FWPM_CONDITION_IP_REMOTE_ADDRESS;
        !          1827:        }
        !          1828: 
        !          1829:        if (!ts2condition(trap->src, starget, &conds, &count) ||
        !          1830:                !ts2condition(trap->dst, dtarget, &conds, &count))
        !          1831:        {
        !          1832:                free_conditions(conds, count);
        !          1833:                return FALSE;
        !          1834:        }
        !          1835: 
        !          1836:        filter.numFilterConditions = count;
        !          1837:        filter.filterCondition = conds;
        !          1838: 
        !          1839:        res = FwpmFilterAdd0(this->handle, &filter, NULL, &trap->filter_id);
        !          1840:        free_conditions(conds, count);
        !          1841:        if (res != ERROR_SUCCESS)
        !          1842:        {
        !          1843:                DBG1(DBG_KNL, "installing WFP trap filter failed: 0x%08x", res);
        !          1844:                return FALSE;
        !          1845:        }
        !          1846:        return TRUE;
        !          1847: }
        !          1848: 
        !          1849: /**
        !          1850:  * Uninstall a trap policy from kernel
        !          1851:  */
        !          1852: static bool uninstall_trap(private_kernel_wfp_ipsec_t *this, trap_t *trap)
        !          1853: {
        !          1854:        DWORD res;
        !          1855: 
        !          1856:        res = FwpmFilterDeleteById0(this->handle, trap->filter_id);
        !          1857:        if (res != ERROR_SUCCESS)
        !          1858:        {
        !          1859:                DBG1(DBG_KNL, "uninstalling WFP trap filter failed: 0x%08x", res);
        !          1860:                return FALSE;
        !          1861:        }
        !          1862:        return TRUE;
        !          1863: }
        !          1864: 
        !          1865: /**
        !          1866:  * Create and install a new trap entry
        !          1867:  */
        !          1868: static bool add_trap(private_kernel_wfp_ipsec_t *this,
        !          1869:                                         uint32_t reqid, bool fwd, host_t *local, host_t *remote,
        !          1870:                                         traffic_selector_t *src, traffic_selector_t *dst)
        !          1871: {
        !          1872:        trap_t *trap;
        !          1873: 
        !          1874:        INIT(trap,
        !          1875:                .reqid = reqid,
        !          1876:                .fwd = fwd,
        !          1877:                .src = src->clone(src),
        !          1878:                .dst = dst->clone(dst),
        !          1879:                .local = local->clone(local),
        !          1880:                .remote = remote->clone(remote),
        !          1881:        );
        !          1882: 
        !          1883:        if (!install_trap(this, trap))
        !          1884:        {
        !          1885:                destroy_trap(trap);
        !          1886:                return FALSE;
        !          1887:        }
        !          1888: 
        !          1889:        trap->route = manage_route(this, local, remote, src, dst, TRUE);
        !          1890: 
        !          1891:        this->mutex->lock(this->mutex);
        !          1892:        this->traps->put(this->traps, trap, trap);
        !          1893:        this->mutex->unlock(this->mutex);
        !          1894:        return TRUE;
        !          1895: }
        !          1896: 
        !          1897: /**
        !          1898:  * Uninstall and remove a new trap entry
        !          1899:  */
        !          1900: static bool remove_trap(private_kernel_wfp_ipsec_t *this,
        !          1901:                                                uint32_t reqid, bool fwd,
        !          1902:                                                traffic_selector_t *src, traffic_selector_t *dst)
        !          1903: {
        !          1904:        enumerator_t *enumerator;
        !          1905:        trap_t *trap, *found = NULL;
        !          1906: 
        !          1907:        this->mutex->lock(this->mutex);
        !          1908:        enumerator = this->traps->create_enumerator(this->traps);
        !          1909:        while (enumerator->enumerate(enumerator, NULL, &trap))
        !          1910:        {
        !          1911:                if (reqid == trap->reqid &&
        !          1912:                        fwd == trap->fwd &&
        !          1913:                        src->equals(src, trap->src) &&
        !          1914:                        dst->equals(dst, trap->dst))
        !          1915:                {
        !          1916:                        this->traps->remove_at(this->traps, enumerator);
        !          1917:                        found = trap;
        !          1918:                        break;
        !          1919:                }
        !          1920:        }
        !          1921:        enumerator->destroy(enumerator);
        !          1922:        this->mutex->unlock(this->mutex);
        !          1923: 
        !          1924:        if (found)
        !          1925:        {
        !          1926:                if (trap->route)
        !          1927:                {
        !          1928:                        trap->route = !manage_route(this, trap->local, trap->remote,
        !          1929:                                                                                src, dst, FALSE);
        !          1930:                }
        !          1931:                uninstall_trap(this, found);
        !          1932:                destroy_trap(found);
        !          1933:                return TRUE;
        !          1934:        }
        !          1935:        return FALSE;
        !          1936: }
        !          1937: 
        !          1938: METHOD(kernel_ipsec_t, get_features, kernel_feature_t,
        !          1939:        private_kernel_wfp_ipsec_t *this)
        !          1940: {
        !          1941:        return KERNEL_ESP_V3_TFC | KERNEL_NO_POLICY_UPDATES;
        !          1942: }
        !          1943: 
        !          1944: /**
        !          1945:  * Initialize seeds for SPI generation
        !          1946:  */
        !          1947: static bool init_spi(private_kernel_wfp_ipsec_t *this)
        !          1948: {
        !          1949:        bool ok = TRUE;
        !          1950:        rng_t *rng;
        !          1951: 
        !          1952:        rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG);
        !          1953:        if (!rng)
        !          1954:        {
        !          1955:                return FALSE;
        !          1956:        }
        !          1957:        ok = rng->get_bytes(rng, sizeof(this->nextspi), (uint8_t*)&this->nextspi);
        !          1958:        if (ok)
        !          1959:        {
        !          1960:                ok = rng->get_bytes(rng, sizeof(this->mixspi), (uint8_t*)&this->mixspi);
        !          1961:        }
        !          1962:        rng->destroy(rng);
        !          1963:        return ok;
        !          1964: }
        !          1965: 
        !          1966: /**
        !          1967:  * Map an integer x with a one-to-one function using quadratic residues.
        !          1968:  */
        !          1969: static u_int permute(u_int x, u_int p)
        !          1970: {
        !          1971:        u_int qr;
        !          1972: 
        !          1973:        x = x % p;
        !          1974:        qr = ((uint64_t)x * x) % p;
        !          1975:        if (x <= p / 2)
        !          1976:        {
        !          1977:                return qr;
        !          1978:        }
        !          1979:        return p - qr;
        !          1980: }
        !          1981: 
        !          1982: METHOD(kernel_ipsec_t, get_spi, status_t,
        !          1983:        private_kernel_wfp_ipsec_t *this, host_t *src, host_t *dst,
        !          1984:        uint8_t protocol, uint32_t *spi)
        !          1985: {
        !          1986:        /* To avoid sequential SPIs, we use a one-to-one permutation function on
        !          1987:         * an incrementing counter, that is a full period PRNG for the range we
        !          1988:         * allocate SPIs in. We add some randomness using a fixed XOR and start
        !          1989:         * the counter at random position. This is not cryptographically safe,
        !          1990:         * but that is actually not required.
        !          1991:         * The selected prime should be smaller than the range we allocate SPIs
        !          1992:         * in, and it must satisfy p % 4 == 3 to map x > p/2 using p - qr. */
        !          1993:        static const u_int p = 268435399, offset = 0xc0000000;
        !          1994: 
        !          1995:        *spi = htonl(offset + permute(ref_get(&this->nextspi) ^ this->mixspi, p));
        !          1996:        return SUCCESS;
        !          1997: }
        !          1998: 
        !          1999: METHOD(kernel_ipsec_t, get_cpi, status_t,
        !          2000:        private_kernel_wfp_ipsec_t *this, host_t *src, host_t *dst,
        !          2001:        uint16_t *cpi)
        !          2002: {
        !          2003:        return NOT_SUPPORTED;
        !          2004: }
        !          2005: 
        !          2006: /**
        !          2007:  * Data for an expire callback job
        !          2008:  */
        !          2009: typedef struct {
        !          2010:        /* backref to kernel backend */
        !          2011:        private_kernel_wfp_ipsec_t *this;
        !          2012:        /* SPI of expiring SA */
        !          2013:        uint32_t spi;
        !          2014:        /* destination address of expiring SA */
        !          2015:        host_t *dst;
        !          2016:        /* is this a hard expire, or a rekey request? */
        !          2017:        bool hard;
        !          2018: } expire_data_t;
        !          2019: 
        !          2020: /**
        !          2021:  * Clean up expire data
        !          2022:  */
        !          2023: static void expire_data_destroy(expire_data_t *data)
        !          2024: {
        !          2025:        data->dst->destroy(data->dst);
        !          2026:        free(data);
        !          2027: }
        !          2028: 
        !          2029: /**
        !          2030:  * Callback job for SA expiration
        !          2031:  */
        !          2032: static job_requeue_t expire_job(expire_data_t *data)
        !          2033: {
        !          2034:        private_kernel_wfp_ipsec_t *this = data->this;
        !          2035:        uint8_t protocol;
        !          2036:        entry_t *entry = NULL;
        !          2037:        sa_entry_t key = {
        !          2038:                .spi = data->spi,
        !          2039:                .dst = data->dst,
        !          2040:        };
        !          2041: 
        !          2042:        if (data->hard)
        !          2043:        {
        !          2044:                this->mutex->lock(this->mutex);
        !          2045:                entry = this->isas->remove(this->isas, &key);
        !          2046:                this->mutex->unlock(this->mutex);
        !          2047:                if (entry)
        !          2048:                {
        !          2049:                        protocol = entry->isa.protocol;
        !          2050:                        if (entry->osa.dst)
        !          2051:                        {
        !          2052:                                key.dst = entry->osa.dst;
        !          2053:                                key.spi = entry->osa.spi;
        !          2054:                                this->osas->remove(this->osas, &key);
        !          2055:                        }
        !          2056:                        entry_destroy(this, entry);
        !          2057:                }
        !          2058:        }
        !          2059:        else
        !          2060:        {
        !          2061:                this->mutex->lock(this->mutex);
        !          2062:                entry = this->isas->get(this->isas, &key);
        !          2063:                if (entry)
        !          2064:                {
        !          2065:                        protocol = entry->isa.protocol;
        !          2066:                }
        !          2067:                this->mutex->unlock(this->mutex);
        !          2068:        }
        !          2069: 
        !          2070:        if (entry)
        !          2071:        {
        !          2072:                charon->kernel->expire(charon->kernel, protocol, data->spi, data->dst,
        !          2073:                                                           data->hard);
        !          2074:        }
        !          2075: 
        !          2076:        return JOB_REQUEUE_NONE;
        !          2077: }
        !          2078: 
        !          2079: /**
        !          2080:  * Schedule an expire event for an SA
        !          2081:  */
        !          2082: static void schedule_expire(private_kernel_wfp_ipsec_t *this, uint32_t spi,
        !          2083:                                                        host_t *dst, uint32_t lifetime, bool hard)
        !          2084: {
        !          2085:        expire_data_t *data;
        !          2086: 
        !          2087:        INIT(data,
        !          2088:                .this = this,
        !          2089:                .spi = spi,
        !          2090:                .dst = dst->clone(dst),
        !          2091:                .hard = hard,
        !          2092:        );
        !          2093: 
        !          2094:        lib->scheduler->schedule_job(lib->scheduler, (job_t*)
        !          2095:                                                callback_job_create((void*)expire_job, data,
        !          2096:                                                                                        (void*)expire_data_destroy, NULL),
        !          2097:                                                lifetime);
        !          2098: }
        !          2099: 
        !          2100: METHOD(kernel_ipsec_t, add_sa, status_t,
        !          2101:        private_kernel_wfp_ipsec_t *this, kernel_ipsec_sa_id_t *id,
        !          2102:        kernel_ipsec_add_sa_t *data)
        !          2103: {
        !          2104:        host_t *local, *remote;
        !          2105:        entry_t *entry;
        !          2106: 
        !          2107:        if (data->inbound)
        !          2108:        {
        !          2109:                /* comes first, create new entry */
        !          2110:                local = id->dst->clone(id->dst);
        !          2111:                remote = id->src->clone(id->src);
        !          2112: 
        !          2113:                INIT(entry,
        !          2114:                        .reqid = data->reqid,
        !          2115:                        .isa = {
        !          2116:                                .spi = id->spi,
        !          2117:                                .dst = local,
        !          2118:                                .protocol = id->proto,
        !          2119:                                .lifetime = data->lifetime->time.life,
        !          2120:                                .encr = {
        !          2121:                                        .alg = data->enc_alg,
        !          2122:                                        .key = chunk_clone(data->enc_key),
        !          2123:                                },
        !          2124:                                .integ = {
        !          2125:                                        .alg = data->int_alg,
        !          2126:                                        .key = chunk_clone(data->int_key),
        !          2127:                                },
        !          2128:                        },
        !          2129:                        .sps = array_create(0, 0),
        !          2130:                        .local = local,
        !          2131:                        .remote = remote,
        !          2132:                        .mode = data->mode,
        !          2133:                        .encap = data->encap,
        !          2134:                );
        !          2135: 
        !          2136:                if (data->lifetime->time.life)
        !          2137:                {
        !          2138:                        schedule_expire(this, id->spi, local,
        !          2139:                                                        data->lifetime->time.life, TRUE);
        !          2140:                }
        !          2141:                if (data->lifetime->time.rekey &&
        !          2142:                        data->lifetime->time.rekey != data->lifetime->time.life)
        !          2143:                {
        !          2144:                        schedule_expire(this, id->spi, local,
        !          2145:                                                        data->lifetime->time.rekey, FALSE);
        !          2146:                }
        !          2147: 
        !          2148:                this->mutex->lock(this->mutex);
        !          2149:                this->tsas->put(this->tsas, (void*)(uintptr_t)data->reqid, entry);
        !          2150:                this->isas->put(this->isas, &entry->isa, entry);
        !          2151:                this->mutex->unlock(this->mutex);
        !          2152:        }
        !          2153:        else
        !          2154:        {
        !          2155:                /* comes after inbound, update entry */
        !          2156:                this->mutex->lock(this->mutex);
        !          2157:                entry = this->tsas->remove(this->tsas, (void*)(uintptr_t)data->reqid);
        !          2158:                this->mutex->unlock(this->mutex);
        !          2159: 
        !          2160:                if (!entry)
        !          2161:                {
        !          2162:                        DBG1(DBG_KNL, "adding outbound SA failed, no inbound SA found "
        !          2163:                                 "for reqid %u ", data->reqid);
        !          2164:                        return NOT_FOUND;
        !          2165:                }
        !          2166:                /* TODO: should we check for local/remote, mode etc.? */
        !          2167: 
        !          2168:                entry->osa = (sa_entry_t){
        !          2169:                        .spi = id->spi,
        !          2170:                        .dst = entry->remote,
        !          2171:                        .protocol = id->proto,
        !          2172:                        .lifetime = data->lifetime->time.life,
        !          2173:                        .encr = {
        !          2174:                                .alg = data->enc_alg,
        !          2175:                                .key = chunk_clone(data->enc_key),
        !          2176:                        },
        !          2177:                        .integ = {
        !          2178:                                .alg = data->int_alg,
        !          2179:                                .key = chunk_clone(data->int_key),
        !          2180:                        },
        !          2181:                };
        !          2182: 
        !          2183:                this->mutex->lock(this->mutex);
        !          2184:                this->osas->put(this->osas, &entry->osa, entry);
        !          2185:                this->mutex->unlock(this->mutex);
        !          2186:        }
        !          2187: 
        !          2188:        return SUCCESS;
        !          2189: }
        !          2190: 
        !          2191: METHOD(kernel_ipsec_t, update_sa, status_t,
        !          2192:        private_kernel_wfp_ipsec_t *this, kernel_ipsec_sa_id_t *id,
        !          2193:        kernel_ipsec_update_sa_t *data)
        !          2194: {
        !          2195:        entry_t *entry;
        !          2196:        sa_entry_t key = {
        !          2197:                .dst = id->dst,
        !          2198:                .spi = id->spi,
        !          2199:        };
        !          2200:        UINT64 sa_id = 0;
        !          2201:        IPSEC_SA_CONTEXT1 *ctx;
        !          2202:        IPSEC_V4_UDP_ENCAPSULATION0 ports;
        !          2203:        UINT32 flags = IPSEC_SA_DETAILS_UPDATE_TRAFFIC;
        !          2204:        DWORD res;
        !          2205: 
        !          2206:        this->mutex->lock(this->mutex);
        !          2207:        entry = this->osas->get(this->osas, &key);
        !          2208:        this->mutex->unlock(this->mutex);
        !          2209: 
        !          2210:        if (entry)
        !          2211:        {
        !          2212:                /* outbound entry, nothing to do */
        !          2213:                return SUCCESS;
        !          2214:        }
        !          2215: 
        !          2216:        this->mutex->lock(this->mutex);
        !          2217:        entry = this->isas->get(this->isas, &key);
        !          2218:        if (entry)
        !          2219:        {
        !          2220:                /* inbound entry, do update */
        !          2221:                sa_id = entry->sa_id;
        !          2222:                ports.localUdpEncapPort = entry->local->get_port(entry->local);
        !          2223:                ports.remoteUdpEncapPort = entry->remote->get_port(entry->remote);
        !          2224:        }
        !          2225:        this->mutex->unlock(this->mutex);
        !          2226: 
        !          2227:        if (!sa_id)
        !          2228:        {
        !          2229:                return NOT_FOUND;
        !          2230:        }
        !          2231: 
        !          2232:        res = IPsecSaContextGetById1(this->handle, sa_id, &ctx);
        !          2233:        if (res != ERROR_SUCCESS)
        !          2234:        {
        !          2235:                DBG1(DBG_KNL, "getting WFP SA context for updated failed: 0x%08x", res);
        !          2236:                return FAILED;
        !          2237:        }
        !          2238:        if (!hosts2traffic(this, data->new_dst, data->new_src, &ctx->inboundSa->traffic) ||
        !          2239:                !hosts2traffic(this, data->new_dst, data->new_src, &ctx->outboundSa->traffic))
        !          2240:        {
        !          2241:                FwpmFreeMemory0((void**)&ctx);
        !          2242:                return FAILED;
        !          2243:        }
        !          2244: 
        !          2245:        if (data->new_encap != data->encap)
        !          2246:        {
        !          2247:                if (data->new_encap)
        !          2248:                {
        !          2249:                        ctx->inboundSa->udpEncapsulation = &ports;
        !          2250:                        ctx->outboundSa->udpEncapsulation = &ports;
        !          2251:                }
        !          2252:                else
        !          2253:                {
        !          2254:                        ctx->inboundSa->udpEncapsulation = NULL;
        !          2255:                        ctx->outboundSa->udpEncapsulation = NULL;
        !          2256:                }
        !          2257:                flags |= IPSEC_SA_DETAILS_UPDATE_UDP_ENCAPSULATION;
        !          2258:        }
        !          2259: 
        !          2260:        res = IPsecSaContextUpdate0(this->handle, flags, ctx);
        !          2261:        FwpmFreeMemory0((void**)&ctx);
        !          2262:        if (res != ERROR_SUCCESS)
        !          2263:        {
        !          2264:                DBG1(DBG_KNL, "updating WFP SA context failed: 0x%08x", res);
        !          2265:                return FAILED;
        !          2266:        }
        !          2267: 
        !          2268:        this->mutex->lock(this->mutex);
        !          2269:        entry = this->isas->remove(this->isas, &key);
        !          2270:        if (entry)
        !          2271:        {
        !          2272:                key.spi = entry->osa.spi;
        !          2273:                key.dst = entry->osa.dst;
        !          2274:                this->osas->remove(this->osas, &key);
        !          2275: 
        !          2276:                entry->local->destroy(entry->local);
        !          2277:                entry->remote->destroy(entry->remote);
        !          2278:                entry->local = data->new_dst->clone(data->new_dst);
        !          2279:                entry->remote = data->new_src->clone(data->new_src);
        !          2280:                entry->isa.dst = entry->local;
        !          2281:                entry->osa.dst = entry->remote;
        !          2282: 
        !          2283:                this->isas->put(this->isas, &entry->isa, entry);
        !          2284:                this->osas->put(this->osas, &entry->osa, entry);
        !          2285: 
        !          2286:                manage_routes(this, entry, FALSE);
        !          2287:                manage_routes(this, entry, TRUE);
        !          2288:        }
        !          2289:        this->mutex->unlock(this->mutex);
        !          2290: 
        !          2291:        return SUCCESS;
        !          2292: }
        !          2293: 
        !          2294: METHOD(kernel_ipsec_t, query_sa, status_t,
        !          2295:        private_kernel_wfp_ipsec_t *this, kernel_ipsec_sa_id_t *id,
        !          2296:        kernel_ipsec_query_sa_t *data, uint64_t *bytes, uint64_t *packets,
        !          2297:        time_t *time)
        !          2298: {
        !          2299:        /* It does not seem that WFP provides any means of getting per-SA traffic
        !          2300:         * statistics. IPsecGetStatistics0/1() provides global stats, and
        !          2301:         * IPsecSaContextEnum0/1() and IPsecSaEnum0/1() return the configured
        !          2302:         * values only. */
        !          2303:        return NOT_SUPPORTED;
        !          2304: }
        !          2305: 
        !          2306: METHOD(kernel_ipsec_t, del_sa, status_t,
        !          2307:        private_kernel_wfp_ipsec_t *this, kernel_ipsec_sa_id_t *id,
        !          2308:        kernel_ipsec_del_sa_t *data)
        !          2309: {
        !          2310:        entry_t *entry;
        !          2311:        sa_entry_t key = {
        !          2312:                .dst = id->dst,
        !          2313:                .spi = id->spi,
        !          2314:        };
        !          2315: 
        !          2316:        this->mutex->lock(this->mutex);
        !          2317:        entry = this->isas->remove(this->isas, &key);
        !          2318:        this->mutex->unlock(this->mutex);
        !          2319: 
        !          2320:        if (entry)
        !          2321:        {
        !          2322:                /* keep entry until removal of outbound */
        !          2323:                return SUCCESS;
        !          2324:        }
        !          2325: 
        !          2326:        this->mutex->lock(this->mutex);
        !          2327:        entry = this->osas->remove(this->osas, &key);
        !          2328:        this->mutex->unlock(this->mutex);
        !          2329: 
        !          2330:        if (entry)
        !          2331:        {
        !          2332:                entry_destroy(this, entry);
        !          2333:                return SUCCESS;
        !          2334:        }
        !          2335: 
        !          2336:        return NOT_FOUND;
        !          2337: }
        !          2338: 
        !          2339: METHOD(kernel_ipsec_t, flush_sas, status_t,
        !          2340:        private_kernel_wfp_ipsec_t *this)
        !          2341: {
        !          2342:        return NOT_SUPPORTED;
        !          2343: }
        !          2344: 
        !          2345: METHOD(kernel_ipsec_t, add_policy, status_t,
        !          2346:        private_kernel_wfp_ipsec_t *this, kernel_ipsec_policy_id_t *id,
        !          2347:        kernel_ipsec_manage_policy_t *data)
        !          2348: {
        !          2349:        status_t status = SUCCESS;
        !          2350:        entry_t *entry;
        !          2351:        sp_entry_t *sp;
        !          2352:        sa_entry_t key = {
        !          2353:                .spi = data->sa->esp.use ? data->sa->esp.spi : data->sa->ah.spi,
        !          2354:                .dst = data->dst,
        !          2355:        };
        !          2356: 
        !          2357:        if (data->sa->esp.use && data->sa->ah.use)
        !          2358:        {
        !          2359:                return NOT_SUPPORTED;
        !          2360:        }
        !          2361: 
        !          2362:        switch (data->type)
        !          2363:        {
        !          2364:                case POLICY_IPSEC:
        !          2365:                        break;
        !          2366:                case POLICY_PASS:
        !          2367:                case POLICY_DROP:
        !          2368:                        return NOT_SUPPORTED;
        !          2369:        }
        !          2370: 
        !          2371:        switch (id->dir)
        !          2372:        {
        !          2373:                case POLICY_OUT:
        !          2374:                        break;
        !          2375:                case POLICY_IN:
        !          2376:                case POLICY_FWD:
        !          2377:                        /* not required */
        !          2378:                        return SUCCESS;
        !          2379:                default:
        !          2380:                        return NOT_SUPPORTED;
        !          2381:        }
        !          2382: 
        !          2383:        switch (data->prio)
        !          2384:        {
        !          2385:                case POLICY_PRIORITY_DEFAULT:
        !          2386:                        break;
        !          2387:                case POLICY_PRIORITY_ROUTED:
        !          2388:                        if (!add_trap(this, data->sa->reqid, FALSE, data->src, data->dst,
        !          2389:                                                  id->src_ts, id->dst_ts))
        !          2390:                        {
        !          2391:                                return FAILED;
        !          2392:                        }
        !          2393:                        if (data->sa->mode == MODE_TUNNEL)
        !          2394:                        {
        !          2395:                                if (!add_trap(this, data->sa->reqid, TRUE, data->src, data->dst,
        !          2396:                                                          id->src_ts, id->dst_ts))
        !          2397:                                {
        !          2398:                                        return FAILED;
        !          2399:                                }
        !          2400:                        }
        !          2401:                        return SUCCESS;
        !          2402:                case POLICY_PRIORITY_FALLBACK:
        !          2403:                default:
        !          2404:                        return NOT_SUPPORTED;
        !          2405:        }
        !          2406: 
        !          2407:        this->mutex->lock(this->mutex);
        !          2408:        entry = this->osas->get(this->osas, &key);
        !          2409:        if (entry)
        !          2410:        {
        !          2411:                if (data->sa->mode == MODE_TUNNEL || array_count(entry->sps) == 0)
        !          2412:                {
        !          2413:                        INIT(sp,
        !          2414:                                .src = id->src_ts->clone(id->src_ts),
        !          2415:                                .dst = id->dst_ts->clone(id->dst_ts),
        !          2416:                        );
        !          2417:                        array_insert(entry->sps, -1, sp);
        !          2418:                        if (array_count(entry->sps) == data->sa->policy_count)
        !          2419:                        {
        !          2420:                                if (!install(this, entry))
        !          2421:                                {
        !          2422:                                        status = FAILED;
        !          2423:                                }
        !          2424:                        }
        !          2425:                }
        !          2426:                else
        !          2427:                {
        !          2428:                        /* TODO: reinstall with a filter using multiple TS?
        !          2429:                         * Filters are ANDed for a match, but we could install a filter
        !          2430:                         * with the inverse TS set using NOT-matches... */
        !          2431:                        DBG1(DBG_KNL, "multiple transport mode traffic selectors not "
        !          2432:                                 "supported by WFP");
        !          2433:                        status = NOT_SUPPORTED;
        !          2434:                }
        !          2435:        }
        !          2436:        else
        !          2437:        {
        !          2438:                DBG1(DBG_KNL, "adding SP failed, no SA found for SPI 0x%08x", key.spi);
        !          2439:                status = FAILED;
        !          2440:        }
        !          2441:        this->mutex->unlock(this->mutex);
        !          2442: 
        !          2443:        return status;
        !          2444: }
        !          2445: 
        !          2446: METHOD(kernel_ipsec_t, query_policy, status_t,
        !          2447:        private_kernel_wfp_ipsec_t *this, kernel_ipsec_policy_id_t *id,
        !          2448:        kernel_ipsec_query_policy_t *data, time_t *use_time)
        !          2449: {
        !          2450:        /* see query_sa() for some notes */
        !          2451:        return NOT_SUPPORTED;
        !          2452: }
        !          2453: 
        !          2454: METHOD(kernel_ipsec_t, del_policy, status_t,
        !          2455:        private_kernel_wfp_ipsec_t *this, kernel_ipsec_policy_id_t *id,
        !          2456:        kernel_ipsec_manage_policy_t *data)
        !          2457: {
        !          2458:        if (id->dir == POLICY_OUT && data->prio == POLICY_PRIORITY_ROUTED)
        !          2459:        {
        !          2460:                if (remove_trap(this, data->sa->reqid, FALSE, id->src_ts,
        !          2461:                                                id->dst_ts))
        !          2462:                {
        !          2463:                        remove_trap(this, data->sa->reqid, TRUE, id->src_ts,
        !          2464:                                                id->dst_ts);
        !          2465:                        return SUCCESS;
        !          2466:                }
        !          2467:                return NOT_FOUND;
        !          2468:        }
        !          2469:        /* not required, as we delete the whole SA/SP set during del_sa() */
        !          2470:        return SUCCESS;
        !          2471: }
        !          2472: 
        !          2473: METHOD(kernel_ipsec_t, flush_policies, status_t,
        !          2474:        private_kernel_wfp_ipsec_t *this)
        !          2475: {
        !          2476:        return NOT_SUPPORTED;
        !          2477: }
        !          2478: 
        !          2479: /**
        !          2480:  * Add a bypass policy for a specific UDP port
        !          2481:  */
        !          2482: static bool add_bypass(private_kernel_wfp_ipsec_t *this,
        !          2483:                                           int family, uint16_t port, bool inbound, UINT64 *luid)
        !          2484: {
        !          2485:        FWPM_FILTER_CONDITION0 *cond, *conds = NULL;
        !          2486:        int count = 0;
        !          2487:        DWORD res;
        !          2488:        UINT64 weight = 0xff00000000000000;
        !          2489:        FWPM_FILTER0 filter = {
        !          2490:                .displayData = {
        !          2491:                        .name = L"charon IKE bypass",
        !          2492:                },
        !          2493:                .action = {
        !          2494:                        .type = FWP_ACTION_PERMIT,
        !          2495:                },
        !          2496:                .weight = {
        !          2497:                        .type = FWP_UINT64,
        !          2498:                        .uint64 = &weight,
        !          2499:                },
        !          2500:        };
        !          2501: 
        !          2502:        switch (family)
        !          2503:        {
        !          2504:                case AF_INET:
        !          2505:                        filter.layerKey = inbound ? FWPM_LAYER_INBOUND_TRANSPORT_V4
        !          2506:                                                                          : FWPM_LAYER_OUTBOUND_TRANSPORT_V4;
        !          2507:                        break;
        !          2508:                case AF_INET6:
        !          2509:                        filter.layerKey = inbound ? FWPM_LAYER_INBOUND_TRANSPORT_V6
        !          2510:                                                                          : FWPM_LAYER_OUTBOUND_TRANSPORT_V6;
        !          2511:                        break;
        !          2512:                default:
        !          2513:                        return FALSE;
        !          2514:        }
        !          2515: 
        !          2516:        cond = append_condition(&conds, &count);
        !          2517:        cond->fieldKey = FWPM_CONDITION_IP_PROTOCOL;
        !          2518:        cond->matchType = FWP_MATCH_EQUAL;
        !          2519:        cond->conditionValue.type = FWP_UINT8;
        !          2520:        cond->conditionValue.uint8 = IPPROTO_UDP;
        !          2521: 
        !          2522:        cond = append_condition(&conds, &count);
        !          2523:        cond->fieldKey = FWPM_CONDITION_IP_LOCAL_PORT;
        !          2524:        cond->matchType = FWP_MATCH_EQUAL;
        !          2525:        cond->conditionValue.type = FWP_UINT16;
        !          2526:        cond->conditionValue.uint16 = port;
        !          2527: 
        !          2528:        filter.numFilterConditions = count;
        !          2529:        filter.filterCondition = conds;
        !          2530: 
        !          2531:        res = FwpmFilterAdd0(this->handle, &filter, NULL, luid);
        !          2532:        free_conditions(conds, count);
        !          2533:        if (res != ERROR_SUCCESS)
        !          2534:        {
        !          2535:                DBG1(DBG_KNL, "installing WFP bypass filter failed: 0x%08x", res);
        !          2536:                return FALSE;
        !          2537:        }
        !          2538:        return TRUE;
        !          2539: }
        !          2540: 
        !          2541: METHOD(kernel_ipsec_t, bypass_socket, bool,
        !          2542:        private_kernel_wfp_ipsec_t *this, int fd, int family)
        !          2543: {
        !          2544:        union {
        !          2545:                struct sockaddr sa;
        !          2546:                SOCKADDR_IN in;
        !          2547:                SOCKADDR_IN6 in6;
        !          2548:        } saddr;
        !          2549:        int addrlen = sizeof(saddr);
        !          2550:        UINT64 filter_out, filter_in = 0;
        !          2551:        uint16_t port;
        !          2552: 
        !          2553:        if (getsockname(fd, &saddr.sa, &addrlen) == SOCKET_ERROR)
        !          2554:        {
        !          2555:                return FALSE;
        !          2556:        }
        !          2557:        switch (family)
        !          2558:        {
        !          2559:                case AF_INET:
        !          2560:                        port = ntohs(saddr.in.sin_port);
        !          2561:                        break;
        !          2562:                case AF_INET6:
        !          2563:                        port = ntohs(saddr.in6.sin6_port);
        !          2564:                        break;
        !          2565:                default:
        !          2566:                        return FALSE;
        !          2567:        }
        !          2568: 
        !          2569:        if (!add_bypass(this, family, port, TRUE, &filter_in) ||
        !          2570:                !add_bypass(this, family, port, FALSE, &filter_out))
        !          2571:        {
        !          2572:                if (filter_in)
        !          2573:                {
        !          2574:                        FwpmFilterDeleteById0(this->handle, filter_in);
        !          2575:                }
        !          2576:                return FALSE;
        !          2577:        }
        !          2578: 
        !          2579:        this->mutex->lock(this->mutex);
        !          2580:        array_insert(this->bypass, ARRAY_TAIL, &filter_in);
        !          2581:        array_insert(this->bypass, ARRAY_TAIL, &filter_out);
        !          2582:        this->mutex->unlock(this->mutex);
        !          2583: 
        !          2584:        return TRUE;
        !          2585: }
        !          2586: 
        !          2587: METHOD(kernel_ipsec_t, enable_udp_decap, bool,
        !          2588:        private_kernel_wfp_ipsec_t *this, int fd, int family, uint16_t port)
        !          2589: {
        !          2590:        return FALSE;
        !          2591: }
        !          2592: 
        !          2593: METHOD(kernel_ipsec_t, destroy, void,
        !          2594:        private_kernel_wfp_ipsec_t *this)
        !          2595: {
        !          2596:        UINT64 filter;
        !          2597: 
        !          2598:        while (array_remove(this->bypass, ARRAY_TAIL, &filter))
        !          2599:        {
        !          2600:                FwpmFilterDeleteById0(this->handle, filter);
        !          2601:        }
        !          2602:        if (this->handle)
        !          2603:        {
        !          2604:                if (this->event)
        !          2605:                {
        !          2606:                        FwpmNetEventUnsubscribe0(this->handle, this->event);
        !          2607:                }
        !          2608:                FwpmProviderDeleteByKey0(this->handle, &this->provider.providerKey);
        !          2609:                FwpmEngineClose0(this->handle);
        !          2610:        }
        !          2611:        array_destroy(this->bypass);
        !          2612:        this->tsas->destroy(this->tsas);
        !          2613:        this->isas->destroy(this->isas);
        !          2614:        this->osas->destroy(this->osas);
        !          2615:        this->routes->destroy(this->routes);
        !          2616:        this->traps->destroy(this->traps);
        !          2617:        this->mutex->destroy(this->mutex);
        !          2618:        free(this);
        !          2619: }
        !          2620: 
        !          2621: /*
        !          2622:  * Described in header.
        !          2623:  */
        !          2624: kernel_wfp_ipsec_t *kernel_wfp_ipsec_create()
        !          2625: {
        !          2626:        private_kernel_wfp_ipsec_t *this;
        !          2627:        DWORD res;
        !          2628:        FWPM_SESSION0 session = {
        !          2629:                .displayData = {
        !          2630:                        .name = L"charon",
        !          2631:                        .description = L"strongSwan IKE kernel-wfp backend",
        !          2632:                },
        !          2633:        };
        !          2634: 
        !          2635:        INIT(this,
        !          2636:                .public = {
        !          2637:                        .interface = {
        !          2638:                                .get_features = _get_features,
        !          2639:                                .get_spi = _get_spi,
        !          2640:                                .get_cpi = _get_cpi,
        !          2641:                                .add_sa  = _add_sa,
        !          2642:                                .update_sa = _update_sa,
        !          2643:                                .query_sa = _query_sa,
        !          2644:                                .del_sa = _del_sa,
        !          2645:                                .flush_sas = _flush_sas,
        !          2646:                                .add_policy = _add_policy,
        !          2647:                                .query_policy = _query_policy,
        !          2648:                                .del_policy = _del_policy,
        !          2649:                                .flush_policies = _flush_policies,
        !          2650:                                .bypass_socket = _bypass_socket,
        !          2651:                                .enable_udp_decap = _enable_udp_decap,
        !          2652:                                .destroy = _destroy,
        !          2653:                        },
        !          2654:                },
        !          2655:                .provider = {
        !          2656:                        .displayData = {
        !          2657:                                .name = L"charon",
        !          2658:                                .description = L"strongSwan IKE kernel-wfp backend",
        !          2659:                        },
        !          2660:                        .providerKey = { 0x59cdae2e, 0xf6bb, 0x4c09,
        !          2661:                                                        { 0xa9,0x59,0x9d,0x91,0xac,0xaf,0xf9,0x19 }},
        !          2662:                },
        !          2663:                .mutex = mutex_create(MUTEX_TYPE_RECURSIVE),
        !          2664:                .bypass = array_create(sizeof(UINT64), 2),
        !          2665:                .tsas = hashtable_create(hashtable_hash_ptr, hashtable_equals_ptr, 4),
        !          2666:                .isas = hashtable_create((void*)hash_sa, (void*)equals_sa, 4),
        !          2667:                .osas = hashtable_create((void*)hash_sa, (void*)equals_sa, 4),
        !          2668:                .routes = hashtable_create((void*)hash_route, (void*)equals_route, 4),
        !          2669:                .traps = hashtable_create((void*)hash_trap, (void*)equals_trap, 4),
        !          2670:        );
        !          2671: 
        !          2672:        if (!init_spi(this))
        !          2673:        {
        !          2674:                destroy(this);
        !          2675:                return NULL;
        !          2676:        }
        !          2677: 
        !          2678:        res = FwpmEngineOpen0(NULL, RPC_C_AUTHN_WINNT, NULL, &session,
        !          2679:                                                  &this->handle);
        !          2680:        if (res != ERROR_SUCCESS)
        !          2681:        {
        !          2682:                DBG1(DBG_KNL, "opening WFP engine failed: 0x%08x", res);
        !          2683:                destroy(this);
        !          2684:                return NULL;
        !          2685:        }
        !          2686: 
        !          2687:        res = FwpmProviderAdd0(this->handle, &this->provider, NULL);
        !          2688:        if (res != ERROR_SUCCESS && res != FWP_E_ALREADY_EXISTS)
        !          2689:        {
        !          2690:                DBG1(DBG_KNL, "registering WFP provider failed: 0x%08x", res);
        !          2691:                destroy(this);
        !          2692:                return NULL;
        !          2693:        }
        !          2694: 
        !          2695:        if (!register_events(this))
        !          2696:        {
        !          2697:                destroy(this);
        !          2698:                return NULL;
        !          2699:        }
        !          2700: 
        !          2701:        return &this->public;
        !          2702: }

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