Annotation of embedaddon/strongswan/src/libcharon/plugins/unity/unity_handler.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2013 Tobias Brunner
! 3: * HSR Hochschule fuer Technik Rapperswil
! 4: *
! 5: * Copyright (C) 2012 Martin Willi
! 6: * Copyright (C) 2012 revosec AG
! 7: *
! 8: * This program is free software; you can redistribute it and/or modify it
! 9: * under the terms of the GNU General Public License as published by the
! 10: * Free Software Foundation; either version 2 of the License, or (at your
! 11: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
! 12: *
! 13: * This program is distributed in the hope that it will be useful, but
! 14: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
! 15: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
! 16: * for more details.
! 17: */
! 18:
! 19: #include "unity_handler.h"
! 20:
! 21: #include <daemon.h>
! 22: #include <threading/mutex.h>
! 23: #include <collections/linked_list.h>
! 24: #include <processing/jobs/callback_job.h>
! 25:
! 26: typedef struct private_unity_handler_t private_unity_handler_t;
! 27:
! 28: /**
! 29: * Private data of an unity_handler_t object.
! 30: */
! 31: struct private_unity_handler_t {
! 32:
! 33: /**
! 34: * Public unity_handler_t interface.
! 35: */
! 36: unity_handler_t public;
! 37:
! 38: /**
! 39: * List of subnets to include, as entry_t
! 40: */
! 41: linked_list_t *include;
! 42:
! 43: /**
! 44: * Mutex for concurrent access to lists
! 45: */
! 46: mutex_t *mutex;
! 47: };
! 48:
! 49: /**
! 50: * Traffic selector entry for networks to include under a given IKE_SA
! 51: */
! 52: typedef struct {
! 53: /** associated IKE_SA COOKIEs */
! 54: ike_sa_id_t *id;
! 55: /** traffic selector to include/exclude */
! 56: traffic_selector_t *ts;
! 57: } entry_t;
! 58:
! 59: /**
! 60: * Clean up an entry
! 61: */
! 62: static void entry_destroy(entry_t *this)
! 63: {
! 64: this->id->destroy(this->id);
! 65: this->ts->destroy(this->ts);
! 66: free(this);
! 67: }
! 68:
! 69: /**
! 70: * Create a traffic selector from a unity subnet definition
! 71: */
! 72: static traffic_selector_t *create_ts(chunk_t subnet)
! 73: {
! 74: chunk_t net, mask;
! 75: int i;
! 76:
! 77: net = chunk_create(subnet.ptr, 4);
! 78: mask = chunk_clonea(chunk_create(subnet.ptr + 4, 4));
! 79: for (i = 0; i < net.len; i++)
! 80: {
! 81: mask.ptr[i] = (mask.ptr[i] ^ 0xFF) | net.ptr[i];
! 82: }
! 83: return traffic_selector_create_from_bytes(0, TS_IPV4_ADDR_RANGE,
! 84: net, 0, mask, 65535);
! 85: }
! 86:
! 87: /**
! 88: * Parse a unity attribute and extract all subnets as traffic selectors
! 89: */
! 90: static linked_list_t *parse_subnets(chunk_t data)
! 91: {
! 92: linked_list_t *list = NULL;
! 93: traffic_selector_t *ts;
! 94:
! 95: while (data.len >= 8)
! 96: { /* the padding is optional */
! 97: ts = create_ts(data);
! 98: if (ts)
! 99: {
! 100: if (!list)
! 101: {
! 102: list = linked_list_create();
! 103: }
! 104: list->insert_last(list, ts);
! 105: }
! 106: /* skip address, mask and 6 bytes of padding */
! 107: data = chunk_skip(data, 14);
! 108: }
! 109: return list;
! 110: }
! 111:
! 112: /**
! 113: * Store a list of subnets to include in tunnels under this IKE_SA
! 114: */
! 115: static bool add_include(private_unity_handler_t *this, chunk_t data)
! 116: {
! 117: traffic_selector_t *ts;
! 118: linked_list_t *list;
! 119: ike_sa_t *ike_sa;
! 120: entry_t *entry;
! 121:
! 122: ike_sa = charon->bus->get_sa(charon->bus);
! 123: if (!ike_sa)
! 124: {
! 125: return FALSE;
! 126: }
! 127: list = parse_subnets(data);
! 128: if (!list)
! 129: {
! 130: return FALSE;
! 131: }
! 132: while (list->remove_first(list, (void**)&ts) == SUCCESS)
! 133: {
! 134: INIT(entry,
! 135: .id = ike_sa->get_id(ike_sa),
! 136: .ts = ts,
! 137: );
! 138: entry->id = entry->id->clone(entry->id);
! 139:
! 140: this->mutex->lock(this->mutex);
! 141: this->include->insert_last(this->include, entry);
! 142: this->mutex->unlock(this->mutex);
! 143: }
! 144: list->destroy(list);
! 145: return TRUE;
! 146: }
! 147:
! 148: /**
! 149: * Remove a list of subnets from the inclusion list for this IKE_SA
! 150: */
! 151: static bool remove_include(private_unity_handler_t *this, chunk_t data)
! 152: {
! 153: enumerator_t *enumerator;
! 154: traffic_selector_t *ts;
! 155: linked_list_t *list;
! 156: ike_sa_t *ike_sa;
! 157: entry_t *entry;
! 158:
! 159: ike_sa = charon->bus->get_sa(charon->bus);
! 160: if (!ike_sa)
! 161: {
! 162: return FALSE;
! 163: }
! 164: list = parse_subnets(data);
! 165: if (!list)
! 166: {
! 167: return FALSE;
! 168: }
! 169:
! 170: this->mutex->lock(this->mutex);
! 171: while (list->remove_first(list, (void**)&ts) == SUCCESS)
! 172: {
! 173: enumerator = this->include->create_enumerator(this->include);
! 174: while (enumerator->enumerate(enumerator, &entry))
! 175: {
! 176: if (entry->id->equals(entry->id, ike_sa->get_id(ike_sa)) &&
! 177: ts->equals(ts, entry->ts))
! 178: {
! 179: this->include->remove_at(this->include, enumerator);
! 180: entry_destroy(entry);
! 181: break;
! 182: }
! 183: }
! 184: enumerator->destroy(enumerator);
! 185: ts->destroy(ts);
! 186: }
! 187: this->mutex->unlock(this->mutex);
! 188: list->destroy(list);
! 189: return TRUE;
! 190: }
! 191:
! 192: /**
! 193: * Create a unique shunt name for a bypass policy
! 194: */
! 195: static void create_shunt_name(ike_sa_t *ike_sa, traffic_selector_t *ts,
! 196: char *buf, size_t len)
! 197: {
! 198: snprintf(buf, len, "Unity (%s[%u]: %R)", ike_sa->get_name(ike_sa),
! 199: ike_sa->get_unique_id(ike_sa), ts);
! 200: }
! 201:
! 202: /**
! 203: * Install entry as a shunt policy
! 204: */
! 205: static job_requeue_t add_exclude_async(entry_t *entry)
! 206: {
! 207: enumerator_t *enumerator;
! 208: child_cfg_t *child_cfg;
! 209: child_cfg_create_t child = {
! 210: .mode = MODE_PASS,
! 211: };
! 212: ike_sa_t *ike_sa;
! 213: char name[128];
! 214: host_t *host;
! 215:
! 216: ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, entry->id);
! 217: if (ike_sa)
! 218: {
! 219: create_shunt_name(ike_sa, entry->ts, name, sizeof(name));
! 220:
! 221: child_cfg = child_cfg_create(name, &child);
! 222: child_cfg->add_traffic_selector(child_cfg, FALSE,
! 223: entry->ts->clone(entry->ts));
! 224: host = ike_sa->get_my_host(ike_sa);
! 225: child_cfg->add_traffic_selector(child_cfg, TRUE,
! 226: traffic_selector_create_from_subnet(host->clone(host),
! 227: 32, 0, 0, 65535));
! 228: enumerator = ike_sa->create_virtual_ip_enumerator(ike_sa, TRUE);
! 229: while (enumerator->enumerate(enumerator, &host))
! 230: {
! 231: child_cfg->add_traffic_selector(child_cfg, TRUE,
! 232: traffic_selector_create_from_subnet(host->clone(host),
! 233: 32, 0, 0, 65535));
! 234: }
! 235: enumerator->destroy(enumerator);
! 236: charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
! 237:
! 238: charon->shunts->install(charon->shunts, "unity", child_cfg);
! 239: child_cfg->destroy(child_cfg);
! 240:
! 241: DBG1(DBG_IKE, "installed %N bypass policy for %R",
! 242: configuration_attribute_type_names, UNITY_LOCAL_LAN, entry->ts);
! 243: }
! 244: return JOB_REQUEUE_NONE;
! 245: }
! 246:
! 247: /**
! 248: * Add a bypass policy for a given subnet
! 249: */
! 250: static bool add_exclude(private_unity_handler_t *this, chunk_t data)
! 251: {
! 252: traffic_selector_t *ts;
! 253: linked_list_t *list;
! 254: ike_sa_t *ike_sa;
! 255: entry_t *entry;
! 256:
! 257: ike_sa = charon->bus->get_sa(charon->bus);
! 258: if (!ike_sa)
! 259: {
! 260: return FALSE;
! 261: }
! 262: list = parse_subnets(data);
! 263: if (!list)
! 264: {
! 265: return FALSE;
! 266: }
! 267:
! 268: while (list->remove_first(list, (void**)&ts) == SUCCESS)
! 269: {
! 270: INIT(entry,
! 271: .id = ike_sa->get_id(ike_sa),
! 272: .ts = ts,
! 273: );
! 274: entry->id = entry->id->clone(entry->id);
! 275:
! 276: /* we can't install the shunt policy yet, as we don't know the virtual IP.
! 277: * Defer installation using an async callback. */
! 278: lib->processor->queue_job(lib->processor, (job_t*)
! 279: callback_job_create((void*)add_exclude_async, entry,
! 280: (void*)entry_destroy, NULL));
! 281: }
! 282: list->destroy(list);
! 283: return TRUE;
! 284: }
! 285:
! 286: /**
! 287: * Remove a bypass policy for a given subnet
! 288: */
! 289: static bool remove_exclude(private_unity_handler_t *this, chunk_t data)
! 290: {
! 291: traffic_selector_t *ts;
! 292: linked_list_t *list;
! 293: ike_sa_t *ike_sa;
! 294: char name[128];
! 295: bool success = TRUE;
! 296:
! 297: ike_sa = charon->bus->get_sa(charon->bus);
! 298: if (!ike_sa)
! 299: {
! 300: return FALSE;
! 301: }
! 302: list = parse_subnets(data);
! 303: if (!list)
! 304: {
! 305: return FALSE;
! 306: }
! 307: while (list->remove_first(list, (void**)&ts) == SUCCESS)
! 308: {
! 309: create_shunt_name(ike_sa, ts, name, sizeof(name));
! 310: DBG1(DBG_IKE, "uninstalling %N bypass policy for %R",
! 311: configuration_attribute_type_names, UNITY_LOCAL_LAN, ts);
! 312: ts->destroy(ts);
! 313: success = charon->shunts->uninstall(charon->shunts, "unity",
! 314: name) && success;
! 315: }
! 316: list->destroy(list);
! 317: return success;
! 318: }
! 319:
! 320: METHOD(attribute_handler_t, handle, bool,
! 321: private_unity_handler_t *this, ike_sa_t *ike_sa,
! 322: configuration_attribute_type_t type, chunk_t data)
! 323: {
! 324: switch (type)
! 325: {
! 326: case UNITY_SPLIT_INCLUDE:
! 327: return add_include(this, data);
! 328: case UNITY_LOCAL_LAN:
! 329: return add_exclude(this, data);
! 330: default:
! 331: return FALSE;
! 332: }
! 333: }
! 334:
! 335: METHOD(attribute_handler_t, release, void,
! 336: private_unity_handler_t *this, ike_sa_t *ike_sa,
! 337: configuration_attribute_type_t type, chunk_t data)
! 338: {
! 339: switch (type)
! 340: {
! 341: case UNITY_SPLIT_INCLUDE:
! 342: remove_include(this, data);
! 343: break;
! 344: case UNITY_LOCAL_LAN:
! 345: remove_exclude(this, data);
! 346: break;
! 347: default:
! 348: break;
! 349: }
! 350: }
! 351:
! 352: /**
! 353: * Configuration attributes to request
! 354: */
! 355: static configuration_attribute_type_t attributes[] = {
! 356: UNITY_SPLIT_INCLUDE,
! 357: UNITY_LOCAL_LAN,
! 358: };
! 359:
! 360: /**
! 361: * Attribute enumerator implementation
! 362: */
! 363: typedef struct {
! 364: /** implements enumerator_t */
! 365: enumerator_t public;
! 366: /** position in attributes[] */
! 367: int i;
! 368: } attribute_enumerator_t;
! 369:
! 370: METHOD(enumerator_t, enumerate_attributes, bool,
! 371: attribute_enumerator_t *this, va_list args)
! 372: {
! 373: configuration_attribute_type_t *type;
! 374: chunk_t *data;
! 375:
! 376: VA_ARGS_VGET(args, type, data);
! 377: if (this->i < countof(attributes))
! 378: {
! 379: *type = attributes[this->i++];
! 380: *data = chunk_empty;
! 381: return TRUE;
! 382: }
! 383: return FALSE;
! 384: }
! 385:
! 386: METHOD(attribute_handler_t, create_attribute_enumerator, enumerator_t *,
! 387: unity_handler_t *this, ike_sa_t *ike_sa, linked_list_t *vips)
! 388: {
! 389: attribute_enumerator_t *enumerator;
! 390:
! 391: ike_sa = charon->bus->get_sa(charon->bus);
! 392: if (!ike_sa || ike_sa->get_version(ike_sa) != IKEV1 ||
! 393: !ike_sa->supports_extension(ike_sa, EXT_CISCO_UNITY))
! 394: {
! 395: return enumerator_create_empty();
! 396: }
! 397: INIT(enumerator,
! 398: .public = {
! 399: .enumerate = enumerator_enumerate_default,
! 400: .venumerate = _enumerate_attributes,
! 401: .destroy = (void*)free,
! 402: },
! 403: );
! 404: return &enumerator->public;
! 405: }
! 406:
! 407: typedef struct {
! 408: /** mutex to unlock */
! 409: mutex_t *mutex;
! 410: /** IKE_SA ID to filter for */
! 411: ike_sa_id_t *id;
! 412: } include_filter_t;
! 413:
! 414: CALLBACK(include_filter, bool,
! 415: include_filter_t *data, enumerator_t *orig, va_list args)
! 416: {
! 417: entry_t *entry;
! 418: traffic_selector_t **ts;
! 419:
! 420: VA_ARGS_VGET(args, ts);
! 421:
! 422: while (orig->enumerate(orig, &entry))
! 423: {
! 424: if (data->id->equals(data->id, entry->id))
! 425: {
! 426: *ts = entry->ts;
! 427: return TRUE;
! 428: }
! 429: }
! 430: return FALSE;
! 431: }
! 432:
! 433: CALLBACK(destroy_filter, void,
! 434: include_filter_t *data)
! 435: {
! 436: data->mutex->unlock(data->mutex);
! 437: free(data);
! 438: }
! 439:
! 440: METHOD(unity_handler_t, create_include_enumerator, enumerator_t*,
! 441: private_unity_handler_t *this, ike_sa_id_t *id)
! 442: {
! 443: include_filter_t *data;
! 444:
! 445: INIT(data,
! 446: .mutex = this->mutex,
! 447: .id = id,
! 448: );
! 449: data->mutex->lock(data->mutex);
! 450: return enumerator_create_filter(
! 451: this->include->create_enumerator(this->include),
! 452: include_filter, data, destroy_filter);
! 453: }
! 454:
! 455: METHOD(unity_handler_t, destroy, void,
! 456: private_unity_handler_t *this)
! 457: {
! 458: this->include->destroy(this->include);
! 459: this->mutex->destroy(this->mutex);
! 460: free(this);
! 461: }
! 462:
! 463: /**
! 464: * See header
! 465: */
! 466: unity_handler_t *unity_handler_create()
! 467: {
! 468: private_unity_handler_t *this;
! 469:
! 470: INIT(this,
! 471: .public = {
! 472: .handler = {
! 473: .handle = _handle,
! 474: .release = _release,
! 475: .create_attribute_enumerator = _create_attribute_enumerator,
! 476: },
! 477: .create_include_enumerator = _create_include_enumerator,
! 478: .destroy = _destroy,
! 479: },
! 480: .include = linked_list_create(),
! 481: .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
! 482: );
! 483:
! 484: return &this->public;
! 485: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>