Return to lookip_listener.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / libcharon / plugins / lookip |
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: }