Annotation of embedaddon/strongswan/src/libcharon/plugins/lookip/lookip_listener.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (C) 2012 Martin Willi
3: * Copyright (C) 2012 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 "lookip_listener.h"
17:
18: #include <daemon.h>
19: #include <collections/hashtable.h>
20: #include <collections/linked_list.h>
21: #include <threading/rwlock.h>
22:
23: typedef struct private_lookip_listener_t private_lookip_listener_t;
24:
25: /**
26: * Private data of an lookip_listener_t object.
27: */
28: struct private_lookip_listener_t {
29:
30: /**
31: * Public lookip_listener_t interface.
32: */
33: lookip_listener_t public;
34:
35: /**
36: * Lock for hashtable
37: */
38: rwlock_t *lock;
39:
40: /**
41: * Hashtable with entries: host_t => entry_t
42: */
43: hashtable_t *entries;
44:
45: /**
46: * List of registered listeners
47: */
48: linked_list_t *listeners;
49: };
50:
51: /**
52: * Listener entry
53: */
54: typedef struct {
55: /** callback function */
56: lookip_callback_t cb;
57: /** user data for callback */
58: void *user;
59: } listener_entry_t;
60:
61: /**
62: * Hashtable entry
63: */
64: typedef struct {
65: /** virtual IP, serves as lookup key */
66: host_t *vip;
67: /** peers external address */
68: host_t *other;
69: /** peer (EAP-)Identity */
70: identification_t *id;
71: /** associated connection name */
72: char *name;
73: /** IKE_SA unique identifier */
74: u_int unique_id;
75: } entry_t;
76:
77: /**
78: * Destroy a hashtable entry
79: */
80: static void entry_destroy(entry_t *entry)
81: {
82: entry->vip->destroy(entry->vip);
83: entry->other->destroy(entry->other);
84: entry->id->destroy(entry->id);
85: free(entry->name);
86: free(entry);
87: }
88:
89: /**
90: * Hashtable hash function
91: */
92: static u_int hash(host_t *key)
93: {
94: return chunk_hash(key->get_address(key));
95: }
96:
97: /**
98: * Hashtable equals function
99: */
100: static bool equals(host_t *a, host_t *b)
101: {
102: return a->ip_equals(a, b);
103: }
104:
105: /**
106: * Compare callback that invokes up callback of all registered listeners
107: */
108: static bool notify_up(listener_entry_t *listener, entry_t *entry)
109: {
110: if (!listener->cb(listener->user, TRUE, entry->vip, entry->other,
111: entry->id, entry->name, entry->unique_id))
112: {
113: free(listener);
114: return TRUE;
115: }
116: return FALSE;
117: }
118:
119: /**
120: * Compare callback that invokes down callback of all registered listeners
121: */
122: static bool notify_down(listener_entry_t *listener, entry_t *entry)
123: {
124: if (!listener->cb(listener->user, FALSE, entry->vip, entry->other,
125: entry->id, entry->name, entry->unique_id))
126: {
127: free(listener);
128: return TRUE;
129: }
130: return FALSE;
131: }
132:
133: /**
134: * Add a new entry to the hashtable
135: */
136: static void add_entry(private_lookip_listener_t *this, ike_sa_t *ike_sa)
137: {
138: enumerator_t *enumerator;
139: host_t *vip, *other;
140: identification_t *id;
141: entry_t *entry;
142:
143: enumerator = ike_sa->create_virtual_ip_enumerator(ike_sa, FALSE);
144: while (enumerator->enumerate(enumerator, &vip))
145: {
146: other = ike_sa->get_other_host(ike_sa);
147: id = ike_sa->get_other_eap_id(ike_sa);
148:
149: INIT(entry,
150: .vip = vip->clone(vip),
151: .other = other->clone(other),
152: .id = id->clone(id),
153: .name = strdup(ike_sa->get_name(ike_sa)),
154: .unique_id = ike_sa->get_unique_id(ike_sa),
155: );
156:
157: this->lock->read_lock(this->lock);
158: this->listeners->remove(this->listeners, entry, (void*)notify_up);
159: this->lock->unlock(this->lock);
160:
161: this->lock->write_lock(this->lock);
162: entry = this->entries->put(this->entries, entry->vip, entry);
163: this->lock->unlock(this->lock);
164: if (entry)
165: {
166: entry_destroy(entry);
167: }
168: }
169: enumerator->destroy(enumerator);
170: }
171:
172: /**
173: * Remove an entry from the hashtable
174: */
175: static void remove_entry(private_lookip_listener_t *this, ike_sa_t *ike_sa)
176: {
177: enumerator_t *enumerator;
178: host_t *vip;
179: entry_t *entry;
180:
181: enumerator = ike_sa->create_virtual_ip_enumerator(ike_sa, FALSE);
182: while (enumerator->enumerate(enumerator, &vip))
183: {
184: this->lock->write_lock(this->lock);
185: entry = this->entries->remove(this->entries, vip);
186: this->lock->unlock(this->lock);
187: if (entry)
188: {
189: this->lock->read_lock(this->lock);
190: this->listeners->remove(this->listeners, entry, (void*)notify_down);
191: this->lock->unlock(this->lock);
192:
193: entry_destroy(entry);
194: }
195: }
196: enumerator->destroy(enumerator);
197: }
198:
199: METHOD(listener_t, message_hook, bool,
200: private_lookip_listener_t *this, ike_sa_t *ike_sa,
201: message_t *message, bool incoming, bool plain)
202: {
203: if (plain && ike_sa->get_state(ike_sa) == IKE_ESTABLISHED &&
204: !incoming && !message->get_request(message))
205: {
206: if (ike_sa->get_version(ike_sa) == IKEV1 &&
207: message->get_exchange_type(message) == TRANSACTION)
208: {
209: add_entry(this, ike_sa);
210: }
211: if (ike_sa->get_version(ike_sa) == IKEV2 &&
212: message->get_exchange_type(message) == IKE_AUTH)
213: {
214: add_entry(this, ike_sa);
215: }
216: }
217: return TRUE;
218: }
219:
220: METHOD(listener_t, ike_updown, bool,
221: private_lookip_listener_t *this, ike_sa_t *ike_sa, bool up)
222: {
223: if (!up)
224: {
225: remove_entry(this, ike_sa);
226: }
227: return TRUE;
228: }
229:
230: METHOD(listener_t, ike_rekey, bool,
231: private_lookip_listener_t *this, ike_sa_t *old, ike_sa_t *new)
232: {
233: /* During IKE_SA rekey, the unique identifier changes. Fire update events
234: * and update the cached entry. During the invocation of this hook, the
235: * virtual IPs have been migrated to new, hence remove that entry. */
236: remove_entry(this, new);
237: add_entry(this, new);
238:
239: return TRUE;
240: }
241:
242: METHOD(lookip_listener_t, lookup, int,
243: private_lookip_listener_t *this, host_t *vip,
244: lookip_callback_t cb, void *user)
245: {
246: entry_t *entry;
247: int matches = 0;
248:
249: this->lock->read_lock(this->lock);
250: if (vip)
251: {
252: entry = this->entries->get(this->entries, vip);
253: if (entry)
254: {
255: cb(user, TRUE, entry->vip, entry->other, entry->id,
256: entry->name, entry->unique_id);
257: matches ++;
258: }
259: }
260: else
261: {
262: enumerator_t *enumerator;
263:
264: enumerator = this->entries->create_enumerator(this->entries);
265: while (enumerator->enumerate(enumerator, &vip, &entry))
266: {
267: cb(user, TRUE, entry->vip, entry->other, entry->id,
268: entry->name, entry->unique_id);
269: matches++;
270: }
271: enumerator->destroy(enumerator);
272: }
273: this->lock->unlock(this->lock);
274:
275: return matches;
276: }
277:
278: METHOD(lookip_listener_t, add_listener, void,
279: private_lookip_listener_t *this, lookip_callback_t cb, void *user)
280: {
281: listener_entry_t *listener;
282:
283: INIT(listener,
284: .cb = cb,
285: .user = user,
286: );
287:
288: this->lock->write_lock(this->lock);
289: this->listeners->insert_last(this->listeners, listener);
290: this->lock->unlock(this->lock);
291: }
292:
293: METHOD(lookip_listener_t, remove_listener, void,
294: private_lookip_listener_t *this, void *user)
295: {
296: listener_entry_t *listener;
297: enumerator_t *enumerator;
298:
299: this->lock->write_lock(this->lock);
300: enumerator = this->listeners->create_enumerator(this->listeners);
301: while (enumerator->enumerate(enumerator, &listener))
302: {
303: if (listener->user == user)
304: {
305: this->listeners->remove_at(this->listeners, enumerator);
306: free(listener);
307: }
308: }
309: enumerator->destroy(enumerator);
310: this->lock->unlock(this->lock);
311: }
312:
313: METHOD(lookip_listener_t, destroy, void,
314: private_lookip_listener_t *this)
315: {
316: this->listeners->destroy_function(this->listeners, free);
317: this->entries->destroy(this->entries);
318: this->lock->destroy(this->lock);
319: free(this);
320: }
321:
322: /**
323: * See header
324: */
325: lookip_listener_t *lookip_listener_create()
326: {
327: private_lookip_listener_t *this;
328:
329: INIT(this,
330: .public = {
331: .listener = {
332: .message = _message_hook,
333: .ike_updown = _ike_updown,
334: .ike_rekey = _ike_rekey,
335: },
336: .lookup = _lookup,
337: .add_listener = _add_listener,
338: .remove_listener = _remove_listener,
339: .destroy = _destroy,
340: },
341: .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
342: .entries = hashtable_create((hashtable_hash_t)hash,
343: (hashtable_equals_t)equals, 32),
344: .listeners = linked_list_create(),
345: );
346:
347: return &this->public;
348: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>