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