Annotation of embedaddon/strongswan/src/libcharon/plugins/duplicheck/duplicheck_listener.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (C) 2011 Martin Willi
3: * Copyright (C) 2011 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 "duplicheck_listener.h"
17:
18: #include <daemon.h>
19: #include <threading/mutex.h>
20: #include <collections/hashtable.h>
21: #include <encoding/payloads/delete_payload.h>
22: #include <processing/jobs/delete_ike_sa_job.h>
23:
24: typedef struct private_duplicheck_listener_t private_duplicheck_listener_t;
25:
26: /**
27: * Private data of an duplicheck_listener_t object.
28: */
29: struct private_duplicheck_listener_t {
30:
31: /**
32: * Public duplicheck_listener_t interface.
33: */
34: duplicheck_listener_t public;
35:
36: /**
37: * Socket to send notifications to
38: */
39: duplicheck_notify_t *notify;
40:
41: /**
42: * Mutex to lock hashtables
43: */
44: mutex_t *mutex;
45:
46: /**
47: * Hashtable of active IKE_SAs, identification_t => entry_t
48: */
49: hashtable_t *active;
50:
51: /**
52: * Hashtable with active liveness checks, identification_t => entry_t
53: */
54: hashtable_t *checking;
55: };
56:
57: /**
58: * Entry for hashtables
59: */
60: typedef struct {
61: /** peer identity */
62: identification_t *id;
63: /** list of IKE_SA identifiers, ike_sa_id_t */
64: linked_list_t *sas;
65: } entry_t;
66:
67: /**
68: * Destroy a hashtable entry
69: */
70: static void entry_destroy(entry_t *this)
71: {
72: this->id->destroy(this->id);
73: this->sas->destroy_offset(this->sas, offsetof(ike_sa_id_t, destroy));
74: free(this);
75: }
76:
77: /**
78: * Hashtable hash function
79: */
80: static u_int hash(identification_t *key)
81: {
82: return chunk_hash(key->get_encoding(key));
83: }
84:
85: /**
86: * Hashtable equals function
87: */
88: static bool equals(identification_t *a, identification_t *b)
89: {
90: return a->equals(a, b);
91: }
92:
93: /**
94: * Put an IKE_SA identifier to hashtable
95: */
96: static void put(hashtable_t *table, identification_t *id, ike_sa_id_t *sa)
97: {
98: entry_t *entry;
99:
100: entry = table->get(table, id);
101: if (!entry)
102: {
103: INIT(entry,
104: .id = id->clone(id),
105: .sas = linked_list_create(),
106: );
107: table->put(table, entry->id, entry);
108: }
109: entry->sas->insert_last(entry->sas, sa->clone(sa));
110: }
111:
112: /**
113: * Purge an entry from table if it has no IKE_SA identifiers
114: */
115: static void remove_if_empty(hashtable_t *table, entry_t *entry)
116: {
117: if (entry->sas->get_count(entry->sas) == 0)
118: {
119: entry = table->remove(table, entry->id);
120: if (entry)
121: {
122: entry_destroy(entry);
123: }
124: }
125: }
126:
127: /**
128: * Remove the first entry found in the table for the given id
129: */
130: static ike_sa_id_t *remove_first(hashtable_t *table, identification_t *id)
131: {
132: ike_sa_id_t *sa = NULL;
133: entry_t *entry;
134:
135: entry = table->get(table, id);
136: if (entry)
137: {
138: entry->sas->remove_first(entry->sas, (void**)&sa);
139: remove_if_empty(table, entry);
140: }
141: return sa;
142: }
143:
144: /**
145: * Remove a specific IKE_SA ID for the given identity
146: */
147: static bool remove_specific(hashtable_t *table, identification_t *id,
148: ike_sa_id_t *sa)
149: {
150: enumerator_t *enumerator;
151: bool found = FALSE;
152: entry_t *entry;
153: ike_sa_id_t *current;
154:
155: entry = table->get(table, id);
156: if (entry)
157: {
158: enumerator = entry->sas->create_enumerator(entry->sas);
159: while (enumerator->enumerate(enumerator, ¤t))
160: {
161: if (sa->equals(sa, current))
162: {
163: entry->sas->remove_at(entry->sas, enumerator);
164: current->destroy(current);
165: found = TRUE;
166: break;
167: }
168: }
169: enumerator->destroy(enumerator);
170: if (found)
171: {
172: remove_if_empty(table, entry);
173: }
174: }
175: return found;
176: }
177:
178: METHOD(listener_t, ike_rekey, bool,
179: private_duplicheck_listener_t *this, ike_sa_t *old, ike_sa_t *new)
180: {
181: this->mutex->lock(this->mutex);
182:
183: remove_specific(this->active, old->get_other_id(old), old->get_id(old));
184: put(this->active, new->get_other_id(new), new->get_id(new));
185:
186: this->mutex->unlock(this->mutex);
187:
188: return TRUE;
189: }
190:
191: METHOD(listener_t, ike_updown, bool,
192: private_duplicheck_listener_t *this, ike_sa_t *ike_sa, bool up)
193: {
194: identification_t *id;
195: ike_sa_id_t *sa;
196:
197: id = ike_sa->get_other_id(ike_sa);
198:
199: this->mutex->lock(this->mutex);
200: if (up)
201: {
202: /* another IKE_SA for this identity active? */
203: sa = remove_first(this->active, id);
204: if (sa)
205: {
206: DBG1(DBG_CFG, "detected duplicate IKE_SA for '%Y', "
207: "triggering delete for old IKE_SA", id);
208: put(this->checking, id, sa);
209: lib->processor->queue_job(lib->processor,
210: (job_t*)delete_ike_sa_job_create(sa, TRUE));
211: sa->destroy(sa);
212: }
213: /* register IKE_SA as the new active */
214: sa = ike_sa->get_id(ike_sa);
215: put(this->active, id, sa);
216: }
217: else
218: {
219: sa = ike_sa->get_id(ike_sa);
220: /* check if closing an IKE_SA currently in checking state */
221: if (remove_specific(this->checking, id, sa))
222: {
223: DBG1(DBG_CFG, "delete for duplicate IKE_SA '%Y' timed out, "
224: "keeping new IKE_SA", id);
225: }
226: /* check normal close of IKE_SA */
227: remove_specific(this->active, id, sa);
228: }
229: this->mutex->unlock(this->mutex);
230:
231: return TRUE;
232: }
233:
234: METHOD(listener_t, message_hook, bool,
235: private_duplicheck_listener_t *this, ike_sa_t *ike_sa,
236: message_t *message, bool incoming, bool plain)
237: {
238: if (incoming && plain && !message->get_request(message))
239: {
240: identification_t *id;
241: ike_sa_id_t *sa;
242:
243: id = ike_sa->get_other_id(ike_sa);
244: sa = ike_sa->get_id(ike_sa);
245:
246: this->mutex->lock(this->mutex);
247: if (remove_specific(this->checking, id, sa))
248: {
249: DBG1(DBG_CFG, "got a response on a duplicate IKE_SA for '%Y', "
250: "deleting new IKE_SA", id);
251: charon->bus->alert(charon->bus, ALERT_UNIQUE_KEEP);
252: sa = remove_first(this->active, id);
253: if (sa)
254: {
255: lib->processor->queue_job(lib->processor,
256: (job_t*)delete_ike_sa_job_create(sa, TRUE));
257: sa->destroy(sa);
258: }
259: this->mutex->unlock(this->mutex);
260:
261: this->notify->send(this->notify, id);
262: }
263: else
264: {
265: this->mutex->unlock(this->mutex);
266: }
267: }
268: return TRUE;
269: }
270:
271: METHOD(duplicheck_listener_t, destroy, void,
272: private_duplicheck_listener_t *this)
273: {
274: enumerator_t *enumerator;
275: identification_t *key;
276: entry_t *value;
277:
278: enumerator = this->active->create_enumerator(this->active);
279: while (enumerator->enumerate(enumerator, &key, &value))
280: {
281: entry_destroy(value);
282: }
283: enumerator->destroy(enumerator);
284:
285: enumerator = this->checking->create_enumerator(this->checking);
286: while (enumerator->enumerate(enumerator, &key, &value))
287: {
288: entry_destroy(value);
289: }
290: enumerator->destroy(enumerator);
291:
292: this->active->destroy(this->active);
293: this->checking->destroy(this->checking);
294: this->mutex->destroy(this->mutex);
295: free(this);
296: }
297:
298: /**
299: * See header
300: */
301: duplicheck_listener_t *duplicheck_listener_create(duplicheck_notify_t *notify)
302: {
303: private_duplicheck_listener_t *this;
304:
305: INIT(this,
306: .public = {
307: .listener = {
308: .ike_rekey = _ike_rekey,
309: .ike_updown = _ike_updown,
310: .message = _message_hook,
311: },
312: .destroy = _destroy,
313: },
314: .notify = notify,
315: .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
316: .active = hashtable_create((hashtable_hash_t)hash,
317: (hashtable_equals_t)equals, 32),
318: .checking = hashtable_create((hashtable_hash_t)hash,
319: (hashtable_equals_t)equals, 2),
320: );
321:
322: return &this->public;
323: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>