Pass full pool list to release_address
[strongswan.git] / src / libcharon / plugins / stroke / stroke_attribute.c
1 /*
2 * Copyright (C) 2010 Tobias Brunner
3 * Copyright (C) 2008 Martin Willi
4 * Hochschule fuer Technik Rapperswil
5 *
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>.
10 *
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
14 * for more details.
15 */
16
17 #include "stroke_attribute.h"
18
19 #include <daemon.h>
20 #include <utils/linked_list.h>
21 #include <threading/rwlock.h>
22
23 typedef struct private_stroke_attribute_t private_stroke_attribute_t;
24
25 /**
26 * private data of stroke_attribute
27 */
28 struct private_stroke_attribute_t {
29
30 /**
31 * public functions
32 */
33 stroke_attribute_t public;
34
35 /**
36 * list of pools, contains mem_pool_t
37 */
38 linked_list_t *pools;
39
40 /**
41 * List of connection specific attributes, as attributes_t
42 */
43 linked_list_t *attrs;
44
45 /**
46 * rwlock to lock access to pools
47 */
48 rwlock_t *lock;
49 };
50
51 /**
52 * Attributes assigned to a connection
53 */
54 typedef struct {
55 /** name of the connection */
56 char *name;
57 /** list of DNS attributes, as host_t */
58 linked_list_t *dns;
59 } attributes_t;
60
61 /**
62 * Destroy an attributes_t entry
63 */
64 static void attributes_destroy(attributes_t *this)
65 {
66 this->dns->destroy_offset(this->dns, offsetof(host_t, destroy));
67 free(this->name);
68 free(this);
69 }
70
71 /**
72 * find a pool by name
73 */
74 static mem_pool_t *find_pool(private_stroke_attribute_t *this, char *name)
75 {
76 enumerator_t *enumerator;
77 mem_pool_t *current, *found = NULL;
78
79 enumerator = this->pools->create_enumerator(this->pools);
80 while (enumerator->enumerate(enumerator, &current))
81 {
82 if (streq(name, current->get_name(current)))
83 {
84 found = current;
85 break;
86 }
87 }
88 enumerator->destroy(enumerator);
89 return found;
90 }
91
92 METHOD(attribute_provider_t, acquire_address, host_t*,
93 private_stroke_attribute_t *this, linked_list_t *pools, identification_t *id,
94 host_t *requested)
95 {
96 enumerator_t *enumerator;
97 mem_pool_t *pool;
98 host_t *addr = NULL;
99 char *name;
100
101 enumerator = pools->create_enumerator(pools);
102 this->lock->read_lock(this->lock);
103 while (enumerator->enumerate(enumerator, &name))
104 {
105 pool = find_pool(this, name);
106 if (pool)
107 {
108 addr = pool->acquire_address(pool, id, requested);
109 if (addr)
110 {
111 break;
112 }
113 }
114 }
115 this->lock->unlock(this->lock);
116 enumerator->destroy(enumerator);
117
118 return addr;
119 }
120
121 METHOD(attribute_provider_t, release_address, bool,
122 private_stroke_attribute_t *this, linked_list_t *pools, host_t *address,
123 identification_t *id)
124 {
125 enumerator_t *enumerator;
126 mem_pool_t *pool;
127 bool found = FALSE;
128 char *name;
129
130 enumerator = pools->create_enumerator(pools);
131 this->lock->read_lock(this->lock);
132 while (enumerator->enumerate(enumerator, &name))
133 {
134 pool = find_pool(this, name);
135 if (pool)
136 {
137 found = pool->release_address(pool, address, id);
138 if (found)
139 {
140 break;
141 }
142 }
143 }
144 this->lock->unlock(this->lock);
145 enumerator->destroy(enumerator);
146
147 return found;
148 }
149
150 /**
151 * Filter function to convert host to DNS configuration attributes
152 */
153 static bool attr_filter(void *lock, host_t **in,
154 configuration_attribute_type_t *type,
155 void *dummy, chunk_t *data)
156 {
157 host_t *host = *in;
158
159 switch (host->get_family(host))
160 {
161 case AF_INET:
162 *type = INTERNAL_IP4_DNS;
163 break;
164 case AF_INET6:
165 *type = INTERNAL_IP6_DNS;
166 break;
167 default:
168 return FALSE;
169 }
170 *data = host->get_address(host);
171 return TRUE;
172 }
173
174 METHOD(attribute_provider_t, create_attribute_enumerator, enumerator_t*,
175 private_stroke_attribute_t *this, linked_list_t *pools,
176 identification_t *id, linked_list_t *vips)
177 {
178 ike_sa_t *ike_sa;
179 peer_cfg_t *peer_cfg;
180 enumerator_t *enumerator;
181 attributes_t *attr;
182
183 ike_sa = charon->bus->get_sa(charon->bus);
184 if (ike_sa)
185 {
186 peer_cfg = ike_sa->get_peer_cfg(ike_sa);
187 this->lock->read_lock(this->lock);
188 enumerator = this->attrs->create_enumerator(this->attrs);
189 while (enumerator->enumerate(enumerator, &attr))
190 {
191 if (streq(attr->name, peer_cfg->get_name(peer_cfg)))
192 {
193 enumerator->destroy(enumerator);
194 return enumerator_create_filter(
195 attr->dns->create_enumerator(attr->dns),
196 (void*)attr_filter, this->lock,
197 (void*)this->lock->unlock);
198 }
199 }
200 enumerator->destroy(enumerator);
201 this->lock->unlock(this->lock);
202 }
203 return enumerator_create_empty();
204 }
205
206 METHOD(stroke_attribute_t, add_pool, void,
207 private_stroke_attribute_t *this, mem_pool_t *pool)
208 {
209 enumerator_t *enumerator;
210 mem_pool_t *current;
211 host_t *base;
212 int size;
213
214 base = pool->get_base(pool);
215 size = pool->get_size(pool);
216
217 this->lock->write_lock(this->lock);
218
219 enumerator = this->pools->create_enumerator(this->pools);
220 while (enumerator->enumerate(enumerator, &current))
221 {
222 if (base && current->get_base(current) &&
223 base->ip_equals(base, current->get_base(current)) &&
224 size == current->get_size(current))
225 {
226 DBG1(DBG_CFG, "reusing virtual IP address pool %s",
227 current->get_name(current));
228 pool->destroy(pool);
229 pool = NULL;
230 break;
231 }
232 }
233 enumerator->destroy(enumerator);
234
235 if (pool)
236 {
237 if (base)
238 {
239 DBG1(DBG_CFG, "adding virtual IP address pool %s",
240 pool->get_name(pool));
241 }
242 this->pools->insert_last(this->pools, pool);
243 }
244
245 this->lock->unlock(this->lock);
246 }
247
248 METHOD(stroke_attribute_t, add_dns, void,
249 private_stroke_attribute_t *this, stroke_msg_t *msg)
250 {
251 if (msg->add_conn.other.dns)
252 {
253 enumerator_t *enumerator;
254 attributes_t *attr = NULL;
255 host_t *host;
256 char *token;
257
258 enumerator = enumerator_create_token(msg->add_conn.other.dns, ",", " ");
259 while (enumerator->enumerate(enumerator, &token))
260 {
261 host = host_create_from_string(token, 0);
262 if (host)
263 {
264 if (!attr)
265 {
266 INIT(attr,
267 .name = strdup(msg->add_conn.name),
268 .dns = linked_list_create(),
269 );
270 }
271 attr->dns->insert_last(attr->dns, host);
272 }
273 else
274 {
275 DBG1(DBG_CFG, "ignoring invalid DNS address '%s'", token);
276 }
277 }
278 enumerator->destroy(enumerator);
279 if (attr)
280 {
281 this->lock->write_lock(this->lock);
282 this->attrs->insert_last(this->attrs, attr);
283 this->lock->unlock(this->lock);
284 }
285 }
286 }
287
288 METHOD(stroke_attribute_t, del_dns, void,
289 private_stroke_attribute_t *this, stroke_msg_t *msg)
290 {
291 enumerator_t *enumerator;
292 attributes_t *attr;
293
294 this->lock->write_lock(this->lock);
295
296 enumerator = this->attrs->create_enumerator(this->attrs);
297 while (enumerator->enumerate(enumerator, &attr))
298 {
299 if (streq(msg->del_conn.name, attr->name))
300 {
301 this->attrs->remove_at(this->attrs, enumerator);
302 attributes_destroy(attr);
303 break;
304 }
305 }
306 enumerator->destroy(enumerator);
307
308 this->lock->unlock(this->lock);
309 }
310
311 /**
312 * Pool enumerator filter function, converts pool_t to name, size, ...
313 */
314 static bool pool_filter(void *lock, mem_pool_t **poolp, const char **name,
315 void *d1, u_int *size, void *d2, u_int *online,
316 void *d3, u_int *offline)
317 {
318 mem_pool_t *pool = *poolp;
319
320 if (pool->get_size(pool) == 0)
321 {
322 return FALSE;
323 }
324 *name = pool->get_name(pool);
325 *size = pool->get_size(pool);
326 *online = pool->get_online(pool);
327 *offline = pool->get_offline(pool);
328 return TRUE;
329 }
330
331 METHOD(stroke_attribute_t, create_pool_enumerator, enumerator_t*,
332 private_stroke_attribute_t *this)
333 {
334 this->lock->read_lock(this->lock);
335 return enumerator_create_filter(this->pools->create_enumerator(this->pools),
336 (void*)pool_filter,
337 this->lock, (void*)this->lock->unlock);
338 }
339
340 METHOD(stroke_attribute_t, create_lease_enumerator, enumerator_t*,
341 private_stroke_attribute_t *this, char *name)
342 {
343 mem_pool_t *pool;
344 this->lock->read_lock(this->lock);
345 pool = find_pool(this, name);
346 if (!pool)
347 {
348 this->lock->unlock(this->lock);
349 return NULL;
350 }
351 return enumerator_create_cleaner(pool->create_lease_enumerator(pool),
352 (void*)this->lock->unlock, this->lock);
353 }
354
355 METHOD(stroke_attribute_t, destroy, void,
356 private_stroke_attribute_t *this)
357 {
358 this->lock->destroy(this->lock);
359 this->pools->destroy_offset(this->pools, offsetof(mem_pool_t, destroy));
360 this->attrs->destroy_function(this->attrs, (void*)attributes_destroy);
361 free(this);
362 }
363
364 /*
365 * see header file
366 */
367 stroke_attribute_t *stroke_attribute_create()
368 {
369 private_stroke_attribute_t *this;
370
371 INIT(this,
372 .public = {
373 .provider = {
374 .acquire_address = _acquire_address,
375 .release_address = _release_address,
376 .create_attribute_enumerator = _create_attribute_enumerator,
377 },
378 .add_pool = _add_pool,
379 .add_dns = _add_dns,
380 .del_dns = _del_dns,
381 .create_pool_enumerator = _create_pool_enumerator,
382 .create_lease_enumerator = _create_lease_enumerator,
383 .destroy = _destroy,
384 },
385 .pools = linked_list_create(),
386 .attrs = linked_list_create(),
387 .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
388 );
389
390 return &this->public;
391 }
392