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