svn cleanup
[anytun.git] / openvpn / pool.c
blobcb666b80238c05b521b0b56c644be9da7f45e21a
1 /*
2 * OpenVPN -- An application to securely tunnel IP networks
3 * over a single TCP/UDP port, with support for SSL/TLS-based
4 * session authentication and key exchange,
5 * packet encryption, packet authentication, and
6 * packet compression.
8 * Copyright (C) 2002-2005 OpenVPN Solutions LLC <info@openvpn.net>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2
12 * as published by the Free Software Foundation.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program (see the file COPYING included with this
21 * distribution); if not, write to the Free Software Foundation, Inc.,
22 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #ifdef WIN32
26 #include "config-win32.h"
27 #else
28 #include "config.h"
29 #endif
31 #include "syshead.h"
33 #include "pool.h"
34 #include "buffer.h"
35 #include "error.h"
36 #include "socket.h"
37 #include "otime.h"
39 #include "memdbg.h"
41 #if P2MP
43 static void
44 ifconfig_pool_entry_free (struct ifconfig_pool_entry *ipe, bool hard)
46 ipe->in_use = false;
47 if (hard && ipe->common_name)
49 free (ipe->common_name);
50 ipe->common_name = NULL;
52 if (hard)
53 ipe->last_release = 0;
54 else
55 ipe->last_release = now;
58 static int
59 ifconfig_pool_find (struct ifconfig_pool *pool, const char *common_name)
61 int i;
62 time_t earliest_release = 0;
63 int previous_usage = -1;
64 int new_usage = -1;
66 for (i = 0; i < pool->size; ++i)
68 struct ifconfig_pool_entry *ipe = &pool->list[i];
69 if (!ipe->in_use)
72 * If duplicate_cn mode, take first available IP address
74 if (pool->duplicate_cn)
76 new_usage = i;
77 break;
81 * Keep track of the unused IP address entry which
82 * was released earliest.
84 if ((new_usage == -1 || ipe->last_release < earliest_release) && !ipe->fixed)
86 earliest_release = ipe->last_release;
87 new_usage = i;
91 * Keep track of a possible allocation to us
92 * from an earlier session.
94 if (previous_usage < 0
95 && common_name
96 && ipe->common_name
97 && !strcmp (common_name, ipe->common_name))
98 previous_usage = i;
103 if (previous_usage >= 0)
104 return previous_usage;
106 if (new_usage >= 0)
107 return new_usage;
109 return -1;
113 * Verify start/end range
115 bool
116 ifconfig_pool_verify_range (const int msglevel, const in_addr_t start, const in_addr_t end)
118 struct gc_arena gc = gc_new ();
119 bool ret = true;
121 if (start > end)
123 msg (msglevel, "--ifconfig-pool start IP [%s] is greater than end IP [%s]",
124 print_in_addr_t (start, 0, &gc),
125 print_in_addr_t (end, 0, &gc));
126 ret = false;
128 if (end - start >= IFCONFIG_POOL_MAX)
130 msg (msglevel, "--ifconfig-pool address range is too large [%s -> %s]. Current maximum is %d addresses, as defined by IFCONFIG_POOL_MAX variable.",
131 print_in_addr_t (start, 0, &gc),
132 print_in_addr_t (end, 0, &gc),
133 IFCONFIG_POOL_MAX);
134 ret = false;
136 gc_free (&gc);
137 return ret;
140 struct ifconfig_pool *
141 ifconfig_pool_init (int type, in_addr_t start, in_addr_t end, const bool duplicate_cn)
143 struct gc_arena gc = gc_new ();
144 struct ifconfig_pool *pool = NULL;
146 ASSERT (start <= end && end - start < IFCONFIG_POOL_MAX);
147 ALLOC_OBJ_CLEAR (pool, struct ifconfig_pool);
149 pool->type = type;
150 pool->duplicate_cn = duplicate_cn;
152 switch (type)
154 case IFCONFIG_POOL_30NET:
155 pool->base = start & ~3;
156 pool->size = (((end | 3) + 1) - pool->base) >> 2;
157 break;
158 case IFCONFIG_POOL_INDIV:
159 pool->base = start;
160 pool->size = end - start + 1;
161 break;
162 default:
163 ASSERT (0);
166 ALLOC_ARRAY_CLEAR (pool->list, struct ifconfig_pool_entry, pool->size);
168 msg (D_IFCONFIG_POOL, "IFCONFIG POOL: base=%s size=%d",
169 print_in_addr_t (pool->base, 0, &gc),
170 pool->size);
172 gc_free (&gc);
173 return pool;
176 void
177 ifconfig_pool_free (struct ifconfig_pool *pool)
179 if (pool)
181 int i;
182 for (i = 0; i < pool->size; ++i)
183 ifconfig_pool_entry_free (&pool->list[i], true);
184 free (pool->list);
185 free (pool);
189 ifconfig_pool_handle
190 ifconfig_pool_acquire (struct ifconfig_pool *pool, in_addr_t *local, in_addr_t *remote, const char *common_name)
192 int i;
194 i = ifconfig_pool_find (pool, common_name);
195 if (i >= 0)
197 struct ifconfig_pool_entry *ipe = &pool->list[i];
198 ASSERT (!ipe->in_use);
199 ifconfig_pool_entry_free (ipe, true);
200 ipe->in_use = true;
201 if (common_name)
202 ipe->common_name = string_alloc (common_name, NULL);
204 switch (pool->type)
206 case IFCONFIG_POOL_30NET:
208 in_addr_t b = pool->base + (i << 2);
209 *local = b + 1;
210 *remote = b + 2;
211 break;
213 case IFCONFIG_POOL_INDIV:
215 in_addr_t b = pool->base + i;
216 *local = 0;
217 *remote = b;
218 break;
220 default:
221 ASSERT (0);
224 return i;
227 bool
228 ifconfig_pool_release (struct ifconfig_pool* pool, ifconfig_pool_handle hand, const bool hard)
230 bool ret = false;
231 if (pool && hand >= 0 && hand < pool->size)
233 ifconfig_pool_entry_free (&pool->list[hand], hard);
234 ret = true;
236 return ret;
240 * private access functions
243 static ifconfig_pool_handle
244 ifconfig_pool_ip_base_to_handle (const struct ifconfig_pool* pool, const in_addr_t addr)
246 ifconfig_pool_handle ret = -1;
248 switch (pool->type)
250 case IFCONFIG_POOL_30NET:
252 ret = (addr - pool->base) >> 2;
253 break;
255 case IFCONFIG_POOL_INDIV:
257 ret = (addr - pool->base);
258 break;
260 default:
261 ASSERT (0);
264 if (ret < 0 || ret >= pool->size)
265 ret = -1;
267 return ret;
270 static in_addr_t
271 ifconfig_pool_handle_to_ip_base (const struct ifconfig_pool* pool, ifconfig_pool_handle hand)
273 in_addr_t ret = 0;
275 if (hand >= 0 && hand < pool->size)
277 switch (pool->type)
279 case IFCONFIG_POOL_30NET:
281 ret = pool->base + (hand << 2);;
282 break;
284 case IFCONFIG_POOL_INDIV:
286 ret = pool->base + hand;
287 break;
289 default:
290 ASSERT (0);
294 return ret;
297 static void
298 ifconfig_pool_set (struct ifconfig_pool* pool, const char *cn, const in_addr_t addr, const bool fixed)
300 ifconfig_pool_handle h = ifconfig_pool_ip_base_to_handle (pool, addr);
301 if (h >= 0)
303 struct ifconfig_pool_entry *e = &pool->list[h];
304 ifconfig_pool_entry_free (e, true);
305 e->in_use = false;
306 e->common_name = string_alloc (cn, NULL);
307 e->last_release = now;
308 e->fixed = fixed;
312 static void
313 ifconfig_pool_list (const struct ifconfig_pool* pool, struct status_output *out)
315 if (pool && out)
317 struct gc_arena gc = gc_new ();
318 int i;
320 for (i = 0; i < pool->size; ++i)
322 const struct ifconfig_pool_entry *e = &pool->list[i];
323 if (e->common_name)
325 const in_addr_t ip = ifconfig_pool_handle_to_ip_base (pool, i);
326 status_printf (out, "%s,%s",
327 e->common_name,
328 print_in_addr_t (ip, 0, &gc));
331 gc_free (&gc);
335 static void
336 ifconfig_pool_msg (const struct ifconfig_pool* pool, int msglevel)
338 struct status_output *so = status_open (NULL, 0, msglevel, NULL, 0);
339 ASSERT (so);
340 status_printf (so, "IFCONFIG POOL LIST");
341 ifconfig_pool_list (pool, so);
342 status_close (so);
346 * Deal with reading/writing the ifconfig pool database to a file
349 struct ifconfig_pool_persist *
350 ifconfig_pool_persist_init (const char *filename, int refresh_freq)
352 struct ifconfig_pool_persist *ret;
354 ASSERT (filename);
356 ALLOC_OBJ_CLEAR (ret, struct ifconfig_pool_persist);
357 if (refresh_freq > 0)
359 ret->fixed = false;
360 ret->file = status_open (filename, refresh_freq, -1, NULL, STATUS_OUTPUT_READ|STATUS_OUTPUT_WRITE);
362 else
364 ret->fixed = true;
365 ret->file = status_open (filename, 0, -1, NULL, STATUS_OUTPUT_READ);
367 return ret;
370 void
371 ifconfig_pool_persist_close (struct ifconfig_pool_persist *persist)
373 if (persist)
375 if (persist->file)
376 status_close (persist->file);
377 free (persist);
381 bool
382 ifconfig_pool_write_trigger (struct ifconfig_pool_persist *persist)
384 if (persist->file)
385 return status_trigger (persist->file);
386 else
387 return false;
390 void
391 ifconfig_pool_read (struct ifconfig_pool_persist *persist, struct ifconfig_pool *pool)
393 const int buf_size = 128;
395 update_time ();
396 if (persist && persist->file && pool)
398 struct gc_arena gc = gc_new ();
399 struct buffer in = alloc_buf_gc (256, &gc);
400 char *cn_buf;
401 char *ip_buf;
402 int line = 0;
404 ALLOC_ARRAY_CLEAR_GC (cn_buf, char, buf_size, &gc);
405 ALLOC_ARRAY_CLEAR_GC (ip_buf, char, buf_size, &gc);
407 while (true)
409 ASSERT (buf_init (&in, 0));
410 if (!status_read (persist->file, &in))
411 break;
412 ++line;
413 if (BLEN (&in))
415 int c = *BSTR(&in);
416 if (c == '#' || c == ';')
417 continue;
418 if (buf_parse (&in, ',', cn_buf, buf_size)
419 && buf_parse (&in, ',', ip_buf, buf_size))
421 bool succeeded;
422 const in_addr_t addr = getaddr (GETADDR_HOST_ORDER, ip_buf, 0, &succeeded, NULL);
423 if (succeeded)
425 ifconfig_pool_set (pool, cn_buf, addr, persist->fixed);
431 ifconfig_pool_msg (pool, D_IFCONFIG_POOL);
433 gc_free (&gc);
437 void
438 ifconfig_pool_write (struct ifconfig_pool_persist *persist, const struct ifconfig_pool *pool)
440 if (persist && persist->file && (status_rw_flags (persist->file) & STATUS_OUTPUT_WRITE) && pool)
442 status_reset (persist->file);
443 ifconfig_pool_list (pool, persist->file);
444 status_flush (persist->file);
449 * TESTING ONLY
452 #ifdef IFCONFIG_POOL_TEST
454 #define DUP_CN
456 void
457 ifconfig_pool_test (in_addr_t start, in_addr_t end)
459 struct gc_arena gc = gc_new ();
460 struct ifconfig_pool *p = ifconfig_pool_init (IFCONFIG_POOL_30NET, start, end);
461 /*struct ifconfig_pool *p = ifconfig_pool_init (IFCONFIG_POOL_INDIV, start, end);*/
462 ifconfig_pool_handle array[256];
463 int i;
465 CLEAR (array);
467 msg (M_INFO | M_NOPREFIX, "************ 1");
468 for (i = 0; i < (int) SIZE (array); ++i)
470 char *cn;
471 ifconfig_pool_handle h;
472 in_addr_t local, remote;
473 char buf[256];
474 openvpn_snprintf (buf, sizeof(buf), "common-name-%d", i);
475 #ifdef DUP_CN
476 cn = NULL;
477 #else
478 cn = buf;
479 #endif
480 h = ifconfig_pool_acquire (p, &local, &remote, cn);
481 if (h < 0)
482 break;
483 msg (M_INFO | M_NOPREFIX, "IFCONFIG_POOL TEST pass 1: l=%s r=%s cn=%s",
484 print_in_addr_t (local, 0, &gc),
485 print_in_addr_t (remote, 0, &gc),
486 cn);
487 array[i] = h;
491 msg (M_INFO | M_NOPREFIX, "************* 2");
492 for (i = (int) SIZE (array) / 16; i < (int) SIZE (array) / 8; ++i)
494 msg (M_INFO, "Attempt to release %d cn=%s", array[i], p->list[i].common_name);
495 if (!ifconfig_pool_release (p, array[i]))
496 break;
497 msg (M_INFO, "Succeeded");
500 CLEAR (array);
502 msg (M_INFO | M_NOPREFIX, "**************** 3");
503 for (i = 0; i < (int) SIZE (array); ++i)
505 char *cn;
506 ifconfig_pool_handle h;
507 in_addr_t local, remote;
508 char buf[256];
509 snprintf (buf, sizeof(buf), "common-name-%d", i+24);
510 #ifdef DUP_CN
511 cn = NULL;
512 #else
513 cn = buf;
514 #endif
515 h = ifconfig_pool_acquire (p, &local, &remote, cn);
516 if (h < 0)
517 break;
518 msg (M_INFO | M_NOPREFIX, "IFCONFIG_POOL TEST pass 3: l=%s r=%s cn=%s",
519 print_in_addr_t (local, 0, &gc),
520 print_in_addr_t (remote, 0, &gc),
521 cn);
522 array[i] = h;
526 ifconfig_pool_free (p);
527 gc_free (&gc);
530 #endif
532 #endif