Annotation of embedaddon/strongswan/src/libcharon/plugins/bypass_lan/bypass_lan_listener.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * Copyright (C) 2016 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:  *
                     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: #include "bypass_lan_listener.h"
                     17: 
                     18: #include <collections/hashtable.h>
                     19: #include <collections/linked_list.h>
                     20: #include <threading/mutex.h>
                     21: #include <processing/jobs/callback_job.h>
                     22: 
                     23: #include <daemon.h>
                     24: 
                     25: typedef struct private_bypass_lan_listener_t private_bypass_lan_listener_t;
                     26: 
                     27: /**
                     28:  * Private data
                     29:  */
                     30: struct private_bypass_lan_listener_t {
                     31: 
                     32:        /**
                     33:         * Public interface.
                     34:         */
                     35:        bypass_lan_listener_t public;
                     36: 
                     37:        /**
                     38:         * Currently installed bypass policies, bypass_policy_t*.
                     39:         */
                     40:        hashtable_t *policies;
                     41: 
                     42:        /**
                     43:         * Mutex to access list of policies.
                     44:         */
                     45:        mutex_t *mutex;
                     46: 
                     47:        /**
                     48:         * List of interface names to include or exclude (char*), NULL if interfaces
                     49:         * are not filtered.
                     50:         */
                     51:        linked_list_t *ifaces_filter;
                     52: 
                     53:        /**
                     54:         * TRUE to exclude interfaces listed in ifaces_filter, FALSE to consider
                     55:         * only those listed there.
                     56:         */
                     57:        bool ifaces_exclude;
                     58: };
                     59: 
                     60: /**
                     61:  * Data for bypass policies
                     62:  */
                     63: typedef struct {
                     64:        private_bypass_lan_listener_t *listener;
                     65:        host_t *net;
                     66:        uint8_t mask;
                     67:        char *iface;
                     68:        child_cfg_t *cfg;
                     69: } bypass_policy_t;
                     70: 
                     71: /**
                     72:  * Destroy a bypass policy
                     73:  */
                     74: static void bypass_policy_destroy(bypass_policy_t *this)
                     75: {
                     76:        traffic_selector_t *ts;
                     77: 
                     78:        if (this->cfg)
                     79:        {
                     80:                ts = traffic_selector_create_from_subnet(this->net->clone(this->net),
                     81:                                                                                                 this->mask, 0, 0, 65535);
                     82:                DBG1(DBG_IKE, "uninstalling bypass policy for %R", ts);
                     83:                charon->shunts->uninstall(charon->shunts, "bypass-lan",
                     84:                                                                  this->cfg->get_name(this->cfg));
                     85:                this->cfg->destroy(this->cfg);
                     86:                ts->destroy(ts);
                     87:        }
                     88:        this->net->destroy(this->net);
                     89:        free(this->iface);
                     90:        free(this);
                     91: }
                     92: 
                     93: /**
                     94:  * Hash a bypass policy
                     95:  */
                     96: static u_int policy_hash(bypass_policy_t *policy)
                     97: {
                     98:        return chunk_hash_inc(policy->net->get_address(policy->net),
                     99:                                                  chunk_hash(chunk_from_thing(policy->mask)));
                    100: }
                    101: 
                    102: /**
                    103:  * Compare bypass policy
                    104:  */
                    105: static bool policy_equals(bypass_policy_t *a, bypass_policy_t *b)
                    106: {
                    107:        return a->mask == b->mask && a->net->equals(a->net, b->net);
                    108: }
                    109: 
                    110: /**
                    111:  * Check if an interface should be considered
                    112:  */
                    113: static bool consider_interface(private_bypass_lan_listener_t *this, char *iface)
                    114: {
                    115:        if (!iface || !this->ifaces_filter)
                    116:        {
                    117:                return TRUE;
                    118:        }
                    119:        return this->ifaces_filter->find_first(this->ifaces_filter,
                    120:                                        linked_list_match_str, NULL, iface) != this->ifaces_exclude;
                    121: }
                    122: 
                    123: /**
                    124:  * Job updating bypass policies
                    125:  */
                    126: static job_requeue_t update_bypass(private_bypass_lan_listener_t *this)
                    127: {
                    128:        enumerator_t *enumerator;
                    129:        hashtable_t *seen;
                    130:        bypass_policy_t *found, *lookup;
                    131:        traffic_selector_t *ts;
                    132:        host_t *net;
                    133:        uint8_t mask;
                    134:        char *iface;
                    135: 
                    136:        seen = hashtable_create((hashtable_hash_t)policy_hash,
                    137:                                                        (hashtable_equals_t)policy_equals, 4);
                    138: 
                    139:        this->mutex->lock(this->mutex);
                    140: 
                    141:        enumerator = charon->kernel->create_local_subnet_enumerator(charon->kernel);
                    142:        while (enumerator->enumerate(enumerator, &net, &mask, &iface))
                    143:        {
                    144:                if (!consider_interface(this, iface))
                    145:                {
                    146:                        continue;
                    147:                }
                    148: 
                    149:                INIT(lookup,
                    150:                        .net = net->clone(net),
                    151:                        .mask = mask,
                    152:                        .iface = strdupnull(iface),
                    153:                );
                    154:                found = seen->put(seen, lookup, lookup);
                    155:                if (found)
                    156:                {       /* in case the same subnet is on multiple interfaces */
                    157:                        bypass_policy_destroy(found);
                    158:                }
                    159: 
                    160:                found = this->policies->get(this->policies, lookup);
                    161:                if (!found)
                    162:                {
                    163:                        child_cfg_create_t child = {
                    164:                                .mode = MODE_PASS,
                    165:                        };
                    166:                        child_cfg_t *cfg;
                    167:                        char name[128];
                    168: 
                    169:                        ts = traffic_selector_create_from_subnet(net->clone(net), mask,
                    170:                                                                                                         0, 0, 65535);
                    171:                        snprintf(name, sizeof(name), "Bypass LAN %R", ts);
                    172: 
                    173:                        cfg = child_cfg_create(name, &child);
                    174:                        cfg->add_traffic_selector(cfg, FALSE, ts->clone(ts));
                    175:                        cfg->add_traffic_selector(cfg, TRUE, ts);
                    176:                        charon->shunts->install(charon->shunts, "bypass-lan", cfg);
                    177:                        DBG1(DBG_IKE, "installed bypass policy for %R", ts);
                    178: 
                    179:                        INIT(found,
                    180:                                .net = net->clone(net),
                    181:                                .mask = mask,
                    182:                                .iface = strdupnull(iface),
                    183:                                .cfg = cfg,
                    184:                        );
                    185:                        this->policies->put(this->policies, found, found);
                    186:                }
                    187:        }
                    188:        enumerator->destroy(enumerator);
                    189: 
                    190:        enumerator = this->policies->create_enumerator(this->policies);
                    191:        while (enumerator->enumerate(enumerator, NULL, &lookup))
                    192:        {
                    193:                found = seen->get(seen, lookup);
                    194:                if (!found)
                    195:                {
                    196:                        this->policies->remove_at(this->policies, enumerator);
                    197:                        bypass_policy_destroy(lookup);
                    198:                }
                    199:                else if (!streq(lookup->iface, found->iface))
                    200:                {       /* if the subnet is on multiple interfaces, we only get the last
                    201:                         * one (hopefully, they are enumerated in a consistent order) */
                    202:                        ts = traffic_selector_create_from_subnet(
                    203:                                                                                                lookup->net->clone(lookup->net),
                    204:                                                                                                lookup->mask, 0, 0, 65535);
                    205:                        DBG1(DBG_IKE, "interface change for bypass policy for %R (from %s "
                    206:                                 "to %s)", ts, lookup->iface, found->iface);
                    207:                        ts->destroy(ts);
                    208:                        free(lookup->iface);
                    209:                        lookup->iface = strdupnull(found->iface);
                    210:                        /* there is currently no API to update shunts, so we remove and
                    211:                         * reinstall it to update the route */
                    212:                        charon->shunts->uninstall(charon->shunts, "bypass-lan",
                    213:                                                                          lookup->cfg->get_name(lookup->cfg));
                    214:                        charon->shunts->install(charon->shunts, "bypass-lan", lookup->cfg);
                    215:                }
                    216:        }
                    217:        enumerator->destroy(enumerator);
                    218:        this->mutex->unlock(this->mutex);
                    219: 
                    220:        seen->destroy_function(seen, (void*)bypass_policy_destroy);
                    221:        return JOB_REQUEUE_NONE;
                    222: }
                    223: 
                    224: METHOD(kernel_listener_t, roam, bool,
                    225:        private_bypass_lan_listener_t *this, bool address)
                    226: {
                    227:        lib->processor->queue_job(lib->processor,
                    228:                        (job_t*)callback_job_create((callback_job_cb_t)update_bypass, this,
                    229:                                                                        NULL, (callback_job_cancel_t)return_false));
                    230:        return TRUE;
                    231: }
                    232: 
                    233: METHOD(bypass_lan_listener_t, reload_interfaces, void,
                    234:        private_bypass_lan_listener_t *this)
                    235: {
                    236:        char *ifaces;
                    237: 
                    238:        this->mutex->lock(this->mutex);
                    239:        DESTROY_FUNCTION_IF(this->ifaces_filter, (void*)free);
                    240:        this->ifaces_filter = NULL;
                    241:        this->ifaces_exclude = FALSE;
                    242: 
                    243:        ifaces = lib->settings->get_str(lib->settings,
                    244:                                        "%s.plugins.bypass-lan.interfaces_use", NULL, lib->ns);
                    245:        if (!ifaces)
                    246:        {
                    247:                this->ifaces_exclude = TRUE;
                    248:                ifaces = lib->settings->get_str(lib->settings,
                    249:                                        "%s.plugins.bypass-lan.interfaces_ignore", NULL, lib->ns);
                    250:        }
                    251:        if (ifaces)
                    252:        {
                    253:                enumerator_t *enumerator;
                    254:                char *iface;
                    255: 
                    256:                enumerator = enumerator_create_token(ifaces, ",", " ");
                    257:                while (enumerator->enumerate(enumerator, &iface))
                    258:                {
                    259:                        if (!this->ifaces_filter)
                    260:                        {
                    261:                                this->ifaces_filter = linked_list_create();
                    262:                        }
                    263:                        this->ifaces_filter->insert_last(this->ifaces_filter,
                    264:                                                                                         strdup(iface));
                    265:                }
                    266:                enumerator->destroy(enumerator);
                    267:        }
                    268:        this->mutex->unlock(this->mutex);
                    269:        lib->processor->queue_job(lib->processor,
                    270:                        (job_t*)callback_job_create((callback_job_cb_t)update_bypass, this,
                    271:                                                                        NULL, (callback_job_cancel_t)return_false));
                    272: }
                    273: 
                    274: METHOD(bypass_lan_listener_t, destroy, void,
                    275:        private_bypass_lan_listener_t *this)
                    276: {
                    277:        enumerator_t *enumerator;
                    278:        bypass_policy_t *policy;
                    279: 
                    280:        enumerator = this->policies->create_enumerator(this->policies);
                    281:        while (enumerator->enumerate(enumerator, NULL, &policy))
                    282:        {
                    283:                bypass_policy_destroy(policy);
                    284:        }
                    285:        enumerator->destroy(enumerator);
                    286:        DESTROY_FUNCTION_IF(this->ifaces_filter, (void*)free);
                    287:        this->policies->destroy(this->policies);
                    288:        this->mutex->destroy(this->mutex);
                    289:        free(this);
                    290: }
                    291: 
                    292: /*
                    293:  * See header
                    294:  */
                    295: bypass_lan_listener_t *bypass_lan_listener_create()
                    296: {
                    297:        private_bypass_lan_listener_t *this;
                    298: 
                    299:        INIT(this,
                    300:                .public = {
                    301:                        .listener = {
                    302:                                .roam = _roam,
                    303:                        },
                    304:                        .reload_interfaces = _reload_interfaces,
                    305:                        .destroy = _destroy,
                    306:                },
                    307:                .policies = hashtable_create((hashtable_hash_t)policy_hash,
                    308:                                                                         (hashtable_equals_t)policy_equals, 4),
                    309:                .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
                    310:        );
                    311: 
                    312:        reload_interfaces(this);
                    313:        return &this->public;
                    314: }

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