Annotation of embedaddon/strongswan/src/libcharon/sa/child_sa_manager.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (C) 2014 Martin Willi
3: * Copyright (C) 2014 revosec AG
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 "child_sa_manager.h"
17:
18: #include <daemon.h>
19: #include <threading/mutex.h>
20: #include <collections/hashtable.h>
21:
22: typedef struct private_child_sa_manager_t private_child_sa_manager_t;
23:
24: /**
25: * Private data of an child_sa_manager_t object.
26: */
27: struct private_child_sa_manager_t {
28:
29: /**
30: * Public child_sa_manager_t interface.
31: */
32: child_sa_manager_t public;
33:
34: /**
35: * CHILD_SAs by inbound SPI/dst, child_entry_t => child_entry_t
36: */
37: hashtable_t *in;
38:
39: /**
40: * CHILD_SAs by outbound SPI/dst, child_entry_t => child_entry_t
41: */
42: hashtable_t *out;
43:
44: /**
45: * CHILD_SAs by unique ID, child_entry_t => child_entry_t
46: */
47: hashtable_t *ids;
48:
49: /**
50: * Mutex to access any hashtable
51: */
52: mutex_t *mutex;
53: };
54:
55: /**
56: * Hashtable entry for a known CHILD_SA
57: */
58: typedef struct {
59: /** the associated IKE_SA */
60: ike_sa_id_t *ike_id;
61: /** unique CHILD_SA identifier */
62: uint32_t unique_id;
63: /** inbound SPI */
64: uint32_t spi_in;
65: /** outbound SPI */
66: uint32_t spi_out;
67: /** inbound host address */
68: host_t *host_in;
69: /** outbound host address and port */
70: host_t *host_out;
71: /** IPsec protocol, AH|ESP */
72: protocol_id_t proto;
73: } child_entry_t;
74:
75: /**
76: * Destroy a CHILD_SA entry
77: */
78: static void child_entry_destroy(child_entry_t *entry)
79: {
80: entry->ike_id->destroy(entry->ike_id);
81: entry->host_in->destroy(entry->host_in);
82: entry->host_out->destroy(entry->host_out);
83: free(entry);
84: }
85:
86: /**
87: * Hashtable hash function for inbound SAs
88: */
89: static u_int hash_in(child_entry_t *entry)
90: {
91: return chunk_hash_inc(chunk_from_thing(entry->spi_in),
92: chunk_hash_inc(entry->host_in->get_address(entry->host_in),
93: chunk_hash(chunk_from_thing(entry->proto))));
94: }
95:
96: /**
97: * Hashtable equals function for inbound SAs
98: */
99: static bool equals_in(child_entry_t *a, child_entry_t *b)
100: {
101: return a->spi_in == b->spi_in &&
102: a->proto == b->proto &&
103: a->host_in->ip_equals(a->host_in, b->host_in);
104: }
105:
106: /**
107: * Hashtable hash function for outbound SAs
108: */
109: static u_int hash_out(child_entry_t *entry)
110: {
111: return chunk_hash_inc(chunk_from_thing(entry->spi_out),
112: chunk_hash_inc(entry->host_out->get_address(entry->host_out),
113: chunk_hash(chunk_from_thing(entry->proto))));
114: }
115:
116: /**
117: * Hashtable equals function for outbound SAs
118: */
119: static bool equals_out(child_entry_t *a, child_entry_t *b)
120: {
121: return a->spi_out == b->spi_out &&
122: a->proto == b->proto &&
123: a->host_out->ip_equals(a->host_out, b->host_out);
124: }
125:
126: /**
127: * Hashtable hash function for SAs by unique ID
128: */
129: static u_int hash_id(child_entry_t *entry)
130: {
131: return chunk_hash(chunk_from_thing(entry->unique_id));
132: }
133:
134: /**
135: * Hashtable equals function for SAs by unique ID
136: */
137: static bool equals_id(child_entry_t *a, child_entry_t *b)
138: {
139: return a->unique_id == b->unique_id;
140: }
141:
142: METHOD(child_sa_manager_t, add, void,
143: private_child_sa_manager_t *this, child_sa_t *child_sa, ike_sa_t *ike_sa)
144: {
145: child_entry_t *entry;
146: host_t *in, *out;
147: ike_sa_id_t *id;
148:
149: id = ike_sa->get_id(ike_sa);
150: in = ike_sa->get_my_host(ike_sa);
151: out = ike_sa->get_other_host(ike_sa);
152:
153: INIT(entry,
154: .ike_id = id->clone(id),
155: .unique_id = child_sa->get_unique_id(child_sa),
156: .proto = child_sa->get_protocol(child_sa),
157: .spi_in = child_sa->get_spi(child_sa, TRUE),
158: .spi_out = child_sa->get_spi(child_sa, FALSE),
159: .host_in = in->clone(in),
160: .host_out = out->clone(out),
161: );
162:
163: this->mutex->lock(this->mutex);
164: if (!this->in->get(this->in, entry) &&
165: !this->out->get(this->out, entry))
166: {
167: this->in->put(this->in, entry, entry);
168: this->out->put(this->out, entry, entry);
169: entry = this->ids->put(this->ids, entry, entry);
170: }
171: this->mutex->unlock(this->mutex);
172:
173: if (entry)
174: {
175: child_entry_destroy(entry);
176: }
177: }
178:
179: METHOD(child_sa_manager_t, remove_, void,
180: private_child_sa_manager_t *this, child_sa_t *child_sa)
181: {
182: child_entry_t *entry, key = {
183: .unique_id = child_sa->get_unique_id(child_sa),
184: };
185:
186: this->mutex->lock(this->mutex);
187: entry = this->ids->remove(this->ids, &key);
188: if (entry)
189: {
190: this->in->remove(this->in, entry);
191: this->out->remove(this->out, entry);
192: }
193: this->mutex->unlock(this->mutex);
194:
195: if (entry)
196: {
197: child_entry_destroy(entry);
198: }
199: }
200:
201: /**
202: * Check out an IKE_SA for a given CHILD_SA
203: */
204: static ike_sa_t *checkout_ikesa(private_child_sa_manager_t *this,
205: ike_sa_id_t *id, uint32_t unique_id, child_sa_t **child_sa)
206: {
207: enumerator_t *enumerator;
208: child_sa_t *current;
209: ike_sa_t *ike_sa;
210: bool found = FALSE;
211:
212: ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, id);
213: id->destroy(id);
214: if (ike_sa)
215: {
216: enumerator = ike_sa->create_child_sa_enumerator(ike_sa);
217: while (enumerator->enumerate(enumerator, ¤t))
218: {
219: found = current->get_unique_id(current) == unique_id;
220: if (found)
221: {
222: if (child_sa)
223: {
224: *child_sa = current;
225: }
226: break;
227: }
228: }
229: enumerator->destroy(enumerator);
230:
231: if (found)
232: {
233: return ike_sa;
234: }
235: charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
236: }
237: return NULL;
238: }
239:
240: METHOD(child_sa_manager_t, checkout_by_id, ike_sa_t*,
241: private_child_sa_manager_t *this, uint32_t unique_id,
242: child_sa_t **child_sa)
243: {
244: ike_sa_id_t *id;
245: child_entry_t *entry, key = {
246: .unique_id = unique_id,
247: };
248:
249: this->mutex->lock(this->mutex);
250: entry = this->ids->get(this->ids, &key);
251: if (entry)
252: {
253: id = entry->ike_id->clone(entry->ike_id);
254: }
255: this->mutex->unlock(this->mutex);
256:
257: if (entry)
258: {
259: return checkout_ikesa(this, id, unique_id, child_sa);
260: }
261: return NULL;
262: }
263:
264: METHOD(child_sa_manager_t, checkout, ike_sa_t*,
265: private_child_sa_manager_t *this, protocol_id_t protocol, uint32_t spi,
266: host_t *dst, child_sa_t **child_sa)
267: {
268: ike_sa_id_t *id;
269: uint32_t unique_id;
270: child_entry_t *entry, key = {
271: .spi_in = spi,
272: .spi_out = spi,
273: .host_in = dst,
274: .host_out = dst,
275: .proto = protocol,
276: };
277:
278: this->mutex->lock(this->mutex);
279: entry = this->in->get(this->in, &key);
280: if (!entry)
281: {
282: entry = this->out->get(this->out, &key);
283: }
284: if (entry)
285: {
286: unique_id = entry->unique_id;
287: id = entry->ike_id->clone(entry->ike_id);
288: }
289: this->mutex->unlock(this->mutex);
290:
291: if (entry)
292: {
293: return checkout_ikesa(this, id, unique_id, child_sa);
294: }
295: return NULL;
296: }
297:
298: METHOD(child_sa_manager_t, destroy, void,
299: private_child_sa_manager_t *this)
300: {
301: this->in->destroy(this->in);
302: this->out->destroy(this->out);
303: this->ids->destroy(this->ids);
304: this->mutex->destroy(this->mutex);
305: free(this);
306: }
307:
308: /**
309: * See header
310: */
311: child_sa_manager_t *child_sa_manager_create()
312: {
313: private_child_sa_manager_t *this;
314:
315: INIT(this,
316: .public = {
317: .add = _add,
318: .remove = _remove_,
319: .checkout = _checkout,
320: .checkout_by_id = _checkout_by_id,
321: .destroy = _destroy,
322: },
323: .in = hashtable_create((hashtable_hash_t)hash_in,
324: (hashtable_equals_t)equals_in, 8),
325: .out = hashtable_create((hashtable_hash_t)hash_out,
326: (hashtable_equals_t)equals_out, 8),
327: .ids = hashtable_create((hashtable_hash_t)hash_id,
328: (hashtable_equals_t)equals_id, 8),
329: .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
330: );
331:
332: return &this->public;
333: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>