Add a lookip listener that collects the information we are interested in
[strongswan.git] / src / libcharon / plugins / lookip / lookip_listener.c
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 <utils/hashtable.h>
20 #include <threading/rwlock.h>
21
22 typedef struct private_lookip_listener_t private_lookip_listener_t;
23
24 /**
25 * Private data of an lookip_listener_t object.
26 */
27 struct private_lookip_listener_t {
28
29 /**
30 * Public lookip_listener_t interface.
31 */
32 lookip_listener_t public;
33
34 /**
35 * Lock for hashtable
36 */
37 rwlock_t *lock;
38
39 /**
40 * Hashtable with entries: host_t => entry_t
41 */
42 hashtable_t *entries;
43 };
44
45 /**
46 * Hashtable entry
47 */
48 typedef struct {
49 /** virtual IP, serves as lookup key */
50 host_t *vip;
51 /** peers external address */
52 host_t *other;
53 /** peer (EAP-)Identity */
54 identification_t *id;
55 /** associated connection name */
56 char *name;
57 } entry_t;
58
59 /**
60 * Destroy a hashtable entry
61 */
62 static void entry_destroy(entry_t *entry)
63 {
64 entry->vip->destroy(entry->vip);
65 entry->other->destroy(entry->other);
66 entry->id->destroy(entry->id);
67 free(entry->name);
68 free(entry);
69 }
70
71 /**
72 * Hashtable hash function
73 */
74 static u_int hash(host_t *key)
75 {
76 return chunk_hash(key->get_address(key));
77 }
78
79 /**
80 * Hashtable equals function
81 */
82 static bool equals(host_t *a, host_t *b)
83 {
84 return a->ip_equals(a, b);
85 }
86
87 /**
88 * Add a new entry to the hashtable
89 */
90 static void add_entry(private_lookip_listener_t *this, ike_sa_t *ike_sa)
91 {
92 enumerator_t *enumerator;
93 host_t *vip, *other;
94 identification_t *id;
95 entry_t *entry;
96
97 enumerator = ike_sa->create_virtual_ip_enumerator(ike_sa, FALSE);
98 while (enumerator->enumerate(enumerator, &vip))
99 {
100 other = ike_sa->get_other_host(ike_sa);
101 id = ike_sa->get_other_eap_id(ike_sa);
102
103 INIT(entry,
104 .vip = vip->clone(vip),
105 .other = other->clone(other),
106 .id = id->clone(id),
107 .name = strdup(ike_sa->get_name(ike_sa)),
108 );
109
110 this->lock->write_lock(this->lock);
111 entry = this->entries->put(this->entries, entry->vip, entry);
112 this->lock->unlock(this->lock);
113 if (entry)
114 {
115 entry_destroy(entry);
116 }
117 }
118 enumerator->destroy(enumerator);
119 }
120
121 /**
122 * Remove an entry from the hashtable
123 */
124 static void remove_entry(private_lookip_listener_t *this, ike_sa_t *ike_sa)
125 {
126 enumerator_t *enumerator;
127 host_t *vip;
128 entry_t *entry;
129
130 enumerator = ike_sa->create_virtual_ip_enumerator(ike_sa, FALSE);
131 while (enumerator->enumerate(enumerator, &vip))
132 {
133 this->lock->write_lock(this->lock);
134 entry = this->entries->remove(this->entries, vip);
135 this->lock->unlock(this->lock);
136 if (entry)
137 {
138 entry_destroy(entry);
139 }
140 }
141 enumerator->destroy(enumerator);
142 }
143
144 METHOD(listener_t, message_hook, bool,
145 private_lookip_listener_t *this, ike_sa_t *ike_sa,
146 message_t *message, bool incoming, bool plain)
147 {
148 if (plain && ike_sa->get_state(ike_sa) == IKE_ESTABLISHED &&
149 !incoming && !message->get_request(message))
150 {
151 if (ike_sa->get_version(ike_sa) == IKEV1 &&
152 message->get_exchange_type(message) == TRANSACTION)
153 {
154 add_entry(this, ike_sa);
155 }
156 if (ike_sa->get_version(ike_sa) == IKEV2 &&
157 message->get_exchange_type(message) == IKE_AUTH)
158 {
159 add_entry(this, ike_sa);
160 }
161 }
162 return TRUE;
163 }
164
165 METHOD(listener_t, ike_updown, bool,
166 private_lookip_listener_t *this, ike_sa_t *ike_sa, bool up)
167 {
168 if (!up)
169 {
170 remove_entry(this, ike_sa);
171 }
172 return TRUE;
173 }
174
175 METHOD(lookip_listener_t, destroy, void,
176 private_lookip_listener_t *this)
177 {
178 this->entries->destroy(this->entries);
179 this->lock->destroy(this->lock);
180 free(this);
181 }
182
183 /**
184 * See header
185 */
186 lookip_listener_t *lookip_listener_create()
187 {
188 private_lookip_listener_t *this;
189
190 INIT(this,
191 .public = {
192 .listener = {
193 .message = _message_hook,
194 .ike_updown = _ike_updown,
195 },
196 .destroy = _destroy,
197 },
198 .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
199 .entries = hashtable_create((hashtable_hash_t)hash,
200 (hashtable_equals_t)equals, 32),
201 );
202
203 return &this->public;
204 }