OpenVPN
pool.c
Go to the documentation of this file.
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.
7  *
8  * Copyright (C) 2002-2018 OpenVPN Inc <sales@openvpn.net>
9  *
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.
13  *
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.
18  *
19  * You should have received a copy of the GNU General Public License along
20  * with this program; if not, write to the Free Software Foundation, Inc.,
21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22  */
23 
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #elif defined(_MSC_VER)
27 #include "config-msvc.h"
28 #endif
29 
30 #include "syshead.h"
31 
32 #include "pool.h"
33 #include "buffer.h"
34 #include "error.h"
35 #include "socket.h"
36 #include "otime.h"
37 
38 #include "memdbg.h"
39 
40 #if P2MP
41 
42 static void
44 {
45  ipe->in_use = false;
46  if (hard && ipe->common_name)
47  {
48  free(ipe->common_name);
49  ipe->common_name = NULL;
50  }
51  if (hard)
52  {
53  ipe->last_release = 0;
54  }
55  else
56  {
57  ipe->last_release = now;
58  }
59 }
60 
61 static int
62 ifconfig_pool_find(struct ifconfig_pool *pool, const char *common_name)
63 {
64  int i;
65  time_t earliest_release = 0;
66  int previous_usage = -1;
67  int new_usage = -1;
68 
69  for (i = 0; i < pool->ipv4.size; ++i)
70  {
71  struct ifconfig_pool_entry *ipe = &pool->list[i];
72  if (!ipe->in_use)
73  {
74  /*
75  * If duplicate_cn mode, take first available IP address
76  */
77  if (pool->duplicate_cn)
78  {
79  new_usage = i;
80  break;
81  }
82 
83  /*
84  * Keep track of the unused IP address entry which
85  * was released earliest.
86  */
87  if ((new_usage == -1 || ipe->last_release < earliest_release) && !ipe->fixed)
88  {
89  earliest_release = ipe->last_release;
90  new_usage = i;
91  }
92 
93  /*
94  * Keep track of a possible allocation to us
95  * from an earlier session.
96  */
97  if (previous_usage < 0
98  && common_name
99  && ipe->common_name
100  && !strcmp(common_name, ipe->common_name))
101  {
102  previous_usage = i;
103  }
104 
105  }
106  }
107 
108  if (previous_usage >= 0)
109  {
110  return previous_usage;
111  }
112 
113  if (new_usage >= 0)
114  {
115  return new_usage;
116  }
117 
118  return -1;
119 }
120 
121 /*
122  * Verify start/end range
123  */
124 bool
125 ifconfig_pool_verify_range(const int msglevel, const in_addr_t start, const in_addr_t end)
126 {
127  struct gc_arena gc = gc_new();
128  bool ret = true;
129 
130  if (start > end)
131  {
132  msg(msglevel, "--ifconfig-pool start IP [%s] is greater than end IP [%s]",
133  print_in_addr_t(start, 0, &gc),
134  print_in_addr_t(end, 0, &gc));
135  ret = false;
136  }
137  if (end - start >= IFCONFIG_POOL_MAX)
138  {
139  msg(msglevel, "--ifconfig-pool address range is too large [%s -> %s]. Current maximum is %d addresses, as defined by IFCONFIG_POOL_MAX variable.",
140  print_in_addr_t(start, 0, &gc),
141  print_in_addr_t(end, 0, &gc),
143  ret = false;
144  }
145  gc_free(&gc);
146  return ret;
147 }
148 
149 struct ifconfig_pool *
151  const bool duplicate_cn,
152  const bool ipv6_pool, const struct in6_addr ipv6_base,
153  const int ipv6_netbits )
154 {
155  struct gc_arena gc = gc_new();
156  struct ifconfig_pool *pool = NULL;
157 
158  ASSERT(start <= end && end - start < IFCONFIG_POOL_MAX);
159  ALLOC_OBJ_CLEAR(pool, struct ifconfig_pool);
160 
161  pool->ipv4.type = type;
162  pool->duplicate_cn = duplicate_cn;
163 
164  switch (pool->ipv4.type)
165  {
166  case IFCONFIG_POOL_30NET:
167  pool->ipv4.base = start & ~3;
168  pool->ipv4.size = (((end | 3) + 1) - pool->ipv4.base) >> 2;
169  break;
170 
171  case IFCONFIG_POOL_INDIV:
172  pool->ipv4.base = start;
173  pool->ipv4.size = end - start + 1;
174  break;
175 
176  default:
177  ASSERT(0);
178  }
179 
180  /* IPv6 pools are always "INDIV" type */
181  pool->ipv6.enabled = ipv6_pool;
182 
183  if (pool->ipv6.enabled)
184  {
185  pool->ipv6.base = ipv6_base;
186  pool->ipv6.size = ipv6_netbits > 96 ? (1 << (128 - ipv6_netbits))
188 
189  msg( D_IFCONFIG_POOL, "IFCONFIG POOL IPv6: (IPv4) size=%d, size_ipv6=%d, netbits=%d, base_ipv6=%s",
190  pool->ipv4.size, pool->ipv6.size, ipv6_netbits,
191  print_in6_addr(pool->ipv6.base, 0, &gc));
192 
193  /* the current code is very simple and assumes that the IPv6
194  * pool is at least as big as the IPv4 pool, and we don't need
195  * to do separate math etc. for IPv6
196  */
197  ASSERT(pool->ipv4.size < pool->ipv6.size);
198  }
199 
200  ALLOC_ARRAY_CLEAR(pool->list, struct ifconfig_pool_entry, pool->ipv4.size);
201 
202  msg(D_IFCONFIG_POOL, "IFCONFIG POOL: base=%s size=%d, ipv6=%d",
203  print_in_addr_t(pool->ipv4.base, 0, &gc),
204  pool->ipv4.size, pool->ipv6.enabled);
205 
206  gc_free(&gc);
207  return pool;
208 }
209 
210 void
212 {
213  if (pool)
214  {
215  int i;
216  for (i = 0; i < pool->ipv4.size; ++i)
217  {
218  ifconfig_pool_entry_free(&pool->list[i], true);
219  }
220  free(pool->list);
221  free(pool);
222  }
223 }
224 
226 ifconfig_pool_acquire(struct ifconfig_pool *pool, in_addr_t *local, in_addr_t *remote, struct in6_addr *remote_ipv6, const char *common_name)
227 {
228  int i;
229 
230  i = ifconfig_pool_find(pool, common_name);
231  if (i >= 0)
232  {
233  struct ifconfig_pool_entry *ipe = &pool->list[i];
234  ASSERT(!ipe->in_use);
235  ifconfig_pool_entry_free(ipe, true);
236  ipe->in_use = true;
237  if (common_name)
238  {
239  ipe->common_name = string_alloc(common_name, NULL);
240  }
241 
242  switch (pool->ipv4.type)
243  {
244  case IFCONFIG_POOL_30NET:
245  {
246  in_addr_t b = pool->ipv4.base + (i << 2);
247  *local = b + 1;
248  *remote = b + 2;
249  break;
250  }
251 
252  case IFCONFIG_POOL_INDIV:
253  {
254  in_addr_t b = pool->ipv4.base + i;
255  *local = 0;
256  *remote = b;
257  break;
258  }
259 
260  default:
261  ASSERT(0);
262  }
263 
264  /* IPv6 pools are always INDIV (--linear) */
265  if (pool->ipv6.enabled && remote_ipv6)
266  {
267  *remote_ipv6 = add_in6_addr(pool->ipv6.base, i);
268  }
269  }
270  return i;
271 }
272 
273 bool
274 ifconfig_pool_release(struct ifconfig_pool *pool, ifconfig_pool_handle hand, const bool hard)
275 {
276  bool ret = false;
277  if (pool && hand >= 0 && hand < pool->ipv4.size)
278  {
279  ifconfig_pool_entry_free(&pool->list[hand], hard);
280  ret = true;
281  }
282  return ret;
283 }
284 
285 /*
286  * private access functions
287  */
288 
291 {
292  ifconfig_pool_handle ret = -1;
293 
294  switch (pool->ipv4.type)
295  {
296  case IFCONFIG_POOL_30NET:
297  {
298  ret = (addr - pool->ipv4.base) >> 2;
299  break;
300  }
301 
302  case IFCONFIG_POOL_INDIV:
303  {
304  ret = (addr - pool->ipv4.base);
305  break;
306  }
307 
308  default:
309  ASSERT(0);
310  }
311 
312  if (ret < 0 || ret >= pool->ipv4.size)
313  {
314  ret = -1;
315  }
316 
317  return ret;
318 }
319 
320 static in_addr_t
322 {
323  in_addr_t ret = 0;
324 
325  if (hand >= 0 && hand < pool->ipv4.size)
326  {
327  switch (pool->ipv4.type)
328  {
329  case IFCONFIG_POOL_30NET:
330  {
331  ret = pool->ipv4.base + (hand << 2);
332  break;
333  }
334 
335  case IFCONFIG_POOL_INDIV:
336  {
337  ret = pool->ipv4.base + hand;
338  break;
339  }
340 
341  default:
342  ASSERT(0);
343  }
344  }
345 
346  return ret;
347 }
348 
349 static struct in6_addr
351 {
352  struct in6_addr ret = in6addr_any;
353 
354  /* IPv6 pools are always INDIV (--linear) */
355  if (hand >= 0 && hand < pool->ipv6.size)
356  {
357  ret = add_in6_addr( pool->ipv6.base, hand );
358  }
359  return ret;
360 }
361 
362 static void
363 ifconfig_pool_set(struct ifconfig_pool *pool, const char *cn, const in_addr_t addr, const bool fixed)
364 {
366  if (h >= 0)
367  {
368  struct ifconfig_pool_entry *e = &pool->list[h];
369  ifconfig_pool_entry_free(e, true);
370  e->in_use = false;
371  e->common_name = string_alloc(cn, NULL);
372  e->last_release = now;
373  e->fixed = fixed;
374  }
375 }
376 
377 static void
378 ifconfig_pool_list(const struct ifconfig_pool *pool, struct status_output *out)
379 {
380  if (pool && out)
381  {
382  struct gc_arena gc = gc_new();
383  int i;
384 
385  for (i = 0; i < pool->ipv4.size; ++i)
386  {
387  const struct ifconfig_pool_entry *e = &pool->list[i];
388  if (e->common_name)
389  {
390  const in_addr_t ip = ifconfig_pool_handle_to_ip_base(pool, i);
391  if (pool->ipv6.enabled)
392  {
393  struct in6_addr ip6 = ifconfig_pool_handle_to_ipv6_base(pool, i);
394  status_printf(out, "%s,%s,%s",
395  e->common_name,
396  print_in_addr_t(ip, 0, &gc),
397  print_in6_addr(ip6, 0, &gc));
398  }
399  else
400  {
401  status_printf(out, "%s,%s",
402  e->common_name,
403  print_in_addr_t(ip, 0, &gc));
404  }
405  }
406  }
407  gc_free(&gc);
408  }
409 }
410 
411 static void
412 ifconfig_pool_msg(const struct ifconfig_pool *pool, int msglevel)
413 {
414  struct status_output *so = status_open(NULL, 0, msglevel, NULL, 0);
415  ASSERT(so);
416  status_printf(so, "IFCONFIG POOL LIST");
417  ifconfig_pool_list(pool, so);
418  status_close(so);
419 }
420 
421 /*
422  * Deal with reading/writing the ifconfig pool database to a file
423  */
424 
425 struct ifconfig_pool_persist *
426 ifconfig_pool_persist_init(const char *filename, int refresh_freq)
427 {
428  struct ifconfig_pool_persist *ret;
429 
430  ASSERT(filename);
431 
433  if (refresh_freq > 0)
434  {
435  ret->fixed = false;
436  ret->file = status_open(filename, refresh_freq, -1, NULL, STATUS_OUTPUT_READ|STATUS_OUTPUT_WRITE);
437  }
438  else
439  {
440  ret->fixed = true;
441  ret->file = status_open(filename, 0, -1, NULL, STATUS_OUTPUT_READ);
442  }
443  return ret;
444 }
445 
446 void
448 {
449  if (persist)
450  {
451  if (persist->file)
452  {
453  status_close(persist->file);
454  }
455  free(persist);
456  }
457 }
458 
459 bool
461 {
462  if (persist->file)
463  {
464  return status_trigger(persist->file);
465  }
466  else
467  {
468  return false;
469  }
470 }
471 
472 void
474 {
475  const int buf_size = 128;
476 
477  update_time();
478  if (persist && persist->file && pool)
479  {
480  struct gc_arena gc = gc_new();
481  struct buffer in = alloc_buf_gc(256, &gc);
482  char *cn_buf;
483  char *ip_buf;
484  int line = 0;
485 
486  ALLOC_ARRAY_CLEAR_GC(cn_buf, char, buf_size, &gc);
487  ALLOC_ARRAY_CLEAR_GC(ip_buf, char, buf_size, &gc);
488 
489  while (true)
490  {
491  ASSERT(buf_init(&in, 0));
492  if (!status_read(persist->file, &in))
493  {
494  break;
495  }
496  ++line;
497  if (BLEN(&in))
498  {
499  int c = *BSTR(&in);
500  if (c == '#' || c == ';')
501  {
502  continue;
503  }
504  msg( M_INFO, "ifconfig_pool_read(), in='%s', TODO: IPv6",
505  BSTR(&in) );
506 
507  if (buf_parse(&in, ',', cn_buf, buf_size)
508  && buf_parse(&in, ',', ip_buf, buf_size))
509  {
510  bool succeeded;
511  const in_addr_t addr = getaddr(GETADDR_HOST_ORDER, ip_buf, 0, &succeeded, NULL);
512  if (succeeded)
513  {
514  msg( M_INFO, "succeeded -> ifconfig_pool_set()");
515  ifconfig_pool_set(pool, cn_buf, addr, persist->fixed);
516  }
517  }
518  }
519  }
520 
522 
523  gc_free(&gc);
524  }
525 }
526 
527 void
528 ifconfig_pool_write(struct ifconfig_pool_persist *persist, const struct ifconfig_pool *pool)
529 {
530  if (persist && persist->file && (status_rw_flags(persist->file) & STATUS_OUTPUT_WRITE) && pool)
531  {
532  status_reset(persist->file);
533  ifconfig_pool_list(pool, persist->file);
534  status_flush(persist->file);
535  }
536 }
537 
538 /*
539  * TESTING ONLY
540  */
541 
542 #ifdef IFCONFIG_POOL_TEST
543 
544 #define DUP_CN
545 
546 void
547 ifconfig_pool_test(in_addr_t start, in_addr_t end)
548 {
549  struct gc_arena gc = gc_new();
550  struct ifconfig_pool *p = ifconfig_pool_init(IFCONFIG_POOL_30NET, start, end);
551  /*struct ifconfig_pool *p = ifconfig_pool_init (IFCONFIG_POOL_INDIV, start, end);*/
552  ifconfig_pool_handle array[256];
553  int i;
554 
555  CLEAR(array);
556 
557  msg(M_INFO | M_NOPREFIX, "************ 1");
558  for (i = 0; i < (int) SIZE(array); ++i)
559  {
560  char *cn;
562  in_addr_t local, remote;
563  char buf[256];
564  openvpn_snprintf(buf, sizeof(buf), "common-name-%d", i);
565 #ifdef DUP_CN
566  cn = NULL;
567 #else
568  cn = buf;
569 #endif
570  h = ifconfig_pool_acquire(p, &local, &remote, NULL, cn);
571  if (h < 0)
572  {
573  break;
574  }
575  msg(M_INFO | M_NOPREFIX, "IFCONFIG_POOL TEST pass 1: l=%s r=%s cn=%s",
576  print_in_addr_t(local, 0, &gc),
577  print_in_addr_t(remote, 0, &gc),
578  cn);
579  array[i] = h;
580 
581  }
582 
583  msg(M_INFO | M_NOPREFIX, "************* 2");
584  for (i = (int) SIZE(array) / 16; i < (int) SIZE(array) / 8; ++i)
585  {
586  msg(M_INFO, "Attempt to release %d cn=%s", array[i], p->list[i].common_name);
587  if (!ifconfig_pool_release(p, array[i]))
588  {
589  break;
590  }
591  msg(M_INFO, "Succeeded");
592  }
593 
594  CLEAR(array);
595 
596  msg(M_INFO | M_NOPREFIX, "**************** 3");
597  for (i = 0; i < (int) SIZE(array); ++i)
598  {
599  char *cn;
601  in_addr_t local, remote;
602  char buf[256];
603  snprintf(buf, sizeof(buf), "common-name-%d", i+24);
604 #ifdef DUP_CN
605  cn = NULL;
606 #else
607  cn = buf;
608 #endif
609  h = ifconfig_pool_acquire(p, &local, &remote, NULL, cn);
610  if (h < 0)
611  {
612  break;
613  }
614  msg(M_INFO | M_NOPREFIX, "IFCONFIG_POOL TEST pass 3: l=%s r=%s cn=%s",
615  print_in_addr_t(local, 0, &gc),
616  print_in_addr_t(remote, 0, &gc),
617  cn);
618  array[i] = h;
619 
620  }
621 
623  gc_free(&gc);
624 }
625 
626 #endif /* ifdef IFCONFIG_POOL_TEST */
627 
628 #endif /* if P2MP */
void ifconfig_pool_free(struct ifconfig_pool *pool)
Definition: pool.c:211
struct ifconfig_pool_persist * ifconfig_pool_persist_init(const char *filename, int refresh_freq)
Definition: pool.c:426
static void ifconfig_pool_entry_free(struct ifconfig_pool_entry *ipe, bool hard)
Definition: pool.c:43
bool ifconfig_pool_release(struct ifconfig_pool *pool, ifconfig_pool_handle hand, const bool hard)
Definition: pool.c:274
struct ifconfig_pool::@6 ipv6
#define M_NOPREFIX
Definition: error.h:102
static in_addr_t ifconfig_pool_handle_to_ip_base(const struct ifconfig_pool *pool, ifconfig_pool_handle hand)
Definition: pool.c:321
char * string_alloc(const char *str, struct gc_arena *gc)
Definition: buffer.c:688
struct ifconfig_pool_entry * list
Definition: pool.h:64
#define STATUS_OUTPUT_WRITE
Definition: status.h:51
in_addr_t getaddr(unsigned int flags, const char *hostname, int resolve_retry_seconds, bool *succeeded, volatile int *signal_received)
Translate an IPv4 addr or hostname from string form to in_addr_t.
Definition: socket.c:193
const char * print_in6_addr(struct in6_addr a6, unsigned int flags, struct gc_arena *gc)
Definition: socket.c:2992
#define M_INFO
Definition: errlevel.h:55
pool_type
Definition: pool.h:37
static void gc_free(struct gc_arena *a)
Definition: buffer.h:1023
void ifconfig_pool_read(struct ifconfig_pool_persist *persist, struct ifconfig_pool *pool)
Definition: pool.c:473
bool fixed
Definition: pool.h:48
struct ifconfig_pool * ifconfig_pool_init(enum pool_type type, in_addr_t start, in_addr_t end, const bool duplicate_cn, const bool ipv6_pool, const struct in6_addr ipv6_base, const int ipv6_netbits)
Definition: pool.c:150
#define SIZE(x)
Definition: basic.h:30
#define in_addr_t
Definition: config-msvc.h:104
static unsigned int status_rw_flags(const struct status_output *so)
Definition: status.h:95
#define ASSERT(x)
Definition: error.h:221
static void ifconfig_pool_list(const struct ifconfig_pool *pool, struct status_output *out)
Definition: pool.c:378
#define snprintf
Definition: config-msvc.h:97
static void ifconfig_pool_msg(const struct ifconfig_pool *pool, int msglevel)
Definition: pool.c:412
void status_printf(struct status_output *so, const char *format,...)
Definition: status.c:239
bool ifconfig_pool_verify_range(const int msglevel, const in_addr_t start, const in_addr_t end)
Definition: pool.c:125
void status_flush(struct status_output *so)
Definition: status.c:172
static ifconfig_pool_handle ifconfig_pool_ip_base_to_handle(const struct ifconfig_pool *pool, const in_addr_t addr)
Definition: pool.c:290
int ifconfig_pool_handle
Definition: pool.h:73
#define IFCONFIG_POOL_MAX
Definition: pool.h:34
void ifconfig_pool_persist_close(struct ifconfig_pool_persist *persist)
Definition: pool.c:447
struct status_output * status_open(const char *filename, const int refresh_freq, const int msglevel, const struct virtual_output *vout, const unsigned int flags)
Definition: status.c:63
in_addr_t base
Definition: pool.h:56
bool status_close(struct status_output *so)
Definition: status.c:203
#define CLEAR(x)
Definition: basic.h:33
bool openvpn_snprintf(char *str, size_t size, const char *format,...)
Definition: buffer.c:299
void ifconfig_pool_write(struct ifconfig_pool_persist *persist, const struct ifconfig_pool *pool)
Definition: pool.c:528
static struct gc_arena gc_new(void)
Definition: buffer.h:1015
time_t now
Definition: otime.c:36
#define ALLOC_OBJ_CLEAR(dptr, type)
Definition: buffer.h:1050
const char * print_in_addr_t(in_addr_t addr, unsigned int flags, struct gc_arena *gc)
Definition: socket.c:2972
#define D_IFCONFIG_POOL
Definition: errlevel.h:84
bool duplicate_cn
Definition: pool.h:53
#define STATUS_OUTPUT_READ
Definition: status.h:50
static void ifconfig_pool_set(struct ifconfig_pool *pool, const char *cn, const in_addr_t addr, const bool fixed)
Definition: pool.c:363
bool status_trigger(struct status_output *so)
Definition: status.c:135
#define msg
Definition: error.h:173
#define GETADDR_HOST_ORDER
Definition: socket.h:522
bool in_use
Definition: pool.h:45
char * common_name
Definition: pool.h:46
#define BLEN(buf)
Definition: buffer.h:127
static struct in6_addr ifconfig_pool_handle_to_ipv6_base(const struct ifconfig_pool *pool, ifconfig_pool_handle hand)
Definition: pool.c:350
struct status_output * file
Definition: pool.h:69
#define ALLOC_ARRAY_CLEAR(dptr, type, n)
Definition: buffer.h:1066
#define ALLOC_ARRAY_CLEAR_GC(dptr, type, n, gc)
Definition: buffer.h:1072
ifconfig_pool_handle ifconfig_pool_acquire(struct ifconfig_pool *pool, in_addr_t *local, in_addr_t *remote, struct in6_addr *remote_ipv6, const char *common_name)
Definition: pool.c:226
bool buf_parse(struct buffer *buf, const int delim, char *line, const int size)
Definition: buffer.c:865
Wrapper structure for dynamically allocated memory.
Definition: buffer.h:60
#define buf_init(buf, offset)
Definition: buffer.h:196
bool ifconfig_pool_write_trigger(struct ifconfig_pool_persist *persist)
Definition: pool.c:460
time_t last_release
Definition: pool.h:47
struct buffer alloc_buf_gc(size_t size, struct gc_arena *gc)
Definition: buffer.c:90
#define free
Definition: cmocka.c:1850
static int ifconfig_pool_find(struct ifconfig_pool *pool, const char *common_name)
Definition: pool.c:62
Garbage collection arena used to keep track of dynamically allocated memory.
Definition: buffer.h:116
bool enabled
Definition: pool.h:60
#define BSTR(buf)
Definition: buffer.h:129
bool status_read(struct status_output *so, struct buffer *buf)
Definition: status.c:285
static void update_time(void)
Definition: otime.h:93
Definition: pool.h:43
struct ifconfig_pool::@5 ipv4
int size
Definition: pool.h:57
void status_reset(struct status_output *so)
Definition: status.c:163
enum pool_type type
Definition: pool.h:55
struct in6_addr add_in6_addr(struct in6_addr base, uint32_t add)
Definition: socket.c:3014