implemented a simple attribute provider for stroke
[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 this->base->destroy(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 i = host2offset(pool, requested);
172 if (i >= 0 && !pool->in_use[i])
173 {
174 pool->in_use[i] = TRUE;
175 host = requested->clone(requested);
176 }
177 }
178 if (!host)
179 {
180 for (i = 0; i < pool->count; i++)
181 {
182 if (!pool->in_use[i])
183 {
184 pool->in_use[i] = TRUE;
185 host = offset2host(pool, i);
186 break;
187 }
188 }
189 }
190 }
191 this->mutex->unlock(this->mutex);
192 return host;
193 }
194
195 /**
196 * Implementation of attribute_provider_t.release_address
197 */
198 static bool release_address(private_stroke_attribute_t *this,
199 char *name, host_t *address)
200 {
201 pool_t *pool;
202 bool found = FALSE;
203 int i;
204
205 this->mutex->lock(this->mutex);
206 pool = find_pool(this, name);
207 if (pool)
208 {
209 i = host2offset(pool, address);
210 if (i >= 0 && pool->in_use[i])
211 {
212 pool->in_use[i] = FALSE;
213 found =TRUE;
214 }
215 }
216 this->mutex->unlock(this->mutex);
217 return found;
218 }
219
220 /**
221 * Implementation of stroke_attribute_t.add_pool.
222 */
223 static void add_pool(private_stroke_attribute_t *this, stroke_msg_t *msg)
224 {
225 if (msg->add_conn.other.sourceip && msg->add_conn.other.sourceip_size)
226 {
227 pool_t *pool;
228 u_int32_t bits;
229 int family;
230
231 DBG1(DBG_CFG, "adding virtual IP address pool '%s': %s/%d",
232 msg->add_conn.name, msg->add_conn.other.sourceip,
233 msg->add_conn.other.sourceip_size);
234
235 pool = malloc_thing(pool_t);
236 pool->base = host_create_from_string(msg->add_conn.other.sourceip, 0);
237 if (!pool->base)
238 {
239 free(pool);
240 DBG1(DBG_CFG, "virtual IP address invalid, discarded");
241 return;
242 }
243 pool->name = strdup(msg->add_conn.name);
244 family = pool->base->get_family(pool->base);
245 bits = (family == AF_INET ? 32 : 128) - msg->add_conn.other.sourceip_size;
246 if (bits > POOL_LIMIT)
247 {
248 bits = POOL_LIMIT;
249 DBG1(DBG_CFG, "virtual IP pool to large, limiting to %s/%d",
250 msg->add_conn.other.sourceip,
251 (family == AF_INET ? 32 : 128) - bits);
252 }
253 pool->count = 1 << (bits);
254 pool->in_use = calloc(pool->count, sizeof(u_int8_t));
255
256 if (pool->count > 2)
257 { /* do not use first and last addresses of a block */
258 pool->in_use[0] = TRUE;
259 pool->in_use[pool->count-1] = TRUE;
260 }
261 this->mutex->lock(this->mutex);
262 this->pools->insert_last(this->pools, pool);
263 this->mutex->unlock(this->mutex);
264 }
265 }
266
267 /**
268 * Implementation of stroke_attribute_t.del_pool.
269 */
270 static void del_pool(private_stroke_attribute_t *this, stroke_msg_t *msg)
271 {
272 enumerator_t *enumerator;
273 pool_t *pool;
274
275 this->mutex->lock(this->mutex);
276 enumerator = this->pools->create_enumerator(this->pools);
277 while (enumerator->enumerate(enumerator, &pool))
278 {
279 if (streq(msg->del_conn.name, pool->name))
280 {
281 this->pools->remove_at(this->pools, enumerator);
282 pool_destroy(pool);
283 break;
284 }
285 }
286 enumerator->destroy(enumerator);
287 this->mutex->unlock(this->mutex);
288 }
289
290 /**
291 * Implementation of stroke_attribute_t.destroy
292 */
293 static void destroy(private_stroke_attribute_t *this)
294 {
295 this->mutex->destroy(this->mutex);
296 this->pools->destroy_function(this->pools, (void*)pool_destroy);
297 free(this);
298 }
299
300 /*
301 * see header file
302 */
303 stroke_attribute_t *stroke_attribute_create()
304 {
305 private_stroke_attribute_t *this = malloc_thing(private_stroke_attribute_t);
306
307 this->public.provider.acquire_address = (host_t*(*)(attribute_provider_t *this, char*, identification_t *,auth_info_t *, host_t *))acquire_address;
308 this->public.provider.release_address = (bool(*)(attribute_provider_t *this, char*,host_t *))release_address;
309 this->public.add_pool = (void(*)(stroke_attribute_t*, stroke_msg_t *msg))add_pool;
310 this->public.del_pool = (void(*)(stroke_attribute_t*, stroke_msg_t *msg))del_pool;
311 this->public.destroy = (void(*)(stroke_attribute_t*))destroy;
312
313 this->pools = linked_list_create();
314 this->mutex = mutex_create(MUTEX_DEFAULT);
315
316 return &this->public;
317 }
318