Annotation of embedaddon/strongswan/src/libcharon/plugins/ha/ha_cache.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (C) 2010 Martin Willi
3: * Copyright (C) 2010 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 "ha_cache.h"
17:
18: #include <collections/hashtable.h>
19: #include <collections/linked_list.h>
20: #include <threading/mutex.h>
21: #include <processing/jobs/callback_job.h>
22:
23: typedef struct private_ha_cache_t private_ha_cache_t;
24:
25: /**
26: * Private data of an ha_cache_t object.
27: */
28: struct private_ha_cache_t {
29:
30: /**
31: * Public ha_cache_t interface.
32: */
33: ha_cache_t public;
34:
35: /**
36: * Kernel helper functions
37: */
38: ha_kernel_t *kernel;
39:
40: /**
41: * Socket to send sync messages over
42: */
43: ha_socket_t *socket;
44:
45: /**
46: * Tunnel securing sync messages
47: */
48: ha_tunnel_t *tunnel;
49:
50: /**
51: * Total number of segments
52: */
53: u_int count;
54:
55: /**
56: * cached entries (ike_sa_t, entry_t)
57: */
58: hashtable_t *cache;
59:
60: /**
61: * Mutex to lock cache
62: */
63: mutex_t *mutex;
64: };
65:
66: /**
67: * Cache entry for an IKE_SA
68: */
69: typedef struct {
70: /* segment this entry is associate to */
71: u_int segment;
72: /* ADD message */
73: ha_message_t *add;
74: /* list of updates UPDATE message */
75: linked_list_t *updates;
76: /* last initiator mid */
77: ha_message_t *midi;
78: /* last responder mid */
79: ha_message_t *midr;
80: /* last IV update */
81: ha_message_t *iv;
82: } entry_t;
83:
84: /**
85: * Create a entry with an add message
86: */
87: static entry_t *entry_create(ha_message_t *add)
88: {
89: entry_t *entry;
90:
91: INIT(entry,
92: .add = add,
93: .updates = linked_list_create(),
94: );
95: return entry;
96: }
97:
98: /**
99: * clean up a entry
100: */
101: static void entry_destroy(entry_t *entry)
102: {
103: entry->updates->destroy_offset(entry->updates,
104: offsetof(ha_message_t, destroy));
105: entry->add->destroy(entry->add);
106: DESTROY_IF(entry->midi);
107: DESTROY_IF(entry->midr);
108: DESTROY_IF(entry->iv);
109: free(entry);
110: }
111:
112: METHOD(ha_cache_t, cache, void,
113: private_ha_cache_t *this, ike_sa_t *ike_sa, ha_message_t *message)
114: {
115: entry_t *entry;
116:
117: this->mutex->lock(this->mutex);
118: switch (message->get_type(message))
119: {
120: case HA_IKE_ADD:
121: entry = entry_create(message);
122: entry = this->cache->put(this->cache, ike_sa, entry);
123: if (entry)
124: {
125: entry_destroy(entry);
126: }
127: break;
128: case HA_IKE_UPDATE:
129: entry = this->cache->get(this->cache, ike_sa);
130: if (entry)
131: {
132: entry->segment = this->kernel->get_segment(this->kernel,
133: ike_sa->get_other_host(ike_sa));
134: entry->updates->insert_last(entry->updates, message);
135: break;
136: }
137: message->destroy(message);
138: break;
139: case HA_IKE_MID_INITIATOR:
140: entry = this->cache->get(this->cache, ike_sa);
141: if (entry)
142: {
143: DESTROY_IF(entry->midi);
144: entry->midi = message;
145: break;
146: }
147: message->destroy(message);
148: break;
149: case HA_IKE_MID_RESPONDER:
150: entry = this->cache->get(this->cache, ike_sa);
151: if (entry)
152: {
153: DESTROY_IF(entry->midr);
154: entry->midr = message;
155: break;
156: }
157: message->destroy(message);
158: break;
159: case HA_IKE_IV:
160: entry = this->cache->get(this->cache, ike_sa);
161: if (entry)
162: {
163: DESTROY_IF(entry->iv);
164: entry->iv = message;
165: break;
166: }
167: message->destroy(message);
168: break;
169: case HA_IKE_DELETE:
170: entry = this->cache->remove(this->cache, ike_sa);
171: if (entry)
172: {
173: entry_destroy(entry);
174: }
175: message->destroy(message);
176: break;
177: default:
178: message->destroy(message);
179: break;
180: }
181: this->mutex->unlock(this->mutex);
182: }
183:
184: METHOD(ha_cache_t, delete_, void,
185: private_ha_cache_t *this, ike_sa_t *ike_sa)
186: {
187: entry_t *entry;
188:
189: this->mutex->lock(this->mutex);
190: entry = this->cache->remove(this->cache, ike_sa);
191: if (entry)
192: {
193: entry_destroy(entry);
194: }
195: this->mutex->unlock(this->mutex);
196: }
197:
198: /**
199: * Rekey all children of an IKE_SA
200: */
201: static status_t rekey_children(ike_sa_t *ike_sa)
202: {
203: enumerator_t *enumerator;
204: child_sa_t *child_sa;
205: status_t status = SUCCESS;
206: linked_list_t *children;
207: struct {
208: protocol_id_t protocol;
209: uint32_t spi;
210: } *info;
211:
212: children = linked_list_create();
213: enumerator = ike_sa->create_child_sa_enumerator(ike_sa);
214: while (enumerator->enumerate(enumerator, &child_sa))
215: {
216: INIT(info,
217: .protocol = child_sa->get_protocol(child_sa),
218: .spi = child_sa->get_spi(child_sa, TRUE),
219: );
220: children->insert_last(children, info);
221: }
222: enumerator->destroy(enumerator);
223:
224: enumerator = children->create_enumerator(children);
225: while (enumerator->enumerate(enumerator, &info))
226: {
227: if (ike_sa->supports_extension(ike_sa, EXT_MS_WINDOWS) &&
228: ike_sa->has_condition(ike_sa, COND_NAT_THERE))
229: {
230: /* NATed Windows clients don't accept CHILD_SA rekeying, but fail
231: * with an "invalid situation" error. We just close the CHILD_SA,
232: * Windows will reestablish it immediately if required. */
233: DBG1(DBG_CFG, "resyncing CHILD_SA using a delete");
234: status = ike_sa->delete_child_sa(ike_sa, info->protocol, info->spi,
235: FALSE);
236: }
237: else
238: {
239: DBG1(DBG_CFG, "resyncing CHILD_SA using a rekey");
240: status = ike_sa->rekey_child_sa(ike_sa, info->protocol, info->spi);
241: }
242: if (status == DESTROY_ME)
243: {
244: break;
245: }
246: }
247: enumerator->destroy(enumerator);
248: children->destroy_function(children, free);
249:
250: return status;
251: }
252:
253: /**
254: * Trigger rekeying of CHILD_SA in segment
255: */
256: static void rekey_segment(private_ha_cache_t *this, u_int segment)
257: {
258: ike_sa_t *ike_sa;
259: enumerator_t *enumerator;
260: linked_list_t *list;
261: ike_sa_id_t *id;
262:
263: list = linked_list_create();
264:
265: enumerator = charon->ike_sa_manager->create_enumerator(
266: charon->ike_sa_manager, TRUE);
267: while (enumerator->enumerate(enumerator, &ike_sa))
268: {
269: if (this->tunnel && this->tunnel->is_sa(this->tunnel, ike_sa))
270: {
271: continue;
272: }
273: if (ike_sa->get_state(ike_sa) == IKE_ESTABLISHED &&
274: this->kernel->get_segment(this->kernel,
275: ike_sa->get_other_host(ike_sa)) == segment)
276: {
277: id = ike_sa->get_id(ike_sa);
278: list->insert_last(list, id->clone(id));
279: }
280: }
281: enumerator->destroy(enumerator);
282:
283: while (list->remove_last(list, (void**)&id) == SUCCESS)
284: {
285: ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, id);
286: if (ike_sa)
287: {
288: if (rekey_children(ike_sa) != DESTROY_ME)
289: {
290: charon->ike_sa_manager->checkin(
291: charon->ike_sa_manager, ike_sa);
292: }
293: else
294: {
295: charon->ike_sa_manager->checkin_and_destroy(
296: charon->ike_sa_manager, ike_sa);
297: }
298: }
299: id->destroy(id);
300: }
301: list->destroy(list);
302: }
303:
304: METHOD(ha_cache_t, resync, void,
305: private_ha_cache_t *this, u_int segment)
306: {
307: enumerator_t *enumerator, *updates;
308: ike_sa_t *ike_sa;
309: entry_t *entry;
310: ha_message_t *message;
311:
312: DBG1(DBG_CFG, "resyncing HA segment %d", segment);
313:
314: this->mutex->lock(this->mutex);
315: enumerator = this->cache->create_enumerator(this->cache);
316: while (enumerator->enumerate(enumerator, &ike_sa, &entry))
317: {
318: if (entry->segment == segment)
319: {
320: this->socket->push(this->socket, entry->add);
321: updates = entry->updates->create_enumerator(entry->updates);
322: while (updates->enumerate(updates, &message))
323: {
324: this->socket->push(this->socket, message);
325: }
326: updates->destroy(updates);
327: if (entry->midi)
328: {
329: this->socket->push(this->socket, entry->midi);
330: }
331: if (entry->midr)
332: {
333: this->socket->push(this->socket, entry->midr);
334: }
335: if (entry->iv)
336: {
337: this->socket->push(this->socket, entry->iv);
338: }
339: }
340: }
341: enumerator->destroy(enumerator);
342: this->mutex->unlock(this->mutex);
343:
344: rekey_segment(this, segment);
345: }
346:
347: /**
348: * Request a resync of all segments
349: */
350: static job_requeue_t request_resync(private_ha_cache_t *this)
351: {
352: ha_message_t *message;
353: int i;
354:
355: DBG1(DBG_CFG, "requesting HA resynchronization");
356:
357: message = ha_message_create(HA_RESYNC);
358: for (i = 1; i <= this->count; i++)
359: {
360: message->add_attribute(message, HA_SEGMENT, i);
361: }
362: this->socket->push(this->socket, message);
363: message->destroy(message);
364: return JOB_REQUEUE_NONE;
365: }
366:
367: METHOD(ha_cache_t, destroy, void,
368: private_ha_cache_t *this)
369: {
370: this->cache->destroy(this->cache);
371: this->mutex->destroy(this->mutex);
372: free(this);
373: }
374:
375: /**
376: * See header
377: */
378: ha_cache_t *ha_cache_create(ha_kernel_t *kernel, ha_socket_t *socket,
379: ha_tunnel_t *tunnel, bool sync, u_int count)
380: {
381: private_ha_cache_t *this;
382:
383: INIT(this,
384: .public = {
385: .cache = _cache,
386: .delete = _delete_,
387: .resync = _resync,
388: .destroy = _destroy,
389: },
390: .count = count,
391: .kernel = kernel,
392: .socket = socket,
393: .tunnel = tunnel,
394: .cache = hashtable_create(hashtable_hash_ptr, hashtable_equals_ptr, 8),
395: .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
396: );
397:
398: if (sync)
399: {
400: /* request a resync as soon as we are up */
401: lib->scheduler->schedule_job(lib->scheduler, (job_t*)
402: callback_job_create_with_prio((callback_job_cb_t)request_resync,
403: this, NULL, NULL, JOB_PRIO_CRITICAL), 1);
404: }
405: return &this->public;
406: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>