Return to bypass_lan_listener.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / libcharon / plugins / bypass_lan |
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: }