cosmetics
[tomato.git] / release / src / router / openvpn / pool.c
blob5600083421152f99ff422366f2a5a5d9c2da75fb
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-2009 OpenVPN Technologies, Inc. <sales@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 #include "syshead.h"
27 #include "pool.h"
28 #include "buffer.h"
29 #include "error.h"
30 #include "socket.h"
31 #include "otime.h"
33 #include "memdbg.h"
35 #if P2MP
37 static void
38 ifconfig_pool_entry_free (struct ifconfig_pool_entry *ipe, bool hard)
40 ipe->in_use = false;
41 if (hard && ipe->common_name)
43 free (ipe->common_name);
44 ipe->common_name = NULL;
46 if (hard)
47 ipe->last_release = 0;
48 else
49 ipe->last_release = now;
52 static int
53 ifconfig_pool_find (struct ifconfig_pool *pool, const char *common_name)
55 int i;
56 time_t earliest_release = 0;
57 int previous_usage = -1;
58 int new_usage = -1;
60 for (i = 0; i < pool->size; ++i)
62 struct ifconfig_pool_entry *ipe = &pool->list[i];
63 if (!ipe->in_use)
66 * If duplicate_cn mode, take first available IP address
68 if (pool->duplicate_cn)
70 new_usage = i;
71 break;
75 * Keep track of the unused IP address entry which
76 * was released earliest.
78 if ((new_usage == -1 || ipe->last_release < earliest_release) && !ipe->fixed)
80 earliest_release = ipe->last_release;
81 new_usage = i;
85 * Keep track of a possible allocation to us
86 * from an earlier session.
88 if (previous_usage < 0
89 && common_name
90 && ipe->common_name
91 && !strcmp (common_name, ipe->common_name))
92 previous_usage = i;
97 if (previous_usage >= 0)
98 return previous_usage;
100 if (new_usage >= 0)
101 return new_usage;
103 return -1;
107 * Verify start/end range
109 bool
110 ifconfig_pool_verify_range (const int msglevel, const in_addr_t start, const in_addr_t end)
112 struct gc_arena gc = gc_new ();
113 bool ret = true;
115 if (start > end)
117 msg (msglevel, "--ifconfig-pool start IP [%s] is greater than end IP [%s]",
118 print_in_addr_t (start, 0, &gc),
119 print_in_addr_t (end, 0, &gc));
120 ret = false;
122 if (end - start >= IFCONFIG_POOL_MAX)
124 msg (msglevel, "--ifconfig-pool address range is too large [%s -> %s]. Current maximum is %d addresses, as defined by IFCONFIG_POOL_MAX variable.",
125 print_in_addr_t (start, 0, &gc),
126 print_in_addr_t (end, 0, &gc),
127 IFCONFIG_POOL_MAX);
128 ret = false;
130 gc_free (&gc);
131 return ret;
134 struct ifconfig_pool *
135 ifconfig_pool_init (int type, in_addr_t start, in_addr_t end, const bool duplicate_cn)
137 struct gc_arena gc = gc_new ();
138 struct ifconfig_pool *pool = NULL;
140 ASSERT (start <= end && end - start < IFCONFIG_POOL_MAX);
141 ALLOC_OBJ_CLEAR (pool, struct ifconfig_pool);
143 pool->type = type;
144 pool->duplicate_cn = duplicate_cn;
146 switch (type)
148 case IFCONFIG_POOL_30NET:
149 pool->base = start & ~3;
150 pool->size = (((end | 3) + 1) - pool->base) >> 2;
151 break;
152 case IFCONFIG_POOL_INDIV:
153 pool->base = start;
154 pool->size = end - start + 1;
155 break;
156 default:
157 ASSERT (0);
160 ALLOC_ARRAY_CLEAR (pool->list, struct ifconfig_pool_entry, pool->size);
162 msg (D_IFCONFIG_POOL, "IFCONFIG POOL: base=%s size=%d",
163 print_in_addr_t (pool->base, 0, &gc),
164 pool->size);
166 gc_free (&gc);
167 return pool;
170 void
171 ifconfig_pool_free (struct ifconfig_pool *pool)
173 if (pool)
175 int i;
176 for (i = 0; i < pool->size; ++i)
177 ifconfig_pool_entry_free (&pool->list[i], true);
178 free (pool->list);
179 free (pool);
183 ifconfig_pool_handle
184 ifconfig_pool_acquire (struct ifconfig_pool *pool, in_addr_t *local, in_addr_t *remote, const char *common_name)
186 int i;
188 i = ifconfig_pool_find (pool, common_name);
189 if (i >= 0)
191 struct ifconfig_pool_entry *ipe = &pool->list[i];
192 ASSERT (!ipe->in_use);
193 ifconfig_pool_entry_free (ipe, true);
194 ipe->in_use = true;
195 if (common_name)
196 ipe->common_name = string_alloc (common_name, NULL);
198 switch (pool->type)
200 case IFCONFIG_POOL_30NET:
202 in_addr_t b = pool->base + (i << 2);
203 *local = b + 1;
204 *remote = b + 2;
205 break;
207 case IFCONFIG_POOL_INDIV:
209 in_addr_t b = pool->base + i;
210 *local = 0;
211 *remote = b;
212 break;
214 default:
215 ASSERT (0);
218 return i;
221 bool
222 ifconfig_pool_release (struct ifconfig_pool* pool, ifconfig_pool_handle hand, const bool hard)
224 bool ret = false;
225 if (pool && hand >= 0 && hand < pool->size)
227 ifconfig_pool_entry_free (&pool->list[hand], hard);
228 ret = true;
230 return ret;
234 * private access functions
237 static ifconfig_pool_handle
238 ifconfig_pool_ip_base_to_handle (const struct ifconfig_pool* pool, const in_addr_t addr)
240 ifconfig_pool_handle ret = -1;
242 switch (pool->type)
244 case IFCONFIG_POOL_30NET:
246 ret = (addr - pool->base) >> 2;
247 break;
249 case IFCONFIG_POOL_INDIV:
251 ret = (addr - pool->base);
252 break;
254 default:
255 ASSERT (0);
258 if (ret < 0 || ret >= pool->size)
259 ret = -1;
261 return ret;
264 static in_addr_t
265 ifconfig_pool_handle_to_ip_base (const struct ifconfig_pool* pool, ifconfig_pool_handle hand)
267 in_addr_t ret = 0;
269 if (hand >= 0 && hand < pool->size)
271 switch (pool->type)
273 case IFCONFIG_POOL_30NET:
275 ret = pool->base + (hand << 2);;
276 break;
278 case IFCONFIG_POOL_INDIV:
280 ret = pool->base + hand;
281 break;
283 default:
284 ASSERT (0);
288 return ret;
291 static void
292 ifconfig_pool_set (struct ifconfig_pool* pool, const char *cn, const in_addr_t addr, const bool fixed)
294 ifconfig_pool_handle h = ifconfig_pool_ip_base_to_handle (pool, addr);
295 if (h >= 0)
297 struct ifconfig_pool_entry *e = &pool->list[h];
298 ifconfig_pool_entry_free (e, true);
299 e->in_use = false;
300 e->common_name = string_alloc (cn, NULL);
301 e->last_release = now;
302 e->fixed = fixed;
306 static void
307 ifconfig_pool_list (const struct ifconfig_pool* pool, struct status_output *out)
309 if (pool && out)
311 struct gc_arena gc = gc_new ();
312 int i;
314 for (i = 0; i < pool->size; ++i)
316 const struct ifconfig_pool_entry *e = &pool->list[i];
317 if (e->common_name)
319 const in_addr_t ip = ifconfig_pool_handle_to_ip_base (pool, i);
320 status_printf (out, "%s,%s",
321 e->common_name,
322 print_in_addr_t (ip, 0, &gc));
325 gc_free (&gc);
329 static void
330 ifconfig_pool_msg (const struct ifconfig_pool* pool, int msglevel)
332 struct status_output *so = status_open (NULL, 0, msglevel, NULL, 0);
333 ASSERT (so);
334 status_printf (so, "IFCONFIG POOL LIST");
335 ifconfig_pool_list (pool, so);
336 status_close (so);
340 * Deal with reading/writing the ifconfig pool database to a file
343 struct ifconfig_pool_persist *
344 ifconfig_pool_persist_init (const char *filename, int refresh_freq)
346 struct ifconfig_pool_persist *ret;
348 ASSERT (filename);
350 ALLOC_OBJ_CLEAR (ret, struct ifconfig_pool_persist);
351 if (refresh_freq > 0)
353 ret->fixed = false;
354 ret->file = status_open (filename, refresh_freq, -1, NULL, STATUS_OUTPUT_READ|STATUS_OUTPUT_WRITE);
356 else
358 ret->fixed = true;
359 ret->file = status_open (filename, 0, -1, NULL, STATUS_OUTPUT_READ);
361 return ret;
364 void
365 ifconfig_pool_persist_close (struct ifconfig_pool_persist *persist)
367 if (persist)
369 if (persist->file)
370 status_close (persist->file);
371 free (persist);
375 bool
376 ifconfig_pool_write_trigger (struct ifconfig_pool_persist *persist)
378 if (persist->file)
379 return status_trigger (persist->file);
380 else
381 return false;
384 void
385 ifconfig_pool_read (struct ifconfig_pool_persist *persist, struct ifconfig_pool *pool)
387 const int buf_size = 128;
389 update_time ();
390 if (persist && persist->file && pool)
392 struct gc_arena gc = gc_new ();
393 struct buffer in = alloc_buf_gc (256, &gc);
394 char *cn_buf;
395 char *ip_buf;
396 int line = 0;
398 ALLOC_ARRAY_CLEAR_GC (cn_buf, char, buf_size, &gc);
399 ALLOC_ARRAY_CLEAR_GC (ip_buf, char, buf_size, &gc);
401 while (true)
403 ASSERT (buf_init (&in, 0));
404 if (!status_read (persist->file, &in))
405 break;
406 ++line;
407 if (BLEN (&in))
409 int c = *BSTR(&in);
410 if (c == '#' || c == ';')
411 continue;
412 if (buf_parse (&in, ',', cn_buf, buf_size)
413 && buf_parse (&in, ',', ip_buf, buf_size))
415 bool succeeded;
416 const in_addr_t addr = getaddr (GETADDR_HOST_ORDER, ip_buf, 0, &succeeded, NULL);
417 if (succeeded)
419 ifconfig_pool_set (pool, cn_buf, addr, persist->fixed);
425 ifconfig_pool_msg (pool, D_IFCONFIG_POOL);
427 gc_free (&gc);
431 void
432 ifconfig_pool_write (struct ifconfig_pool_persist *persist, const struct ifconfig_pool *pool)
434 if (persist && persist->file && (status_rw_flags (persist->file) & STATUS_OUTPUT_WRITE) && pool)
436 status_reset (persist->file);
437 ifconfig_pool_list (pool, persist->file);
438 status_flush (persist->file);
443 * TESTING ONLY
446 #ifdef IFCONFIG_POOL_TEST
448 #define DUP_CN
450 void
451 ifconfig_pool_test (in_addr_t start, in_addr_t end)
453 struct gc_arena gc = gc_new ();
454 struct ifconfig_pool *p = ifconfig_pool_init (IFCONFIG_POOL_30NET, start, end);
455 /*struct ifconfig_pool *p = ifconfig_pool_init (IFCONFIG_POOL_INDIV, start, end);*/
456 ifconfig_pool_handle array[256];
457 int i;
459 CLEAR (array);
461 msg (M_INFO | M_NOPREFIX, "************ 1");
462 for (i = 0; i < (int) SIZE (array); ++i)
464 char *cn;
465 ifconfig_pool_handle h;
466 in_addr_t local, remote;
467 char buf[256];
468 openvpn_snprintf (buf, sizeof(buf), "common-name-%d", i);
469 #ifdef DUP_CN
470 cn = NULL;
471 #else
472 cn = buf;
473 #endif
474 h = ifconfig_pool_acquire (p, &local, &remote, cn);
475 if (h < 0)
476 break;
477 msg (M_INFO | M_NOPREFIX, "IFCONFIG_POOL TEST pass 1: l=%s r=%s cn=%s",
478 print_in_addr_t (local, 0, &gc),
479 print_in_addr_t (remote, 0, &gc),
480 cn);
481 array[i] = h;
485 msg (M_INFO | M_NOPREFIX, "************* 2");
486 for (i = (int) SIZE (array) / 16; i < (int) SIZE (array) / 8; ++i)
488 msg (M_INFO, "Attempt to release %d cn=%s", array[i], p->list[i].common_name);
489 if (!ifconfig_pool_release (p, array[i]))
490 break;
491 msg (M_INFO, "Succeeded");
494 CLEAR (array);
496 msg (M_INFO | M_NOPREFIX, "**************** 3");
497 for (i = 0; i < (int) SIZE (array); ++i)
499 char *cn;
500 ifconfig_pool_handle h;
501 in_addr_t local, remote;
502 char buf[256];
503 snprintf (buf, sizeof(buf), "common-name-%d", i+24);
504 #ifdef DUP_CN
505 cn = NULL;
506 #else
507 cn = buf;
508 #endif
509 h = ifconfig_pool_acquire (p, &local, &remote, cn);
510 if (h < 0)
511 break;
512 msg (M_INFO | M_NOPREFIX, "IFCONFIG_POOL TEST pass 3: l=%s r=%s cn=%s",
513 print_in_addr_t (local, 0, &gc),
514 print_in_addr_t (remote, 0, &gc),
515 cn);
516 array[i] = h;
520 ifconfig_pool_free (p);
521 gc_free (&gc);
524 #endif
526 #endif