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