71b56bc8a2ce1b39682565b1140047f75bd7a56c
[strongswan.git] / src / charon / plugins / stroke / stroke_attribute.c
1 /*
2 * Copyright (C) 2008 Martin Willi
3 * Hochschule fuer Technik Rapperswil
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 * $Id$
16 */
17
18 #include "stroke_attribute.h"
19
20 #include <daemon.h>
21 #include <utils/linked_list.h>
22 #include <utils/mutex.h>
23
24 #define POOL_LIMIT 16
25
26 typedef struct private_stroke_attribute_t private_stroke_attribute_t;
27
28 /**
29 * private data of stroke_attribute
30 */
31 struct private_stroke_attribute_t {
32
33 /**
34 * public functions
35 */
36 stroke_attribute_t public;
37
38 /**
39 * list of pools, contains pool_t
40 */
41 linked_list_t *pools;
42
43 /**
44 * mutex to lock access to pools
45 */
46 mutex_t *mutex;
47 };
48
49 typedef struct {
50 /** name of the pool */
51 char *name;
52 /** base address of the pool */
53 host_t *base;
54 /** number of entries in the pool */
55 int count;
56 /** array of in-use flags, TODO: use bit fields */
57 u_int8_t *in_use;
58 } pool_t;
59
60 /**
61 * destroy a pool_t
62 */
63 static void pool_destroy(pool_t *this)
64 {
65 DESTROY_IF(this->base);
66 free(this->name);
67 free(this->in_use);
68 free(this);
69 }
70
71 /**
72 * find a pool by name
73 */
74 static pool_t *find_pool(private_stroke_attribute_t *this, char *name)
75 {
76 enumerator_t *enumerator;
77 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->name))
83 {
84 found = current;
85 break;
86 }
87 }
88 enumerator->destroy(enumerator);
89 return found;
90 }
91
92 /**
93 * convert an pool offset to an address
94 */
95 host_t* offset2host(pool_t *pool, int offset)
96 {
97 chunk_t addr;
98 host_t *host;
99 u_int32_t *pos;
100
101 if (offset > pool->count)
102 {
103 return NULL;
104 }
105
106 addr = chunk_clone(pool->base->get_address(pool->base));
107 if (pool->base->get_family(pool->base) == AF_INET6)
108 {
109 pos = (u_int32_t*)(addr.ptr + 12);
110 }
111 else
112 {
113 pos = (u_int32_t*)addr.ptr;
114 }
115 *pos = htonl(offset + ntohl(*pos));
116 host = host_create_from_chunk(pool->base->get_family(pool->base), addr, 0);
117 free(addr.ptr);
118 return host;
119 }
120
121 /**
122 * convert a host to a pool offset
123 */
124 int host2offset(pool_t *pool, host_t *addr)
125 {
126 chunk_t host, base;
127 u_int32_t hosti, basei;
128
129 if (addr->get_family(addr) != pool->base->get_family(pool->base))
130 {
131 return -1;
132 }
133 host = addr->get_address(addr);
134 base = pool->base->get_address(pool->base);
135 if (addr->get_family(addr) == AF_INET6)
136 {
137 /* only look at last /32 block */
138 if (!memeq(host.ptr, base.ptr, 12))
139 {
140 return -1;
141 }
142 host = chunk_skip(host, 12);
143 base = chunk_skip(base, 12);
144 }
145 hosti = ntohl(*(u_int32_t*)(host.ptr));
146 basei = ntohl(*(u_int32_t*)(base.ptr));
147 if (hosti > basei + pool->count)
148 {
149 return -1;
150 }
151 return hosti - basei;
152 }
153
154 /**
155 * Implementation of attribute_provider_t.acquire_address
156 */
157 static host_t* acquire_address(private_stroke_attribute_t *this,
158 char *name, identification_t *id,
159 auth_info_t *auth, host_t *requested)
160 {
161 pool_t *pool;
162 host_t *host = NULL;
163 int i;
164
165 this->mutex->lock(this->mutex);
166 pool = find_pool(this, name);
167 if (pool)
168 {
169 if (requested && !requested->is_anyaddr(requested))
170 {
171 if (pool->count == 0)
172 { /* %config, give any */
173 host = requested->clone(requested);
174 }
175 else
176 {
177 i = host2offset(pool, requested);
178 if (i >= 0 && !pool->in_use[i])
179 {
180 pool->in_use[i] = TRUE;
181 host = requested->clone(requested);
182 }
183 }
184 }
185 if (!host)
186 {
187 for (i = 0; i < pool->count; i++)
188 {
189 if (!pool->in_use[i])
190 {
191 pool->in_use[i] = TRUE;
192 host = offset2host(pool, i);
193 break;
194 }
195 }
196 }
197 }
198 this->mutex->unlock(this->mutex);
199 return host;
200 }
201
202 /**
203 * Implementation of attribute_provider_t.release_address
204 */
205 static bool release_address(private_stroke_attribute_t *this,
206 char *name, host_t *address)
207 {
208 pool_t *pool;
209 bool found = FALSE;
210 int i;
211
212 this->mutex->lock(this->mutex);
213 pool = find_pool(this, name);
214 if (pool)
215 {
216 if (pool->count != 0)
217 {
218 i = host2offset(pool, address);
219 if (i >= 0 && pool->in_use[i])
220 {
221 pool->in_use[i] = FALSE;
222 found = TRUE;
223 }
224 }
225 }
226 this->mutex->unlock(this->mutex);
227 return found;
228 }
229
230 /**
231 * Implementation of stroke_attribute_t.add_pool.
232 */
233 static void add_pool(private_stroke_attribute_t *this, stroke_msg_t *msg)
234 {
235 if (msg->add_conn.other.sourceip_size)
236 {
237 pool_t *pool;
238
239 if (msg->add_conn.other.sourceip)
240 {
241 u_int32_t bits;
242 int family;
243
244 DBG1(DBG_CFG, "adding virtual IP address pool '%s': %s/%d",
245 msg->add_conn.name, msg->add_conn.other.sourceip,
246 msg->add_conn.other.sourceip_size);
247
248 pool = malloc_thing(pool_t);
249 pool->base = host_create_from_string(msg->add_conn.other.sourceip, 0);
250 if (!pool->base)
251 {
252 free(pool);
253 DBG1(DBG_CFG, "virtual IP address invalid, discarded");
254 return;
255 }
256 pool->name = strdup(msg->add_conn.name);
257 family = pool->base->get_family(pool->base);
258 bits = (family == AF_INET ? 32 : 128) - msg->add_conn.other.sourceip_size;
259 if (bits > POOL_LIMIT)
260 {
261 bits = POOL_LIMIT;
262 DBG1(DBG_CFG, "virtual IP pool to large, limiting to %s/%d",
263 msg->add_conn.other.sourceip,
264 (family == AF_INET ? 32 : 128) - bits);
265 }
266 pool->count = 1 << (bits);
267 pool->in_use = calloc(pool->count, sizeof(u_int8_t));
268
269 if (pool->count > 2)
270 { /* do not use first and last addresses of a block */
271 pool->in_use[0] = TRUE;
272 pool->in_use[pool->count-1] = TRUE;
273 }
274 }
275 else
276 { /* %config, add an empty pool */
277 pool = malloc_thing(pool_t);
278 pool->name = strdup(msg->add_conn.name);
279 pool->base = NULL;
280 pool->count = 0;
281 pool->in_use = NULL;
282 }
283 this->mutex->lock(this->mutex);
284 this->pools->insert_last(this->pools, pool);
285 this->mutex->unlock(this->mutex);
286 }
287 }
288
289 /**
290 * Implementation of stroke_attribute_t.del_pool.
291 */
292 static void del_pool(private_stroke_attribute_t *this, stroke_msg_t *msg)
293 {
294 enumerator_t *enumerator;
295 pool_t *pool;
296
297 this->mutex->lock(this->mutex);
298 enumerator = this->pools->create_enumerator(this->pools);
299 while (enumerator->enumerate(enumerator, &pool))
300 {
301 if (streq(msg->del_conn.name, pool->name))
302 {
303 this->pools->remove_at(this->pools, enumerator);
304 pool_destroy(pool);
305 break;
306 }
307 }
308 enumerator->destroy(enumerator);
309 this->mutex->unlock(this->mutex);
310 }
311
312 /**
313 * Implementation of stroke_attribute_t.destroy
314 */
315 static void destroy(private_stroke_attribute_t *this)
316 {
317 this->mutex->destroy(this->mutex);
318 this->pools->destroy_function(this->pools, (void*)pool_destroy);
319 free(this);
320 }
321
322 /*
323 * see header file
324 */
325 stroke_attribute_t *stroke_attribute_create()
326 {
327 private_stroke_attribute_t *this = malloc_thing(private_stroke_attribute_t);
328
329 this->public.provider.acquire_address = (host_t*(*)(attribute_provider_t *this, char*, identification_t *,auth_info_t *, host_t *))acquire_address;
330 this->public.provider.release_address = (bool(*)(attribute_provider_t *this, char*,host_t *))release_address;
331 this->public.add_pool = (void(*)(stroke_attribute_t*, stroke_msg_t *msg))add_pool;
332 this->public.del_pool = (void(*)(stroke_attribute_t*, stroke_msg_t *msg))del_pool;
333 this->public.destroy = (void(*)(stroke_attribute_t*))destroy;
334
335 this->pools = linked_list_create();
336 this->mutex = mutex_create(MUTEX_DEFAULT);
337
338 return &this->public;
339 }
340