Annotation of embedaddon/strongswan/src/libcharon/plugins/kernel_wfp/kernel_wfp_ipsec.c, revision 1.1.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>