2 * Copyright (C) 2012 Martin Willi
4 * Copyright (C) secunet Security Networks AG
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>.
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
17 #include "lookip_listener.h"
20 #include <collections/hashtable.h>
21 #include <collections/linked_list.h>
22 #include <threading/rwlock.h>
24 typedef struct private_lookip_listener_t private_lookip_listener_t
;
27 * Private data of an lookip_listener_t object.
29 struct private_lookip_listener_t
{
32 * Public lookip_listener_t interface.
34 lookip_listener_t
public;
42 * Hashtable with entries: host_t => entry_t
47 * List of registered listeners
49 linked_list_t
*listeners
;
56 /** callback function */
58 /** user data for callback */
66 /** virtual IP, serves as lookup key */
68 /** peers external address */
70 /** peer (EAP-)Identity */
72 /** associated connection name */
74 /** IKE_SA unique identifier */
79 * Destroy a hashtable entry
81 static void entry_destroy(entry_t
*entry
)
83 entry
->vip
->destroy(entry
->vip
);
84 entry
->other
->destroy(entry
->other
);
85 entry
->id
->destroy(entry
->id
);
91 * Hashtable hash function
93 static u_int
hash(host_t
*key
)
95 return chunk_hash(key
->get_address(key
));
99 * Hashtable equals function
101 static bool equals(host_t
*a
, host_t
*b
)
103 return a
->ip_equals(a
, b
);
107 * Compare callback that invokes up callback of all registered listeners
109 static bool notify_up(listener_entry_t
*listener
, entry_t
*entry
)
111 if (!listener
->cb(listener
->user
, TRUE
, entry
->vip
, entry
->other
,
112 entry
->id
, entry
->name
, entry
->unique_id
))
121 * Compare callback that invokes down callback of all registered listeners
123 static bool notify_down(listener_entry_t
*listener
, entry_t
*entry
)
125 if (!listener
->cb(listener
->user
, FALSE
, entry
->vip
, entry
->other
,
126 entry
->id
, entry
->name
, entry
->unique_id
))
135 * Add a new entry to the hashtable
137 static void add_entry(private_lookip_listener_t
*this, ike_sa_t
*ike_sa
)
139 enumerator_t
*enumerator
;
141 identification_t
*id
;
144 enumerator
= ike_sa
->create_virtual_ip_enumerator(ike_sa
, FALSE
);
145 while (enumerator
->enumerate(enumerator
, &vip
))
147 other
= ike_sa
->get_other_host(ike_sa
);
148 id
= ike_sa
->get_other_eap_id(ike_sa
);
151 .vip
= vip
->clone(vip
),
152 .other
= other
->clone(other
),
154 .name
= strdup(ike_sa
->get_name(ike_sa
)),
155 .unique_id
= ike_sa
->get_unique_id(ike_sa
),
158 this->lock
->read_lock(this->lock
);
159 this->listeners
->remove(this->listeners
, entry
, (void*)notify_up
);
160 this->lock
->unlock(this->lock
);
162 this->lock
->write_lock(this->lock
);
163 entry
= this->entries
->put(this->entries
, entry
->vip
, entry
);
164 this->lock
->unlock(this->lock
);
167 entry_destroy(entry
);
170 enumerator
->destroy(enumerator
);
174 * Remove an entry from the hashtable
176 static void remove_entry(private_lookip_listener_t
*this, ike_sa_t
*ike_sa
)
178 enumerator_t
*enumerator
;
182 enumerator
= ike_sa
->create_virtual_ip_enumerator(ike_sa
, FALSE
);
183 while (enumerator
->enumerate(enumerator
, &vip
))
185 this->lock
->write_lock(this->lock
);
186 entry
= this->entries
->remove(this->entries
, vip
);
187 this->lock
->unlock(this->lock
);
190 this->lock
->read_lock(this->lock
);
191 this->listeners
->remove(this->listeners
, entry
, (void*)notify_down
);
192 this->lock
->unlock(this->lock
);
194 entry_destroy(entry
);
197 enumerator
->destroy(enumerator
);
200 METHOD(listener_t
, message_hook
, bool,
201 private_lookip_listener_t
*this, ike_sa_t
*ike_sa
,
202 message_t
*message
, bool incoming
, bool plain
)
204 if (plain
&& ike_sa
->get_state(ike_sa
) == IKE_ESTABLISHED
&&
205 !incoming
&& !message
->get_request(message
))
207 if (ike_sa
->get_version(ike_sa
) == IKEV1
&&
208 message
->get_exchange_type(message
) == TRANSACTION
)
210 add_entry(this, ike_sa
);
212 if (ike_sa
->get_version(ike_sa
) == IKEV2
&&
213 message
->get_exchange_type(message
) == IKE_AUTH
)
215 add_entry(this, ike_sa
);
221 METHOD(listener_t
, ike_updown
, bool,
222 private_lookip_listener_t
*this, ike_sa_t
*ike_sa
, bool up
)
226 remove_entry(this, ike_sa
);
231 METHOD(listener_t
, ike_rekey
, bool,
232 private_lookip_listener_t
*this, ike_sa_t
*old
, ike_sa_t
*new)
234 /* During IKE_SA rekey, the unique identifier changes. Fire update events
235 * and update the cached entry. During the invocation of this hook, the
236 * virtual IPs have been migrated to new, hence remove that entry. */
237 remove_entry(this, new);
238 add_entry(this, new);
243 METHOD(lookip_listener_t
, lookup
, int,
244 private_lookip_listener_t
*this, host_t
*vip
,
245 lookip_callback_t cb
, void *user
)
250 this->lock
->read_lock(this->lock
);
253 entry
= this->entries
->get(this->entries
, vip
);
256 cb(user
, TRUE
, entry
->vip
, entry
->other
, entry
->id
,
257 entry
->name
, entry
->unique_id
);
263 enumerator_t
*enumerator
;
265 enumerator
= this->entries
->create_enumerator(this->entries
);
266 while (enumerator
->enumerate(enumerator
, &vip
, &entry
))
268 cb(user
, TRUE
, entry
->vip
, entry
->other
, entry
->id
,
269 entry
->name
, entry
->unique_id
);
272 enumerator
->destroy(enumerator
);
274 this->lock
->unlock(this->lock
);
279 METHOD(lookip_listener_t
, add_listener
, void,
280 private_lookip_listener_t
*this, lookip_callback_t cb
, void *user
)
282 listener_entry_t
*listener
;
289 this->lock
->write_lock(this->lock
);
290 this->listeners
->insert_last(this->listeners
, listener
);
291 this->lock
->unlock(this->lock
);
294 METHOD(lookip_listener_t
, remove_listener
, void,
295 private_lookip_listener_t
*this, void *user
)
297 listener_entry_t
*listener
;
298 enumerator_t
*enumerator
;
300 this->lock
->write_lock(this->lock
);
301 enumerator
= this->listeners
->create_enumerator(this->listeners
);
302 while (enumerator
->enumerate(enumerator
, &listener
))
304 if (listener
->user
== user
)
306 this->listeners
->remove_at(this->listeners
, enumerator
);
310 enumerator
->destroy(enumerator
);
311 this->lock
->unlock(this->lock
);
314 METHOD(lookip_listener_t
, destroy
, void,
315 private_lookip_listener_t
*this)
317 this->listeners
->destroy_function(this->listeners
, free
);
318 this->entries
->destroy(this->entries
);
319 this->lock
->destroy(this->lock
);
326 lookip_listener_t
*lookip_listener_create()
328 private_lookip_listener_t
*this;
333 .message
= _message_hook
,
334 .ike_updown
= _ike_updown
,
335 .ike_rekey
= _ike_rekey
,
338 .add_listener
= _add_listener
,
339 .remove_listener
= _remove_listener
,
342 .lock
= rwlock_create(RWLOCK_TYPE_DEFAULT
),
343 .entries
= hashtable_create((hashtable_hash_t
)hash
,
344 (hashtable_equals_t
)equals
, 32),
345 .listeners
= linked_list_create(),
348 return &this->public;