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