Annotation of embedaddon/strongswan/src/libcharon/plugins/kernel_libipsec/kernel_libipsec_ipsec.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * Copyright (C) 2012-2013 Tobias Brunner
                      3:  * HSR Hochschule fuer Technik Rapperswil
                      4:  *
                      5:  * This program is free software; you can redistribute it and/or modify it
                      6:  * under the terms of the GNU General Public License as published by the
                      7:  * Free Software Foundation; either version 2 of the License, or (at your
                      8:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.  *
                      9:  * This program is distributed in the hope that it will be useful, but
                     10:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
                     11:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
                     12:  * for more details.
                     13:  */
                     14: 
                     15: #include "kernel_libipsec_ipsec.h"
                     16: #include "kernel_libipsec_router.h"
                     17: 
                     18: #include <library.h>
                     19: #include <ipsec.h>
                     20: #include <daemon.h>
                     21: #include <networking/tun_device.h>
                     22: #include <threading/mutex.h>
                     23: #include <utils/debug.h>
                     24: 
                     25: typedef struct private_kernel_libipsec_ipsec_t private_kernel_libipsec_ipsec_t;
                     26: 
                     27: struct private_kernel_libipsec_ipsec_t {
                     28: 
                     29:        /**
                     30:         * Public libipsec_ipsec interface
                     31:         */
                     32:        kernel_libipsec_ipsec_t public;
                     33: 
                     34:        /**
                     35:         * Listener for lifetime expire events
                     36:         */
                     37:        ipsec_event_listener_t ipsec_listener;
                     38: 
                     39:        /**
                     40:         * Mutex to lock access to various lists
                     41:         */
                     42:        mutex_t *mutex;
                     43: 
                     44:        /**
                     45:         * List of installed policies (policy_entry_t)
                     46:         */
                     47:        linked_list_t *policies;
                     48: 
                     49:        /**
                     50:         * List of exclude routes (exclude_route_t)
                     51:         */
                     52:        linked_list_t *excludes;
                     53: 
                     54:        /**
                     55:         * Whether the remote TS may equal the IKE peer
                     56:         */
                     57:        bool allow_peer_ts;
                     58: };
                     59: 
                     60: typedef struct exclude_route_t exclude_route_t;
                     61: 
                     62: /**
                     63:  * Exclude route definition
                     64:  */
                     65: struct exclude_route_t {
                     66:        /** Destination address to exclude */
                     67:        host_t *dst;
                     68:        /** Source address for route */
                     69:        host_t *src;
                     70:        /** Nexthop exclude has been installed */
                     71:        host_t *gtw;
                     72:        /** References to this route */
                     73:        int refs;
                     74: };
                     75: 
                     76: /**
                     77:  * Clean up an exclude route entry
                     78:  */
                     79: static void exclude_route_destroy(exclude_route_t *this)
                     80: {
                     81:        this->dst->destroy(this->dst);
                     82:        this->src->destroy(this->src);
                     83:        this->gtw->destroy(this->gtw);
                     84:        free(this);
                     85: }
                     86: 
                     87: CALLBACK(exclude_route_match, bool,
                     88:        exclude_route_t *current, va_list args)
                     89: {
                     90:        host_t *dst;
                     91: 
                     92:        VA_ARGS_VGET(args, dst);
                     93:        return dst->ip_equals(dst, current->dst);
                     94: }
                     95: 
                     96: typedef struct route_entry_t route_entry_t;
                     97: 
                     98: /**
                     99:  * Installed routing entry
                    100:  */
                    101: struct route_entry_t {
                    102:        /** Name of the interface the route is bound to */
                    103:        char *if_name;
                    104:        /** Source IP of the route */
                    105:        host_t *src_ip;
                    106:        /** Gateway of the route */
                    107:        host_t *gateway;
                    108:        /** Destination net */
                    109:        chunk_t dst_net;
                    110:        /** Destination net prefixlen */
                    111:        uint8_t prefixlen;
                    112:        /** Reference to exclude route, if any */
                    113:        exclude_route_t *exclude;
                    114: };
                    115: 
                    116: /**
                    117:  * Destroy a route_entry_t object
                    118:  */
                    119: static void route_entry_destroy(route_entry_t *this)
                    120: {
                    121:        free(this->if_name);
                    122:        DESTROY_IF(this->src_ip);
                    123:        DESTROY_IF(this->gateway);
                    124:        chunk_free(&this->dst_net);
                    125:        free(this);
                    126: }
                    127: 
                    128: /**
                    129:  * Compare two route_entry_t objects
                    130:  */
                    131: static bool route_entry_equals(route_entry_t *a, route_entry_t *b)
                    132: {
                    133:        if ((!a->src_ip && !b->src_ip) || (a->src_ip && b->src_ip &&
                    134:                  a->src_ip->ip_equals(a->src_ip, b->src_ip)))
                    135:        {
                    136:                if ((!a->gateway && !b->gateway) || (a->gateway && b->gateway &&
                    137:                          a->gateway->ip_equals(a->gateway, b->gateway)))
                    138:                {
                    139:                        return a->if_name && b->if_name && streq(a->if_name, b->if_name) &&
                    140:                                   chunk_equals(a->dst_net, b->dst_net) &&
                    141:                                   a->prefixlen == b->prefixlen;
                    142:                }
                    143:        }
                    144:        return FALSE;
                    145: }
                    146: 
                    147: typedef struct policy_entry_t policy_entry_t;
                    148: 
                    149: /**
                    150:  * Installed policy
                    151:  */
                    152: struct policy_entry_t {
                    153:        /** Direction of this policy: in, out, forward */
                    154:        uint8_t direction;
                    155:        /** Parameters of installed policy */
                    156:        struct {
                    157:                /** Subnet and port */
                    158:                host_t *net;
                    159:                /** Subnet mask */
                    160:                uint8_t mask;
                    161:                /** Protocol */
                    162:                uint8_t proto;
                    163:        } src, dst;
                    164:        /** Associated route installed for this policy */
                    165:        route_entry_t *route;
                    166:        /** References to this policy */
                    167:        int refs;
                    168: };
                    169: 
                    170: /**
                    171:  * Create a policy_entry_t object
                    172:  */
                    173: static policy_entry_t *create_policy_entry(traffic_selector_t *src_ts,
                    174:                                                                                   traffic_selector_t *dst_ts,
                    175:                                                                                   policy_dir_t dir)
                    176: {
                    177:        policy_entry_t *this;
                    178:        INIT(this,
                    179:                .direction = dir,
                    180:        );
                    181: 
                    182:        src_ts->to_subnet(src_ts, &this->src.net, &this->src.mask);
                    183:        dst_ts->to_subnet(dst_ts, &this->dst.net, &this->dst.mask);
                    184: 
                    185:        /* src or dest proto may be "any" (0), use more restrictive one */
                    186:        this->src.proto = max(src_ts->get_protocol(src_ts),
                    187:                                                  dst_ts->get_protocol(dst_ts));
                    188:        this->src.proto = this->src.proto ? this->src.proto : 0;
                    189:        this->dst.proto = this->src.proto;
                    190:        return this;
                    191: }
                    192: 
                    193: /**
                    194:  * Destroy a policy_entry_t object
                    195:  */
                    196: static void policy_entry_destroy(policy_entry_t *this)
                    197: {
                    198:        if (this->route)
                    199:        {
                    200:                route_entry_destroy(this->route);
                    201:        }
                    202:        DESTROY_IF(this->src.net);
                    203:        DESTROY_IF(this->dst.net);
                    204:        free(this);
                    205: }
                    206: 
                    207: CALLBACK(policy_entry_equals, bool,
                    208:        policy_entry_t *a, va_list args)
                    209: {
                    210:        policy_entry_t *b;
                    211: 
                    212:        VA_ARGS_VGET(args, b);
                    213:        return a->direction == b->direction &&
                    214:                   a->src.proto == b->src.proto &&
                    215:                   a->dst.proto == b->dst.proto &&
                    216:                   a->src.mask == b->src.mask &&
                    217:                   a->dst.mask == b->dst.mask &&
                    218:                   a->src.net->equals(a->src.net, b->src.net) &&
                    219:                   a->dst.net->equals(a->dst.net, b->dst.net);
                    220: }
                    221: 
                    222: /**
                    223:  * Expiration callback
                    224:  */
                    225: static void expire(uint8_t protocol, uint32_t spi, host_t *dst, bool hard)
                    226: {
                    227:        charon->kernel->expire(charon->kernel, protocol, spi, dst, hard);
                    228: }
                    229: 
                    230: METHOD(kernel_ipsec_t, get_features, kernel_feature_t,
                    231:        private_kernel_libipsec_ipsec_t *this)
                    232: {
                    233:        return KERNEL_REQUIRE_UDP_ENCAPSULATION | KERNEL_ESP_V3_TFC;
                    234: }
                    235: 
                    236: METHOD(kernel_ipsec_t, get_spi, status_t,
                    237:        private_kernel_libipsec_ipsec_t *this, host_t *src, host_t *dst,
                    238:        uint8_t protocol, uint32_t *spi)
                    239: {
                    240:        return ipsec->sas->get_spi(ipsec->sas, src, dst, protocol, spi);
                    241: }
                    242: 
                    243: METHOD(kernel_ipsec_t, get_cpi, status_t,
                    244:        private_kernel_libipsec_ipsec_t *this, host_t *src, host_t *dst,
                    245:        uint16_t *cpi)
                    246: {
                    247:        return NOT_SUPPORTED;
                    248: }
                    249: 
                    250: METHOD(kernel_ipsec_t, add_sa, status_t,
                    251:        private_kernel_libipsec_ipsec_t *this, kernel_ipsec_sa_id_t *id,
                    252:        kernel_ipsec_add_sa_t *data)
                    253: {
                    254:        return ipsec->sas->add_sa(ipsec->sas, id->src, id->dst, id->spi, id->proto,
                    255:                                        data->reqid, id->mark, data->tfc, data->lifetime,
                    256:                                        data->enc_alg, data->enc_key, data->int_alg, data->int_key,
                    257:                                        data->mode, data->ipcomp, data->cpi, data->initiator,
                    258:                                        data->encap, data->esn, data->inbound, data->update);
                    259: }
                    260: 
                    261: METHOD(kernel_ipsec_t, update_sa, status_t,
                    262:        private_kernel_libipsec_ipsec_t *this, kernel_ipsec_sa_id_t *id,
                    263:        kernel_ipsec_update_sa_t *data)
                    264: {
                    265:        return NOT_SUPPORTED;
                    266: }
                    267: 
                    268: METHOD(kernel_ipsec_t, query_sa, status_t,
                    269:        private_kernel_libipsec_ipsec_t *this, kernel_ipsec_sa_id_t *id,
                    270:        kernel_ipsec_query_sa_t *data, uint64_t *bytes, uint64_t *packets,
                    271:        time_t *time)
                    272: {
                    273:        return ipsec->sas->query_sa(ipsec->sas, id->src, id->dst, id->spi,
                    274:                                                                id->proto, id->mark, bytes, packets, time);
                    275: }
                    276: 
                    277: METHOD(kernel_ipsec_t, del_sa, status_t,
                    278:        private_kernel_libipsec_ipsec_t *this, kernel_ipsec_sa_id_t *id,
                    279:        kernel_ipsec_del_sa_t *data)
                    280: {
                    281:        return ipsec->sas->del_sa(ipsec->sas, id->src, id->dst, id->spi, id->proto,
                    282:                                                          data->cpi, id->mark);
                    283: }
                    284: 
                    285: METHOD(kernel_ipsec_t, flush_sas, status_t,
                    286:        private_kernel_libipsec_ipsec_t *this)
                    287: {
                    288:        return ipsec->sas->flush_sas(ipsec->sas);
                    289: }
                    290: 
                    291: /**
                    292:  * Add an explicit exclude route to a routing entry
                    293:  */
                    294: static void add_exclude_route(private_kernel_libipsec_ipsec_t *this,
                    295:                                                          route_entry_t *route, host_t *src, host_t *dst)
                    296: {
                    297:        exclude_route_t *exclude;
                    298:        host_t *gtw;
                    299: 
                    300:        if (this->excludes->find_first(this->excludes, exclude_route_match,
                    301:                                                                  (void**)&exclude, dst))
                    302:        {
                    303:                route->exclude = exclude;
                    304:                exclude->refs++;
                    305:        }
                    306: 
                    307:        if (!route->exclude)
                    308:        {
                    309:                DBG2(DBG_KNL, "installing new exclude route for %H src %H", dst, src);
                    310:                gtw = charon->kernel->get_nexthop(charon->kernel, dst, -1, NULL, NULL);
                    311:                if (gtw)
                    312:                {
                    313:                        char *if_name = NULL;
                    314: 
                    315:                        if (charon->kernel->get_interface(charon->kernel, src, &if_name) &&
                    316:                                charon->kernel->add_route(charon->kernel, dst->get_address(dst),
                    317:                                                                        dst->get_family(dst) == AF_INET ? 32 : 128,
                    318:                                                                        gtw, src, if_name, TRUE) == SUCCESS)
                    319:                        {
                    320:                                INIT(exclude,
                    321:                                        .dst = dst->clone(dst),
                    322:                                        .src = src->clone(src),
                    323:                                        .gtw = gtw->clone(gtw),
                    324:                                        .refs = 1,
                    325:                                );
                    326:                                route->exclude = exclude;
                    327:                                this->excludes->insert_last(this->excludes, exclude);
                    328:                        }
                    329:                        else
                    330:                        {
                    331:                                DBG1(DBG_KNL, "installing exclude route for %H failed", dst);
                    332:                        }
                    333:                        gtw->destroy(gtw);
                    334:                        free(if_name);
                    335:                }
                    336:                else
                    337:                {
                    338:                        DBG1(DBG_KNL, "gateway lookup for %H failed", dst);
                    339:                }
                    340:        }
                    341: }
                    342: 
                    343: /**
                    344:  * Remove an exclude route attached to a routing entry
                    345:  */
                    346: static void remove_exclude_route(private_kernel_libipsec_ipsec_t *this,
                    347:                                                                 route_entry_t *route)
                    348: {
                    349:        char *if_name = NULL;
                    350:        host_t *dst;
                    351: 
                    352:        if (!route->exclude || --route->exclude->refs > 0)
                    353:        {
                    354:                return;
                    355:        }
                    356:        this->excludes->remove(this->excludes, route->exclude, NULL);
                    357: 
                    358:        dst = route->exclude->dst;
                    359:        DBG2(DBG_KNL, "uninstalling exclude route for %H src %H",
                    360:                 dst, route->exclude->src);
                    361:        if (charon->kernel->get_interface(charon->kernel, route->exclude->src,
                    362:                                                                          &if_name) &&
                    363:                charon->kernel->del_route(charon->kernel, dst->get_address(dst),
                    364:                                                                  dst->get_family(dst) == AF_INET ? 32 : 128,
                    365:                                                                  route->exclude->gtw, route->exclude->src,
                    366:                                                                  if_name, TRUE) != SUCCESS)
                    367:        {
                    368:                DBG1(DBG_KNL, "uninstalling exclude route for %H failed", dst);
                    369:        }
                    370:        exclude_route_destroy(route->exclude);
                    371:        route->exclude = NULL;
                    372:        free(if_name);
                    373: }
                    374: 
                    375: /**
                    376:  * Install a route for the given policy
                    377:  *
                    378:  * this->mutex is released by this function
                    379:  */
                    380: static bool install_route(private_kernel_libipsec_ipsec_t *this,
                    381:        host_t *src, host_t *dst, traffic_selector_t *src_ts,
                    382:        traffic_selector_t *dst_ts, policy_entry_t *policy)
                    383: {
                    384:        route_entry_t *route, *old;
                    385:        host_t *src_ip;
                    386:        bool is_virtual;
                    387: 
                    388:        if (policy->direction != POLICY_OUT)
                    389:        {
                    390:                this->mutex->unlock(this->mutex);
                    391:                return TRUE;
                    392:        }
                    393: 
                    394:        if (charon->kernel->get_address_by_ts(charon->kernel, src_ts, &src_ip,
                    395:                                                                                  &is_virtual) != SUCCESS)
                    396:        {
                    397:                traffic_selector_t *multicast, *broadcast = NULL;
                    398:                bool ignore = FALSE;
                    399: 
                    400:                this->mutex->unlock(this->mutex);
                    401:                switch (src_ts->get_type(src_ts))
                    402:                {
                    403:                        case TS_IPV4_ADDR_RANGE:
                    404:                                multicast = traffic_selector_create_from_cidr("224.0.0.0/4",
                    405:                                                                                                                          0, 0, 0xffff);
                    406:                                broadcast = traffic_selector_create_from_cidr("255.255.255.255/32",
                    407:                                                                                                                          0, 0, 0xffff);
                    408:                                break;
                    409:                        case TS_IPV6_ADDR_RANGE:
                    410:                                multicast = traffic_selector_create_from_cidr("ff00::/8",
                    411:                                                                                                                          0, 0, 0xffff);
                    412:                                break;
                    413:                        default:
                    414:                                return FALSE;
                    415:                }
                    416:                ignore = src_ts->is_contained_in(src_ts, multicast);
                    417:                ignore |= broadcast && src_ts->is_contained_in(src_ts, broadcast);
                    418:                multicast->destroy(multicast);
                    419:                DESTROY_IF(broadcast);
                    420:                if (!ignore)
                    421:                {
                    422:                        DBG1(DBG_KNL, "error installing route with policy %R === %R %N",
                    423:                                 src_ts, dst_ts, policy_dir_names, policy->direction);
                    424:                }
                    425:                return ignore;
                    426:        }
                    427: 
                    428:        INIT(route,
                    429:                .if_name = router->get_tun_name(router, is_virtual ? src_ip : NULL),
                    430:                .src_ip = src_ip,
                    431:                .dst_net = chunk_clone(policy->dst.net->get_address(policy->dst.net)),
                    432:                .prefixlen = policy->dst.mask,
                    433:        );
                    434: #ifndef __linux__
                    435:        /* on Linux we can't install a gateway */
                    436:        route->gateway = charon->kernel->get_nexthop(charon->kernel, dst, -1, src,
                    437:                                                                                                 NULL);
                    438: #endif
                    439: 
                    440:        if (policy->route)
                    441:        {
                    442:                old = policy->route;
                    443: 
                    444:                if (route_entry_equals(old, route))
                    445:                {       /* such a route already exists */
                    446:                        route_entry_destroy(route);
                    447:                        this->mutex->unlock(this->mutex);
                    448:                        return TRUE;
                    449:                }
                    450:                /* uninstall previously installed route */
                    451:                if (charon->kernel->del_route(charon->kernel, old->dst_net,
                    452:                                                                          old->prefixlen, old->gateway, old->src_ip,
                    453:                                                                          old->if_name, FALSE) != SUCCESS)
                    454:                {
                    455:                        DBG1(DBG_KNL, "error uninstalling route installed with policy "
                    456:                                 "%R === %R %N", src_ts, dst_ts, policy_dir_names,
                    457:                                 policy->direction);
                    458:                }
                    459:                route_entry_destroy(old);
                    460:                policy->route = NULL;
                    461:        }
                    462: 
                    463:        if (!this->allow_peer_ts && dst_ts->is_host(dst_ts, dst))
                    464:        {
                    465:                DBG1(DBG_KNL, "can't install route for %R === %R %N, conflicts with "
                    466:                         "IKE traffic", src_ts, dst_ts, policy_dir_names,
                    467:                         policy->direction);
                    468:                route_entry_destroy(route);
                    469:                this->mutex->unlock(this->mutex);
                    470:                return FALSE;
                    471:        }
                    472:        /* if remote traffic selector covers the IKE peer, add an exclude route */
                    473:        if (!this->allow_peer_ts && dst_ts->includes(dst_ts, dst))
                    474:        {
                    475:                /* add exclude route for peer */
                    476:                add_exclude_route(this, route, src, dst);
                    477:        }
                    478: 
                    479:        DBG2(DBG_KNL, "installing route: %R src %H dev %s",
                    480:                 dst_ts, route->src_ip, route->if_name);
                    481: 
                    482:        switch (charon->kernel->add_route(charon->kernel, route->dst_net,
                    483:                                                                          route->prefixlen, route->gateway,
                    484:                                                                          route->src_ip, route->if_name, FALSE))
                    485:        {
                    486:                case ALREADY_DONE:
                    487:                        /* route exists, do not uninstall */
                    488:                        remove_exclude_route(this, route);
                    489:                        route_entry_destroy(route);
                    490:                        this->mutex->unlock(this->mutex);
                    491:                        return TRUE;
                    492:                case SUCCESS:
                    493:                        /* cache the installed route */
                    494:                        policy->route = route;
                    495:                        this->mutex->unlock(this->mutex);
                    496:                        return TRUE;
                    497:                default:
                    498:                        DBG1(DBG_KNL, "installing route failed: %R src %H dev %s",
                    499:                                 dst_ts, route->src_ip, route->if_name);
                    500:                        remove_exclude_route(this, route);
                    501:                        route_entry_destroy(route);
                    502:                        this->mutex->unlock(this->mutex);
                    503:                        return FALSE;
                    504:        }
                    505: }
                    506: 
                    507: METHOD(kernel_ipsec_t, add_policy, status_t,
                    508:        private_kernel_libipsec_ipsec_t *this, kernel_ipsec_policy_id_t *id,
                    509:        kernel_ipsec_manage_policy_t *data)
                    510: {
                    511:        policy_entry_t *policy, *found = NULL;
                    512:        status_t status;
                    513: 
                    514:        status = ipsec->policies->add_policy(ipsec->policies, data->src, data->dst,
                    515:                                                                                 id->src_ts, id->dst_ts, id->dir,
                    516:                                                                                 data->type, data->sa, id->mark,
                    517:                                                                                 data->prio);
                    518:        if (status != SUCCESS)
                    519:        {
                    520:                return status;
                    521:        }
                    522:        /* we track policies in order to install routes */
                    523:        policy = create_policy_entry(id->src_ts, id->dst_ts, id->dir);
                    524: 
                    525:        this->mutex->lock(this->mutex);
                    526:        if (this->policies->find_first(this->policies, policy_entry_equals,
                    527:                                                                  (void**)&found, policy))
                    528:        {
                    529:                policy_entry_destroy(policy);
                    530:                policy = found;
                    531:        }
                    532:        else
                    533:        {       /* use the new one, if we have no such policy */
                    534:                this->policies->insert_last(this->policies, policy);
                    535:        }
                    536:        policy->refs++;
                    537: 
                    538:        if (!install_route(this, data->src, data->dst, id->src_ts, id->dst_ts,
                    539:                                           policy))
                    540:        {
                    541:                return FAILED;
                    542:        }
                    543:        return SUCCESS;
                    544: }
                    545: 
                    546: METHOD(kernel_ipsec_t, query_policy, status_t,
                    547:        private_kernel_libipsec_ipsec_t *this, kernel_ipsec_policy_id_t *id,
                    548:        kernel_ipsec_query_policy_t *data, time_t *use_time)
                    549: {
                    550:        return NOT_SUPPORTED;
                    551: }
                    552: 
                    553: METHOD(kernel_ipsec_t, del_policy, status_t,
                    554:        private_kernel_libipsec_ipsec_t *this, kernel_ipsec_policy_id_t *id,
                    555:        kernel_ipsec_manage_policy_t *data)
                    556: {
                    557:        policy_entry_t *policy, *found = NULL;
                    558:        status_t status;
                    559: 
                    560:        status = ipsec->policies->del_policy(ipsec->policies, data->src, data->dst,
                    561:                                                                                 id->src_ts, id->dst_ts, id->dir,
                    562:                                                                                 data->type, data->sa, id->mark,
                    563:                                                                                 data->prio);
                    564: 
                    565:        policy = create_policy_entry(id->src_ts, id->dst_ts, id->dir);
                    566: 
                    567:        this->mutex->lock(this->mutex);
                    568:        if (!this->policies->find_first(this->policies, policy_entry_equals,
                    569:                                                                        (void**)&found, policy))
                    570:        {
                    571:                policy_entry_destroy(policy);
                    572:                this->mutex->unlock(this->mutex);
                    573:                return status;
                    574:        }
                    575:        policy_entry_destroy(policy);
                    576:        policy = found;
                    577: 
                    578:        if (--policy->refs > 0)
                    579:        {       /* policy is still in use */
                    580:                this->mutex->unlock(this->mutex);
                    581:                return status;
                    582:        }
                    583: 
                    584:        if (policy->route)
                    585:        {
                    586:                route_entry_t *route = policy->route;
                    587: 
                    588:                if (charon->kernel->del_route(charon->kernel, route->dst_net,
                    589:                                                                route->prefixlen, route->gateway, route->src_ip,
                    590:                                                                route->if_name, FALSE) != SUCCESS)
                    591:                {
                    592:                        DBG1(DBG_KNL, "error uninstalling route installed with "
                    593:                                 "policy %R === %R %N", id->src_ts, id->dst_ts,
                    594:                                 policy_dir_names, id->dir);
                    595:                }
                    596:                remove_exclude_route(this, route);
                    597:        }
                    598:        this->policies->remove(this->policies, policy, NULL);
                    599:        policy_entry_destroy(policy);
                    600:        this->mutex->unlock(this->mutex);
                    601:        return status;
                    602: }
                    603: 
                    604: METHOD(kernel_ipsec_t, flush_policies, status_t,
                    605:        private_kernel_libipsec_ipsec_t *this)
                    606: {
                    607:        policy_entry_t *pol;
                    608:        status_t status;
                    609: 
                    610:        status = ipsec->policies->flush_policies(ipsec->policies);
                    611: 
                    612:        this->mutex->lock(this->mutex);
                    613:        while (this->policies->remove_first(this->policies, (void*)&pol) == SUCCESS)
                    614:        {
                    615:                if (pol->route)
                    616:                {
                    617:                        route_entry_t *route = pol->route;
                    618: 
                    619:                        charon->kernel->del_route(charon->kernel, route->dst_net,
                    620:                                                                          route->prefixlen, route->gateway,
                    621:                                                                          route->src_ip, route->if_name, FALSE);
                    622:                        remove_exclude_route(this, route);
                    623:                }
                    624:                policy_entry_destroy(pol);
                    625:        }
                    626:        this->mutex->unlock(this->mutex);
                    627:        return status;
                    628: }
                    629: 
                    630: METHOD(kernel_ipsec_t, bypass_socket, bool,
                    631:        private_kernel_libipsec_ipsec_t *this, int fd, int family)
                    632: {
                    633:        /* we use exclude routes for this */
                    634:        return NOT_SUPPORTED;
                    635: }
                    636: 
                    637: METHOD(kernel_ipsec_t, enable_udp_decap, bool,
                    638:        private_kernel_libipsec_ipsec_t *this, int fd, int family, uint16_t port)
                    639: {
                    640:        return NOT_SUPPORTED;
                    641: }
                    642: 
                    643: METHOD(kernel_ipsec_t, destroy, void,
                    644:        private_kernel_libipsec_ipsec_t *this)
                    645: {
                    646:        ipsec->events->unregister_listener(ipsec->events, &this->ipsec_listener);
                    647:        this->policies->destroy_function(this->policies, (void*)policy_entry_destroy);
                    648:        this->excludes->destroy(this->excludes);
                    649:        this->mutex->destroy(this->mutex);
                    650:        free(this);
                    651: }
                    652: 
                    653: /*
                    654:  * Described in header.
                    655:  */
                    656: kernel_libipsec_ipsec_t *kernel_libipsec_ipsec_create()
                    657: {
                    658:        private_kernel_libipsec_ipsec_t *this;
                    659: 
                    660:        INIT(this,
                    661:                .public = {
                    662:                        .interface = {
                    663:                                .get_features = _get_features,
                    664:                                .get_spi = _get_spi,
                    665:                                .get_cpi = _get_cpi,
                    666:                                .add_sa  = _add_sa,
                    667:                                .update_sa = _update_sa,
                    668:                                .query_sa = _query_sa,
                    669:                                .del_sa = _del_sa,
                    670:                                .flush_sas = _flush_sas,
                    671:                                .add_policy = _add_policy,
                    672:                                .query_policy = _query_policy,
                    673:                                .del_policy = _del_policy,
                    674:                                .flush_policies = _flush_policies,
                    675:                                .bypass_socket = _bypass_socket,
                    676:                                .enable_udp_decap = _enable_udp_decap,
                    677:                                .destroy = _destroy,
                    678:                        },
                    679:                },
                    680:                .ipsec_listener = {
                    681:                        .expire = expire,
                    682:                },
                    683:                .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
                    684:                .policies = linked_list_create(),
                    685:                .excludes = linked_list_create(),
                    686:                .allow_peer_ts = lib->settings->get_bool(lib->settings,
                    687:                                        "%s.plugins.kernel-libipsec.allow_peer_ts", FALSE, lib->ns),
                    688:        );
                    689: 
                    690:        ipsec->events->register_listener(ipsec->events, &this->ipsec_listener);
                    691: 
                    692:        return &this->public;
                    693: };

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