Annotation of embedaddon/strongswan/src/libcharon/sa/trap_manager.c, revision 1.1.1.2
1.1 misho 1: /*
2: * Copyright (C) 2011-2017 Tobias Brunner
3: * Copyright (C) 2009 Martin Willi
4: * HSR Hochschule fuer Technik Rapperswil
5: *
6: * This program is free software; you can redistribute it and/or modify it
7: * under the terms of the GNU General Public License as published by the
8: * Free Software Foundation; either version 2 of the License, or (at your
9: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10: *
11: * This program is distributed in the hope that it will be useful, but
12: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14: * for more details.
15: */
16:
17: #include "trap_manager.h"
18:
19: #include <daemon.h>
20: #include <threading/mutex.h>
21: #include <threading/rwlock.h>
22: #include <threading/rwlock_condvar.h>
23: #include <collections/linked_list.h>
24:
25: #define INSTALL_DISABLED ((u_int)~0)
26:
27: typedef struct private_trap_manager_t private_trap_manager_t;
28: typedef struct trap_listener_t trap_listener_t;
29:
30: /**
31: * listener to track acquires
32: */
33: struct trap_listener_t {
34:
35: /**
36: * Implements listener interface
37: */
38: listener_t listener;
39:
40: /**
41: * points to trap_manager
42: */
43: private_trap_manager_t *traps;
44: };
45:
46: /**
47: * Private data of an trap_manager_t object.
48: */
49: struct private_trap_manager_t {
50:
51: /**
52: * Public trap_manager_t interface.
53: */
54: trap_manager_t public;
55:
56: /**
57: * Installed traps, as entry_t
58: */
59: linked_list_t *traps;
60:
61: /**
62: * read write lock for traps list
63: */
64: rwlock_t *lock;
65:
66: /**
67: * listener to track acquiring IKE_SAs
68: */
69: trap_listener_t listener;
70:
71: /**
72: * list of acquires we currently handle
73: */
74: linked_list_t *acquires;
75:
76: /**
77: * mutex for list of acquires
78: */
79: mutex_t *mutex;
80:
81: /**
82: * number of threads currently installing trap policies, or INSTALL_DISABLED
83: */
84: u_int installing;
85:
86: /**
87: * condvar to signal trap policy installation
88: */
89: rwlock_condvar_t *condvar;
90:
91: /**
92: * Whether to ignore traffic selectors from acquires
93: */
94: bool ignore_acquire_ts;
95: };
96:
97: /**
98: * A installed trap entry
99: */
100: typedef struct {
101: /** name of the trapped CHILD_SA */
102: char *name;
103: /** ref to peer_cfg to initiate */
104: peer_cfg_t *peer_cfg;
105: /** ref to instantiated CHILD_SA (i.e the trap policy) */
106: child_sa_t *child_sa;
107: /** TRUE in case of wildcard Transport Mode SA */
108: bool wildcard;
109: } entry_t;
110:
111: /**
112: * A handled acquire
113: */
114: typedef struct {
115: /** pending IKE_SA connecting upon acquire */
116: ike_sa_t *ike_sa;
117: /** reqid of pending trap policy */
118: uint32_t reqid;
119: /** destination address (wildcard case) */
120: host_t *dst;
121: } acquire_t;
122:
123: /**
124: * actually uninstall and destroy an installed entry
125: */
126: static void destroy_entry(entry_t *this)
127: {
128: this->child_sa->destroy(this->child_sa);
129: this->peer_cfg->destroy(this->peer_cfg);
130: free(this->name);
131: free(this);
132: }
133:
134: /**
135: * destroy a cached acquire entry
136: */
137: static void destroy_acquire(acquire_t *this)
138: {
139: DESTROY_IF(this->dst);
140: free(this);
141: }
142:
143: CALLBACK(acquire_by_reqid, bool,
144: acquire_t *this, va_list args)
145: {
146: uint32_t reqid;
147:
148: VA_ARGS_VGET(args, reqid);
149: return this->reqid == reqid;
150: }
151:
152: CALLBACK(acquire_by_dst, bool,
153: acquire_t *this, va_list args)
154: {
155: host_t *dst;
156:
157: VA_ARGS_VGET(args, dst);
158: return this->dst && this->dst->ip_equals(this->dst, dst);
159: }
160:
161: /**
162: * Check if any remote TS are dynamic
163: */
164: static bool dynamic_remote_ts(child_cfg_t *child)
165: {
166: enumerator_t *enumerator;
167: linked_list_t *other_ts;
168: traffic_selector_t *ts;
169: bool found = FALSE;
170:
171: other_ts = child->get_traffic_selectors(child, FALSE, NULL, NULL, FALSE);
172: enumerator = other_ts->create_enumerator(other_ts);
173: while (enumerator->enumerate(enumerator, &ts))
174: {
175: if (ts->is_dynamic(ts))
176: {
177: found = TRUE;
178: break;
179: }
180: }
181: enumerator->destroy(enumerator);
182: other_ts->destroy_offset(other_ts, offsetof(traffic_selector_t, destroy));
183: return found;
184: }
185:
186: METHOD(trap_manager_t, install, bool,
187: private_trap_manager_t *this, peer_cfg_t *peer, child_cfg_t *child)
188: {
189: entry_t *entry, *found = NULL;
190: ike_cfg_t *ike_cfg;
191: child_sa_t *child_sa;
192: host_t *me, *other;
193: linked_list_t *my_ts, *other_ts, *list;
194: enumerator_t *enumerator;
195: status_t status;
196: linked_list_t *proposals;
197: proposal_t *proposal;
198: protocol_id_t proto = PROTO_ESP;
199: bool result = FALSE, wildcard = FALSE;
200:
201: /* try to resolve addresses */
202: ike_cfg = peer->get_ike_cfg(peer);
203: other = ike_cfg->resolve_other(ike_cfg, AF_UNSPEC);
204: if (other && other->is_anyaddr(other) &&
205: child->get_mode(child) == MODE_TRANSPORT)
206: {
207: /* allow wildcard for Transport Mode SAs */
208: me = host_create_any(other->get_family(other));
209: wildcard = TRUE;
210: }
211: else if (other && other->is_anyaddr(other))
212: {
213: other->destroy(other);
214: DBG1(DBG_CFG, "installing trap failed, remote address unknown");
215: return FALSE;
216: }
217: else
218: { /* depending on the traffic selectors we don't really need a remote
219: * host yet, but we might fail later if no IP can be resolved */
220: if (!other && dynamic_remote_ts(child))
221: { /* with dynamic TS we do need a host, otherwise 0.0.0.0/0 is used,
222: * which is probably not what users expect*/
223: DBG1(DBG_CFG, "installing trap failed, remote address unknown with "
224: "dynamic traffic selector");
225: return FALSE;
226: }
227: me = ike_cfg->resolve_me(ike_cfg, other ? other->get_family(other)
228: : AF_UNSPEC);
229: if (!other)
230: {
231: other = host_create_any(me ? me->get_family(me) : AF_INET);
232: }
233: other->set_port(other, ike_cfg->get_other_port(ike_cfg));
234: if ((!me || me->is_anyaddr(me)) && !other->is_anyaddr(other))
235: {
236: DESTROY_IF(me);
237: me = charon->kernel->get_source_addr(charon->kernel, other, NULL);
238: }
239: if (!me)
240: {
241: me = host_create_any(other->get_family(other));
242: }
243: me->set_port(me, ike_cfg->get_my_port(ike_cfg));
244: }
245:
246: this->lock->write_lock(this->lock);
247: if (this->installing == INSTALL_DISABLED)
248: { /* flush() has been called */
249: this->lock->unlock(this->lock);
250: other->destroy(other);
251: me->destroy(me);
252: return FALSE;
253: }
254: enumerator = this->traps->create_enumerator(this->traps);
255: while (enumerator->enumerate(enumerator, &entry))
256: {
257: if (streq(entry->name, child->get_name(child)) &&
258: streq(entry->peer_cfg->get_name(entry->peer_cfg),
259: peer->get_name(peer)))
260: {
261: found = entry;
262: if (entry->child_sa)
263: { /* replace it with an updated version, if already installed */
264: this->traps->remove_at(this->traps, enumerator);
265: }
266: break;
267: }
268: }
269: enumerator->destroy(enumerator);
270:
271: if (found)
272: {
273: if (!found->child_sa)
274: {
275: DBG1(DBG_CFG, "CHILD_SA '%s' is already being routed", found->name);
276: this->lock->unlock(this->lock);
277: other->destroy(other);
278: me->destroy(me);
279: return FALSE;
280: }
281: /* config might have changed so update everything */
282: DBG1(DBG_CFG, "updating already routed CHILD_SA '%s'", found->name);
283: }
284:
285: INIT(entry,
286: .name = strdup(child->get_name(child)),
287: .peer_cfg = peer->get_ref(peer),
288: .wildcard = wildcard,
289: );
290: this->traps->insert_first(this->traps, entry);
291: this->installing++;
292: /* don't hold lock while creating CHILD_SA and installing policies */
293: this->lock->unlock(this->lock);
294:
295: /* create and route CHILD_SA */
296: child_sa_create_t child_data = {
297: /* TODO: no reason to allocate unique interface IDs, there is currently
298: * no event to use them upon trap installation and we'd also have to
299: * pass them in a later initiate() call */
300: .if_id_in_def = peer->get_if_id(peer, TRUE),
301: .if_id_out_def = peer->get_if_id(peer, FALSE),
302: };
303: child_sa = child_sa_create(me, other, child, &child_data);
304:
305: list = linked_list_create_with_items(me, NULL);
306: my_ts = child->get_traffic_selectors(child, TRUE, NULL, list, FALSE);
307: list->destroy_offset(list, offsetof(host_t, destroy));
308:
309: list = linked_list_create_with_items(other, NULL);
310: other_ts = child->get_traffic_selectors(child, FALSE, NULL, list, FALSE);
311: list->destroy_offset(list, offsetof(host_t, destroy));
312:
313: /* We don't know the finally negotiated protocol (ESP|AH), we install
314: * the SA with the protocol of the first proposal */
315: proposals = child->get_proposals(child, TRUE);
316: if (proposals->get_first(proposals, (void**)&proposal) == SUCCESS)
317: {
318: proto = proposal->get_protocol(proposal);
319: }
320: proposals->destroy_offset(proposals, offsetof(proposal_t, destroy));
321: child_sa->set_protocol(child_sa, proto);
322: child_sa->set_mode(child_sa, child->get_mode(child));
323: child_sa->set_policies(child_sa, my_ts, other_ts);
324: status = child_sa->install_policies(child_sa);
325: my_ts->destroy_offset(my_ts, offsetof(traffic_selector_t, destroy));
326: other_ts->destroy_offset(other_ts, offsetof(traffic_selector_t, destroy));
327: if (status != SUCCESS)
328: {
329: DBG1(DBG_CFG, "installing trap failed");
330: this->lock->write_lock(this->lock);
331: this->traps->remove(this->traps, entry, NULL);
332: this->lock->unlock(this->lock);
333: entry->child_sa = child_sa;
334: destroy_entry(entry);
335: }
336: else
337: {
338: this->lock->write_lock(this->lock);
339: entry->child_sa = child_sa;
340: this->lock->unlock(this->lock);
341: result = TRUE;
342: }
343: if (found)
344: {
345: destroy_entry(found);
346: }
347: this->lock->write_lock(this->lock);
348: /* do this at the end, so entries created temporarily are also destroyed */
349: this->installing--;
350: this->condvar->signal(this->condvar);
351: this->lock->unlock(this->lock);
352: return result;
353: }
354:
355: METHOD(trap_manager_t, uninstall, bool,
356: private_trap_manager_t *this, char *peer, char *child)
357: {
358: enumerator_t *enumerator;
359: entry_t *entry, *found = NULL;
360:
361: this->lock->write_lock(this->lock);
362: while (this->installing)
363: {
364: this->condvar->wait(this->condvar, this->lock);
365: }
366: enumerator = this->traps->create_enumerator(this->traps);
367: while (enumerator->enumerate(enumerator, &entry))
368: {
369: if (streq(entry->name, child) &&
370: (!peer || streq(peer, entry->peer_cfg->get_name(entry->peer_cfg))))
371: {
372: this->traps->remove_at(this->traps, enumerator);
373: found = entry;
374: break;
375: }
376: }
377: enumerator->destroy(enumerator);
378: this->lock->unlock(this->lock);
379:
380: if (!found)
381: {
382: return FALSE;
383: }
384: destroy_entry(found);
385: return TRUE;
386: }
387:
388: CALLBACK(trap_filter, bool,
389: rwlock_t *lock, enumerator_t *orig, va_list args)
390: {
391: entry_t *entry;
392: peer_cfg_t **peer_cfg;
393: child_sa_t **child_sa;
394:
395: VA_ARGS_VGET(args, peer_cfg, child_sa);
396:
397: while (orig->enumerate(orig, &entry))
398: {
399: if (!entry->child_sa)
400: { /* skip entries that are currently being installed */
401: continue;
402: }
403: if (peer_cfg)
404: {
405: *peer_cfg = entry->peer_cfg;
406: }
407: if (child_sa)
408: {
409: *child_sa = entry->child_sa;
410: }
411: return TRUE;
412: }
413: return FALSE;
414: }
415:
416: METHOD(trap_manager_t, create_enumerator, enumerator_t*,
417: private_trap_manager_t *this)
418: {
419: this->lock->read_lock(this->lock);
420: return enumerator_create_filter(this->traps->create_enumerator(this->traps),
421: trap_filter, this->lock,
422: (void*)this->lock->unlock);
423: }
424:
425: METHOD(trap_manager_t, acquire, void,
426: private_trap_manager_t *this, uint32_t reqid,
427: traffic_selector_t *src, traffic_selector_t *dst)
428: {
429: enumerator_t *enumerator;
430: entry_t *entry, *found = NULL;
431: acquire_t *acquire;
432: peer_cfg_t *peer;
433: child_cfg_t *child;
434: ike_sa_t *ike_sa;
435: host_t *host;
436: bool wildcard, ignore = FALSE;
437:
438: this->lock->read_lock(this->lock);
439: enumerator = this->traps->create_enumerator(this->traps);
440: while (enumerator->enumerate(enumerator, &entry))
441: {
442: if (entry->child_sa &&
443: entry->child_sa->get_reqid(entry->child_sa) == reqid)
444: {
445: found = entry;
446: break;
447: }
448: }
449: enumerator->destroy(enumerator);
450:
451: if (!found)
452: {
453: DBG1(DBG_CFG, "trap not found, unable to acquire reqid %d", reqid);
454: this->lock->unlock(this->lock);
455: return;
456: }
457: reqid = found->child_sa->get_reqid(found->child_sa);
458: wildcard = found->wildcard;
459:
460: this->mutex->lock(this->mutex);
461: if (wildcard)
462: { /* for wildcard acquires we check that we don't have a pending acquire
463: * with the same peer */
464: uint8_t mask;
465:
466: dst->to_subnet(dst, &host, &mask);
467: if (this->acquires->find_first(this->acquires, acquire_by_dst,
468: (void**)&acquire, host))
469: {
470: host->destroy(host);
471: ignore = TRUE;
472: }
473: else
474: {
475: INIT(acquire,
476: .dst = host,
477: .reqid = reqid,
478: );
479: this->acquires->insert_last(this->acquires, acquire);
480: }
481: }
482: else
483: {
484: if (this->acquires->find_first(this->acquires, acquire_by_reqid,
485: (void**)&acquire, reqid))
486: {
487: ignore = TRUE;
488: }
489: else
490: {
491: INIT(acquire,
492: .reqid = reqid,
493: );
494: this->acquires->insert_last(this->acquires, acquire);
495: }
496: }
497: this->mutex->unlock(this->mutex);
498: if (ignore)
499: {
500: DBG1(DBG_CFG, "ignoring acquire, connection attempt pending");
501: this->lock->unlock(this->lock);
502: return;
503: }
504: peer = found->peer_cfg->get_ref(found->peer_cfg);
505: child = found->child_sa->get_config(found->child_sa);
506: child = child->get_ref(child);
507: /* don't hold the lock while checking out the IKE_SA */
508: this->lock->unlock(this->lock);
509:
510: if (wildcard)
511: { /* the peer config would match IKE_SAs with other peers */
1.1.1.2 ! misho 512: ike_sa = charon->ike_sa_manager->create_new(charon->ike_sa_manager,
1.1 misho 513: peer->get_ike_version(peer), TRUE);
514: if (ike_sa)
515: {
516: ike_cfg_t *ike_cfg;
517: uint16_t port;
518: uint8_t mask;
519:
520: ike_sa->set_peer_cfg(ike_sa, peer);
521: ike_cfg = ike_sa->get_ike_cfg(ike_sa);
522:
523: port = ike_cfg->get_other_port(ike_cfg);
524: dst->to_subnet(dst, &host, &mask);
525: host->set_port(host, port);
526: ike_sa->set_other_host(ike_sa, host);
527:
528: port = ike_cfg->get_my_port(ike_cfg);
529: src->to_subnet(src, &host, &mask);
530: host->set_port(host, port);
531: ike_sa->set_my_host(ike_sa, host);
532:
533: charon->bus->set_sa(charon->bus, ike_sa);
534: }
535: }
536: else
537: {
538: ike_sa = charon->ike_sa_manager->checkout_by_config(
539: charon->ike_sa_manager, peer);
540: }
1.1.1.2 ! misho 541: peer->destroy(peer);
! 542:
1.1 misho 543: if (ike_sa)
544: {
545: if (this->ignore_acquire_ts || ike_sa->get_version(ike_sa) == IKEV1)
546: { /* in IKEv1, don't prepend the acquiring packet TS, as we only
547: * have a single TS that we can establish in a Quick Mode. */
548: src = dst = NULL;
549: }
550:
551: this->mutex->lock(this->mutex);
552: acquire->ike_sa = ike_sa;
553: this->mutex->unlock(this->mutex);
554:
555: if (ike_sa->initiate(ike_sa, child, reqid, src, dst) != DESTROY_ME)
556: {
557: charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
558: }
559: else
560: {
561: charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager,
562: ike_sa);
563: }
564: }
565: else
566: {
567: this->mutex->lock(this->mutex);
568: this->acquires->remove(this->acquires, acquire, NULL);
569: this->mutex->unlock(this->mutex);
570: destroy_acquire(acquire);
571: child->destroy(child);
572: }
573: }
574:
575: /**
576: * Complete the acquire, if successful or failed
577: */
578: static void complete(private_trap_manager_t *this, ike_sa_t *ike_sa,
579: child_sa_t *child_sa)
580: {
581: enumerator_t *enumerator;
582: acquire_t *acquire;
583:
584: this->mutex->lock(this->mutex);
585: enumerator = this->acquires->create_enumerator(this->acquires);
586: while (enumerator->enumerate(enumerator, &acquire))
587: {
588: if (!acquire->ike_sa || acquire->ike_sa != ike_sa)
589: {
590: continue;
591: }
592: if (child_sa)
593: {
594: if (acquire->dst)
595: {
596: /* since every wildcard acquire results in a separate IKE_SA
597: * there is no need to compare the destination address */
598: }
599: else if (child_sa->get_reqid(child_sa) != acquire->reqid)
600: {
601: continue;
602: }
603: }
604: this->acquires->remove_at(this->acquires, enumerator);
605: destroy_acquire(acquire);
606: }
607: enumerator->destroy(enumerator);
608: this->mutex->unlock(this->mutex);
609: }
610:
611: METHOD(listener_t, ike_state_change, bool,
612: trap_listener_t *listener, ike_sa_t *ike_sa, ike_sa_state_t state)
613: {
614: switch (state)
615: {
616: case IKE_DESTROYING:
617: complete(listener->traps, ike_sa, NULL);
618: return TRUE;
619: default:
620: return TRUE;
621: }
622: }
623:
624: METHOD(listener_t, child_state_change, bool,
625: trap_listener_t *listener, ike_sa_t *ike_sa, child_sa_t *child_sa,
626: child_sa_state_t state)
627: {
628: switch (state)
629: {
630: case CHILD_INSTALLED:
631: case CHILD_DESTROYING:
632: complete(listener->traps, ike_sa, child_sa);
633: return TRUE;
634: default:
635: return TRUE;
636: }
637: }
638:
639: METHOD(trap_manager_t, flush, void,
640: private_trap_manager_t *this)
641: {
642: this->lock->write_lock(this->lock);
643: while (this->installing)
644: {
645: this->condvar->wait(this->condvar, this->lock);
646: }
647: this->traps->destroy_function(this->traps, (void*)destroy_entry);
648: this->traps = linked_list_create();
649: this->installing = INSTALL_DISABLED;
650: this->lock->unlock(this->lock);
651: }
652:
653: METHOD(trap_manager_t, destroy, void,
654: private_trap_manager_t *this)
655: {
656: charon->bus->remove_listener(charon->bus, &this->listener.listener);
657: this->traps->destroy_function(this->traps, (void*)destroy_entry);
658: this->acquires->destroy_function(this->acquires, (void*)destroy_acquire);
659: this->condvar->destroy(this->condvar);
660: this->mutex->destroy(this->mutex);
661: this->lock->destroy(this->lock);
662: free(this);
663: }
664:
665: /**
666: * See header
667: */
668: trap_manager_t *trap_manager_create(void)
669: {
670: private_trap_manager_t *this;
671:
672: INIT(this,
673: .public = {
674: .install = _install,
675: .uninstall = _uninstall,
676: .create_enumerator = _create_enumerator,
677: .acquire = _acquire,
678: .flush = _flush,
679: .destroy = _destroy,
680: },
681: .listener = {
682: .traps = this,
683: .listener = {
684: .ike_state_change = _ike_state_change,
685: .child_state_change = _child_state_change,
686: },
687: },
688: .traps = linked_list_create(),
689: .acquires = linked_list_create(),
690: .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
691: .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
692: .condvar = rwlock_condvar_create(),
693: .ignore_acquire_ts = lib->settings->get_bool(lib->settings,
694: "%s.ignore_acquire_ts", FALSE, lib->ns),
695: );
696: charon->bus->add_listener(charon->bus, &this->listener.listener);
697:
698: return &this->public;
699: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>