Pass the full list of pools to acquire_address, enumerate in providers
[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, char *name, host_t *address,
123 identification_t *id)
124 {
125 mem_pool_t *pool;
126 bool found = FALSE;
127
128 this->lock->read_lock(this->lock);
129 pool = find_pool(this, name);
130 if (pool)
131 {
132 found = pool->release_address(pool, address, id);
133 }
134 this->lock->unlock(this->lock);
135 return found;
136 }
137
138 /**
139 * Filter function to convert host to DNS configuration attributes
140 */
141 static bool attr_filter(void *lock, host_t **in,
142 configuration_attribute_type_t *type,
143 void *dummy, chunk_t *data)
144 {
145 host_t *host = *in;
146
147 switch (host->get_family(host))
148 {
149 case AF_INET:
150 *type = INTERNAL_IP4_DNS;
151 break;
152 case AF_INET6:
153 *type = INTERNAL_IP6_DNS;
154 break;
155 default:
156 return FALSE;
157 }
158 *data = host->get_address(host);
159 return TRUE;
160 }
161
162 METHOD(attribute_provider_t, create_attribute_enumerator, enumerator_t*,
163 private_stroke_attribute_t *this, linked_list_t *pools,
164 identification_t *id, linked_list_t *vips)
165 {
166 ike_sa_t *ike_sa;
167 peer_cfg_t *peer_cfg;
168 enumerator_t *enumerator;
169 attributes_t *attr;
170
171 ike_sa = charon->bus->get_sa(charon->bus);
172 if (ike_sa)
173 {
174 peer_cfg = ike_sa->get_peer_cfg(ike_sa);
175 this->lock->read_lock(this->lock);
176 enumerator = this->attrs->create_enumerator(this->attrs);
177 while (enumerator->enumerate(enumerator, &attr))
178 {
179 if (streq(attr->name, peer_cfg->get_name(peer_cfg)))
180 {
181 enumerator->destroy(enumerator);
182 return enumerator_create_filter(
183 attr->dns->create_enumerator(attr->dns),
184 (void*)attr_filter, this->lock,
185 (void*)this->lock->unlock);
186 }
187 }
188 enumerator->destroy(enumerator);
189 this->lock->unlock(this->lock);
190 }
191 return enumerator_create_empty();
192 }
193
194 METHOD(stroke_attribute_t, add_pool, void,
195 private_stroke_attribute_t *this, mem_pool_t *pool)
196 {
197 enumerator_t *enumerator;
198 mem_pool_t *current;
199 host_t *base;
200 int size;
201
202 base = pool->get_base(pool);
203 size = pool->get_size(pool);
204
205 this->lock->write_lock(this->lock);
206
207 enumerator = this->pools->create_enumerator(this->pools);
208 while (enumerator->enumerate(enumerator, &current))
209 {
210 if (base && current->get_base(current) &&
211 base->ip_equals(base, current->get_base(current)) &&
212 size == current->get_size(current))
213 {
214 DBG1(DBG_CFG, "reusing virtual IP address pool %s",
215 current->get_name(current));
216 pool->destroy(pool);
217 pool = NULL;
218 break;
219 }
220 }
221 enumerator->destroy(enumerator);
222
223 if (pool)
224 {
225 if (base)
226 {
227 DBG1(DBG_CFG, "adding virtual IP address pool %s",
228 pool->get_name(pool));
229 }
230 this->pools->insert_last(this->pools, pool);
231 }
232
233 this->lock->unlock(this->lock);
234 }
235
236 METHOD(stroke_attribute_t, add_dns, void,
237 private_stroke_attribute_t *this, stroke_msg_t *msg)
238 {
239 if (msg->add_conn.other.dns)
240 {
241 enumerator_t *enumerator;
242 attributes_t *attr = NULL;
243 host_t *host;
244 char *token;
245
246 enumerator = enumerator_create_token(msg->add_conn.other.dns, ",", " ");
247 while (enumerator->enumerate(enumerator, &token))
248 {
249 host = host_create_from_string(token, 0);
250 if (host)
251 {
252 if (!attr)
253 {
254 INIT(attr,
255 .name = strdup(msg->add_conn.name),
256 .dns = linked_list_create(),
257 );
258 }
259 attr->dns->insert_last(attr->dns, host);
260 }
261 else
262 {
263 DBG1(DBG_CFG, "ignoring invalid DNS address '%s'", token);
264 }
265 }
266 enumerator->destroy(enumerator);
267 if (attr)
268 {
269 this->lock->write_lock(this->lock);
270 this->attrs->insert_last(this->attrs, attr);
271 this->lock->unlock(this->lock);
272 }
273 }
274 }
275
276 METHOD(stroke_attribute_t, del_dns, void,
277 private_stroke_attribute_t *this, stroke_msg_t *msg)
278 {
279 enumerator_t *enumerator;
280 attributes_t *attr;
281
282 this->lock->write_lock(this->lock);
283
284 enumerator = this->attrs->create_enumerator(this->attrs);
285 while (enumerator->enumerate(enumerator, &attr))
286 {
287 if (streq(msg->del_conn.name, attr->name))
288 {
289 this->attrs->remove_at(this->attrs, enumerator);
290 attributes_destroy(attr);
291 break;
292 }
293 }
294 enumerator->destroy(enumerator);
295
296 this->lock->unlock(this->lock);
297 }
298
299 /**
300 * Pool enumerator filter function, converts pool_t to name, size, ...
301 */
302 static bool pool_filter(void *lock, mem_pool_t **poolp, const char **name,
303 void *d1, u_int *size, void *d2, u_int *online,
304 void *d3, u_int *offline)
305 {
306 mem_pool_t *pool = *poolp;
307
308 if (pool->get_size(pool) == 0)
309 {
310 return FALSE;
311 }
312 *name = pool->get_name(pool);
313 *size = pool->get_size(pool);
314 *online = pool->get_online(pool);
315 *offline = pool->get_offline(pool);
316 return TRUE;
317 }
318
319 METHOD(stroke_attribute_t, create_pool_enumerator, enumerator_t*,
320 private_stroke_attribute_t *this)
321 {
322 this->lock->read_lock(this->lock);
323 return enumerator_create_filter(this->pools->create_enumerator(this->pools),
324 (void*)pool_filter,
325 this->lock, (void*)this->lock->unlock);
326 }
327
328 METHOD(stroke_attribute_t, create_lease_enumerator, enumerator_t*,
329 private_stroke_attribute_t *this, char *name)
330 {
331 mem_pool_t *pool;
332 this->lock->read_lock(this->lock);
333 pool = find_pool(this, name);
334 if (!pool)
335 {
336 this->lock->unlock(this->lock);
337 return NULL;
338 }
339 return enumerator_create_cleaner(pool->create_lease_enumerator(pool),
340 (void*)this->lock->unlock, this->lock);
341 }
342
343 METHOD(stroke_attribute_t, destroy, void,
344 private_stroke_attribute_t *this)
345 {
346 this->lock->destroy(this->lock);
347 this->pools->destroy_offset(this->pools, offsetof(mem_pool_t, destroy));
348 this->attrs->destroy_function(this->attrs, (void*)attributes_destroy);
349 free(this);
350 }
351
352 /*
353 * see header file
354 */
355 stroke_attribute_t *stroke_attribute_create()
356 {
357 private_stroke_attribute_t *this;
358
359 INIT(this,
360 .public = {
361 .provider = {
362 .acquire_address = _acquire_address,
363 .release_address = _release_address,
364 .create_attribute_enumerator = _create_attribute_enumerator,
365 },
366 .add_pool = _add_pool,
367 .add_dns = _add_dns,
368 .del_dns = _del_dns,
369 .create_pool_enumerator = _create_pool_enumerator,
370 .create_lease_enumerator = _create_lease_enumerator,
371 .destroy = _destroy,
372 },
373 .pools = linked_list_create(),
374 .attrs = linked_list_create(),
375 .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
376 );
377
378 return &this->public;
379 }
380